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