]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/dns-configuration.c
2254e4170257cbcb700b6139cfce449ed5cfc7ea
[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_REQUEST_ALL_RECORDS;
1024
1025 if (CFDictionaryContainsKey(new_resolver, kSCPropInterfaceName)) {
1026 CFDictionarySetValue(new_resolver, DNS_CONFIGURATION_SCOPED_QUERY_KEY, kCFBooleanTrue);
1027 CFDictionaryRemoveValue(new_resolver, kSCPropNetDNSServiceIdentifier);
1028 flags |= DNS_RESOLVER_FLAGS_SCOPED;
1029 } else {
1030 flags |= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC;
1031 }
1032
1033 flags_num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags);
1034 CFDictionarySetValue(new_resolver, DNS_CONFIGURATION_FLAGS_KEY, flags_num);
1035 CFRelease(flags_num);
1036
1037 CFDictionaryRemoveValue(new_resolver, kSCPropNetDNSSupplementalMatchDomains);
1038 CFDictionaryRemoveValue(new_resolver, kSCPropNetDNSSupplementalMatchOrders);
1039
1040 add_resolver_signature(new_resolver, "Service", serviceID, 0);
1041 add_resolver(resolvers, new_resolver);
1042 CFRelease(new_resolver);
1043 }
1044 CFRelease(seen);
1045
1046 if (keys != keys_q) {
1047 CFAllocatorDeallocate(kCFAllocatorDefault, keys);
1048 CFAllocatorDeallocate(kCFAllocatorDefault, vals);
1049 }
1050
1051 return;
1052 }
1053
1054
1055 static void
1056 add_default_resolver(CFMutableArrayRef resolvers,
1057 CFDictionaryRef defaultResolver,
1058 Boolean *orderAdded,
1059 CFArrayRef *searchDomains)
1060 {
1061 CFMutableDictionaryRef myDefault;
1062 uint32_t myOrder = DEFAULT_SEARCH_ORDER;
1063 CFNumberRef order;
1064
1065 if (defaultResolver == NULL) {
1066 myDefault = CFDictionaryCreateMutable(NULL,
1067 0,
1068 &kCFTypeDictionaryKeyCallBacks,
1069 &kCFTypeDictionaryValueCallBacks);
1070 } else {
1071 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver);
1072 }
1073 assert(myDefault != NULL);
1074
1075 // ensure that the default resolver has a search order
1076
1077 order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder);
1078 if (!isA_CFNumber(order) ||
1079 !CFNumberGetValue(order, kCFNumberSInt32Type, &myOrder)) {
1080 myOrder = DEFAULT_SEARCH_ORDER;
1081 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
1082 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order);
1083 CFRelease(order);
1084 *orderAdded = TRUE;
1085 }
1086
1087 // extract the "search" domain list for the default resolver (and
1088 // any supplemental resolvers)
1089
1090 *searchDomains = extract_search_domains(myDefault, resolvers);
1091
1092 // add the default resolver
1093
1094 add_resolver_signature(myDefault, "Default", NULL, 0);
1095 add_resolver(resolvers, myDefault);
1096 CFRelease(myDefault);
1097 return;
1098 }
1099
1100
1101 static dns_create_resolver_t
1102 create_resolver(CFDictionaryRef dns)
1103 {
1104 CFArrayRef list;
1105 CFNumberRef num;
1106 dns_create_resolver_t _resolver;
1107 CFStringRef str;
1108 CFStringRef targetInterface = NULL;
1109 unsigned int targetInterfaceIndex = 0;
1110
1111 _resolver = _dns_resolver_create();
1112
1113 // process domain
1114 str = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
1115 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
1116 char domain[NS_MAXDNAME];
1117
1118 if (_SC_cfstring_to_cstring(str, domain, sizeof(domain), kCFStringEncodingUTF8) != NULL) {
1119 _dns_resolver_set_domain(&_resolver, domain);
1120 }
1121 }
1122
1123 // process search domains
1124 list = CFDictionaryGetValue(dns, kSCPropNetDNSSearchDomains);
1125 if (isA_CFArray(list)) {
1126 CFIndex i;
1127 CFIndex n = CFArrayGetCount(list);
1128
1129 // add "search" domains
1130 for (i = 0; i < n; i++) {
1131 str = CFArrayGetValueAtIndex(list, i);
1132 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
1133 char search[NS_MAXDNAME];
1134
1135 if (_SC_cfstring_to_cstring(str, search, sizeof(search), kCFStringEncodingUTF8) != NULL) {
1136 _dns_resolver_add_search(&_resolver, search);
1137 }
1138 }
1139 }
1140 }
1141
1142 // process interface index
1143 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_IF_INDEX_KEY);
1144 if (isA_CFNumber(num)) {
1145 int if_index;
1146
1147 if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) {
1148 char if_name[IFNAMSIZ];
1149
1150 _dns_resolver_set_if_index(&_resolver, if_index);
1151
1152 if ((if_index != 0) &&
1153 (my_if_indextoname(if_index, if_name) != NULL)) {
1154 targetInterface = CFStringCreateWithCString(NULL,
1155 if_name,
1156 kCFStringEncodingASCII);
1157 targetInterfaceIndex = if_index;
1158 }
1159 }
1160 }
1161
1162 // process flags
1163 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_FLAGS_KEY);
1164 if (isA_CFNumber(num)) {
1165 uint32_t flags;
1166
1167 if (CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
1168 _dns_resolver_set_flags(&_resolver, flags);
1169 }
1170 }
1171
1172 // process nameserver addresses
1173 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1174 list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
1175 if (isA_CFArray(list)) {
1176 CFIndex i;
1177 CFIndex n = CFArrayGetCount(list);
1178
1179 for (i = 0; i < n; i++) {
1180 union {
1181 struct sockaddr sa;
1182 struct sockaddr_in sin;
1183 struct sockaddr_in6 sin6;
1184 } addr;
1185 char buf[64];
1186
1187 str = CFArrayGetValueAtIndex(list, i);
1188 if (!isA_CFString(str)) {
1189 continue;
1190 }
1191
1192 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
1193 continue;
1194 }
1195
1196 if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
1197 continue;
1198 }
1199
1200 if ((addr.sa.sa_family == AF_INET6) &&
1201 IN6_IS_ADDR_LINKLOCAL(&addr.sin6.sin6_addr) &&
1202 (addr.sin6.sin6_scope_id == 0) &&
1203 (targetInterfaceIndex != 0)) {
1204 // for link local [IPv6] addresses, if the scope id is not
1205 // set then we should use the interface associated with the
1206 // resolver configuration
1207 addr.sin6.sin6_scope_id = targetInterfaceIndex;
1208 }
1209
1210 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
1211 }
1212 }
1213
1214 // process search order
1215 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
1216 if (isA_CFNumber(num)) {
1217 uint32_t order;
1218
1219 if (CFNumberGetValue(num, kCFNumberSInt32Type, &order)) {
1220 _dns_resolver_set_order(&_resolver, order);
1221 }
1222 }
1223
1224 // process sortlist
1225 list = CFDictionaryGetValue(dns, kSCPropNetDNSSortList);
1226 if (isA_CFArray(list)) {
1227 CFIndex i;
1228 CFIndex n = CFArrayGetCount(list);
1229
1230 for (i = 0; i < n; i++) {
1231 char buf[128];
1232 char *slash;
1233 dns_sortaddr_t sortaddr;
1234
1235 str = CFArrayGetValueAtIndex(list, i);
1236 if (!isA_CFString(str)) {
1237 continue;
1238 }
1239
1240 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
1241 continue;
1242 }
1243
1244 slash = strchr(buf, '/');
1245 if (slash != NULL) {
1246 *slash = '\0';
1247 }
1248
1249 bzero(&sortaddr, sizeof(sortaddr));
1250 if (inet_aton(buf, &sortaddr.address) != 1) {
1251 /* if address not valid */
1252 continue;
1253 }
1254
1255 if (slash != NULL) {
1256 if (inet_aton(slash + 1, &sortaddr.mask) != 1) {
1257 /* if subnet mask not valid */
1258 continue;
1259 }
1260 } else {
1261 in_addr_t a;
1262 in_addr_t m;
1263
1264 a = ntohl(sortaddr.address.s_addr);
1265 if (IN_CLASSA(a)) {
1266 m = IN_CLASSA_NET;
1267 } else if (IN_CLASSB(a)) {
1268 m = IN_CLASSB_NET;
1269 } else if (IN_CLASSC(a)) {
1270 m = IN_CLASSC_NET;
1271 } else {
1272 continue;
1273 }
1274
1275 sortaddr.mask.s_addr = htonl(m);
1276 }
1277
1278 _dns_resolver_add_sortaddr(&_resolver, &sortaddr);
1279 }
1280 }
1281
1282 // process port
1283 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerPort);
1284 if (isA_CFNumber(num)) {
1285 int port;
1286
1287 if (CFNumberGetValue(num, kCFNumberIntType, &port)) {
1288 _dns_resolver_set_port(&_resolver, (uint16_t)port);
1289 }
1290 }
1291
1292 // process timeout
1293 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerTimeout);
1294 if (isA_CFNumber(num)) {
1295 int timeout;
1296
1297 if (CFNumberGetValue(num, kCFNumberIntType, &timeout)) {
1298 _dns_resolver_set_timeout(&_resolver, (uint32_t)timeout);
1299 }
1300 }
1301
1302 // process options
1303 str = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
1304 if (isA_CFString(str)) {
1305 char *options;
1306
1307 options = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
1308 if (options != NULL) {
1309 _dns_resolver_set_options(&_resolver, options);
1310 CFAllocatorDeallocate(NULL, options);
1311 }
1312 }
1313
1314 num = CFDictionaryGetValue(dns, kSCPropNetDNSServiceIdentifier);
1315 if (isA_CFNumber(num)) {
1316 int dns_service_identifier;
1317
1318 if (CFNumberGetValue(num, kCFNumberIntType, &dns_service_identifier)) {
1319 _dns_resolver_set_service_identifier(&_resolver, (uint32_t)dns_service_identifier);
1320 }
1321 }
1322
1323 // process configuration ID
1324 str = CFDictionaryGetValue(dns, DNS_CONFIGURATION_CONFIGURATION_ID);
1325 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
1326 char *cID;
1327
1328 cID = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
1329 if (cID != NULL) {
1330 _dns_resolver_set_configuration_identifier(&_resolver, cID);
1331 CFAllocatorDeallocate(NULL, cID);
1332 }
1333 }
1334
1335 if (targetInterface != NULL) {
1336 CFRelease(targetInterface);
1337 }
1338
1339 return _resolver;
1340 }
1341
1342
1343 static __inline__ Boolean
1344 isDefaultConfiguration(CFDictionaryRef dns)
1345 {
1346 uint32_t flags;
1347 CFNumberRef num;
1348
1349 if ((dns != NULL) &&
1350 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
1351 (num != NULL) &&
1352 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
1353 (((flags & DNS_RESOLVER_FLAGS_SCOPED ) != 0) ||
1354 ((flags & DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC) != 0))
1355 ) {
1356 // if scoped or service-specific
1357 return FALSE;
1358 }
1359
1360 return TRUE;
1361 }
1362
1363
1364
1365 static __inline__ Boolean
1366 isScopedConfiguration(CFDictionaryRef dns)
1367 {
1368 uint32_t flags;
1369 CFNumberRef num;
1370
1371 if ((dns != NULL) &&
1372 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
1373 (num != NULL) &&
1374 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
1375 ((flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)) {
1376 // if scoped
1377 return TRUE;
1378 }
1379
1380 return FALSE;
1381 }
1382
1383
1384 static CFComparisonResult
1385 compareDomain(const void *val1, const void *val2, void *context)
1386 {
1387 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
1388 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
1389 CFStringRef domain1;
1390 CFStringRef domain2;
1391 CFArrayRef labels1 = NULL;
1392 CFArrayRef labels2 = NULL;
1393 CFIndex n1;
1394 CFIndex n2;
1395 CFComparisonResult result;
1396 Boolean rev1;
1397 Boolean rev2;
1398 Boolean scoped1;
1399 Boolean scoped2;
1400
1401 // "default" domains sort before "supplemental" domains
1402 domain1 = CFDictionaryGetValue(dns1, kSCPropNetDNSDomainName);
1403 domain2 = CFDictionaryGetValue(dns2, kSCPropNetDNSDomainName);
1404 if (domain1 == NULL) {
1405 return kCFCompareLessThan;
1406 } else if (domain2 == NULL) {
1407 return kCFCompareGreaterThan;
1408 }
1409
1410 // sort non-scoped before scoped
1411 scoped1 = isScopedConfiguration(dns1);
1412 scoped2 = isScopedConfiguration(dns2);
1413 if (scoped1 != scoped2) {
1414 if (!scoped1) {
1415 return kCFCompareLessThan;
1416 } else {
1417 return kCFCompareGreaterThan;
1418 }
1419 }
1420
1421 // must have domain names for any further comparisons
1422 if ((domain1 == NULL) || (domain2 == NULL)) {
1423 return kCFCompareEqualTo;
1424 }
1425
1426 // forward (A, AAAA) domains sort before reverse (PTR) domains
1427 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa"));
1428 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa"));
1429 if (rev1 != rev2) {
1430 if (rev1) {
1431 return kCFCompareGreaterThan;
1432 } else {
1433 return kCFCompareLessThan;
1434 }
1435 }
1436
1437 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR("."));
1438 n1 = CFArrayGetCount(labels1);
1439
1440 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR("."));
1441 n2 = CFArrayGetCount(labels2);
1442
1443 while ((n1 > 0) && (n2 > 0)) {
1444 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1);
1445 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2);
1446
1447 // compare domain labels
1448 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive);
1449 if (result != kCFCompareEqualTo) {
1450 goto done;
1451 }
1452 }
1453
1454 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1455 if (n1 > n2) {
1456 result = kCFCompareLessThan;
1457 goto done;
1458 } else if (n1 < n2) {
1459 result = kCFCompareGreaterThan;
1460 goto done;
1461 }
1462
1463 // sort by search order
1464 result = compareBySearchOrder(val1, val2, context);
1465
1466 done :
1467
1468 if (labels1 != NULL) CFRelease(labels1);
1469 if (labels2 != NULL) CFRelease(labels2);
1470 return result;
1471 }
1472
1473
1474 __private_extern__
1475 Boolean
1476 dns_configuration_set(CFDictionaryRef defaultResolver,
1477 CFDictionaryRef services,
1478 CFArrayRef serviceOrder,
1479 CFArrayRef multicastResolvers,
1480 CFArrayRef privateResolvers)
1481 {
1482 dns_create_config_t _config;
1483 Boolean changed = FALSE;
1484 uint32_t dns_resolver_flags = 0;
1485 CFIndex i;
1486 CFMutableDictionaryRef myDefault;
1487 Boolean myOrderAdded = FALSE;
1488 CFArrayRef mySearchDomains = NULL;
1489 CFIndex n_resolvers;
1490 CFMutableArrayRef resolvers;
1491 unsigned char signature[CC_SHA1_DIGEST_LENGTH];
1492 static unsigned char signature_last[CC_SHA1_DIGEST_LENGTH];
1493
1494 // establish list of resolvers
1495
1496 resolvers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1497 assert(resolvers != NULL);
1498
1499 // collect (and add) any "supplemental" resolver configurations
1500
1501 add_supplemental_resolvers(resolvers, services, serviceOrder, NULL, NULL);
1502
1503 // collect (and add) any "private" resolver configurations
1504
1505 add_private_resolvers(resolvers, privateResolvers);
1506
1507 // add the "default" resolver
1508
1509 add_default_resolver(resolvers, defaultResolver, &myOrderAdded, &mySearchDomains);
1510
1511 // collect (and add) any "multicast" resolver configurations
1512
1513 add_multicast_resolvers(resolvers, multicastResolvers);
1514
1515 // collect (and add) any "scoped" resolver configurations
1516
1517 add_scoped_resolvers(resolvers, services, serviceOrder);
1518
1519 // collect (and add) any "service-specific" resolver configurations
1520
1521 add_service_specific_resolvers(resolvers, services);
1522
1523 // sort resolvers
1524
1525 n_resolvers = CFArrayGetCount(resolvers);
1526 if (n_resolvers > 1) {
1527 CFArraySortValues(resolvers, CFRangeMake(0, n_resolvers), compareDomain, NULL);
1528 }
1529
1530 // cleanup
1531
1532 for (i = n_resolvers; --i > 0; ) {
1533 CFDictionaryRef resolver;
1534
1535 resolver = CFArrayGetValueAtIndex(resolvers, i);
1536 if (!CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) &&
1537 !CFDictionaryContainsKey(resolver, kSCPropNetDNSSearchDomains) &&
1538 !CFDictionaryContainsKey(resolver, kSCPropNetDNSServerAddresses)) {
1539 // remove empty resolver
1540 CFArrayRemoveValueAtIndex(resolvers, i);
1541 n_resolvers--;
1542 }
1543 }
1544
1545 // update the default resolver
1546
1547 myDefault = CFDictionaryCreateMutableCopy(NULL,
1548 0,
1549 CFArrayGetValueAtIndex(resolvers, 0));
1550 if (mySearchDomains != NULL) {
1551 // add search domains to the default resolver
1552 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchDomains, mySearchDomains);
1553 CFRelease(mySearchDomains);
1554 }
1555 if (myOrderAdded && (n_resolvers > 1)) {
1556 CFDictionaryRef resolver;
1557
1558 resolver = CFArrayGetValueAtIndex(resolvers, 1);
1559 if (CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) ||
1560 isScopedConfiguration(resolver)) {
1561 // if not a supplemental "default" resolver (a domain name is
1562 // present) or if it's a scoped configuration
1563 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
1564 }
1565 }
1566 CFArraySetValueAtIndex(resolvers, 0, myDefault);
1567 CFRelease(myDefault);
1568
1569 // establish resolver configuration
1570
1571 if ((defaultResolver == NULL) && (n_resolvers <= 1)) {
1572 /*
1573 * if no default and no supplemental/scoped resolvers
1574 */
1575 _config = NULL;
1576 } else {
1577 /*
1578 * if default and/or supplemental/scoped resolvers are defined
1579 */
1580 _config = _dns_configuration_create();
1581
1582 CFDictionaryApplyFunction(services, add_dns_resolver_flags, &dns_resolver_flags);
1583
1584 for (i = 0; i < n_resolvers; i++) {
1585 boolean_t is_default_resolver;
1586 CFDictionaryRef resolver;
1587 dns_create_resolver_t _resolver;
1588
1589 resolver = CFArrayGetValueAtIndex(resolvers, i);
1590
1591 is_default_resolver = isDefaultConfiguration(resolver);
1592 if (is_default_resolver) {
1593 CFMutableDictionaryRef new_resolver;
1594 CFNumberRef num;
1595
1596 new_resolver = CFDictionaryCreateMutableCopy(NULL, 0, resolver);
1597
1598 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &dns_resolver_flags);
1599 CFDictionarySetValue(new_resolver, DNS_CONFIGURATION_FLAGS_KEY, num);
1600 CFRelease(num);
1601
1602 resolver = new_resolver;
1603 }
1604
1605 _resolver = create_resolver(resolver);
1606 _dns_configuration_add_resolver(&_config, _resolver);
1607 _dns_resolver_free(&_resolver);
1608
1609 if (is_default_resolver) {
1610 CFRelease(resolver);
1611 }
1612 }
1613
1614 #if !TARGET_OS_IPHONE
1615 // add flatfile resolvers
1616
1617 _dnsinfo_flatfile_set_flags(dns_resolver_flags);
1618 _dnsinfo_flatfile_add_resolvers(&_config);
1619 #endif // !TARGET_OS_IPHONE
1620 }
1621
1622 // check if the configuration changed
1623 _dns_configuration_signature(&_config, signature, sizeof(signature));
1624 if (bcmp(signature, signature_last, sizeof(signature)) != 0) {
1625 // save [new] signature
1626 bcopy(signature, signature_last, sizeof(signature));
1627
1628 my_log(LOG_INFO, "Updating DNS configuration");
1629 if (_config != NULL) {
1630 uint8_t *buf;
1631 dns_config_t *config;
1632 _dns_config_buf_t *config_buf;
1633 uint32_t n_config;
1634 uint32_t n_padding;
1635
1636 config_buf = (_dns_config_buf_t *)_config;
1637 n_config = sizeof(_dns_config_buf_t) + ntohl(config_buf->n_attribute);
1638 n_padding = ntohl(config_buf->n_padding);
1639 buf = malloc(n_config + n_padding);
1640 bcopy((void *)config_buf, buf, n_config);
1641 bzero(&buf[n_config], n_padding);
1642 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
1643 config = _dns_configuration_expand_config((_dns_config_buf_t *)(void *)buf);
1644 _dns_configuration_log(config, TRUE);
1645 free(buf);
1646 } else {
1647 my_log(LOG_INFO, "*** No DNS configuration");
1648 }
1649 #ifndef MAIN
1650 // save [new] configuration
1651 if (!_dns_configuration_store(&_config)) {
1652 my_log(LOG_ERR, "could not store configuration");
1653 }
1654 #endif // MAIN
1655
1656 changed = TRUE;
1657 }
1658
1659 if (_config != NULL) _dns_configuration_free(&_config);
1660
1661 CFRelease(resolvers);
1662 return changed;
1663 }
1664
1665
1666 #if !TARGET_OS_IPHONE
1667 static SCDynamicStoreRef dns_configuration_store;
1668 static SCDynamicStoreCallBack dns_configuration_callout;
1669
1670 static void
1671 dns_configuration_changed(CFMachPortRef port, void *msg, CFIndex size, void *info)
1672 {
1673 os_activity_t activity_id;
1674 static const CFStringRef key = CFSTR(_PATH_RESOLVER_DIR);
1675 CFArrayRef keys;
1676 Boolean resolvers_now;
1677 static Boolean resolvers_save = FALSE;
1678 struct stat statbuf;
1679
1680 activity_id = os_activity_start("processing DNS configuration change",
1681 OS_ACTIVITY_FLAG_DEFAULT);
1682
1683 resolvers_now = (stat(_PATH_RESOLVER_DIR, &statbuf) == 0);
1684 if (!resolvers_save && (resolvers_save == resolvers_now)) {
1685 // if we did not (and still do not) have an "/etc/resolvers"
1686 // directory than this notification is the result of a change
1687 // to the "/etc" directory.
1688 goto done;
1689 }
1690 resolvers_save = resolvers_now;
1691
1692 my_log(LOG_INFO, _PATH_RESOLVER_DIR " changed");
1693
1694 // fake a "DNS" change
1695 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
1696 (*dns_configuration_callout)(dns_configuration_store, keys, NULL);
1697 CFRelease(keys);
1698
1699 done :
1700
1701 os_activity_end(activity_id);
1702
1703 return;
1704 }
1705
1706
1707 __private_extern__
1708 void
1709 dns_configuration_monitor(SCDynamicStoreRef store, SCDynamicStoreCallBack callout)
1710 {
1711 CFMachPortRef mp;
1712 mach_port_t notify_port;
1713 int notify_token;
1714 CFRunLoopSourceRef rls;
1715 uint32_t status;
1716
1717 dns_configuration_store = store;
1718 dns_configuration_callout = callout;
1719
1720 status = notify_register_mach_port(_PATH_RESOLVER_DIR, &notify_port, 0, &notify_token);
1721 if (status != NOTIFY_STATUS_OK) {
1722 my_log(LOG_ERR, "notify_register_mach_port() failed");
1723 return;
1724 }
1725
1726 status = notify_monitor_file(notify_token, "/private" _PATH_RESOLVER_DIR, 0);
1727 if (status != NOTIFY_STATUS_OK) {
1728 my_log(LOG_ERR, "notify_monitor_file() failed");
1729 (void)notify_cancel(notify_token);
1730 return;
1731 }
1732
1733 mp = _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1734 notify_port,
1735 dns_configuration_changed,
1736 NULL);
1737
1738 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1739 if (rls == NULL) {
1740 my_log(LOG_ERR, "SCDynamicStoreCreateRunLoopSource() failed");
1741 CFRelease(mp);
1742 (void)notify_cancel(notify_token);
1743 return;
1744 }
1745 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1746 CFRelease(rls);
1747
1748 CFRelease(mp);
1749 return;
1750 }
1751 #endif // !TARGET_OS_IPHONE
1752
1753
1754 __private_extern__
1755 void
1756 dns_configuration_init(CFBundleRef bundle)
1757 {
1758 CFDictionaryRef dict;
1759
1760 dict = CFBundleGetInfoDictionary(bundle);
1761 if (isA_CFDictionary(dict)) {
1762 S_mdns_timeout = CFDictionaryGetValue(dict, CFSTR("mdns_timeout"));
1763 S_mdns_timeout = isA_CFNumber(S_mdns_timeout);
1764
1765 S_pdns_timeout = CFDictionaryGetValue(dict, CFSTR("pdns_timeout"));
1766 S_pdns_timeout = isA_CFNumber(S_pdns_timeout);
1767 }
1768
1769 return;
1770 }
1771
1772
1773 #pragma mark -
1774 #pragma mark Standalone test code
1775
1776
1777 #ifdef MAIN
1778
1779 static void
1780 split(const void * key, const void * value, void * context)
1781 {
1782 CFArrayRef components;
1783 CFStringRef entity_id;
1784 CFStringRef service_id;
1785 CFMutableDictionaryRef state_dict;
1786
1787 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/"));
1788 service_id = CFArrayGetValueAtIndex(components, 3);
1789 entity_id = CFArrayGetValueAtIndex(components, 4);
1790 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id);
1791 if (state_dict != NULL) {
1792 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
1793 } else {
1794 state_dict = CFDictionaryCreateMutable(NULL,
1795 0,
1796 &kCFTypeDictionaryKeyCallBacks,
1797 &kCFTypeDictionaryValueCallBacks);
1798 }
1799
1800 if (CFEqual(entity_id, kSCEntNetIPv4) ||
1801 CFEqual(entity_id, kSCEntNetIPv6)) {
1802 CFDictionaryRef dict;
1803 CFStringRef interface;
1804
1805 if (CFEqual(entity_id, kSCEntNetIPv4)) {
1806 dict = ipv4_dict_create(value);
1807 }
1808 else {
1809 dict = ipv6_dict_create(value);
1810 }
1811 if (dict != NULL) {
1812 CFDictionarySetValue(state_dict, entity_id, dict);
1813 }
1814
1815 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName);
1816 if (interface != NULL) {
1817 CFDictionaryRef dns;
1818 CFMutableDictionaryRef new_dns;
1819
1820 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1821 if (dns != NULL) {
1822 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, dns);
1823 } else {
1824 new_dns = CFDictionaryCreateMutable(NULL,
1825 0,
1826 &kCFTypeDictionaryKeyCallBacks,
1827 &kCFTypeDictionaryValueCallBacks);
1828 }
1829 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1830 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1831 CFRelease(new_dns);
1832 }
1833 } else if (CFEqual(entity_id, kSCEntNetDNS)) {
1834 CFDictionaryRef dns;
1835
1836 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1837 if (dns != NULL) {
1838 CFStringRef interface;
1839
1840 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
1841 if (interface != NULL) {
1842 CFMutableDictionaryRef new_dns;
1843
1844 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
1845 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1846 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1847 CFRelease(new_dns);
1848 } else {
1849 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1850 }
1851 } else {
1852 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1853 }
1854 } else {
1855 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
1856 }
1857
1858 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
1859 CFRelease(state_dict);
1860 CFRelease(components);
1861
1862 return;
1863 }
1864
1865 int
1866 main(int argc, char **argv)
1867 {
1868 CFDictionaryRef entities;
1869 CFStringRef key;
1870 CFArrayRef multicast_resolvers;
1871 CFStringRef pattern;
1872 CFMutableArrayRef patterns;
1873 CFStringRef primary = NULL;
1874 CFDictionaryRef primaryDNS = NULL;
1875 CFArrayRef private_resolvers;
1876 CFArrayRef service_order = NULL;
1877 CFMutableDictionaryRef service_state_dict;
1878 CFDictionaryRef setup_global_ipv4;
1879 CFDictionaryRef state_global_ipv4;
1880 SCDynamicStoreRef store;
1881
1882 _sc_debug = TRUE;
1883 _sc_log = FALSE;
1884 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1885
1886 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
1887
1888 // get IPv4, IPv6, and DNS entities
1889 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1890 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1891 kSCDynamicStoreDomainState,
1892 kSCCompAnyRegex,
1893 kSCEntNetIPv4);
1894 CFArrayAppendValue(patterns, pattern);
1895 CFRelease(pattern);
1896 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1897 kSCDynamicStoreDomainState,
1898 kSCCompAnyRegex,
1899 kSCEntNetIPv6);
1900 CFArrayAppendValue(patterns, pattern);
1901 CFRelease(pattern);
1902 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1903 kSCDynamicStoreDomainState,
1904 kSCCompAnyRegex,
1905 kSCEntNetDNS);
1906 CFArrayAppendValue(patterns, pattern);
1907 CFRelease(pattern);
1908 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
1909 CFRelease(patterns);
1910
1911 service_state_dict = CFDictionaryCreateMutable(NULL,
1912 0,
1913 &kCFTypeDictionaryKeyCallBacks,
1914 &kCFTypeDictionaryValueCallBacks);
1915 CFDictionaryApplyFunction(entities, split, service_state_dict);
1916 CFRelease(entities);
1917
1918 // get primary service ID
1919 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1920 kSCDynamicStoreDomainState,
1921 kSCEntNetIPv4);
1922 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1923 CFRelease(key);
1924 if (state_global_ipv4 != NULL) {
1925 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
1926 if (primary != NULL) {
1927 CFDictionaryRef service_dict;
1928
1929 // get DNS configuration for primary service
1930 service_dict = CFDictionaryGetValue(service_state_dict, primary);
1931 if (service_dict != NULL) {
1932 primaryDNS = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
1933 }
1934 }
1935 }
1936
1937 // get serviceOrder
1938 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
1939 kSCDynamicStoreDomainSetup,
1940 kSCEntNetIPv4);
1941 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
1942 CFRelease(key);
1943 if (setup_global_ipv4 != NULL) {
1944 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
1945 }
1946
1947 // get multicast resolvers
1948 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1949 kSCDynamicStoreDomainState,
1950 kSCCompNetwork,
1951 CFSTR(kDNSServiceCompMulticastDNS));
1952 multicast_resolvers = SCDynamicStoreCopyValue(store, key);
1953 CFRelease(key);
1954
1955 // get private resolvers
1956 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
1957 kSCDynamicStoreDomainState,
1958 kSCCompNetwork,
1959 CFSTR(kDNSServiceCompPrivateDNS));
1960 private_resolvers = SCDynamicStoreCopyValue(store, key);
1961 CFRelease(key);
1962
1963 // update DNS configuration
1964 dns_configuration_init(CFBundleGetMainBundle());
1965 (void)dns_configuration_set(primaryDNS,
1966 service_state_dict,
1967 service_order,
1968 multicast_resolvers,
1969 private_resolvers);
1970
1971 // cleanup
1972 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
1973 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
1974 if (multicast_resolvers != NULL) CFRelease(multicast_resolvers);
1975 if (private_resolvers != NULL) CFRelease(private_resolvers);
1976 CFRelease(service_state_dict);
1977 CFRelease(store);
1978
1979 /* not reached */
1980 exit(0);
1981 return 0;
1982 }
1983 #endif
1984