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.
19 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
21 #include <AssertMacros.h>
22 #include <nw/private.h>
27 #include "dns_sd_internal.h"
28 #include "mDNSMacOSX.h"
31 //===========================================================================================================================
33 //===========================================================================================================================
35 #define kDNS64IPv4OnlyFQDNString "\x8" "ipv4only" "\x4" "arpa"
36 #define kDNS64IPv4OnlyFQDN ((const domainname *) kDNS64IPv4OnlyFQDNString)
37 #define kDNS64IPv4OnlyFQDNLength 15 // 9 bytes for first label, 5 bytes for second label, and 1 byte for the root label.
39 #define sizeof_field(TYPE, FIELD) sizeof(((TYPE *)0)->FIELD) // From CoreUtils.h
41 check_compile_time(sizeof(kDNS64IPv4OnlyFQDNString
) == kDNS64IPv4OnlyFQDNLength
);
42 check_compile_time(sizeof_field(DNSQuestion
, qname
) >= kDNS64IPv4OnlyFQDNLength
);
43 check_compile_time(sizeof_field(DNS64
, qnameStash
) == kDNS64IPv4OnlyFQDNLength
);
45 //===========================================================================================================================
47 //===========================================================================================================================
49 mDNSlocal mStatus
_DNS64GetIPv6Addrs(mDNS
*m
, mDNSu32 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
);
50 mDNSlocal mStatus
_DNS64GetPrefixes(mDNS
*m
, mDNSu32 inResGroupID
, nw_nat64_prefix_t
**outPrefixes
, uint32_t *outPrefixCount
);
51 mDNSlocal mDNSBool
_DNS64GetReverseIPv6Addr(const domainname
*inQName
, struct in6_addr
*outAddr
);
52 mDNSlocal mDNSu32
_DNS64IPv4OnlyFQDNHash(void);
53 mDNSlocal
void _DNS64RestartQuestion(mDNS
*m
, DNSQuestion
*q
, DNS64State newState
);
54 mDNSlocal mDNSBool
_DNS64InterfaceSupportsNAT64(uint32_t inIfIndex
);
55 mDNSlocal mDNSBool
_DNS64TestIPv6Synthesis(mDNS
*m
, mDNSu32 inResGroupID
, const mDNSv4Addr
*inV4Addr
);
57 //===========================================================================================================================
59 //===========================================================================================================================
61 mDNSexport mDNSBool
DNS64StateMachine(mDNS
*m
, DNSQuestion
*inQ
, const ResourceRecord
*inRR
, QC_result inResult
)
63 // If this is an mDNS question, then exit early. DNS64 is only for unicast DNS questions.
65 if (mDNSOpaque16IsZero(inQ
->TargetQID
)) return (mDNSfalse
);
67 switch (inQ
->dns64
.state
)
69 // If this question is going to be answered with a negative AAAA record and the question is not for "ipv4only.arpa." and
70 // the question's DNS server's interface supports NAT64, then restart the question as an "ipv4only.arpa." AAAA question.
71 // Otherwise, do nothing.
73 case kDNS64State_Initial
:
74 if ((inRR
->RecordType
== kDNSRecordTypePacketNegative
) && (inResult
== QC_add
))
76 if ((inQ
->qtype
== kDNSType_AAAA
) &&
77 (inRR
->rrtype
== kDNSType_AAAA
) &&
78 (inRR
->rrclass
== kDNSClass_IN
) &&
79 ((inQ
->qnamehash
!= _DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ
->qname
, kDNS64IPv4OnlyFQDN
)) &&
81 _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ
->qDNSServer
->interface
)))
83 _DNS64RestartQuestion(m
, inQ
, kDNS64State_PrefixDiscovery
);
86 else if ((inQ
->qtype
== kDNSType_PTR
) &&
87 (inRR
->rrtype
== kDNSType_PTR
) &&
88 (inRR
->rrclass
== kDNSClass_IN
) &&
90 _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ
->qDNSServer
->interface
)) &&
91 _DNS64GetReverseIPv6Addr(&inQ
->qname
, NULL
))
93 _DNS64RestartQuestion(m
, inQ
, kDNS64State_PrefixDiscoveryPTR
);
99 // If the "ipv4only.arpa." question is going to be answered with a positive AAAA record, then restart it as a question
100 // for an A record with the original AAAA qname.
101 // Otherwise, restart the question for the original AAAA record.
103 case kDNS64State_PrefixDiscovery
:
104 if ((inRR
->RecordType
!= kDNSRecordTypePacketNegative
) &&
105 (inResult
== QC_add
) &&
106 (inRR
->rrtype
== kDNSType_AAAA
) &&
107 (inRR
->rrclass
== kDNSClass_IN
))
109 _DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryA
);
114 _DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryAAAA
);
119 // The "ipv4only.arpa." question is going to be answered. Restart the question now. DNS64HandleNewQuestion() will decide
120 // whether or not to change it to a reverse IPv4 question.
122 case kDNS64State_PrefixDiscoveryPTR
:
123 _DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryPTR
);
127 // If this question is going to be answered with a CNAME, then do nothing.
128 // If this question is going to be answered with a positive A record that's synthesizable, then set the state to
130 // Otherwise, restart the question for the original AAAA record.
132 case kDNS64State_QueryA
:
133 if (inRR
->rrtype
!= kDNSType_CNAME
)
135 if ((inRR
->RecordType
!= kDNSRecordTypePacketNegative
) &&
136 (inResult
== QC_add
) &&
137 (inRR
->rrtype
== kDNSType_A
) &&
138 (inRR
->rrclass
== kDNSClass_IN
) &&
140 _DNS64TestIPv6Synthesis(m
, inQ
->qDNSServer
->resGroupID
, &inRR
->rdata
->u
.ipv4
))
142 inQ
->dns64
.state
= kDNS64State_QueryA2
;
146 _DNS64RestartQuestion(m
, inQ
, kDNS64State_QueryAAAA
);
152 // For all other states, do nothing.
154 case kDNS64State_QueryA2
:
155 case kDNS64State_QueryAAAA
:
156 case kDNS64State_QueryPTR
:
157 case kDNS64State_ReverseIPv4
:
158 case kDNS64State_ReverseIPv6
:
162 LogMsg("DNS64StateMachine: unrecognized DNS64 state %d", inQ
->dns64
.state
);
169 //===========================================================================================================================
170 // DNS64AnswerCurrentQuestion
171 //===========================================================================================================================
173 mDNSexport mStatus
DNS64AnswerCurrentQuestion(mDNS
*m
, const ResourceRecord
*inRR
, QC_result inResult
)
176 ResourceRecord newRR
;
178 nw_nat64_prefix_t
* prefixes
= NULL
;
179 uint32_t prefixCount
;
181 struct in_addr v4Addr
;
182 struct in6_addr synthV6
;
183 DNSQuestion
* const q
= m
->CurrentQuestion
;
185 require_action_quiet(q
->qDNSServer
, exit
, err
= mStatus_BadParamErr
);
187 err
= _DNS64GetPrefixes(m
, q
->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 q
->QuestionCallback(m
, q
, &newRR
, inResult
);
203 if (m
->CurrentQuestion
!= q
) break;
206 err
= mStatus_NoError
;
209 if (prefixes
) free(prefixes
);
213 //===========================================================================================================================
214 // DNS64HandleNewQuestion
215 //===========================================================================================================================
217 mDNSexport
void DNS64HandleNewQuestion(mDNS
*m
, DNSQuestion
*inQ
)
219 if (inQ
->dns64
.state
== kDNS64State_QueryPTR
)
221 struct in6_addr v6Addr
;
223 inQ
->dns64
.state
= kDNS64State_ReverseIPv6
;
224 if (inQ
->qDNSServer
&& _DNS64GetReverseIPv6Addr(&inQ
->qname
, &v6Addr
))
227 nw_nat64_prefix_t
* prefixes
;
228 uint32_t prefixCount
;
230 struct in_addr v4Addr
;
231 char qnameStr
[MAX_REVERSE_MAPPING_NAME_V4
];
233 err
= _DNS64GetPrefixes(m
, inQ
->qDNSServer
->resGroupID
, &prefixes
, &prefixCount
);
234 require_noerr_quiet(err
, exit
);
236 for (i
= 0; i
< prefixCount
; i
++)
238 if (nw_nat64_extract_v4(&prefixes
[i
], &v6Addr
, &v4Addr
))
240 const mDNSu8
* const a
= (const mDNSu8
*)&v4Addr
.s_addr
;
242 snprintf(qnameStr
, sizeof(qnameStr
), "%u.%u.%u.%u.in-addr.arpa.", a
[3], a
[2], a
[1], a
[0]);
243 MakeDomainNameFromDNSNameString(&inQ
->qname
, qnameStr
);
244 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
245 inQ
->dns64
.state
= kDNS64State_ReverseIPv4
;
257 //===========================================================================================================================
259 //===========================================================================================================================
261 // Called from mDNS_StopQuery_internal().
263 mDNSexport
void DNS64ResetState(DNSQuestion
*inQ
)
265 switch (inQ
->dns64
.state
)
267 case kDNS64State_PrefixDiscoveryPTR
:
268 inQ
->qtype
= kDNSType_PTR
; // Restore qtype to PTR and fall through.
270 case kDNS64State_PrefixDiscovery
:
271 memcpy(&inQ
->qname
, inQ
->dns64
.qnameStash
, sizeof(inQ
->dns64
.qnameStash
)); // Restore the previous qname.
272 inQ
->qnamehash
= DomainNameHashValue(&inQ
->qname
);
275 case kDNS64State_QueryA
:
276 case kDNS64State_QueryA2
:
277 inQ
->qtype
= kDNSType_AAAA
; // Restore qtype to AAAA.
280 // Do nothing for the other states.
282 case kDNS64State_Initial
:
283 case kDNS64State_QueryAAAA
:
284 case kDNS64State_QueryPTR
:
285 case kDNS64State_ReverseIPv4
:
286 case kDNS64State_ReverseIPv6
:
290 LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ
->dns64
.state
);
293 inQ
->dns64
.state
= kDNS64State_Initial
;
296 //===========================================================================================================================
297 // DNS64RestartQuestions
298 //===========================================================================================================================
300 mDNSexport
void DNS64RestartQuestions(mDNS
*m
)
303 DNSQuestion
* restartList
= NULL
;
304 DNSServer
* newServer
;
306 m
->RestartQuestion
= m
->Questions
;
307 while (m
->RestartQuestion
)
309 q
= m
->RestartQuestion
;
310 m
->RestartQuestion
= q
->next
;
311 if (q
->dns64
.state
!= kDNS64State_Initial
)
313 SetValidDNSServers(m
, q
);
314 q
->triedAllServersOnce
= mDNSfalse
;
315 newServer
= GetServerForQuestion(m
, q
);
316 if (q
->qDNSServer
!= newServer
)
318 if (!CacheRecordRmvEventsForQuestion(m
, q
))
320 LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
324 LogInfo("DNS64RestartQuestions: Stop question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
325 mDNS_StopQuery_internal(m
, q
);
326 q
->next
= restartList
;
332 while ((q
= restartList
) != NULL
)
334 restartList
= restartList
->next
;
336 LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
337 mDNS_StartQuery_internal(m
, q
);
341 //===========================================================================================================================
342 // _DNS64GetIPv6Addrs
343 //===========================================================================================================================
345 #define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID) \
346 ((RR)->rDNSServer && \
347 ((RR)->rDNSServer->resGroupID == RES_GROUP_ID) && \
348 ((RR)->rrtype == kDNSType_AAAA) && \
349 ((RR)->RecordType != kDNSRecordTypePacketNegative) && \
352 mDNSlocal mStatus
_DNS64GetIPv6Addrs(mDNS
*m
, const mDNSu32 inResGroupID
, struct in6_addr
**outAddrs
, uint32_t *outAddrCount
)
355 const CacheGroup
* cg
;
356 const CacheRecord
* cr
;
357 struct in6_addr
* addrs
= NULL
;
359 uint32_t recordCount
;
361 cg
= CacheGroupForName(m
, _DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN
);
362 require_action_quiet(cg
, exit
, err
= mStatus_NoSuchRecord
);
365 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
367 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
372 require_action_quiet(recordCount
> 0, exit
, err
= mStatus_NoSuchRecord
);
374 addrs
= (struct in6_addr
*)calloc(recordCount
, sizeof(*addrs
));
375 require_action_quiet(addrs
, exit
, err
= mStatus_NoMemoryErr
);
378 for (cr
= cg
->members
; cr
&& (addrCount
< recordCount
); cr
= cr
->next
)
380 if (IsPositiveAAAAFromResGroup(&cr
->resrec
, inResGroupID
))
382 memcpy(addrs
[addrCount
].s6_addr
, cr
->resrec
.rdata
->u
.ipv6
.b
, 16);
389 *outAddrCount
= addrCount
;
390 err
= mStatus_NoError
;
393 if (addrs
) free(addrs
);
397 //===========================================================================================================================
399 //===========================================================================================================================
401 mDNSlocal mStatus
_DNS64GetPrefixes(mDNS
*m
, mDNSu32 inResGroupID
, nw_nat64_prefix_t
**outPrefixes
, uint32_t *outPrefixCount
)
404 struct in6_addr
* v6Addrs
;
405 uint32_t v6AddrCount
;
406 nw_nat64_prefix_t
* prefixes
;
409 err
= _DNS64GetIPv6Addrs(m
, inResGroupID
, &v6Addrs
, &v6AddrCount
);
410 require_noerr_quiet(err
, exit
);
412 prefixCount
= nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs
, v6AddrCount
, &prefixes
);
414 require_action_quiet(prefixCount
> 0, exit
, err
= mStatus_UnknownErr
);
416 *outPrefixes
= prefixes
;
417 *outPrefixCount
= prefixCount
;
423 //===========================================================================================================================
424 // _DNS64GetReverseIPv6Addr
425 //===========================================================================================================================
427 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
429 mDNSlocal mDNSBool
_DNS64GetReverseIPv6Addr(const domainname
*inQName
, struct in6_addr
*outAddr
)
437 // 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
438 // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order.
439 // See <https://tools.ietf.org/html/rfc3596#section-2.5>.
441 ptr
= (const mDNSu8
*)inQName
;
442 for (i
= 0; i
< 16; i
++)
444 if (*ptr
++ != 1) return (mDNSfalse
); // If this label's length is not 1, then fail.
445 c
= *ptr
++; // Get label byte.
446 if ( (c
>= '0') && (c
<= '9')) nl
= c
- '0'; // If it's a hex digit, get its numeric value.
447 else if ((c
>= 'a') && (c
<= 'f')) nl
= (c
- 'a') + 10;
448 else if ((c
>= 'A') && (c
<= 'F')) nl
= (c
- 'A') + 10;
449 else return (mDNSfalse
); // Otherwise, fail.
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')) nu
= c
- '0'; // If it's a hex digit, get its numeric value.
454 else if ((c
>= 'a') && (c
<= 'f')) nu
= (c
- 'a') + 10;
455 else if ((c
>= 'A') && (c
<= 'F')) nu
= (c
- 'A') + 10;
456 else return (mDNSfalse
); // Otherwise, fail.
458 if (outAddr
) outAddr
->s6_addr
[15 - i
] = (mDNSu8
)((nu
<< 4) | nl
);
461 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
463 if (!SameDomainName((const domainname
*)ptr
, kReverseIPv6Domain
)) return (mDNSfalse
);
468 //===========================================================================================================================
469 // _DNS64IPv4OnlyFQDNHash
470 //===========================================================================================================================
472 mDNSlocal mDNSu32
_DNS64IPv4OnlyFQDNHash(void)
474 static dispatch_once_t sHashOnce
;
475 static mDNSu32 sHash
;
477 dispatch_once(&sHashOnce
, ^{ sHash
= DomainNameHashValue(kDNS64IPv4OnlyFQDN
); });
482 //===========================================================================================================================
483 // _DNS64RestartQuestion
484 //===========================================================================================================================
486 mDNSlocal
void _DNS64RestartQuestion(mDNS
*const m
, DNSQuestion
*inQ
, DNS64State inNewState
)
488 mDNS_StopQuery_internal(m
, inQ
);
490 inQ
->dns64
.state
= inNewState
;
491 switch (inQ
->dns64
.state
)
493 case kDNS64State_Initial
:
496 case kDNS64State_PrefixDiscovery
:
497 case kDNS64State_PrefixDiscoveryPTR
:
498 // Save the first 15 bytes from the original qname that are displaced by setting qname to "ipv4only.arpa.".
500 memcpy(inQ
->dns64
.qnameStash
, &inQ
->qname
, sizeof(inQ
->dns64
.qnameStash
));
501 AssignDomainName(&inQ
->qname
, kDNS64IPv4OnlyFQDN
);
502 inQ
->qnamehash
= _DNS64IPv4OnlyFQDNHash();
503 inQ
->qtype
= kDNSType_AAAA
;
506 case kDNS64State_QueryA
:
507 case kDNS64State_QueryA2
:
508 inQ
->qtype
= kDNSType_A
;
511 case kDNS64State_QueryPTR
:
512 case kDNS64State_ReverseIPv4
:
513 case kDNS64State_ReverseIPv6
:
514 inQ
->qtype
= kDNSType_PTR
;
517 case kDNS64State_QueryAAAA
:
518 inQ
->qtype
= kDNSType_AAAA
;
522 LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ
->dns64
.state
);
526 mDNS_StartQuery_internal(m
, inQ
);
529 //===========================================================================================================================
530 // _DNS64InterfaceSupportsNAT64
531 //===========================================================================================================================
533 mDNSlocal mDNSBool
_DNS64InterfaceSupportsNAT64(uint32_t inIfIndex
)
535 mdns_interface_monitor_t monitor
= GetInterfaceMonitorForIndex(inIfIndex
);
536 if (monitor
&& !mdns_interface_monitor_has_ipv4_connectivity(monitor
) &&
537 mdns_interface_monitor_has_ipv6_connectivity(monitor
))
544 //===========================================================================================================================
545 // _DNS64TestIPv6Synthesis
546 //===========================================================================================================================
548 mDNSlocal mDNSBool
_DNS64TestIPv6Synthesis(mDNS
*m
, mDNSu32 inResGroupID
, const mDNSv4Addr
*inV4Addr
)
551 nw_nat64_prefix_t
* prefixes
= NULL
;
552 uint32_t prefixCount
;
554 struct in_addr v4Addr
;
555 struct in6_addr synthV6
;
556 mDNSBool result
= mDNSfalse
;
558 err
= _DNS64GetPrefixes(m
, inResGroupID
, &prefixes
, &prefixCount
);
559 require_noerr_quiet(err
, exit
);
561 memcpy(&v4Addr
.s_addr
, inV4Addr
->b
, 4);
562 for (i
= 0; i
< prefixCount
; i
++)
564 if (nw_nat64_synthesize_v6(&prefixes
[i
], &v4Addr
, &synthV6
))
572 if (prefixes
) free(prefixes
);
575 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNS64)