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