]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/dns-configuration.c
ca9e7bae14ef2237a193653312cbb96517ea9978
[apple/configd.git] / Plugins / IPMonitor / dns-configuration.c
1 /*
2 * Copyright (c) 2004-2011 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 #include <CommonCrypto/CommonDigest.h>
49
50 #include <CoreFoundation/CoreFoundation.h>
51 #include <SystemConfiguration/SystemConfiguration.h>
52 #include <SystemConfiguration/SCPrivate.h>
53 #include <SystemConfiguration/SCValidation.h>
54
55 #include "dns-configuration.h"
56
57 #include <dnsinfo.h>
58 #include <dnsinfo_create.h>
59
60 #ifdef MAIN
61 #undef MAIN
62 #include "dnsinfo_copy.c"
63 #define MAIN
64 #endif // MAIN
65
66 #include <dns_sd.h>
67 #ifndef kDNSServiceCompMulticastDNS
68 #define kDNSServiceCompMulticastDNS "MulticastDNS"
69 #endif
70 #ifndef kDNSServiceCompPrivateDNS
71 #define kDNSServiceCompPrivateDNS "PrivateDNS"
72 #endif
73
74 #define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
75 #define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
76 #define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
77
78 /* multicast DNS resolver configurations */
79 static CFNumberRef S_mdns_timeout = NULL;
80
81 /* private DNS resolver configurations */
82 static CFNumberRef S_pdns_timeout = NULL;
83
84
85 static void
86 add_resolver(CFMutableArrayRef resolvers, CFMutableDictionaryRef resolver)
87 {
88 CFIndex i;
89 CFStringRef interface;
90 CFIndex n_resolvers;
91 CFNumberRef order;
92 uint32_t order_val = 0;
93
94 order = CFDictionaryGetValue(resolver, kSCPropNetDNSSearchOrder);
95 if (!isA_CFNumber(order) ||
96 !CFNumberGetValue(order, kCFNumberIntType, &order_val)) {
97 order = NULL;
98 order_val = 0;
99 }
100
101 n_resolvers = CFArrayGetCount(resolvers);
102 for (i = 0; i < n_resolvers; i++) {
103 CFDictionaryRef match_resolver;
104
105 match_resolver = CFArrayGetValueAtIndex(resolvers, i);
106 if (CFEqual(resolver, match_resolver)) {
107 // a real duplicate
108 return;
109 }
110
111 if (order != NULL) {
112 CFMutableDictionaryRef compare;
113 Boolean match;
114
115 compare = CFDictionaryCreateMutableCopy(NULL, 0, match_resolver);
116 CFDictionarySetValue(compare, kSCPropNetDNSSearchOrder, order);
117 match = CFEqual(resolver, compare);
118 CFRelease(compare);
119 if (match) {
120 CFNumberRef match_order;
121 uint32_t match_order_val = 0;
122
123 // if only the search order's are different
124 match_order = CFDictionaryGetValue(match_resolver, kSCPropNetDNSSearchOrder);
125 if (!isA_CFNumber(match_order) ||
126 !CFNumberGetValue(match_order, kCFNumberIntType, &match_order_val)) {
127 match_order_val = 0;
128 }
129
130 if (order_val < match_order_val ) {
131 // if we should prefer this match resolver, else just skip it
132 CFArraySetValueAtIndex(resolvers, i, resolver);
133 }
134
135 return;
136 }
137 }
138 }
139
140 order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_resolvers);
141 CFDictionarySetValue(resolver, DNS_CONFIGURATION_ORDER_KEY, order);
142 CFRelease(order);
143
144 interface = CFDictionaryGetValue(resolver, kSCPropInterfaceName);
145 if (interface != NULL) {
146 uint32_t flags;
147 unsigned int if_index = 0;
148 char if_name[IF_NAMESIZE];
149 CFNumberRef num;
150 CFBooleanRef val;
151
152 if (_SC_cfstring_to_cstring(interface,
153 if_name,
154 sizeof(if_name),
155 kCFStringEncodingASCII) != NULL) {
156 if_index = if_nametoindex(if_name);
157 }
158
159 if ((if_index != 0) &&
160 (
161 // check if this is a "scoped" configuration
162 (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
163 isA_CFNumber(num) &&
164 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
165 (flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)
166 ||
167 // check if we should scope all queries with this configuration
168 (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_SCOPED_QUERY_KEY, (const void **)&val) &&
169 isA_CFBoolean(val) &&
170 CFBooleanGetValue(val))
171 )
172 ) {
173 // if interface index available and it should be used
174 num = CFNumberCreate(NULL, kCFNumberIntType, &if_index);
175 CFDictionarySetValue(resolver, DNS_CONFIGURATION_IF_INDEX_KEY, num);
176 CFRelease(num);
177 }
178 }
179
180 CFArrayAppendValue(resolvers, resolver);
181 return;
182 }
183
184
185 static void
186 add_supplemental(CFMutableArrayRef resolvers, CFDictionaryRef dns, uint32_t defaultOrder)
187 {
188 CFArrayRef domains;
189 CFIndex i;
190 CFIndex n_domains;
191 CFArrayRef orders;
192
193 domains = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomains);
194 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0;
195 if (n_domains == 0) {
196 return;
197 }
198
199 orders = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchOrders);
200 if (orders != NULL) {
201 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) {
202 return;
203 }
204 }
205
206 /*
207 * yes, this is a "supplemental" resolver configuration, expand
208 * the match domains and add each to the resolvers list.
209 */
210 for (i = 0; i < n_domains; i++) {
211 CFStringRef match_domain;
212 CFNumberRef match_order;
213 CFMutableDictionaryRef match_resolver;
214
215 match_domain = CFArrayGetValueAtIndex(domains, i);
216 if (!isA_CFString(match_domain)) {
217 continue;
218 }
219
220 match_resolver = CFDictionaryCreateMutableCopy(NULL, 0, dns);
221
222 // set supplemental resolver "domain"
223 if (CFStringGetLength(match_domain) > 0) {
224 CFDictionarySetValue(match_resolver, kSCPropNetDNSDomainName, match_domain);
225 } else {
226 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSDomainName);
227 }
228
229 // set supplemental resolver "search_order"
230 match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL;
231 if (isA_CFNumber(match_order)) {
232 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, match_order);
233 } else if (!CFDictionaryContainsKey(match_resolver, kSCPropNetDNSSearchOrder)) {
234 CFNumberRef num;
235
236 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
237 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, num);
238 CFRelease(num);
239
240 defaultOrder++; // if multiple domains, maintain ordering
241 }
242
243 // remove keys we don't want in a supplemental resolver
244 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchDomains);
245 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchOrders);
246 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSearchDomains);
247 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSortList);
248
249 add_resolver(resolvers, match_resolver);
250 CFRelease(match_resolver);
251 }
252
253 return;
254 }
255
256
257 #define N_QUICK 32
258
259
260 static void
261 add_supplemental_resolvers(CFMutableArrayRef resolvers, CFDictionaryRef services, CFArrayRef service_order)
262 {
263 const void * keys_q[N_QUICK];
264 const void ** keys = keys_q;
265 CFIndex i;
266 CFIndex n_order;
267 CFIndex n_services;
268 const void * vals_q[N_QUICK];
269 const void ** vals = vals_q;
270
271 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
272 if (n_services == 0) {
273 return; // if no services
274 }
275
276 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
277 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
278 vals = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
279 }
280
281 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
282
283 CFDictionaryGetKeysAndValues(services, keys, vals);
284 for (i = 0; i < n_services; i++) {
285 uint32_t defaultOrder;
286 CFDictionaryRef dns;
287 CFDictionaryRef service = (CFDictionaryRef)vals[i];
288
289 if (!isA_CFDictionary(service)) {
290 continue;
291 }
292
293 dns = CFDictionaryGetValue(service, kSCEntNetDNS);
294 if (!isA_CFDictionary(dns)) {
295 continue;
296 }
297
298 defaultOrder = DEFAULT_SEARCH_ORDER
299 - (DEFAULT_SEARCH_ORDER / 2)
300 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
301 if ((n_order > 0) &&
302 !CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) {
303 // push out services not specified in service order
304 defaultOrder += (DEFAULT_SEARCH_ORDER / 1000) * n_services;
305 }
306
307 add_supplemental(resolvers, dns, defaultOrder);
308 }
309
310 if (keys != keys_q) {
311 CFAllocatorDeallocate(NULL, keys);
312 CFAllocatorDeallocate(NULL, vals);
313 }
314
315 return;
316 }
317
318
319 static void
320 add_multicast_resolvers(CFMutableArrayRef resolvers, CFArrayRef multicastResolvers)
321 {
322 CFIndex i;
323 CFIndex n;
324
325 n = isA_CFArray(multicastResolvers) ? CFArrayGetCount(multicastResolvers) : 0;
326 for (i = 0; i < n; i++) {
327 uint32_t defaultOrder;
328 CFStringRef domain;
329 CFNumberRef num;
330 CFMutableDictionaryRef resolver;
331
332 domain = CFArrayGetValueAtIndex(multicastResolvers, i);
333 domain = _SC_trimDomain(domain);
334 if (domain == NULL) {
335 continue;
336 }
337
338 defaultOrder = DEFAULT_SEARCH_ORDER
339 + (DEFAULT_SEARCH_ORDER / 2)
340 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
341
342 resolver = CFDictionaryCreateMutable(NULL,
343 0,
344 &kCFTypeDictionaryKeyCallBacks,
345 &kCFTypeDictionaryValueCallBacks);
346 CFDictionarySetValue(resolver, kSCPropNetDNSDomainName, domain);
347 CFDictionarySetValue(resolver, kSCPropNetDNSOptions, CFSTR("mdns"));
348 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
349 CFDictionarySetValue(resolver, kSCPropNetDNSSearchOrder, num);
350 CFRelease(num);
351 if (S_mdns_timeout != NULL) {
352 CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_mdns_timeout);
353 }
354 add_resolver(resolvers, resolver);
355 CFRelease(resolver);
356 CFRelease(domain);
357 }
358
359 return;
360 }
361
362
363 static void
364 add_private_resolvers(CFMutableArrayRef resolvers, CFArrayRef privateResolvers)
365 {
366 CFIndex i;
367 CFIndex n;
368
369 n = isA_CFArray(privateResolvers) ? CFArrayGetCount(privateResolvers) : 0;
370 for (i = 0; i < n; i++) {
371 uint32_t defaultOrder;
372 CFStringRef domain;
373 CFNumberRef num;
374 CFMutableDictionaryRef resolver;
375
376 domain = CFArrayGetValueAtIndex(privateResolvers, i);
377 domain = _SC_trimDomain(domain);
378 if (domain == NULL) {
379 continue;
380 }
381
382 defaultOrder = DEFAULT_SEARCH_ORDER
383 - (DEFAULT_SEARCH_ORDER / 4)
384 + ((DEFAULT_SEARCH_ORDER / 1000) * i);
385
386 resolver = CFDictionaryCreateMutable(NULL,
387 0,
388 &kCFTypeDictionaryKeyCallBacks,
389 &kCFTypeDictionaryValueCallBacks);
390 CFDictionarySetValue(resolver, kSCPropNetDNSDomainName, domain);
391 CFDictionarySetValue(resolver, kSCPropNetDNSOptions, CFSTR("pdns"));
392 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
393 CFDictionarySetValue(resolver, kSCPropNetDNSSearchOrder, num);
394 CFRelease(num);
395 if (S_pdns_timeout != NULL) {
396 CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_pdns_timeout);
397 }
398 add_resolver(resolvers, resolver);
399 CFRelease(resolver);
400 CFRelease(domain);
401 }
402
403 return;
404 }
405
406
407 static CFComparisonResult
408 compareBySearchOrder(const void *val1, const void *val2, void *context)
409 {
410 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
411 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
412 CFNumberRef num1;
413 CFNumberRef num2;
414 uint32_t order1 = DEFAULT_SEARCH_ORDER;
415 uint32_t order2 = DEFAULT_SEARCH_ORDER;
416
417 num1 = CFDictionaryGetValue(dns1, kSCPropNetDNSSearchOrder);
418 if (!isA_CFNumber(num1) ||
419 !CFNumberGetValue(num1, kCFNumberIntType, &order1)) {
420 order1 = DEFAULT_SEARCH_ORDER;
421 }
422
423 num2 = CFDictionaryGetValue(dns2, kSCPropNetDNSSearchOrder);
424 if (!isA_CFNumber(num2) ||
425 !CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
426 order2 = DEFAULT_SEARCH_ORDER;
427 }
428
429 if (order1 == order2) {
430 // if same "SearchOrder", retain original orderring for configurations
431 if (CFDictionaryGetValueIfPresent(dns1, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num1) &&
432 CFDictionaryGetValueIfPresent(dns2, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num2) &&
433 isA_CFNumber(num1) &&
434 isA_CFNumber(num2) &&
435 CFNumberGetValue(num1, kCFNumberIntType, &order1) &&
436 CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
437 if (order1 == order2) {
438 return kCFCompareEqualTo;
439 } else {
440 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
441 }
442 }
443
444 return kCFCompareEqualTo;
445 }
446
447 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
448 }
449
450
451 static CF_RETURNS_RETAINED CFArrayRef
452 extract_search_domains(CFMutableDictionaryRef defaultDomain, CFArrayRef supplemental)
453 {
454 CFStringRef defaultDomainName = NULL;
455 uint32_t defaultOrder = DEFAULT_SEARCH_ORDER;
456 CFArrayRef defaultSearchDomains = NULL;
457 CFIndex defaultSearchIndex = 0;
458 CFIndex i;
459 CFMutableArrayRef mySearchDomains;
460 CFMutableArrayRef mySupplemental = NULL;
461 CFIndex n_supplemental;
462
463 mySearchDomains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
464
465 if (defaultDomain != NULL) {
466 CFNumberRef num;
467
468 num = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSSearchOrder);
469 if (!isA_CFNumber(num) ||
470 !CFNumberGetValue(num, kCFNumberIntType, &defaultOrder)) {
471 defaultOrder = DEFAULT_SEARCH_ORDER;
472 }
473
474 defaultDomainName = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSDomainName);
475 defaultSearchDomains = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSSearchDomains);
476 }
477
478 // validate the provided "search" domains or move/expand/promote the "domain" name
479 if (isA_CFArray(defaultSearchDomains)) {
480 CFIndex n_search;
481
482 n_search = CFArrayGetCount(defaultSearchDomains);
483 for (i = 0; i < n_search; i++) {
484 CFStringRef search;
485
486 search = CFArrayGetValueAtIndex(defaultSearchDomains, i);
487 search = _SC_trimDomain(search);
488 if (search != NULL) {
489 CFArrayAppendValue(mySearchDomains, search);
490 CFRelease(search);
491 }
492 }
493 } else {
494 defaultDomainName = _SC_trimDomain(defaultDomainName);
495 if (defaultDomainName != NULL) {
496 CFStringRef defaultOptions;
497 char *domain;
498 int domain_parts = 1;
499 char *dp;
500 int ndots = 1;
501
502 #define NDOTS_OPT "ndots="
503 #define NDOTS_OPT_LEN (sizeof("ndots=") - 1)
504
505 defaultOptions = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSOptions);
506 if (defaultOptions != NULL) {
507 char *cp;
508 char *options;
509
510 options = _SC_cfstring_to_cstring(defaultOptions,
511 NULL,
512 0,
513 kCFStringEncodingUTF8);
514 cp = strstr(options, NDOTS_OPT);
515 if ((cp != NULL) &&
516 ((cp == options) || isspace(cp[-1])) &&
517 ((cp[NDOTS_OPT_LEN] != '\0') && isdigit(cp[NDOTS_OPT_LEN]))) {
518 char *end;
519 long val;
520
521 cp += NDOTS_OPT_LEN;
522 errno = 0;
523 val = strtol(cp, &end, 10);
524 if ((*cp != '\0') && (cp != end) && (errno == 0) &&
525 ((*end == '\0') || isspace(*end)) && (val > 0)) {
526 ndots = val;
527 }
528 }
529 CFAllocatorDeallocate(NULL, options);
530 }
531
532 domain = _SC_cfstring_to_cstring(defaultDomainName,
533 NULL,
534 0,
535 kCFStringEncodingUTF8);
536 CFRelease(defaultDomainName);
537
538 // count domain parts
539 for (dp = domain; *dp != '\0'; dp++) {
540 if (*dp == '.') {
541 domain_parts++;
542 }
543 }
544
545 // move "domain" to "search" list (and expand as needed)
546 i = LOCALDOMAINPARTS;
547 dp = domain;
548 do {
549 CFStringRef search;
550 CFStringRef str;
551
552 str = CFStringCreateWithCString(NULL,
553 dp,
554 kCFStringEncodingUTF8);
555 search = _SC_trimDomain(str);
556 CFRelease(str);
557 if (search != NULL) {
558 CFArrayAppendValue(mySearchDomains, search);
559 CFRelease(search);
560 }
561
562 dp = strchr(dp, '.') + 1;
563 } while (++i <= (domain_parts - ndots));
564 CFAllocatorDeallocate(NULL, domain);
565 }
566 }
567
568 // add any supplemental "domain" names to the search list
569 n_supplemental = (supplemental != NULL) ? CFArrayGetCount(supplemental) : 0;
570 if (n_supplemental > 1) {
571 mySupplemental = CFArrayCreateMutableCopy(NULL, 0, supplemental);
572 CFArraySortValues(mySupplemental,
573 CFRangeMake(0, n_supplemental),
574 compareBySearchOrder,
575 NULL);
576 supplemental = mySupplemental;
577 }
578 for (i = 0; i < n_supplemental; i++) {
579 CFDictionaryRef dns;
580 CFIndex domainIndex;
581 CFNumberRef num;
582 CFStringRef options;
583 CFStringRef supplementalDomain;
584 uint32_t supplementalOrder;
585
586 dns = CFArrayGetValueAtIndex(supplemental, i);
587
588 options = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
589 if (isA_CFString(options)) {
590 CFRange range;
591
592 if (CFEqual(options, CFSTR("pdns"))) {
593 // don't add private resolver domains to the search list
594 continue;
595 }
596
597 range = CFStringFind(options, CFSTR("interface="), 0);
598 if (range.location != kCFNotFound) {
599 // don't add scoped resolver domains to the search list
600 continue;
601 }
602 }
603
604 supplementalDomain = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
605 supplementalDomain = _SC_trimDomain(supplementalDomain);
606 if (supplementalDomain == NULL) {
607 continue;
608 }
609
610 if (CFStringHasSuffix(supplementalDomain, CFSTR(".in-addr.arpa")) ||
611 CFStringHasSuffix(supplementalDomain, CFSTR(".ip6.arpa" ))) {
612 CFRelease(supplementalDomain);
613 continue;
614 }
615
616 domainIndex = CFArrayGetFirstIndexOfValue(mySearchDomains,
617 CFRangeMake(0, CFArrayGetCount(mySearchDomains)),
618 supplementalDomain);
619
620 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
621 if (!isA_CFNumber(num) ||
622 !CFNumberGetValue(num, kCFNumberIntType, &supplementalOrder)) {
623 supplementalOrder = DEFAULT_SEARCH_ORDER;
624 }
625
626 if (supplementalOrder < defaultOrder) {
627 if (domainIndex != kCFNotFound) {
628 // if supplemental domain is already in the search list
629 CFArrayRemoveValueAtIndex(mySearchDomains, domainIndex);
630 if (domainIndex < defaultSearchIndex) {
631 defaultSearchIndex--;
632 }
633 }
634 CFArrayInsertValueAtIndex(mySearchDomains,
635 defaultSearchIndex,
636 supplementalDomain);
637 defaultSearchIndex++;
638 } else {
639 if (domainIndex == kCFNotFound) {
640 // add to the (end of the) search list
641 CFArrayAppendValue(mySearchDomains, supplementalDomain);
642 }
643 }
644
645 CFRelease(supplementalDomain);
646 }
647 if (mySupplemental != NULL) CFRelease(mySupplemental);
648
649 // update the "search" domains
650 if (CFArrayGetCount(mySearchDomains) == 0) {
651 CFRelease(mySearchDomains);
652 mySearchDomains = NULL;
653 }
654
655 // remove the "domain" name and "search" list
656 CFDictionaryRemoveValue(defaultDomain, kSCPropNetDNSDomainName);
657 CFDictionaryRemoveValue(defaultDomain, kSCPropNetDNSSearchDomains);
658
659 return mySearchDomains;
660 }
661
662
663 static void
664 add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArrayRef service_order)
665 {
666 const void * keys_q[N_QUICK];
667 const void ** keys = keys_q;
668 CFIndex i;
669 CFIndex n_order;
670 CFIndex n_services;
671 CFMutableArrayRef order;
672 CFMutableSetRef seen;
673
674 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
675 if (n_services == 0) {
676 return; // if no services
677 }
678
679 // ensure that we process all services in order
680
681 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
682 if (n_order > 0) {
683 order = CFArrayCreateMutableCopy(NULL, 0, service_order);
684 } else{
685 order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
686 }
687
688 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
689 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
690 }
691 CFDictionaryGetKeysAndValues(services, keys, NULL);
692 for (i = 0; i < n_services; i++) {
693 CFStringRef serviceID = (CFStringRef)keys[i];
694
695 if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) {
696 CFArrayAppendValue(order, serviceID);
697 n_order++;
698 }
699 }
700 if (keys != keys_q) {
701 CFAllocatorDeallocate(NULL, keys);
702 }
703
704 // iterate over services
705
706 seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
707 for (i = 0; i < n_order; i++) {
708 CFDictionaryRef dns;
709 uint32_t flags;
710 char if_name[IF_NAMESIZE];
711 CFStringRef interface;
712 CFMutableDictionaryRef newDNS;
713 CFNumberRef num;
714 CFArrayRef searchDomains;
715 CFDictionaryRef service;
716 CFStringRef serviceID;
717
718 serviceID = CFArrayGetValueAtIndex(order, i);
719 service = CFDictionaryGetValue(services, serviceID);
720 if (!isA_CFDictionary(service)) {
721 // if no service
722 continue;
723 }
724
725 dns = CFDictionaryGetValue(service, kSCEntNetDNS);
726 if (!isA_CFDictionary(dns)) {
727 // if no DNS
728 continue;
729 }
730
731 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
732 if (interface == NULL) {
733 // if no [scoped] interface
734 continue;
735 }
736 if (CFSetContainsValue(seen, interface)) {
737 // if we've already processed this [scoped] interface
738 continue;
739 }
740 CFSetSetValue(seen, interface);
741
742 if ((_SC_cfstring_to_cstring(interface,
743 if_name,
744 sizeof(if_name),
745 kCFStringEncodingASCII) == NULL) ||
746 (if_nametoindex(if_name) == 0)) {
747 // if interface index not available
748 continue;
749 }
750
751 // add [scoped] resolver entry
752 newDNS = CFDictionaryCreateMutableCopy(NULL, 0, dns);
753
754 // set search list
755 searchDomains = extract_search_domains(newDNS, NULL);
756 if (searchDomains != NULL) {
757 CFDictionarySetValue(newDNS, kSCPropNetDNSSearchDomains, searchDomains);
758 CFRelease(searchDomains);
759 }
760
761 // set "scoped" configuration flag(s)
762 if (!CFDictionaryGetValueIfPresent(newDNS, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) ||
763 !isA_CFNumber(num) ||
764 !CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
765 flags = 0;
766 }
767 flags |= DNS_RESOLVER_FLAGS_SCOPED;
768 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags);
769 CFDictionarySetValue(newDNS, DNS_CONFIGURATION_FLAGS_KEY, num);
770 CFRelease(num);
771
772 // remove keys we don't want in a [scoped] resolver
773 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchDomains);
774 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchOrders);
775
776 add_resolver(scoped, newDNS);
777 CFRelease(newDNS);
778 }
779
780 CFRelease(seen);
781 CFRelease(order);
782 return;
783 }
784
785
786 static void
787 add_default_resolver(CFMutableArrayRef resolvers,
788 CFDictionaryRef defaultResolver,
789 Boolean *orderAdded,
790 CFArrayRef *searchDomains)
791 {
792 CFMutableDictionaryRef myDefault;
793 uint32_t myOrder = DEFAULT_SEARCH_ORDER;
794 CFNumberRef order;
795
796 if (defaultResolver == NULL) {
797 myDefault = CFDictionaryCreateMutable(NULL,
798 0,
799 &kCFTypeDictionaryKeyCallBacks,
800 &kCFTypeDictionaryValueCallBacks);
801 } else {
802 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver);
803 }
804
805 // ensure that the default resolver has a search order
806
807 order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder);
808 if (!isA_CFNumber(order) ||
809 !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) {
810 myOrder = DEFAULT_SEARCH_ORDER;
811 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
812 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order);
813 CFRelease(order);
814 *orderAdded = TRUE;
815 }
816
817 // extract the "search" domain list for the default resolver (and
818 // any supplemental resolvers)
819
820 *searchDomains = extract_search_domains(myDefault, resolvers);
821
822 // add the default resolver
823
824 add_resolver(resolvers, myDefault);
825 CFRelease(myDefault);
826 return;
827 }
828
829
830 /*
831 * rankReachability()
832 * Not reachable == 0
833 * Connection Required == 1
834 * Reachable == 2
835 */
836 static int
837 rankReachability(SCNetworkReachabilityFlags flags)
838 {
839 int rank = 0;
840
841 if (flags & kSCNetworkReachabilityFlagsReachable) rank = 2;
842 if (flags & kSCNetworkReachabilityFlagsConnectionRequired) rank = 1;
843 return rank;
844 }
845
846
847 static dns_create_resolver_t
848 create_resolver(CFDictionaryRef dns)
849 {
850 CFArrayRef list;
851 CFNumberRef num;
852 dns_create_resolver_t _resolver;
853 CFStringRef str;
854 CFMutableArrayRef serverAddresses = NULL;
855 CFStringRef targetInterface = NULL;
856 unsigned int targetInterfaceIndex = 0;
857
858 _resolver = _dns_resolver_create();
859
860 // process domain
861 str = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
862 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
863 char domain[NS_MAXDNAME];
864
865 if (_SC_cfstring_to_cstring(str, domain, sizeof(domain), kCFStringEncodingUTF8) != NULL) {
866 _dns_resolver_set_domain(&_resolver, domain);
867 }
868 }
869
870 // process search domains
871 list = CFDictionaryGetValue(dns, kSCPropNetDNSSearchDomains);
872 if (isA_CFArray(list)) {
873 CFIndex i;
874 CFIndex n = CFArrayGetCount(list);
875
876 // add "search" domains
877 for (i = 0; i < n; i++) {
878 str = CFArrayGetValueAtIndex(list, i);
879 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
880 char search[NS_MAXDNAME];
881
882 if (_SC_cfstring_to_cstring(str, search, sizeof(search), kCFStringEncodingUTF8) != NULL) {
883 _dns_resolver_add_search(&_resolver, search);
884 }
885 }
886 }
887 }
888
889 // process interface index
890 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_IF_INDEX_KEY);
891 if (isA_CFNumber(num)) {
892 int if_index;
893
894 if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) {
895 char if_name[IFNAMSIZ];
896
897 _dns_resolver_set_if_index(&_resolver, if_index);
898
899 if ((if_index != 0) &&
900 (if_indextoname(if_index, if_name) != NULL)) {
901 targetInterface = CFStringCreateWithCString(NULL,
902 if_name,
903 kCFStringEncodingASCII);
904 targetInterfaceIndex = if_index;
905 }
906 }
907 }
908
909 // process nameserver addresses
910 list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
911 if (isA_CFArray(list)) {
912 CFIndex i;
913 CFIndex n = CFArrayGetCount(list);
914
915 serverAddresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
916
917 for (i = 0; i < n; i++) {
918 union {
919 struct sockaddr sa;
920 struct sockaddr_in sin;
921 struct sockaddr_in6 sin6;
922 } addr;
923 char buf[64];
924 CFDataRef serverAddress;
925
926 str = CFArrayGetValueAtIndex(list, i);
927 if (!isA_CFString(str)) {
928 continue;
929 }
930
931 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
932 continue;
933 }
934
935 if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
936 continue;
937 }
938
939 if ((addr.sa.sa_family == AF_INET6) &&
940 (IN6_IS_ADDR_LINKLOCAL(&addr.sin6.sin6_addr) ||
941 IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6.sin6_addr)) &&
942 (addr.sin6.sin6_scope_id == 0) &&
943 (targetInterfaceIndex != 0)) {
944 // for link local [IPv6] addresses, if the scope id is not
945 // set then we should use the interface associated with the
946 // resolver configuration
947 addr.sin6.sin6_scope_id = targetInterfaceIndex;
948 }
949
950 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
951
952 serverAddress = CFDataCreate(NULL, (const void *)&addr.sa, addr.sa.sa_len);
953 CFArrayAppendValue(serverAddresses, serverAddress);
954 CFRelease(serverAddress);
955 }
956 }
957
958 // process search order
959 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
960 if (isA_CFNumber(num)) {
961 uint32_t order;
962
963 if (CFNumberGetValue(num, kCFNumberIntType, &order)) {
964 _dns_resolver_set_order(&_resolver, order);
965 }
966 }
967
968 // process sortlist
969 list = CFDictionaryGetValue(dns, kSCPropNetDNSSortList);
970 if (isA_CFArray(list)) {
971 CFIndex i;
972 CFIndex n = CFArrayGetCount(list);
973
974 for (i = 0; i < n; i++) {
975 char buf[128];
976 char *slash;
977 dns_sortaddr_t sortaddr;
978
979 str = CFArrayGetValueAtIndex(list, i);
980 if (!isA_CFString(str)) {
981 continue;
982 }
983
984 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
985 continue;
986 }
987
988 slash = strchr(buf, '/');
989 if (slash != NULL) {
990 *slash = '\0';
991 }
992
993 bzero(&sortaddr, sizeof(sortaddr));
994 if (inet_aton(buf, &sortaddr.address) != 1) {
995 /* if address not valid */
996 continue;
997 }
998
999 if (slash != NULL) {
1000 if (inet_aton(slash + 1, &sortaddr.mask) != 1) {
1001 /* if subnet mask not valid */
1002 continue;
1003 }
1004 } else {
1005 in_addr_t a;
1006 in_addr_t m;
1007
1008 a = ntohl(sortaddr.address.s_addr);
1009 if (IN_CLASSA(a)) {
1010 m = IN_CLASSA_NET;
1011 } else if (IN_CLASSB(a)) {
1012 m = IN_CLASSB_NET;
1013 } else if (IN_CLASSC(a)) {
1014 m = IN_CLASSC_NET;
1015 } else {
1016 continue;
1017 }
1018
1019 sortaddr.mask.s_addr = htonl(m);
1020 }
1021
1022 _dns_resolver_add_sortaddr(&_resolver, &sortaddr);
1023 }
1024 }
1025
1026 // process port
1027 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerPort);
1028 if (isA_CFNumber(num)) {
1029 int port;
1030
1031 if (CFNumberGetValue(num, kCFNumberIntType, &port)) {
1032 _dns_resolver_set_port(&_resolver, (uint16_t)port);
1033 }
1034 }
1035
1036 // process timeout
1037 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerTimeout);
1038 if (isA_CFNumber(num)) {
1039 int timeout;
1040
1041 if (CFNumberGetValue(num, kCFNumberIntType, &timeout)) {
1042 _dns_resolver_set_timeout(&_resolver, (uint32_t)timeout);
1043 }
1044 }
1045
1046 // process options
1047 str = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
1048 if (isA_CFString(str)) {
1049 char *options;
1050
1051 options = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
1052 if (options != NULL) {
1053 _dns_resolver_set_options(&_resolver, options);
1054 CFAllocatorDeallocate(NULL, options);
1055 }
1056 }
1057
1058 // process flags
1059 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_FLAGS_KEY);
1060 if (isA_CFNumber(num)) {
1061 uint32_t flags;
1062
1063 if (CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
1064 _dns_resolver_set_flags(&_resolver, flags);
1065 }
1066 }
1067
1068 if (serverAddresses != NULL) {
1069 SCNetworkReachabilityFlags flags = kSCNetworkReachabilityFlagsReachable;
1070 CFIndex i;
1071 CFIndex n = CFArrayGetCount(serverAddresses);
1072 CFMutableDictionaryRef targetOptions;
1073
1074 targetOptions = CFDictionaryCreateMutable(NULL,
1075 0,
1076 &kCFTypeDictionaryKeyCallBacks,
1077 &kCFTypeDictionaryValueCallBacks);
1078 if (targetInterface != NULL) {
1079 CFDictionarySetValue(targetOptions,
1080 kSCNetworkReachabilityOptionInterface,
1081 targetInterface);
1082 }
1083
1084 for (i = 0; i < n; i++) {
1085 SCNetworkReachabilityFlags ns_flags;
1086 Boolean ok;
1087 CFDataRef serverAddress;
1088 SCNetworkReachabilityRef target;
1089
1090 serverAddress = CFArrayGetValueAtIndex(serverAddresses, i);
1091 CFDictionarySetValue(targetOptions,
1092 kSCNetworkReachabilityOptionRemoteAddress,
1093 serverAddress);
1094 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
1095 if (target == NULL) {
1096 CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface);
1097 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
1098 if (target != NULL) {
1099 // if interface name not (no longer) valid
1100 CFRelease(target);
1101 flags = 0;
1102 break;
1103 }
1104
1105 // address not valid?
1106 SCLog(TRUE, LOG_ERR,
1107 CFSTR("create_resolver SCNetworkReachabilityCreateWithOptions() failed:\n options = %@"),
1108 targetOptions);
1109 break;
1110 }
1111
1112 ok = SCNetworkReachabilityGetFlags(target, &ns_flags);
1113 CFRelease(target);
1114 if (!ok) {
1115 break;
1116 }
1117
1118 if ((i == 0) ||
1119 (rankReachability(ns_flags) < rankReachability(flags))) {
1120 /* return the worst case result */
1121 flags = ns_flags;
1122 }
1123 }
1124
1125 _dns_resolver_set_reach_flags(&_resolver, flags);
1126
1127 CFRelease(targetOptions);
1128 CFRelease(serverAddresses);
1129 }
1130
1131 if (targetInterface != NULL) {
1132 CFRelease(targetInterface);
1133 }
1134
1135 return _resolver;
1136 }
1137
1138
1139 static __inline__ Boolean
1140 isScopedConfiguration(CFDictionaryRef dns)
1141 {
1142 uint32_t flags;
1143 CFNumberRef num;
1144
1145 if ((dns != NULL) &&
1146 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
1147 (num != NULL) &&
1148 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
1149 ((flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)) {
1150 return TRUE;
1151 }
1152
1153 return FALSE;
1154 }
1155
1156
1157 static CFComparisonResult
1158 compareDomain(const void *val1, const void *val2, void *context)
1159 {
1160 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
1161 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
1162 CFStringRef domain1;
1163 CFStringRef domain2;
1164 CFArrayRef labels1 = NULL;
1165 CFArrayRef labels2 = NULL;
1166 CFIndex n1;
1167 CFIndex n2;
1168 CFComparisonResult result;
1169 Boolean rev1;
1170 Boolean rev2;
1171 Boolean scoped1;
1172 Boolean scoped2;
1173
1174 // "default" domains sort before "supplemental" domains
1175 domain1 = CFDictionaryGetValue(dns1, kSCPropNetDNSDomainName);
1176 domain2 = CFDictionaryGetValue(dns2, kSCPropNetDNSDomainName);
1177 if (domain1 == NULL) {
1178 return kCFCompareLessThan;
1179 } else if (domain2 == NULL) {
1180 return kCFCompareGreaterThan;
1181 }
1182
1183 // sort non-scoped before scoped
1184 scoped1 = isScopedConfiguration(dns1);
1185 scoped2 = isScopedConfiguration(dns2);
1186 if (scoped1 != scoped2) {
1187 if (!scoped1) {
1188 return kCFCompareLessThan;
1189 } else {
1190 return kCFCompareGreaterThan;
1191 }
1192 }
1193
1194 // must have domain names for any further comparisons
1195 if ((domain1 == NULL) || (domain2 == NULL)) {
1196 return kCFCompareEqualTo;
1197 }
1198
1199 // forward (A, AAAA) domains sort before reverse (PTR) domains
1200 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa"));
1201 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa"));
1202 if (rev1 != rev2) {
1203 if (rev1) {
1204 return kCFCompareGreaterThan;
1205 } else {
1206 return kCFCompareLessThan;
1207 }
1208 }
1209
1210 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR("."));
1211 n1 = CFArrayGetCount(labels1);
1212
1213 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR("."));
1214 n2 = CFArrayGetCount(labels2);
1215
1216 while ((n1 > 0) && (n2 > 0)) {
1217 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1);
1218 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2);
1219
1220 // compare domain labels
1221 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive);
1222 if (result != kCFCompareEqualTo) {
1223 goto done;
1224 }
1225 }
1226
1227 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1228 if (n1 > n2) {
1229 result = kCFCompareLessThan;
1230 goto done;
1231 } else if (n1 < n2) {
1232 result = kCFCompareGreaterThan;
1233 goto done;
1234 }
1235
1236 // sort by search order
1237 result = compareBySearchOrder(val1, val2, context);
1238
1239 done :
1240
1241 if (labels1 != NULL) CFRelease(labels1);
1242 if (labels2 != NULL) CFRelease(labels2);
1243 return result;
1244 }
1245
1246
1247 __private_extern__
1248 Boolean
1249 dns_configuration_set(CFDictionaryRef defaultResolver,
1250 CFDictionaryRef services,
1251 CFArrayRef serviceOrder,
1252 CFArrayRef multicastResolvers,
1253 CFArrayRef privateResolvers)
1254 {
1255 dns_create_config_t _config;
1256 Boolean changed = FALSE;
1257 CFIndex i;
1258 CFMutableDictionaryRef myDefault;
1259 Boolean myOrderAdded = FALSE;
1260 CFArrayRef mySearchDomains = NULL;
1261 CFIndex n_resolvers;
1262 CFMutableArrayRef resolvers;
1263 unsigned char signature[CC_SHA1_DIGEST_LENGTH];
1264 static unsigned char signature_last[CC_SHA1_DIGEST_LENGTH];
1265
1266 // establish list of resolvers
1267
1268 resolvers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1269
1270 // collect (and add) any "supplemental" resolver configurations
1271
1272 add_supplemental_resolvers(resolvers, services, serviceOrder);
1273
1274 // collect (and add) any "private" resolver configurations
1275
1276 add_private_resolvers(resolvers, privateResolvers);
1277
1278 // add the "default" resolver
1279
1280 add_default_resolver(resolvers, defaultResolver, &myOrderAdded, &mySearchDomains);
1281
1282 // collect (and add) any "multicast" resolver configurations
1283
1284 add_multicast_resolvers(resolvers, multicastResolvers);
1285
1286 // collect (and add) any "scoped" resolver configurations
1287
1288 add_scoped_resolvers(resolvers, services, serviceOrder);
1289
1290 // sort resolvers
1291
1292 n_resolvers = CFArrayGetCount(resolvers);
1293 if (n_resolvers > 1) {
1294 CFArraySortValues(resolvers, CFRangeMake(0, n_resolvers), compareDomain, NULL);
1295 }
1296
1297 // cleanup
1298
1299 for (i = n_resolvers; --i > 0; ) {
1300 CFDictionaryRef resolver;
1301
1302 resolver = CFArrayGetValueAtIndex(resolvers, i);
1303 if (!CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) &&
1304 !CFDictionaryContainsKey(resolver, kSCPropNetDNSSearchDomains) &&
1305 !CFDictionaryContainsKey(resolver, kSCPropNetDNSServerAddresses)) {
1306 // remove empty resolver
1307 CFArrayRemoveValueAtIndex(resolvers, i);
1308 n_resolvers--;
1309 }
1310 }
1311
1312 // update the default resolver
1313
1314 myDefault = CFDictionaryCreateMutableCopy(NULL,
1315 0,
1316 CFArrayGetValueAtIndex(resolvers, 0));
1317 if (mySearchDomains != NULL) {
1318 // add search domains to the default resolver
1319 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchDomains, mySearchDomains);
1320 CFRelease(mySearchDomains);
1321 }
1322 if (myOrderAdded && (n_resolvers > 1)) {
1323 CFDictionaryRef resolver;
1324
1325 resolver = CFArrayGetValueAtIndex(resolvers, 1);
1326 if (CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) ||
1327 isScopedConfiguration(resolver)) {
1328 // if not a supplemental "default" resolver (a domain name is
1329 // present) or if it's a scoped configuration
1330 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
1331 }
1332 }
1333 CFArraySetValueAtIndex(resolvers, 0, myDefault);
1334 CFRelease(myDefault);
1335
1336 // establish resolver configuration
1337
1338 if ((defaultResolver == NULL) && (n_resolvers <= 1)) {
1339 /*
1340 * if no default and no supplemental/scoped resolvers
1341 */
1342 _config = NULL;
1343 } else {
1344 /*
1345 * if default and/or supplemental/scoped resolvers are defined
1346 */
1347 _config = _dns_configuration_create();
1348
1349 // add resolvers
1350
1351 for (i = 0; i < n_resolvers; i++) {
1352 CFDictionaryRef resolver;
1353 dns_create_resolver_t _resolver;
1354
1355 resolver = CFArrayGetValueAtIndex(resolvers, i);
1356 _resolver = create_resolver(resolver);
1357 _dns_configuration_add_resolver(&_config, _resolver);
1358 _dns_resolver_free(&_resolver);
1359 }
1360
1361 #if !TARGET_OS_IPHONE
1362 // add flatfile resolvers
1363
1364 _dnsinfo_flatfile_add_resolvers(&_config);
1365 #endif // !TARGET_OS_IPHONE
1366 }
1367
1368 // check if the configuration changed
1369 _dns_configuration_signature(&_config, signature, sizeof(signature));
1370 if (bcmp(signature, signature_last, sizeof(signature)) != 0) {
1371 changed = TRUE;
1372 }
1373 bcopy(signature, signature_last, sizeof(signature));
1374
1375 // save configuration
1376 if (!_dns_configuration_store(&_config)) {
1377 SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
1378 }
1379 if (_config != NULL) _dns_configuration_free(&_config);
1380
1381 CFRelease(resolvers);
1382 return changed;
1383 }
1384
1385
1386 #if !TARGET_OS_IPHONE
1387 static SCDynamicStoreRef dns_configuration_store;
1388 static SCDynamicStoreCallBack dns_configuration_callout;
1389
1390 static void
1391 dns_configuration_changed(CFMachPortRef port, void *msg, CFIndex size, void *info)
1392 {
1393 CFStringRef key = CFSTR(_PATH_RESOLVER_DIR);
1394 CFArrayRef keys;
1395 Boolean resolvers_now;
1396 static Boolean resolvers_save = FALSE;
1397 struct stat statbuf;
1398
1399 resolvers_now = (stat(_PATH_RESOLVER_DIR, &statbuf) == 0);
1400 if (!resolvers_save && (resolvers_save == resolvers_now)) {
1401 // if we did not (and still do not) have an "/etc/resolvers"
1402 // directory than this notification is the result of a change
1403 // to the "/etc" directory.
1404 return;
1405 }
1406 resolvers_save = resolvers_now;
1407
1408 SCLog(TRUE, LOG_DEBUG, CFSTR(_PATH_RESOLVER_DIR " changed"));
1409
1410 // fake a "DNS" change
1411 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
1412 (*dns_configuration_callout)(dns_configuration_store, keys, NULL);
1413 CFRelease(keys);
1414 return;
1415 }
1416
1417
1418 __private_extern__
1419 void
1420 dns_configuration_monitor(SCDynamicStoreRef store, SCDynamicStoreCallBack callout)
1421 {
1422 CFMachPortRef mp;
1423 mach_port_t notify_port;
1424 int notify_token;
1425 CFRunLoopSourceRef rls;
1426 uint32_t status;
1427
1428 dns_configuration_store = store;
1429 dns_configuration_callout = callout;
1430
1431 status = notify_register_mach_port(_PATH_RESOLVER_DIR, &notify_port, 0, &notify_token);
1432 if (status != NOTIFY_STATUS_OK) {
1433 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1434 return;
1435 }
1436
1437 status = notify_monitor_file(notify_token, "/private" _PATH_RESOLVER_DIR, 0);
1438 if (status != NOTIFY_STATUS_OK) {
1439 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_monitor_file() failed"));
1440 (void)notify_cancel(notify_token);
1441 return;
1442 }
1443
1444 mp = _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1445 notify_port,
1446 dns_configuration_changed,
1447 NULL);
1448
1449 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1450 if (rls == NULL) {
1451 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1452 CFRelease(mp);
1453 (void)notify_cancel(notify_token);
1454 return;
1455 }
1456 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1457 CFRelease(rls);
1458
1459 CFRelease(mp);
1460 return;
1461 }
1462 #endif // !TARGET_OS_IPHONE
1463
1464
1465 __private_extern__
1466 void
1467 dns_configuration_init(CFBundleRef bundle)
1468 {
1469 CFDictionaryRef dict;
1470
1471 dict = CFBundleGetInfoDictionary(bundle);
1472 if (isA_CFDictionary(dict)) {
1473 S_mdns_timeout = CFDictionaryGetValue(dict, CFSTR("mdns_timeout"));
1474 S_mdns_timeout = isA_CFNumber(S_mdns_timeout);
1475
1476 S_pdns_timeout = CFDictionaryGetValue(dict, CFSTR("pdns_timeout"));
1477 S_pdns_timeout = isA_CFNumber(S_pdns_timeout);
1478 }
1479
1480 return;
1481 }
1482
1483
1484 #pragma mark -
1485 #pragma mark Standalone test code
1486
1487
1488 #ifdef MAIN
1489
1490 static void
1491 split(const void * key, const void * value, void * context)
1492 {
1493 CFArrayRef components;
1494 CFStringRef entity_id;
1495 CFStringRef service_id;
1496 CFMutableDictionaryRef state_dict;
1497
1498 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/"));
1499 service_id = CFArrayGetValueAtIndex(components, 3);
1500 entity_id = CFArrayGetValueAtIndex(components, 4);
1501 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id);
1502 if (state_dict != NULL) {
1503 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
1504 } else {
1505 state_dict = CFDictionaryCreateMutable(NULL,
1506 0,
1507 &kCFTypeDictionaryKeyCallBacks,
1508 &kCFTypeDictionaryValueCallBacks);
1509 }
1510
1511 if (CFEqual(entity_id, kSCEntNetIPv4) ||
1512 CFEqual(entity_id, kSCEntNetIPv6)) {
1513 CFStringRef interface;
1514
1515 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName);
1516 if (interface != NULL) {
1517 CFDictionaryRef dns;
1518 CFMutableDictionaryRef new_dns;
1519
1520 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1521 if (dns != NULL) {
1522 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, dns);
1523 } else {
1524 new_dns = CFDictionaryCreateMutable(NULL,
1525 0,
1526 &kCFTypeDictionaryKeyCallBacks,
1527 &kCFTypeDictionaryValueCallBacks);
1528 }
1529 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1530 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1531 CFRelease(new_dns);
1532 }
1533 } else if (CFEqual(entity_id, kSCEntNetDNS)) {
1534 CFDictionaryRef dns;
1535
1536 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1537 if (dns != NULL) {
1538 CFStringRef interface;
1539
1540 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
1541 if (interface != NULL) {
1542 CFMutableDictionaryRef new_dns;
1543
1544 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
1545 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1546 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1547 CFRelease(new_dns);
1548 } else {
1549 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1550 }
1551 } else {
1552 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1553 }
1554 } else {
1555 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
1556 }
1557
1558 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
1559 CFRelease(state_dict);
1560 CFRelease(components);
1561
1562 return;
1563 }
1564
1565 int
1566 main(int argc, char **argv)
1567 {
1568 CFDictionaryRef entities;
1569 CFStringRef key;
1570 CFArrayRef multicast_resolvers;
1571 CFStringRef pattern;
1572 CFMutableArrayRef patterns;
1573 CFStringRef primary = NULL;
1574 CFDictionaryRef primaryDNS = NULL;
1575 CFArrayRef private_resolvers;
1576 CFArrayRef service_order = NULL;
1577 CFMutableDictionaryRef service_state_dict;
1578 CFDictionaryRef setup_global_ipv4;
1579 CFDictionaryRef state_global_ipv4;
1580 SCDynamicStoreRef store;
1581
1582 _sc_log = FALSE;
1583 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1584
1585 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
1586
1587 // get IPv4, IPv6, and DNS entities
1588 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1589 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1590 kSCDynamicStoreDomainState,
1591 kSCCompAnyRegex,
1592 kSCEntNetIPv4);
1593 CFArrayAppendValue(patterns, pattern);
1594 CFRelease(pattern);
1595 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1596 kSCDynamicStoreDomainState,
1597 kSCCompAnyRegex,
1598 kSCEntNetIPv6);
1599 CFArrayAppendValue(patterns, pattern);
1600 CFRelease(pattern);
1601 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1602 kSCDynamicStoreDomainState,
1603 kSCCompAnyRegex,
1604 kSCEntNetDNS);
1605 CFArrayAppendValue(patterns, pattern);
1606 CFRelease(pattern);
1607 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
1608 CFRelease(patterns);
1609
1610 service_state_dict = CFDictionaryCreateMutable(NULL,
1611 0,
1612 &kCFTypeDictionaryKeyCallBacks,
1613 &kCFTypeDictionaryValueCallBacks);
1614 CFDictionaryApplyFunction(entities, split, service_state_dict);
1615 CFRelease(entities);
1616
1617 // get primary service ID
1618 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1619 kSCDynamicStoreDomainState,
1620 kSCEntNetIPv4);
1621 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1622 CFRelease(key);
1623 if (state_global_ipv4 != NULL) {
1624 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
1625 if (primary != NULL) {
1626 CFDictionaryRef service_dict;
1627
1628 // get DNS configuration for primary service
1629 service_dict = CFDictionaryGetValue(service_state_dict, primary);
1630 if (service_dict != NULL) {
1631 primaryDNS = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
1632 }
1633 }
1634 }
1635
1636 // get serviceOrder
1637 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1638 kSCDynamicStoreDomainSetup,
1639 kSCEntNetIPv4);
1640 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1641 CFRelease(key);
1642 if (setup_global_ipv4 != NULL) {
1643 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
1644 }
1645
1646 // get multicast resolvers
1647 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1648 kSCDynamicStoreDomainState,
1649 kSCCompNetwork,
1650 CFSTR(kDNSServiceCompMulticastDNS));
1651 multicast_resolvers = SCDynamicStoreCopyValue(store, key);
1652 CFRelease(key);
1653
1654 // get private resolvers
1655 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1656 kSCDynamicStoreDomainState,
1657 kSCCompNetwork,
1658 CFSTR(kDNSServiceCompPrivateDNS));
1659 private_resolvers = SCDynamicStoreCopyValue(store, key);
1660 CFRelease(key);
1661
1662 // update DNS configuration
1663 dns_configuration_init(CFBundleGetMainBundle());
1664 (void)dns_configuration_set(primaryDNS,
1665 service_state_dict,
1666 service_order,
1667 multicast_resolvers,
1668 private_resolvers);
1669
1670 // cleanup
1671 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
1672 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
1673 if (multicast_resolvers != NULL) CFRelease(multicast_resolvers);
1674 if (private_resolvers != NULL) CFRelease(private_resolvers);
1675 CFRelease(service_state_dict);
1676 CFRelease(store);
1677
1678 /* not reached */
1679 exit(0);
1680 return 0;
1681 }
1682 #endif
1683