]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/DNS64.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / DNS64.c
1 /*
2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include "DNS64.h"
18
19 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
20
21 #include <AssertMacros.h>
22 #include <nw/private.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "dns_sd.h"
27 #include "dns_sd_internal.h"
28 #include "mDNSMacOSX.h"
29 #include "uDNS.h"
30
31 //===========================================================================================================================
32 // Constants
33 //===========================================================================================================================
34
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.
38
39 #define sizeof_field(TYPE, FIELD) sizeof(((TYPE *)0)->FIELD) // From CoreUtils.h
40
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);
44
45 //===========================================================================================================================
46 // Local Prototypes
47 //===========================================================================================================================
48
49 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
50 mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, mdns_dns_service_t inDNSService, struct in6_addr **outAddrs, uint32_t *outAddrCount);
51 #else
52 mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
53 #endif
54 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
55 mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mdns_dns_service_t inDNSService, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
56 #else
57 mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
58 #endif
59 mDNSlocal mDNSu32 _DNS64IPv4OnlyFQDNHash(void);
60 mDNSlocal void _DNS64RestartQuestion(mDNS *m, DNSQuestion *q, DNS64State newState);
61 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
62 mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(mdns_dns_service_t inDNSService);
63 #else
64 mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(uint32_t inIfIndex);
65 #endif
66 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
67 mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mdns_dns_service_t inDNSService, const mDNSv4Addr *inV4Addr);
68 #else
69 mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr);
70 #endif
71
72 //===========================================================================================================================
73 // DNS64StateMachine
74 //===========================================================================================================================
75
76 mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult)
77 {
78 // If this is an mDNS question, then exit early. DNS64 is only for unicast DNS questions.
79
80 if (mDNSOpaque16IsZero(inQ->TargetQID)) return (mDNSfalse);
81
82 switch (inQ->dns64.state)
83 {
84 // If this question is going to be answered with a negative AAAA record and the question is not for "ipv4only.arpa." and
85 // the question's DNS server's interface supports NAT64, then restart the question as an "ipv4only.arpa." AAAA question.
86 // Otherwise, do nothing.
87
88 case kDNS64State_Initial:
89 if ((inRR->RecordType == kDNSRecordTypePacketNegative) && (inResult == QC_add))
90 {
91 if ((inQ->qtype == kDNSType_AAAA) &&
92 (inRR->rrtype == kDNSType_AAAA) &&
93 (inRR->rrclass == kDNSClass_IN) &&
94 ((inQ->qnamehash != _DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
95 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
96 inQ->dnsservice && _DNS64InterfaceSupportsNAT64(inQ->dnsservice))
97 #else
98 inQ->qDNSServer &&
99 _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)))
100 #endif
101 {
102 _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
103 return (mDNStrue);
104 }
105 else if ((inQ->qtype == kDNSType_PTR) &&
106 (inRR->rrtype == kDNSType_PTR) &&
107 (inRR->rrclass == kDNSClass_IN) &&
108 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
109 inQ->dnsservice && _DNS64InterfaceSupportsNAT64(inQ->dnsservice) &&
110 #else
111 inQ->qDNSServer &&
112 _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)) &&
113 #endif
114 GetReverseIPv6Addr(&inQ->qname, NULL))
115 {
116 _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
117 return (mDNStrue);
118 }
119 }
120 break;
121
122 // If the "ipv4only.arpa." question is going to be answered with a positive AAAA record, then restart it as a question
123 // for an A record with the original AAAA qname.
124 // Otherwise, restart the question for the original AAAA record.
125
126 case kDNS64State_PrefixDiscovery:
127 if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
128 (inResult == QC_add) &&
129 (inRR->rrtype == kDNSType_AAAA) &&
130 (inRR->rrclass == kDNSClass_IN))
131 {
132 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
133 }
134 else
135 {
136 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
137 }
138 return (mDNStrue);
139
140 // The "ipv4only.arpa." question is going to be answered. Restart the question now. DNS64HandleNewQuestion() will decide
141 // whether or not to change it to a reverse IPv4 question.
142
143 case kDNS64State_PrefixDiscoveryPTR:
144 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
145 return (mDNStrue);
146
147 // If this question is going to be answered with a CNAME, then do nothing.
148 // If this question is going to be answered with a positive A record that's synthesizable, then set the state to
149 // QueryARecord2.
150 // Otherwise, restart the question for the original AAAA record.
151
152 case kDNS64State_QueryA:
153 if (inRR->rrtype != kDNSType_CNAME)
154 {
155 if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
156 (inResult == QC_add) &&
157 (inRR->rrtype == kDNSType_A) &&
158 (inRR->rrclass == kDNSClass_IN) &&
159 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
160 inQ->dnsservice &&
161 _DNS64TestIPv6Synthesis(m, inQ->dnsservice, &inRR->rdata->u.ipv4))
162 #else
163 inQ->qDNSServer &&
164 _DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
165 #endif
166 {
167 inQ->dns64.state = kDNS64State_QueryA2;
168 }
169 else
170 {
171 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
172 return (mDNStrue);
173 }
174 }
175 break;
176
177 // For all other states, do nothing.
178
179 case kDNS64State_QueryA2:
180 case kDNS64State_QueryAAAA:
181 case kDNS64State_QueryPTR:
182 case kDNS64State_ReverseIPv4:
183 case kDNS64State_ReverseIPv6:
184 break;
185
186 default:
187 LogMsg("DNS64StateMachine: unrecognized DNS64 state %d", inQ->dns64.state);
188 break;
189 }
190
191 return (mDNSfalse);
192 }
193
194 //===========================================================================================================================
195 // DNS64AnswerCurrentQuestion
196 //===========================================================================================================================
197
198 mDNSexport mStatus DNS64AnswerCurrentQuestion(mDNS *m, const ResourceRecord *inRR, QC_result inResult)
199 {
200 mStatus err;
201 ResourceRecord newRR;
202 RData rdata;
203 nw_nat64_prefix_t * prefixes = NULL;
204 uint32_t prefixCount;
205 uint32_t i;
206 struct in_addr v4Addr;
207 struct in6_addr synthV6;
208 DNSQuestion * const q = m->CurrentQuestion;
209
210 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
211 require_action_quiet(q->dnsservice, exit, err = mStatus_BadParamErr);
212 #else
213 require_action_quiet(q->qDNSServer, exit, err = mStatus_BadParamErr);
214 #endif
215
216 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
217 err = _DNS64GetPrefixes(m, q->dnsservice, &prefixes, &prefixCount);
218 #else
219 err = _DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
220 #endif
221 require_noerr_quiet(err, exit);
222
223 newRR = *inRR;
224 newRR.rrtype = kDNSType_AAAA;
225 newRR.rdlength = 16;
226 rdata.MaxRDLength = newRR.rdlength;
227 newRR.rdata = &rdata;
228
229 memcpy(&v4Addr.s_addr, inRR->rdata->u.ipv4.b, 4);
230 for (i = 0; i < prefixCount; i++)
231 {
232 if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
233 {
234 memcpy(rdata.u.ipv6.b, synthV6.s6_addr, 16);
235 q->QuestionCallback(m, q, &newRR, inResult);
236 if (m->CurrentQuestion != q) break;
237 }
238 }
239 err = mStatus_NoError;
240
241 exit:
242 if (prefixes) free(prefixes);
243 return (err);
244 }
245
246 //===========================================================================================================================
247 // DNS64HandleNewQuestion
248 //===========================================================================================================================
249
250 mDNSexport void DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ)
251 {
252 if (inQ->dns64.state == kDNS64State_QueryPTR)
253 {
254 struct in6_addr v6Addr;
255
256 inQ->dns64.state = kDNS64State_ReverseIPv6;
257 memset(&v6Addr, 0, sizeof(v6Addr));
258 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
259 if (inQ->dnsservice && GetReverseIPv6Addr(&inQ->qname, v6Addr.s6_addr))
260 #else
261 if (inQ->qDNSServer && GetReverseIPv6Addr(&inQ->qname, v6Addr.s6_addr))
262 #endif
263 {
264 mStatus err;
265 nw_nat64_prefix_t * prefixes;
266 uint32_t prefixCount;
267 uint32_t i;
268 struct in_addr v4Addr;
269 char qnameStr[MAX_REVERSE_MAPPING_NAME_V4];
270
271 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
272 err = _DNS64GetPrefixes(m, inQ->dnsservice, &prefixes, &prefixCount);
273 #else
274 err = _DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
275 #endif
276 require_noerr_quiet(err, exit);
277
278 for (i = 0; i < prefixCount; i++)
279 {
280 if (nw_nat64_extract_v4(&prefixes[i], &v6Addr, &v4Addr))
281 {
282 const mDNSu8 * const a = (const mDNSu8 *)&v4Addr.s_addr;
283
284 snprintf(qnameStr, sizeof(qnameStr), "%u.%u.%u.%u.in-addr.arpa.", a[3], a[2], a[1], a[0]);
285 MakeDomainNameFromDNSNameString(&inQ->qname, qnameStr);
286 inQ->qnamehash = DomainNameHashValue(&inQ->qname);
287 inQ->dns64.state = kDNS64State_ReverseIPv4;
288 break;
289 }
290 }
291 free(prefixes);
292 }
293 }
294
295 exit:
296 return;
297 }
298
299 //===========================================================================================================================
300 // DNS64ResetState
301 //===========================================================================================================================
302
303 // Called from mDNS_StopQuery_internal().
304
305 mDNSexport void DNS64ResetState(DNSQuestion *inQ)
306 {
307 switch (inQ->dns64.state)
308 {
309 case kDNS64State_PrefixDiscoveryPTR:
310 inQ->qtype = kDNSType_PTR; // Restore qtype to PTR and fall through.
311
312 case kDNS64State_PrefixDiscovery:
313 memcpy(&inQ->qname, inQ->dns64.qnameStash, sizeof(inQ->dns64.qnameStash)); // Restore the previous qname.
314 inQ->qnamehash = DomainNameHashValue(&inQ->qname);
315 break;
316
317 case kDNS64State_QueryA:
318 case kDNS64State_QueryA2:
319 inQ->qtype = kDNSType_AAAA; // Restore qtype to AAAA.
320 break;
321
322 // Do nothing for the other states.
323
324 case kDNS64State_Initial:
325 case kDNS64State_QueryAAAA:
326 case kDNS64State_QueryPTR:
327 case kDNS64State_ReverseIPv4:
328 case kDNS64State_ReverseIPv6:
329 break;
330
331 default:
332 LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ->dns64.state);
333 break;
334 }
335 inQ->dns64.state = kDNS64State_Initial;
336 }
337
338 //===========================================================================================================================
339 // DNS64RestartQuestions
340 //===========================================================================================================================
341
342 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
343 mDNSexport void DNS64RestartQuestions(mDNS *m)
344 {
345 DNSQuestion * q;
346 DNSQuestion * restartList = NULL;
347 DNSServer * newServer;
348
349 m->RestartQuestion = m->Questions;
350 while (m->RestartQuestion)
351 {
352 q = m->RestartQuestion;
353 m->RestartQuestion = q->next;
354 if (q->dns64.state != kDNS64State_Initial)
355 {
356 SetValidDNSServers(m, q);
357 q->triedAllServersOnce = mDNSfalse;
358 newServer = GetServerForQuestion(m, q);
359 if (q->qDNSServer != newServer)
360 {
361 if (!CacheRecordRmvEventsForQuestion(m, q))
362 {
363 LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
364 }
365 else
366 {
367 LogInfo("DNS64RestartQuestions: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
368 mDNS_StopQuery_internal(m, q);
369 q->next = restartList;
370 restartList = q;
371 }
372 }
373 }
374 }
375 while ((q = restartList) != NULL)
376 {
377 restartList = restartList->next;
378 q->next = NULL;
379 LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
380 mDNS_StartQuery_internal(m, q);
381 }
382 }
383 #endif
384
385 //===========================================================================================================================
386 // _DNS64GetIPv6Addrs
387 //===========================================================================================================================
388
389 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
390 #define IsPositiveAAAAFromDNSService(RR, DNS_SERVICE) \
391 (((RR)->dnsservice == (DNS_SERVICE)) && \
392 ((RR)->rrtype == kDNSType_AAAA) && \
393 ((RR)->RecordType != kDNSRecordTypePacketNegative) && \
394 !(RR)->InterfaceID)
395 #else
396 #define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID) \
397 ((RR)->rDNSServer && \
398 ((RR)->rDNSServer->resGroupID == RES_GROUP_ID) && \
399 ((RR)->rrtype == kDNSType_AAAA) && \
400 ((RR)->RecordType != kDNSRecordTypePacketNegative) && \
401 !(RR)->InterfaceID)
402 #endif
403
404 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
405 mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, mdns_dns_service_t inDNSService, struct in6_addr **outAddrs, uint32_t *outAddrCount)
406 #else
407 mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
408 #endif
409 {
410 mStatus err;
411 const CacheGroup * cg;
412 const CacheRecord * cr;
413 struct in6_addr * addrs = NULL;
414 uint32_t addrCount;
415 uint32_t recordCount;
416
417 cg = CacheGroupForName(m, _DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
418 require_action_quiet(cg, exit, err = mStatus_NoSuchRecord);
419
420 recordCount = 0;
421 for (cr = cg->members; cr; cr = cr->next)
422 {
423 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
424 if (IsPositiveAAAAFromDNSService(&cr->resrec, inDNSService))
425 #else
426 if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
427 #endif
428 {
429 recordCount++;
430 }
431 }
432 require_action_quiet(recordCount > 0, exit, err = mStatus_NoSuchRecord);
433
434 addrs = (struct in6_addr *)calloc(recordCount, sizeof(*addrs));
435 require_action_quiet(addrs, exit, err = mStatus_NoMemoryErr);
436
437 addrCount = 0;
438 for (cr = cg->members; cr && (addrCount < recordCount); cr = cr->next)
439 {
440 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
441 if (IsPositiveAAAAFromDNSService(&cr->resrec, inDNSService))
442 #else
443 if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
444 #endif
445 {
446 memcpy(addrs[addrCount].s6_addr, cr->resrec.rdata->u.ipv6.b, 16);
447 addrCount++;
448 }
449 }
450
451 *outAddrs = addrs;
452 addrs = NULL;
453 *outAddrCount = addrCount;
454 err = mStatus_NoError;
455
456 exit:
457 if (addrs) free(addrs);
458 return (err);
459 }
460
461 //===========================================================================================================================
462 // _DNS64GetPrefixes
463 //===========================================================================================================================
464
465 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
466 mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mdns_dns_service_t inDNSService, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
467 #else
468 mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
469 #endif
470 {
471 mStatus err;
472 struct in6_addr * v6Addrs;
473 uint32_t v6AddrCount;
474 nw_nat64_prefix_t * prefixes;
475 int32_t prefixCount;
476
477 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
478 err = _DNS64GetIPv6Addrs(m, inDNSService, &v6Addrs, &v6AddrCount);
479 #else
480 err = _DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
481 #endif
482 require_noerr_quiet(err, exit);
483
484 prefixCount = nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs, v6AddrCount, &prefixes);
485 free(v6Addrs);
486 require_action_quiet(prefixCount > 0, exit, err = mStatus_UnknownErr);
487
488 *outPrefixes = prefixes;
489 *outPrefixCount = prefixCount;
490
491 exit:
492 return (err);
493 }
494
495 //===========================================================================================================================
496 // _DNS64IPv4OnlyFQDNHash
497 //===========================================================================================================================
498
499 mDNSlocal mDNSu32 _DNS64IPv4OnlyFQDNHash(void)
500 {
501 static dispatch_once_t sHashOnce;
502 static mDNSu32 sHash;
503
504 dispatch_once(&sHashOnce, ^{ sHash = DomainNameHashValue(kDNS64IPv4OnlyFQDN); });
505
506 return (sHash);
507 }
508
509 //===========================================================================================================================
510 // _DNS64RestartQuestion
511 //===========================================================================================================================
512
513 mDNSlocal void _DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
514 {
515 mDNS_StopQuery_internal(m, inQ);
516
517 inQ->dns64.state = inNewState;
518 switch (inQ->dns64.state)
519 {
520 case kDNS64State_Initial:
521 break;
522
523 case kDNS64State_PrefixDiscovery:
524 case kDNS64State_PrefixDiscoveryPTR:
525 // Save the first 15 bytes from the original qname that are displaced by setting qname to "ipv4only.arpa.".
526
527 memcpy(inQ->dns64.qnameStash, &inQ->qname, sizeof(inQ->dns64.qnameStash));
528 AssignDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN);
529 inQ->qnamehash = _DNS64IPv4OnlyFQDNHash();
530 inQ->qtype = kDNSType_AAAA;
531 break;
532
533 case kDNS64State_QueryA:
534 case kDNS64State_QueryA2:
535 inQ->qtype = kDNSType_A;
536 break;
537
538 case kDNS64State_QueryPTR:
539 case kDNS64State_ReverseIPv4:
540 case kDNS64State_ReverseIPv6:
541 inQ->qtype = kDNSType_PTR;
542 break;
543
544 case kDNS64State_QueryAAAA:
545 inQ->qtype = kDNSType_AAAA;
546 break;
547
548 default:
549 LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ->dns64.state);
550 break;
551 }
552
553 mDNS_StartQuery_internal(m, inQ);
554 }
555
556 //===========================================================================================================================
557 // _DNS64InterfaceSupportsNAT64
558 //===========================================================================================================================
559
560 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
561 mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(mdns_dns_service_t inDNSService)
562 {
563 if (!mdns_dns_service_interface_has_ipv4_connectivity(inDNSService) &&
564 mdns_dns_service_interface_has_ipv6_connectivity(inDNSService))
565 {
566 return (mDNStrue);
567 }
568 else
569 {
570 return (mDNSfalse);
571 }
572 }
573 #else
574 mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(uint32_t inIfIndex)
575 {
576 mdns_interface_monitor_t monitor = GetInterfaceMonitorForIndex(inIfIndex);
577 if (monitor && !mdns_interface_monitor_has_ipv4_connectivity(monitor) &&
578 mdns_interface_monitor_has_ipv6_connectivity(monitor))
579 {
580 return (mDNStrue);
581 }
582 return (mDNSfalse);
583 }
584 #endif
585
586 //===========================================================================================================================
587 // _DNS64TestIPv6Synthesis
588 //===========================================================================================================================
589
590 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
591 mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mdns_dns_service_t inDNSService, const mDNSv4Addr *inV4Addr)
592 #else
593 mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
594 #endif
595 {
596 mStatus err;
597 nw_nat64_prefix_t * prefixes = NULL;
598 uint32_t prefixCount;
599 uint32_t i;
600 struct in_addr v4Addr;
601 struct in6_addr synthV6;
602 mDNSBool result = mDNSfalse;
603
604 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
605 err = _DNS64GetPrefixes(m, inDNSService, &prefixes, &prefixCount);
606 #else
607 err = _DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
608 #endif
609 require_noerr_quiet(err, exit);
610
611 memcpy(&v4Addr.s_addr, inV4Addr->b, 4);
612 for (i = 0; i < prefixCount; i++)
613 {
614 if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
615 {
616 result = mDNStrue;
617 break;
618 }
619 }
620
621 exit:
622 if (prefixes) free(prefixes);
623 return (result);
624 }
625 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNS64)