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