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