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