2 * Copyright (c) 2004-2013 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>
54 #include "ip_plugin.h"
56 #include "dns-configuration.h"
59 #include "dnsinfo_create.h"
60 #include "dnsinfo_server.h"
64 #include "dnsinfo_copy.c"
65 #include "dnsinfo_internal.h"
67 #define DNS_CONFIGURATION_DEBUG
71 #ifndef kDNSServiceCompMulticastDNS
72 #define kDNSServiceCompMulticastDNS "MulticastDNS"
74 #ifndef kDNSServiceCompPrivateDNS
75 #define kDNSServiceCompPrivateDNS "PrivateDNS"
78 #define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
79 #define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
80 #define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
82 /* multicast DNS resolver configurations */
83 static CFNumberRef S_mdns_timeout
= NULL
;
85 /* private DNS resolver configurations */
86 static CFNumberRef S_pdns_timeout
= NULL
;
90 #pragma mark DNS resolver flags
93 static __inline__ boolean_t
94 dns_resolver_flags_all_queries(uint32_t query_flags
)
96 return ((query_flags
& DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
) == DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
);
103 add_dns_query_flags(const void *key
, const void *value
, void *context
)
105 CFDictionaryRef service
= value
;
106 uint32_t *query_flags
= context
;
109 // check if the service has v4 or v6 configured
111 if ((*query_flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
) == 0) {
112 CFDictionaryRef v4_dict
;
114 v4_dict
= CFDictionaryGetValue(service
, kSCEntNetIPv4
);
115 if (v4_dict
!= NULL
) {
116 CFDictionaryRef v4_service
;
118 v4_service
= CFDictionaryGetValue(v4_dict
, kIPv4DictService
);
119 if (isA_CFDictionary(v4_service
)) {
121 CFBooleanRef is_null
;
123 is_null
= CFDictionaryGetValue(v4_service
, kIsNULL
);
124 if_addrs
= CFDictionaryGetValue(v4_service
, kSCPropNetIPv4Addresses
);
125 if (isA_CFBoolean(is_null
) != NULL
&& CFBooleanGetValue(is_null
)) {
126 // ignore this service
128 else if (isA_CFArray(if_addrs
) != NULL
) {
132 count
= CFArrayGetCount(if_addrs
);
133 for (i
= 0; i
< count
; i
++) {
135 struct in_addr v4_addr
;
137 if_addr
= CFArrayGetValueAtIndex(if_addrs
, i
);
138 if (isA_CFString(if_addr
) == NULL
) {
142 cfstring_to_ip(if_addr
, &v4_addr
);
143 if (!IN_LINKLOCAL(ntohl(v4_addr
.s_addr
))) {
144 // set the request v4 dns record bit
145 *query_flags
|= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
;
154 if ((*query_flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
) == 0) {
155 CFDictionaryRef v6_dict
;
157 v6_dict
= CFDictionaryGetValue(service
, kSCEntNetIPv6
);
158 if (isA_CFDictionary(v6_dict
) != NULL
) {
159 CFArrayRef if_addrs6
;
160 CFBooleanRef is_null
;
162 is_null
= CFDictionaryGetValue(v6_dict
, kIsNULL
);
163 if_addrs6
= CFDictionaryGetValue(v6_dict
, kSCPropNetIPv6Addresses
);
164 if (isA_CFBoolean(is_null
) != NULL
&& CFBooleanGetValue(is_null
)) {
165 // ignore this service
167 else if (isA_CFArray(if_addrs6
) != NULL
) {
171 count
= CFArrayGetCount(if_addrs6
);
172 for (i
= 0; i
< count
; i
++) {
173 CFStringRef if_addr6
;
174 struct in6_addr v6_addr
;
176 if_addr6
= CFArrayGetValueAtIndex(if_addrs6
, i
);
177 if (isA_CFString(if_addr6
) == NULL
) {
181 cfstring_to_ip6(if_addr6
, &v6_addr
);
182 if (!IN6_IS_ADDR_LINKLOCAL(&v6_addr
)
183 && !IN6_IS_ADDR_MC_LINKLOCAL(&v6_addr
)) {
184 // set the request v6 dns record bit
185 *query_flags
|= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
;
199 #pragma mark DNS resolver configuration
203 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
)
206 CFStringRef interface
;
209 uint32_t order_val
= 0;
211 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
212 if (!isA_CFNumber(order
) ||
213 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &order_val
)) {
218 n_resolvers
= CFArrayGetCount(resolvers
);
219 for (i
= 0; i
< n_resolvers
; i
++) {
220 CFDictionaryRef match_resolver
;
222 match_resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
223 if (CFEqual(resolver
, match_resolver
)) {
229 CFMutableDictionaryRef compare
;
232 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
);
233 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
234 match
= CFEqual(resolver
, compare
);
237 CFNumberRef match_order
;
238 uint32_t match_order_val
= 0;
240 // if only the search order's are different
241 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
242 if (!isA_CFNumber(match_order
) ||
243 !CFNumberGetValue(match_order
, kCFNumberSInt32Type
, &match_order_val
)) {
247 if (order_val
< match_order_val
) {
248 // if we should prefer this match resolver, else just skip it
249 CFArraySetValueAtIndex(resolvers
, i
, resolver
);
257 order
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_resolvers
);
258 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_ORDER_KEY
, order
);
261 interface
= CFDictionaryGetValue(resolver
, kSCPropInterfaceName
);
262 if ((interface
!= NULL
) && !CFEqual(interface
, CFSTR("*"))) {
264 unsigned int if_index
= 0;
265 char if_name
[IF_NAMESIZE
];
269 if (_SC_cfstring_to_cstring(interface
,
272 kCFStringEncodingASCII
) != NULL
) {
273 if_index
= if_nametoindex(if_name
);
276 if ((if_index
!= 0) &&
278 // check if this is a "scoped" configuration
279 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
281 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
282 (flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)
284 // check if we should scope all queries with this configuration
285 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
286 isA_CFBoolean(val
) &&
287 CFBooleanGetValue(val
))
290 // if interface index available and it should be used
291 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
);
292 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_IF_INDEX_KEY
, num
);
297 CFArrayAppendValue(resolvers
, resolver
);
303 add_supplemental(CFMutableArrayRef resolvers
, CFDictionaryRef dns
, uint32_t defaultOrder
)
310 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
311 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
312 if (n_domains
== 0) {
316 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
317 if (orders
!= NULL
) {
318 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
324 * yes, this is a "supplemental" resolver configuration, expand
325 * the match domains and add each to the resolvers list.
327 for (i
= 0; i
< n_domains
; i
++) {
328 CFStringRef match_domain
;
329 CFNumberRef match_order
;
330 CFMutableDictionaryRef match_resolver
;
332 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
333 if (!isA_CFString(match_domain
)) {
337 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
339 // set supplemental resolver "domain"
340 if (CFStringGetLength(match_domain
) > 0) {
341 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
343 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
346 // set supplemental resolver "search_order"
347 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
348 if (isA_CFNumber(match_order
)) {
349 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
350 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
353 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
354 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
357 defaultOrder
++; // if multiple domains, maintain ordering
360 // remove keys we don't want in a supplemental resolver
361 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
362 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
363 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
364 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
366 add_resolver(resolvers
, match_resolver
);
367 CFRelease(match_resolver
);
378 add_supplemental_resolvers(CFMutableArrayRef resolvers
,
379 CFDictionaryRef services
,
380 CFArrayRef service_order
,
381 CFStringRef scoped_interface
,
382 CFDictionaryRef scoped_service
)
384 const void * keys_q
[N_QUICK
];
385 const void ** keys
= keys_q
;
389 const void * vals_q
[N_QUICK
];
390 const void ** vals
= vals_q
;
392 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
393 if (n_services
== 0) {
394 return; // if no services
397 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
398 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
399 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
402 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
404 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
405 for (i
= 0; i
< n_services
; i
++) {
406 uint32_t defaultOrder
;
408 CFStringRef interface
;
409 uint32_t interface_flags
;
410 CFMutableDictionaryRef newDNS
= NULL
;
411 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
413 if (!isA_CFDictionary(service
)) {
417 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
418 dns
= isA_CFDictionary(dns
);
423 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
425 if (scoped_interface
!= NULL
) {
427 // we only want to add split/supplemental configurations
428 // for queries scoped to an interface if they are NOT
429 // associated with a "real" service
431 if (CFDictionaryContainsKey(service
, kSCEntNetIPv4
) ||
432 CFDictionaryContainsKey(service
, kSCEntNetIPv6
)) {
437 // in addition, we don't want to add split/supplemental
438 // configurations for queries scoped to an interface if
439 // the configuration does not apply to all interfaces and
440 // the configuration is explicitly NOT for this interface
442 if (!_SC_CFEqual(interface
, CFSTR("*")) &&
443 !_SC_CFEqual(interface
, scoped_interface
)) {
448 // lastly, check if A/AAAA queries should be issued (based
449 // on the IP[v6] addresses). If we would not be issuing a
450 // query then don't bother adding the configuration.
453 add_dns_query_flags(NULL
, scoped_service
, &interface_flags
);
454 if (interface_flags
== 0) {
459 defaultOrder
= DEFAULT_SEARCH_ORDER
460 - (DEFAULT_SEARCH_ORDER
/ 2)
461 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
463 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
464 // push out services not specified in service order
465 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
469 * Ensure that we have the correct InterfaceName in the DNS configuration
471 * scoped_interface [supplemental] interface DNS interface
472 * ================ ======================== =================
473 * NULL NULL NULL (No change)
477 * en0 en0 "en0" (now mutable)
480 if ((scoped_interface
== NULL
) && (interface
== NULL
)) {
481 newDNS
= (CFMutableDictionaryRef
)CFRetain(dns
);
483 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
484 if (scoped_interface
!= NULL
) {
485 CFDictionarySetValue(newDNS
, kSCPropInterfaceName
, scoped_interface
);
487 CFDictionaryRemoveValue(newDNS
, kSCPropInterfaceName
);
491 if (scoped_interface
!= NULL
) {
495 // set "scoped" configuration flag(s)
496 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
497 !isA_CFNumber(num
) ||
498 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
501 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
503 // add A/AAAA query flag(s)
504 flags
|= interface_flags
;
506 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
507 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
511 // add [scoped] resolver entry
512 add_supplemental(resolvers
, newDNS
, defaultOrder
);
516 if (keys
!= keys_q
) {
517 CFAllocatorDeallocate(NULL
, keys
);
518 CFAllocatorDeallocate(NULL
, vals
);
526 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
531 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
532 for (i
= 0; i
< n
; i
++) {
533 uint32_t defaultOrder
;
536 CFMutableDictionaryRef resolver
;
538 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
539 domain
= _SC_trimDomain(domain
);
540 if (domain
== NULL
) {
544 defaultOrder
= DEFAULT_SEARCH_ORDER
545 + (DEFAULT_SEARCH_ORDER
/ 2)
546 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
548 resolver
= CFDictionaryCreateMutable(NULL
,
550 &kCFTypeDictionaryKeyCallBacks
,
551 &kCFTypeDictionaryValueCallBacks
);
552 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
553 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
554 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
555 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
557 if (S_mdns_timeout
!= NULL
) {
558 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
560 add_resolver(resolvers
, resolver
);
570 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
575 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
576 for (i
= 0; i
< n
; i
++) {
577 uint32_t defaultOrder
;
580 CFMutableDictionaryRef resolver
;
582 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
583 domain
= _SC_trimDomain(domain
);
584 if (domain
== NULL
) {
588 defaultOrder
= DEFAULT_SEARCH_ORDER
589 - (DEFAULT_SEARCH_ORDER
/ 4)
590 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
592 resolver
= CFDictionaryCreateMutable(NULL
,
594 &kCFTypeDictionaryKeyCallBacks
,
595 &kCFTypeDictionaryValueCallBacks
);
596 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
597 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
598 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
599 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
601 if (S_pdns_timeout
!= NULL
) {
602 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
604 add_resolver(resolvers
, resolver
);
613 static CFComparisonResult
614 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
616 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
617 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
620 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
621 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
623 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
624 if (!isA_CFNumber(num1
) ||
625 !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) {
626 order1
= DEFAULT_SEARCH_ORDER
;
629 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
630 if (!isA_CFNumber(num2
) ||
631 !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
632 order2
= DEFAULT_SEARCH_ORDER
;
635 if (order1
== order2
) {
636 // if same "SearchOrder", retain original orderring for configurations
637 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) &&
638 CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) &&
639 isA_CFNumber(num1
) &&
640 isA_CFNumber(num2
) &&
641 CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
) &&
642 CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
643 if (order1
== order2
) {
644 return kCFCompareEqualTo
;
646 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
650 return kCFCompareEqualTo
;
653 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
657 static CF_RETURNS_RETAINED CFArrayRef
658 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
660 CFStringRef defaultDomainName
= NULL
;
661 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
662 CFArrayRef defaultSearchDomains
= NULL
;
663 CFIndex defaultSearchIndex
= 0;
665 CFMutableArrayRef mySearchDomains
;
666 CFMutableArrayRef mySupplemental
= NULL
;
667 CFIndex n_supplemental
;
669 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
671 if (defaultDomain
!= NULL
) {
674 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
675 if (!isA_CFNumber(num
) ||
676 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &defaultOrder
)) {
677 defaultOrder
= DEFAULT_SEARCH_ORDER
;
680 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
681 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
684 // validate the provided "search" domains or move/expand/promote the "domain" name
685 if (isA_CFArray(defaultSearchDomains
)) {
688 n_search
= CFArrayGetCount(defaultSearchDomains
);
689 for (i
= 0; i
< n_search
; i
++) {
692 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
693 search
= _SC_trimDomain(search
);
694 if (search
!= NULL
) {
695 CFArrayAppendValue(mySearchDomains
, search
);
700 defaultDomainName
= _SC_trimDomain(defaultDomainName
);
701 if (defaultDomainName
!= NULL
) {
702 CFStringRef defaultOptions
;
704 int domain_parts
= 1;
708 #define NDOTS_OPT "ndots="
709 #define NDOTS_OPT_LEN (sizeof("ndots=") - 1)
711 defaultOptions
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSOptions
);
712 if (defaultOptions
!= NULL
) {
716 options
= _SC_cfstring_to_cstring(defaultOptions
,
719 kCFStringEncodingUTF8
);
720 cp
= strstr(options
, NDOTS_OPT
);
722 ((cp
== options
) || isspace(cp
[-1])) &&
723 ((cp
[NDOTS_OPT_LEN
] != '\0') && isdigit(cp
[NDOTS_OPT_LEN
]))) {
729 val
= strtol(cp
, &end
, 10);
730 if ((*cp
!= '\0') && (cp
!= end
) && (errno
== 0) &&
731 ((*end
== '\0') || isspace(*end
)) && (val
> 0)) {
735 CFAllocatorDeallocate(NULL
, options
);
738 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
741 kCFStringEncodingUTF8
);
742 CFRelease(defaultDomainName
);
744 // count domain parts
745 for (dp
= domain
; *dp
!= '\0'; dp
++) {
751 // move "domain" to "search" list (and expand as needed)
752 i
= LOCALDOMAINPARTS
;
758 str
= CFStringCreateWithCString(NULL
,
760 kCFStringEncodingUTF8
);
761 search
= _SC_trimDomain(str
);
763 if (search
!= NULL
) {
764 CFArrayAppendValue(mySearchDomains
, search
);
768 dp
= strchr(dp
, '.') + 1;
769 } while (++i
<= (domain_parts
- ndots
));
770 CFAllocatorDeallocate(NULL
, domain
);
774 // add any supplemental "domain" names to the search list
775 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
776 if (n_supplemental
> 1) {
777 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
778 CFArraySortValues(mySupplemental
,
779 CFRangeMake(0, n_supplemental
),
780 compareBySearchOrder
,
782 supplemental
= mySupplemental
;
784 for (i
= 0; i
< n_supplemental
; i
++) {
790 CFStringRef supplementalDomain
;
791 uint32_t supplementalOrder
;
793 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
795 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
796 if (isA_CFString(options
)) {
799 if (CFEqual(options
, CFSTR("pdns"))) {
800 // don't add private resolver domains to the search list
804 range
= CFStringFind(options
, CFSTR("interface="), 0);
805 if (range
.location
!= kCFNotFound
) {
806 // don't add scoped resolver domains to the search list
811 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
812 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
813 if (supplementalDomain
== NULL
) {
817 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomainsNoSearch
);
818 if (isA_CFNumber(num
) &&
819 CFNumberGetValue(num
, kCFNumberIntType
, &noSearch
) &&
821 CFRelease(supplementalDomain
);
825 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
826 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
827 CFRelease(supplementalDomain
);
831 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
832 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
835 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
836 if (!isA_CFNumber(num
) ||
837 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &supplementalOrder
)) {
838 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
841 if (supplementalOrder
< defaultOrder
) {
842 if (domainIndex
!= kCFNotFound
) {
843 // if supplemental domain is already in the search list
844 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
845 if (domainIndex
< defaultSearchIndex
) {
846 defaultSearchIndex
--;
849 CFArrayInsertValueAtIndex(mySearchDomains
,
852 defaultSearchIndex
++;
854 if (domainIndex
== kCFNotFound
) {
855 // add to the (end of the) search list
856 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
860 CFRelease(supplementalDomain
);
862 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
864 // update the "search" domains
865 if (CFArrayGetCount(mySearchDomains
) == 0) {
866 CFRelease(mySearchDomains
);
867 mySearchDomains
= NULL
;
870 // remove the "domain" name and "search" list
871 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
872 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
874 return mySearchDomains
;
879 add_scoped_resolvers(CFMutableArrayRef scoped
, CFDictionaryRef services
, CFArrayRef service_order
)
881 const void * keys_q
[N_QUICK
];
882 const void ** keys
= keys_q
;
886 CFMutableArrayRef order
;
887 CFMutableSetRef seen
;
889 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
890 if (n_services
== 0) {
891 return; // if no services
894 // ensure that we process all services in order
896 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
898 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
900 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
903 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
904 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
906 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
907 for (i
= 0; i
< n_services
; i
++) {
908 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
910 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
911 CFArrayAppendValue(order
, serviceID
);
915 if (keys
!= keys_q
) {
916 CFAllocatorDeallocate(NULL
, keys
);
919 // iterate over services
921 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
922 for (i
= 0; i
< n_order
; i
++) {
925 char if_name
[IF_NAMESIZE
];
926 CFStringRef interface
;
927 CFMutableDictionaryRef newDNS
;
929 CFArrayRef searchDomains
;
930 CFDictionaryRef service
;
931 CFStringRef serviceID
;
932 uint32_t these_flags
;
934 serviceID
= CFArrayGetValueAtIndex(order
, i
);
935 service
= CFDictionaryGetValue(services
, serviceID
);
936 if (!isA_CFDictionary(service
)) {
941 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
942 if (!isA_CFDictionary(dns
)) {
947 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
948 if ((interface
== NULL
) || CFEqual(interface
, CFSTR("*"))) {
949 // if no [scoped] interface or supplemental configuration w/match-all
953 if (CFDictionaryContainsKey(dns
, kSCPropNetDNSServiceIdentifier
)) {
954 // if this is a service-specific resolver
958 if (CFSetContainsValue(seen
, interface
)) {
959 // if we've already processed this [scoped] interface
962 CFSetSetValue(seen
, interface
);
964 if ((_SC_cfstring_to_cstring(interface
,
967 kCFStringEncodingASCII
) == NULL
) ||
968 (if_nametoindex(if_name
) == 0)) {
969 // if interface index not available
973 // add [scoped] resolver entry
974 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
977 searchDomains
= extract_search_domains(newDNS
, NULL
);
978 if (searchDomains
!= NULL
) {
979 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
980 CFRelease(searchDomains
);
983 // set "scoped" configuration flag(s)
984 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
985 !isA_CFNumber(num
) ||
986 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
989 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
992 add_dns_query_flags(serviceID
, service
, &these_flags
);
993 if (these_flags
== 0) {
996 flags
|= these_flags
;
998 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
999 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
1002 // remove keys we don't want in a [scoped] resolver
1003 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
1004 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
1006 // add the [scoped] resolver
1007 add_resolver(scoped
, newDNS
);
1009 // add any supplemental resolver configurations for this interface
1010 add_supplemental_resolvers(scoped
, services
, service_order
, interface
, service
);
1023 add_service_specific_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
)
1025 CFIndex services_count
= (isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0);
1027 if (services_count
> 0) {
1029 CFStringRef keys_q
[N_QUICK
];
1030 CFStringRef
*keys
= keys_q
;
1031 CFMutableSetRef seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1033 if (services_count
> (CFIndex
)(sizeof(keys_q
) / sizeof(keys_q
[0]))) {
1034 keys
= CFAllocatorAllocate(kCFAllocatorDefault
, services_count
* sizeof(keys
[0]), 0);
1037 CFDictionaryGetKeysAndValues(services
, (const void **)keys
, NULL
);
1039 for (key_idx
= 0; key_idx
< services_count
; key_idx
++) {
1040 CFDictionaryRef service
= CFDictionaryGetValue(services
, keys
[key_idx
]);
1041 CFDictionaryRef dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
1043 if (isA_CFDictionary(dns
)) {
1044 CFNumberRef service_identifier
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1046 if (isA_CFNumber(service_identifier
)) {
1047 if (!CFSetContainsValue(seen
, service_identifier
)) {
1048 CFMutableDictionaryRef new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1049 CFNumberRef flags_num
;
1052 CFSetSetValue(seen
, service_identifier
);
1054 if (!CFDictionaryGetValueIfPresent(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&flags_num
) ||
1055 !isA_CFNumber(flags_num
) ||
1056 !CFNumberGetValue(flags_num
, kCFNumberSInt32Type
, &flags
)) {
1060 flags
|= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
| DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
1062 flags_num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
1063 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, flags_num
);
1064 CFRelease(flags_num
);
1066 if (CFDictionaryContainsKey(new_resolver
, kSCPropInterfaceName
)) {
1067 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
);
1070 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
1071 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
1073 add_resolver(resolvers
, new_resolver
);
1074 CFRelease(new_resolver
);
1076 my_log(LOG_ERR
, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
1082 if (keys
!= keys_q
) {
1083 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
);
1091 add_default_resolver(CFMutableArrayRef resolvers
,
1092 CFDictionaryRef defaultResolver
,
1093 Boolean
*orderAdded
,
1094 CFArrayRef
*searchDomains
)
1096 CFMutableDictionaryRef myDefault
;
1097 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
1100 if (defaultResolver
== NULL
) {
1101 myDefault
= CFDictionaryCreateMutable(NULL
,
1103 &kCFTypeDictionaryKeyCallBacks
,
1104 &kCFTypeDictionaryValueCallBacks
);
1106 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
1108 assert(myDefault
!= NULL
);
1110 // ensure that the default resolver has a search order
1112 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
1113 if (!isA_CFNumber(order
) ||
1114 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) {
1115 myOrder
= DEFAULT_SEARCH_ORDER
;
1116 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
1117 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
1122 // extract the "search" domain list for the default resolver (and
1123 // any supplemental resolvers)
1125 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
1127 // add the default resolver
1129 add_resolver(resolvers
, myDefault
);
1130 CFRelease(myDefault
);
1135 static dns_create_resolver_t
1136 create_resolver(CFDictionaryRef dns
)
1140 dns_create_resolver_t _resolver
;
1142 CFStringRef targetInterface
= NULL
;
1143 unsigned int targetInterfaceIndex
= 0;
1145 _resolver
= _dns_resolver_create();
1148 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
1149 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1150 char domain
[NS_MAXDNAME
];
1152 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
1153 _dns_resolver_set_domain(&_resolver
, domain
);
1157 // process search domains
1158 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
1159 if (isA_CFArray(list
)) {
1161 CFIndex n
= CFArrayGetCount(list
);
1163 // add "search" domains
1164 for (i
= 0; i
< n
; i
++) {
1165 str
= CFArrayGetValueAtIndex(list
, i
);
1166 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1167 char search
[NS_MAXDNAME
];
1169 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
1170 _dns_resolver_add_search(&_resolver
, search
);
1176 // process interface index
1177 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
1178 if (isA_CFNumber(num
)) {
1181 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
1182 char if_name
[IFNAMSIZ
];
1184 _dns_resolver_set_if_index(&_resolver
, if_index
);
1186 if ((if_index
!= 0) &&
1187 (if_indextoname(if_index
, if_name
) != NULL
)) {
1188 targetInterface
= CFStringCreateWithCString(NULL
,
1190 kCFStringEncodingASCII
);
1191 targetInterfaceIndex
= if_index
;
1197 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1198 if (isA_CFNumber(num
)) {
1201 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1202 _dns_resolver_set_flags(&_resolver
, flags
);
1206 // process nameserver addresses
1207 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1208 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
1209 if (isA_CFArray(list
)) {
1211 CFIndex n
= CFArrayGetCount(list
);
1213 for (i
= 0; i
< n
; i
++) {
1216 struct sockaddr_in sin
;
1217 struct sockaddr_in6 sin6
;
1221 str
= CFArrayGetValueAtIndex(list
, i
);
1222 if (!isA_CFString(str
)) {
1226 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1230 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
1234 if ((addr
.sa
.sa_family
== AF_INET6
) &&
1235 (IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) ||
1236 IN6_IS_ADDR_MC_LINKLOCAL(&addr
.sin6
.sin6_addr
)) &&
1237 (addr
.sin6
.sin6_scope_id
== 0) &&
1238 (targetInterfaceIndex
!= 0)) {
1239 // for link local [IPv6] addresses, if the scope id is not
1240 // set then we should use the interface associated with the
1241 // resolver configuration
1242 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
1245 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
1249 // process search order
1250 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
1251 if (isA_CFNumber(num
)) {
1254 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) {
1255 _dns_resolver_set_order(&_resolver
, order
);
1260 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
1261 if (isA_CFArray(list
)) {
1263 CFIndex n
= CFArrayGetCount(list
);
1265 for (i
= 0; i
< n
; i
++) {
1268 dns_sortaddr_t sortaddr
;
1270 str
= CFArrayGetValueAtIndex(list
, i
);
1271 if (!isA_CFString(str
)) {
1275 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1279 slash
= strchr(buf
, '/');
1280 if (slash
!= NULL
) {
1284 bzero(&sortaddr
, sizeof(sortaddr
));
1285 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
1286 /* if address not valid */
1290 if (slash
!= NULL
) {
1291 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1292 /* if subnet mask not valid */
1299 a
= ntohl(sortaddr
.address
.s_addr
);
1302 } else if (IN_CLASSB(a
)) {
1304 } else if (IN_CLASSC(a
)) {
1310 sortaddr
.mask
.s_addr
= htonl(m
);
1313 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1318 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1319 if (isA_CFNumber(num
)) {
1322 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1323 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1328 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1329 if (isA_CFNumber(num
)) {
1332 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1333 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1338 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1339 if (isA_CFString(str
)) {
1342 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1343 if (options
!= NULL
) {
1344 _dns_resolver_set_options(&_resolver
, options
);
1345 CFAllocatorDeallocate(NULL
, options
);
1349 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1350 if (isA_CFNumber(num
)) {
1351 int service_identifier
;
1353 if (CFNumberGetValue(num
, kCFNumberIntType
, &service_identifier
)) {
1354 _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)service_identifier
);
1358 if (targetInterface
!= NULL
) {
1359 CFRelease(targetInterface
);
1366 static __inline__ Boolean
1367 isScopedConfiguration(CFDictionaryRef dns
)
1372 if ((dns
!= NULL
) &&
1373 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1375 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1376 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1384 static __inline__ Boolean
1385 isServiceSpecificConfiguration(CFDictionaryRef dns
)
1391 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1393 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1394 (flags
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
))
1403 static CFComparisonResult
1404 compareDomain(const void *val1
, const void *val2
, void *context
)
1406 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1407 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1408 CFStringRef domain1
;
1409 CFStringRef domain2
;
1410 CFArrayRef labels1
= NULL
;
1411 CFArrayRef labels2
= NULL
;
1414 CFComparisonResult result
;
1420 // "default" domains sort before "supplemental" domains
1421 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1422 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1423 if (domain1
== NULL
) {
1424 return kCFCompareLessThan
;
1425 } else if (domain2
== NULL
) {
1426 return kCFCompareGreaterThan
;
1429 // sort non-scoped before scoped
1430 scoped1
= isScopedConfiguration(dns1
);
1431 scoped2
= isScopedConfiguration(dns2
);
1432 if (scoped1
!= scoped2
) {
1434 return kCFCompareLessThan
;
1436 return kCFCompareGreaterThan
;
1440 // must have domain names for any further comparisons
1441 if ((domain1
== NULL
) || (domain2
== NULL
)) {
1442 return kCFCompareEqualTo
;
1445 // forward (A, AAAA) domains sort before reverse (PTR) domains
1446 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1447 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1450 return kCFCompareGreaterThan
;
1452 return kCFCompareLessThan
;
1456 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1457 n1
= CFArrayGetCount(labels1
);
1459 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1460 n2
= CFArrayGetCount(labels2
);
1462 while ((n1
> 0) && (n2
> 0)) {
1463 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1464 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1466 // compare domain labels
1467 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1468 if (result
!= kCFCompareEqualTo
) {
1473 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1475 result
= kCFCompareLessThan
;
1477 } else if (n1
< n2
) {
1478 result
= kCFCompareGreaterThan
;
1482 // sort by search order
1483 result
= compareBySearchOrder(val1
, val2
, context
);
1487 if (labels1
!= NULL
) CFRelease(labels1
);
1488 if (labels2
!= NULL
) CFRelease(labels2
);
1495 dns_configuration_set(CFDictionaryRef defaultResolver
,
1496 CFDictionaryRef services
,
1497 CFArrayRef serviceOrder
,
1498 CFArrayRef multicastResolvers
,
1499 CFArrayRef privateResolvers
)
1501 dns_create_config_t _config
;
1502 Boolean changed
= FALSE
;
1503 uint32_t dns_resolver_flags
= 0;
1505 CFMutableDictionaryRef myDefault
;
1506 Boolean myOrderAdded
= FALSE
;
1507 CFArrayRef mySearchDomains
= NULL
;
1508 CFIndex n_resolvers
;
1509 CFMutableArrayRef resolvers
;
1510 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1511 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1513 // establish list of resolvers
1515 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1516 assert(resolvers
!= NULL
);
1518 // collect (and add) any "supplemental" resolver configurations
1520 add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
);
1522 // collect (and add) any "private" resolver configurations
1524 add_private_resolvers(resolvers
, privateResolvers
);
1526 // add the "default" resolver
1528 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1530 // collect (and add) any "multicast" resolver configurations
1532 add_multicast_resolvers(resolvers
, multicastResolvers
);
1534 // collect (and add) any "scoped" resolver configurations
1536 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1538 // collect (and add) any "service-specific" resolver configurations
1540 add_service_specific_resolvers(resolvers
, services
);
1544 n_resolvers
= CFArrayGetCount(resolvers
);
1545 if (n_resolvers
> 1) {
1546 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1551 for (i
= n_resolvers
; --i
> 0; ) {
1552 CFDictionaryRef resolver
;
1554 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1555 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1556 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1557 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1558 // remove empty resolver
1559 CFArrayRemoveValueAtIndex(resolvers
, i
);
1564 // update the default resolver
1566 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1568 CFArrayGetValueAtIndex(resolvers
, 0));
1569 if (mySearchDomains
!= NULL
) {
1570 // add search domains to the default resolver
1571 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1572 CFRelease(mySearchDomains
);
1574 if (myOrderAdded
&& (n_resolvers
> 1)) {
1575 CFDictionaryRef resolver
;
1577 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1578 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1579 isScopedConfiguration(resolver
)) {
1580 // if not a supplemental "default" resolver (a domain name is
1581 // present) or if it's a scoped configuration
1582 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1585 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1586 CFRelease(myDefault
);
1588 // establish resolver configuration
1590 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1592 * if no default and no supplemental/scoped resolvers
1597 * if default and/or supplemental/scoped resolvers are defined
1599 _config
= _dns_configuration_create();
1601 CFDictionaryApplyFunction(services
, add_dns_query_flags
, &dns_resolver_flags
);
1603 for (i
= 0; i
< n_resolvers
; i
++) {
1604 boolean_t is_default_resolver
;
1605 CFDictionaryRef resolver
;
1606 dns_create_resolver_t _resolver
;
1608 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1610 is_default_resolver
= (!isScopedConfiguration(resolver
) && !isServiceSpecificConfiguration(resolver
));
1611 if (is_default_resolver
) {
1612 CFMutableDictionaryRef new_resolver
;
1615 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
);
1617 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &dns_resolver_flags
);
1618 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
1621 resolver
= new_resolver
;
1624 _resolver
= create_resolver(resolver
);
1625 _dns_configuration_add_resolver(&_config
, _resolver
);
1626 _dns_resolver_free(&_resolver
);
1628 if (is_default_resolver
) {
1629 CFRelease(resolver
);
1633 #if !TARGET_OS_IPHONE
1634 // add flatfile resolvers
1636 _dnsinfo_flatfile_set_flags(dns_resolver_flags
);
1637 _dnsinfo_flatfile_add_resolvers(&_config
);
1638 #endif // !TARGET_OS_IPHONE
1641 #ifdef DNS_CONFIGURATION_DEBUG
1644 dns_config_t
*config
;
1645 _dns_config_buf_t
*config_buf
;
1649 config_buf
= (_dns_config_buf_t
*)_config
;
1650 n_config
= sizeof(_dns_config_buf_t
) + ntohl(config_buf
->n_attribute
);
1651 n_padding
= ntohl(config_buf
->n_padding
);
1652 buf
= malloc(n_config
+ n_padding
);
1653 bcopy((void *)config_buf
, buf
, n_config
);
1654 bzero(&buf
[n_config
], n_padding
);
1655 config
= expand_config((_dns_config_buf_t
*)buf
);
1656 _dns_configuration_print(config
);
1659 #endif // DNS_CONFIGURATION_DEBUG
1661 // check if the configuration changed
1662 _dns_configuration_signature(&_config
, signature
, sizeof(signature
));
1663 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1664 // save [new] signature
1665 bcopy(signature
, signature_last
, sizeof(signature
));
1667 // save [new] configuration
1668 if (!_dns_configuration_store(&_config
)) {
1669 my_log(LOG_ERR
, "dns_configuration_set: could not store configuration");
1675 if (_config
!= NULL
) _dns_configuration_free(&_config
);
1677 CFRelease(resolvers
);
1682 #if !TARGET_OS_IPHONE
1683 static SCDynamicStoreRef dns_configuration_store
;
1684 static SCDynamicStoreCallBack dns_configuration_callout
;
1687 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1689 CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1691 Boolean resolvers_now
;
1692 static Boolean resolvers_save
= FALSE
;
1693 struct stat statbuf
;
1695 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1696 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1697 // if we did not (and still do not) have an "/etc/resolvers"
1698 // directory than this notification is the result of a change
1699 // to the "/etc" directory.
1702 resolvers_save
= resolvers_now
;
1704 my_log(LOG_DEBUG
, _PATH_RESOLVER_DIR
" changed");
1706 // fake a "DNS" change
1707 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1708 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1716 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1719 mach_port_t notify_port
;
1721 CFRunLoopSourceRef rls
;
1724 dns_configuration_store
= store
;
1725 dns_configuration_callout
= callout
;
1727 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1728 if (status
!= NOTIFY_STATUS_OK
) {
1729 my_log(LOG_ERR
, "notify_register_mach_port() failed");
1733 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1734 if (status
!= NOTIFY_STATUS_OK
) {
1735 my_log(LOG_ERR
, "notify_monitor_file() failed");
1736 (void)notify_cancel(notify_token
);
1740 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1742 dns_configuration_changed
,
1745 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1747 my_log(LOG_ERR
, "SCDynamicStoreCreateRunLoopSource() failed");
1749 (void)notify_cancel(notify_token
);
1752 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1758 #endif // !TARGET_OS_IPHONE
1763 dns_configuration_init(CFBundleRef bundle
)
1765 CFDictionaryRef dict
;
1767 dict
= CFBundleGetInfoDictionary(bundle
);
1768 if (isA_CFDictionary(dict
)) {
1769 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1770 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1772 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1773 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1781 #pragma mark Standalone test code
1787 split(const void * key
, const void * value
, void * context
)
1789 CFArrayRef components
;
1790 CFStringRef entity_id
;
1791 CFStringRef service_id
;
1792 CFMutableDictionaryRef state_dict
;
1794 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1795 service_id
= CFArrayGetValueAtIndex(components
, 3);
1796 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1797 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1798 if (state_dict
!= NULL
) {
1799 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1801 state_dict
= CFDictionaryCreateMutable(NULL
,
1803 &kCFTypeDictionaryKeyCallBacks
,
1804 &kCFTypeDictionaryValueCallBacks
);
1807 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1808 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1809 CFStringRef interface
;
1811 if (CFEqual(entity_id
, kSCEntNetIPv4
)) {
1812 CFMutableDictionaryRef ipv4_dict
;
1814 ipv4_dict
= CFDictionaryCreateMutable(NULL
,
1816 &kCFTypeDictionaryKeyCallBacks
,
1817 &kCFTypeDictionaryValueCallBacks
);
1818 CFDictionarySetValue(ipv4_dict
, kIPv4DictService
, (CFDictionaryRef
)value
);
1819 CFDictionarySetValue(state_dict
, entity_id
, ipv4_dict
);
1820 CFRelease(ipv4_dict
);
1822 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1825 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1826 if (interface
!= NULL
) {
1827 CFDictionaryRef dns
;
1828 CFMutableDictionaryRef new_dns
;
1830 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1832 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1834 new_dns
= CFDictionaryCreateMutable(NULL
,
1836 &kCFTypeDictionaryKeyCallBacks
,
1837 &kCFTypeDictionaryValueCallBacks
);
1839 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1840 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1843 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1844 CFDictionaryRef dns
;
1846 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1848 CFStringRef interface
;
1850 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1851 if (interface
!= NULL
) {
1852 CFMutableDictionaryRef new_dns
;
1854 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1855 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1856 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1859 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1862 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1865 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1868 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1869 CFRelease(state_dict
);
1870 CFRelease(components
);
1876 main(int argc
, char **argv
)
1878 CFDictionaryRef entities
;
1880 CFArrayRef multicast_resolvers
;
1881 CFStringRef pattern
;
1882 CFMutableArrayRef patterns
;
1883 CFStringRef primary
= NULL
;
1884 CFDictionaryRef primaryDNS
= NULL
;
1885 CFArrayRef private_resolvers
;
1886 CFArrayRef service_order
= NULL
;
1887 CFMutableDictionaryRef service_state_dict
;
1888 CFDictionaryRef setup_global_ipv4
;
1889 CFDictionaryRef state_global_ipv4
;
1890 SCDynamicStoreRef store
;
1893 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1895 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1897 // get IPv4, IPv6, and DNS entities
1898 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1899 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1900 kSCDynamicStoreDomainState
,
1903 CFArrayAppendValue(patterns
, pattern
);
1905 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1906 kSCDynamicStoreDomainState
,
1909 CFArrayAppendValue(patterns
, pattern
);
1911 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1912 kSCDynamicStoreDomainState
,
1915 CFArrayAppendValue(patterns
, pattern
);
1917 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1918 CFRelease(patterns
);
1920 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1922 &kCFTypeDictionaryKeyCallBacks
,
1923 &kCFTypeDictionaryValueCallBacks
);
1924 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1925 CFRelease(entities
);
1927 // get primary service ID
1928 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1929 kSCDynamicStoreDomainState
,
1931 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1933 if (state_global_ipv4
!= NULL
) {
1934 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1935 if (primary
!= NULL
) {
1936 CFDictionaryRef service_dict
;
1938 // get DNS configuration for primary service
1939 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1940 if (service_dict
!= NULL
) {
1941 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1947 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1948 kSCDynamicStoreDomainSetup
,
1950 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1952 if (setup_global_ipv4
!= NULL
) {
1953 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1956 // get multicast resolvers
1957 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1958 kSCDynamicStoreDomainState
,
1960 CFSTR(kDNSServiceCompMulticastDNS
));
1961 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1964 // get private resolvers
1965 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1966 kSCDynamicStoreDomainState
,
1968 CFSTR(kDNSServiceCompPrivateDNS
));
1969 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1972 // update DNS configuration
1973 dns_configuration_init(CFBundleGetMainBundle());
1974 (void)dns_configuration_set(primaryDNS
,
1977 multicast_resolvers
,
1981 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1982 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1983 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
1984 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1985 CFRelease(service_state_dict
);