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>
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
, mDNSu16 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
);
58 mDNSlocal mStatus
DNS64GetPrefixes(mDNS
*m
, mDNSu16 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
, mDNSu16 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 // DNS64AnswerQuestion
178 //===========================================================================================================================
180 mDNSexport mStatus
DNS64AnswerQuestion(mDNS
*m
, DNSQuestion
*inQ
, 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
;
191 require_action_quiet(inQ
->qDNSServer
, exit
, err
= mStatus_BadParamErr
);
193 err
= DNS64GetPrefixes(m
, inQ
->qDNSServer
->resGroupID
, &prefixes
, &prefixCount
);
194 require_noerr_quiet(err
, exit
);
197 newRR
.rrtype
= kDNSType_AAAA
;
199 rdata
.MaxRDLength
= newRR
.rdlength
;
200 newRR
.rdata
= &rdata
;
202 memcpy(&v4Addr
.s_addr
, inRR
->rdata
->u
.ipv4
.b
, 4);
203 for (i
= 0; i
< prefixCount
; i
++)
205 if (nw_nat64_synthesize_v6(&prefixes
[i
], &v4Addr
, &synthV6
))
207 memcpy(rdata
.u
.ipv6
.b
, synthV6
.s6_addr
, 16);
208 inQ
->QuestionCallback(m
, inQ
, &newRR
, inResult
);
211 err
= mStatus_NoError
;
214 if (prefixes
) free(prefixes
);
218 //===========================================================================================================================
219 // DNS64HandleNewQuestion
220 //===========================================================================================================================
222 mDNSexport
void DNS64HandleNewQuestion(mDNS
*m
, DNSQuestion
*inQ
)
224 if (inQ
->dns64
.state
== kDNS64State_QueryPTR
)
226 struct in6_addr v6Addr
;
228 inQ
->dns64
.state
= kDNS64State_ReverseIPv6
;
229 if (inQ
->qDNSServer
&& DNS64GetReverseIPv6Addr(&inQ
->qname
, &v6Addr
))
232 nw_nat64_prefix_t
* prefixes
;
233 uint32_t prefixCount
;
235 struct in_addr v4Addr
;
236 char qnameStr
[MAX_REVERSE_MAPPING_NAME_V4
];
238 err
= DNS64GetPrefixes(m
, inQ
->qDNSServer
->resGroupID
, &prefixes
, &prefixCount
);
239 require_noerr_quiet(err
, exit
);
241 for (i
= 0; i
< prefixCount
; i
++)
243 if (nw_nat64_extract_v4(&prefixes
[i
], &v6Addr
, &v4Addr
))
245 const mDNSu8
* const a
= (const mDNSu8
*)&v4Addr
.s_addr
;
247 snprintf(qnameStr
, sizeof(qnameStr
), "%u.%u.%u.%u.in-addr.arpa.", a
[3], a
[2], a
[1], a
[0]);
248 MakeDomainNameFromDNSNameString(&inQ
->qname
, qnameStr
);
249 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
250 inQ
->dns64
.state
= kDNS64State_ReverseIPv4
;
262 //===========================================================================================================================
264 //===========================================================================================================================
266 // Called from mDNS_StopQuery_internal().
268 mDNSexport
void DNS64ResetState(DNSQuestion
*inQ
)
270 switch (inQ
->dns64
.state
)
272 case kDNS64State_PrefixDiscoveryPTR
:
273 inQ
->qtype
= kDNSType_PTR
; // Restore qtype to PTR and fall through.
275 case kDNS64State_PrefixDiscovery
:
276 memcpy(&inQ
->qname
, inQ
->dns64
.qnameStash
, sizeof(inQ
->dns64
.qnameStash
)); // Restore the previous qname.
277 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
280 case kDNS64State_QueryA
:
281 case kDNS64State_QueryA2
:
282 inQ
->qtype
= kDNSType_AAAA
; // Restore qtype to AAAA.
285 // Do nothing for the other states.
287 case kDNS64State_Initial
:
288 case kDNS64State_QueryAAAA
:
289 case kDNS64State_QueryPTR
:
290 case kDNS64State_ReverseIPv4
:
291 case kDNS64State_ReverseIPv6
:
295 LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ
->dns64
.state
);
298 inQ
->dns64
.state
= kDNS64State_Initial
;
301 //===========================================================================================================================
302 // DNS64RestartQuestions
303 //===========================================================================================================================
305 mDNSexport
void DNS64RestartQuestions(mDNS
*m
)
308 DNSQuestion
* restartList
= NULL
;
309 DNSServer
* newServer
;
311 m
->RestartQuestion
= m
->Questions
;
312 while (m
->RestartQuestion
)
314 q
= m
->RestartQuestion
;
315 m
->RestartQuestion
= q
->next
;
316 if (q
->dns64
.state
!= kDNS64State_Initial
)
318 SetValidDNSServers(m
, q
);
319 q
->triedAllServersOnce
= 0;
320 newServer
= GetServerForQuestion(m
, q
);
321 if (q
->qDNSServer
!= newServer
)
323 if (!CacheRecordRmvEventsForQuestion(m
, q
))
325 LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
329 LogInfo("DNS64RestartQuestions: Stop question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
330 mDNS_StopQuery_internal(m
, q
);
331 q
->next
= restartList
;
337 while ((q
= restartList
) != NULL
)
339 restartList
= restartList
->next
;
341 LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
342 mDNS_StartQuery_internal(m
, q
);
346 //===========================================================================================================================
348 //===========================================================================================================================
350 #define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID) \
351 ((RR)->rDNSServer && \
352 ((RR)->rDNSServer->resGroupID == RES_GROUP_ID) && \
353 ((RR)->rrtype == kDNSType_AAAA) && \
354 ((RR)->RecordType != kDNSRecordTypePacketNegative) && \
357 mDNSlocal mStatus
DNS64GetIPv6Addrs(mDNS
*m
, const mDNSu16 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
)
360 const CacheGroup
* cg
;
361 const CacheRecord
* cr
;
362 struct in6_addr
* addrs
= NULL
;
364 uint32_t recordCount
;
366 cg
= CacheGroupForName(m
, DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN
);
367 require_action_quiet(cg
, exit
, err
= mStatus_NoSuchRecord
);
370 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
372 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
377 require_action_quiet(recordCount
> 0, exit
, err
= mStatus_NoSuchRecord
);
379 addrs
= (struct in6_addr
*)calloc(recordCount
, sizeof(*addrs
));
380 require_action_quiet(addrs
, exit
, err
= mStatus_NoMemoryErr
);
383 for (cr
= cg
->members
; cr
&& (addrCount
< recordCount
); cr
= cr
->next
)
385 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
387 memcpy(addrs
[addrCount
].s6_addr
, cr
->resrec
.rdata
->u
.ipv6
.b
, 16);
394 *outAddrCount
= addrCount
;
395 err
= mStatus_NoError
;
398 if (addrs
) free(addrs
);
402 //===========================================================================================================================
404 //===========================================================================================================================
406 mDNSlocal mStatus
DNS64GetPrefixes(mDNS
*m
, mDNSu16 inResGroupID
, nw_nat64_prefix_t
**outPrefixes
, uint32_t *outPrefixCount
)
409 struct in6_addr
* v6Addrs
;
410 uint32_t v6AddrCount
;
411 nw_nat64_prefix_t
* prefixes
;
414 err
= DNS64GetIPv6Addrs(m
, inResGroupID
, &v6Addrs
, &v6AddrCount
);
415 require_noerr_quiet(err
, exit
);
417 prefixCount
= nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs
, v6AddrCount
, &prefixes
);
419 require_action_quiet(prefixCount
> 0, exit
, err
= mStatus_UnknownErr
);
421 *outPrefixes
= prefixes
;
422 *outPrefixCount
= prefixCount
;
428 //===========================================================================================================================
429 // DNS64GetReverseIPv6Addr
430 //===========================================================================================================================
432 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
434 mDNSlocal mDNSBool
DNS64GetReverseIPv6Addr(const domainname
*inQName
, struct in6_addr
*outAddr
)
442 // 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
443 // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order.
444 // See <https://tools.ietf.org/html/rfc3596#section-2.5>.
446 ptr
= (const mDNSu8
*)inQName
;
447 for (i
= 0; i
< 16; i
++)
449 if (*ptr
++ != 1) return (mDNSfalse
); // If this label's length is not 1, then fail.
450 c
= *ptr
++; // Get label byte.
451 if ( (c
>= '0') && (c
<= '9')) nl
= c
- '0'; // If it's a hex digit, get its numeric value.
452 else if ((c
>= 'a') && (c
<= 'f')) nl
= (c
- 'a') + 10;
453 else if ((c
>= 'A') && (c
<= 'F')) nl
= (c
- 'A') + 10;
454 else return (mDNSfalse
); // Otherwise, fail.
456 if (*ptr
++ != 1) return (mDNSfalse
); // If this label's length is not 1, then fail.
457 c
= *ptr
++; // Get label byte.
458 if ( (c
>= '0') && (c
<= '9')) nu
= c
- '0'; // If it's a hex digit, get its numeric value.
459 else if ((c
>= 'a') && (c
<= 'f')) nu
= (c
- 'a') + 10;
460 else if ((c
>= 'A') && (c
<= 'F')) nu
= (c
- 'A') + 10;
461 else return (mDNSfalse
); // Otherwise, fail.
463 if (outAddr
) outAddr
->s6_addr
[15 - i
] = (mDNSu8
)((nu
<< 4) | nl
);
466 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
468 if (!SameDomainName((const domainname
*)ptr
, kReverseIPv6Domain
)) return (mDNSfalse
);
473 //===========================================================================================================================
474 // DNS64IPv4OnlyFQDNHash
475 //===========================================================================================================================
477 mDNSlocal mDNSu32
DNS64IPv4OnlyFQDNHash(void)
479 static dispatch_once_t sHashOnce
;
480 static mDNSu32 sHash
;
482 dispatch_once(&sHashOnce
, ^{ sHash
= DomainNameHashValue(kDNS64IPv4OnlyFQDN
); });
487 //===========================================================================================================================
488 // DNS64RestartQuestion
489 //===========================================================================================================================
491 mDNSlocal
void DNS64RestartQuestion(mDNS
*const m
, DNSQuestion
*inQ
, DNS64State inNewState
)
493 mDNS_StopQuery_internal(m
, inQ
);
495 inQ
->dns64
.state
= inNewState
;
496 switch (inQ
->dns64
.state
)
498 case kDNS64State_Initial
:
501 case kDNS64State_PrefixDiscovery
:
502 case kDNS64State_PrefixDiscoveryPTR
:
503 // Save the first 15 bytes from the original qname that are displaced by setting qname to "ipv4only.arpa.".
505 memcpy(inQ
->dns64
.qnameStash
, &inQ
->qname
, sizeof(inQ
->dns64
.qnameStash
));
506 AssignDomainName(&inQ
->qname
, kDNS64IPv4OnlyFQDN
);
507 inQ
->qnamehash
= DNS64IPv4OnlyFQDNHash();
508 inQ
->qtype
= kDNSType_AAAA
;
511 case kDNS64State_QueryA
:
512 case kDNS64State_QueryA2
:
513 inQ
->qtype
= kDNSType_A
;
516 case kDNS64State_QueryPTR
:
517 case kDNS64State_ReverseIPv4
:
518 case kDNS64State_ReverseIPv6
:
519 inQ
->qtype
= kDNSType_PTR
;
522 case kDNS64State_QueryAAAA
:
523 inQ
->qtype
= kDNSType_AAAA
;
527 LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ
->dns64
.state
);
531 mDNS_StartQuery_internal(m
, inQ
);
534 //===========================================================================================================================
535 // DNS64TestIPv6Synthesis
536 //===========================================================================================================================
538 mDNSlocal mDNSBool
DNS64TestIPv6Synthesis(mDNS
*m
, mDNSu16 inResGroupID
, const mDNSv4Addr
*inV4Addr
)
541 nw_nat64_prefix_t
* prefixes
= NULL
;
542 uint32_t prefixCount
;
544 struct in_addr v4Addr
;
545 struct in6_addr synthV6
;
546 mDNSBool result
= mDNSfalse
;
548 err
= DNS64GetPrefixes(m
, inResGroupID
, &prefixes
, &prefixCount
);
549 require_noerr_quiet(err
, exit
);
551 memcpy(&v4Addr
.s_addr
, inV4Addr
->b
, 4);
552 for (i
= 0; i
< prefixCount
; i
++)
554 if (nw_nat64_synthesize_v6(&prefixes
[i
], &v4Addr
, &synthV6
))
562 if (prefixes
) free(prefixes
);
565 #endif // TARGET_OS_IOS