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