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