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