]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/dns-configuration.c
configd-137.3.tar.gz
[apple/configd.git] / Plugins / IPMonitor / dns-configuration.c
1 /*
2 * Copyright (c) 2004 Apple Computer, 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
53 /* pre-defined (supplemental) resolver configurations */
54 static CFArrayRef S_predefined = NULL;
55
56
57 static void
58 add_supplemental(CFMutableArrayRef supplemental, CFDictionaryRef dns, uint32_t defaultOrder)
59 {
60 CFArrayRef domains;
61 CFIndex i;
62 CFIndex n_domains;
63 CFArrayRef orders;
64
65
66 domains = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomains);
67 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0;
68 if (n_domains == 0) {
69 return;
70 }
71
72 orders = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchOrders);
73 if (orders != NULL) {
74 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) {
75 return;
76 }
77 }
78
79 /*
80 * yes, this is a "supplemental" resolver configuration, expand
81 * the match domains and add each to the supplemental list.
82 */
83 for (i = 0; i < n_domains; i++) {
84 CFIndex j;
85 CFStringRef match_domain;
86 CFNumberRef match_order;
87 uint32_t match_order_val = 0;
88 CFMutableDictionaryRef match_resolver;
89 CFIndex n_supplemental;
90
91 match_domain = CFArrayGetValueAtIndex(domains, i);
92 if (!isA_CFString(match_domain)) {
93 continue;
94 }
95
96 match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL;
97
98 match_resolver = CFDictionaryCreateMutableCopy(NULL, 0, dns);
99 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchDomains);
100 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchOrders);
101 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSearchDomains);
102 CFDictionarySetValue(match_resolver, kSCPropNetDNSDomainName, match_domain);
103 if (isA_CFNumber(match_order)) {
104 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, match_order);
105 } else if (!CFDictionaryContainsKey(match_resolver, kSCPropNetDNSSearchOrder)) {
106 CFNumberRef num;
107
108 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
109 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, num);
110 CFRelease(num);
111
112 defaultOrder++; // if multiple domains, maintain ordering
113 }
114
115 match_order = CFDictionaryGetValue(match_resolver, kSCPropNetDNSSearchOrder);
116 if (!isA_CFNumber(match_order) ||
117 !CFNumberGetValue(match_order, kCFNumberIntType, &match_order_val)) {
118 match_order = NULL;
119 match_order_val = 0;
120 }
121
122 n_supplemental = CFArrayGetCount(supplemental);
123 for (j = 0; j < n_supplemental; j++) {
124 CFMutableDictionaryRef compare;
125 Boolean match;
126 CFDictionaryRef supplemental_resolver;
127
128 supplemental_resolver = CFArrayGetValueAtIndex(supplemental, j);
129 if (CFEqual(match_resolver, supplemental_resolver)) {
130 // a real duplicate
131 CFRelease(match_resolver);
132 match_resolver = NULL;
133 break;
134 }
135
136 compare = CFDictionaryCreateMutableCopy(NULL, 0, supplemental_resolver);
137 if (match_order != NULL) {
138 CFDictionarySetValue(compare, kSCPropNetDNSSearchOrder, match_order);
139 }
140 match = CFEqual(match_resolver, compare);
141 CFRelease(compare);
142
143 if (match) {
144 CFNumberRef supplemental_order;
145 uint32_t supplemental_order_val = 0;
146
147 // if only the search order's are different
148 supplemental_order = CFDictionaryGetValue(supplemental_resolver, kSCPropNetDNSSearchOrder);
149 if (!isA_CFNumber(supplemental_order) ||
150 !CFNumberGetValue(supplemental_order, kCFNumberIntType, &supplemental_order_val)) {
151 supplemental_order_val = 0;
152 }
153
154 if (match_order_val < supplemental_order_val ) {
155 // if we should prefer this match resolver, else just skip it
156 CFArraySetValueAtIndex(supplemental, j, match_resolver);
157 }
158
159 CFRelease(match_resolver);
160 match_resolver = NULL;
161 break;
162 }
163 }
164
165 if (match_resolver != NULL) {
166 CFArrayAppendValue(supplemental, match_resolver);
167 CFRelease(match_resolver);
168 }
169 }
170
171 return;
172 }
173
174
175 static void
176 add_predefined_resolvers(CFMutableArrayRef supplemental)
177 {
178 CFIndex i;
179 CFIndex n;
180
181 if (S_predefined == NULL) {
182 return;
183 }
184
185 n = CFArrayGetCount(S_predefined);
186 for (i = 0; i < n; i++) {
187 uint32_t defaultOrder;
188 CFDictionaryRef dns;
189
190 dns = CFArrayGetValueAtIndex(S_predefined, i);
191 if (!isA_CFDictionary(dns)) {
192 continue;
193 }
194
195 defaultOrder = DEFAULT_SEARCH_ORDER +
196 (DEFAULT_SEARCH_ORDER / 2) +
197 ((DEFAULT_SEARCH_ORDER / 1000) * i);
198 add_supplemental(supplemental, dns, defaultOrder);
199 }
200
201 return;
202 }
203
204
205 #define N_QUICK 32
206
207
208 static void
209 add_supplemental_resolvers(CFMutableArrayRef supplemental, CFDictionaryRef services, CFArrayRef service_order)
210 {
211 const void * keys_q[N_QUICK];
212 const void ** keys = keys_q;
213 CFIndex i;
214 CFIndex n_order;
215 CFIndex n_services;
216 const void * vals_q[N_QUICK];
217 const void ** vals = vals_q;
218
219 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
220 if (n_services == 0) {
221 return; // if no services
222 }
223
224 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
225 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
226 vals = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
227 }
228
229 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
230
231 CFDictionaryGetKeysAndValues(services, keys, vals);
232 for (i = 0; i < n_services; i++) {
233 uint32_t defaultOrder;
234 CFDictionaryRef dns;
235 CFDictionaryRef service = (CFDictionaryRef)vals[i];
236
237 if (!isA_CFDictionary(service)) {
238 continue;
239 }
240
241 dns = CFDictionaryGetValue(service, kSCEntNetDNS);
242 if (!isA_CFDictionary(dns)) {
243 continue;
244 }
245
246 defaultOrder = DEFAULT_SEARCH_ORDER -
247 (DEFAULT_SEARCH_ORDER / 2) +
248 ((DEFAULT_SEARCH_ORDER / 1000) * i);
249 if ((n_order > 0) &&
250 !CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) {
251 // push out services not specified in service order
252 defaultOrder += (DEFAULT_SEARCH_ORDER / 1000) * n_services;
253 }
254
255 add_supplemental(supplemental, dns, defaultOrder);
256 }
257
258 if (keys != keys_q) {
259 CFAllocatorDeallocate(NULL, keys);
260 CFAllocatorDeallocate(NULL, vals);
261 }
262
263 return;
264 }
265
266
267 static CFComparisonResult
268 compareBySearchOrder(const void *val1, const void *val2, void *context)
269 {
270 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
271 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
272 CFNumberRef num;
273 uint32_t order1 = DEFAULT_SEARCH_ORDER;
274 uint32_t order2 = DEFAULT_SEARCH_ORDER;
275
276 num = CFDictionaryGetValue(dns1, kSCPropNetDNSSearchOrder);
277 if (!isA_CFNumber(num) ||
278 !CFNumberGetValue(num, kCFNumberIntType, &order1)) {
279 order1 = DEFAULT_SEARCH_ORDER;
280 }
281
282 num = CFDictionaryGetValue(dns2, kSCPropNetDNSSearchOrder);
283 if (!isA_CFNumber(num) ||
284 !CFNumberGetValue(num, kCFNumberIntType, &order2)) {
285 order2 = DEFAULT_SEARCH_ORDER;
286 }
287
288 if (order1 == order2) {
289 return kCFCompareEqualTo;
290 }
291
292 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
293 }
294
295
296 static CFStringRef
297 trimDomain(CFStringRef domain)
298 {
299 CFIndex length;
300 CFRange range;
301 Boolean trimmed = FALSE;
302
303 if (!isA_CFString(domain)) {
304 return NULL;
305 }
306
307 // remove trailing dots
308 length = CFStringGetLength(domain);
309 while (CFStringFindWithOptions(domain,
310 CFSTR("."),
311 CFRangeMake(0, length),
312 kCFCompareAnchored|kCFCompareBackwards,
313 &range)) {
314 trimmed = TRUE;
315 length = range.location;
316 }
317
318 if (length == 0) {
319 return NULL;
320 }
321
322 if (trimmed) {
323 domain = CFStringCreateWithSubstring(NULL, domain, CFRangeMake(0, length));
324 } else {
325 CFRetain(domain);
326 }
327
328 return domain;
329 }
330
331
332 static void
333 update_search_domains(CFMutableDictionaryRef *defaultDomain, CFArrayRef supplemental)
334 {
335 CFStringRef defaultDomainName = NULL;
336 uint32_t defaultOrder = DEFAULT_SEARCH_ORDER;
337 CFArrayRef defaultSearchDomains = NULL;
338 CFIndex defaultSearchIndex = 0;
339 CFIndex i;
340 CFMutableArrayRef mySearchDomains;
341 CFMutableArrayRef mySupplemental = (CFMutableArrayRef)supplemental;
342 CFIndex n_supplemental;
343 Boolean searchDomainAdded = FALSE;
344
345 n_supplemental = CFArrayGetCount(supplemental);
346 if (n_supplemental == 0) {
347 // if no supplemental domains
348 return;
349 }
350
351 if (*defaultDomain != NULL) {
352 CFNumberRef num;
353
354 num = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSSearchOrder);
355 if (!isA_CFNumber(num) ||
356 !CFNumberGetValue(num, kCFNumberIntType, &defaultOrder)) {
357 defaultOrder = DEFAULT_SEARCH_ORDER;
358 }
359
360 defaultDomainName = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSDomainName);
361 defaultSearchDomains = CFDictionaryGetValue(*defaultDomain, kSCPropNetDNSSearchDomains);
362 }
363
364 mySearchDomains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
365
366 if (isA_CFArray(defaultSearchDomains)) {
367 CFIndex n_search;
368
369 n_search = CFArrayGetCount(defaultSearchDomains);
370 for (i = 0; i < n_search; i++) {
371 CFStringRef search;
372
373 search = CFArrayGetValueAtIndex(defaultSearchDomains, i);
374 search = trimDomain(search);
375 if (search != NULL) {
376 CFArrayAppendValue(mySearchDomains, search);
377 CFRelease(search);
378 }
379 }
380 } else {
381 defaultDomainName = trimDomain(defaultDomainName);
382 if (defaultDomainName != NULL) {
383 char *domain;
384 int domain_parts = 1;
385 char *dp;
386
387 domain = _SC_cfstring_to_cstring(defaultDomainName,
388 NULL,
389 0,
390 kCFStringEncodingUTF8);
391 CFRelease(defaultDomainName);
392
393 // count domain parts
394 for (dp = domain; *dp != '\0'; dp++) {
395 if (*dp == '.') {
396 domain_parts++;
397 }
398 }
399
400 dp = domain;
401 for (i = LOCALDOMAINPARTS; i <= domain_parts; i++) {
402 CFStringRef search;
403
404 search = CFStringCreateWithCString(NULL,
405 dp,
406 kCFStringEncodingUTF8);
407 CFArrayAppendValue(mySearchDomains, search);
408 CFRelease(search);
409
410 dp = strchr(dp, '.') + 1;
411 }
412
413 CFAllocatorDeallocate(NULL, domain);
414 }
415 }
416
417 if (n_supplemental > 1) {
418 mySupplemental = CFArrayCreateMutableCopy(NULL, 0, supplemental);
419 CFArraySortValues(mySupplemental,
420 CFRangeMake(0, n_supplemental),
421 compareBySearchOrder,
422 NULL);
423 }
424
425 for (i = 0; i < n_supplemental; i++) {
426 CFDictionaryRef dns;
427 CFIndex domainIndex;
428 CFNumberRef num;
429 CFStringRef supplementalDomain;
430 uint32_t supplementalOrder;
431
432 dns = CFArrayGetValueAtIndex(mySupplemental, i);
433
434 supplementalDomain = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
435 supplementalDomain = trimDomain(supplementalDomain);
436 if (supplementalDomain == NULL) {
437 continue;
438 }
439
440 if (CFStringHasSuffix(supplementalDomain, CFSTR(".in-addr.arpa")) ||
441 CFStringHasSuffix(supplementalDomain, CFSTR(".ip6.arpa" ))) {
442 CFRelease(supplementalDomain);
443 continue;
444 }
445
446 domainIndex = CFArrayGetFirstIndexOfValue(mySearchDomains,
447 CFRangeMake(0, CFArrayGetCount(mySearchDomains)),
448 supplementalDomain);
449
450 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
451 if (!isA_CFNumber(num) ||
452 !CFNumberGetValue(num, kCFNumberIntType, &supplementalOrder)) {
453 supplementalOrder = DEFAULT_SEARCH_ORDER;
454 }
455
456 if (supplementalOrder < defaultOrder) {
457 if (domainIndex != kCFNotFound) {
458 // if supplemental domain is already in the search list
459 CFArrayRemoveValueAtIndex(mySearchDomains, domainIndex);
460 if (domainIndex < defaultSearchIndex) {
461 defaultSearchIndex--;
462 }
463 }
464 CFArrayInsertValueAtIndex(mySearchDomains,
465 defaultSearchIndex,
466 supplementalDomain);
467 defaultSearchIndex++;
468 searchDomainAdded = TRUE;
469 } else {
470 if (domainIndex == kCFNotFound) {
471 // add to the (end of the) search list
472 CFArrayAppendValue(mySearchDomains, supplementalDomain);
473 searchDomainAdded = TRUE;
474 }
475 }
476
477 CFRelease(supplementalDomain);
478 }
479
480 if (searchDomainAdded) {
481 if (*defaultDomain == NULL) {
482 *defaultDomain = CFDictionaryCreateMutable(NULL,
483 0,
484 &kCFTypeDictionaryKeyCallBacks,
485 &kCFTypeDictionaryValueCallBacks);
486 }
487 CFDictionarySetValue(*defaultDomain, kSCPropNetDNSSearchDomains, mySearchDomains);
488 }
489
490 CFRelease(mySearchDomains);
491 if (mySupplemental != supplemental) CFRelease(mySupplemental);
492 return;
493 }
494
495
496 static dns_create_resolver_t
497 create_resolver(CFDictionaryRef dns)
498 {
499 CFArrayRef list;
500 CFNumberRef num;
501 dns_create_resolver_t _resolver;
502 CFStringRef str;
503
504 _resolver = _dns_resolver_create();
505
506 // process domain
507 str = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
508 if (isA_CFString(str)) {
509 char domain[NS_MAXDNAME];
510
511 if (_SC_cfstring_to_cstring(str, domain, sizeof(domain), kCFStringEncodingUTF8) != NULL) {
512 _dns_resolver_set_domain(&_resolver, domain);
513 }
514 }
515
516 // process search domains
517 list = CFDictionaryGetValue(dns, kSCPropNetDNSSearchDomains);
518 if (isA_CFArray(list)) {
519 CFIndex i;
520 CFIndex n = CFArrayGetCount(list);
521
522 // add "search" domains
523 for (i = 0; i < n; i++) {
524 str = CFArrayGetValueAtIndex(list, i);
525 if (isA_CFString(str)) {
526 char search[NS_MAXDNAME];
527
528 if (_SC_cfstring_to_cstring(str, search, sizeof(search), kCFStringEncodingUTF8) != NULL) {
529 _dns_resolver_add_search(&_resolver, search);
530 }
531 }
532 }
533 }
534
535 // process nameserver addresses
536 list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
537 if (isA_CFArray(list)) {
538 CFIndex i;
539 CFIndex n = CFArrayGetCount(list);
540
541 for (i = 0; i < n; i++) {
542 union {
543 struct sockaddr sa;
544 struct sockaddr_in sin;
545 struct sockaddr_in6 sin6;
546 } addr;
547 char buf[128];
548
549 str = CFArrayGetValueAtIndex(list, i);
550 if (!isA_CFString(str)) {
551 continue;
552 }
553
554 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
555 continue;
556 }
557
558 bzero(&addr, sizeof(addr));
559 if (inet_aton(buf, &addr.sin.sin_addr) == 1) {
560 /* if IPv4 address */
561 addr.sin.sin_len = sizeof(addr.sin);
562 addr.sin.sin_family = AF_INET;
563 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
564 } else if (inet_pton(AF_INET6, buf, &addr.sin6.sin6_addr) == 1) {
565 /* if IPv6 address */
566 char *p;
567
568 p = strchr(buf, '%');
569 if (p != NULL) {
570 addr.sin6.sin6_scope_id = if_nametoindex(p + 1);
571 }
572
573 addr.sin6.sin6_len = sizeof(addr.sin6);
574 addr.sin6.sin6_family = AF_INET6;
575 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
576 } else {
577 continue;
578 }
579 }
580 }
581
582 // process search order
583 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
584 if (isA_CFNumber(num)) {
585 uint32_t order;
586
587 if (CFNumberGetValue(num, kCFNumberIntType, &order)) {
588 _dns_resolver_set_order(&_resolver, order);
589 }
590 }
591
592 // process port
593 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerPort);
594 if (isA_CFNumber(num)) {
595 int port;
596
597 if (CFNumberGetValue(num, kCFNumberIntType, &port)) {
598 _dns_resolver_set_port(&_resolver, (uint16_t)port);
599 }
600 }
601
602 // process timeout
603 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerTimeout);
604 if (isA_CFNumber(num)) {
605 int timeout;
606
607 if (CFNumberGetValue(num, kCFNumberIntType, &timeout)) {
608 _dns_resolver_set_timeout(&_resolver, (uint32_t)timeout);
609 }
610 }
611
612 // process options
613 str = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
614 if (isA_CFString(str)) {
615 char *options;
616
617 options = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
618 if (options != NULL) {
619 _dns_resolver_set_options(&_resolver, options);
620 CFAllocatorDeallocate(NULL, options);
621 }
622 }
623
624 return _resolver;
625 }
626
627
628 __private_extern__
629 void
630 dns_configuration_set(CFDictionaryRef defaultResolver,
631 CFDictionaryRef services,
632 CFArrayRef serviceOrder)
633 {
634 CFIndex i;
635 CFMutableDictionaryRef myDefault;
636 CFStringRef myDomain = NULL;
637 uint32_t myOrder = DEFAULT_SEARCH_ORDER;
638 Boolean myOrderAdded = FALSE;
639 CFIndex n_supplemental;
640 CFNumberRef order;
641 dns_create_resolver_t resolver;
642 CFArrayRef search;
643 CFMutableArrayRef supplemental;
644
645 if (defaultResolver == NULL) {
646 myDefault = CFDictionaryCreateMutable(NULL,
647 0,
648 &kCFTypeDictionaryKeyCallBacks,
649 &kCFTypeDictionaryValueCallBacks);
650 } else {
651 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver);
652
653 // ensure that the default resolver has a search order
654
655 order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder);
656 if (!isA_CFNumber(order) ||
657 !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) {
658 myOrderAdded = TRUE;
659 myOrder = DEFAULT_SEARCH_ORDER;
660 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
661 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order);
662 CFRelease(order);
663 }
664 }
665
666 // establish list of supplemental resolvers
667
668 supplemental = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
669
670 // identify search[] list and/or domain name
671
672 search = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchDomains);
673 if (isA_CFArray(search) && (CFArrayGetCount(search) > 0)) {
674 myDomain = CFArrayGetValueAtIndex(search, 0);
675 myDomain = isA_CFString(myDomain);
676 }
677
678 if (myDomain == NULL) {
679 myDomain = CFDictionaryGetValue(myDefault, kSCPropNetDNSDomainName);
680 myDomain = isA_CFString(myDomain);
681 }
682
683 // add match for default domain
684
685 if (myDomain != NULL) {
686 CFMutableDictionaryRef mySupplemental;
687
688 mySupplemental = CFDictionaryCreateMutableCopy(NULL, 0, myDefault);
689 CFDictionarySetValue (mySupplemental, kSCPropNetDNSDomainName, myDomain);
690 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSearchDomains);
691 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSupplementalMatchDomains);
692 CFDictionaryRemoveValue(mySupplemental, kSCPropNetDNSSupplementalMatchOrders);
693 CFArrayAppendValue(supplemental, mySupplemental);
694 CFRelease(mySupplemental);
695 }
696
697 // collect (and add) any supplemental resolver configurations
698
699 add_supplemental_resolvers(supplemental, services, serviceOrder);
700
701 // update the "search" list
702
703 update_search_domains(&myDefault, supplemental);
704
705 // add any pre-defined resolver configurations
706
707 add_predefined_resolvers(supplemental);
708
709 // check if the "match for default domain" (above) is really needed
710
711 if (myDomain != NULL) {
712 Boolean sharedDomain = FALSE;
713
714 n_supplemental = CFArrayGetCount(supplemental);
715 for (i = 1; i < n_supplemental; i++) {
716 CFStringRef domain;
717 CFDictionaryRef mySupplemental;
718
719 mySupplemental = CFArrayGetValueAtIndex(supplemental, i);
720 domain = CFDictionaryGetValue(mySupplemental, kSCPropNetDNSDomainName);
721 if (isA_CFString(domain)) {
722 if (CFEqual(myDomain, domain)) {
723 sharedDomain = TRUE;
724 break;
725 }
726
727 if (CFStringHasSuffix(myDomain, domain)) {
728 CFIndex dotIndex;
729
730 dotIndex = CFStringGetLength(myDomain) - CFStringGetLength(domain) - 1;
731 if (dotIndex > 0) {
732 UniChar dot;
733
734 dot = CFStringGetCharacterAtIndex(myDomain, dotIndex);
735 if (dot == (UniChar)'.') {
736 sharedDomain = TRUE;
737 break;
738 }
739 }
740 }
741 }
742 }
743
744 if (!sharedDomain) {
745 // if the default resolver domain name is not shared
746 CFArrayRemoveValueAtIndex(supplemental, 0);
747 }
748 }
749
750 // establish resolver configuration
751
752 n_supplemental = CFArrayGetCount(supplemental);
753 if ((defaultResolver == NULL) && (n_supplemental == 0)) {
754 /*
755 * if no default or supplemental resolvers
756 */
757 if (!_dns_configuration_store(NULL)) {
758 SCLog(TRUE, LOG_ERR, CFSTR("set_dns_configuration: could not store configuration"));
759 }
760 } else {
761 dns_create_config_t _config;
762
763 /*
764 * if default and/or supplemental resolvers are defined
765 */
766 _config = _dns_configuration_create();
767
768 // add [default] resolver
769
770 if ((n_supplemental == 0) && myOrderAdded) {
771 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
772 }
773 resolver = create_resolver(myDefault);
774 _dns_configuration_add_resolver(&_config, resolver);
775 _dns_resolver_free(&resolver);
776
777 // add [supplemental] resolvers
778
779 for (i = 0; i < n_supplemental; i++) {
780 CFDictionaryRef supplementalResolver;
781
782 supplementalResolver = CFArrayGetValueAtIndex(supplemental, i);
783 resolver = create_resolver(supplementalResolver);
784 _dns_configuration_add_resolver(&_config, resolver);
785 _dns_resolver_free(&resolver);
786 }
787
788 // save configuration
789
790 if (!_dns_configuration_store(&_config)) {
791 SCLog(TRUE, LOG_ERR, CFSTR("set_dns_configuration() failed: could not store configuration"));
792 }
793
794 _dns_configuration_free(&_config);
795 }
796
797 CFRelease(myDefault);
798 CFRelease(supplemental);
799
800 return;
801 }
802
803
804 static void
805 load_predefined_resolvers(CFBundleRef bundle)
806 {
807 Boolean ok;
808 CFURLRef url;
809 CFStringRef xmlError = NULL;
810 CFDataRef xmlResolvers = NULL;
811
812 url = CFBundleCopyResourceURL(bundle, CFSTR("Resolvers"), CFSTR("plist"), NULL);
813 if (url == NULL) {
814 return;
815 }
816
817 ok = CFURLCreateDataAndPropertiesFromResource(NULL, url, &xmlResolvers, NULL, NULL, NULL);
818 CFRelease(url);
819 if (!ok || (xmlResolvers == NULL)) {
820 return;
821 }
822
823 /* convert the XML data into a property list */
824 S_predefined = CFPropertyListCreateFromXMLData(NULL, xmlResolvers, kCFPropertyListImmutable, &xmlError);
825 CFRelease(xmlResolvers);
826 if (S_predefined == NULL) {
827 if (xmlError != NULL) {
828 SCLog(TRUE, LOG_DEBUG, CFSTR("add_predefined_resolvers: %@"), xmlError);
829 CFRelease(xmlError);
830 }
831 return;
832 }
833
834 if (!isA_CFArray(S_predefined)) {
835 CFRelease(S_predefined);
836 S_predefined = NULL;
837 return;
838 }
839
840 return;
841 }
842
843
844 __private_extern__
845 void
846 dns_configuration_init(CFBundleRef bundle)
847 {
848 load_predefined_resolvers(bundle);
849 return;
850 }
851