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