2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <TargetConditionals.h>
19 // DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
24 #include <AssertMacros.h>
25 #include <network/nat64.h>
30 #include "dns_sd_internal.h"
33 //===========================================================================================================================
35 //===========================================================================================================================
37 #define kDNS64IPv4OnlyFQDNString "\x8" "ipv4only" "\x4" "arpa"
38 #define kDNS64IPv4OnlyFQDN ((const domainname *) kDNS64IPv4OnlyFQDNString)
39 #define kDNS64IPv4OnlyFQDNLength 15 // 9 bytes for first label, 5 bytes for second label, and 1 byte for the root label.
41 #define sizeof_field(TYPE, FIELD) sizeof(((TYPE *)0)->FIELD) // From CoreUtils.h
43 check_compile_time(sizeof(kDNS64IPv4OnlyFQDNString
) == kDNS64IPv4OnlyFQDNLength
);
44 check_compile_time(sizeof_field(DNSQuestion
, qname
) >= kDNS64IPv4OnlyFQDNLength
);
45 check_compile_time(sizeof_field(DNS64
, qnameStash
) == kDNS64IPv4OnlyFQDNLength
);
47 //===========================================================================================================================
49 //===========================================================================================================================
51 mDNSlocal mStatus
DNS64GetIPv6Addrs(mDNS
*m
, mDNSu16 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
);
52 mDNSlocal mStatus
DNS64GetPrefixes(mDNS
*m
, mDNSu16 inResGroupID
, nw_nat64_prefix_t
**outPrefixes
, uint32_t *outPrefixCount
);
53 mDNSlocal mDNSBool
DNS64GetReverseIPv6Addr(const domainname
*inQName
, struct in6_addr
*outAddr
);
54 mDNSlocal mDNSu32
DNS64IPv4OnlyFQDNHash(void);
55 mDNSlocal
void DNS64RestartQuestion(mDNS
*m
, DNSQuestion
*q
, DNS64State newState
);
56 mDNSlocal mDNSBool
DNS64TestIPv6Synthesis(mDNS
*m
, mDNSu16 inResGroupID
, const mDNSv4Addr
*inV4Addr
);
58 //===========================================================================================================================
60 //===========================================================================================================================
62 mDNSexport mDNSBool
DNS64StateMachine(mDNS
*m
, DNSQuestion
*inQ
, const ResourceRecord
*inRR
, QC_result inResult
)
64 // If this is an mDNS question, then exit early. DNS64 is only for unicast DNS questions.
66 if (mDNSOpaque16IsZero(inQ
->TargetQID
)) return (mDNSfalse
);
68 switch (inQ
->dns64
.state
)
70 // If this question is going to be answered with a negative AAAA record and the question is not for "ipv4only.arpa." and
71 // the question's DNS server's interface supports NAT64, then restart the question as an "ipv4only.arpa." AAAA question.
72 // Otherwise, do nothing.
74 case kDNS64State_Initial
:
75 if ((inRR
->RecordType
== kDNSRecordTypePacketNegative
) && (inResult
== QC_add
))
77 if ((inQ
->qtype
== kDNSType_AAAA
) &&
78 (inRR
->rrtype
== kDNSType_AAAA
) &&
79 (inRR
->rrclass
== kDNSClass_IN
) &&
80 ((inQ
->qnamehash
!= DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ
->qname
, kDNS64IPv4OnlyFQDN
)) &&
82 nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ
->qDNSServer
->interface
))
84 DNS64RestartQuestion(m
, inQ
, kDNS64State_PrefixDiscovery
);
87 else if ((inQ
->qtype
== kDNSType_PTR
) &&
88 (inRR
->rrtype
== kDNSType_PTR
) &&
89 (inRR
->rrclass
== kDNSClass_IN
) &&
91 nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ
->qDNSServer
->interface
) &&
92 DNS64GetReverseIPv6Addr(&inQ
->qname
, NULL
))
94 DNS64RestartQuestion(m
, inQ
, kDNS64State_PrefixDiscoveryPTR
);
100 // If the "ipv4only.arpa." question is going to be answered with a positive AAAA record, then restart it as a question
101 // for an A record with the original AAAA qname.
102 // Otherwise, restart the question for the original AAAA record.
104 case kDNS64State_PrefixDiscovery
:
105 if ((inRR
->RecordType
!= kDNSRecordTypePacketNegative
) &&
106 (inResult
== QC_add
) &&
107 (inRR
->rrtype
== kDNSType_AAAA
) &&
108 (inRR
->rrclass
== kDNSClass_IN
))
110 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryA
);
115 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryAAAA
);
120 // The "ipv4only.arpa." question is going to be answered. Restart the question now. DNS64HandleNewQuestion() will decide
121 // whether or not to change it to a reverse IPv4 question.
123 case kDNS64State_PrefixDiscoveryPTR
:
124 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryPTR
);
128 // If this question is going to be answered with a CNAME, then do nothing.
129 // If this question is going to be answered with a positive A record that's synthesizable, then set the state to
131 // Otherwise, restart the question for the original AAAA record.
133 case kDNS64State_QueryA
:
134 if (inRR
->rrtype
!= kDNSType_CNAME
)
136 if ((inRR
->RecordType
!= kDNSRecordTypePacketNegative
) &&
137 (inResult
== QC_add
) &&
138 (inRR
->rrtype
== kDNSType_A
) &&
139 (inRR
->rrclass
== kDNSClass_IN
) &&
141 DNS64TestIPv6Synthesis(m
, inQ
->qDNSServer
->resGroupID
, &inRR
->rdata
->u
.ipv4
))
143 inQ
->dns64
.state
= kDNS64State_QueryA2
;
147 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryAAAA
);
153 // For all other states, do nothing.
155 case kDNS64State_QueryA2
:
156 case kDNS64State_QueryAAAA
:
157 case kDNS64State_QueryPTR
:
158 case kDNS64State_ReverseIPv4
:
159 case kDNS64State_ReverseIPv6
:
163 LogMsg("DNS64StateMachine: unrecognized DNS64 state %d", inQ
->dns64
.state
);
170 //===========================================================================================================================
171 // DNS64AnswerQuestion
172 //===========================================================================================================================
174 mDNSexport mStatus
DNS64AnswerQuestion(mDNS
*m
, DNSQuestion
*inQ
, const ResourceRecord
*inRR
, QC_result inResult
)
177 ResourceRecord newRR
;
179 nw_nat64_prefix_t
* prefixes
= NULL
;
180 uint32_t prefixCount
;
182 struct in_addr v4Addr
;
183 struct in6_addr synthV6
;
185 require_action_quiet(inQ
->qDNSServer
, exit
, err
= mStatus_BadParamErr
);
187 err
= DNS64GetPrefixes(m
, inQ
->qDNSServer
->resGroupID
, &prefixes
, &prefixCount
);
188 require_noerr_quiet(err
, exit
);
191 newRR
.rrtype
= kDNSType_AAAA
;
193 rdata
.MaxRDLength
= newRR
.rdlength
;
194 newRR
.rdata
= &rdata
;
196 memcpy(&v4Addr
.s_addr
, inRR
->rdata
->u
.ipv4
.b
, 4);
197 for (i
= 0; i
< prefixCount
; i
++)
199 if (nw_nat64_synthesize_v6(&prefixes
[i
], &v4Addr
, &synthV6
))
201 memcpy(rdata
.u
.ipv6
.b
, synthV6
.s6_addr
, 16);
202 inQ
->QuestionCallback(m
, inQ
, &newRR
, inResult
);
205 err
= mStatus_NoError
;
208 if (prefixes
) free(prefixes
);
212 //===========================================================================================================================
213 // DNS64HandleNewQuestion
214 //===========================================================================================================================
216 mDNSexport
void DNS64HandleNewQuestion(mDNS
*m
, DNSQuestion
*inQ
)
218 if (inQ
->dns64
.state
== kDNS64State_QueryPTR
)
220 struct in6_addr v6Addr
;
222 inQ
->dns64
.state
= kDNS64State_ReverseIPv6
;
223 if (inQ
->qDNSServer
&& DNS64GetReverseIPv6Addr(&inQ
->qname
, &v6Addr
))
226 nw_nat64_prefix_t
* prefixes
;
227 uint32_t prefixCount
;
229 struct in_addr v4Addr
;
230 char qnameStr
[MAX_REVERSE_MAPPING_NAME_V4
];
232 err
= DNS64GetPrefixes(m
, inQ
->qDNSServer
->resGroupID
, &prefixes
, &prefixCount
);
233 require_noerr_quiet(err
, exit
);
235 for (i
= 0; i
< prefixCount
; i
++)
237 if (nw_nat64_extract_v4(&prefixes
[i
], &v6Addr
, &v4Addr
))
239 const mDNSu8
* const a
= (const mDNSu8
*)&v4Addr
.s_addr
;
241 snprintf(qnameStr
, sizeof(qnameStr
), "%u.%u.%u.%u.in-addr.arpa.", a
[3], a
[2], a
[1], a
[0]);
242 MakeDomainNameFromDNSNameString(&inQ
->qname
, qnameStr
);
243 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
244 inQ
->dns64
.state
= kDNS64State_ReverseIPv4
;
256 //===========================================================================================================================
258 //===========================================================================================================================
260 // Called from mDNS_StopQuery_internal().
262 mDNSexport
void DNS64ResetState(DNSQuestion
*inQ
)
264 switch (inQ
->dns64
.state
)
266 case kDNS64State_PrefixDiscoveryPTR
:
267 inQ
->qtype
= kDNSType_PTR
; // Restore qtype to PTR and fall through.
269 case kDNS64State_PrefixDiscovery
:
270 memcpy(&inQ
->qname
, inQ
->dns64
.qnameStash
, sizeof(inQ
->dns64
.qnameStash
)); // Restore the previous qname.
271 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
274 case kDNS64State_QueryA
:
275 case kDNS64State_QueryA2
:
276 inQ
->qtype
= kDNSType_AAAA
; // Restore qtype to AAAA.
279 // Do nothing for the other states.
281 case kDNS64State_Initial
:
282 case kDNS64State_QueryAAAA
:
283 case kDNS64State_QueryPTR
:
284 case kDNS64State_ReverseIPv4
:
285 case kDNS64State_ReverseIPv6
:
289 LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ
->dns64
.state
);
292 inQ
->dns64
.state
= kDNS64State_Initial
;
295 //===========================================================================================================================
296 // DNS64RestartQuestions
297 //===========================================================================================================================
299 mDNSexport
void DNS64RestartQuestions(mDNS
*m
)
302 DNSQuestion
* restartList
= NULL
;
303 DNSServer
* newServer
;
305 m
->RestartQuestion
= m
->Questions
;
306 while (m
->RestartQuestion
)
308 q
= m
->RestartQuestion
;
309 m
->RestartQuestion
= q
->next
;
310 if (q
->dns64
.state
!= kDNS64State_Initial
)
312 SetValidDNSServers(m
, q
);
313 q
->triedAllServersOnce
= 0;
314 newServer
= GetServerForQuestion(m
, q
);
315 if (q
->qDNSServer
!= newServer
)
317 if (!CacheRecordRmvEventsForQuestion(m
, q
))
319 LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
323 LogInfo("DNS64RestartQuestions: Stop question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
324 mDNS_StopQuery_internal(m
, q
);
325 q
->next
= restartList
;
331 while ((q
= restartList
) != NULL
)
333 restartList
= restartList
->next
;
335 LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
336 mDNS_StartQuery_internal(m
, q
);
340 //===========================================================================================================================
342 //===========================================================================================================================
344 #define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID) \
345 ((RR)->rDNSServer && \
346 ((RR)->rDNSServer->resGroupID == RES_GROUP_ID) && \
347 ((RR)->rrtype == kDNSType_AAAA) && \
348 ((RR)->RecordType != kDNSRecordTypePacketNegative) && \
351 mDNSlocal mStatus
DNS64GetIPv6Addrs(mDNS
*m
, const mDNSu16 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
)
354 const CacheGroup
* cg
;
355 const CacheRecord
* cr
;
356 struct in6_addr
* addrs
= NULL
;
358 uint32_t recordCount
;
360 cg
= CacheGroupForName(m
, DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN
);
361 require_action_quiet(cg
, exit
, err
= mStatus_NoSuchRecord
);
364 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
366 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
371 require_action_quiet(recordCount
> 0, exit
, err
= mStatus_NoSuchRecord
);
373 addrs
= (struct in6_addr
*)calloc(recordCount
, sizeof(*addrs
));
374 require_action_quiet(addrs
, exit
, err
= mStatus_NoMemoryErr
);
377 for (cr
= cg
->members
; cr
&& (addrCount
< recordCount
); cr
= cr
->next
)
379 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
381 memcpy(addrs
[addrCount
].s6_addr
, cr
->resrec
.rdata
->u
.ipv6
.b
, 16);
388 *outAddrCount
= addrCount
;
389 err
= mStatus_NoError
;
392 if (addrs
) free(addrs
);
396 //===========================================================================================================================
398 //===========================================================================================================================
400 mDNSlocal mStatus
DNS64GetPrefixes(mDNS
*m
, mDNSu16 inResGroupID
, nw_nat64_prefix_t
**outPrefixes
, uint32_t *outPrefixCount
)
403 struct in6_addr
* v6Addrs
;
404 uint32_t v6AddrCount
;
405 nw_nat64_prefix_t
* prefixes
;
408 err
= DNS64GetIPv6Addrs(m
, inResGroupID
, &v6Addrs
, &v6AddrCount
);
409 require_noerr_quiet(err
, exit
);
411 prefixCount
= nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs
, v6AddrCount
, &prefixes
);
413 require_action_quiet(prefixCount
> 0, exit
, err
= mStatus_UnknownErr
);
415 *outPrefixes
= prefixes
;
416 *outPrefixCount
= prefixCount
;
422 //===========================================================================================================================
423 // DNS64GetReverseIPv6Addr
424 //===========================================================================================================================
426 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
428 mDNSlocal mDNSBool
DNS64GetReverseIPv6Addr(const domainname
*inQName
, struct in6_addr
*outAddr
)
436 // If the name is of the form "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa.", where each x
437 // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order.
438 // See <https://tools.ietf.org/html/rfc3596#section-2.5>.
440 ptr
= (const mDNSu8
*)inQName
;
441 for (i
= 0; i
< 16; i
++)
443 if (*ptr
++ != 1) return (mDNSfalse
); // If this label's length is not 1, then fail.
444 c
= *ptr
++; // Get label byte.
445 if ( (c
>= '0') && (c
<= '9')) nl
= c
- '0'; // If it's a hex digit, get its numeric value.
446 else if ((c
>= 'a') && (c
<= 'f')) nl
= (c
- 'a') + 10;
447 else if ((c
>= 'A') && (c
<= 'F')) nl
= (c
- 'A') + 10;
448 else return (mDNSfalse
); // Otherwise, fail.
450 if (*ptr
++ != 1) return (mDNSfalse
); // If this label's length is not 1, then fail.
451 c
= *ptr
++; // Get label byte.
452 if ( (c
>= '0') && (c
<= '9')) nu
= c
- '0'; // If it's a hex digit, get its numeric value.
453 else if ((c
>= 'a') && (c
<= 'f')) nu
= (c
- 'a') + 10;
454 else if ((c
>= 'A') && (c
<= 'F')) nu
= (c
- 'A') + 10;
455 else return (mDNSfalse
); // Otherwise, fail.
457 if (outAddr
) outAddr
->s6_addr
[15 - i
] = (mDNSu8
)((nu
<< 4) | nl
);
460 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
462 if (!SameDomainName((const domainname
*)ptr
, kReverseIPv6Domain
)) return (mDNSfalse
);
467 //===========================================================================================================================
468 // DNS64IPv4OnlyFQDNHash
469 //===========================================================================================================================
471 mDNSlocal mDNSu32
DNS64IPv4OnlyFQDNHash(void)
473 static dispatch_once_t sHashOnce
;
474 static mDNSu32 sHash
;
476 dispatch_once(&sHashOnce
, ^{ sHash
= DomainNameHashValue(kDNS64IPv4OnlyFQDN
); });
481 //===========================================================================================================================
482 // DNS64RestartQuestion
483 //===========================================================================================================================
485 mDNSlocal
void DNS64RestartQuestion(mDNS
*const m
, DNSQuestion
*inQ
, DNS64State inNewState
)
487 mDNS_StopQuery_internal(m
, inQ
);
489 inQ
->dns64
.state
= inNewState
;
490 switch (inQ
->dns64
.state
)
492 case kDNS64State_Initial
:
495 case kDNS64State_PrefixDiscovery
:
496 case kDNS64State_PrefixDiscoveryPTR
:
497 // Save the first 15 bytes from the original qname that are displaced by setting qname to "ipv4only.arpa.".
499 memcpy(inQ
->dns64
.qnameStash
, &inQ
->qname
, sizeof(inQ
->dns64
.qnameStash
));
500 AssignDomainName(&inQ
->qname
, kDNS64IPv4OnlyFQDN
);
501 inQ
->qnamehash
= DNS64IPv4OnlyFQDNHash();
502 inQ
->qtype
= kDNSType_AAAA
;
505 case kDNS64State_QueryA
:
506 case kDNS64State_QueryA2
:
507 inQ
->qtype
= kDNSType_A
;
510 case kDNS64State_QueryPTR
:
511 case kDNS64State_ReverseIPv4
:
512 case kDNS64State_ReverseIPv6
:
513 inQ
->qtype
= kDNSType_PTR
;
516 case kDNS64State_QueryAAAA
:
517 inQ
->qtype
= kDNSType_AAAA
;
521 LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ
->dns64
.state
);
525 mDNS_StartQuery_internal(m
, inQ
);
528 //===========================================================================================================================
529 // DNS64TestIPv6Synthesis
530 //===========================================================================================================================
532 mDNSlocal mDNSBool
DNS64TestIPv6Synthesis(mDNS
*m
, mDNSu16 inResGroupID
, const mDNSv4Addr
*inV4Addr
)
535 nw_nat64_prefix_t
* prefixes
= NULL
;
536 uint32_t prefixCount
;
538 struct in_addr v4Addr
;
539 struct in6_addr synthV6
;
540 mDNSBool result
= mDNSfalse
;
542 err
= DNS64GetPrefixes(m
, inResGroupID
, &prefixes
, &prefixCount
);
543 require_noerr_quiet(err
, exit
);
545 memcpy(&v4Addr
.s_addr
, inV4Addr
->b
, 4);
546 for (i
= 0; i
< prefixCount
; i
++)
548 if (nw_nat64_synthesize_v6(&prefixes
[i
], &v4Addr
, &synthV6
))
556 if (prefixes
) free(prefixes
);
559 #endif // TARGET_OS_IOS