]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/DNS64.c
mDNSResponder-1096.0.2.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 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);
56
57 //===========================================================================================================================
58 // DNS64StateMachine
59 //===========================================================================================================================
60
61 mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult)
62 {
63 // If this is an mDNS question, then exit early. DNS64 is only for unicast DNS questions.
64
65 if (mDNSOpaque16IsZero(inQ->TargetQID)) return (mDNSfalse);
66
67 switch (inQ->dns64.state)
68 {
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.
72
73 case kDNS64State_Initial:
74 if ((inRR->RecordType == kDNSRecordTypePacketNegative) && (inResult == QC_add))
75 {
76 if ((inQ->qtype == kDNSType_AAAA) &&
77 (inRR->rrtype == kDNSType_AAAA) &&
78 (inRR->rrclass == kDNSClass_IN) &&
79 ((inQ->qnamehash != _DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
80 inQ->qDNSServer &&
81 _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)))
82 {
83 _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
84 return (mDNStrue);
85 }
86 else if ((inQ->qtype == kDNSType_PTR) &&
87 (inRR->rrtype == kDNSType_PTR) &&
88 (inRR->rrclass == kDNSClass_IN) &&
89 inQ->qDNSServer &&
90 _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)) &&
91 _DNS64GetReverseIPv6Addr(&inQ->qname, NULL))
92 {
93 _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
94 return (mDNStrue);
95 }
96 }
97 break;
98
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.
102
103 case kDNS64State_PrefixDiscovery:
104 if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
105 (inResult == QC_add) &&
106 (inRR->rrtype == kDNSType_AAAA) &&
107 (inRR->rrclass == kDNSClass_IN))
108 {
109 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
110 return (mDNStrue);
111 }
112 else
113 {
114 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
115 return (mDNStrue);
116 }
117 break;
118
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.
121
122 case kDNS64State_PrefixDiscoveryPTR:
123 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
124 return (mDNStrue);
125 break;
126
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
129 // QueryARecord2.
130 // Otherwise, restart the question for the original AAAA record.
131
132 case kDNS64State_QueryA:
133 if (inRR->rrtype != kDNSType_CNAME)
134 {
135 if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
136 (inResult == QC_add) &&
137 (inRR->rrtype == kDNSType_A) &&
138 (inRR->rrclass == kDNSClass_IN) &&
139 inQ->qDNSServer &&
140 _DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
141 {
142 inQ->dns64.state = kDNS64State_QueryA2;
143 }
144 else
145 {
146 _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
147 return (mDNStrue);
148 }
149 }
150 break;
151
152 // For all other states, do nothing.
153
154 case kDNS64State_QueryA2:
155 case kDNS64State_QueryAAAA:
156 case kDNS64State_QueryPTR:
157 case kDNS64State_ReverseIPv4:
158 case kDNS64State_ReverseIPv6:
159 break;
160
161 default:
162 LogMsg("DNS64StateMachine: unrecognized DNS64 state %d", inQ->dns64.state);
163 break;
164 }
165
166 return (mDNSfalse);
167 }
168
169 //===========================================================================================================================
170 // DNS64AnswerCurrentQuestion
171 //===========================================================================================================================
172
173 mDNSexport mStatus DNS64AnswerCurrentQuestion(mDNS *m, const ResourceRecord *inRR, QC_result inResult)
174 {
175 mStatus err;
176 ResourceRecord newRR;
177 RData rdata;
178 nw_nat64_prefix_t * prefixes = NULL;
179 uint32_t prefixCount;
180 uint32_t i;
181 struct in_addr v4Addr;
182 struct in6_addr synthV6;
183 DNSQuestion * const q = m->CurrentQuestion;
184
185 require_action_quiet(q->qDNSServer, exit, err = mStatus_BadParamErr);
186
187 err = _DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
188 require_noerr_quiet(err, exit);
189
190 newRR = *inRR;
191 newRR.rrtype = kDNSType_AAAA;
192 newRR.rdlength = 16;
193 rdata.MaxRDLength = newRR.rdlength;
194 newRR.rdata = &rdata;
195
196 memcpy(&v4Addr.s_addr, inRR->rdata->u.ipv4.b, 4);
197 for (i = 0; i < prefixCount; i++)
198 {
199 if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
200 {
201 memcpy(rdata.u.ipv6.b, synthV6.s6_addr, 16);
202 q->QuestionCallback(m, q, &newRR, inResult);
203 if (m->CurrentQuestion != q) break;
204 }
205 }
206 err = mStatus_NoError;
207
208 exit:
209 if (prefixes) free(prefixes);
210 return (err);
211 }
212
213 //===========================================================================================================================
214 // DNS64HandleNewQuestion
215 //===========================================================================================================================
216
217 mDNSexport void DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ)
218 {
219 if (inQ->dns64.state == kDNS64State_QueryPTR)
220 {
221 struct in6_addr v6Addr;
222
223 inQ->dns64.state = kDNS64State_ReverseIPv6;
224 if (inQ->qDNSServer && _DNS64GetReverseIPv6Addr(&inQ->qname, &v6Addr))
225 {
226 mStatus err;
227 nw_nat64_prefix_t * prefixes;
228 uint32_t prefixCount;
229 uint32_t i;
230 struct in_addr v4Addr;
231 char qnameStr[MAX_REVERSE_MAPPING_NAME_V4];
232
233 err = _DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
234 require_noerr_quiet(err, exit);
235
236 for (i = 0; i < prefixCount; i++)
237 {
238 if (nw_nat64_extract_v4(&prefixes[i], &v6Addr, &v4Addr))
239 {
240 const mDNSu8 * const a = (const mDNSu8 *)&v4Addr.s_addr;
241
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;
246 break;
247 }
248 }
249 free(prefixes);
250 }
251 }
252
253 exit:
254 return;
255 }
256
257 //===========================================================================================================================
258 // DNS64ResetState
259 //===========================================================================================================================
260
261 // Called from mDNS_StopQuery_internal().
262
263 mDNSexport void DNS64ResetState(DNSQuestion *inQ)
264 {
265 switch (inQ->dns64.state)
266 {
267 case kDNS64State_PrefixDiscoveryPTR:
268 inQ->qtype = kDNSType_PTR; // Restore qtype to PTR and fall through.
269
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);
273 break;
274
275 case kDNS64State_QueryA:
276 case kDNS64State_QueryA2:
277 inQ->qtype = kDNSType_AAAA; // Restore qtype to AAAA.
278 break;
279
280 // Do nothing for the other states.
281
282 case kDNS64State_Initial:
283 case kDNS64State_QueryAAAA:
284 case kDNS64State_QueryPTR:
285 case kDNS64State_ReverseIPv4:
286 case kDNS64State_ReverseIPv6:
287 break;
288
289 default:
290 LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ->dns64.state);
291 break;
292 }
293 inQ->dns64.state = kDNS64State_Initial;
294 }
295
296 //===========================================================================================================================
297 // DNS64RestartQuestions
298 //===========================================================================================================================
299
300 mDNSexport void DNS64RestartQuestions(mDNS *m)
301 {
302 DNSQuestion * q;
303 DNSQuestion * restartList = NULL;
304 DNSServer * newServer;
305
306 m->RestartQuestion = m->Questions;
307 while (m->RestartQuestion)
308 {
309 q = m->RestartQuestion;
310 m->RestartQuestion = q->next;
311 if (q->dns64.state != kDNS64State_Initial)
312 {
313 SetValidDNSServers(m, q);
314 q->triedAllServersOnce = mDNSfalse;
315 newServer = GetServerForQuestion(m, q);
316 if (q->qDNSServer != newServer)
317 {
318 if (!CacheRecordRmvEventsForQuestion(m, q))
319 {
320 LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
321 }
322 else
323 {
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;
327 restartList = q;
328 }
329 }
330 }
331 }
332 while ((q = restartList) != NULL)
333 {
334 restartList = restartList->next;
335 q->next = NULL;
336 LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
337 mDNS_StartQuery_internal(m, q);
338 }
339 }
340
341 //===========================================================================================================================
342 // _DNS64GetIPv6Addrs
343 //===========================================================================================================================
344
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) && \
350 !(RR)->InterfaceID)
351
352 mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
353 {
354 mStatus err;
355 const CacheGroup * cg;
356 const CacheRecord * cr;
357 struct in6_addr * addrs = NULL;
358 uint32_t addrCount;
359 uint32_t recordCount;
360
361 cg = CacheGroupForName(m, _DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
362 require_action_quiet(cg, exit, err = mStatus_NoSuchRecord);
363
364 recordCount = 0;
365 for (cr = cg->members; cr; cr = cr->next)
366 {
367 if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
368 {
369 recordCount++;
370 }
371 }
372 require_action_quiet(recordCount > 0, exit, err = mStatus_NoSuchRecord);
373
374 addrs = (struct in6_addr *)calloc(recordCount, sizeof(*addrs));
375 require_action_quiet(addrs, exit, err = mStatus_NoMemoryErr);
376
377 addrCount = 0;
378 for (cr = cg->members; cr && (addrCount < recordCount); cr = cr->next)
379 {
380 if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
381 {
382 memcpy(addrs[addrCount].s6_addr, cr->resrec.rdata->u.ipv6.b, 16);
383 addrCount++;
384 }
385 }
386
387 *outAddrs = addrs;
388 addrs = NULL;
389 *outAddrCount = addrCount;
390 err = mStatus_NoError;
391
392 exit:
393 if (addrs) free(addrs);
394 return (err);
395 }
396
397 //===========================================================================================================================
398 // _DNS64GetPrefixes
399 //===========================================================================================================================
400
401 mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
402 {
403 mStatus err;
404 struct in6_addr * v6Addrs;
405 uint32_t v6AddrCount;
406 nw_nat64_prefix_t * prefixes;
407 int32_t prefixCount;
408
409 err = _DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
410 require_noerr_quiet(err, exit);
411
412 prefixCount = nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs, v6AddrCount, &prefixes);
413 free(v6Addrs);
414 require_action_quiet(prefixCount > 0, exit, err = mStatus_UnknownErr);
415
416 *outPrefixes = prefixes;
417 *outPrefixCount = prefixCount;
418
419 exit:
420 return (err);
421 }
422
423 //===========================================================================================================================
424 // _DNS64GetReverseIPv6Addr
425 //===========================================================================================================================
426
427 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
428
429 mDNSlocal mDNSBool _DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr)
430 {
431 const mDNSu8 * ptr;
432 int i;
433 unsigned int c;
434 unsigned int nl;
435 unsigned int nu;
436
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>.
440
441 ptr = (const mDNSu8 *)inQName;
442 for (i = 0; i < 16; i++)
443 {
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.
450
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.
457
458 if (outAddr) outAddr->s6_addr[15 - i] = (mDNSu8)((nu << 4) | nl);
459 }
460
461 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
462
463 if (!SameDomainName((const domainname *)ptr, kReverseIPv6Domain)) return (mDNSfalse);
464
465 return (mDNStrue);
466 }
467
468 //===========================================================================================================================
469 // _DNS64IPv4OnlyFQDNHash
470 //===========================================================================================================================
471
472 mDNSlocal mDNSu32 _DNS64IPv4OnlyFQDNHash(void)
473 {
474 static dispatch_once_t sHashOnce;
475 static mDNSu32 sHash;
476
477 dispatch_once(&sHashOnce, ^{ sHash = DomainNameHashValue(kDNS64IPv4OnlyFQDN); });
478
479 return (sHash);
480 }
481
482 //===========================================================================================================================
483 // _DNS64RestartQuestion
484 //===========================================================================================================================
485
486 mDNSlocal void _DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
487 {
488 mDNS_StopQuery_internal(m, inQ);
489
490 inQ->dns64.state = inNewState;
491 switch (inQ->dns64.state)
492 {
493 case kDNS64State_Initial:
494 break;
495
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.".
499
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;
504 break;
505
506 case kDNS64State_QueryA:
507 case kDNS64State_QueryA2:
508 inQ->qtype = kDNSType_A;
509 break;
510
511 case kDNS64State_QueryPTR:
512 case kDNS64State_ReverseIPv4:
513 case kDNS64State_ReverseIPv6:
514 inQ->qtype = kDNSType_PTR;
515 break;
516
517 case kDNS64State_QueryAAAA:
518 inQ->qtype = kDNSType_AAAA;
519 break;
520
521 default:
522 LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ->dns64.state);
523 break;
524 }
525
526 mDNS_StartQuery_internal(m, inQ);
527 }
528
529 //===========================================================================================================================
530 // _DNS64InterfaceSupportsNAT64
531 //===========================================================================================================================
532
533 mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(uint32_t inIfIndex)
534 {
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))
538 {
539 return (mDNStrue);
540 }
541 return (mDNSfalse);
542 }
543
544 //===========================================================================================================================
545 // _DNS64TestIPv6Synthesis
546 //===========================================================================================================================
547
548 mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
549 {
550 mStatus err;
551 nw_nat64_prefix_t * prefixes = NULL;
552 uint32_t prefixCount;
553 uint32_t i;
554 struct in_addr v4Addr;
555 struct in6_addr synthV6;
556 mDNSBool result = mDNSfalse;
557
558 err = _DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
559 require_noerr_quiet(err, exit);
560
561 memcpy(&v4Addr.s_addr, inV4Addr->b, 4);
562 for (i = 0; i < prefixCount; i++)
563 {
564 if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
565 {
566 result = mDNStrue;
567 break;
568 }
569 }
570
571 exit:
572 if (prefixes) free(prefixes);
573 return (result);
574 }
575 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNS64)