]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/dns-configuration.c
configd-204.tar.gz
[apple/configd.git] / Plugins / IPMonitor / dns-configuration.c
1 /*
2 * Copyright (c) 2004-2007 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 <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #include <net/if.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <arpa/nameser.h>
42 #include <resolv.h>
43
44 #include <CoreFoundation/CoreFoundation.h>
45 #include <SystemConfiguration/SystemConfiguration.h>
46 #include <SystemConfiguration/SCPrivate.h>
47 #include <SystemConfiguration/SCValidation.h>
48
49 #include <dnsinfo.h>
50 #include <dnsinfo_create.h>
51
52 #include <dns_sd.h>
53 #ifndef kDNSServiceCompPrivateDNS
54 #define kDNSServiceCompPrivateDNS "PrivateDNS"
55 #endif
56
57 /* pre-defined (supplemental) resolver configurations */
58 static CFArrayRef S_predefined = NULL;
59
60 /* private DNS resolver configurations */
61 static CFNumberRef S_pdns_timeout = NULL;
62
63
64 static void
65 add_resolver(CFMutableArrayRef supplemental, CFMutableDictionaryRef resolver)
66 {
67 CFIndex i;
68 CFIndex n_supplemental;
69 CFNumberRef order;
70 uint32_t order_val = 0;
71
72 order = CFDictionaryGetValue(resolver, kSCPropNetDNSSearchOrder);
73 if (!isA_CFNumber(order) ||
74 !CFNumberGetValue(order, kCFNumberIntType, &order_val)) {
75 order = NULL;
76 order_val = 0;
77 }
78
79 n_supplemental = CFArrayGetCount(supplemental);
80 for (i = 0; i < n_supplemental; i++) {
81 CFDictionaryRef supplemental_resolver;
82
83 supplemental_resolver = CFArrayGetValueAtIndex(supplemental, i);
84 if (CFEqual(resolver, supplemental_resolver)) {
85 // a real duplicate
86 return;
87 }
88
89 if (order != NULL) {
90 CFMutableDictionaryRef compare;
91 Boolean match;
92
93 compare = CFDictionaryCreateMutableCopy(NULL, 0, supplemental_resolver);
94 CFDictionarySetValue(compare, kSCPropNetDNSSearchOrder, order);
95 match = CFEqual(resolver, compare);
96 CFRelease(compare);
97 if (match) {
98 CFNumberRef supplemental_order;
99 uint32_t supplemental_order_val = 0;
100
101 // if only the search order's are different
102 supplemental_order = CFDictionaryGetValue(supplemental_resolver, kSCPropNetDNSSearchOrder);
103 if (!isA_CFNumber(supplemental_order) ||
104 !CFNumberGetValue(supplemental_order, kCFNumberIntType, &supplemental_order_val)) {
105 supplemental_order_val = 0;
106 }
107
108 if (order_val < supplemental_order_val ) {
109 // if we should prefer this match resolver, else just skip it
110 CFArraySetValueAtIndex(supplemental, i, resolver);
111 }
112
113 return;
114 }
115 }
116 }
117
118 order = CFNumberCreate(NULL, kCFNumberIntType, &n_supplemental);
119 CFDictionarySetValue(resolver, CFSTR("*ORDER*"), order);
120 CFRelease(order);
121
122 CFArrayAppendValue(supplemental, resolver);
123 return;
124 }
125
126
127 static void
128 add_supplemental(CFMutableArrayRef supplemental, CFDictionaryRef dns, uint32_t defaultOrder)
129 {
130 CFArrayRef domains;
131 CFIndex i;
132 CFIndex n_domains;
133 CFArrayRef orders;
134
135 domains = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomains);
136 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0;
137 if (n_domains == 0) {
138 return;
139 }
140
141 orders = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchOrders);
142 if (orders != NULL) {
143 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) {
144 return;
145 }
146 }
147
148 /*
149 * yes, this is a "supplemental" resolver configuration, expand
150 * the match domains and add each to the supplemental list.
151 */
152 for (i = 0; i < n_domains; i++) {
153 CFStringRef match_domain;
154 CFNumberRef match_order;
155 CFMutableDictionaryRef match_resolver;
156
157 match_domain = CFArrayGetValueAtIndex(domains, i);
158 if (!isA_CFString(match_domain)) {
159 continue;
160 }
161
162 match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL;
163
164 match_resolver = CFDictionaryCreateMutableCopy(NULL, 0, dns);
165
166 // remove keys we don't want in a supplemental resolver
167 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchDomains);
168 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchOrders);
169 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSearchDomains);
170 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSortList);
171
172 // set supplemental resolver "domain"
173 if (CFStringGetLength(match_domain) > 0) {
174 CFDictionarySetValue(match_resolver, kSCPropNetDNSDomainName, match_domain);
175 } else {
176 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSDomainName);
177 }
178
179 // set supplemental resolver "search_order"
180 if (isA_CFNumber(match_order)) {
181 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, match_order);
182 } else if (!CFDictionaryContainsKey(match_resolver, kSCPropNetDNSSearchOrder)) {
183 CFNumberRef num;
184
185 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
186 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, num);
187 CFRelease(num);
188
189 defaultOrder++; // if multiple domains, maintain ordering
190 }
191 add_resolver(supplemental, match_resolver);
192 CFRelease(match_resolver);
193 }
194
195 return;
196 }
197
198
199 static void
200 add_predefined_resolvers(CFMutableArrayRef supplemental)
201 {
202 CFIndex i;
203 CFIndex n;
204
205 if (S_predefined == NULL) {
206 return;
207 }
208
209 n = CFArrayGetCount(S_predefined);
210 for (i = 0; i < n; i++) {
211 uint32_t defaultOrder;
212 CFDictionaryRef dns;
213
214 dns = CFArrayGetValueAtIndex(S_predefined, i);
215 if (!isA_CFDictionary(dns)) {
216 continue;
217 }
218
219 defaultOrder = DEFAULT_SEARCH_ORDER
220 + (DEFAULT_SEARCH_ORDER / 2)
221 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
222 add_supplemental(supplemental, dns, defaultOrder);
223 }
224
225 return;
226 }
227
228
229 #define N_QUICK 32
230
231
232 static void
233 add_supplemental_resolvers(CFMutableArrayRef supplemental, CFDictionaryRef services, CFArrayRef service_order)
234 {
235 const void * keys_q[N_QUICK];
236 const void ** keys = keys_q;
237 CFIndex i;
238 CFIndex n_order;
239 CFIndex n_services;
240 const void * vals_q[N_QUICK];
241 const void ** vals = vals_q;
242
243 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
244 if (n_services == 0) {
245 return; // if no services
246 }
247
248 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
249 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
250 vals = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
251 }
252
253 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
254
255 CFDictionaryGetKeysAndValues(services, keys, vals);
256 for (i = 0; i < n_services; i++) {
257 uint32_t defaultOrder;
258 CFDictionaryRef dns;
259 CFDictionaryRef service = (CFDictionaryRef)vals[i];
260
261 if (!isA_CFDictionary(service)) {
262 continue;
263 }
264
265 dns = CFDictionaryGetValue(service, kSCEntNetDNS);
266 if (!isA_CFDictionary(dns)) {
267 continue;
268 }
269
270 defaultOrder = DEFAULT_SEARCH_ORDER
271 - (DEFAULT_SEARCH_ORDER / 2)
272 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
273 if ((n_order > 0) &&
274 !CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) {
275 // push out services not specified in service order
276 defaultOrder += (DEFAULT_SEARCH_ORDER / 1000) * n_services;
277 }
278
279 add_supplemental(supplemental, dns, defaultOrder);
280 }
281
282 if (keys != keys_q) {
283 CFAllocatorDeallocate(NULL, keys);
284 CFAllocatorDeallocate(NULL, vals);
285 }
286
287 return;
288 }
289
290
291 static void
292 add_private_resolvers(CFMutableArrayRef supplemental, CFArrayRef privateResolvers)
293 {
294 CFIndex i;
295 CFIndex n;
296
297 n = isA_CFArray(privateResolvers) ? CFArrayGetCount(privateResolvers) : 0;
298 for (i = 0; i < n; i++) {
299 uint32_t defaultOrder;
300 CFStringRef domain;
301 CFNumberRef num;
302 CFMutableDictionaryRef resolver;
303
304 domain = CFArrayGetValueAtIndex(privateResolvers, i);
305 if (!isA_CFString(domain) || (CFStringGetLength(domain) == 0)) {
306 continue;
307 }
308
309 defaultOrder = DEFAULT_SEARCH_ORDER
310 - (DEFAULT_SEARCH_ORDER / 4)
311 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
312
313 resolver = CFDictionaryCreateMutable(NULL,
314 0,
315 &kCFTypeDictionaryKeyCallBacks,
316 &kCFTypeDictionaryValueCallBacks);
317 CFDictionarySetValue(resolver, kSCPropNetDNSDomainName, domain);
318 CFDictionarySetValue(resolver, kSCPropNetDNSOptions, CFSTR("pdns"));
319 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
320 CFDictionarySetValue(resolver, kSCPropNetDNSSearchOrder, num);
321 CFRelease(num);
322 if (S_pdns_timeout != NULL) {
323 CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_pdns_timeout);
324 }
325 add_resolver(supplemental, resolver);
326 CFRelease(resolver);
327 }
328
329 return;
330 }
331
332
333 static CFComparisonResult
334 compareBySearchOrder(const void *val1, const void *val2, void *context)
335 {
336 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
337 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
338 CFNumberRef num1;
339 CFNumberRef num2;
340 uint32_t order1 = DEFAULT_SEARCH_ORDER;
341 uint32_t order2 = DEFAULT_SEARCH_ORDER;
342
343 num1 = CFDictionaryGetValue(dns1, kSCPropNetDNSSearchOrder);
344 if (!isA_CFNumber(num1) ||
345 !CFNumberGetValue(num1, kCFNumberIntType, &order1)) {
346 order1 = DEFAULT_SEARCH_ORDER;
347 }
348
349 num2 = CFDictionaryGetValue(dns2, kSCPropNetDNSSearchOrder);
350 if (!isA_CFNumber(num2) ||
351 !CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
352 order2 = DEFAULT_SEARCH_ORDER;
353 }
354
355 if (order1 == order2) {
356 // if same "SearchOrder", retain original orderring for configurations
357 if (CFDictionaryGetValueIfPresent(dns1, CFSTR("*ORDER*"), (const void **)&num1) &&
358 CFDictionaryGetValueIfPresent(dns2, CFSTR("*ORDER*"), (const void **)&num2) &&
359 isA_CFNumber(num1) &&
360 isA_CFNumber(num2) &&
361 CFNumberGetValue(num1, kCFNumberIntType, &order1) &&
362 CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
363 if (order1 == order2) {
364 return kCFCompareEqualTo;
365 } else {
366 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
367 }
368 }
369
370 return kCFCompareEqualTo;
371 }
372
373 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
374 }
375
376
377 static CFStringRef
378 trimDomain(CFStringRef domain)
379 {
380 CFIndex length;
381
382 if (!isA_CFString(domain)) {
383 return NULL;
384 }
385
386 // remove any leading/trailing dots
387 length = CFStringGetLength(domain);
388 if ((length > 0) &&
389 (CFStringFindWithOptions(domain,
390 CFSTR("."),
391 CFRangeMake(0, 1),
392 kCFCompareAnchored,
393 NULL) ||
394 CFStringFindWithOptions(domain,
395 CFSTR("."),
396 CFRangeMake(0, length),
397 kCFCompareAnchored|kCFCompareBackwards,
398 NULL))) {
399 CFMutableStringRef trimmed;
400
401 trimmed = CFStringCreateMutableCopy(NULL, 0, domain);
402 CFStringTrim(trimmed, CFSTR("."));
403 domain = (CFStringRef)trimmed;
404 length = CFStringGetLength(domain);
405 } else {
406 CFRetain(domain);
407 }
408
409 if (length == 0) {
410 CFRelease(domain);
411 domain = NULL;
412 }
413
414 return domain;
415 }
416
417
418 static void
419 update_search_domains(CFMutableDictionaryRef *defaultDomain, CFArrayRef supplemental)
420 {
421 CFStringRef defaultDomainName = NULL;
422 uint32_t defaultOrder = DEFAULT_SEARCH_ORDER;
423 CFArrayRef defaultSearchDomains = NULL;
424 CFIndex defaultSearchIndex = 0;
425 CFIndex i;
426 CFMutableArrayRef mySearchDomains;
427 CFMutableArrayRef mySupplemental = (CFMutableArrayRef)supplemental;
428 CFIndex n_supplemental;
429 Boolean searchDomainAdded = FALSE;
430
431 n_supplemental = CFArrayGetCount(supplemental);
432 if (n_supplemental == 0) {
433 // if no supplemental domains
434 return;
435 }
436
437 if (*defaultDomain != NULL) {
438 CFNumberRef num;
439
440 num = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSSearchOrder);
441 if (!isA_CFNumber(num) ||
442 !CFNumberGetValue(num, kCFNumberIntType, &defaultOrder)) {
443 defaultOrder = DEFAULT_SEARCH_ORDER;
444 }
445
446 defaultDomainName = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSDomainName);
447 defaultSearchDomains = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSSearchDomains);
448 }
449
450 mySearchDomains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
451
452 if (isA_CFArray(defaultSearchDomains)) {
453 CFIndex n_search;
454
455 n_search = CFArrayGetCount(defaultSearchDomains);
456 for (i = 0; i < n_search; i++) {
457 CFStringRef search;
458
459 search = CFArrayGetValueAtIndex(defaultSearchDomains, i);
460 search = trimDomain(search);
461 if (search != NULL) {
462 CFArrayAppendValue(mySearchDomains, search);
463 CFRelease(search);
464 }
465 }
466 } else {
467 defaultDomainName = trimDomain(defaultDomainName);
468 if (defaultDomainName != NULL) {
469 char *domain;
470 int domain_parts = 1;
471 char *dp;
472
473 domain = _SC_cfstring_to_cstring(defaultDomainName,
474 NULL,
475 0,
476 kCFStringEncodingUTF8);
477 CFRelease(defaultDomainName);
478
479 // count domain parts
480 for (dp = domain; *dp != '\0'; dp++) {
481 if (*dp == '.') {
482 domain_parts++;
483 }
484 }
485
486 dp = domain;
487 for (i = LOCALDOMAINPARTS; i <= domain_parts; i++) {
488 CFStringRef search;
489
490 search = CFStringCreateWithCString(NULL,
491 dp,
492 kCFStringEncodingUTF8);
493 CFArrayAppendValue(mySearchDomains, search);
494 CFRelease(search);
495
496 dp = strchr(dp, '.') + 1;
497 }
498
499 CFAllocatorDeallocate(NULL, domain);
500 }
501 }
502
503 if (n_supplemental > 1) {
504 mySupplemental = CFArrayCreateMutableCopy(NULL, 0, supplemental);
505 CFArraySortValues(mySupplemental,
506 CFRangeMake(0, n_supplemental),
507 compareBySearchOrder,
508 NULL);
509 }
510
511 for (i = 0; i < n_supplemental; i++) {
512 CFDictionaryRef dns;
513 CFIndex domainIndex;
514 CFNumberRef num;
515 CFStringRef options;
516 CFStringRef supplementalDomain;
517 uint32_t supplementalOrder;
518
519 dns = CFArrayGetValueAtIndex(mySupplemental, i);
520
521 options = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
522 if (isA_CFString(options) && CFEqual(options, CFSTR("pdns"))) {
523 // don't add private resolver domains to the search list
524 continue;
525 }
526
527 supplementalDomain = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
528 supplementalDomain = trimDomain(supplementalDomain);
529 if (supplementalDomain == NULL) {
530 continue;
531 }
532
533 if (CFStringHasSuffix(supplementalDomain, CFSTR(".in-addr.arpa")) ||
534 CFStringHasSuffix(supplementalDomain, CFSTR(".ip6.arpa" ))) {
535 CFRelease(supplementalDomain);
536 continue;
537 }
538
539 domainIndex = CFArrayGetFirstIndexOfValue(mySearchDomains,
540 CFRangeMake(0, CFArrayGetCount(mySearchDomains)),
541 supplementalDomain);
542
543 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
544 if (!isA_CFNumber(num) ||
545 !CFNumberGetValue(num, kCFNumberIntType, &supplementalOrder)) {
546 supplementalOrder = DEFAULT_SEARCH_ORDER;
547 }
548
549 if (supplementalOrder < defaultOrder) {
550 if (domainIndex != kCFNotFound) {
551 // if supplemental domain is already in the search list
552 CFArrayRemoveValueAtIndex(mySearchDomains, domainIndex);
553 if (domainIndex < defaultSearchIndex) {
554 defaultSearchIndex--;
555 }
556 }
557 CFArrayInsertValueAtIndex(mySearchDomains,
558 defaultSearchIndex,
559 supplementalDomain);
560 defaultSearchIndex++;
561 searchDomainAdded = TRUE;
562 } else {
563 if (domainIndex == kCFNotFound) {
564 // add to the (end of the) search list
565 CFArrayAppendValue(mySearchDomains, supplementalDomain);
566 searchDomainAdded = TRUE;
567 }
568 }
569
570 CFRelease(supplementalDomain);
571 }
572
573 if (searchDomainAdded) {
574 if (*defaultDomain == NULL) {
575 *defaultDomain = CFDictionaryCreateMutable(NULL,
576 0,
577 &kCFTypeDictionaryKeyCallBacks,
578 &kCFTypeDictionaryValueCallBacks);
579 }
580 CFDictionarySetValue(*defaultDomain, kSCPropNetDNSSearchDomains, mySearchDomains);
581 }
582
583 CFRelease(mySearchDomains);
584 if (mySupplemental != supplemental) CFRelease(mySupplemental);
585 return;
586 }
587
588
589 static dns_create_resolver_t
590 create_resolver(CFDictionaryRef dns)
591 {
592 CFArrayRef list;
593 CFNumberRef num;
594 dns_create_resolver_t _resolver;
595 CFStringRef str;
596
597 _resolver = _dns_resolver_create();
598
599 // process domain
600 str = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
601 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
602 char domain[NS_MAXDNAME];
603
604 if (_SC_cfstring_to_cstring(str, domain, sizeof(domain), kCFStringEncodingUTF8) != NULL) {
605 _dns_resolver_set_domain(&_resolver, domain);
606 }
607 }
608
609 // process search domains
610 list = CFDictionaryGetValue(dns, kSCPropNetDNSSearchDomains);
611 if (isA_CFArray(list)) {
612 CFIndex i;
613 CFIndex n = CFArrayGetCount(list);
614
615 // add "search" domains
616 for (i = 0; i < n; i++) {
617 str = CFArrayGetValueAtIndex(list, i);
618 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
619 char search[NS_MAXDNAME];
620
621 if (_SC_cfstring_to_cstring(str, search, sizeof(search), kCFStringEncodingUTF8) != NULL) {
622 _dns_resolver_add_search(&_resolver, search);
623 }
624 }
625 }
626 }
627
628 // process nameserver addresses
629 list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
630 if (isA_CFArray(list)) {
631 CFIndex i;
632 CFIndex n = CFArrayGetCount(list);
633
634 for (i = 0; i < n; i++) {
635 union {
636 struct sockaddr sa;
637 struct sockaddr_in sin;
638 struct sockaddr_in6 sin6;
639 } addr;
640 char buf[128];
641
642 str = CFArrayGetValueAtIndex(list, i);
643 if (!isA_CFString(str)) {
644 continue;
645 }
646
647 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
648 continue;
649 }
650
651 bzero(&addr, sizeof(addr));
652 if (inet_aton(buf, &addr.sin.sin_addr) == 1) {
653 /* if IPv4 address */
654 addr.sin.sin_len = sizeof(addr.sin);
655 addr.sin.sin_family = AF_INET;
656 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
657 } else if (inet_pton(AF_INET6, buf, &addr.sin6.sin6_addr) == 1) {
658 /* if IPv6 address */
659 char *p;
660
661 p = strchr(buf, '%');
662 if (p != NULL) {
663 addr.sin6.sin6_scope_id = if_nametoindex(p + 1);
664 }
665
666 addr.sin6.sin6_len = sizeof(addr.sin6);
667 addr.sin6.sin6_family = AF_INET6;
668 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
669 } else {
670 continue;
671 }
672 }
673 }
674
675 // process search order
676 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
677 if (isA_CFNumber(num)) {
678 uint32_t order;
679
680 if (CFNumberGetValue(num, kCFNumberIntType, &order)) {
681 _dns_resolver_set_order(&_resolver, order);
682 }
683 }
684
685 // process port
686 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerPort);
687 if (isA_CFNumber(num)) {
688 int port;
689
690 if (CFNumberGetValue(num, kCFNumberIntType, &port)) {
691 _dns_resolver_set_port(&_resolver, (uint16_t)port);
692 }
693 }
694
695 // process timeout
696 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerTimeout);
697 if (isA_CFNumber(num)) {
698 int timeout;
699
700 if (CFNumberGetValue(num, kCFNumberIntType, &timeout)) {
701 _dns_resolver_set_timeout(&_resolver, (uint32_t)timeout);
702 }
703 }
704
705 // process options
706 str = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
707 if (isA_CFString(str)) {
708 char *options;
709
710 options = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
711 if (options != NULL) {
712 _dns_resolver_set_options(&_resolver, options);
713 CFAllocatorDeallocate(NULL, options);
714 }
715 }
716
717 return _resolver;
718 }
719
720
721 __private_extern__
722 void
723 dns_configuration_set(CFDictionaryRef defaultResolver,
724 CFDictionaryRef services,
725 CFArrayRef serviceOrder,
726 CFArrayRef privateResolvers)
727 {
728 CFIndex i;
729 CFMutableDictionaryRef myDefault;
730 CFStringRef myDomain = NULL;
731 uint32_t myOrder = DEFAULT_SEARCH_ORDER;
732 Boolean myOrderAdded = FALSE;
733 CFIndex n_supplemental;
734 CFNumberRef order;
735 dns_create_resolver_t resolver;
736 CFArrayRef search;
737 CFMutableArrayRef supplemental;
738
739 if (defaultResolver == NULL) {
740 myDefault = CFDictionaryCreateMutable(NULL,
741 0,
742 &kCFTypeDictionaryKeyCallBacks,
743 &kCFTypeDictionaryValueCallBacks);
744 } else {
745 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver);
746
747 // ensure that the default resolver has a search order
748
749 order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder);
750 if (!isA_CFNumber(order) ||
751 !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) {
752 myOrderAdded = TRUE;
753 myOrder = DEFAULT_SEARCH_ORDER;
754 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
755 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order);
756 CFRelease(order);
757 }
758 }
759
760 // establish list of supplemental resolvers
761
762 supplemental = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
763
764 // identify search[] list and/or domain name
765
766 search = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchDomains);
767 if (isA_CFArray(search) && (CFArrayGetCount(search) > 0)) {
768 myDomain = CFArrayGetValueAtIndex(search, 0);
769 myDomain = isA_CFString(myDomain);
770 }
771
772 if (myDomain == NULL) {
773 myDomain = CFDictionaryGetValue(myDefault, kSCPropNetDNSDomainName);
774 myDomain = isA_CFString(myDomain);
775 }
776
777 // add match for default domain
778
779 if (myDomain != NULL) {
780 CFMutableDictionaryRef mySupplemental;
781
782 mySupplemental = CFDictionaryCreateMutableCopy(NULL, 0, myDefault);
783 CFDictionarySetValue (mySupplemental, kSCPropNetDNSDomainName, myDomain);
784 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSearchDomains);
785 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSupplementalMatchDomains);
786 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSupplementalMatchOrders);
787 add_resolver(supplemental, mySupplemental);
788 CFRelease(mySupplemental);
789 }
790
791 // collect (and add) any supplemental resolver configurations
792
793 add_supplemental_resolvers(supplemental, services, serviceOrder);
794
795 // collect (and add) any "private" resolver configurations
796
797 add_private_resolvers(supplemental, privateResolvers);
798
799 // update the "search" list
800
801 update_search_domains(&myDefault, supplemental);
802
803 // add any pre-defined resolver configurations
804
805 add_predefined_resolvers(supplemental);
806
807 // check if the "match for default domain" (above) is really needed
808
809 if (myDomain != NULL) {
810 Boolean sharedDomain = FALSE;
811
812 n_supplemental = CFArrayGetCount(supplemental);
813 for (i = 1; i < n_supplemental; i++) {
814 CFStringRef domain;
815 CFDictionaryRef mySupplemental;
816
817 mySupplemental = CFArrayGetValueAtIndex(supplemental, i);
818 domain = CFDictionaryGetValue(mySupplemental, kSCPropNetDNSDomainName);
819 if (isA_CFString(domain)) {
820 if (CFEqual(myDomain, domain)) {
821 sharedDomain = TRUE;
822 break;
823 }
824
825 if (CFStringHasSuffix(myDomain, domain)) {
826 CFIndex dotIndex;
827
828 dotIndex = CFStringGetLength(myDomain) - CFStringGetLength(domain) - 1;
829 if (dotIndex > 0) {
830 UniChar dot;
831
832 dot = CFStringGetCharacterAtIndex(myDomain, dotIndex);
833 if (dot == (UniChar)'.') {
834 sharedDomain = TRUE;
835 break;
836 }
837 }
838 }
839 }
840 }
841
842 if (!sharedDomain) {
843 // if the default resolver domain name is not shared
844 CFArrayRemoveValueAtIndex(supplemental, 0);
845 }
846 }
847
848 // establish resolver configuration
849
850 n_supplemental = CFArrayGetCount(supplemental);
851 if ((defaultResolver == NULL) && (n_supplemental == 0)) {
852 /*
853 * if no default or supplemental resolvers
854 */
855 if (!_dns_configuration_store(NULL)) {
856 SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
857 }
858 } else {
859 dns_create_config_t _config;
860
861 /*
862 * if default and/or supplemental resolvers are defined
863 */
864 _config = _dns_configuration_create();
865
866 // add [default] resolver
867
868 if ((n_supplemental == 0) && myOrderAdded) {
869 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
870 }
871 resolver = create_resolver(myDefault);
872 _dns_configuration_add_resolver(&_config, resolver);
873 _dns_resolver_free(&resolver);
874
875 // add [supplemental] resolvers
876
877 for (i = 0; i < n_supplemental; i++) {
878 CFDictionaryRef supplementalResolver;
879
880 supplementalResolver = CFArrayGetValueAtIndex(supplemental, i);
881 resolver = create_resolver(supplementalResolver);
882 _dns_configuration_add_resolver(&_config, resolver);
883 _dns_resolver_free(&resolver);
884 }
885
886 // save configuration
887
888 if (!_dns_configuration_store(&_config)) {
889 SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
890 }
891
892 _dns_configuration_free(&_config);
893 }
894
895 CFRelease(myDefault);
896 CFRelease(supplemental);
897
898 return;
899 }
900
901
902 static void
903 load_predefined_resolvers(CFBundleRef bundle)
904 {
905 Boolean ok;
906 CFURLRef url;
907 CFStringRef xmlError = NULL;
908 CFDataRef xmlResolvers = NULL;
909
910 url = CFBundleCopyResourceURL(bundle, CFSTR("Resolvers"), CFSTR("plist"), NULL);
911 if (url == NULL) {
912 return;
913 }
914
915 ok = CFURLCreateDataAndPropertiesFromResource(NULL, url, &xmlResolvers, NULL, NULL, NULL);
916 CFRelease(url);
917 if (!ok || (xmlResolvers == NULL)) {
918 return;
919 }
920
921 /* convert the XML data into a property list */
922 S_predefined = CFPropertyListCreateFromXMLData(NULL, xmlResolvers, kCFPropertyListImmutable, &xmlError);
923 CFRelease(xmlResolvers);
924 if (S_predefined == NULL) {
925 if (xmlError != NULL) {
926 SCLog(TRUE, LOG_DEBUG, CFSTR("add_predefined_resolvers: %@"), xmlError);
927 CFRelease(xmlError);
928 }
929 return;
930 }
931
932 if (!isA_CFArray(S_predefined)) {
933 CFRelease(S_predefined);
934 S_predefined = NULL;
935 return;
936 }
937
938 return;
939 }
940
941
942 __private_extern__
943 void
944 dns_configuration_init(CFBundleRef bundle)
945 {
946 CFDictionaryRef dict;
947
948 dict = CFBundleGetInfoDictionary(bundle);
949 if (isA_CFDictionary(dict)) {
950 S_pdns_timeout = CFDictionaryGetValue(dict, CFSTR("pdns_timeout"));
951 S_pdns_timeout = isA_CFNumber(S_pdns_timeout);
952 }
953
954 load_predefined_resolvers(bundle);
955 return;
956 }
957
958
959 #ifdef MAIN
960 #undef MAIN
961
962 static void
963 split(const void * key, const void * value, void * context)
964 {
965 CFArrayRef components;
966 CFStringRef entity_id;
967 CFStringRef service_id;
968 CFMutableDictionaryRef state_dict;
969
970 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/"));
971 service_id = CFArrayGetValueAtIndex(components, 3);
972 entity_id = CFArrayGetValueAtIndex(components, 4);
973 state_dict = CFDictionaryCreateMutable(NULL,
974 0,
975 &kCFTypeDictionaryKeyCallBacks,
976 &kCFTypeDictionaryValueCallBacks);
977 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
978 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
979 CFRelease(state_dict);
980 CFRelease(components);
981
982 return;
983 }
984
985 int
986 main(int argc, char **argv)
987 {
988 CFDictionaryRef entities;
989 CFStringRef key;
990 CFStringRef pattern;
991 CFMutableArrayRef patterns;
992 CFStringRef primary = NULL;
993 CFDictionaryRef primaryDNS = NULL;
994 CFArrayRef private_resolvers;
995 CFArrayRef service_order = NULL;
996 CFMutableDictionaryRef service_state_dict;
997 CFDictionaryRef setup_global_ipv4;
998 CFDictionaryRef state_global_ipv4;
999 SCDynamicStoreRef store;
1000
1001 _sc_log = FALSE;
1002 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1003
1004 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
1005
1006 // get DNS entities
1007 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1008 kSCDynamicStoreDomainState,
1009 kSCCompAnyRegex,
1010 kSCEntNetDNS);
1011 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1012 CFArrayAppendValue(patterns, pattern);
1013 CFRelease(pattern);
1014 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
1015 CFRelease(patterns);
1016
1017 service_state_dict = CFDictionaryCreateMutable(NULL,
1018 0,
1019 &kCFTypeDictionaryKeyCallBacks,
1020 &kCFTypeDictionaryValueCallBacks);
1021 CFDictionaryApplyFunction(entities, split, service_state_dict);
1022 CFRelease(entities);
1023
1024 // get primary service ID
1025 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1026 kSCDynamicStoreDomainState,
1027 kSCEntNetIPv4);
1028 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1029 CFRelease(key);
1030 if (state_global_ipv4 != NULL) {
1031 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
1032 if (primary != NULL) {
1033 CFDictionaryRef service_dict;
1034
1035 // get DNS configuration for primary service
1036 service_dict = CFDictionaryGetValue(service_state_dict, primary);
1037 if (service_dict != NULL) {
1038 primaryDNS = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
1039 }
1040 }
1041 }
1042
1043 // get serviceOrder
1044 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1045 kSCDynamicStoreDomainSetup,
1046 kSCEntNetIPv4);
1047 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1048 CFRelease(key);
1049 if (setup_global_ipv4 != NULL) {
1050 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
1051 }
1052
1053 // get private resolvers
1054 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1055 kSCDynamicStoreDomainState,
1056 kSCCompNetwork,
1057 CFSTR(kDNSServiceCompPrivateDNS));
1058 private_resolvers = SCDynamicStoreCopyValue(store, key);
1059 CFRelease(key);
1060
1061 // update DNS configuration
1062 dns_configuration_init(CFBundleGetMainBundle());
1063 dns_configuration_set(primaryDNS, service_state_dict, service_order, private_resolvers);
1064
1065 // cleanup
1066 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
1067 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
1068 if (private_resolvers != NULL) CFRelease(private_resolvers);
1069 CFRelease(service_state_dict);
1070 CFRelease(store);
1071
1072 /* not reached */
1073 exit(0);
1074 return 0;
1075 }
1076 #endif
1077