2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * March 22, 2004 Allan Nathanson <ajn@apple.com>
31 #include <TargetConditionals.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <arpa/nameser.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>
50 #include <CoreFoundation/CoreFoundation.h>
51 #include <SystemConfiguration/SystemConfiguration.h>
52 #include <SystemConfiguration/SCPrivate.h>
53 #include <SystemConfiguration/SCValidation.h>
55 #include "dns-configuration.h"
58 #include <dnsinfo_create.h>
62 #include "dnsinfo_copy.c"
67 #ifndef kDNSServiceCompMulticastDNS
68 #define kDNSServiceCompMulticastDNS "MulticastDNS"
70 #ifndef kDNSServiceCompPrivateDNS
71 #define kDNSServiceCompPrivateDNS "PrivateDNS"
74 #define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
75 #define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
76 #define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
78 /* multicast DNS resolver configurations */
79 static CFNumberRef S_mdns_timeout
= NULL
;
81 /* private DNS resolver configurations */
82 static CFNumberRef S_pdns_timeout
= NULL
;
86 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
)
89 CFStringRef interface
;
92 uint32_t order_val
= 0;
94 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
95 if (!isA_CFNumber(order
) ||
96 !CFNumberGetValue(order
, kCFNumberIntType
, &order_val
)) {
101 n_resolvers
= CFArrayGetCount(resolvers
);
102 for (i
= 0; i
< n_resolvers
; i
++) {
103 CFDictionaryRef match_resolver
;
105 match_resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
106 if (CFEqual(resolver
, match_resolver
)) {
112 CFMutableDictionaryRef compare
;
115 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
);
116 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
117 match
= CFEqual(resolver
, compare
);
120 CFNumberRef match_order
;
121 uint32_t match_order_val
= 0;
123 // if only the search order's are different
124 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
125 if (!isA_CFNumber(match_order
) ||
126 !CFNumberGetValue(match_order
, kCFNumberIntType
, &match_order_val
)) {
130 if (order_val
< match_order_val
) {
131 // if we should prefer this match resolver, else just skip it
132 CFArraySetValueAtIndex(resolvers
, i
, resolver
);
140 order
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_resolvers
);
141 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_ORDER_KEY
, order
);
144 interface
= CFDictionaryGetValue(resolver
, kSCPropInterfaceName
);
145 if (interface
!= NULL
) {
147 unsigned int if_index
= 0;
148 char if_name
[IF_NAMESIZE
];
152 if (_SC_cfstring_to_cstring(interface
,
155 kCFStringEncodingASCII
) != NULL
) {
156 if_index
= if_nametoindex(if_name
);
159 if ((if_index
!= 0) &&
161 // check if this is a "scoped" configuration
162 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
164 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
165 (flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)
167 // check if we should scope all queries with this configuration
168 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
169 isA_CFBoolean(val
) &&
170 CFBooleanGetValue(val
))
173 // if interface index available and it should be used
174 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
);
175 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_IF_INDEX_KEY
, num
);
180 CFArrayAppendValue(resolvers
, resolver
);
186 add_supplemental(CFMutableArrayRef resolvers
, CFDictionaryRef dns
, uint32_t defaultOrder
)
193 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
194 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
195 if (n_domains
== 0) {
199 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
200 if (orders
!= NULL
) {
201 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
207 * yes, this is a "supplemental" resolver configuration, expand
208 * the match domains and add each to the resolvers list.
210 for (i
= 0; i
< n_domains
; i
++) {
211 CFStringRef match_domain
;
212 CFNumberRef match_order
;
213 CFMutableDictionaryRef match_resolver
;
215 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
216 if (!isA_CFString(match_domain
)) {
220 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
222 // set supplemental resolver "domain"
223 if (CFStringGetLength(match_domain
) > 0) {
224 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
226 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
229 // set supplemental resolver "search_order"
230 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
231 if (isA_CFNumber(match_order
)) {
232 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
233 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
236 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
237 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
240 defaultOrder
++; // if multiple domains, maintain ordering
243 // remove keys we don't want in a supplemental resolver
244 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
245 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
246 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
247 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
249 add_resolver(resolvers
, match_resolver
);
250 CFRelease(match_resolver
);
261 add_supplemental_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
, CFArrayRef service_order
)
263 const void * keys_q
[N_QUICK
];
264 const void ** keys
= keys_q
;
268 const void * vals_q
[N_QUICK
];
269 const void ** vals
= vals_q
;
271 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
272 if (n_services
== 0) {
273 return; // if no services
276 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
277 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
278 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
281 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
283 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
284 for (i
= 0; i
< n_services
; i
++) {
285 uint32_t defaultOrder
;
287 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
289 if (!isA_CFDictionary(service
)) {
293 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
294 if (!isA_CFDictionary(dns
)) {
298 defaultOrder
= DEFAULT_SEARCH_ORDER
299 - (DEFAULT_SEARCH_ORDER
/ 2)
300 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
302 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
303 // push out services not specified in service order
304 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
307 add_supplemental(resolvers
, dns
, defaultOrder
);
310 if (keys
!= keys_q
) {
311 CFAllocatorDeallocate(NULL
, keys
);
312 CFAllocatorDeallocate(NULL
, vals
);
320 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
325 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
326 for (i
= 0; i
< n
; i
++) {
327 uint32_t defaultOrder
;
330 CFMutableDictionaryRef resolver
;
332 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
333 domain
= _SC_trimDomain(domain
);
334 if (domain
== NULL
) {
338 defaultOrder
= DEFAULT_SEARCH_ORDER
339 + (DEFAULT_SEARCH_ORDER
/ 2)
340 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
342 resolver
= CFDictionaryCreateMutable(NULL
,
344 &kCFTypeDictionaryKeyCallBacks
,
345 &kCFTypeDictionaryValueCallBacks
);
346 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
347 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
348 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
349 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
351 if (S_mdns_timeout
!= NULL
) {
352 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
354 add_resolver(resolvers
, resolver
);
364 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
369 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
370 for (i
= 0; i
< n
; i
++) {
371 uint32_t defaultOrder
;
374 CFMutableDictionaryRef resolver
;
376 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
377 domain
= _SC_trimDomain(domain
);
378 if (domain
== NULL
) {
382 defaultOrder
= DEFAULT_SEARCH_ORDER
383 - (DEFAULT_SEARCH_ORDER
/ 4)
384 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
386 resolver
= CFDictionaryCreateMutable(NULL
,
388 &kCFTypeDictionaryKeyCallBacks
,
389 &kCFTypeDictionaryValueCallBacks
);
390 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
391 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
392 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
393 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
395 if (S_pdns_timeout
!= NULL
) {
396 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
398 add_resolver(resolvers
, resolver
);
407 static CFComparisonResult
408 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
410 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
411 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
414 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
415 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
417 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
418 if (!isA_CFNumber(num1
) ||
419 !CFNumberGetValue(num1
, kCFNumberIntType
, &order1
)) {
420 order1
= DEFAULT_SEARCH_ORDER
;
423 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
424 if (!isA_CFNumber(num2
) ||
425 !CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
426 order2
= DEFAULT_SEARCH_ORDER
;
429 if (order1
== order2
) {
430 // if same "SearchOrder", retain original orderring for configurations
431 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) &&
432 CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) &&
433 isA_CFNumber(num1
) &&
434 isA_CFNumber(num2
) &&
435 CFNumberGetValue(num1
, kCFNumberIntType
, &order1
) &&
436 CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
437 if (order1
== order2
) {
438 return kCFCompareEqualTo
;
440 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
444 return kCFCompareEqualTo
;
447 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
451 static CF_RETURNS_RETAINED CFArrayRef
452 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
454 CFStringRef defaultDomainName
= NULL
;
455 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
456 CFArrayRef defaultSearchDomains
= NULL
;
457 CFIndex defaultSearchIndex
= 0;
459 CFMutableArrayRef mySearchDomains
;
460 CFMutableArrayRef mySupplemental
= NULL
;
461 CFIndex n_supplemental
;
463 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
465 if (defaultDomain
!= NULL
) {
468 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
469 if (!isA_CFNumber(num
) ||
470 !CFNumberGetValue(num
, kCFNumberIntType
, &defaultOrder
)) {
471 defaultOrder
= DEFAULT_SEARCH_ORDER
;
474 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
475 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
478 // validate the provided "search" domains or move/expand/promote the "domain" name
479 if (isA_CFArray(defaultSearchDomains
)) {
482 n_search
= CFArrayGetCount(defaultSearchDomains
);
483 for (i
= 0; i
< n_search
; i
++) {
486 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
487 search
= _SC_trimDomain(search
);
488 if (search
!= NULL
) {
489 CFArrayAppendValue(mySearchDomains
, search
);
494 defaultDomainName
= _SC_trimDomain(defaultDomainName
);
495 if (defaultDomainName
!= NULL
) {
496 CFStringRef defaultOptions
;
498 int domain_parts
= 1;
502 #define NDOTS_OPT "ndots="
503 #define NDOTS_OPT_LEN (sizeof("ndots=") - 1)
505 defaultOptions
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSOptions
);
506 if (defaultOptions
!= NULL
) {
510 options
= _SC_cfstring_to_cstring(defaultOptions
,
513 kCFStringEncodingUTF8
);
514 cp
= strstr(options
, NDOTS_OPT
);
516 ((cp
== options
) || isspace(cp
[-1])) &&
517 ((cp
[NDOTS_OPT_LEN
] != '\0') && isdigit(cp
[NDOTS_OPT_LEN
]))) {
523 val
= strtol(cp
, &end
, 10);
524 if ((*cp
!= '\0') && (cp
!= end
) && (errno
== 0) &&
525 ((*end
== '\0') || isspace(*end
)) && (val
> 0)) {
529 CFAllocatorDeallocate(NULL
, options
);
532 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
535 kCFStringEncodingUTF8
);
536 CFRelease(defaultDomainName
);
538 // count domain parts
539 for (dp
= domain
; *dp
!= '\0'; dp
++) {
545 // move "domain" to "search" list (and expand as needed)
546 i
= LOCALDOMAINPARTS
;
552 str
= CFStringCreateWithCString(NULL
,
554 kCFStringEncodingUTF8
);
555 search
= _SC_trimDomain(str
);
557 if (search
!= NULL
) {
558 CFArrayAppendValue(mySearchDomains
, search
);
562 dp
= strchr(dp
, '.') + 1;
563 } while (++i
<= (domain_parts
- ndots
));
564 CFAllocatorDeallocate(NULL
, domain
);
568 // add any supplemental "domain" names to the search list
569 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
570 if (n_supplemental
> 1) {
571 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
572 CFArraySortValues(mySupplemental
,
573 CFRangeMake(0, n_supplemental
),
574 compareBySearchOrder
,
576 supplemental
= mySupplemental
;
578 for (i
= 0; i
< n_supplemental
; i
++) {
583 CFStringRef supplementalDomain
;
584 uint32_t supplementalOrder
;
586 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
588 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
589 if (isA_CFString(options
)) {
592 if (CFEqual(options
, CFSTR("pdns"))) {
593 // don't add private resolver domains to the search list
597 range
= CFStringFind(options
, CFSTR("interface="), 0);
598 if (range
.location
!= kCFNotFound
) {
599 // don't add scoped resolver domains to the search list
604 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
605 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
606 if (supplementalDomain
== NULL
) {
610 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
611 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
612 CFRelease(supplementalDomain
);
616 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
617 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
620 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
621 if (!isA_CFNumber(num
) ||
622 !CFNumberGetValue(num
, kCFNumberIntType
, &supplementalOrder
)) {
623 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
626 if (supplementalOrder
< defaultOrder
) {
627 if (domainIndex
!= kCFNotFound
) {
628 // if supplemental domain is already in the search list
629 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
630 if (domainIndex
< defaultSearchIndex
) {
631 defaultSearchIndex
--;
634 CFArrayInsertValueAtIndex(mySearchDomains
,
637 defaultSearchIndex
++;
639 if (domainIndex
== kCFNotFound
) {
640 // add to the (end of the) search list
641 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
645 CFRelease(supplementalDomain
);
647 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
649 // update the "search" domains
650 if (CFArrayGetCount(mySearchDomains
) == 0) {
651 CFRelease(mySearchDomains
);
652 mySearchDomains
= NULL
;
655 // remove the "domain" name and "search" list
656 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
657 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
659 return mySearchDomains
;
664 add_scoped_resolvers(CFMutableArrayRef scoped
, CFDictionaryRef services
, CFArrayRef service_order
)
666 const void * keys_q
[N_QUICK
];
667 const void ** keys
= keys_q
;
671 CFMutableArrayRef order
;
672 CFMutableSetRef seen
;
674 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
675 if (n_services
== 0) {
676 return; // if no services
679 // ensure that we process all services in order
681 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
683 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
685 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
688 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
689 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
691 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
692 for (i
= 0; i
< n_services
; i
++) {
693 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
695 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
696 CFArrayAppendValue(order
, serviceID
);
700 if (keys
!= keys_q
) {
701 CFAllocatorDeallocate(NULL
, keys
);
704 // iterate over services
706 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
707 for (i
= 0; i
< n_order
; i
++) {
710 char if_name
[IF_NAMESIZE
];
711 CFStringRef interface
;
712 CFMutableDictionaryRef newDNS
;
714 CFArrayRef searchDomains
;
715 CFDictionaryRef service
;
716 CFStringRef serviceID
;
718 serviceID
= CFArrayGetValueAtIndex(order
, i
);
719 service
= CFDictionaryGetValue(services
, serviceID
);
720 if (!isA_CFDictionary(service
)) {
725 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
726 if (!isA_CFDictionary(dns
)) {
731 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
732 if (interface
== NULL
) {
733 // if no [scoped] interface
736 if (CFSetContainsValue(seen
, interface
)) {
737 // if we've already processed this [scoped] interface
740 CFSetSetValue(seen
, interface
);
742 if ((_SC_cfstring_to_cstring(interface
,
745 kCFStringEncodingASCII
) == NULL
) ||
746 (if_nametoindex(if_name
) == 0)) {
747 // if interface index not available
751 // add [scoped] resolver entry
752 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
755 searchDomains
= extract_search_domains(newDNS
, NULL
);
756 if (searchDomains
!= NULL
) {
757 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
758 CFRelease(searchDomains
);
761 // set "scoped" configuration flag(s)
762 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
763 !isA_CFNumber(num
) ||
764 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
767 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
768 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
769 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
772 // remove keys we don't want in a [scoped] resolver
773 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
774 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
776 add_resolver(scoped
, newDNS
);
787 add_default_resolver(CFMutableArrayRef resolvers
,
788 CFDictionaryRef defaultResolver
,
790 CFArrayRef
*searchDomains
)
792 CFMutableDictionaryRef myDefault
;
793 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
796 if (defaultResolver
== NULL
) {
797 myDefault
= CFDictionaryCreateMutable(NULL
,
799 &kCFTypeDictionaryKeyCallBacks
,
800 &kCFTypeDictionaryValueCallBacks
);
802 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
805 // ensure that the default resolver has a search order
807 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
808 if (!isA_CFNumber(order
) ||
809 !CFNumberGetValue(order
, kCFNumberIntType
, &myOrder
)) {
810 myOrder
= DEFAULT_SEARCH_ORDER
;
811 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
812 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
817 // extract the "search" domain list for the default resolver (and
818 // any supplemental resolvers)
820 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
822 // add the default resolver
824 add_resolver(resolvers
, myDefault
);
825 CFRelease(myDefault
);
833 * Connection Required == 1
837 rankReachability(SCNetworkReachabilityFlags flags
)
841 if (flags
& kSCNetworkReachabilityFlagsReachable
) rank
= 2;
842 if (flags
& kSCNetworkReachabilityFlagsConnectionRequired
) rank
= 1;
847 static dns_create_resolver_t
848 create_resolver(CFDictionaryRef dns
)
852 dns_create_resolver_t _resolver
;
854 CFMutableArrayRef serverAddresses
= NULL
;
855 CFStringRef targetInterface
= NULL
;
856 unsigned int targetInterfaceIndex
= 0;
858 _resolver
= _dns_resolver_create();
861 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
862 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
863 char domain
[NS_MAXDNAME
];
865 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
866 _dns_resolver_set_domain(&_resolver
, domain
);
870 // process search domains
871 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
872 if (isA_CFArray(list
)) {
874 CFIndex n
= CFArrayGetCount(list
);
876 // add "search" domains
877 for (i
= 0; i
< n
; i
++) {
878 str
= CFArrayGetValueAtIndex(list
, i
);
879 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
880 char search
[NS_MAXDNAME
];
882 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
883 _dns_resolver_add_search(&_resolver
, search
);
889 // process interface index
890 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
891 if (isA_CFNumber(num
)) {
894 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
895 char if_name
[IFNAMSIZ
];
897 _dns_resolver_set_if_index(&_resolver
, if_index
);
899 if ((if_index
!= 0) &&
900 (if_indextoname(if_index
, if_name
) != NULL
)) {
901 targetInterface
= CFStringCreateWithCString(NULL
,
903 kCFStringEncodingASCII
);
904 targetInterfaceIndex
= if_index
;
909 // process nameserver addresses
910 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
911 if (isA_CFArray(list
)) {
913 CFIndex n
= CFArrayGetCount(list
);
915 serverAddresses
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
917 for (i
= 0; i
< n
; i
++) {
920 struct sockaddr_in sin
;
921 struct sockaddr_in6 sin6
;
924 CFDataRef serverAddress
;
926 str
= CFArrayGetValueAtIndex(list
, i
);
927 if (!isA_CFString(str
)) {
931 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
935 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
939 if ((addr
.sa
.sa_family
== AF_INET6
) &&
940 (IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) ||
941 IN6_IS_ADDR_MC_LINKLOCAL(&addr
.sin6
.sin6_addr
)) &&
942 (addr
.sin6
.sin6_scope_id
== 0) &&
943 (targetInterfaceIndex
!= 0)) {
944 // for link local [IPv6] addresses, if the scope id is not
945 // set then we should use the interface associated with the
946 // resolver configuration
947 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
950 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
952 serverAddress
= CFDataCreate(NULL
, (const void *)&addr
.sa
, addr
.sa
.sa_len
);
953 CFArrayAppendValue(serverAddresses
, serverAddress
);
954 CFRelease(serverAddress
);
958 // process search order
959 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
960 if (isA_CFNumber(num
)) {
963 if (CFNumberGetValue(num
, kCFNumberIntType
, &order
)) {
964 _dns_resolver_set_order(&_resolver
, order
);
969 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
970 if (isA_CFArray(list
)) {
972 CFIndex n
= CFArrayGetCount(list
);
974 for (i
= 0; i
< n
; i
++) {
977 dns_sortaddr_t sortaddr
;
979 str
= CFArrayGetValueAtIndex(list
, i
);
980 if (!isA_CFString(str
)) {
984 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
988 slash
= strchr(buf
, '/');
993 bzero(&sortaddr
, sizeof(sortaddr
));
994 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
995 /* if address not valid */
1000 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1001 /* if subnet mask not valid */
1008 a
= ntohl(sortaddr
.address
.s_addr
);
1011 } else if (IN_CLASSB(a
)) {
1013 } else if (IN_CLASSC(a
)) {
1019 sortaddr
.mask
.s_addr
= htonl(m
);
1022 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1027 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1028 if (isA_CFNumber(num
)) {
1031 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1032 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1037 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1038 if (isA_CFNumber(num
)) {
1041 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1042 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1047 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1048 if (isA_CFString(str
)) {
1051 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1052 if (options
!= NULL
) {
1053 _dns_resolver_set_options(&_resolver
, options
);
1054 CFAllocatorDeallocate(NULL
, options
);
1059 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1060 if (isA_CFNumber(num
)) {
1063 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1064 _dns_resolver_set_flags(&_resolver
, flags
);
1068 if (serverAddresses
!= NULL
) {
1069 SCNetworkReachabilityFlags flags
= kSCNetworkReachabilityFlagsReachable
;
1071 CFIndex n
= CFArrayGetCount(serverAddresses
);
1072 CFMutableDictionaryRef targetOptions
;
1074 targetOptions
= CFDictionaryCreateMutable(NULL
,
1076 &kCFTypeDictionaryKeyCallBacks
,
1077 &kCFTypeDictionaryValueCallBacks
);
1078 CFDictionarySetValue(targetOptions
,
1079 kSCNetworkReachabilityOptionServerBypass
,
1081 if (targetInterface
!= NULL
) {
1082 CFDictionarySetValue(targetOptions
,
1083 kSCNetworkReachabilityOptionInterface
,
1087 for (i
= 0; i
< n
; i
++) {
1088 SCNetworkReachabilityFlags ns_flags
;
1090 CFDataRef serverAddress
;
1091 SCNetworkReachabilityRef target
;
1093 serverAddress
= CFArrayGetValueAtIndex(serverAddresses
, i
);
1094 CFDictionarySetValue(targetOptions
,
1095 kSCNetworkReachabilityOptionRemoteAddress
,
1097 target
= SCNetworkReachabilityCreateWithOptions(NULL
, targetOptions
);
1098 if (target
== NULL
) {
1099 CFDictionaryRemoveValue(targetOptions
, kSCNetworkReachabilityOptionInterface
);
1100 target
= SCNetworkReachabilityCreateWithOptions(NULL
, targetOptions
);
1101 if (target
!= NULL
) {
1102 // if interface name not (no longer) valid
1108 // address not valid?
1109 SCLog(TRUE
, LOG_ERR
,
1110 CFSTR("create_resolver SCNetworkReachabilityCreateWithOptions() failed:\n options = %@"),
1115 ok
= SCNetworkReachabilityGetFlags(target
, &ns_flags
);
1122 (rankReachability(ns_flags
) < rankReachability(flags
))) {
1123 /* return the worst case result */
1128 _dns_resolver_set_reach_flags(&_resolver
, flags
);
1130 CFRelease(targetOptions
);
1131 CFRelease(serverAddresses
);
1134 if (targetInterface
!= NULL
) {
1135 CFRelease(targetInterface
);
1142 static __inline__ Boolean
1143 isScopedConfiguration(CFDictionaryRef dns
)
1148 if ((dns
!= NULL
) &&
1149 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1151 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1152 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1160 static CFComparisonResult
1161 compareDomain(const void *val1
, const void *val2
, void *context
)
1163 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1164 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1165 CFStringRef domain1
;
1166 CFStringRef domain2
;
1167 CFArrayRef labels1
= NULL
;
1168 CFArrayRef labels2
= NULL
;
1171 CFComparisonResult result
;
1177 // "default" domains sort before "supplemental" domains
1178 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1179 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1180 if (domain1
== NULL
) {
1181 return kCFCompareLessThan
;
1182 } else if (domain2
== NULL
) {
1183 return kCFCompareGreaterThan
;
1186 // sort non-scoped before scoped
1187 scoped1
= isScopedConfiguration(dns1
);
1188 scoped2
= isScopedConfiguration(dns2
);
1189 if (scoped1
!= scoped2
) {
1191 return kCFCompareLessThan
;
1193 return kCFCompareGreaterThan
;
1197 // must have domain names for any further comparisons
1198 if ((domain1
== NULL
) || (domain2
== NULL
)) {
1199 return kCFCompareEqualTo
;
1202 // forward (A, AAAA) domains sort before reverse (PTR) domains
1203 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1204 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1207 return kCFCompareGreaterThan
;
1209 return kCFCompareLessThan
;
1213 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1214 n1
= CFArrayGetCount(labels1
);
1216 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1217 n2
= CFArrayGetCount(labels2
);
1219 while ((n1
> 0) && (n2
> 0)) {
1220 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1221 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1223 // compare domain labels
1224 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1225 if (result
!= kCFCompareEqualTo
) {
1230 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1232 result
= kCFCompareLessThan
;
1234 } else if (n1
< n2
) {
1235 result
= kCFCompareGreaterThan
;
1239 // sort by search order
1240 result
= compareBySearchOrder(val1
, val2
, context
);
1244 if (labels1
!= NULL
) CFRelease(labels1
);
1245 if (labels2
!= NULL
) CFRelease(labels2
);
1252 dns_configuration_set(CFDictionaryRef defaultResolver
,
1253 CFDictionaryRef services
,
1254 CFArrayRef serviceOrder
,
1255 CFArrayRef multicastResolvers
,
1256 CFArrayRef privateResolvers
)
1258 dns_create_config_t _config
;
1259 Boolean changed
= FALSE
;
1261 CFMutableDictionaryRef myDefault
;
1262 Boolean myOrderAdded
= FALSE
;
1263 CFArrayRef mySearchDomains
= NULL
;
1264 CFIndex n_resolvers
;
1265 CFMutableArrayRef resolvers
;
1266 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1267 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1269 // establish list of resolvers
1271 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1273 // collect (and add) any "supplemental" resolver configurations
1275 add_supplemental_resolvers(resolvers
, services
, serviceOrder
);
1277 // collect (and add) any "private" resolver configurations
1279 add_private_resolvers(resolvers
, privateResolvers
);
1281 // add the "default" resolver
1283 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1285 // collect (and add) any "multicast" resolver configurations
1287 add_multicast_resolvers(resolvers
, multicastResolvers
);
1289 // collect (and add) any "scoped" resolver configurations
1291 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1295 n_resolvers
= CFArrayGetCount(resolvers
);
1296 if (n_resolvers
> 1) {
1297 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1302 for (i
= n_resolvers
; --i
> 0; ) {
1303 CFDictionaryRef resolver
;
1305 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1306 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1307 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1308 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1309 // remove empty resolver
1310 CFArrayRemoveValueAtIndex(resolvers
, i
);
1315 // update the default resolver
1317 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1319 CFArrayGetValueAtIndex(resolvers
, 0));
1320 if (mySearchDomains
!= NULL
) {
1321 // add search domains to the default resolver
1322 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1323 CFRelease(mySearchDomains
);
1325 if (myOrderAdded
&& (n_resolvers
> 1)) {
1326 CFDictionaryRef resolver
;
1328 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1329 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1330 isScopedConfiguration(resolver
)) {
1331 // if not a supplemental "default" resolver (a domain name is
1332 // present) or if it's a scoped configuration
1333 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1336 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1337 CFRelease(myDefault
);
1339 // establish resolver configuration
1341 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1343 * if no default and no supplemental/scoped resolvers
1348 * if default and/or supplemental/scoped resolvers are defined
1350 _config
= _dns_configuration_create();
1354 for (i
= 0; i
< n_resolvers
; i
++) {
1355 CFDictionaryRef resolver
;
1356 dns_create_resolver_t _resolver
;
1358 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1359 _resolver
= create_resolver(resolver
);
1360 _dns_configuration_add_resolver(&_config
, _resolver
);
1361 _dns_resolver_free(&_resolver
);
1364 #if !TARGET_OS_IPHONE
1365 // add flatfile resolvers
1367 _dnsinfo_flatfile_add_resolvers(&_config
);
1368 #endif // !TARGET_OS_IPHONE
1371 // check if the configuration changed
1372 _dns_configuration_signature(&_config
, signature
, sizeof(signature
));
1373 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1376 bcopy(signature
, signature_last
, sizeof(signature
));
1378 // save configuration
1379 if (!_dns_configuration_store(&_config
)) {
1380 SCLog(TRUE
, LOG_ERR
, CFSTR("dns_configuration_set: could not store configuration"));
1382 if (_config
!= NULL
) _dns_configuration_free(&_config
);
1384 CFRelease(resolvers
);
1389 #if !TARGET_OS_IPHONE
1390 static SCDynamicStoreRef dns_configuration_store
;
1391 static SCDynamicStoreCallBack dns_configuration_callout
;
1394 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1396 CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1398 Boolean resolvers_now
;
1399 static Boolean resolvers_save
= FALSE
;
1400 struct stat statbuf
;
1402 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1403 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1404 // if we did not (and still do not) have an "/etc/resolvers"
1405 // directory than this notification is the result of a change
1406 // to the "/etc" directory.
1409 resolvers_save
= resolvers_now
;
1411 SCLog(TRUE
, LOG_DEBUG
, CFSTR(_PATH_RESOLVER_DIR
" changed"));
1413 // fake a "DNS" change
1414 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1415 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1423 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1426 mach_port_t notify_port
;
1428 CFRunLoopSourceRef rls
;
1431 dns_configuration_store
= store
;
1432 dns_configuration_callout
= callout
;
1434 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1435 if (status
!= NOTIFY_STATUS_OK
) {
1436 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("notify_register_mach_port() failed"));
1440 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1441 if (status
!= NOTIFY_STATUS_OK
) {
1442 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("notify_monitor_file() failed"));
1443 (void)notify_cancel(notify_token
);
1447 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1449 dns_configuration_changed
,
1452 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1454 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1456 (void)notify_cancel(notify_token
);
1459 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1465 #endif // !TARGET_OS_IPHONE
1470 dns_configuration_init(CFBundleRef bundle
)
1472 CFDictionaryRef dict
;
1474 dict
= CFBundleGetInfoDictionary(bundle
);
1475 if (isA_CFDictionary(dict
)) {
1476 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1477 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1479 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1480 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1488 #pragma mark Standalone test code
1494 split(const void * key
, const void * value
, void * context
)
1496 CFArrayRef components
;
1497 CFStringRef entity_id
;
1498 CFStringRef service_id
;
1499 CFMutableDictionaryRef state_dict
;
1501 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1502 service_id
= CFArrayGetValueAtIndex(components
, 3);
1503 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1504 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1505 if (state_dict
!= NULL
) {
1506 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1508 state_dict
= CFDictionaryCreateMutable(NULL
,
1510 &kCFTypeDictionaryKeyCallBacks
,
1511 &kCFTypeDictionaryValueCallBacks
);
1514 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1515 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1516 CFStringRef interface
;
1518 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1519 if (interface
!= NULL
) {
1520 CFDictionaryRef dns
;
1521 CFMutableDictionaryRef new_dns
;
1523 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1525 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1527 new_dns
= CFDictionaryCreateMutable(NULL
,
1529 &kCFTypeDictionaryKeyCallBacks
,
1530 &kCFTypeDictionaryValueCallBacks
);
1532 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1533 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1536 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1537 CFDictionaryRef dns
;
1539 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1541 CFStringRef interface
;
1543 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1544 if (interface
!= NULL
) {
1545 CFMutableDictionaryRef new_dns
;
1547 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1548 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1549 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1552 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1555 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1558 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1561 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1562 CFRelease(state_dict
);
1563 CFRelease(components
);
1569 main(int argc
, char **argv
)
1571 CFDictionaryRef entities
;
1573 CFArrayRef multicast_resolvers
;
1574 CFStringRef pattern
;
1575 CFMutableArrayRef patterns
;
1576 CFStringRef primary
= NULL
;
1577 CFDictionaryRef primaryDNS
= NULL
;
1578 CFArrayRef private_resolvers
;
1579 CFArrayRef service_order
= NULL
;
1580 CFMutableDictionaryRef service_state_dict
;
1581 CFDictionaryRef setup_global_ipv4
;
1582 CFDictionaryRef state_global_ipv4
;
1583 SCDynamicStoreRef store
;
1586 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1588 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1590 // get IPv4, IPv6, and DNS entities
1591 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1592 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1593 kSCDynamicStoreDomainState
,
1596 CFArrayAppendValue(patterns
, pattern
);
1598 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1599 kSCDynamicStoreDomainState
,
1602 CFArrayAppendValue(patterns
, pattern
);
1604 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1605 kSCDynamicStoreDomainState
,
1608 CFArrayAppendValue(patterns
, pattern
);
1610 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1611 CFRelease(patterns
);
1613 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1615 &kCFTypeDictionaryKeyCallBacks
,
1616 &kCFTypeDictionaryValueCallBacks
);
1617 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1618 CFRelease(entities
);
1620 // get primary service ID
1621 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1622 kSCDynamicStoreDomainState
,
1624 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1626 if (state_global_ipv4
!= NULL
) {
1627 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1628 if (primary
!= NULL
) {
1629 CFDictionaryRef service_dict
;
1631 // get DNS configuration for primary service
1632 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1633 if (service_dict
!= NULL
) {
1634 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1640 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1641 kSCDynamicStoreDomainSetup
,
1643 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1645 if (setup_global_ipv4
!= NULL
) {
1646 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1649 // get multicast resolvers
1650 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1651 kSCDynamicStoreDomainState
,
1653 CFSTR(kDNSServiceCompMulticastDNS
));
1654 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1657 // get private resolvers
1658 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1659 kSCDynamicStoreDomainState
,
1661 CFSTR(kDNSServiceCompPrivateDNS
));
1662 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1665 // update DNS configuration
1666 dns_configuration_init(CFBundleGetMainBundle());
1667 (void)dns_configuration_set(primaryDNS
,
1670 multicast_resolvers
,
1674 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1675 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1676 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
1677 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1678 CFRelease(service_state_dict
);