]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/DNS64.c
mDNSResponder-878.270.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 <TargetConditionals.h>
18
19 // DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
20
21 #if TARGET_OS_IOS
22 #include "DNS64.h"
23
24 #include <AssertMacros.h>
25
26 #if __has_include(<nw/private.h>)
27 #include <nw/private.h>
28 #else
29 #include <network/nat64.h>
30 #endif
31
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "dns_sd.h"
36 #include "dns_sd_internal.h"
37 #include "uDNS.h"
38
39 //===========================================================================================================================
40 // Constants
41 //===========================================================================================================================
42
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.
46
47 #define sizeof_field(TYPE, FIELD) sizeof(((TYPE *)0)->FIELD) // From CoreUtils.h
48
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);
52
53 //===========================================================================================================================
54 // Local Prototypes
55 //===========================================================================================================================
56
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);
63
64 //===========================================================================================================================
65 // DNS64StateMachine
66 //===========================================================================================================================
67
68 mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult)
69 {
70 // If this is an mDNS question, then exit early. DNS64 is only for unicast DNS questions.
71
72 if (mDNSOpaque16IsZero(inQ->TargetQID)) return (mDNSfalse);
73
74 switch (inQ->dns64.state)
75 {
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.
79
80 case kDNS64State_Initial:
81 if ((inRR->RecordType == kDNSRecordTypePacketNegative) && (inResult == QC_add))
82 {
83 if ((inQ->qtype == kDNSType_AAAA) &&
84 (inRR->rrtype == kDNSType_AAAA) &&
85 (inRR->rrclass == kDNSClass_IN) &&
86 ((inQ->qnamehash != DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
87 inQ->qDNSServer &&
88 nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface))
89 {
90 DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
91 return (mDNStrue);
92 }
93 else if ((inQ->qtype == kDNSType_PTR) &&
94 (inRR->rrtype == kDNSType_PTR) &&
95 (inRR->rrclass == kDNSClass_IN) &&
96 inQ->qDNSServer &&
97 nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface) &&
98 DNS64GetReverseIPv6Addr(&inQ->qname, NULL))
99 {
100 DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
101 return (mDNStrue);
102 }
103 }
104 break;
105
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.
109
110 case kDNS64State_PrefixDiscovery:
111 if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
112 (inResult == QC_add) &&
113 (inRR->rrtype == kDNSType_AAAA) &&
114 (inRR->rrclass == kDNSClass_IN))
115 {
116 DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
117 return (mDNStrue);
118 }
119 else
120 {
121 DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
122 return (mDNStrue);
123 }
124 break;
125
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.
128
129 case kDNS64State_PrefixDiscoveryPTR:
130 DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
131 return (mDNStrue);
132 break;
133
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
136 // QueryARecord2.
137 // Otherwise, restart the question for the original AAAA record.
138
139 case kDNS64State_QueryA:
140 if (inRR->rrtype != kDNSType_CNAME)
141 {
142 if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
143 (inResult == QC_add) &&
144 (inRR->rrtype == kDNSType_A) &&
145 (inRR->rrclass == kDNSClass_IN) &&
146 inQ->qDNSServer &&
147 DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
148 {
149 inQ->dns64.state = kDNS64State_QueryA2;
150 }
151 else
152 {
153 DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
154 return (mDNStrue);
155 }
156 }
157 break;
158
159 // For all other states, do nothing.
160
161 case kDNS64State_QueryA2:
162 case kDNS64State_QueryAAAA:
163 case kDNS64State_QueryPTR:
164 case kDNS64State_ReverseIPv4:
165 case kDNS64State_ReverseIPv6:
166 break;
167
168 default:
169 LogMsg("DNS64StateMachine: unrecognized DNS64 state %d", inQ->dns64.state);
170 break;
171 }
172
173 return (mDNSfalse);
174 }
175
176 //===========================================================================================================================
177 // DNS64AnswerCurrentQuestion
178 //===========================================================================================================================
179
180 mDNSexport mStatus DNS64AnswerCurrentQuestion(mDNS *m, const ResourceRecord *inRR, QC_result inResult)
181 {
182 mStatus err;
183 ResourceRecord newRR;
184 RData rdata;
185 nw_nat64_prefix_t * prefixes = NULL;
186 uint32_t prefixCount;
187 uint32_t i;
188 struct in_addr v4Addr;
189 struct in6_addr synthV6;
190 DNSQuestion * const q = m->CurrentQuestion;
191
192 require_action_quiet(q->qDNSServer, exit, err = mStatus_BadParamErr);
193
194 err = DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
195 require_noerr_quiet(err, exit);
196
197 newRR = *inRR;
198 newRR.rrtype = kDNSType_AAAA;
199 newRR.rdlength = 16;
200 rdata.MaxRDLength = newRR.rdlength;
201 newRR.rdata = &rdata;
202
203 memcpy(&v4Addr.s_addr, inRR->rdata->u.ipv4.b, 4);
204 for (i = 0; i < prefixCount; i++)
205 {
206 if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
207 {
208 memcpy(rdata.u.ipv6.b, synthV6.s6_addr, 16);
209 q->QuestionCallback(m, q, &newRR, inResult);
210 if (m->CurrentQuestion != q) break;
211 }
212 }
213 err = mStatus_NoError;
214
215 exit:
216 if (prefixes) free(prefixes);
217 return (err);
218 }
219
220 //===========================================================================================================================
221 // DNS64HandleNewQuestion
222 //===========================================================================================================================
223
224 mDNSexport void DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ)
225 {
226 if (inQ->dns64.state == kDNS64State_QueryPTR)
227 {
228 struct in6_addr v6Addr;
229
230 inQ->dns64.state = kDNS64State_ReverseIPv6;
231 if (inQ->qDNSServer && DNS64GetReverseIPv6Addr(&inQ->qname, &v6Addr))
232 {
233 mStatus err;
234 nw_nat64_prefix_t * prefixes;
235 uint32_t prefixCount;
236 uint32_t i;
237 struct in_addr v4Addr;
238 char qnameStr[MAX_REVERSE_MAPPING_NAME_V4];
239
240 err = DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
241 require_noerr_quiet(err, exit);
242
243 for (i = 0; i < prefixCount; i++)
244 {
245 if (nw_nat64_extract_v4(&prefixes[i], &v6Addr, &v4Addr))
246 {
247 const mDNSu8 * const a = (const mDNSu8 *)&v4Addr.s_addr;
248
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;
253 break;
254 }
255 }
256 free(prefixes);
257 }
258 }
259
260 exit:
261 return;
262 }
263
264 //===========================================================================================================================
265 // DNS64ResetState
266 //===========================================================================================================================
267
268 // Called from mDNS_StopQuery_internal().
269
270 mDNSexport void DNS64ResetState(DNSQuestion *inQ)
271 {
272 switch (inQ->dns64.state)
273 {
274 case kDNS64State_PrefixDiscoveryPTR:
275 inQ->qtype = kDNSType_PTR; // Restore qtype to PTR and fall through.
276
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);
280 break;
281
282 case kDNS64State_QueryA:
283 case kDNS64State_QueryA2:
284 inQ->qtype = kDNSType_AAAA; // Restore qtype to AAAA.
285 break;
286
287 // Do nothing for the other states.
288
289 case kDNS64State_Initial:
290 case kDNS64State_QueryAAAA:
291 case kDNS64State_QueryPTR:
292 case kDNS64State_ReverseIPv4:
293 case kDNS64State_ReverseIPv6:
294 break;
295
296 default:
297 LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ->dns64.state);
298 break;
299 }
300 inQ->dns64.state = kDNS64State_Initial;
301 }
302
303 //===========================================================================================================================
304 // DNS64RestartQuestions
305 //===========================================================================================================================
306
307 mDNSexport void DNS64RestartQuestions(mDNS *m)
308 {
309 DNSQuestion * q;
310 DNSQuestion * restartList = NULL;
311 DNSServer * newServer;
312
313 m->RestartQuestion = m->Questions;
314 while (m->RestartQuestion)
315 {
316 q = m->RestartQuestion;
317 m->RestartQuestion = q->next;
318 if (q->dns64.state != kDNS64State_Initial)
319 {
320 SetValidDNSServers(m, q);
321 q->triedAllServersOnce = 0;
322 newServer = GetServerForQuestion(m, q);
323 if (q->qDNSServer != newServer)
324 {
325 if (!CacheRecordRmvEventsForQuestion(m, q))
326 {
327 LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
328 }
329 else
330 {
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;
334 restartList = q;
335 }
336 }
337 }
338 }
339 while ((q = restartList) != NULL)
340 {
341 restartList = restartList->next;
342 q->next = NULL;
343 LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
344 mDNS_StartQuery_internal(m, q);
345 }
346 }
347
348 //===========================================================================================================================
349 // DNS64GetIPv6Addrs
350 //===========================================================================================================================
351
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) && \
357 !(RR)->InterfaceID)
358
359 mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
360 {
361 mStatus err;
362 const CacheGroup * cg;
363 const CacheRecord * cr;
364 struct in6_addr * addrs = NULL;
365 uint32_t addrCount;
366 uint32_t recordCount;
367
368 cg = CacheGroupForName(m, DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
369 require_action_quiet(cg, exit, err = mStatus_NoSuchRecord);
370
371 recordCount = 0;
372 for (cr = cg->members; cr; cr = cr->next)
373 {
374 if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
375 {
376 recordCount++;
377 }
378 }
379 require_action_quiet(recordCount > 0, exit, err = mStatus_NoSuchRecord);
380
381 addrs = (struct in6_addr *)calloc(recordCount, sizeof(*addrs));
382 require_action_quiet(addrs, exit, err = mStatus_NoMemoryErr);
383
384 addrCount = 0;
385 for (cr = cg->members; cr && (addrCount < recordCount); cr = cr->next)
386 {
387 if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
388 {
389 memcpy(addrs[addrCount].s6_addr, cr->resrec.rdata->u.ipv6.b, 16);
390 addrCount++;
391 }
392 }
393
394 *outAddrs = addrs;
395 addrs = NULL;
396 *outAddrCount = addrCount;
397 err = mStatus_NoError;
398
399 exit:
400 if (addrs) free(addrs);
401 return (err);
402 }
403
404 //===========================================================================================================================
405 // DNS64GetPrefixes
406 //===========================================================================================================================
407
408 mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
409 {
410 mStatus err;
411 struct in6_addr * v6Addrs;
412 uint32_t v6AddrCount;
413 nw_nat64_prefix_t * prefixes;
414 int32_t prefixCount;
415
416 err = DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
417 require_noerr_quiet(err, exit);
418
419 prefixCount = nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs, v6AddrCount, &prefixes);
420 free(v6Addrs);
421 require_action_quiet(prefixCount > 0, exit, err = mStatus_UnknownErr);
422
423 *outPrefixes = prefixes;
424 *outPrefixCount = prefixCount;
425
426 exit:
427 return (err);
428 }
429
430 //===========================================================================================================================
431 // DNS64GetReverseIPv6Addr
432 //===========================================================================================================================
433
434 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
435
436 mDNSlocal mDNSBool DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr)
437 {
438 const mDNSu8 * ptr;
439 int i;
440 unsigned int c;
441 unsigned int nl;
442 unsigned int nu;
443
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>.
447
448 ptr = (const mDNSu8 *)inQName;
449 for (i = 0; i < 16; i++)
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')) 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.
457
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.
464
465 if (outAddr) outAddr->s6_addr[15 - i] = (mDNSu8)((nu << 4) | nl);
466 }
467
468 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
469
470 if (!SameDomainName((const domainname *)ptr, kReverseIPv6Domain)) return (mDNSfalse);
471
472 return (mDNStrue);
473 }
474
475 //===========================================================================================================================
476 // DNS64IPv4OnlyFQDNHash
477 //===========================================================================================================================
478
479 mDNSlocal mDNSu32 DNS64IPv4OnlyFQDNHash(void)
480 {
481 static dispatch_once_t sHashOnce;
482 static mDNSu32 sHash;
483
484 dispatch_once(&sHashOnce, ^{ sHash = DomainNameHashValue(kDNS64IPv4OnlyFQDN); });
485
486 return (sHash);
487 }
488
489 //===========================================================================================================================
490 // DNS64RestartQuestion
491 //===========================================================================================================================
492
493 mDNSlocal void DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
494 {
495 mDNS_StopQuery_internal(m, inQ);
496
497 inQ->dns64.state = inNewState;
498 switch (inQ->dns64.state)
499 {
500 case kDNS64State_Initial:
501 break;
502
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.".
506
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;
511 break;
512
513 case kDNS64State_QueryA:
514 case kDNS64State_QueryA2:
515 inQ->qtype = kDNSType_A;
516 break;
517
518 case kDNS64State_QueryPTR:
519 case kDNS64State_ReverseIPv4:
520 case kDNS64State_ReverseIPv6:
521 inQ->qtype = kDNSType_PTR;
522 break;
523
524 case kDNS64State_QueryAAAA:
525 inQ->qtype = kDNSType_AAAA;
526 break;
527
528 default:
529 LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ->dns64.state);
530 break;
531 }
532
533 mDNS_StartQuery_internal(m, inQ);
534 }
535
536 //===========================================================================================================================
537 // DNS64TestIPv6Synthesis
538 //===========================================================================================================================
539
540 mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
541 {
542 mStatus err;
543 nw_nat64_prefix_t * prefixes = NULL;
544 uint32_t prefixCount;
545 uint32_t i;
546 struct in_addr v4Addr;
547 struct in6_addr synthV6;
548 mDNSBool result = mDNSfalse;
549
550 err = DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
551 require_noerr_quiet(err, exit);
552
553 memcpy(&v4Addr.s_addr, inV4Addr->b, 4);
554 for (i = 0; i < prefixCount; i++)
555 {
556 if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
557 {
558 result = mDNStrue;
559 break;
560 }
561 }
562
563 exit:
564 if (prefixes) free(prefixes);
565 return (result);
566 }
567 #endif // TARGET_OS_IOS