]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/dns-configuration.c
configd-453.18.tar.gz
[apple/configd.git] / Plugins / IPMonitor / dns-configuration.c
1 /*
2 * Copyright (c) 2004-2012 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 CFDictionarySetValue(targetOptions,
1079 kSCNetworkReachabilityOptionServerBypass,
1080 kCFBooleanTrue);
1081 if (targetInterface != NULL) {
1082 CFDictionarySetValue(targetOptions,
1083 kSCNetworkReachabilityOptionInterface,
1084 targetInterface);
1085 }
1086
1087 for (i = 0; i < n; i++) {
1088 SCNetworkReachabilityFlags ns_flags;
1089 Boolean ok;
1090 CFDataRef serverAddress;
1091 SCNetworkReachabilityRef target;
1092
1093 serverAddress = CFArrayGetValueAtIndex(serverAddresses, i);
1094 CFDictionarySetValue(targetOptions,
1095 kSCNetworkReachabilityOptionRemoteAddress,
1096 serverAddress);
1097 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
1098 if (target == NULL) {
1099 CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface);
1100 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
1101 if (target != NULL) {
1102 // if interface name not (no longer) valid
1103 CFRelease(target);
1104 flags = 0;
1105 break;
1106 }
1107
1108 // address not valid?
1109 SCLog(TRUE, LOG_ERR,
1110 CFSTR("create_resolver SCNetworkReachabilityCreateWithOptions() failed:\n options = %@"),
1111 targetOptions);
1112 break;
1113 }
1114
1115 ok = SCNetworkReachabilityGetFlags(target, &ns_flags);
1116 CFRelease(target);
1117 if (!ok) {
1118 break;
1119 }
1120
1121 if ((i == 0) ||
1122 (rankReachability(ns_flags) < rankReachability(flags))) {
1123 /* return the worst case result */
1124 flags = ns_flags;
1125 }
1126 }
1127
1128 _dns_resolver_set_reach_flags(&_resolver, flags);
1129
1130 CFRelease(targetOptions);
1131 CFRelease(serverAddresses);
1132 }
1133
1134 if (targetInterface != NULL) {
1135 CFRelease(targetInterface);
1136 }
1137
1138 return _resolver;
1139 }
1140
1141
1142 static __inline__ Boolean
1143 isScopedConfiguration(CFDictionaryRef dns)
1144 {
1145 uint32_t flags;
1146 CFNumberRef num;
1147
1148 if ((dns != NULL) &&
1149 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
1150 (num != NULL) &&
1151 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
1152 ((flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)) {
1153 return TRUE;
1154 }
1155
1156 return FALSE;
1157 }
1158
1159
1160 static CFComparisonResult
1161 compareDomain(const void *val1, const void *val2, void *context)
1162 {
1163 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
1164 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
1165 CFStringRef domain1;
1166 CFStringRef domain2;
1167 CFArrayRef labels1 = NULL;
1168 CFArrayRef labels2 = NULL;
1169 CFIndex n1;
1170 CFIndex n2;
1171 CFComparisonResult result;
1172 Boolean rev1;
1173 Boolean rev2;
1174 Boolean scoped1;
1175 Boolean scoped2;
1176
1177 // "default" domains sort before "supplemental" domains
1178 domain1 = CFDictionaryGetValue(dns1, kSCPropNetDNSDomainName);
1179 domain2 = CFDictionaryGetValue(dns2, kSCPropNetDNSDomainName);
1180 if (domain1 == NULL) {
1181 return kCFCompareLessThan;
1182 } else if (domain2 == NULL) {
1183 return kCFCompareGreaterThan;
1184 }
1185
1186 // sort non-scoped before scoped
1187 scoped1 = isScopedConfiguration(dns1);
1188 scoped2 = isScopedConfiguration(dns2);
1189 if (scoped1 != scoped2) {
1190 if (!scoped1) {
1191 return kCFCompareLessThan;
1192 } else {
1193 return kCFCompareGreaterThan;
1194 }
1195 }
1196
1197 // must have domain names for any further comparisons
1198 if ((domain1 == NULL) || (domain2 == NULL)) {
1199 return kCFCompareEqualTo;
1200 }
1201
1202 // forward (A, AAAA) domains sort before reverse (PTR) domains
1203 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa"));
1204 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa"));
1205 if (rev1 != rev2) {
1206 if (rev1) {
1207 return kCFCompareGreaterThan;
1208 } else {
1209 return kCFCompareLessThan;
1210 }
1211 }
1212
1213 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR("."));
1214 n1 = CFArrayGetCount(labels1);
1215
1216 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR("."));
1217 n2 = CFArrayGetCount(labels2);
1218
1219 while ((n1 > 0) && (n2 > 0)) {
1220 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1);
1221 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2);
1222
1223 // compare domain labels
1224 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive);
1225 if (result != kCFCompareEqualTo) {
1226 goto done;
1227 }
1228 }
1229
1230 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1231 if (n1 > n2) {
1232 result = kCFCompareLessThan;
1233 goto done;
1234 } else if (n1 < n2) {
1235 result = kCFCompareGreaterThan;
1236 goto done;
1237 }
1238
1239 // sort by search order
1240 result = compareBySearchOrder(val1, val2, context);
1241
1242 done :
1243
1244 if (labels1 != NULL) CFRelease(labels1);
1245 if (labels2 != NULL) CFRelease(labels2);
1246 return result;
1247 }
1248
1249
1250 __private_extern__
1251 Boolean
1252 dns_configuration_set(CFDictionaryRef defaultResolver,
1253 CFDictionaryRef services,
1254 CFArrayRef serviceOrder,
1255 CFArrayRef multicastResolvers,
1256 CFArrayRef privateResolvers)
1257 {
1258 dns_create_config_t _config;
1259 Boolean changed = FALSE;
1260 CFIndex i;
1261 CFMutableDictionaryRef myDefault;
1262 Boolean myOrderAdded = FALSE;
1263 CFArrayRef mySearchDomains = NULL;
1264 CFIndex n_resolvers;
1265 CFMutableArrayRef resolvers;
1266 unsigned char signature[CC_SHA1_DIGEST_LENGTH];
1267 static unsigned char signature_last[CC_SHA1_DIGEST_LENGTH];
1268
1269 // establish list of resolvers
1270
1271 resolvers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1272
1273 // collect (and add) any "supplemental" resolver configurations
1274
1275 add_supplemental_resolvers(resolvers, services, serviceOrder);
1276
1277 // collect (and add) any "private" resolver configurations
1278
1279 add_private_resolvers(resolvers, privateResolvers);
1280
1281 // add the "default" resolver
1282
1283 add_default_resolver(resolvers, defaultResolver, &myOrderAdded, &mySearchDomains);
1284
1285 // collect (and add) any "multicast" resolver configurations
1286
1287 add_multicast_resolvers(resolvers, multicastResolvers);
1288
1289 // collect (and add) any "scoped" resolver configurations
1290
1291 add_scoped_resolvers(resolvers, services, serviceOrder);
1292
1293 // sort resolvers
1294
1295 n_resolvers = CFArrayGetCount(resolvers);
1296 if (n_resolvers > 1) {
1297 CFArraySortValues(resolvers, CFRangeMake(0, n_resolvers), compareDomain, NULL);
1298 }
1299
1300 // cleanup
1301
1302 for (i = n_resolvers; --i > 0; ) {
1303 CFDictionaryRef resolver;
1304
1305 resolver = CFArrayGetValueAtIndex(resolvers, i);
1306 if (!CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) &&
1307 !CFDictionaryContainsKey(resolver, kSCPropNetDNSSearchDomains) &&
1308 !CFDictionaryContainsKey(resolver, kSCPropNetDNSServerAddresses)) {
1309 // remove empty resolver
1310 CFArrayRemoveValueAtIndex(resolvers, i);
1311 n_resolvers--;
1312 }
1313 }
1314
1315 // update the default resolver
1316
1317 myDefault = CFDictionaryCreateMutableCopy(NULL,
1318 0,
1319 CFArrayGetValueAtIndex(resolvers, 0));
1320 if (mySearchDomains != NULL) {
1321 // add search domains to the default resolver
1322 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchDomains, mySearchDomains);
1323 CFRelease(mySearchDomains);
1324 }
1325 if (myOrderAdded && (n_resolvers > 1)) {
1326 CFDictionaryRef resolver;
1327
1328 resolver = CFArrayGetValueAtIndex(resolvers, 1);
1329 if (CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) ||
1330 isScopedConfiguration(resolver)) {
1331 // if not a supplemental "default" resolver (a domain name is
1332 // present) or if it's a scoped configuration
1333 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
1334 }
1335 }
1336 CFArraySetValueAtIndex(resolvers, 0, myDefault);
1337 CFRelease(myDefault);
1338
1339 // establish resolver configuration
1340
1341 if ((defaultResolver == NULL) && (n_resolvers <= 1)) {
1342 /*
1343 * if no default and no supplemental/scoped resolvers
1344 */
1345 _config = NULL;
1346 } else {
1347 /*
1348 * if default and/or supplemental/scoped resolvers are defined
1349 */
1350 _config = _dns_configuration_create();
1351
1352 // add resolvers
1353
1354 for (i = 0; i < n_resolvers; i++) {
1355 CFDictionaryRef resolver;
1356 dns_create_resolver_t _resolver;
1357
1358 resolver = CFArrayGetValueAtIndex(resolvers, i);
1359 _resolver = create_resolver(resolver);
1360 _dns_configuration_add_resolver(&_config, _resolver);
1361 _dns_resolver_free(&_resolver);
1362 }
1363
1364 #if !TARGET_OS_IPHONE
1365 // add flatfile resolvers
1366
1367 _dnsinfo_flatfile_add_resolvers(&_config);
1368 #endif // !TARGET_OS_IPHONE
1369 }
1370
1371 // check if the configuration changed
1372 _dns_configuration_signature(&_config, signature, sizeof(signature));
1373 if (bcmp(signature, signature_last, sizeof(signature)) != 0) {
1374 changed = TRUE;
1375 }
1376 bcopy(signature, signature_last, sizeof(signature));
1377
1378 // save configuration
1379 if (!_dns_configuration_store(&_config)) {
1380 SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
1381 }
1382 if (_config != NULL) _dns_configuration_free(&_config);
1383
1384 CFRelease(resolvers);
1385 return changed;
1386 }
1387
1388
1389 #if !TARGET_OS_IPHONE
1390 static SCDynamicStoreRef dns_configuration_store;
1391 static SCDynamicStoreCallBack dns_configuration_callout;
1392
1393 static void
1394 dns_configuration_changed(CFMachPortRef port, void *msg, CFIndex size, void *info)
1395 {
1396 CFStringRef key = CFSTR(_PATH_RESOLVER_DIR);
1397 CFArrayRef keys;
1398 Boolean resolvers_now;
1399 static Boolean resolvers_save = FALSE;
1400 struct stat statbuf;
1401
1402 resolvers_now = (stat(_PATH_RESOLVER_DIR, &statbuf) == 0);
1403 if (!resolvers_save && (resolvers_save == resolvers_now)) {
1404 // if we did not (and still do not) have an "/etc/resolvers"
1405 // directory than this notification is the result of a change
1406 // to the "/etc" directory.
1407 return;
1408 }
1409 resolvers_save = resolvers_now;
1410
1411 SCLog(TRUE, LOG_DEBUG, CFSTR(_PATH_RESOLVER_DIR " changed"));
1412
1413 // fake a "DNS" change
1414 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
1415 (*dns_configuration_callout)(dns_configuration_store, keys, NULL);
1416 CFRelease(keys);
1417 return;
1418 }
1419
1420
1421 __private_extern__
1422 void
1423 dns_configuration_monitor(SCDynamicStoreRef store, SCDynamicStoreCallBack callout)
1424 {
1425 CFMachPortRef mp;
1426 mach_port_t notify_port;
1427 int notify_token;
1428 CFRunLoopSourceRef rls;
1429 uint32_t status;
1430
1431 dns_configuration_store = store;
1432 dns_configuration_callout = callout;
1433
1434 status = notify_register_mach_port(_PATH_RESOLVER_DIR, &notify_port, 0, &notify_token);
1435 if (status != NOTIFY_STATUS_OK) {
1436 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1437 return;
1438 }
1439
1440 status = notify_monitor_file(notify_token, "/private" _PATH_RESOLVER_DIR, 0);
1441 if (status != NOTIFY_STATUS_OK) {
1442 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_monitor_file() failed"));
1443 (void)notify_cancel(notify_token);
1444 return;
1445 }
1446
1447 mp = _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1448 notify_port,
1449 dns_configuration_changed,
1450 NULL);
1451
1452 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1453 if (rls == NULL) {
1454 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1455 CFRelease(mp);
1456 (void)notify_cancel(notify_token);
1457 return;
1458 }
1459 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1460 CFRelease(rls);
1461
1462 CFRelease(mp);
1463 return;
1464 }
1465 #endif // !TARGET_OS_IPHONE
1466
1467
1468 __private_extern__
1469 void
1470 dns_configuration_init(CFBundleRef bundle)
1471 {
1472 CFDictionaryRef dict;
1473
1474 dict = CFBundleGetInfoDictionary(bundle);
1475 if (isA_CFDictionary(dict)) {
1476 S_mdns_timeout = CFDictionaryGetValue(dict, CFSTR("mdns_timeout"));
1477 S_mdns_timeout = isA_CFNumber(S_mdns_timeout);
1478
1479 S_pdns_timeout = CFDictionaryGetValue(dict, CFSTR("pdns_timeout"));
1480 S_pdns_timeout = isA_CFNumber(S_pdns_timeout);
1481 }
1482
1483 return;
1484 }
1485
1486
1487 #pragma mark -
1488 #pragma mark Standalone test code
1489
1490
1491 #ifdef MAIN
1492
1493 static void
1494 split(const void * key, const void * value, void * context)
1495 {
1496 CFArrayRef components;
1497 CFStringRef entity_id;
1498 CFStringRef service_id;
1499 CFMutableDictionaryRef state_dict;
1500
1501 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/"));
1502 service_id = CFArrayGetValueAtIndex(components, 3);
1503 entity_id = CFArrayGetValueAtIndex(components, 4);
1504 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id);
1505 if (state_dict != NULL) {
1506 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
1507 } else {
1508 state_dict = CFDictionaryCreateMutable(NULL,
1509 0,
1510 &kCFTypeDictionaryKeyCallBacks,
1511 &kCFTypeDictionaryValueCallBacks);
1512 }
1513
1514 if (CFEqual(entity_id, kSCEntNetIPv4) ||
1515 CFEqual(entity_id, kSCEntNetIPv6)) {
1516 CFStringRef interface;
1517
1518 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName);
1519 if (interface != NULL) {
1520 CFDictionaryRef dns;
1521 CFMutableDictionaryRef new_dns;
1522
1523 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1524 if (dns != NULL) {
1525 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, dns);
1526 } else {
1527 new_dns = CFDictionaryCreateMutable(NULL,
1528 0,
1529 &kCFTypeDictionaryKeyCallBacks,
1530 &kCFTypeDictionaryValueCallBacks);
1531 }
1532 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1533 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1534 CFRelease(new_dns);
1535 }
1536 } else if (CFEqual(entity_id, kSCEntNetDNS)) {
1537 CFDictionaryRef dns;
1538
1539 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1540 if (dns != NULL) {
1541 CFStringRef interface;
1542
1543 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
1544 if (interface != NULL) {
1545 CFMutableDictionaryRef new_dns;
1546
1547 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
1548 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1549 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1550 CFRelease(new_dns);
1551 } else {
1552 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1553 }
1554 } else {
1555 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1556 }
1557 } else {
1558 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
1559 }
1560
1561 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
1562 CFRelease(state_dict);
1563 CFRelease(components);
1564
1565 return;
1566 }
1567
1568 int
1569 main(int argc, char **argv)
1570 {
1571 CFDictionaryRef entities;
1572 CFStringRef key;
1573 CFArrayRef multicast_resolvers;
1574 CFStringRef pattern;
1575 CFMutableArrayRef patterns;
1576 CFStringRef primary = NULL;
1577 CFDictionaryRef primaryDNS = NULL;
1578 CFArrayRef private_resolvers;
1579 CFArrayRef service_order = NULL;
1580 CFMutableDictionaryRef service_state_dict;
1581 CFDictionaryRef setup_global_ipv4;
1582 CFDictionaryRef state_global_ipv4;
1583 SCDynamicStoreRef store;
1584
1585 _sc_log = FALSE;
1586 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1587
1588 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
1589
1590 // get IPv4, IPv6, and DNS entities
1591 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1592 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1593 kSCDynamicStoreDomainState,
1594 kSCCompAnyRegex,
1595 kSCEntNetIPv4);
1596 CFArrayAppendValue(patterns, pattern);
1597 CFRelease(pattern);
1598 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1599 kSCDynamicStoreDomainState,
1600 kSCCompAnyRegex,
1601 kSCEntNetIPv6);
1602 CFArrayAppendValue(patterns, pattern);
1603 CFRelease(pattern);
1604 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1605 kSCDynamicStoreDomainState,
1606 kSCCompAnyRegex,
1607 kSCEntNetDNS);
1608 CFArrayAppendValue(patterns, pattern);
1609 CFRelease(pattern);
1610 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
1611 CFRelease(patterns);
1612
1613 service_state_dict = CFDictionaryCreateMutable(NULL,
1614 0,
1615 &kCFTypeDictionaryKeyCallBacks,
1616 &kCFTypeDictionaryValueCallBacks);
1617 CFDictionaryApplyFunction(entities, split, service_state_dict);
1618 CFRelease(entities);
1619
1620 // get primary service ID
1621 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1622 kSCDynamicStoreDomainState,
1623 kSCEntNetIPv4);
1624 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1625 CFRelease(key);
1626 if (state_global_ipv4 != NULL) {
1627 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
1628 if (primary != NULL) {
1629 CFDictionaryRef service_dict;
1630
1631 // get DNS configuration for primary service
1632 service_dict = CFDictionaryGetValue(service_state_dict, primary);
1633 if (service_dict != NULL) {
1634 primaryDNS = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
1635 }
1636 }
1637 }
1638
1639 // get serviceOrder
1640 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1641 kSCDynamicStoreDomainSetup,
1642 kSCEntNetIPv4);
1643 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1644 CFRelease(key);
1645 if (setup_global_ipv4 != NULL) {
1646 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
1647 }
1648
1649 // get multicast resolvers
1650 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1651 kSCDynamicStoreDomainState,
1652 kSCCompNetwork,
1653 CFSTR(kDNSServiceCompMulticastDNS));
1654 multicast_resolvers = SCDynamicStoreCopyValue(store, key);
1655 CFRelease(key);
1656
1657 // get private resolvers
1658 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1659 kSCDynamicStoreDomainState,
1660 kSCCompNetwork,
1661 CFSTR(kDNSServiceCompPrivateDNS));
1662 private_resolvers = SCDynamicStoreCopyValue(store, key);
1663 CFRelease(key);
1664
1665 // update DNS configuration
1666 dns_configuration_init(CFBundleGetMainBundle());
1667 (void)dns_configuration_set(primaryDNS,
1668 service_state_dict,
1669 service_order,
1670 multicast_resolvers,
1671 private_resolvers);
1672
1673 // cleanup
1674 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
1675 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
1676 if (multicast_resolvers != NULL) CFRelease(multicast_resolvers);
1677 if (private_resolvers != NULL) CFRelease(private_resolvers);
1678 CFRelease(service_state_dict);
1679 CFRelease(store);
1680
1681 /* not reached */
1682 exit(0);
1683 return 0;
1684 }
1685 #endif
1686