]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/dns-configuration.c
configd-293.8.tar.gz
[apple/configd.git] / Plugins / IPMonitor / dns-configuration.c
1 /*
2 * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * March 22, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <TargetConditionals.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <net/if.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <arpa/nameser.h>
43 #include <resolv.h>
44 #if !TARGET_OS_IPHONE
45 #include <notify.h>
46 extern uint32_t notify_monitor_file(int token, const char *name, int flags);
47 #endif // !TARGET_OS_IPHONE
48
49 #include <CoreFoundation/CoreFoundation.h>
50 #include <SystemConfiguration/SystemConfiguration.h>
51 #include <SystemConfiguration/SCPrivate.h>
52 #include <SystemConfiguration/SCValidation.h>
53
54 #include <dnsinfo.h>
55 #include <dnsinfo_create.h>
56
57 #include <dns_sd.h>
58 #ifndef kDNSServiceCompMulticastDNS
59 #define kDNSServiceCompMulticastDNS "MulticastDNS"
60 #endif
61 #ifndef kDNSServiceCompPrivateDNS
62 #define kDNSServiceCompPrivateDNS "PrivateDNS"
63 #endif
64
65 /* multicast DNS resolver configurations */
66 static CFNumberRef S_mdns_timeout = NULL;
67
68 /* private DNS resolver configurations */
69 static CFNumberRef S_pdns_timeout = NULL;
70
71
72 static void
73 add_resolver(CFMutableArrayRef supplemental, CFMutableDictionaryRef resolver)
74 {
75 CFIndex i;
76 CFIndex n_supplemental;
77 CFNumberRef order;
78 uint32_t order_val = 0;
79
80 order = CFDictionaryGetValue(resolver, kSCPropNetDNSSearchOrder);
81 if (!isA_CFNumber(order) ||
82 !CFNumberGetValue(order, kCFNumberIntType, &order_val)) {
83 order = NULL;
84 order_val = 0;
85 }
86
87 n_supplemental = CFArrayGetCount(supplemental);
88 for (i = 0; i < n_supplemental; i++) {
89 CFDictionaryRef supplemental_resolver;
90
91 supplemental_resolver = CFArrayGetValueAtIndex(supplemental, i);
92 if (CFEqual(resolver, supplemental_resolver)) {
93 // a real duplicate
94 return;
95 }
96
97 if (order != NULL) {
98 CFMutableDictionaryRef compare;
99 Boolean match;
100
101 compare = CFDictionaryCreateMutableCopy(NULL, 0, supplemental_resolver);
102 CFDictionarySetValue(compare, kSCPropNetDNSSearchOrder, order);
103 match = CFEqual(resolver, compare);
104 CFRelease(compare);
105 if (match) {
106 CFNumberRef supplemental_order;
107 uint32_t supplemental_order_val = 0;
108
109 // if only the search order's are different
110 supplemental_order = CFDictionaryGetValue(supplemental_resolver, kSCPropNetDNSSearchOrder);
111 if (!isA_CFNumber(supplemental_order) ||
112 !CFNumberGetValue(supplemental_order, kCFNumberIntType, &supplemental_order_val)) {
113 supplemental_order_val = 0;
114 }
115
116 if (order_val < supplemental_order_val ) {
117 // if we should prefer this match resolver, else just skip it
118 CFArraySetValueAtIndex(supplemental, i, resolver);
119 }
120
121 return;
122 }
123 }
124 }
125
126 order = CFNumberCreate(NULL, kCFNumberIntType, &n_supplemental);
127 CFDictionarySetValue(resolver, CFSTR("*ORDER*"), order);
128 CFRelease(order);
129
130 CFArrayAppendValue(supplemental, resolver);
131 return;
132 }
133
134
135 static void
136 add_supplemental(CFMutableArrayRef supplemental, CFDictionaryRef dns, uint32_t defaultOrder)
137 {
138 CFArrayRef domains;
139 CFIndex i;
140 CFIndex n_domains;
141 CFArrayRef orders;
142
143 domains = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomains);
144 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0;
145 if (n_domains == 0) {
146 return;
147 }
148
149 orders = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchOrders);
150 if (orders != NULL) {
151 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) {
152 return;
153 }
154 }
155
156 /*
157 * yes, this is a "supplemental" resolver configuration, expand
158 * the match domains and add each to the supplemental list.
159 */
160 for (i = 0; i < n_domains; i++) {
161 CFStringRef match_domain;
162 CFNumberRef match_order;
163 CFMutableDictionaryRef match_resolver;
164
165 match_domain = CFArrayGetValueAtIndex(domains, i);
166 if (!isA_CFString(match_domain)) {
167 continue;
168 }
169
170 match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL;
171
172 match_resolver = CFDictionaryCreateMutableCopy(NULL, 0, dns);
173
174 // remove keys we don't want in a supplemental resolver
175 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchDomains);
176 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchOrders);
177 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSearchDomains);
178 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSortList);
179
180 // set supplemental resolver "domain"
181 if (CFStringGetLength(match_domain) > 0) {
182 CFDictionarySetValue(match_resolver, kSCPropNetDNSDomainName, match_domain);
183 } else {
184 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSDomainName);
185 }
186
187 // set supplemental resolver "search_order"
188 if (isA_CFNumber(match_order)) {
189 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, match_order);
190 } else if (!CFDictionaryContainsKey(match_resolver, kSCPropNetDNSSearchOrder)) {
191 CFNumberRef num;
192
193 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
194 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, num);
195 CFRelease(num);
196
197 defaultOrder++; // if multiple domains, maintain ordering
198 }
199 add_resolver(supplemental, match_resolver);
200 CFRelease(match_resolver);
201 }
202
203 return;
204 }
205
206
207 #define N_QUICK 32
208
209
210 static void
211 add_supplemental_resolvers(CFMutableArrayRef supplemental, CFDictionaryRef services, CFArrayRef service_order)
212 {
213 const void * keys_q[N_QUICK];
214 const void ** keys = keys_q;
215 CFIndex i;
216 CFIndex n_order;
217 CFIndex n_services;
218 const void * vals_q[N_QUICK];
219 const void ** vals = vals_q;
220
221 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
222 if (n_services == 0) {
223 return; // if no services
224 }
225
226 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
227 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
228 vals = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
229 }
230
231 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
232
233 CFDictionaryGetKeysAndValues(services, keys, vals);
234 for (i = 0; i < n_services; i++) {
235 uint32_t defaultOrder;
236 CFDictionaryRef dns;
237 CFDictionaryRef service = (CFDictionaryRef)vals[i];
238
239 if (!isA_CFDictionary(service)) {
240 continue;
241 }
242
243 dns = CFDictionaryGetValue(service, kSCEntNetDNS);
244 if (!isA_CFDictionary(dns)) {
245 continue;
246 }
247
248 defaultOrder = DEFAULT_SEARCH_ORDER
249 - (DEFAULT_SEARCH_ORDER / 2)
250 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
251 if ((n_order > 0) &&
252 !CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) {
253 // push out services not specified in service order
254 defaultOrder += (DEFAULT_SEARCH_ORDER / 1000) * n_services;
255 }
256
257 add_supplemental(supplemental, dns, defaultOrder);
258 }
259
260 if (keys != keys_q) {
261 CFAllocatorDeallocate(NULL, keys);
262 CFAllocatorDeallocate(NULL, vals);
263 }
264
265 return;
266 }
267
268
269 static void
270 add_multicast_resolvers(CFMutableArrayRef supplemental, CFArrayRef multicastResolvers)
271 {
272 CFIndex i;
273 CFIndex n;
274
275 n = isA_CFArray(multicastResolvers) ? CFArrayGetCount(multicastResolvers) : 0;
276 for (i = 0; i < n; i++) {
277 uint32_t defaultOrder;
278 CFStringRef domain;
279 CFNumberRef num;
280 CFMutableDictionaryRef resolver;
281
282 domain = CFArrayGetValueAtIndex(multicastResolvers, i);
283 if (!isA_CFString(domain) || (CFStringGetLength(domain) == 0)) {
284 continue;
285 }
286
287 defaultOrder = DEFAULT_SEARCH_ORDER
288 + (DEFAULT_SEARCH_ORDER / 2)
289 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
290
291 resolver = CFDictionaryCreateMutable(NULL,
292 0,
293 &kCFTypeDictionaryKeyCallBacks,
294 &kCFTypeDictionaryValueCallBacks);
295 CFDictionarySetValue(resolver, kSCPropNetDNSDomainName, domain);
296 CFDictionarySetValue(resolver, kSCPropNetDNSOptions, CFSTR("mdns"));
297 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
298 CFDictionarySetValue(resolver, kSCPropNetDNSSearchOrder, num);
299 CFRelease(num);
300 if (S_mdns_timeout != NULL) {
301 CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_mdns_timeout);
302 }
303 add_resolver(supplemental, resolver);
304 CFRelease(resolver);
305 }
306
307 return;
308 }
309
310
311 static void
312 add_private_resolvers(CFMutableArrayRef supplemental, CFArrayRef privateResolvers)
313 {
314 CFIndex i;
315 CFIndex n;
316
317 n = isA_CFArray(privateResolvers) ? CFArrayGetCount(privateResolvers) : 0;
318 for (i = 0; i < n; i++) {
319 uint32_t defaultOrder;
320 CFStringRef domain;
321 CFNumberRef num;
322 CFMutableDictionaryRef resolver;
323
324 domain = CFArrayGetValueAtIndex(privateResolvers, i);
325 if (!isA_CFString(domain) || (CFStringGetLength(domain) == 0)) {
326 continue;
327 }
328
329 defaultOrder = DEFAULT_SEARCH_ORDER
330 - (DEFAULT_SEARCH_ORDER / 4)
331 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
332
333 resolver = CFDictionaryCreateMutable(NULL,
334 0,
335 &kCFTypeDictionaryKeyCallBacks,
336 &kCFTypeDictionaryValueCallBacks);
337 CFDictionarySetValue(resolver, kSCPropNetDNSDomainName, domain);
338 CFDictionarySetValue(resolver, kSCPropNetDNSOptions, CFSTR("pdns"));
339 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
340 CFDictionarySetValue(resolver, kSCPropNetDNSSearchOrder, num);
341 CFRelease(num);
342 if (S_pdns_timeout != NULL) {
343 CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_pdns_timeout);
344 }
345 add_resolver(supplemental, resolver);
346 CFRelease(resolver);
347 }
348
349 return;
350 }
351
352
353 static CFComparisonResult
354 compareBySearchOrder(const void *val1, const void *val2, void *context)
355 {
356 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
357 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
358 CFNumberRef num1;
359 CFNumberRef num2;
360 uint32_t order1 = DEFAULT_SEARCH_ORDER;
361 uint32_t order2 = DEFAULT_SEARCH_ORDER;
362
363 num1 = CFDictionaryGetValue(dns1, kSCPropNetDNSSearchOrder);
364 if (!isA_CFNumber(num1) ||
365 !CFNumberGetValue(num1, kCFNumberIntType, &order1)) {
366 order1 = DEFAULT_SEARCH_ORDER;
367 }
368
369 num2 = CFDictionaryGetValue(dns2, kSCPropNetDNSSearchOrder);
370 if (!isA_CFNumber(num2) ||
371 !CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
372 order2 = DEFAULT_SEARCH_ORDER;
373 }
374
375 if (order1 == order2) {
376 // if same "SearchOrder", retain original orderring for configurations
377 if (CFDictionaryGetValueIfPresent(dns1, CFSTR("*ORDER*"), (const void **)&num1) &&
378 CFDictionaryGetValueIfPresent(dns2, CFSTR("*ORDER*"), (const void **)&num2) &&
379 isA_CFNumber(num1) &&
380 isA_CFNumber(num2) &&
381 CFNumberGetValue(num1, kCFNumberIntType, &order1) &&
382 CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
383 if (order1 == order2) {
384 return kCFCompareEqualTo;
385 } else {
386 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
387 }
388 }
389
390 return kCFCompareEqualTo;
391 }
392
393 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
394 }
395
396
397 static CFStringRef
398 trimDomain(CFStringRef domain)
399 {
400 CFIndex length;
401
402 if (!isA_CFString(domain)) {
403 return NULL;
404 }
405
406 // remove any leading/trailing dots
407 length = CFStringGetLength(domain);
408 if ((length > 0) &&
409 (CFStringFindWithOptions(domain,
410 CFSTR("."),
411 CFRangeMake(0, 1),
412 kCFCompareAnchored,
413 NULL) ||
414 CFStringFindWithOptions(domain,
415 CFSTR("."),
416 CFRangeMake(0, length),
417 kCFCompareAnchored|kCFCompareBackwards,
418 NULL))) {
419 CFMutableStringRef trimmed;
420
421 trimmed = CFStringCreateMutableCopy(NULL, 0, domain);
422 CFStringTrim(trimmed, CFSTR("."));
423 domain = (CFStringRef)trimmed;
424 length = CFStringGetLength(domain);
425 } else {
426 CFRetain(domain);
427 }
428
429 if (length == 0) {
430 CFRelease(domain);
431 domain = NULL;
432 }
433
434 return domain;
435 }
436
437
438 static void
439 update_search_domains(CFMutableDictionaryRef *defaultDomain, CFArrayRef supplemental)
440 {
441 CFStringRef defaultDomainName = NULL;
442 uint32_t defaultOrder = DEFAULT_SEARCH_ORDER;
443 CFArrayRef defaultSearchDomains = NULL;
444 CFIndex defaultSearchIndex = 0;
445 CFIndex i;
446 CFMutableArrayRef mySearchDomains;
447 CFMutableArrayRef mySupplemental = NULL;
448 CFIndex n_supplemental;
449 Boolean searchDomainAdded = FALSE;
450
451 n_supplemental = CFArrayGetCount(supplemental);
452 if (n_supplemental == 0) {
453 // if no supplemental domains
454 return;
455 }
456
457 if (*defaultDomain != NULL) {
458 CFNumberRef num;
459
460 num = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSSearchOrder);
461 if (!isA_CFNumber(num) ||
462 !CFNumberGetValue(num, kCFNumberIntType, &defaultOrder)) {
463 defaultOrder = DEFAULT_SEARCH_ORDER;
464 }
465
466 defaultDomainName = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSDomainName);
467 defaultSearchDomains = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSSearchDomains);
468 }
469
470 mySearchDomains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
471
472 if (isA_CFArray(defaultSearchDomains)) {
473 CFIndex n_search;
474
475 n_search = CFArrayGetCount(defaultSearchDomains);
476 for (i = 0; i < n_search; i++) {
477 CFStringRef search;
478
479 search = CFArrayGetValueAtIndex(defaultSearchDomains, i);
480 search = trimDomain(search);
481 if (search != NULL) {
482 CFArrayAppendValue(mySearchDomains, search);
483 CFRelease(search);
484 }
485 }
486 } else {
487 defaultDomainName = trimDomain(defaultDomainName);
488 if (defaultDomainName != NULL) {
489 char *domain;
490 int domain_parts = 1;
491 char *dp;
492
493 domain = _SC_cfstring_to_cstring(defaultDomainName,
494 NULL,
495 0,
496 kCFStringEncodingUTF8);
497 CFRelease(defaultDomainName);
498
499 // count domain parts
500 for (dp = domain; *dp != '\0'; dp++) {
501 if (*dp == '.') {
502 domain_parts++;
503 }
504 }
505
506 dp = domain;
507 for (i = LOCALDOMAINPARTS; i <= domain_parts; i++) {
508 CFStringRef search;
509
510 search = CFStringCreateWithCString(NULL,
511 dp,
512 kCFStringEncodingUTF8);
513 CFArrayAppendValue(mySearchDomains, search);
514 CFRelease(search);
515
516 dp = strchr(dp, '.') + 1;
517 }
518
519 CFAllocatorDeallocate(NULL, domain);
520 }
521 }
522
523 if (n_supplemental > 1) {
524 mySupplemental = CFArrayCreateMutableCopy(NULL, 0, supplemental);
525 CFArraySortValues(mySupplemental,
526 CFRangeMake(0, n_supplemental),
527 compareBySearchOrder,
528 NULL);
529 supplemental = mySupplemental;
530 }
531
532 for (i = 0; i < n_supplemental; i++) {
533 CFDictionaryRef dns;
534 CFIndex domainIndex;
535 CFNumberRef num;
536 CFStringRef options;
537 CFStringRef supplementalDomain;
538 uint32_t supplementalOrder;
539
540 dns = CFArrayGetValueAtIndex(supplemental, i);
541
542 options = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
543 if (isA_CFString(options)) {
544 CFRange range;
545
546 if (CFEqual(options, CFSTR("pdns"))) {
547 // don't add private resolver domains to the search list
548 continue;
549 }
550
551 range = CFStringFind(options, CFSTR("interface="), 0);
552 if (range.location != kCFNotFound) {
553 // don't add scoped resolver domains to the search list
554 continue;
555 }
556 }
557
558 supplementalDomain = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
559 supplementalDomain = trimDomain(supplementalDomain);
560 if (supplementalDomain == NULL) {
561 continue;
562 }
563
564 if (CFStringHasSuffix(supplementalDomain, CFSTR(".in-addr.arpa")) ||
565 CFStringHasSuffix(supplementalDomain, CFSTR(".ip6.arpa" ))) {
566 CFRelease(supplementalDomain);
567 continue;
568 }
569
570 domainIndex = CFArrayGetFirstIndexOfValue(mySearchDomains,
571 CFRangeMake(0, CFArrayGetCount(mySearchDomains)),
572 supplementalDomain);
573
574 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
575 if (!isA_CFNumber(num) ||
576 !CFNumberGetValue(num, kCFNumberIntType, &supplementalOrder)) {
577 supplementalOrder = DEFAULT_SEARCH_ORDER;
578 }
579
580 if (supplementalOrder < defaultOrder) {
581 if (domainIndex != kCFNotFound) {
582 // if supplemental domain is already in the search list
583 CFArrayRemoveValueAtIndex(mySearchDomains, domainIndex);
584 if (domainIndex < defaultSearchIndex) {
585 defaultSearchIndex--;
586 }
587 }
588 CFArrayInsertValueAtIndex(mySearchDomains,
589 defaultSearchIndex,
590 supplementalDomain);
591 defaultSearchIndex++;
592 searchDomainAdded = TRUE;
593 } else {
594 if (domainIndex == kCFNotFound) {
595 // add to the (end of the) search list
596 CFArrayAppendValue(mySearchDomains, supplementalDomain);
597 searchDomainAdded = TRUE;
598 }
599 }
600
601 CFRelease(supplementalDomain);
602 }
603
604 if (searchDomainAdded) {
605 if (*defaultDomain == NULL) {
606 *defaultDomain = CFDictionaryCreateMutable(NULL,
607 0,
608 &kCFTypeDictionaryKeyCallBacks,
609 &kCFTypeDictionaryValueCallBacks);
610 }
611 CFDictionarySetValue(*defaultDomain, kSCPropNetDNSSearchDomains, mySearchDomains);
612 }
613
614 CFRelease(mySearchDomains);
615 if (mySupplemental != NULL) CFRelease(mySupplemental);
616 return;
617 }
618
619
620 static dns_create_resolver_t
621 create_resolver(CFDictionaryRef dns)
622 {
623 CFArrayRef list;
624 CFNumberRef num;
625 dns_create_resolver_t _resolver;
626 CFStringRef str;
627
628 _resolver = _dns_resolver_create();
629
630 // process domain
631 str = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
632 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
633 char domain[NS_MAXDNAME];
634
635 if (_SC_cfstring_to_cstring(str, domain, sizeof(domain), kCFStringEncodingUTF8) != NULL) {
636 _dns_resolver_set_domain(&_resolver, domain);
637 }
638 }
639
640 // process search domains
641 list = CFDictionaryGetValue(dns, kSCPropNetDNSSearchDomains);
642 if (isA_CFArray(list)) {
643 CFIndex i;
644 CFIndex n = CFArrayGetCount(list);
645
646 // add "search" domains
647 for (i = 0; i < n; i++) {
648 str = CFArrayGetValueAtIndex(list, i);
649 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
650 char search[NS_MAXDNAME];
651
652 if (_SC_cfstring_to_cstring(str, search, sizeof(search), kCFStringEncodingUTF8) != NULL) {
653 _dns_resolver_add_search(&_resolver, search);
654 }
655 }
656 }
657 }
658
659 // process nameserver addresses
660 list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
661 if (isA_CFArray(list)) {
662 CFIndex i;
663 CFIndex n = CFArrayGetCount(list);
664
665 for (i = 0; i < n; i++) {
666 union {
667 struct sockaddr sa;
668 struct sockaddr_in sin;
669 struct sockaddr_in6 sin6;
670 } addr;
671 char buf[128];
672
673 str = CFArrayGetValueAtIndex(list, i);
674 if (!isA_CFString(str)) {
675 continue;
676 }
677
678 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
679 continue;
680 }
681
682 bzero(&addr, sizeof(addr));
683 if (inet_aton(buf, &addr.sin.sin_addr) == 1) {
684 /* if IPv4 address */
685 addr.sin.sin_len = sizeof(addr.sin);
686 addr.sin.sin_family = AF_INET;
687 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
688 } else if (inet_pton(AF_INET6, buf, &addr.sin6.sin6_addr) == 1) {
689 /* if IPv6 address */
690 char *p;
691
692 p = strchr(buf, '%');
693 if (p != NULL) {
694 addr.sin6.sin6_scope_id = if_nametoindex(p + 1);
695 }
696
697 addr.sin6.sin6_len = sizeof(addr.sin6);
698 addr.sin6.sin6_family = AF_INET6;
699 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
700 } else {
701 continue;
702 }
703 }
704 }
705
706 // process search order
707 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
708 if (isA_CFNumber(num)) {
709 uint32_t order;
710
711 if (CFNumberGetValue(num, kCFNumberIntType, &order)) {
712 _dns_resolver_set_order(&_resolver, order);
713 }
714 }
715
716 // process sortlist
717 list = CFDictionaryGetValue(dns, kSCPropNetDNSSortList);
718 if (isA_CFArray(list)) {
719 CFIndex i;
720 CFIndex n = CFArrayGetCount(list);
721
722 for (i = 0; i < n; i++) {
723 char buf[128];
724 char *slash;
725 dns_sortaddr_t sortaddr;
726
727 str = CFArrayGetValueAtIndex(list, i);
728 if (!isA_CFString(str)) {
729 continue;
730 }
731
732 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
733 continue;
734 }
735
736 slash = strchr(buf, '/');
737 if (slash != NULL) {
738 *slash = '\0';
739 }
740
741 bzero(&sortaddr, sizeof(sortaddr));
742 if (inet_aton(buf, &sortaddr.address) != 1) {
743 /* if address not valid */
744 continue;
745 }
746
747 if (slash != NULL) {
748 if (inet_aton(slash + 1, &sortaddr.mask) != 1) {
749 /* if subnet mask not valid */
750 continue;
751 }
752 } else {
753 in_addr_t a;
754 in_addr_t m;
755
756 a = ntohl(sortaddr.address.s_addr);
757 if (IN_CLASSA(a)) {
758 m = IN_CLASSA_NET;
759 } else if (IN_CLASSB(a)) {
760 m = IN_CLASSB_NET;
761 } else if (IN_CLASSC(a)) {
762 m = IN_CLASSC_NET;
763 } else {
764 continue;
765 }
766
767 sortaddr.mask.s_addr = htonl(m);
768 }
769
770 _dns_resolver_add_sortaddr(&_resolver, &sortaddr);
771 }
772 }
773
774 // process port
775 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerPort);
776 if (isA_CFNumber(num)) {
777 int port;
778
779 if (CFNumberGetValue(num, kCFNumberIntType, &port)) {
780 _dns_resolver_set_port(&_resolver, (uint16_t)port);
781 }
782 }
783
784 // process timeout
785 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerTimeout);
786 if (isA_CFNumber(num)) {
787 int timeout;
788
789 if (CFNumberGetValue(num, kCFNumberIntType, &timeout)) {
790 _dns_resolver_set_timeout(&_resolver, (uint32_t)timeout);
791 }
792 }
793
794 // process options
795 str = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
796 if (isA_CFString(str)) {
797 char *options;
798
799 options = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
800 if (options != NULL) {
801 _dns_resolver_set_options(&_resolver, options);
802 CFAllocatorDeallocate(NULL, options);
803 }
804 }
805
806 return _resolver;
807 }
808
809
810 __private_extern__
811 void
812 dns_configuration_set(CFDictionaryRef defaultResolver,
813 CFDictionaryRef services,
814 CFArrayRef serviceOrder,
815 CFArrayRef multicastResolvers,
816 CFArrayRef privateResolvers)
817 {
818 CFIndex i;
819 CFMutableDictionaryRef myDefault;
820 uint32_t myOrder = DEFAULT_SEARCH_ORDER;
821 Boolean myOrderAdded = FALSE;
822 CFIndex n_supplemental;
823 CFNumberRef order;
824 dns_create_resolver_t resolver;
825 CFMutableArrayRef supplemental;
826
827 #ifdef SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
828 CFStringRef myDomain = NULL;
829 CFArrayRef search;
830 #endif // SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
831
832 if (defaultResolver == NULL) {
833 myDefault = CFDictionaryCreateMutable(NULL,
834 0,
835 &kCFTypeDictionaryKeyCallBacks,
836 &kCFTypeDictionaryValueCallBacks);
837 } else {
838 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver);
839
840 // ensure that the default resolver has a search order
841
842 order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder);
843 if (!isA_CFNumber(order) ||
844 !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) {
845 myOrderAdded = TRUE;
846 myOrder = DEFAULT_SEARCH_ORDER;
847 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
848 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order);
849 CFRelease(order);
850 }
851 }
852
853 // establish list of supplemental resolvers
854
855 supplemental = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
856
857 // identify search[] list and/or domain name
858
859 #ifdef SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
860 search = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchDomains);
861 if (isA_CFArray(search) && (CFArrayGetCount(search) > 0)) {
862 myDomain = CFArrayGetValueAtIndex(search, 0);
863 myDomain = isA_CFString(myDomain);
864 }
865
866 if (myDomain == NULL) {
867 myDomain = CFDictionaryGetValue(myDefault, kSCPropNetDNSDomainName);
868 myDomain = isA_CFString(myDomain);
869 }
870
871 // add match for default domain
872
873 if (myDomain != NULL) {
874 CFMutableDictionaryRef mySupplemental;
875
876 mySupplemental = CFDictionaryCreateMutableCopy(NULL, 0, myDefault);
877 CFDictionarySetValue (mySupplemental, kSCPropNetDNSDomainName, myDomain);
878 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSearchDomains);
879 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSupplementalMatchDomains);
880 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSupplementalMatchOrders);
881 add_resolver(supplemental, mySupplemental);
882 CFRelease(mySupplemental);
883 }
884 #endif // SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
885
886 // collect (and add) any supplemental resolver configurations
887
888 add_supplemental_resolvers(supplemental, services, serviceOrder);
889
890 // collect (and add) any "private" resolver configurations
891
892 add_private_resolvers(supplemental, privateResolvers);
893
894 // update the "search" list
895
896 update_search_domains(&myDefault, supplemental);
897
898 // collect (and add) any "multicast" resolver configurations
899
900 add_multicast_resolvers(supplemental, multicastResolvers);
901
902 // check if the "match for default domain" (above) is really needed
903
904 #ifdef SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
905 if (myDomain != NULL) {
906 Boolean sharedDomain = FALSE;
907
908 n_supplemental = CFArrayGetCount(supplemental);
909 for (i = 1; i < n_supplemental; i++) {
910 CFStringRef domain;
911 CFDictionaryRef mySupplemental;
912
913 mySupplemental = CFArrayGetValueAtIndex(supplemental, i);
914 domain = CFDictionaryGetValue(mySupplemental, kSCPropNetDNSDomainName);
915 if (isA_CFString(domain)) {
916 if (CFEqual(myDomain, domain)) {
917 sharedDomain = TRUE;
918 break;
919 }
920
921 if (CFStringHasSuffix(myDomain, domain)) {
922 CFIndex dotIndex;
923
924 dotIndex = CFStringGetLength(myDomain) - CFStringGetLength(domain) - 1;
925 if (dotIndex > 0) {
926 UniChar dot;
927
928 dot = CFStringGetCharacterAtIndex(myDomain, dotIndex);
929 if (dot == (UniChar)'.') {
930 sharedDomain = TRUE;
931 break;
932 }
933 }
934 }
935 }
936 }
937
938 if (!sharedDomain) {
939 // if the default resolver domain name is not shared
940 CFArrayRemoveValueAtIndex(supplemental, 0);
941 }
942 }
943 #endif // SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
944
945 // establish resolver configuration
946
947 n_supplemental = CFArrayGetCount(supplemental);
948 if ((defaultResolver == NULL) && (n_supplemental == 0)) {
949 /*
950 * if no default or supplemental resolvers
951 */
952 if (!_dns_configuration_store(NULL)) {
953 SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
954 }
955 } else {
956 dns_create_config_t _config;
957
958 /*
959 * if default and/or supplemental resolvers are defined
960 */
961 _config = _dns_configuration_create();
962
963 // add [default] resolver
964
965 if ((n_supplemental == 0) && myOrderAdded) {
966 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
967 }
968 resolver = create_resolver(myDefault);
969 _dns_configuration_add_resolver(&_config, resolver);
970 _dns_resolver_free(&resolver);
971
972 // add [supplemental] resolvers
973
974 for (i = 0; i < n_supplemental; i++) {
975 CFDictionaryRef supplementalResolver;
976
977 supplementalResolver = CFArrayGetValueAtIndex(supplemental, i);
978 resolver = create_resolver(supplementalResolver);
979 _dns_configuration_add_resolver(&_config, resolver);
980 _dns_resolver_free(&resolver);
981 }
982
983 #if !TARGET_OS_IPHONE
984 // add flatfile resolvers
985
986 _dnsinfo_flatfile_add_resolvers(&_config);
987 #endif // !TARGET_OS_IPHONE
988
989 // save configuration
990
991 if (!_dns_configuration_store(&_config)) {
992 SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
993 }
994
995 _dns_configuration_free(&_config);
996 }
997
998 CFRelease(myDefault);
999 CFRelease(supplemental);
1000
1001 return;
1002 }
1003
1004
1005 #if !TARGET_OS_IPHONE
1006 static SCDynamicStoreRef dns_configuration_store;
1007 static SCDynamicStoreCallBack dns_configuration_callout;
1008
1009 static void
1010 dns_configuration_changed(CFMachPortRef port, void *msg, CFIndex size, void *info)
1011 {
1012 CFStringRef key = CFSTR(_PATH_RESOLVER_DIR);
1013 CFArrayRef keys;
1014 Boolean resolvers_now;
1015 static Boolean resolvers_save = FALSE;
1016 struct stat statbuf;
1017
1018 resolvers_now = (stat(_PATH_RESOLVER_DIR, &statbuf) == 0);
1019 if (!resolvers_save && (resolvers_save == resolvers_now)) {
1020 // if we did not (and still do not) have an "/etc/resolvers"
1021 // directory than this notification is the result of a change
1022 // to the "/etc" directory.
1023 return;
1024 }
1025 resolvers_save = resolvers_now;
1026
1027 SCLog(TRUE, LOG_DEBUG, CFSTR(_PATH_RESOLVER_DIR " changed"));
1028
1029 // fake a "DNS" change
1030 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
1031 (*dns_configuration_callout)(dns_configuration_store, keys, NULL);
1032 CFRelease(keys);
1033 return;
1034 }
1035
1036
1037 __private_extern__
1038 void
1039 dns_configuration_monitor(SCDynamicStoreRef store, SCDynamicStoreCallBack callout)
1040 {
1041 CFMachPortRef mp;
1042 mach_port_t notify_port;
1043 int notify_token;
1044 CFRunLoopSourceRef rls;
1045 uint32_t status;
1046
1047 dns_configuration_store = store;
1048 dns_configuration_callout = callout;
1049
1050 status = notify_register_mach_port(_PATH_RESOLVER_DIR, &notify_port, 0, &notify_token);
1051 if (status != NOTIFY_STATUS_OK) {
1052 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1053 return;
1054 }
1055
1056 status = notify_monitor_file(notify_token, "/private" _PATH_RESOLVER_DIR, 0);
1057 if (status != NOTIFY_STATUS_OK) {
1058 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_monitor_file() failed"));
1059 (void)notify_cancel(notify_token);
1060 return;
1061 }
1062
1063 mp = CFMachPortCreateWithPort(NULL, notify_port, dns_configuration_changed, NULL, NULL);
1064 if (mp == NULL) {
1065 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1066 (void)notify_cancel(notify_token);
1067 return;
1068 }
1069
1070 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1071 if (rls == NULL) {
1072 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1073 CFRelease(mp);
1074 (void)notify_cancel(notify_token);
1075 return;
1076 }
1077 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1078 CFRelease(rls);
1079
1080 CFRelease(mp);
1081 return;
1082 }
1083 #endif // !TARGET_OS_IPHONE
1084
1085
1086 __private_extern__
1087 void
1088 dns_configuration_init(CFBundleRef bundle)
1089 {
1090 CFDictionaryRef dict;
1091
1092 dict = CFBundleGetInfoDictionary(bundle);
1093 if (isA_CFDictionary(dict)) {
1094 S_mdns_timeout = CFDictionaryGetValue(dict, CFSTR("mdns_timeout"));
1095 S_mdns_timeout = isA_CFNumber(S_mdns_timeout);
1096
1097 S_pdns_timeout = CFDictionaryGetValue(dict, CFSTR("pdns_timeout"));
1098 S_pdns_timeout = isA_CFNumber(S_pdns_timeout);
1099 }
1100
1101 return;
1102 }
1103
1104
1105 #ifdef MAIN
1106 #undef MAIN
1107
1108 static void
1109 split(const void * key, const void * value, void * context)
1110 {
1111 CFArrayRef components;
1112 CFStringRef entity_id;
1113 CFStringRef service_id;
1114 CFMutableDictionaryRef state_dict;
1115
1116 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/"));
1117 service_id = CFArrayGetValueAtIndex(components, 3);
1118 entity_id = CFArrayGetValueAtIndex(components, 4);
1119 state_dict = CFDictionaryCreateMutable(NULL,
1120 0,
1121 &kCFTypeDictionaryKeyCallBacks,
1122 &kCFTypeDictionaryValueCallBacks);
1123 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
1124 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
1125 CFRelease(state_dict);
1126 CFRelease(components);
1127
1128 return;
1129 }
1130
1131 int
1132 main(int argc, char **argv)
1133 {
1134 CFDictionaryRef entities;
1135 CFStringRef key;
1136 CFArrayRef multicast_resolvers;
1137 CFStringRef pattern;
1138 CFMutableArrayRef patterns;
1139 CFStringRef primary = NULL;
1140 CFDictionaryRef primaryDNS = NULL;
1141 CFArrayRef private_resolvers;
1142 CFArrayRef service_order = NULL;
1143 CFMutableDictionaryRef service_state_dict;
1144 CFDictionaryRef setup_global_ipv4;
1145 CFDictionaryRef state_global_ipv4;
1146 SCDynamicStoreRef store;
1147
1148 _sc_log = FALSE;
1149 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1150
1151 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
1152
1153 // get DNS entities
1154 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1155 kSCDynamicStoreDomainState,
1156 kSCCompAnyRegex,
1157 kSCEntNetDNS);
1158 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1159 CFArrayAppendValue(patterns, pattern);
1160 CFRelease(pattern);
1161 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
1162 CFRelease(patterns);
1163
1164 service_state_dict = CFDictionaryCreateMutable(NULL,
1165 0,
1166 &kCFTypeDictionaryKeyCallBacks,
1167 &kCFTypeDictionaryValueCallBacks);
1168 CFDictionaryApplyFunction(entities, split, service_state_dict);
1169 CFRelease(entities);
1170
1171 // get primary service ID
1172 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1173 kSCDynamicStoreDomainState,
1174 kSCEntNetIPv4);
1175 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1176 CFRelease(key);
1177 if (state_global_ipv4 != NULL) {
1178 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
1179 if (primary != NULL) {
1180 CFDictionaryRef service_dict;
1181
1182 // get DNS configuration for primary service
1183 service_dict = CFDictionaryGetValue(service_state_dict, primary);
1184 if (service_dict != NULL) {
1185 primaryDNS = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
1186 }
1187 }
1188 }
1189
1190 // get serviceOrder
1191 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1192 kSCDynamicStoreDomainSetup,
1193 kSCEntNetIPv4);
1194 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1195 CFRelease(key);
1196 if (setup_global_ipv4 != NULL) {
1197 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
1198 }
1199
1200 // get multicast resolvers
1201 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1202 kSCDynamicStoreDomainState,
1203 kSCCompNetwork,
1204 CFSTR(kDNSServiceCompMulticastDNS));
1205 multicast_resolvers = SCDynamicStoreCopyValue(store, key);
1206 CFRelease(key);
1207
1208 // get private resolvers
1209 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1210 kSCDynamicStoreDomainState,
1211 kSCCompNetwork,
1212 CFSTR(kDNSServiceCompPrivateDNS));
1213 private_resolvers = SCDynamicStoreCopyValue(store, key);
1214 CFRelease(key);
1215
1216 // update DNS configuration
1217 dns_configuration_init(CFBundleGetMainBundle());
1218 dns_configuration_set(primaryDNS,
1219 service_state_dict,
1220 service_order,
1221 multicast_resolvers,
1222 private_resolvers);
1223
1224 // cleanup
1225 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
1226 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
1227 if (multicast_resolvers != NULL) CFRelease(multicast_resolvers);
1228 if (private_resolvers != NULL) CFRelease(private_resolvers);
1229 CFRelease(service_state_dict);
1230 CFRelease(store);
1231
1232 /* not reached */
1233 exit(0);
1234 return 0;
1235 }
1236 #endif
1237