]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/dns-configuration.c
configd-1061.141.1.tar.gz
[apple/configd.git] / Plugins / IPMonitor / dns-configuration.c
1 /*
2 * Copyright (c) 2004-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * March 22, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <TargetConditionals.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <net/if.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <arpa/nameser.h>
43 #include <resolv.h>
44 #include <notify.h>
45 #include <notify_private.h>
46 #include <CommonCrypto/CommonDigest.h>
47
48 #include <CoreFoundation/CoreFoundation.h>
49 #include <SystemConfiguration/SystemConfiguration.h>
50 #include <SystemConfiguration/SCPrivate.h>
51 #include <SystemConfiguration/SCValidation.h>
52 #include "ip_plugin.h"
53
54 #include "dns-configuration.h"
55
56 #include <dnsinfo.h>
57 #include "dnsinfo_create.h"
58 #include "dnsinfo_internal.h"
59 #include "dnsinfo_logging.h"
60 #include "dnsinfo_private.h"
61 #include "dnsinfo_server.h"
62
63 #include <network_information.h>
64
65 #include <dns_sd.h>
66 #include <dns_sd_private.h>
67
68 #define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
69 #define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
70 #define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
71
72 /* multicast DNS resolver configurations */
73 static CFNumberRef S_mdns_timeout = NULL;
74
75 /* private DNS resolver configurations */
76 static CFNumberRef S_pdns_timeout = NULL;
77
78
79 #pragma mark -
80 #pragma mark DNS resolver flags
81
82
83 static __inline__ boolean_t
84 dns_resolver_flags_all_queries(uint32_t query_flags)
85 {
86 return ((query_flags & DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS) == DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS);
87 }
88
89
90
91
92 static uint32_t
93 dns_resolver_flags_service(CFDictionaryRef service, uint32_t resolver_flags)
94 {
95
96 // check if the service has v4 configured
97 if (((resolver_flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS) == 0) &&
98 service_is_routable(service, AF_INET)) {
99 resolver_flags |= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS;
100 }
101
102 // check if the service has v6 configured
103 if (((resolver_flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS) == 0) &&
104 service_is_routable(service, AF_INET6)) {
105 resolver_flags |= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS;
106 }
107
108 return resolver_flags;
109 }
110
111
112 static void
113 add_dns_resolver_flags(const void *key, const void *value, void *context)
114 {
115 #pragma unused(key)
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 #pragma unused(context)
620 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
621 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
622 CFNumberRef num1;
623 CFNumberRef num2;
624 uint32_t order1 = DEFAULT_SEARCH_ORDER;
625 uint32_t order2 = DEFAULT_SEARCH_ORDER;
626
627 num1 = CFDictionaryGetValue(dns1, kSCPropNetDNSSearchOrder);
628 if (!isA_CFNumber(num1) ||
629 !CFNumberGetValue(num1, kCFNumberSInt32Type, &order1)) {
630 order1 = DEFAULT_SEARCH_ORDER;
631 }
632
633 num2 = CFDictionaryGetValue(dns2, kSCPropNetDNSSearchOrder);
634 if (!isA_CFNumber(num2) ||
635 !CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
636 order2 = DEFAULT_SEARCH_ORDER;
637 }
638
639 if (order1 == order2) {
640 // if same "SearchOrder", retain original orderring for configurations
641 if (CFDictionaryGetValueIfPresent(dns1, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num1) &&
642 CFDictionaryGetValueIfPresent(dns2, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num2) &&
643 isA_CFNumber(num1) &&
644 isA_CFNumber(num2) &&
645 CFNumberGetValue(num1, kCFNumberSInt32Type, &order1) &&
646 CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
647 if (order1 == order2) {
648 return kCFCompareEqualTo;
649 } else {
650 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
651 }
652 }
653
654 return kCFCompareEqualTo;
655 }
656
657 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
658 }
659
660
661 static CF_RETURNS_RETAINED CFArrayRef
662 extract_search_domains(CFMutableDictionaryRef defaultDomain, CFArrayRef supplemental)
663 {
664 CFStringRef defaultDomainName = NULL;
665 uint32_t defaultOrder = DEFAULT_SEARCH_ORDER;
666 CFArrayRef defaultSearchDomains = NULL;
667 CFIndex defaultSearchIndex = 0;
668 CFMutableArrayRef mySearchDomains;
669 CFMutableArrayRef mySupplemental = NULL;
670 CFIndex n_supplemental;
671 CFStringRef trimmedDomainName;
672
673 mySearchDomains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
674
675 if (defaultDomain != NULL) {
676 CFNumberRef num;
677
678 num = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSSearchOrder);
679 if (!isA_CFNumber(num) ||
680 !CFNumberGetValue(num, kCFNumberSInt32Type, &defaultOrder)) {
681 defaultOrder = DEFAULT_SEARCH_ORDER;
682 }
683
684 defaultDomainName = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSDomainName);
685 defaultSearchDomains = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSSearchDomains);
686 }
687
688 // validate the provided "search" domains or move/expand/promote the "domain" name
689 if (isA_CFArray(defaultSearchDomains)) {
690 CFIndex n_search;
691
692 n_search = CFArrayGetCount(defaultSearchDomains);
693 for (int i = 0; i < n_search; i++) {
694 CFStringRef search;
695
696 search = CFArrayGetValueAtIndex(defaultSearchDomains, i);
697 search = _SC_trimDomain(search);
698 if (search != NULL) {
699 CFArrayAppendValue(mySearchDomains, search);
700 CFRelease(search);
701 }
702 }
703 } else {
704 trimmedDomainName = _SC_trimDomain(defaultDomainName);
705 #ifdef PERFORM_DOMAIN_EXPANSION
706 /*
707 * With BIND 4.8.3 (and earlier) resolvers, the default search list included
708 * the default domain and each of its parent domains with two or more labels.
709 */
710 if ((trimmedDomainName != NULL) &&
711 CFStringHasSuffix(defaultDomainName, CFSTR("."))) {
712 // if "domain" name is fully qualified
713 CFArrayAppendValue(mySearchDomains, trimmedDomainName);
714 CFRelease(trimmedDomainName);
715 } else if (trimmedDomainName != NULL) {
716 char *domain;
717 int domain_parts = 1;
718 char *dp;
719 const int ndots = 1;
720
721 domain = _SC_cfstring_to_cstring(trimmedDomainName,
722 NULL,
723 0,
724 kCFStringEncodingUTF8);
725 CFRelease(trimmedDomainName);
726
727 // count domain parts
728 for (dp = domain; *dp != '\0'; dp++) {
729 if (*dp == '.') {
730 domain_parts++;
731 }
732 }
733
734 // move "domain" to "search" list (and expand as needed)
735 dp = domain;
736 do {
737 CFStringRef search;
738 CFStringRef str;
739
740 str = CFStringCreateWithCString(NULL,
741 dp,
742 kCFStringEncodingUTF8);
743 search = _SC_trimDomain(str);
744 CFRelease(str);
745 if (search != NULL) {
746 CFArrayAppendValue(mySearchDomains, search);
747 CFRelease(search);
748 }
749
750 dp = strchr(dp, '.') + 1;
751 } while (domain_parts-- > 2);
752 CFAllocatorDeallocate(NULL, domain);
753 }
754 #else // PERFORM_DOMAIN_EXPANSION
755 /*
756 * With BIND 4.9.3 (and later) resolvers, the default search list included
757 * just the default domain.
758 */
759 if (trimmedDomainName != NULL) {
760 CFArrayAppendValue(mySearchDomains, trimmedDomainName);
761 CFRelease(trimmedDomainName);
762 }
763 #endif // PERFORM_DOMAIN_EXPANSION
764 }
765
766 // add any supplemental "domain" names to the search list
767 n_supplemental = (supplemental != NULL) ? CFArrayGetCount(supplemental) : 0;
768 if (n_supplemental > 1) {
769 mySupplemental = CFArrayCreateMutableCopy(NULL, 0, supplemental);
770 CFArraySortValues(mySupplemental,
771 CFRangeMake(0, n_supplemental),
772 compareBySearchOrder,
773 NULL);
774 supplemental = mySupplemental;
775 }
776 for (int i = 0; i < n_supplemental; i++) {
777 CFDictionaryRef dns;
778 CFIndex domainIndex;
779 int noSearch;
780 CFNumberRef num;
781 CFStringRef options;
782 CFStringRef supplementalDomain;
783 uint32_t supplementalOrder;
784
785 dns = CFArrayGetValueAtIndex(supplemental, i);
786
787 options = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
788 if (isA_CFString(options)) {
789 CFRange range;
790
791 if (CFEqual(options, CFSTR("pdns"))) {
792 // don't add private resolver domains to the search list
793 continue;
794 }
795
796 range = CFStringFind(options, CFSTR("interface="), 0);
797 if (range.location != kCFNotFound) {
798 // don't add scoped resolver domains to the search list
799 continue;
800 }
801 }
802
803 supplementalDomain = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
804 supplementalDomain = _SC_trimDomain(supplementalDomain);
805 if (supplementalDomain == NULL) {
806 continue;
807 }
808
809 num = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomainsNoSearch);
810 if (isA_CFNumber(num) &&
811 CFNumberGetValue(num, kCFNumberIntType, &noSearch) &&
812 (noSearch != 0)) {
813 CFRelease(supplementalDomain);
814 continue;
815 }
816
817 if (CFStringHasSuffix(supplementalDomain, CFSTR(".in-addr.arpa")) ||
818 CFStringHasSuffix(supplementalDomain, CFSTR(".ip6.arpa" ))) {
819 CFRelease(supplementalDomain);
820 continue;
821 }
822
823 domainIndex = CFArrayGetFirstIndexOfValue(mySearchDomains,
824 CFRangeMake(0, CFArrayGetCount(mySearchDomains)),
825 supplementalDomain);
826
827 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
828 if (!isA_CFNumber(num) ||
829 !CFNumberGetValue(num, kCFNumberSInt32Type, &supplementalOrder)) {
830 supplementalOrder = DEFAULT_SEARCH_ORDER;
831 }
832
833 if (supplementalOrder < defaultOrder) {
834 if (domainIndex != kCFNotFound) {
835 // if supplemental domain is already in the search list
836 CFArrayRemoveValueAtIndex(mySearchDomains, domainIndex);
837 if (domainIndex < defaultSearchIndex) {
838 defaultSearchIndex--;
839 }
840 }
841 CFArrayInsertValueAtIndex(mySearchDomains,
842 defaultSearchIndex,
843 supplementalDomain);
844 defaultSearchIndex++;
845 } else {
846 if (domainIndex == kCFNotFound) {
847 // add to the (end of the) search list
848 CFArrayAppendValue(mySearchDomains, supplementalDomain);
849 }
850 }
851
852 CFRelease(supplementalDomain);
853 }
854 if (mySupplemental != NULL) CFRelease(mySupplemental);
855
856 // update the "search" domains
857 if (CFArrayGetCount(mySearchDomains) == 0) {
858 CFRelease(mySearchDomains);
859 mySearchDomains = NULL;
860 }
861
862 // remove the "domain" name and "search" list
863 CFDictionaryRemoveValue(defaultDomain, kSCPropNetDNSDomainName);
864 CFDictionaryRemoveValue(defaultDomain, kSCPropNetDNSSearchDomains);
865
866 return mySearchDomains;
867 }
868
869
870 static void
871 add_scoped_resolvers(CFMutableArrayRef scoped,
872 CFDictionaryRef services,
873 CFArrayRef service_order)
874 {
875 const void * keys_q[N_QUICK];
876 const void ** keys = keys_q;
877 CFIndex i;
878 CFIndex n_order;
879 CFIndex n_services;
880 CFMutableArrayRef order;
881 CFMutableSetRef seen;
882
883 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
884 if (n_services == 0) {
885 return; // if no services
886 }
887
888 // ensure that we process all services in order
889
890 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
891 if (n_order > 0) {
892 order = CFArrayCreateMutableCopy(NULL, 0, service_order);
893 } else {
894 order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
895 }
896
897 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
898 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
899 }
900 CFDictionaryGetKeysAndValues(services, keys, NULL);
901 for (i = 0; i < n_services; i++) {
902 CFStringRef serviceID = (CFStringRef)keys[i];
903
904 if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) {
905 CFArrayAppendValue(order, serviceID);
906 n_order++;
907 }
908 }
909 if (keys != keys_q) {
910 CFAllocatorDeallocate(NULL, keys);
911 }
912
913 // iterate over services
914
915 seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
916 for (i = 0; i < n_order; i++) {
917 CFDictionaryRef dns;
918 uint32_t dns_resolver_flags;
919 char if_name[IF_NAMESIZE];
920 CFStringRef interface;
921 CFMutableDictionaryRef newDNS;
922 uint32_t newFlags;
923 CFArrayRef searchDomains;
924 CFDictionaryRef service;
925 CFStringRef serviceID;
926 CFArrayRef servers;
927
928 serviceID = CFArrayGetValueAtIndex(order, i);
929 service = CFDictionaryGetValue(services, serviceID);
930 if (!isA_CFDictionary(service)) {
931 // if no service
932 continue;
933 }
934
935 dns = CFDictionaryGetValue(service, kSCEntNetDNS);
936 if (!isA_CFDictionary(dns)) {
937 // if no DNS
938 continue;
939 }
940
941 servers = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
942 if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) {
943 // if no DNS server addresses
944 continue;
945 }
946
947 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
948 if ((interface == NULL) || CFEqual(interface, CFSTR("*"))) {
949 // if no [scoped] interface or supplemental configuration w/match-all
950 continue;
951 }
952
953 if (CFDictionaryContainsKey(dns, kSCPropNetDNSServiceIdentifier)) {
954 // if this is a service-specific resolver
955 continue;
956 }
957
958 if (CFSetContainsValue(seen, interface)) {
959 // if we've already processed this [scoped] interface
960 continue;
961 }
962 CFSetSetValue(seen, interface);
963
964 if ((_SC_cfstring_to_cstring(interface,
965 if_name,
966 sizeof(if_name),
967 kCFStringEncodingASCII) == NULL) ||
968 (my_if_nametoindex(if_name) == 0)) {
969 // if interface index not available
970 continue;
971 }
972
973 // add [scoped] resolver entry
974 newDNS = CFDictionaryCreateMutableCopy(NULL, 0, dns);
975
976 // set search list
977 searchDomains = extract_search_domains(newDNS, NULL);
978 if (searchDomains != NULL) {
979 CFDictionarySetValue(newDNS, kSCPropNetDNSSearchDomains, searchDomains);
980 CFRelease(searchDomains);
981 }
982
983 // get "Request A/AAAA query" flag(s)
984 dns_resolver_flags = dns_resolver_flags_service(service, 0);
985 if (dns_resolver_flags == 0) {
986 goto skip;
987 }
988
989 // set "scoped" configuration flag
990 newFlags = DNS_RESOLVER_FLAGS_SCOPED;
991
992 // add "Request A/AAAA query" flag(s)
993 newFlags |= dns_resolver_flags;
994
995 merge_configuration_flags(newDNS, newFlags);
996
997 // remove keys we don't want in a [scoped] resolver
998 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchDomains);
999 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchOrders);
1000
1001 // add the [scoped] resolver
1002 add_resolver_signature(newDNS, "Scoped", serviceID, 0);
1003 add_resolver(scoped, newDNS);
1004
1005 // add any supplemental resolver configurations for this interface
1006 add_supplemental_resolvers(scoped, services, service_order, interface, service);
1007
1008 skip:
1009 CFRelease(newDNS);
1010 }
1011
1012 CFRelease(seen);
1013 CFRelease(order);
1014 return;
1015 }
1016
1017
1018 static void
1019 add_service_specific_resolvers(CFMutableArrayRef resolvers, CFDictionaryRef services)
1020 {
1021 CFIndex i;
1022 CFStringRef keys_q[N_QUICK];
1023 CFStringRef *keys = keys_q;
1024 CFIndex n_services;
1025 CFMutableSetRef seen;
1026 CFDictionaryRef vals_q[N_QUICK];
1027 CFDictionaryRef *vals = vals_q;
1028
1029 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
1030 if (n_services == 0) {
1031 return; // if no services
1032 }
1033
1034 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(keys_q[0]))) {
1035 keys = CFAllocatorAllocate(kCFAllocatorDefault, n_services * sizeof(keys[0]), 0);
1036 vals = CFAllocatorAllocate(kCFAllocatorDefault, n_services * sizeof(vals[0]), 0);
1037 }
1038 CFDictionaryGetKeysAndValues(services, (const void **)keys, (const void **)vals);
1039
1040 seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1041 for (i = 0; i < n_services; i++) {
1042 CFDictionaryRef dns;
1043 CFNumberRef dns_service_identifier;
1044 CFMutableDictionaryRef newDNS;
1045 uint32_t newFlags = 0;
1046 CFDictionaryRef service = vals[i];
1047 CFStringRef serviceID = keys[i];
1048 CFArrayRef searchDomains;
1049
1050 dns = CFDictionaryGetValue(service, kSCEntNetDNS);
1051 if (!isA_CFDictionary(dns)) {
1052 // if no DNS
1053 continue;
1054 }
1055
1056 dns_service_identifier = CFDictionaryGetValue(dns, kSCPropNetDNSServiceIdentifier);
1057 if (!isA_CFNumber(dns_service_identifier)) {
1058 // if no DNS [vpn] Service Identifier
1059 continue;
1060 }
1061
1062 if (CFSetContainsValue(seen, dns_service_identifier)) {
1063 my_log(LOG_ERR, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
1064 continue;
1065 }
1066 CFSetSetValue(seen, dns_service_identifier);
1067
1068 newDNS = CFDictionaryCreateMutableCopy(NULL, 0, dns);
1069
1070 // add "Request A/AAAA query" flag(s)
1071 newFlags |= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
1072
1073 // set search list
1074 searchDomains = extract_search_domains(newDNS, NULL);
1075 if (searchDomains != NULL) {
1076 CFDictionarySetValue(newDNS, kSCPropNetDNSSearchDomains, searchDomains);
1077 CFRelease(searchDomains);
1078 searchDomains = NULL;
1079 }
1080
1081 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchDomains);
1082 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchOrders);
1083
1084 if (CFDictionaryContainsKey(newDNS, kSCPropInterfaceName)) {
1085 CFMutableDictionaryRef interfaceScopedDNS;
1086 uint32_t interfaceScopedFlags;
1087
1088 // The dictionary has an interface, so add a interface-scoped resolver
1089
1090 CFDictionarySetValue(newDNS, DNS_CONFIGURATION_SCOPED_QUERY_KEY, kCFBooleanTrue);
1091
1092 interfaceScopedDNS = CFDictionaryCreateMutableCopy(NULL, 0, newDNS);
1093 interfaceScopedFlags = newFlags;
1094
1095 // set "scoped" configuration flag
1096 interfaceScopedFlags |= DNS_RESOLVER_FLAGS_SCOPED;
1097 merge_configuration_flags(interfaceScopedDNS, interfaceScopedFlags);
1098
1099 CFDictionaryRemoveValue(interfaceScopedDNS, kSCPropNetDNSServiceIdentifier);
1100
1101 add_resolver_signature(interfaceScopedDNS, "Service", serviceID, 0);
1102 add_resolver(resolvers, interfaceScopedDNS);
1103 CFRelease(interfaceScopedDNS);
1104 }
1105
1106 // set "service specific" configuration flag
1107 newFlags |= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC;
1108 merge_configuration_flags(newDNS, newFlags);
1109
1110 add_resolver_signature(newDNS, "Service", serviceID, 0);
1111 add_resolver(resolvers, newDNS);
1112 CFRelease(newDNS);
1113 }
1114 CFRelease(seen);
1115
1116 if (keys != keys_q) {
1117 CFAllocatorDeallocate(kCFAllocatorDefault, keys);
1118 CFAllocatorDeallocate(kCFAllocatorDefault, vals);
1119 }
1120
1121 return;
1122 }
1123
1124
1125 static void
1126 add_default_resolver(CFMutableArrayRef resolvers,
1127 CFDictionaryRef defaultResolver,
1128 Boolean *orderAdded,
1129 CFArrayRef *searchDomains)
1130 {
1131 CFMutableDictionaryRef myDefault;
1132 uint32_t myOrder = DEFAULT_SEARCH_ORDER;
1133 CFNumberRef order;
1134
1135 if (defaultResolver == NULL) {
1136 myDefault = CFDictionaryCreateMutable(NULL,
1137 0,
1138 &kCFTypeDictionaryKeyCallBacks,
1139 &kCFTypeDictionaryValueCallBacks);
1140 } else {
1141 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver);
1142 }
1143 assert(myDefault != NULL);
1144
1145 // ensure that the default resolver has a search order
1146
1147 order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder);
1148 if (!isA_CFNumber(order) ||
1149 !CFNumberGetValue(order, kCFNumberSInt32Type, &myOrder)) {
1150 myOrder = DEFAULT_SEARCH_ORDER;
1151 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
1152 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order);
1153 CFRelease(order);
1154 *orderAdded = TRUE;
1155 }
1156
1157 // extract the "search" domain list for the default resolver (and
1158 // any supplemental resolvers)
1159
1160 *searchDomains = extract_search_domains(myDefault, resolvers);
1161
1162 // add the default resolver
1163
1164 add_resolver_signature(myDefault, "Default", NULL, 0);
1165 add_resolver(resolvers, myDefault);
1166 CFRelease(myDefault);
1167 return;
1168 }
1169
1170
1171 static dns_create_resolver_t
1172 create_resolver(CFDictionaryRef dns)
1173 {
1174 CFArrayRef list;
1175 CFNumberRef num;
1176 dns_create_resolver_t _resolver;
1177 CFStringRef str;
1178 CFStringRef targetInterface = NULL;
1179 unsigned int targetInterfaceIndex = 0;
1180
1181 _resolver = _dns_resolver_create();
1182
1183 // process domain
1184 str = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName);
1185 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
1186 char domain[NS_MAXDNAME];
1187
1188 if (_SC_cfstring_to_cstring(str, domain, sizeof(domain), kCFStringEncodingUTF8) != NULL) {
1189 _dns_resolver_set_domain(&_resolver, domain);
1190 }
1191 }
1192
1193 // process search domains
1194 list = CFDictionaryGetValue(dns, kSCPropNetDNSSearchDomains);
1195 if (isA_CFArray(list)) {
1196 CFIndex i;
1197 CFIndex n = CFArrayGetCount(list);
1198
1199 // add "search" domains
1200 for (i = 0; i < n; i++) {
1201 str = CFArrayGetValueAtIndex(list, i);
1202 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
1203 char search[NS_MAXDNAME];
1204
1205 if (_SC_cfstring_to_cstring(str, search, sizeof(search), kCFStringEncodingUTF8) != NULL) {
1206 _dns_resolver_add_search(&_resolver, search);
1207 }
1208 }
1209 }
1210 }
1211
1212 // process interface index
1213 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_IF_INDEX_KEY);
1214 if (isA_CFNumber(num)) {
1215 int if_index;
1216
1217 if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) {
1218 char buf[IFNAMSIZ];
1219 const char *if_name = NULL;
1220
1221 if (if_index != 0) {
1222 if_name = my_if_indextoname(if_index, buf);
1223 if (if_name != NULL) {
1224 targetInterface = CFStringCreateWithCString(NULL,
1225 if_name,
1226 kCFStringEncodingASCII);
1227 targetInterfaceIndex = if_index;
1228 }
1229 }
1230
1231 _dns_resolver_set_if_index(&_resolver, if_index, if_name);
1232 }
1233 }
1234
1235 // process flags
1236 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_FLAGS_KEY);
1237 if (isA_CFNumber(num)) {
1238 uint32_t flags;
1239
1240 if (CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
1241 _dns_resolver_set_flags(&_resolver, flags);
1242 }
1243 }
1244
1245 // process nameserver addresses
1246 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1247 list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
1248 if (isA_CFArray(list)) {
1249 CFIndex i;
1250 CFIndex n = CFArrayGetCount(list);
1251
1252 for (i = 0; i < n; i++) {
1253 union {
1254 struct sockaddr sa;
1255 struct sockaddr_in sin;
1256 struct sockaddr_in6 sin6;
1257 } addr;
1258 char buf[64];
1259
1260 str = CFArrayGetValueAtIndex(list, i);
1261 if (!isA_CFString(str)) {
1262 continue;
1263 }
1264
1265 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
1266 continue;
1267 }
1268
1269 if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
1270 continue;
1271 }
1272
1273 if ((addr.sa.sa_family == AF_INET6) &&
1274 IN6_IS_ADDR_LINKLOCAL(&addr.sin6.sin6_addr) &&
1275 (addr.sin6.sin6_scope_id == 0) &&
1276 (targetInterfaceIndex != 0)) {
1277 // for link local [IPv6] addresses, if the scope id is not
1278 // set then we should use the interface associated with the
1279 // resolver configuration
1280 addr.sin6.sin6_scope_id = targetInterfaceIndex;
1281 }
1282
1283 _dns_resolver_add_nameserver(&_resolver, &addr.sa);
1284 }
1285 }
1286
1287 // process search order
1288 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
1289 if (isA_CFNumber(num)) {
1290 uint32_t order;
1291
1292 if (CFNumberGetValue(num, kCFNumberSInt32Type, &order)) {
1293 _dns_resolver_set_order(&_resolver, order);
1294 }
1295 }
1296
1297 // process sortlist
1298 list = CFDictionaryGetValue(dns, kSCPropNetDNSSortList);
1299 if (isA_CFArray(list)) {
1300 CFIndex i;
1301 CFIndex n = CFArrayGetCount(list);
1302
1303 for (i = 0; i < n; i++) {
1304 char buf[128];
1305 char *slash;
1306 dns_sortaddr_t sortaddr;
1307
1308 str = CFArrayGetValueAtIndex(list, i);
1309 if (!isA_CFString(str)) {
1310 continue;
1311 }
1312
1313 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
1314 continue;
1315 }
1316
1317 slash = strchr(buf, '/');
1318 if (slash != NULL) {
1319 *slash = '\0';
1320 }
1321
1322 memset(&sortaddr, 0, sizeof(sortaddr));
1323 if (inet_aton(buf, &sortaddr.address) != 1) {
1324 /* if address not valid */
1325 continue;
1326 }
1327
1328 if (slash != NULL) {
1329 if (inet_aton(slash + 1, &sortaddr.mask) != 1) {
1330 /* if subnet mask not valid */
1331 continue;
1332 }
1333 } else {
1334 in_addr_t a;
1335 in_addr_t m;
1336
1337 a = ntohl(sortaddr.address.s_addr);
1338 if (IN_CLASSA(a)) {
1339 m = IN_CLASSA_NET;
1340 } else if (IN_CLASSB(a)) {
1341 m = IN_CLASSB_NET;
1342 } else if (IN_CLASSC(a)) {
1343 m = IN_CLASSC_NET;
1344 } else {
1345 continue;
1346 }
1347
1348 sortaddr.mask.s_addr = htonl(m);
1349 }
1350
1351 _dns_resolver_add_sortaddr(&_resolver, &sortaddr);
1352 }
1353 }
1354
1355 // process port
1356 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerPort);
1357 if (isA_CFNumber(num)) {
1358 int port;
1359
1360 if (CFNumberGetValue(num, kCFNumberIntType, &port)) {
1361 _dns_resolver_set_port(&_resolver, (uint16_t)port);
1362 }
1363 }
1364
1365 // process timeout
1366 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerTimeout);
1367 if (isA_CFNumber(num)) {
1368 int timeout;
1369
1370 if (CFNumberGetValue(num, kCFNumberIntType, &timeout)) {
1371 _dns_resolver_set_timeout(&_resolver, (uint32_t)timeout);
1372 }
1373 }
1374
1375 // process options
1376 str = CFDictionaryGetValue(dns, kSCPropNetDNSOptions);
1377 if (isA_CFString(str)) {
1378 char *options;
1379
1380 options = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
1381 if (options != NULL) {
1382 _dns_resolver_set_options(&_resolver, options);
1383 CFAllocatorDeallocate(NULL, options);
1384 }
1385 }
1386
1387 num = CFDictionaryGetValue(dns, kSCPropNetDNSServiceIdentifier);
1388 if (isA_CFNumber(num)) {
1389 int dns_service_identifier;
1390
1391 if (CFNumberGetValue(num, kCFNumberIntType, &dns_service_identifier)) {
1392 _dns_resolver_set_service_identifier(&_resolver, (uint32_t)dns_service_identifier);
1393 }
1394 }
1395
1396 // process configuration ID
1397 str = CFDictionaryGetValue(dns, DNS_CONFIGURATION_CONFIGURATION_ID);
1398 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
1399 char *cID;
1400
1401 cID = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
1402 if (cID != NULL) {
1403 _dns_resolver_set_configuration_identifier(&_resolver, cID);
1404 CFAllocatorDeallocate(NULL, cID);
1405 }
1406 }
1407
1408 if (targetInterface != NULL) {
1409 CFRelease(targetInterface);
1410 }
1411
1412 return _resolver;
1413 }
1414
1415
1416 static __inline__ Boolean
1417 isScopedConfiguration(CFDictionaryRef dns)
1418 {
1419 uint32_t flags;
1420 CFNumberRef num;
1421
1422 if ((dns != NULL) &&
1423 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
1424 (num != NULL) &&
1425 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
1426 ((flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)) {
1427 // if scoped
1428 return TRUE;
1429 }
1430
1431 return FALSE;
1432 }
1433
1434
1435 static CFComparisonResult
1436 compareDomain(const void *val1, const void *val2, void *context)
1437 {
1438 CFDictionaryRef dns1 = (CFDictionaryRef)val1;
1439 CFDictionaryRef dns2 = (CFDictionaryRef)val2;
1440 CFStringRef domain1;
1441 CFStringRef domain2;
1442 CFArrayRef labels1 = NULL;
1443 CFArrayRef labels2 = NULL;
1444 CFIndex n1;
1445 CFIndex n2;
1446 CFComparisonResult result;
1447 Boolean rev1;
1448 Boolean rev2;
1449 Boolean scoped1;
1450 Boolean scoped2;
1451
1452 // "default" domains sort before "supplemental" domains
1453 domain1 = CFDictionaryGetValue(dns1, kSCPropNetDNSDomainName);
1454 domain2 = CFDictionaryGetValue(dns2, kSCPropNetDNSDomainName);
1455 if (domain1 == NULL) {
1456 return kCFCompareLessThan;
1457 } else if (domain2 == NULL) {
1458 return kCFCompareGreaterThan;
1459 }
1460
1461 // sort non-scoped before scoped
1462 scoped1 = isScopedConfiguration(dns1);
1463 scoped2 = isScopedConfiguration(dns2);
1464 if (scoped1 != scoped2) {
1465 if (!scoped1) {
1466 return kCFCompareLessThan;
1467 } else {
1468 return kCFCompareGreaterThan;
1469 }
1470 }
1471
1472 // forward (A, AAAA) domains sort before reverse (PTR) domains
1473 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa"));
1474 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa"));
1475 if (rev1 != rev2) {
1476 if (rev1) {
1477 return kCFCompareGreaterThan;
1478 } else {
1479 return kCFCompareLessThan;
1480 }
1481 }
1482
1483 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR("."));
1484 n1 = CFArrayGetCount(labels1);
1485
1486 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR("."));
1487 n2 = CFArrayGetCount(labels2);
1488
1489 while ((n1 > 0) && (n2 > 0)) {
1490 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1);
1491 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2);
1492
1493 // compare domain labels
1494 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive);
1495 if (result != kCFCompareEqualTo) {
1496 goto done;
1497 }
1498 }
1499
1500 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1501 if (n1 > n2) {
1502 result = kCFCompareLessThan;
1503 goto done;
1504 } else if (n1 < n2) {
1505 result = kCFCompareGreaterThan;
1506 goto done;
1507 }
1508
1509 // sort by search order
1510 result = compareBySearchOrder(val1, val2, context);
1511
1512 done :
1513
1514 if (labels1 != NULL) CFRelease(labels1);
1515 if (labels2 != NULL) CFRelease(labels2);
1516 return result;
1517 }
1518
1519
1520 static __inline__ Boolean
1521 needsMergeWithDefaultConfiguration(CFDictionaryRef dns)
1522 {
1523 uint32_t flags;
1524 CFNumberRef num;
1525
1526 if ((dns != NULL) &&
1527 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
1528 (num != NULL) &&
1529 CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
1530
1531 // check if merge needed (at all)
1532 if (dns_resolver_flags_all_queries(flags)) {
1533 // if we are already querying for both A/AAAA
1534 return FALSE;
1535 }
1536
1537 // check if scoped or service-specific
1538 if (((flags & DNS_RESOLVER_FLAGS_SCOPED ) != 0) ||
1539 ((flags & DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC) != 0)) {
1540 // yes, skip merge
1541 return FALSE;
1542 }
1543 }
1544
1545 return TRUE;
1546 }
1547
1548
1549 __private_extern__
1550 Boolean
1551 dns_configuration_set(CFDictionaryRef defaultResolver,
1552 CFDictionaryRef services,
1553 CFArrayRef serviceOrder,
1554 CFArrayRef multicastResolvers,
1555 CFArrayRef privateResolvers)
1556 {
1557 dns_create_config_t dns_create_config;
1558 Boolean changed = FALSE;
1559 CFIndex i;
1560 CFMutableDictionaryRef myDefault;
1561 Boolean myOrderAdded = FALSE;
1562 CFArrayRef mySearchDomains = NULL;
1563 CFIndex n_resolvers;
1564 CFMutableArrayRef resolvers;
1565 unsigned char signature[CC_SHA256_DIGEST_LENGTH];
1566 static unsigned char signature_last[CC_SHA256_DIGEST_LENGTH];
1567
1568 // establish list of resolvers
1569
1570 resolvers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1571 assert(resolvers != NULL);
1572
1573 // collect (and add) any "supplemental" resolver configurations
1574
1575 add_supplemental_resolvers(resolvers, services, serviceOrder, NULL, NULL);
1576
1577 // collect (and add) any "private" resolver configurations
1578
1579 add_private_resolvers(resolvers, privateResolvers);
1580
1581 // add the "default" resolver
1582
1583 if (defaultResolver != NULL) {
1584 CFArrayRef servers;
1585
1586 servers = CFDictionaryGetValue(defaultResolver, kSCPropNetDNSServerAddresses);
1587 if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) {
1588 // if no DNS server addresses
1589 defaultResolver = NULL;
1590 }
1591 }
1592
1593 add_default_resolver(resolvers, defaultResolver, &myOrderAdded, &mySearchDomains);
1594
1595 // collect (and add) any "multicast" resolver configurations
1596
1597 add_multicast_resolvers(resolvers, multicastResolvers);
1598
1599 // collect (and add) any "scoped" resolver configurations
1600
1601 add_scoped_resolvers(resolvers, services, serviceOrder);
1602
1603 // collect (and add) any "service-specific" resolver configurations
1604
1605 add_service_specific_resolvers(resolvers, services);
1606
1607 // sort resolvers
1608
1609 n_resolvers = CFArrayGetCount(resolvers);
1610 if (n_resolvers > 1) {
1611 CFArraySortValues(resolvers, CFRangeMake(0, n_resolvers), compareDomain, NULL);
1612 }
1613
1614 // cleanup
1615
1616 for (i = n_resolvers; --i > 0; ) {
1617 CFDictionaryRef resolver;
1618
1619 resolver = CFArrayGetValueAtIndex(resolvers, i);
1620 if (!CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) &&
1621 !CFDictionaryContainsKey(resolver, kSCPropNetDNSSearchDomains) &&
1622 !CFDictionaryContainsKey(resolver, kSCPropNetDNSServerAddresses)) {
1623 // remove empty resolver
1624 CFArrayRemoveValueAtIndex(resolvers, i);
1625 n_resolvers--;
1626 }
1627 }
1628
1629 // update the default resolver
1630
1631 myDefault = CFDictionaryCreateMutableCopy(NULL,
1632 0,
1633 CFArrayGetValueAtIndex(resolvers, 0));
1634 if (mySearchDomains != NULL) {
1635 // add search domains to the default resolver
1636 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchDomains, mySearchDomains);
1637 CFRelease(mySearchDomains);
1638 }
1639 if (myOrderAdded && (n_resolvers > 1)) {
1640 CFDictionaryRef resolver;
1641
1642 resolver = CFArrayGetValueAtIndex(resolvers, 1);
1643 if (CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) ||
1644 isScopedConfiguration(resolver)) {
1645 // if not a supplemental "default" resolver (a domain name is
1646 // present) or if it's a scoped configuration
1647 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
1648 }
1649 }
1650 CFArraySetValueAtIndex(resolvers, 0, myDefault);
1651 CFRelease(myDefault);
1652
1653 // establish resolver configuration
1654
1655 if ((defaultResolver == NULL) && (n_resolvers <= 1)) {
1656 /*
1657 * if no default and no supplemental/scoped resolvers
1658 */
1659 dns_create_config = NULL;
1660 } else {
1661 uint32_t default_resolver_flags = 0;
1662 Boolean have_default_flags = FALSE;
1663
1664 /*
1665 * if default and/or supplemental/scoped resolvers are defined
1666 */
1667 dns_create_config = _dns_configuration_create();
1668
1669 for (i = 0; i < n_resolvers; i++) {
1670 Boolean merge_default_flags;
1671 CFDictionaryRef resolver;
1672 dns_create_resolver_t _resolver;
1673
1674 resolver = CFArrayGetValueAtIndex(resolvers, i);
1675
1676 merge_default_flags = needsMergeWithDefaultConfiguration(resolver);
1677 if (merge_default_flags) {
1678 CFMutableDictionaryRef new_resolver;
1679
1680 if (!have_default_flags) {
1681 CFDictionaryApplyFunction(services,
1682 add_dns_resolver_flags,
1683 &default_resolver_flags);
1684 have_default_flags = TRUE;
1685 }
1686
1687 new_resolver = CFDictionaryCreateMutableCopy(NULL, 0, resolver);
1688 merge_configuration_flags(new_resolver, default_resolver_flags);
1689 resolver = new_resolver;
1690 }
1691
1692 _resolver = create_resolver(resolver);
1693 _dns_configuration_add_resolver(&dns_create_config, _resolver);
1694 _dns_resolver_free(&_resolver);
1695
1696 if (merge_default_flags) {
1697 CFRelease(resolver);
1698 }
1699 }
1700
1701 // add flatfile resolvers
1702
1703 _dnsinfo_flatfile_set_flags(default_resolver_flags);
1704 _dnsinfo_flatfile_add_resolvers(&dns_create_config);
1705 }
1706
1707 // check if the configuration changed
1708 _dns_configuration_signature(&dns_create_config, signature, sizeof(signature));
1709 if (bcmp(signature, signature_last, sizeof(signature)) != 0) {
1710 // save [new] signature
1711 memcpy(signature_last, signature, sizeof(signature));
1712
1713 my_log(LOG_INFO, "Updating DNS configuration");
1714 if (dns_create_config != NULL) {
1715 dns_config_t *dns_config = NULL;
1716 _dns_config_buf_t *dns_config_buf;
1717 size_t n;
1718
1719 n = sizeof(_dns_config_buf_t);
1720 n += ntohl(((_dns_config_buf_t *)dns_create_config)->n_attribute);
1721 dns_config_buf = _dns_configuration_buffer_create((void *)dns_create_config, n);
1722 if (dns_config_buf != NULL) {
1723 dns_config = _dns_configuration_buffer_expand(dns_config_buf);
1724 if (dns_config == NULL) {
1725 // if we were unable to expand the configuration
1726 _dns_configuration_buffer_free(&dns_config_buf);
1727 }
1728 }
1729
1730 if (dns_config != NULL) {
1731 _dns_configuration_log(dns_config, TRUE, NULL);
1732 free(dns_config);
1733 }
1734 } else {
1735 my_log(LOG_INFO, "*** No DNS configuration");
1736 }
1737 #ifndef MAIN
1738 // save [new] configuration
1739 if (!_dns_configuration_store(&dns_create_config)) {
1740 my_log(LOG_ERR, "could not store configuration");
1741 }
1742 #endif // MAIN
1743
1744 changed = TRUE;
1745 }
1746
1747 if (dns_create_config != NULL) {
1748 _dns_configuration_free(&dns_create_config);
1749 }
1750
1751 CFRelease(resolvers);
1752 return changed;
1753 }
1754
1755
1756 static SCDynamicStoreRef dns_configuration_store;
1757 static SCDynamicStoreCallBack dns_configuration_callout;
1758
1759 static void
1760 dns_configuration_changed(CFMachPortRef port, void *msg, CFIndex size, void *info)
1761 {
1762 #pragma unused(port)
1763 #pragma unused(msg)
1764 #pragma unused(size)
1765 #pragma unused(info)
1766 static const CFStringRef key = CFSTR(_PATH_RESOLVER_DIR);
1767 CFArrayRef keys;
1768 Boolean resolvers_now;
1769 static Boolean resolvers_save = FALSE;
1770 struct stat statbuf;
1771
1772 resolvers_now = (stat(_PATH_RESOLVER_DIR, &statbuf) == 0);
1773 if (!resolvers_save && (resolvers_save == resolvers_now)) {
1774 // if we did not (and still do not) have an "/etc/resolvers"
1775 // directory than this notification is the result of a change
1776 // to the "/etc" directory.
1777 return;
1778 }
1779 resolvers_save = resolvers_now;
1780
1781 my_log(LOG_INFO, _PATH_RESOLVER_DIR " changed");
1782
1783 // fake a "DNS" change
1784 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
1785 (*dns_configuration_callout)(dns_configuration_store, keys, NULL);
1786 CFRelease(keys);
1787
1788 return;
1789 }
1790
1791
1792 static Boolean
1793 normalize_path(const char *file_name, char resolved_name[PATH_MAX])
1794 {
1795 char *ch;
1796 char path[PATH_MAX];
1797
1798 strlcpy(path, file_name, sizeof(path));
1799 if (realpath(path, resolved_name) != NULL) {
1800 // if the path exists
1801 return TRUE;
1802 }
1803
1804 ch = strrchr(path, '/');
1805 if (ch != NULL) {
1806 *ch = '\0';
1807 if (realpath(path, resolved_name) != NULL) {
1808 // if a parent path exists
1809 strlcat(resolved_name, "/", PATH_MAX);
1810 strlcat(resolved_name, ch+1, PATH_MAX);
1811 return TRUE;
1812 }
1813 }
1814
1815 return FALSE;
1816 }
1817
1818
1819 __private_extern__
1820 void
1821 dns_configuration_monitor(SCDynamicStoreRef store, SCDynamicStoreCallBack callout)
1822 {
1823 CFMachPortRef mp;
1824 mach_port_t notify_port;
1825 int notify_token;
1826 char resolver_directory_path[PATH_MAX];
1827 CFRunLoopSourceRef rls;
1828 uint32_t status;
1829
1830 if (!normalize_path(_PATH_RESOLVER_DIR, resolver_directory_path)) {
1831 my_log(LOG_ERR, "Not monitoring \"%s\", could not resolve directory path", _PATH_RESOLVER_DIR);
1832 return;
1833 }
1834
1835 dns_configuration_store = store;
1836 dns_configuration_callout = callout;
1837
1838 status = notify_register_mach_port(_PATH_RESOLVER_DIR, &notify_port, 0, &notify_token);
1839 if (status != NOTIFY_STATUS_OK) {
1840 my_log(LOG_ERR, "notify_register_mach_port() failed");
1841 return;
1842 }
1843
1844 #pragma GCC diagnostic push
1845 #pragma GCC diagnostic ignored "-Wdeprecated"
1846 status = notify_monitor_file(notify_token, resolver_directory_path, 0);
1847 #pragma GCC diagnostic pop
1848 if (status != NOTIFY_STATUS_OK) {
1849 my_log(LOG_ERR, "notify_monitor_file() failed");
1850 (void)notify_cancel(notify_token);
1851 return;
1852 }
1853
1854 mp = _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1855 notify_port,
1856 dns_configuration_changed,
1857 NULL);
1858
1859 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1860 if (rls == NULL) {
1861 my_log(LOG_ERR, "SCDynamicStoreCreateRunLoopSource() failed");
1862 CFRelease(mp);
1863 (void)notify_cancel(notify_token);
1864 return;
1865 }
1866 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1867 CFRelease(rls);
1868
1869 CFRelease(mp);
1870 return;
1871 }
1872
1873
1874 __private_extern__
1875 void
1876 dns_configuration_init(CFBundleRef bundle)
1877 {
1878 CFDictionaryRef dict;
1879
1880 dict = CFBundleGetInfoDictionary(bundle);
1881 if (isA_CFDictionary(dict)) {
1882 S_mdns_timeout = CFDictionaryGetValue(dict, CFSTR("mdns_timeout"));
1883 S_mdns_timeout = isA_CFNumber(S_mdns_timeout);
1884
1885 S_pdns_timeout = CFDictionaryGetValue(dict, CFSTR("pdns_timeout"));
1886 S_pdns_timeout = isA_CFNumber(S_pdns_timeout);
1887 }
1888
1889 return;
1890 }
1891
1892
1893 #pragma mark -
1894 #pragma mark Standalone test code
1895
1896
1897 #ifdef MAIN
1898
1899 static void
1900 split(const void * key, const void * value, void * context)
1901 {
1902 CFArrayRef components;
1903 CFStringRef entity_id;
1904 CFStringRef service_id;
1905 CFMutableDictionaryRef state_dict;
1906
1907 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/"));
1908 service_id = CFArrayGetValueAtIndex(components, 3);
1909 entity_id = CFArrayGetValueAtIndex(components, 4);
1910 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id);
1911 if (state_dict != NULL) {
1912 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
1913 } else {
1914 state_dict = CFDictionaryCreateMutable(NULL,
1915 0,
1916 &kCFTypeDictionaryKeyCallBacks,
1917 &kCFTypeDictionaryValueCallBacks);
1918 }
1919
1920 if (CFEqual(entity_id, kSCEntNetIPv4) ||
1921 CFEqual(entity_id, kSCEntNetIPv6)) {
1922 CFDictionaryRef dict;
1923 CFStringRef interface;
1924
1925 if (CFEqual(entity_id, kSCEntNetIPv4)) {
1926 dict = ipv4_dict_create(value);
1927 }
1928 else {
1929 dict = ipv6_dict_create(value);
1930 }
1931 if (dict != NULL) {
1932 CFDictionarySetValue(state_dict, entity_id, dict);
1933 }
1934
1935 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName);
1936 if (interface != NULL) {
1937 CFDictionaryRef dns;
1938 CFMutableDictionaryRef new_dns;
1939
1940 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1941 if (dns != NULL) {
1942 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, dns);
1943 } else {
1944 new_dns = CFDictionaryCreateMutable(NULL,
1945 0,
1946 &kCFTypeDictionaryKeyCallBacks,
1947 &kCFTypeDictionaryValueCallBacks);
1948 }
1949 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1950 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1951 CFRelease(new_dns);
1952 }
1953 } else if (CFEqual(entity_id, kSCEntNetDNS)) {
1954 CFDictionaryRef dns;
1955
1956 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS);
1957 if (dns != NULL) {
1958 CFStringRef interface;
1959
1960 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
1961 if (interface != NULL) {
1962 CFMutableDictionaryRef new_dns;
1963
1964 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
1965 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
1966 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
1967 CFRelease(new_dns);
1968 } else {
1969 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1970 }
1971 } else {
1972 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value);
1973 }
1974 } else {
1975 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
1976 }
1977
1978 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
1979 CFRelease(state_dict);
1980 CFRelease(components);
1981
1982 return;
1983 }
1984
1985 int
1986 main(int argc, char **argv)
1987 {
1988 CFDictionaryRef entities;
1989 CFStringRef key;
1990 CFArrayRef multicast_resolvers;
1991 CFStringRef pattern;
1992 CFMutableArrayRef patterns;
1993 CFStringRef primary = NULL;
1994 CFDictionaryRef primaryDNS = NULL;
1995 CFArrayRef private_resolvers;
1996 CFArrayRef service_order = NULL;
1997 CFMutableDictionaryRef service_state_dict;
1998 CFDictionaryRef setup_global_ipv4;
1999 CFDictionaryRef state_global_ipv4;
2000 SCDynamicStoreRef store;
2001
2002 _sc_debug = TRUE;
2003 _sc_log = kSCLogDestinationFile;
2004 _sc_verbose = (argc > 1) ? TRUE : FALSE;
2005
2006 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
2007
2008 // get IPv4, IPv6, and DNS entities
2009 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2010 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2011 kSCDynamicStoreDomainState,
2012 kSCCompAnyRegex,
2013 kSCEntNetIPv4);
2014 CFArrayAppendValue(patterns, pattern);
2015 CFRelease(pattern);
2016 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2017 kSCDynamicStoreDomainState,
2018 kSCCompAnyRegex,
2019 kSCEntNetIPv6);
2020 CFArrayAppendValue(patterns, pattern);
2021 CFRelease(pattern);
2022 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2023 kSCDynamicStoreDomainState,
2024 kSCCompAnyRegex,
2025 kSCEntNetDNS);
2026 CFArrayAppendValue(patterns, pattern);
2027 CFRelease(pattern);
2028 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
2029 CFRelease(patterns);
2030
2031 service_state_dict = CFDictionaryCreateMutable(NULL,
2032 0,
2033 &kCFTypeDictionaryKeyCallBacks,
2034 &kCFTypeDictionaryValueCallBacks);
2035 CFDictionaryApplyFunction(entities, split, service_state_dict);
2036 CFRelease(entities);
2037
2038 // get primary service ID
2039 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2040 kSCDynamicStoreDomainState,
2041 kSCEntNetIPv4);
2042 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
2043 CFRelease(key);
2044 if (state_global_ipv4 != NULL) {
2045 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
2046 if (primary != NULL) {
2047 CFDictionaryRef service_dict;
2048
2049 // get DNS configuration for primary service
2050 service_dict = CFDictionaryGetValue(service_state_dict, primary);
2051 if (service_dict != NULL) {
2052 primaryDNS = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
2053 }
2054 }
2055 }
2056
2057 // get serviceOrder
2058 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2059 kSCDynamicStoreDomainSetup,
2060 kSCEntNetIPv4);
2061 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
2062 CFRelease(key);
2063 if (setup_global_ipv4 != NULL) {
2064 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
2065 }
2066
2067 // get multicast resolvers
2068 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
2069 kSCDynamicStoreDomainState,
2070 kSCCompNetwork,
2071 CFSTR(kDNSServiceCompMulticastDNS));
2072 multicast_resolvers = SCDynamicStoreCopyValue(store, key);
2073 CFRelease(key);
2074
2075 // get private resolvers
2076 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
2077 kSCDynamicStoreDomainState,
2078 kSCCompNetwork,
2079 CFSTR(kDNSServiceCompPrivateDNS));
2080 private_resolvers = SCDynamicStoreCopyValue(store, key);
2081 CFRelease(key);
2082
2083 // update DNS configuration
2084 dns_configuration_init(CFBundleGetMainBundle());
2085 (void)dns_configuration_set(primaryDNS,
2086 service_state_dict,
2087 service_order,
2088 multicast_resolvers,
2089 private_resolvers);
2090
2091 // cleanup
2092 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
2093 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
2094 if (multicast_resolvers != NULL) CFRelease(multicast_resolvers);
2095 if (private_resolvers != NULL) CFRelease(private_resolvers);
2096 CFRelease(service_state_dict);
2097 CFRelease(store);
2098
2099 /* not reached */
2100 exit(0);
2101 return 0;
2102 }
2103 #endif
2104