2 * Copyright (c) 2017-2019 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>
26 #if __has_include(<nw/private.h>)
27 #include <nw/private.h>
29 #include <network/nat64.h>
36 #include "dns_sd_internal.h"
39 //===========================================================================================================================
41 //===========================================================================================================================
43 #define kDNS64IPv4OnlyFQDNString "\x8" "ipv4only" "\x4" "arpa"
44 #define kDNS64IPv4OnlyFQDN ((const domainname *) kDNS64IPv4OnlyFQDNString)
45 #define kDNS64IPv4OnlyFQDNLength 15 // 9 bytes for first label, 5 bytes for second label, and 1 byte for the root label.
47 #define sizeof_field(TYPE, FIELD) sizeof(((TYPE *)0)->FIELD) // From CoreUtils.h
49 check_compile_time(sizeof(kDNS64IPv4OnlyFQDNString
) == kDNS64IPv4OnlyFQDNLength
);
50 check_compile_time(sizeof_field(DNSQuestion
, qname
) >= kDNS64IPv4OnlyFQDNLength
);
51 check_compile_time(sizeof_field(DNS64
, qnameStash
) == kDNS64IPv4OnlyFQDNLength
);
53 //===========================================================================================================================
55 //===========================================================================================================================
57 mDNSlocal mStatus
DNS64GetIPv6Addrs(mDNS
*m
, mDNSu32 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
);
58 mDNSlocal mStatus
DNS64GetPrefixes(mDNS
*m
, mDNSu32 inResGroupID
, nw_nat64_prefix_t
**outPrefixes
, uint32_t *outPrefixCount
);
59 mDNSlocal mDNSBool
DNS64GetReverseIPv6Addr(const domainname
*inQName
, struct in6_addr
*outAddr
);
60 mDNSlocal mDNSu32
DNS64IPv4OnlyFQDNHash(void);
61 mDNSlocal
void DNS64RestartQuestion(mDNS
*m
, DNSQuestion
*q
, DNS64State newState
);
62 mDNSlocal mDNSBool
DNS64TestIPv6Synthesis(mDNS
*m
, mDNSu32 inResGroupID
, const mDNSv4Addr
*inV4Addr
);
64 //===========================================================================================================================
66 //===========================================================================================================================
68 mDNSexport mDNSBool
DNS64StateMachine(mDNS
*m
, DNSQuestion
*inQ
, const ResourceRecord
*inRR
, QC_result inResult
)
70 // If this is an mDNS question, then exit early. DNS64 is only for unicast DNS questions.
72 if (mDNSOpaque16IsZero(inQ
->TargetQID
)) return (mDNSfalse
);
74 switch (inQ
->dns64
.state
)
76 // If this question is going to be answered with a negative AAAA record and the question is not for "ipv4only.arpa." and
77 // the question's DNS server's interface supports NAT64, then restart the question as an "ipv4only.arpa." AAAA question.
78 // Otherwise, do nothing.
80 case kDNS64State_Initial
:
81 if ((inRR
->RecordType
== kDNSRecordTypePacketNegative
) && (inResult
== QC_add
))
83 if ((inQ
->qtype
== kDNSType_AAAA
) &&
84 (inRR
->rrtype
== kDNSType_AAAA
) &&
85 (inRR
->rrclass
== kDNSClass_IN
) &&
86 ((inQ
->qnamehash
!= DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ
->qname
, kDNS64IPv4OnlyFQDN
)) &&
88 nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ
->qDNSServer
->interface
))
90 DNS64RestartQuestion(m
, inQ
, kDNS64State_PrefixDiscovery
);
93 else if ((inQ
->qtype
== kDNSType_PTR
) &&
94 (inRR
->rrtype
== kDNSType_PTR
) &&
95 (inRR
->rrclass
== kDNSClass_IN
) &&
97 nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ
->qDNSServer
->interface
) &&
98 DNS64GetReverseIPv6Addr(&inQ
->qname
, NULL
))
100 DNS64RestartQuestion(m
, inQ
, kDNS64State_PrefixDiscoveryPTR
);
106 // If the "ipv4only.arpa." question is going to be answered with a positive AAAA record, then restart it as a question
107 // for an A record with the original AAAA qname.
108 // Otherwise, restart the question for the original AAAA record.
110 case kDNS64State_PrefixDiscovery
:
111 if ((inRR
->RecordType
!= kDNSRecordTypePacketNegative
) &&
112 (inResult
== QC_add
) &&
113 (inRR
->rrtype
== kDNSType_AAAA
) &&
114 (inRR
->rrclass
== kDNSClass_IN
))
116 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryA
);
121 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryAAAA
);
126 // The "ipv4only.arpa." question is going to be answered. Restart the question now. DNS64HandleNewQuestion() will decide
127 // whether or not to change it to a reverse IPv4 question.
129 case kDNS64State_PrefixDiscoveryPTR
:
130 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryPTR
);
134 // If this question is going to be answered with a CNAME, then do nothing.
135 // If this question is going to be answered with a positive A record that's synthesizable, then set the state to
137 // Otherwise, restart the question for the original AAAA record.
139 case kDNS64State_QueryA
:
140 if (inRR
->rrtype
!= kDNSType_CNAME
)
142 if ((inRR
->RecordType
!= kDNSRecordTypePacketNegative
) &&
143 (inResult
== QC_add
) &&
144 (inRR
->rrtype
== kDNSType_A
) &&
145 (inRR
->rrclass
== kDNSClass_IN
) &&
147 DNS64TestIPv6Synthesis(m
, inQ
->qDNSServer
->resGroupID
, &inRR
->rdata
->u
.ipv4
))
149 inQ
->dns64
.state
= kDNS64State_QueryA2
;
153 DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryAAAA
);
159 // For all other states, do nothing.
161 case kDNS64State_QueryA2
:
162 case kDNS64State_QueryAAAA
:
163 case kDNS64State_QueryPTR
:
164 case kDNS64State_ReverseIPv4
:
165 case kDNS64State_ReverseIPv6
:
169 LogMsg("DNS64StateMachine: unrecognized DNS64 state %d", inQ
->dns64
.state
);
176 //===========================================================================================================================
177 // DNS64AnswerCurrentQuestion
178 //===========================================================================================================================
180 mDNSexport mStatus
DNS64AnswerCurrentQuestion(mDNS
*m
, const ResourceRecord
*inRR
, QC_result inResult
)
183 ResourceRecord newRR
;
185 nw_nat64_prefix_t
* prefixes
= NULL
;
186 uint32_t prefixCount
;
188 struct in_addr v4Addr
;
189 struct in6_addr synthV6
;
190 DNSQuestion
* const q
= m
->CurrentQuestion
;
192 require_action_quiet(q
->qDNSServer
, exit
, err
= mStatus_BadParamErr
);
194 err
= DNS64GetPrefixes(m
, q
->qDNSServer
->resGroupID
, &prefixes
, &prefixCount
);
195 require_noerr_quiet(err
, exit
);
198 newRR
.rrtype
= kDNSType_AAAA
;
200 rdata
.MaxRDLength
= newRR
.rdlength
;
201 newRR
.rdata
= &rdata
;
203 memcpy(&v4Addr
.s_addr
, inRR
->rdata
->u
.ipv4
.b
, 4);
204 for (i
= 0; i
< prefixCount
; i
++)
206 if (nw_nat64_synthesize_v6(&prefixes
[i
], &v4Addr
, &synthV6
))
208 memcpy(rdata
.u
.ipv6
.b
, synthV6
.s6_addr
, 16);
209 q
->QuestionCallback(m
, q
, &newRR
, inResult
);
210 if (m
->CurrentQuestion
!= q
) break;
213 err
= mStatus_NoError
;
216 if (prefixes
) free(prefixes
);
220 //===========================================================================================================================
221 // DNS64HandleNewQuestion
222 //===========================================================================================================================
224 mDNSexport
void DNS64HandleNewQuestion(mDNS
*m
, DNSQuestion
*inQ
)
226 if (inQ
->dns64
.state
== kDNS64State_QueryPTR
)
228 struct in6_addr v6Addr
;
230 inQ
->dns64
.state
= kDNS64State_ReverseIPv6
;
231 if (inQ
->qDNSServer
&& DNS64GetReverseIPv6Addr(&inQ
->qname
, &v6Addr
))
234 nw_nat64_prefix_t
* prefixes
;
235 uint32_t prefixCount
;
237 struct in_addr v4Addr
;
238 char qnameStr
[MAX_REVERSE_MAPPING_NAME_V4
];
240 err
= DNS64GetPrefixes(m
, inQ
->qDNSServer
->resGroupID
, &prefixes
, &prefixCount
);
241 require_noerr_quiet(err
, exit
);
243 for (i
= 0; i
< prefixCount
; i
++)
245 if (nw_nat64_extract_v4(&prefixes
[i
], &v6Addr
, &v4Addr
))
247 const mDNSu8
* const a
= (const mDNSu8
*)&v4Addr
.s_addr
;
249 snprintf(qnameStr
, sizeof(qnameStr
), "%u.%u.%u.%u.in-addr.arpa.", a
[3], a
[2], a
[1], a
[0]);
250 MakeDomainNameFromDNSNameString(&inQ
->qname
, qnameStr
);
251 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
252 inQ
->dns64
.state
= kDNS64State_ReverseIPv4
;
264 //===========================================================================================================================
266 //===========================================================================================================================
268 // Called from mDNS_StopQuery_internal().
270 mDNSexport
void DNS64ResetState(DNSQuestion
*inQ
)
272 switch (inQ
->dns64
.state
)
274 case kDNS64State_PrefixDiscoveryPTR
:
275 inQ
->qtype
= kDNSType_PTR
; // Restore qtype to PTR and fall through.
277 case kDNS64State_PrefixDiscovery
:
278 memcpy(&inQ
->qname
, inQ
->dns64
.qnameStash
, sizeof(inQ
->dns64
.qnameStash
)); // Restore the previous qname.
279 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
282 case kDNS64State_QueryA
:
283 case kDNS64State_QueryA2
:
284 inQ
->qtype
= kDNSType_AAAA
; // Restore qtype to AAAA.
287 // Do nothing for the other states.
289 case kDNS64State_Initial
:
290 case kDNS64State_QueryAAAA
:
291 case kDNS64State_QueryPTR
:
292 case kDNS64State_ReverseIPv4
:
293 case kDNS64State_ReverseIPv6
:
297 LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ
->dns64
.state
);
300 inQ
->dns64
.state
= kDNS64State_Initial
;
303 //===========================================================================================================================
304 // DNS64RestartQuestions
305 //===========================================================================================================================
307 mDNSexport
void DNS64RestartQuestions(mDNS
*m
)
310 DNSQuestion
* restartList
= NULL
;
311 DNSServer
* newServer
;
313 m
->RestartQuestion
= m
->Questions
;
314 while (m
->RestartQuestion
)
316 q
= m
->RestartQuestion
;
317 m
->RestartQuestion
= q
->next
;
318 if (q
->dns64
.state
!= kDNS64State_Initial
)
320 SetValidDNSServers(m
, q
);
321 q
->triedAllServersOnce
= 0;
322 newServer
= GetServerForQuestion(m
, q
);
323 if (q
->qDNSServer
!= newServer
)
325 if (!CacheRecordRmvEventsForQuestion(m
, q
))
327 LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
331 LogInfo("DNS64RestartQuestions: Stop question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
332 mDNS_StopQuery_internal(m
, q
);
333 q
->next
= restartList
;
339 while ((q
= restartList
) != NULL
)
341 restartList
= restartList
->next
;
343 LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
344 mDNS_StartQuery_internal(m
, q
);
348 //===========================================================================================================================
350 //===========================================================================================================================
352 #define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID) \
353 ((RR)->rDNSServer && \
354 ((RR)->rDNSServer->resGroupID == RES_GROUP_ID) && \
355 ((RR)->rrtype == kDNSType_AAAA) && \
356 ((RR)->RecordType != kDNSRecordTypePacketNegative) && \
359 mDNSlocal mStatus
DNS64GetIPv6Addrs(mDNS
*m
, const mDNSu32 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
)
362 const CacheGroup
* cg
;
363 const CacheRecord
* cr
;
364 struct in6_addr
* addrs
= NULL
;
366 uint32_t recordCount
;
368 cg
= CacheGroupForName(m
, DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN
);
369 require_action_quiet(cg
, exit
, err
= mStatus_NoSuchRecord
);
372 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
374 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
379 require_action_quiet(recordCount
> 0, exit
, err
= mStatus_NoSuchRecord
);
381 addrs
= (struct in6_addr
*)calloc(recordCount
, sizeof(*addrs
));
382 require_action_quiet(addrs
, exit
, err
= mStatus_NoMemoryErr
);
385 for (cr
= cg
->members
; cr
&& (addrCount
< recordCount
); cr
= cr
->next
)
387 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
389 memcpy(addrs
[addrCount
].s6_addr
, cr
->resrec
.rdata
->u
.ipv6
.b
, 16);
396 *outAddrCount
= addrCount
;
397 err
= mStatus_NoError
;
400 if (addrs
) free(addrs
);
404 //===========================================================================================================================
406 //===========================================================================================================================
408 mDNSlocal mStatus
DNS64GetPrefixes(mDNS
*m
, mDNSu32 inResGroupID
, nw_nat64_prefix_t
**outPrefixes
, uint32_t *outPrefixCount
)
411 struct in6_addr
* v6Addrs
;
412 uint32_t v6AddrCount
;
413 nw_nat64_prefix_t
* prefixes
;
416 err
= DNS64GetIPv6Addrs(m
, inResGroupID
, &v6Addrs
, &v6AddrCount
);
417 require_noerr_quiet(err
, exit
);
419 prefixCount
= nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs
, v6AddrCount
, &prefixes
);
421 require_action_quiet(prefixCount
> 0, exit
, err
= mStatus_UnknownErr
);
423 *outPrefixes
= prefixes
;
424 *outPrefixCount
= prefixCount
;
430 //===========================================================================================================================
431 // DNS64GetReverseIPv6Addr
432 //===========================================================================================================================
434 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
436 mDNSlocal mDNSBool
DNS64GetReverseIPv6Addr(const domainname
*inQName
, struct in6_addr
*outAddr
)
444 // 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
445 // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order.
446 // See <https://tools.ietf.org/html/rfc3596#section-2.5>.
448 ptr
= (const mDNSu8
*)inQName
;
449 for (i
= 0; i
< 16; i
++)
451 if (*ptr
++ != 1) return (mDNSfalse
); // If this label's length is not 1, then fail.
452 c
= *ptr
++; // Get label byte.
453 if ( (c
>= '0') && (c
<= '9')) nl
= c
- '0'; // If it's a hex digit, get its numeric value.
454 else if ((c
>= 'a') && (c
<= 'f')) nl
= (c
- 'a') + 10;
455 else if ((c
>= 'A') && (c
<= 'F')) nl
= (c
- 'A') + 10;
456 else return (mDNSfalse
); // Otherwise, fail.
458 if (*ptr
++ != 1) return (mDNSfalse
); // If this label's length is not 1, then fail.
459 c
= *ptr
++; // Get label byte.
460 if ( (c
>= '0') && (c
<= '9')) nu
= c
- '0'; // If it's a hex digit, get its numeric value.
461 else if ((c
>= 'a') && (c
<= 'f')) nu
= (c
- 'a') + 10;
462 else if ((c
>= 'A') && (c
<= 'F')) nu
= (c
- 'A') + 10;
463 else return (mDNSfalse
); // Otherwise, fail.
465 if (outAddr
) outAddr
->s6_addr
[15 - i
] = (mDNSu8
)((nu
<< 4) | nl
);
468 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
470 if (!SameDomainName((const domainname
*)ptr
, kReverseIPv6Domain
)) return (mDNSfalse
);
475 //===========================================================================================================================
476 // DNS64IPv4OnlyFQDNHash
477 //===========================================================================================================================
479 mDNSlocal mDNSu32
DNS64IPv4OnlyFQDNHash(void)
481 static dispatch_once_t sHashOnce
;
482 static mDNSu32 sHash
;
484 dispatch_once(&sHashOnce
, ^{ sHash
= DomainNameHashValue(kDNS64IPv4OnlyFQDN
); });
489 //===========================================================================================================================
490 // DNS64RestartQuestion
491 //===========================================================================================================================
493 mDNSlocal
void DNS64RestartQuestion(mDNS
*const m
, DNSQuestion
*inQ
, DNS64State inNewState
)
495 mDNS_StopQuery_internal(m
, inQ
);
497 inQ
->dns64
.state
= inNewState
;
498 switch (inQ
->dns64
.state
)
500 case kDNS64State_Initial
:
503 case kDNS64State_PrefixDiscovery
:
504 case kDNS64State_PrefixDiscoveryPTR
:
505 // Save the first 15 bytes from the original qname that are displaced by setting qname to "ipv4only.arpa.".
507 memcpy(inQ
->dns64
.qnameStash
, &inQ
->qname
, sizeof(inQ
->dns64
.qnameStash
));
508 AssignDomainName(&inQ
->qname
, kDNS64IPv4OnlyFQDN
);
509 inQ
->qnamehash
= DNS64IPv4OnlyFQDNHash();
510 inQ
->qtype
= kDNSType_AAAA
;
513 case kDNS64State_QueryA
:
514 case kDNS64State_QueryA2
:
515 inQ
->qtype
= kDNSType_A
;
518 case kDNS64State_QueryPTR
:
519 case kDNS64State_ReverseIPv4
:
520 case kDNS64State_ReverseIPv6
:
521 inQ
->qtype
= kDNSType_PTR
;
524 case kDNS64State_QueryAAAA
:
525 inQ
->qtype
= kDNSType_AAAA
;
529 LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ
->dns64
.state
);
533 mDNS_StartQuery_internal(m
, inQ
);
536 //===========================================================================================================================
537 // DNS64TestIPv6Synthesis
538 //===========================================================================================================================
540 mDNSlocal mDNSBool
DNS64TestIPv6Synthesis(mDNS
*m
, mDNSu32 inResGroupID
, const mDNSv4Addr
*inV4Addr
)
543 nw_nat64_prefix_t
* prefixes
= NULL
;
544 uint32_t prefixCount
;
546 struct in_addr v4Addr
;
547 struct in6_addr synthV6
;
548 mDNSBool result
= mDNSfalse
;
550 err
= DNS64GetPrefixes(m
, inResGroupID
, &prefixes
, &prefixCount
);
551 require_noerr_quiet(err
, exit
);
553 memcpy(&v4Addr
.s_addr
, inV4Addr
->b
, 4);
554 for (i
= 0; i
< prefixCount
; i
++)
556 if (nw_nat64_synthesize_v6(&prefixes
[i
], &v4Addr
, &synthV6
))
564 if (prefixes
) free(prefixes
);
567 #endif // TARGET_OS_IOS