2 * Copyright (c) 2004-2011 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
49 #include <CoreFoundation/CoreFoundation.h>
50 #include <SystemConfiguration/SystemConfiguration.h>
51 #include <SystemConfiguration/SCPrivate.h>
52 #include <SystemConfiguration/SCValidation.h>
55 #include <dnsinfo_create.h>
59 #include "dnsinfo_copy.c"
64 #ifndef kDNSServiceCompMulticastDNS
65 #define kDNSServiceCompMulticastDNS "MulticastDNS"
67 #ifndef kDNSServiceCompPrivateDNS
68 #define kDNSServiceCompPrivateDNS "PrivateDNS"
71 /* multicast DNS resolver configurations */
72 static CFNumberRef S_mdns_timeout
= NULL
;
74 /* private DNS resolver configurations */
75 static CFNumberRef S_pdns_timeout
= NULL
;
79 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
)
84 uint32_t order_val
= 0;
86 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
87 if (!isA_CFNumber(order
) ||
88 !CFNumberGetValue(order
, kCFNumberIntType
, &order_val
)) {
93 n_resolvers
= CFArrayGetCount(resolvers
);
94 for (i
= 0; i
< n_resolvers
; i
++) {
95 CFDictionaryRef match_resolver
;
97 match_resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
98 if (CFEqual(resolver
, match_resolver
)) {
104 CFMutableDictionaryRef compare
;
107 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
);
108 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
109 match
= CFEqual(resolver
, compare
);
112 CFNumberRef match_order
;
113 uint32_t match_order_val
= 0;
115 // if only the search order's are different
116 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
117 if (!isA_CFNumber(match_order
) ||
118 !CFNumberGetValue(match_order
, kCFNumberIntType
, &match_order_val
)) {
122 if (order_val
< match_order_val
) {
123 // if we should prefer this match resolver, else just skip it
124 CFArraySetValueAtIndex(resolvers
, i
, resolver
);
132 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &n_resolvers
);
133 CFDictionarySetValue(resolver
, CFSTR("*ORDER*"), order
);
136 CFArrayAppendValue(resolvers
, resolver
);
142 add_supplemental(CFMutableArrayRef resolvers
, CFDictionaryRef dns
, uint32_t defaultOrder
)
149 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
150 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
151 if (n_domains
== 0) {
155 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
156 if (orders
!= NULL
) {
157 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
163 * yes, this is a "supplemental" resolver configuration, expand
164 * the match domains and add each to the resolvers list.
166 for (i
= 0; i
< n_domains
; i
++) {
167 CFStringRef match_domain
;
168 CFNumberRef match_order
;
169 CFMutableDictionaryRef match_resolver
;
171 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
172 if (!isA_CFString(match_domain
)) {
176 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
178 // set supplemental resolver "domain"
179 if (CFStringGetLength(match_domain
) > 0) {
180 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
182 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
185 // set supplemental resolver "search_order"
186 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
187 if (isA_CFNumber(match_order
)) {
188 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
189 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
192 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
193 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
196 defaultOrder
++; // if multiple domains, maintain ordering
199 // remove keys we don't want in a supplemental resolver
200 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
201 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
202 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
203 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
205 add_resolver(resolvers
, match_resolver
);
206 CFRelease(match_resolver
);
217 add_supplemental_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
, CFArrayRef service_order
)
219 const void * keys_q
[N_QUICK
];
220 const void ** keys
= keys_q
;
224 const void * vals_q
[N_QUICK
];
225 const void ** vals
= vals_q
;
227 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
228 if (n_services
== 0) {
229 return; // if no services
232 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
233 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
234 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
237 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
239 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
240 for (i
= 0; i
< n_services
; i
++) {
241 uint32_t defaultOrder
;
243 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
245 if (!isA_CFDictionary(service
)) {
249 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
250 if (!isA_CFDictionary(dns
)) {
254 defaultOrder
= DEFAULT_SEARCH_ORDER
255 - (DEFAULT_SEARCH_ORDER
/ 2)
256 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
258 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
259 // push out services not specified in service order
260 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
263 add_supplemental(resolvers
, dns
, defaultOrder
);
266 if (keys
!= keys_q
) {
267 CFAllocatorDeallocate(NULL
, keys
);
268 CFAllocatorDeallocate(NULL
, vals
);
276 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
281 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
282 for (i
= 0; i
< n
; i
++) {
283 uint32_t defaultOrder
;
286 CFMutableDictionaryRef resolver
;
288 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
289 domain
= _SC_trimDomain(domain
);
290 if (domain
== NULL
) {
294 defaultOrder
= DEFAULT_SEARCH_ORDER
295 + (DEFAULT_SEARCH_ORDER
/ 2)
296 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
298 resolver
= CFDictionaryCreateMutable(NULL
,
300 &kCFTypeDictionaryKeyCallBacks
,
301 &kCFTypeDictionaryValueCallBacks
);
302 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
303 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
304 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
305 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
307 if (S_mdns_timeout
!= NULL
) {
308 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
310 add_resolver(resolvers
, resolver
);
320 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
325 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
326 for (i
= 0; i
< n
; i
++) {
327 uint32_t defaultOrder
;
330 CFMutableDictionaryRef resolver
;
332 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
333 domain
= _SC_trimDomain(domain
);
334 if (domain
== NULL
) {
338 defaultOrder
= DEFAULT_SEARCH_ORDER
339 - (DEFAULT_SEARCH_ORDER
/ 4)
340 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
342 resolver
= CFDictionaryCreateMutable(NULL
,
344 &kCFTypeDictionaryKeyCallBacks
,
345 &kCFTypeDictionaryValueCallBacks
);
346 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
347 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
348 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
349 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
351 if (S_pdns_timeout
!= NULL
) {
352 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
354 add_resolver(resolvers
, resolver
);
363 static CFComparisonResult
364 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
366 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
367 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
370 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
371 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
373 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
374 if (!isA_CFNumber(num1
) ||
375 !CFNumberGetValue(num1
, kCFNumberIntType
, &order1
)) {
376 order1
= DEFAULT_SEARCH_ORDER
;
379 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
380 if (!isA_CFNumber(num2
) ||
381 !CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
382 order2
= DEFAULT_SEARCH_ORDER
;
385 if (order1
== order2
) {
386 // if same "SearchOrder", retain original orderring for configurations
387 if (CFDictionaryGetValueIfPresent(dns1
, CFSTR("*ORDER*"), (const void **)&num1
) &&
388 CFDictionaryGetValueIfPresent(dns2
, CFSTR("*ORDER*"), (const void **)&num2
) &&
389 isA_CFNumber(num1
) &&
390 isA_CFNumber(num2
) &&
391 CFNumberGetValue(num1
, kCFNumberIntType
, &order1
) &&
392 CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
393 if (order1
== order2
) {
394 return kCFCompareEqualTo
;
396 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
400 return kCFCompareEqualTo
;
403 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
408 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
410 CFStringRef defaultDomainName
= NULL
;
411 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
412 CFArrayRef defaultSearchDomains
= NULL
;
413 CFIndex defaultSearchIndex
= 0;
415 CFMutableArrayRef mySearchDomains
;
416 CFMutableArrayRef mySupplemental
= NULL
;
417 CFIndex n_supplemental
;
419 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
421 if (defaultDomain
!= NULL
) {
424 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
425 if (!isA_CFNumber(num
) ||
426 !CFNumberGetValue(num
, kCFNumberIntType
, &defaultOrder
)) {
427 defaultOrder
= DEFAULT_SEARCH_ORDER
;
430 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
431 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
434 // validate the provided "search" domains or move/expand/promote the "domain" name
435 if (isA_CFArray(defaultSearchDomains
)) {
438 n_search
= CFArrayGetCount(defaultSearchDomains
);
439 for (i
= 0; i
< n_search
; i
++) {
442 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
443 search
= _SC_trimDomain(search
);
444 if (search
!= NULL
) {
445 CFArrayAppendValue(mySearchDomains
, search
);
450 defaultDomainName
= _SC_trimDomain(defaultDomainName
);
451 if (defaultDomainName
!= NULL
) {
452 CFStringRef defaultOptions
;
454 int domain_parts
= 1;
458 #define NDOTS_OPT "ndots="
459 #define NDOTS_OPT_LEN (sizeof("ndots=") - 1)
461 defaultOptions
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSOptions
);
462 if (defaultOptions
!= NULL
) {
466 options
= _SC_cfstring_to_cstring(defaultOptions
,
469 kCFStringEncodingUTF8
);
470 cp
= strstr(options
, NDOTS_OPT
);
472 ((cp
== options
) || isspace(cp
[-1])) &&
473 ((cp
[NDOTS_OPT_LEN
] != '\0') && isdigit(cp
[NDOTS_OPT_LEN
]))) {
479 val
= strtol(cp
, &end
, 10);
480 if ((*cp
!= '\0') && (cp
!= end
) && (errno
== 0) &&
481 ((*end
== '\0') || isspace(*end
)) && (val
> 0)) {
485 CFAllocatorDeallocate(NULL
, options
);
488 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
491 kCFStringEncodingUTF8
);
492 CFRelease(defaultDomainName
);
494 // count domain parts
495 for (dp
= domain
; *dp
!= '\0'; dp
++) {
501 // move "domain" to "search" list (and expand as needed)
502 i
= LOCALDOMAINPARTS
;
508 str
= CFStringCreateWithCString(NULL
,
510 kCFStringEncodingUTF8
);
511 search
= _SC_trimDomain(str
);
513 if (search
!= NULL
) {
514 CFArrayAppendValue(mySearchDomains
, search
);
518 dp
= strchr(dp
, '.') + 1;
519 } while (++i
<= (domain_parts
- ndots
));
520 CFAllocatorDeallocate(NULL
, domain
);
524 // add any supplemental "domain" names to the search list
525 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
526 if (n_supplemental
> 1) {
527 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
528 CFArraySortValues(mySupplemental
,
529 CFRangeMake(0, n_supplemental
),
530 compareBySearchOrder
,
532 supplemental
= mySupplemental
;
534 for (i
= 0; i
< n_supplemental
; i
++) {
539 CFStringRef supplementalDomain
;
540 uint32_t supplementalOrder
;
542 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
544 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
545 if (isA_CFString(options
)) {
548 if (CFEqual(options
, CFSTR("pdns"))) {
549 // don't add private resolver domains to the search list
553 range
= CFStringFind(options
, CFSTR("interface="), 0);
554 if (range
.location
!= kCFNotFound
) {
555 // don't add scoped resolver domains to the search list
560 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
561 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
562 if (supplementalDomain
== NULL
) {
566 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
567 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
568 CFRelease(supplementalDomain
);
572 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
573 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
576 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
577 if (!isA_CFNumber(num
) ||
578 !CFNumberGetValue(num
, kCFNumberIntType
, &supplementalOrder
)) {
579 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
582 if (supplementalOrder
< defaultOrder
) {
583 if (domainIndex
!= kCFNotFound
) {
584 // if supplemental domain is already in the search list
585 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
586 if (domainIndex
< defaultSearchIndex
) {
587 defaultSearchIndex
--;
590 CFArrayInsertValueAtIndex(mySearchDomains
,
593 defaultSearchIndex
++;
595 if (domainIndex
== kCFNotFound
) {
596 // add to the (end of the) search list
597 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
601 CFRelease(supplementalDomain
);
603 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
605 // update the "search" domains
606 if (CFArrayGetCount(mySearchDomains
) == 0) {
607 CFRelease(mySearchDomains
);
608 mySearchDomains
= NULL
;
611 // remove the "domain" name and "search" list
612 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
613 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
615 return mySearchDomains
;
620 add_scoped_resolvers(CFMutableArrayRef scoped
, CFDictionaryRef services
, CFArrayRef service_order
)
622 const void * keys_q
[N_QUICK
];
623 const void ** keys
= keys_q
;
627 CFMutableArrayRef order
;
628 CFMutableSetRef seen
;
630 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
631 if (n_services
== 0) {
632 return; // if no services
635 // ensure that we process all services in order
637 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
639 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
641 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
644 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
645 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
647 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
648 for (i
= 0; i
< n_services
; i
++) {
649 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
651 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
652 CFArrayAppendValue(order
, serviceID
);
656 if (keys
!= keys_q
) {
657 CFAllocatorDeallocate(NULL
, keys
);
660 // iterate over services
662 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
663 for (i
= 0; i
< n_order
; i
++) {
666 unsigned int if_index
;
667 char if_name
[IF_NAMESIZE
];
668 CFStringRef interface
;
669 CFMutableDictionaryRef newDNS
;
671 CFArrayRef searchDomains
;
672 CFDictionaryRef service
;
673 CFStringRef serviceID
;
675 serviceID
= CFArrayGetValueAtIndex(order
, i
);
676 service
= CFDictionaryGetValue(services
, serviceID
);
677 if (!isA_CFDictionary(service
)) {
682 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
683 if (!isA_CFDictionary(dns
)) {
688 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
689 if (interface
== NULL
) {
690 // if no [scoped] interface
693 if (CFSetContainsValue(seen
, interface
)) {
694 // if we've already processed this [scoped] interface
697 CFSetSetValue(seen
, interface
);
699 if ((_SC_cfstring_to_cstring(interface
,
702 kCFStringEncodingASCII
) == NULL
) ||
703 ((if_index
= if_nametoindex(if_name
)) == 0)) {
704 // if interface index not available
708 // add [scoped] resolver entry
709 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
712 searchDomains
= extract_search_domains(newDNS
, NULL
);
713 if (searchDomains
!= NULL
) {
714 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
715 CFRelease(searchDomains
);
719 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
);
720 CFDictionarySetValue(newDNS
, CFSTR("*IF_INDEX*"), num
);
724 flags
= DNS_RESOLVER_FLAGS_SCOPED
;
725 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
726 CFDictionarySetValue(newDNS
, CFSTR("*FLAGS*"), num
);
729 // remove keys we don't want in a [scoped] resolver
730 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
731 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
733 add_resolver(scoped
, newDNS
);
744 add_default_resolver(CFMutableArrayRef resolvers
,
745 CFDictionaryRef defaultResolver
,
747 CFArrayRef
*searchDomains
)
749 CFMutableDictionaryRef myDefault
;
750 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
753 if (defaultResolver
== NULL
) {
754 myDefault
= CFDictionaryCreateMutable(NULL
,
756 &kCFTypeDictionaryKeyCallBacks
,
757 &kCFTypeDictionaryValueCallBacks
);
759 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
762 // ensure that the default resolver has a search order
764 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
765 if (!isA_CFNumber(order
) ||
766 !CFNumberGetValue(order
, kCFNumberIntType
, &myOrder
)) {
767 myOrder
= DEFAULT_SEARCH_ORDER
;
768 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
769 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
774 // extract the "search" domain list for the default resolver (and
775 // any supplemental resolvers)
777 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
779 // add the default resolver
781 add_resolver(resolvers
, myDefault
);
782 CFRelease(myDefault
);
787 static dns_create_resolver_t
788 create_resolver(CFDictionaryRef dns
)
792 dns_create_resolver_t _resolver
;
795 _resolver
= _dns_resolver_create();
798 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
799 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
800 char domain
[NS_MAXDNAME
];
802 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
803 _dns_resolver_set_domain(&_resolver
, domain
);
807 // process search domains
808 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
809 if (isA_CFArray(list
)) {
811 CFIndex n
= CFArrayGetCount(list
);
813 // add "search" domains
814 for (i
= 0; i
< n
; i
++) {
815 str
= CFArrayGetValueAtIndex(list
, i
);
816 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
817 char search
[NS_MAXDNAME
];
819 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
820 _dns_resolver_add_search(&_resolver
, search
);
826 // process nameserver addresses
827 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
828 if (isA_CFArray(list
)) {
830 CFIndex n
= CFArrayGetCount(list
);
832 for (i
= 0; i
< n
; i
++) {
835 struct sockaddr_in sin
;
836 struct sockaddr_in6 sin6
;
840 str
= CFArrayGetValueAtIndex(list
, i
);
841 if (!isA_CFString(str
)) {
845 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
849 bzero(&addr
, sizeof(addr
));
850 if (inet_aton(buf
, &addr
.sin
.sin_addr
) == 1) {
851 /* if IPv4 address */
852 addr
.sin
.sin_len
= sizeof(addr
.sin
);
853 addr
.sin
.sin_family
= AF_INET
;
854 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
855 } else if (inet_pton(AF_INET6
, buf
, &addr
.sin6
.sin6_addr
) == 1) {
856 /* if IPv6 address */
859 p
= strchr(buf
, '%');
861 addr
.sin6
.sin6_scope_id
= if_nametoindex(p
+ 1);
864 addr
.sin6
.sin6_len
= sizeof(addr
.sin6
);
865 addr
.sin6
.sin6_family
= AF_INET6
;
866 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
873 // process search order
874 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
875 if (isA_CFNumber(num
)) {
878 if (CFNumberGetValue(num
, kCFNumberIntType
, &order
)) {
879 _dns_resolver_set_order(&_resolver
, order
);
884 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
885 if (isA_CFArray(list
)) {
887 CFIndex n
= CFArrayGetCount(list
);
889 for (i
= 0; i
< n
; i
++) {
892 dns_sortaddr_t sortaddr
;
894 str
= CFArrayGetValueAtIndex(list
, i
);
895 if (!isA_CFString(str
)) {
899 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
903 slash
= strchr(buf
, '/');
908 bzero(&sortaddr
, sizeof(sortaddr
));
909 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
910 /* if address not valid */
915 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
916 /* if subnet mask not valid */
923 a
= ntohl(sortaddr
.address
.s_addr
);
926 } else if (IN_CLASSB(a
)) {
928 } else if (IN_CLASSC(a
)) {
934 sortaddr
.mask
.s_addr
= htonl(m
);
937 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
942 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
943 if (isA_CFNumber(num
)) {
946 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
947 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
952 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
953 if (isA_CFNumber(num
)) {
956 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
957 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
962 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
963 if (isA_CFString(str
)) {
966 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
967 if (options
!= NULL
) {
968 _dns_resolver_set_options(&_resolver
, options
);
969 CFAllocatorDeallocate(NULL
, options
);
973 // process interface index
974 num
= CFDictionaryGetValue(dns
, CFSTR("*IF_INDEX*"));
975 if (isA_CFNumber(num
)) {
978 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
979 _dns_resolver_set_if_index(&_resolver
, if_index
);
984 num
= CFDictionaryGetValue(dns
, CFSTR("*FLAGS*"));
985 if (isA_CFNumber(num
)) {
988 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
989 _dns_resolver_set_flags(&_resolver
, flags
);
997 static __inline__ Boolean
998 isScopedDNS(CFDictionaryRef dns
)
1003 if ((dns
!= NULL
) &&
1004 CFDictionaryGetValueIfPresent(dns
, CFSTR("*FLAGS*"), (const void **)&num
) &&
1006 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1007 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1015 static CFComparisonResult
1016 compareDomain(const void *val1
, const void *val2
, void *context
)
1018 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1019 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1020 CFStringRef domain1
;
1021 CFStringRef domain2
;
1022 CFArrayRef labels1
= NULL
;
1023 CFArrayRef labels2
= NULL
;
1026 CFComparisonResult result
;
1032 // "default" domains sort before "supplemental" domains
1033 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1034 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1035 if (domain1
== NULL
) {
1036 return kCFCompareLessThan
;
1037 } else if (domain2
== NULL
) {
1038 return kCFCompareGreaterThan
;
1041 // sort non-scoped before scoped
1042 scoped1
= isScopedDNS(dns1
);
1043 scoped2
= isScopedDNS(dns2
);
1044 if (scoped1
!= scoped2
) {
1046 return kCFCompareLessThan
;
1048 return kCFCompareGreaterThan
;
1052 // must have domain names for any further comparisons
1053 if ((domain1
== NULL
) || (domain2
== NULL
)) {
1054 return kCFCompareEqualTo
;
1057 // forward (A, AAAA) domains sort before reverse (PTR) domains
1058 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1059 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1062 return kCFCompareGreaterThan
;
1064 return kCFCompareLessThan
;
1068 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1069 n1
= CFArrayGetCount(labels1
);
1071 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1072 n2
= CFArrayGetCount(labels2
);
1074 while ((n1
> 0) && (n2
> 0)) {
1075 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1076 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1078 // compare domain labels
1079 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1080 if (result
!= kCFCompareEqualTo
) {
1085 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1087 result
= kCFCompareLessThan
;
1089 } else if (n1
< n2
) {
1090 result
= kCFCompareGreaterThan
;
1094 // sort by search order
1095 result
= compareBySearchOrder(val1
, val2
, context
);
1099 if (labels1
!= NULL
) CFRelease(labels1
);
1100 if (labels2
!= NULL
) CFRelease(labels2
);
1107 dns_configuration_set(CFDictionaryRef defaultResolver
,
1108 CFDictionaryRef services
,
1109 CFArrayRef serviceOrder
,
1110 CFArrayRef multicastResolvers
,
1111 CFArrayRef privateResolvers
)
1114 CFMutableDictionaryRef myDefault
;
1115 Boolean myOrderAdded
= FALSE
;
1116 CFArrayRef mySearchDomains
= NULL
;
1117 CFIndex n_resolvers
;
1118 CFMutableArrayRef resolvers
;
1120 // establish list of resolvers
1122 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1124 // collect (and add) any "supplemental" resolver configurations
1126 add_supplemental_resolvers(resolvers
, services
, serviceOrder
);
1128 // collect (and add) any "private" resolver configurations
1130 add_private_resolvers(resolvers
, privateResolvers
);
1132 // add the "default" resolver
1134 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1136 // collect (and add) any "multicast" resolver configurations
1138 add_multicast_resolvers(resolvers
, multicastResolvers
);
1140 // collect (and add) any "scoped" resolver configurations
1142 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1146 n_resolvers
= CFArrayGetCount(resolvers
);
1147 if (n_resolvers
> 1) {
1148 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1153 for (i
= n_resolvers
; --i
> 0; ) {
1154 CFDictionaryRef resolver
;
1156 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1157 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1158 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1159 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1160 // remove empty resolver
1161 CFArrayRemoveValueAtIndex(resolvers
, i
);
1166 // update the default resolver
1168 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1170 CFArrayGetValueAtIndex(resolvers
, 0));
1171 if (mySearchDomains
!= NULL
) {
1172 // add search domains to the default resolver
1173 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1174 CFRelease(mySearchDomains
);
1176 if (myOrderAdded
&& (n_resolvers
> 1)) {
1177 CFDictionaryRef resolver
;
1179 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1180 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1181 isScopedDNS(resolver
)) {
1182 // if not a supplemental "default" resolver (a domain name is
1183 // present) or a if it's a scoped resolver
1184 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1187 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1188 CFRelease(myDefault
);
1190 // establish resolver configuration
1192 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1194 * if no default and no supplemental/scoped resolvers
1196 if (!_dns_configuration_store(NULL
)) {
1197 SCLog(TRUE
, LOG_ERR
, CFSTR("dns_configuration_set: could not store configuration"));
1200 dns_create_config_t _config
;
1203 * if default and/or supplemental/scoped resolvers are defined
1205 _config
= _dns_configuration_create();
1209 for (i
= 0; i
< n_resolvers
; i
++) {
1210 CFDictionaryRef resolver
;
1211 dns_create_resolver_t _resolver
;
1213 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1214 _resolver
= create_resolver(resolver
);
1215 _dns_configuration_add_resolver(&_config
, _resolver
);
1216 _dns_resolver_free(&_resolver
);
1219 #if !TARGET_OS_IPHONE
1220 // add flatfile resolvers
1222 _dnsinfo_flatfile_add_resolvers(&_config
);
1223 #endif // !TARGET_OS_IPHONE
1225 // save configuration
1227 if (!_dns_configuration_store(&_config
)) {
1228 SCLog(TRUE
, LOG_ERR
, CFSTR("dns_configuration_set: could not store configuration"));
1231 _dns_configuration_free(&_config
);
1234 CFRelease(resolvers
);
1239 #if !TARGET_OS_IPHONE
1240 static SCDynamicStoreRef dns_configuration_store
;
1241 static SCDynamicStoreCallBack dns_configuration_callout
;
1244 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1246 CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1248 Boolean resolvers_now
;
1249 static Boolean resolvers_save
= FALSE
;
1250 struct stat statbuf
;
1252 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1253 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1254 // if we did not (and still do not) have an "/etc/resolvers"
1255 // directory than this notification is the result of a change
1256 // to the "/etc" directory.
1259 resolvers_save
= resolvers_now
;
1261 SCLog(TRUE
, LOG_DEBUG
, CFSTR(_PATH_RESOLVER_DIR
" changed"));
1263 // fake a "DNS" change
1264 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1265 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1273 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1276 mach_port_t notify_port
;
1278 CFRunLoopSourceRef rls
;
1281 dns_configuration_store
= store
;
1282 dns_configuration_callout
= callout
;
1284 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1285 if (status
!= NOTIFY_STATUS_OK
) {
1286 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("notify_register_mach_port() failed"));
1290 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1291 if (status
!= NOTIFY_STATUS_OK
) {
1292 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("notify_monitor_file() failed"));
1293 (void)notify_cancel(notify_token
);
1297 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1299 dns_configuration_changed
,
1302 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1304 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1306 (void)notify_cancel(notify_token
);
1309 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1315 #endif // !TARGET_OS_IPHONE
1320 dns_configuration_init(CFBundleRef bundle
)
1322 CFDictionaryRef dict
;
1324 dict
= CFBundleGetInfoDictionary(bundle
);
1325 if (isA_CFDictionary(dict
)) {
1326 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1327 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1329 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1330 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1340 split(const void * key
, const void * value
, void * context
)
1342 CFArrayRef components
;
1343 CFStringRef entity_id
;
1344 CFStringRef service_id
;
1345 CFMutableDictionaryRef state_dict
;
1347 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1348 service_id
= CFArrayGetValueAtIndex(components
, 3);
1349 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1350 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1351 if (state_dict
!= NULL
) {
1352 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1354 state_dict
= CFDictionaryCreateMutable(NULL
,
1356 &kCFTypeDictionaryKeyCallBacks
,
1357 &kCFTypeDictionaryValueCallBacks
);
1360 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1361 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1362 CFStringRef interface
;
1364 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1365 if (interface
!= NULL
) {
1366 CFDictionaryRef dns
;
1367 CFMutableDictionaryRef new_dns
;
1369 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1371 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1373 new_dns
= CFDictionaryCreateMutable(NULL
,
1375 &kCFTypeDictionaryKeyCallBacks
,
1376 &kCFTypeDictionaryValueCallBacks
);
1378 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1379 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1382 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1383 CFDictionaryRef dns
;
1385 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1387 CFStringRef interface
;
1389 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1390 if (interface
!= NULL
) {
1391 CFMutableDictionaryRef new_dns
;
1393 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1394 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1395 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1398 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1401 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1404 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1407 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1408 CFRelease(state_dict
);
1409 CFRelease(components
);
1415 main(int argc
, char **argv
)
1417 CFDictionaryRef entities
;
1419 CFArrayRef multicast_resolvers
;
1420 CFStringRef pattern
;
1421 CFMutableArrayRef patterns
;
1422 CFStringRef primary
= NULL
;
1423 CFDictionaryRef primaryDNS
= NULL
;
1424 CFArrayRef private_resolvers
;
1425 CFArrayRef service_order
= NULL
;
1426 CFMutableDictionaryRef service_state_dict
;
1427 CFDictionaryRef setup_global_ipv4
;
1428 CFDictionaryRef state_global_ipv4
;
1429 SCDynamicStoreRef store
;
1432 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1434 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1436 // get IPv4, IPv6, and DNS entities
1437 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1438 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1439 kSCDynamicStoreDomainState
,
1442 CFArrayAppendValue(patterns
, pattern
);
1444 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1445 kSCDynamicStoreDomainState
,
1448 CFArrayAppendValue(patterns
, pattern
);
1450 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1451 kSCDynamicStoreDomainState
,
1454 CFArrayAppendValue(patterns
, pattern
);
1456 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1457 CFRelease(patterns
);
1459 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1461 &kCFTypeDictionaryKeyCallBacks
,
1462 &kCFTypeDictionaryValueCallBacks
);
1463 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1464 CFRelease(entities
);
1466 // get primary service ID
1467 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1468 kSCDynamicStoreDomainState
,
1470 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1472 if (state_global_ipv4
!= NULL
) {
1473 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1474 if (primary
!= NULL
) {
1475 CFDictionaryRef service_dict
;
1477 // get DNS configuration for primary service
1478 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1479 if (service_dict
!= NULL
) {
1480 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1486 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1487 kSCDynamicStoreDomainSetup
,
1489 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1491 if (setup_global_ipv4
!= NULL
) {
1492 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1495 // get multicast resolvers
1496 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1497 kSCDynamicStoreDomainState
,
1499 CFSTR(kDNSServiceCompMulticastDNS
));
1500 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1503 // get private resolvers
1504 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1505 kSCDynamicStoreDomainState
,
1507 CFSTR(kDNSServiceCompPrivateDNS
));
1508 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1511 // update DNS configuration
1512 dns_configuration_init(CFBundleGetMainBundle());
1513 dns_configuration_set(primaryDNS
,
1516 multicast_resolvers
,
1520 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1521 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1522 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
1523 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1524 CFRelease(service_state_dict
);