2 * Copyright (c) 2004-2017 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_internal.h"
61 #include "dnsinfo_logging.h"
62 #include "dnsinfo_private.h"
63 #include "dnsinfo_server.h"
65 #include <network_information.h>
68 #include <dns_sd_private.h>
70 #define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
71 #define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
72 #define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
74 /* multicast DNS resolver configurations */
75 static CFNumberRef S_mdns_timeout
= NULL
;
77 /* private DNS resolver configurations */
78 static CFNumberRef S_pdns_timeout
= NULL
;
82 #pragma mark DNS resolver flags
85 static __inline__ boolean_t
86 dns_resolver_flags_all_queries(uint32_t query_flags
)
88 return ((query_flags
& DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
) == DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
);
95 dns_resolver_flags_service(CFDictionaryRef service
, uint32_t resolver_flags
)
98 // check if the service has v4 configured
99 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
) == 0) &&
100 service_contains_protocol(service
, AF_INET
)) {
101 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
;
104 // check if the service has v6 configured
105 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
) == 0) &&
106 service_contains_protocol(service
, AF_INET6
)) {
107 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
;
110 return resolver_flags
;
115 add_dns_resolver_flags(const void *key
, const void *value
, void *context
)
118 CFDictionaryRef service
= (CFDictionaryRef
)value
;
119 // CFStringRef serviceID = (CFStringRef)key;
120 uint32_t *resolver_flags
= (uint32_t *)context
;
122 if (service_is_scoped_only(service
)) {
126 // update resovler flags based on configured (and available) protocols
127 *resolver_flags
= dns_resolver_flags_service(service
, *resolver_flags
);
133 #pragma mark DNS resolver configuration
137 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
)
140 CFStringRef interface
;
143 uint32_t order_val
= 0;
145 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
146 if (!isA_CFNumber(order
) ||
147 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &order_val
)) {
152 n_resolvers
= CFArrayGetCount(resolvers
);
153 for (i
= 0; i
< n_resolvers
; i
++) {
154 CFDictionaryRef match_resolver
;
156 match_resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
157 if (CFEqual(resolver
, match_resolver
)) {
163 CFMutableDictionaryRef compare
;
166 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
);
167 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
168 match
= CFEqual(resolver
, compare
);
171 CFNumberRef match_order
;
172 uint32_t match_order_val
= 0;
174 // if only the search order's are different
175 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
176 if (!isA_CFNumber(match_order
) ||
177 !CFNumberGetValue(match_order
, kCFNumberSInt32Type
, &match_order_val
)) {
181 if (order_val
< match_order_val
) {
182 // if we should prefer this match resolver, else just skip it
183 CFArraySetValueAtIndex(resolvers
, i
, resolver
);
191 order
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_resolvers
);
192 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_ORDER_KEY
, order
);
195 interface
= CFDictionaryGetValue(resolver
, kSCPropInterfaceName
);
196 if ((interface
!= NULL
) && !CFEqual(interface
, CFSTR("*"))) {
198 unsigned int if_index
= 0;
199 char if_name
[IF_NAMESIZE
];
203 if (_SC_cfstring_to_cstring(interface
,
206 kCFStringEncodingASCII
) != NULL
) {
207 if_index
= my_if_nametoindex(if_name
);
210 if ((if_index
!= 0) &&
212 // check if this is a "scoped" configuration
213 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
215 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
216 (flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)
218 // check if we should scope all queries with this configuration
219 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
220 isA_CFBoolean(val
) &&
221 CFBooleanGetValue(val
))
224 // if interface index available and it should be used
225 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
);
226 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_IF_INDEX_KEY
, num
);
231 CFArrayAppendValue(resolvers
, resolver
);
236 #define DNS_CONFIGURATION_CONFIGURATION_ID CFSTR("__CONFIGURATION_ID__")
240 add_resolver_signature(CFMutableDictionaryRef resolver
, const char *rType
, CFStringRef cID
, CFIndex rIndex
)
244 str
= CFStringCreateWithFormat(NULL
, NULL
,
245 CFSTR("%s:%s%@ %ld"),
247 (cID
!= NULL
) ? " " : "",
248 (cID
!= NULL
) ? cID
: CFSTR(""),
250 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_CONFIGURATION_ID
, str
);
258 add_supplemental(CFMutableArrayRef resolvers
,
259 CFStringRef serviceID
,
261 uint32_t defaultOrder
,
270 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
271 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
272 if (n_domains
== 0) {
273 // if no supplemental match domains
277 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
278 if (orders
!= NULL
) {
279 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
280 // if supplemental match orders... but too many/not enough
285 servers
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
286 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) {
287 // if no DNS server addresses
292 * yes, this is a "supplemental" resolver configuration, expand
293 * the match domains and add each to the resolvers list.
295 for (i
= 0; i
< n_domains
; i
++) {
296 CFStringRef match_domain
;
297 CFNumberRef match_order
;
298 CFMutableDictionaryRef match_resolver
;
300 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
301 if (!isA_CFString(match_domain
)) {
305 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
307 // set supplemental resolver "domain"
308 if (CFStringGetLength(match_domain
) > 0) {
309 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
311 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
314 // set supplemental resolver "search_order"
315 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
316 if (isA_CFNumber(match_order
)) {
317 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
318 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
321 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
322 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
325 defaultOrder
++; // if multiple domains, maintain ordering
328 // remove keys we don't want in a supplemental resolver
329 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
330 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
331 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
332 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
334 add_resolver_signature(match_resolver
,
335 scoped
? "Supplemental/Scoped" : "Supplemental",
338 add_resolver(resolvers
, match_resolver
);
339 CFRelease(match_resolver
);
350 merge_configuration_flags(CFMutableDictionaryRef newDNS
, uint32_t mergeFlags
)
355 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
356 !isA_CFNumber(num
) ||
357 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
363 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
364 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
372 add_supplemental_resolvers(CFMutableArrayRef resolvers
,
373 CFDictionaryRef services
,
374 CFArrayRef service_order
,
375 CFStringRef scoped_interface
,
376 CFDictionaryRef scoped_service
)
378 const void * keys_q
[N_QUICK
];
379 const void ** keys
= keys_q
;
383 const void * vals_q
[N_QUICK
];
384 const void ** vals
= vals_q
;
386 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
387 if (n_services
== 0) {
388 return; // if no services
391 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
392 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
393 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
396 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
398 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
399 for (i
= 0; i
< n_services
; i
++) {
400 uint32_t defaultOrder
;
402 uint32_t dns_resolver_flags
;
403 CFStringRef interface
;
404 CFMutableDictionaryRef newDNS
= NULL
;
406 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
407 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
408 Boolean trusted
= FALSE
; // trusted config w/interface
410 if (!isA_CFDictionary(service
)) {
414 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
415 dns
= isA_CFDictionary(dns
);
420 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
422 if (scoped_interface
!= NULL
) {
424 // we only want to add split/supplemental configurations
425 // for queries scoped to an interface if they are NOT
426 // associated with a "real" service
428 if (CFDictionaryContainsKey(service
, kSCEntNetIPv4
) ||
429 CFDictionaryContainsKey(service
, kSCEntNetIPv6
)) {
434 // in addition, we don't want to add split/supplemental
435 // configurations for queries scoped to an interface if
436 // the configuration does not apply to all interfaces and
437 // the configuration is explicitly NOT for this interface
439 if (!_SC_CFEqual(interface
, CFSTR("*")) &&
440 !_SC_CFEqual(interface
, scoped_interface
)) {
445 // lastly, check if A/AAAA queries should be issued (based
446 // on the IP[v6] addresses). If we would not be issuing a
447 // query then don't bother adding the configuration.
449 dns_resolver_flags
= dns_resolver_flags_service(scoped_service
, 0);
450 if (dns_resolver_flags
== 0) {
455 defaultOrder
= DEFAULT_SEARCH_ORDER
456 - (DEFAULT_SEARCH_ORDER
/ 2)
457 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
459 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
460 // push out services not specified in service order
461 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
465 * Ensure that we have the correct InterfaceName in the DNS configuration
467 * scoped_interface [supplemental] interface Trusted config DNS interface
468 * ================ ======================== ============== =================
469 * NULL NULL No NULL (No change)
472 * NULL NULL Yes NULL (No change)
473 * NULL en0 Yes en0 (trusted config w/interface)
475 * en0 NULL N/A en0 (scoped interface)
476 * en0 en0 N/A en0 (scoped interface)
477 * en0 * N/A en0 (scoped interface)
479 if ((scoped_interface
== NULL
) && (interface
== NULL
)) {
480 newDNS
= (CFMutableDictionaryRef
)CFRetain(dns
);
484 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
485 if (scoped_interface
!= NULL
) {
486 CFDictionarySetValue(newDNS
, kSCPropInterfaceName
, scoped_interface
);
487 } else if ((interface
!= NULL
) &&
488 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
489 isA_CFBoolean(val
) &&
490 CFBooleanGetValue(val
)) {
491 // leave the [trusted configuration] InterfaceName in place
494 CFDictionaryRemoveValue(newDNS
, kSCPropInterfaceName
);
498 // set "supplemental" flag
499 newFlags
= DNS_RESOLVER_FLAGS_SUPPLEMENTAL
;
501 if (scoped_interface
!= NULL
) {
502 // set "scoped" configuration flag
503 newFlags
|= DNS_RESOLVER_FLAGS_SCOPED
;
505 // add "Request A/AAAA query" flag(s)
506 newFlags
|= dns_resolver_flags
;
507 } else if (trusted
) {
508 // use the DNS query flags from the supplemental match service
509 newFlags
|= dns_resolver_flags_service(service
, 0);
512 merge_configuration_flags(newDNS
, newFlags
);
514 // add [scoped] resolver entry
515 add_supplemental(resolvers
, serviceID
, newDNS
, defaultOrder
, (scoped_interface
!= NULL
));
519 if (keys
!= keys_q
) {
520 CFAllocatorDeallocate(NULL
, keys
);
521 CFAllocatorDeallocate(NULL
, vals
);
529 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
534 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
535 for (i
= 0; i
< n
; i
++) {
536 uint32_t defaultOrder
;
539 CFMutableDictionaryRef resolver
;
541 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
542 domain
= _SC_trimDomain(domain
);
543 if (domain
== NULL
) {
547 defaultOrder
= DEFAULT_SEARCH_ORDER
548 + (DEFAULT_SEARCH_ORDER
/ 2)
549 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
551 resolver
= CFDictionaryCreateMutable(NULL
,
553 &kCFTypeDictionaryKeyCallBacks
,
554 &kCFTypeDictionaryValueCallBacks
);
555 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
556 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
557 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
558 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
560 if (S_mdns_timeout
!= NULL
) {
561 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
563 add_resolver_signature(resolver
, "Multicast DNS", NULL
, i
);
564 add_resolver(resolvers
, resolver
);
574 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
579 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
580 for (i
= 0; i
< n
; i
++) {
581 uint32_t defaultOrder
;
584 CFMutableDictionaryRef resolver
;
586 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
587 domain
= _SC_trimDomain(domain
);
588 if (domain
== NULL
) {
592 defaultOrder
= DEFAULT_SEARCH_ORDER
593 - (DEFAULT_SEARCH_ORDER
/ 4)
594 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
596 resolver
= CFDictionaryCreateMutable(NULL
,
598 &kCFTypeDictionaryKeyCallBacks
,
599 &kCFTypeDictionaryValueCallBacks
);
600 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
601 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
602 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
603 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
605 if (S_pdns_timeout
!= NULL
) {
606 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
608 add_resolver_signature(resolver
, "Private DNS", NULL
, i
);
609 add_resolver(resolvers
, resolver
);
618 static CFComparisonResult
619 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
621 #pragma unused(context)
622 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
623 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
626 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
627 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
629 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
630 if (!isA_CFNumber(num1
) ||
631 !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) {
632 order1
= DEFAULT_SEARCH_ORDER
;
635 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
636 if (!isA_CFNumber(num2
) ||
637 !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
638 order2
= DEFAULT_SEARCH_ORDER
;
641 if (order1
== order2
) {
642 // if same "SearchOrder", retain original orderring for configurations
643 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) &&
644 CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) &&
645 isA_CFNumber(num1
) &&
646 isA_CFNumber(num2
) &&
647 CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
) &&
648 CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
649 if (order1
== order2
) {
650 return kCFCompareEqualTo
;
652 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
656 return kCFCompareEqualTo
;
659 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
663 static CF_RETURNS_RETAINED CFArrayRef
664 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
666 CFStringRef defaultDomainName
= NULL
;
667 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
668 CFArrayRef defaultSearchDomains
= NULL
;
669 CFIndex defaultSearchIndex
= 0;
670 CFMutableArrayRef mySearchDomains
;
671 CFMutableArrayRef mySupplemental
= NULL
;
672 CFIndex n_supplemental
;
673 CFStringRef trimmedDomainName
;
675 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
677 if (defaultDomain
!= NULL
) {
680 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
681 if (!isA_CFNumber(num
) ||
682 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &defaultOrder
)) {
683 defaultOrder
= DEFAULT_SEARCH_ORDER
;
686 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
687 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
690 // validate the provided "search" domains or move/expand/promote the "domain" name
691 if (isA_CFArray(defaultSearchDomains
)) {
694 n_search
= CFArrayGetCount(defaultSearchDomains
);
695 for (int i
= 0; i
< n_search
; i
++) {
698 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
699 search
= _SC_trimDomain(search
);
700 if (search
!= NULL
) {
701 CFArrayAppendValue(mySearchDomains
, search
);
706 trimmedDomainName
= _SC_trimDomain(defaultDomainName
);
707 #ifdef PERFORM_DOMAIN_EXPANSION
709 * With BIND 4.8.3 (and earlier) resolvers, the default search list included
710 * the default domain and each of its parent domains with two or more labels.
712 if ((trimmedDomainName
!= NULL
) &&
713 CFStringHasSuffix(defaultDomainName
, CFSTR("."))) {
714 // if "domain" name is fully qualified
715 CFArrayAppendValue(mySearchDomains
, trimmedDomainName
);
716 CFRelease(trimmedDomainName
);
717 } else if (trimmedDomainName
!= NULL
) {
719 int domain_parts
= 1;
723 domain
= _SC_cfstring_to_cstring(trimmedDomainName
,
726 kCFStringEncodingUTF8
);
727 CFRelease(trimmedDomainName
);
729 // count domain parts
730 for (dp
= domain
; *dp
!= '\0'; dp
++) {
736 // move "domain" to "search" list (and expand as needed)
742 str
= CFStringCreateWithCString(NULL
,
744 kCFStringEncodingUTF8
);
745 search
= _SC_trimDomain(str
);
747 if (search
!= NULL
) {
748 CFArrayAppendValue(mySearchDomains
, search
);
752 dp
= strchr(dp
, '.') + 1;
753 } while (domain_parts
-- > 2);
754 CFAllocatorDeallocate(NULL
, domain
);
756 #else // PERFORM_DOMAIN_EXPANSION
758 * With BIND 4.9.3 (and later) resolvers, the default search list included
759 * just the default domain.
761 if (trimmedDomainName
!= NULL
) {
762 CFArrayAppendValue(mySearchDomains
, trimmedDomainName
);
763 CFRelease(trimmedDomainName
);
765 #endif // PERFORM_DOMAIN_EXPANSION
768 // add any supplemental "domain" names to the search list
769 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
770 if (n_supplemental
> 1) {
771 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
772 CFArraySortValues(mySupplemental
,
773 CFRangeMake(0, n_supplemental
),
774 compareBySearchOrder
,
776 supplemental
= mySupplemental
;
778 for (int i
= 0; i
< n_supplemental
; i
++) {
784 CFStringRef supplementalDomain
;
785 uint32_t supplementalOrder
;
787 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
789 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
790 if (isA_CFString(options
)) {
793 if (CFEqual(options
, CFSTR("pdns"))) {
794 // don't add private resolver domains to the search list
798 range
= CFStringFind(options
, CFSTR("interface="), 0);
799 if (range
.location
!= kCFNotFound
) {
800 // don't add scoped resolver domains to the search list
805 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
806 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
807 if (supplementalDomain
== NULL
) {
811 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomainsNoSearch
);
812 if (isA_CFNumber(num
) &&
813 CFNumberGetValue(num
, kCFNumberIntType
, &noSearch
) &&
815 CFRelease(supplementalDomain
);
819 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
820 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
821 CFRelease(supplementalDomain
);
825 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
826 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
829 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
830 if (!isA_CFNumber(num
) ||
831 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &supplementalOrder
)) {
832 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
835 if (supplementalOrder
< defaultOrder
) {
836 if (domainIndex
!= kCFNotFound
) {
837 // if supplemental domain is already in the search list
838 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
839 if (domainIndex
< defaultSearchIndex
) {
840 defaultSearchIndex
--;
843 CFArrayInsertValueAtIndex(mySearchDomains
,
846 defaultSearchIndex
++;
848 if (domainIndex
== kCFNotFound
) {
849 // add to the (end of the) search list
850 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
854 CFRelease(supplementalDomain
);
856 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
858 // update the "search" domains
859 if (CFArrayGetCount(mySearchDomains
) == 0) {
860 CFRelease(mySearchDomains
);
861 mySearchDomains
= NULL
;
864 // remove the "domain" name and "search" list
865 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
866 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
868 return mySearchDomains
;
873 add_scoped_resolvers(CFMutableArrayRef scoped
,
874 CFDictionaryRef services
,
875 CFArrayRef service_order
)
877 const void * keys_q
[N_QUICK
];
878 const void ** keys
= keys_q
;
882 CFMutableArrayRef order
;
883 CFMutableSetRef seen
;
885 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
886 if (n_services
== 0) {
887 return; // if no services
890 // ensure that we process all services in order
892 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
894 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
896 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
899 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
900 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
902 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
903 for (i
= 0; i
< n_services
; i
++) {
904 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
906 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
907 CFArrayAppendValue(order
, serviceID
);
911 if (keys
!= keys_q
) {
912 CFAllocatorDeallocate(NULL
, keys
);
915 // iterate over services
917 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
918 for (i
= 0; i
< n_order
; i
++) {
920 uint32_t dns_resolver_flags
;
921 char if_name
[IF_NAMESIZE
];
922 CFStringRef interface
;
923 CFMutableDictionaryRef newDNS
;
925 CFArrayRef searchDomains
;
926 CFDictionaryRef service
;
927 CFStringRef serviceID
;
930 serviceID
= CFArrayGetValueAtIndex(order
, i
);
931 service
= CFDictionaryGetValue(services
, serviceID
);
932 if (!isA_CFDictionary(service
)) {
937 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
938 if (!isA_CFDictionary(dns
)) {
943 servers
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
944 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) {
945 // if no DNS server addresses
949 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
950 if ((interface
== NULL
) || CFEqual(interface
, CFSTR("*"))) {
951 // if no [scoped] interface or supplemental configuration w/match-all
955 if (CFDictionaryContainsKey(dns
, kSCPropNetDNSServiceIdentifier
)) {
956 // if this is a service-specific resolver
960 if (CFSetContainsValue(seen
, interface
)) {
961 // if we've already processed this [scoped] interface
964 CFSetSetValue(seen
, interface
);
966 if ((_SC_cfstring_to_cstring(interface
,
969 kCFStringEncodingASCII
) == NULL
) ||
970 (my_if_nametoindex(if_name
) == 0)) {
971 // if interface index not available
975 // add [scoped] resolver entry
976 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
979 searchDomains
= extract_search_domains(newDNS
, NULL
);
980 if (searchDomains
!= NULL
) {
981 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
982 CFRelease(searchDomains
);
985 // get "Request A/AAAA query" flag(s)
986 dns_resolver_flags
= dns_resolver_flags_service(service
, 0);
987 if (dns_resolver_flags
== 0) {
991 // set "scoped" configuration flag
992 newFlags
= DNS_RESOLVER_FLAGS_SCOPED
;
994 // add "Request A/AAAA query" flag(s)
995 newFlags
|= dns_resolver_flags
;
997 merge_configuration_flags(newDNS
, newFlags
);
999 // remove keys we don't want in a [scoped] resolver
1000 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
1001 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
1003 // add the [scoped] resolver
1004 add_resolver_signature(newDNS
, "Scoped", serviceID
, 0);
1005 add_resolver(scoped
, newDNS
);
1007 // add any supplemental resolver configurations for this interface
1008 add_supplemental_resolvers(scoped
, services
, service_order
, interface
, service
);
1021 add_service_specific_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
)
1024 CFStringRef keys_q
[N_QUICK
];
1025 CFStringRef
*keys
= keys_q
;
1027 CFMutableSetRef seen
;
1028 CFDictionaryRef vals_q
[N_QUICK
];
1029 CFDictionaryRef
*vals
= vals_q
;
1031 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
1032 if (n_services
== 0) {
1033 return; // if no services
1036 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(keys_q
[0]))) {
1037 keys
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(keys
[0]), 0);
1038 vals
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(vals
[0]), 0);
1040 CFDictionaryGetKeysAndValues(services
, (const void **)keys
, (const void **)vals
);
1042 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1043 for (i
= 0; i
< n_services
; i
++) {
1044 CFDictionaryRef dns
;
1045 CFNumberRef dns_service_identifier
;
1046 CFMutableDictionaryRef newDNS
;
1047 uint32_t newFlags
= 0;
1048 CFDictionaryRef service
= vals
[i
];
1049 CFStringRef serviceID
= keys
[i
];
1050 CFArrayRef searchDomains
;
1052 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
1053 if (!isA_CFDictionary(dns
)) {
1058 dns_service_identifier
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1059 if (!isA_CFNumber(dns_service_identifier
)) {
1060 // if no DNS [vpn] Service Identifier
1064 if (CFSetContainsValue(seen
, dns_service_identifier
)) {
1065 my_log(LOG_ERR
, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
1068 CFSetSetValue(seen
, dns_service_identifier
);
1070 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1072 // add "Request A/AAAA query" flag(s)
1073 newFlags
|= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
1076 searchDomains
= extract_search_domains(newDNS
, NULL
);
1077 if (searchDomains
!= NULL
) {
1078 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
1079 CFRelease(searchDomains
);
1080 searchDomains
= NULL
;
1083 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
1084 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
1086 if (CFDictionaryContainsKey(newDNS
, kSCPropInterfaceName
)) {
1087 CFMutableDictionaryRef interfaceScopedDNS
;
1088 uint32_t interfaceScopedFlags
;
1090 // The dictionary has an interface, so add a interface-scoped resolver
1092 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
);
1094 interfaceScopedDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, newDNS
);
1095 interfaceScopedFlags
= newFlags
;
1097 // set "scoped" configuration flag
1098 interfaceScopedFlags
|= DNS_RESOLVER_FLAGS_SCOPED
;
1099 merge_configuration_flags(interfaceScopedDNS
, interfaceScopedFlags
);
1101 CFDictionaryRemoveValue(interfaceScopedDNS
, kSCPropNetDNSServiceIdentifier
);
1103 add_resolver_signature(interfaceScopedDNS
, "Service", serviceID
, 0);
1104 add_resolver(resolvers
, interfaceScopedDNS
);
1105 CFRelease(interfaceScopedDNS
);
1108 // set "service specific" configuration flag
1109 newFlags
|= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
;
1110 merge_configuration_flags(newDNS
, newFlags
);
1112 add_resolver_signature(newDNS
, "Service", serviceID
, 0);
1113 add_resolver(resolvers
, newDNS
);
1118 if (keys
!= keys_q
) {
1119 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
);
1120 CFAllocatorDeallocate(kCFAllocatorDefault
, vals
);
1128 add_default_resolver(CFMutableArrayRef resolvers
,
1129 CFDictionaryRef defaultResolver
,
1130 Boolean
*orderAdded
,
1131 CFArrayRef
*searchDomains
)
1133 CFMutableDictionaryRef myDefault
;
1134 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
1137 if (defaultResolver
== NULL
) {
1138 myDefault
= CFDictionaryCreateMutable(NULL
,
1140 &kCFTypeDictionaryKeyCallBacks
,
1141 &kCFTypeDictionaryValueCallBacks
);
1143 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
1145 assert(myDefault
!= NULL
);
1147 // ensure that the default resolver has a search order
1149 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
1150 if (!isA_CFNumber(order
) ||
1151 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) {
1152 myOrder
= DEFAULT_SEARCH_ORDER
;
1153 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
1154 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
1159 // extract the "search" domain list for the default resolver (and
1160 // any supplemental resolvers)
1162 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
1164 // add the default resolver
1166 add_resolver_signature(myDefault
, "Default", NULL
, 0);
1167 add_resolver(resolvers
, myDefault
);
1168 CFRelease(myDefault
);
1173 static dns_create_resolver_t
1174 create_resolver(CFDictionaryRef dns
)
1178 dns_create_resolver_t _resolver
;
1180 CFStringRef targetInterface
= NULL
;
1181 unsigned int targetInterfaceIndex
= 0;
1183 _resolver
= _dns_resolver_create();
1186 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
1187 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1188 char domain
[NS_MAXDNAME
];
1190 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
1191 _dns_resolver_set_domain(&_resolver
, domain
);
1195 // process search domains
1196 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
1197 if (isA_CFArray(list
)) {
1199 CFIndex n
= CFArrayGetCount(list
);
1201 // add "search" domains
1202 for (i
= 0; i
< n
; i
++) {
1203 str
= CFArrayGetValueAtIndex(list
, i
);
1204 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1205 char search
[NS_MAXDNAME
];
1207 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
1208 _dns_resolver_add_search(&_resolver
, search
);
1214 // process interface index
1215 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
1216 if (isA_CFNumber(num
)) {
1219 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
1221 const char *if_name
= NULL
;
1223 if (if_index
!= 0) {
1224 if_name
= my_if_indextoname(if_index
, buf
);
1225 if (if_name
!= NULL
) {
1226 targetInterface
= CFStringCreateWithCString(NULL
,
1228 kCFStringEncodingASCII
);
1229 targetInterfaceIndex
= if_index
;
1233 _dns_resolver_set_if_index(&_resolver
, if_index
, if_name
);
1238 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1239 if (isA_CFNumber(num
)) {
1242 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1243 _dns_resolver_set_flags(&_resolver
, flags
);
1247 // process nameserver addresses
1248 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1249 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
1250 if (isA_CFArray(list
)) {
1252 CFIndex n
= CFArrayGetCount(list
);
1254 for (i
= 0; i
< n
; i
++) {
1257 struct sockaddr_in sin
;
1258 struct sockaddr_in6 sin6
;
1262 str
= CFArrayGetValueAtIndex(list
, i
);
1263 if (!isA_CFString(str
)) {
1267 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1271 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
1275 if ((addr
.sa
.sa_family
== AF_INET6
) &&
1276 IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) &&
1277 (addr
.sin6
.sin6_scope_id
== 0) &&
1278 (targetInterfaceIndex
!= 0)) {
1279 // for link local [IPv6] addresses, if the scope id is not
1280 // set then we should use the interface associated with the
1281 // resolver configuration
1282 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
1285 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
1289 // process search order
1290 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
1291 if (isA_CFNumber(num
)) {
1294 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) {
1295 _dns_resolver_set_order(&_resolver
, order
);
1300 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
1301 if (isA_CFArray(list
)) {
1303 CFIndex n
= CFArrayGetCount(list
);
1305 for (i
= 0; i
< n
; i
++) {
1308 dns_sortaddr_t sortaddr
;
1310 str
= CFArrayGetValueAtIndex(list
, i
);
1311 if (!isA_CFString(str
)) {
1315 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1319 slash
= strchr(buf
, '/');
1320 if (slash
!= NULL
) {
1324 bzero(&sortaddr
, sizeof(sortaddr
));
1325 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
1326 /* if address not valid */
1330 if (slash
!= NULL
) {
1331 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1332 /* if subnet mask not valid */
1339 a
= ntohl(sortaddr
.address
.s_addr
);
1342 } else if (IN_CLASSB(a
)) {
1344 } else if (IN_CLASSC(a
)) {
1350 sortaddr
.mask
.s_addr
= htonl(m
);
1353 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1358 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1359 if (isA_CFNumber(num
)) {
1362 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1363 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1368 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1369 if (isA_CFNumber(num
)) {
1372 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1373 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1378 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1379 if (isA_CFString(str
)) {
1382 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1383 if (options
!= NULL
) {
1384 _dns_resolver_set_options(&_resolver
, options
);
1385 CFAllocatorDeallocate(NULL
, options
);
1389 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1390 if (isA_CFNumber(num
)) {
1391 int dns_service_identifier
;
1393 if (CFNumberGetValue(num
, kCFNumberIntType
, &dns_service_identifier
)) {
1394 _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)dns_service_identifier
);
1398 // process configuration ID
1399 str
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_CONFIGURATION_ID
);
1400 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1403 cID
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1405 _dns_resolver_set_configuration_identifier(&_resolver
, cID
);
1406 CFAllocatorDeallocate(NULL
, cID
);
1410 if (targetInterface
!= NULL
) {
1411 CFRelease(targetInterface
);
1418 static __inline__ Boolean
1419 isScopedConfiguration(CFDictionaryRef dns
)
1424 if ((dns
!= NULL
) &&
1425 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1427 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1428 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1437 static CFComparisonResult
1438 compareDomain(const void *val1
, const void *val2
, void *context
)
1440 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1441 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1442 CFStringRef domain1
;
1443 CFStringRef domain2
;
1444 CFArrayRef labels1
= NULL
;
1445 CFArrayRef labels2
= NULL
;
1448 CFComparisonResult result
;
1454 // "default" domains sort before "supplemental" domains
1455 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1456 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1457 if (domain1
== NULL
) {
1458 return kCFCompareLessThan
;
1459 } else if (domain2
== NULL
) {
1460 return kCFCompareGreaterThan
;
1463 // sort non-scoped before scoped
1464 scoped1
= isScopedConfiguration(dns1
);
1465 scoped2
= isScopedConfiguration(dns2
);
1466 if (scoped1
!= scoped2
) {
1468 return kCFCompareLessThan
;
1470 return kCFCompareGreaterThan
;
1474 // forward (A, AAAA) domains sort before reverse (PTR) domains
1475 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1476 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1479 return kCFCompareGreaterThan
;
1481 return kCFCompareLessThan
;
1485 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1486 n1
= CFArrayGetCount(labels1
);
1488 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1489 n2
= CFArrayGetCount(labels2
);
1491 while ((n1
> 0) && (n2
> 0)) {
1492 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1493 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1495 // compare domain labels
1496 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1497 if (result
!= kCFCompareEqualTo
) {
1502 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1504 result
= kCFCompareLessThan
;
1506 } else if (n1
< n2
) {
1507 result
= kCFCompareGreaterThan
;
1511 // sort by search order
1512 result
= compareBySearchOrder(val1
, val2
, context
);
1516 if (labels1
!= NULL
) CFRelease(labels1
);
1517 if (labels2
!= NULL
) CFRelease(labels2
);
1522 static __inline__ Boolean
1523 needsMergeWithDefaultConfiguration(CFDictionaryRef dns
)
1528 if ((dns
!= NULL
) &&
1529 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1531 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1533 // check if merge needed (at all)
1534 if (dns_resolver_flags_all_queries(flags
)) {
1535 // if we are already querying for both A/AAAA
1539 // check if scoped or service-specific
1540 if (((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0) ||
1541 ((flags
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
) != 0)) {
1553 dns_configuration_set(CFDictionaryRef defaultResolver
,
1554 CFDictionaryRef services
,
1555 CFArrayRef serviceOrder
,
1556 CFArrayRef multicastResolvers
,
1557 CFArrayRef privateResolvers
)
1559 dns_create_config_t dns_create_config
;
1560 Boolean changed
= FALSE
;
1562 CFMutableDictionaryRef myDefault
;
1563 Boolean myOrderAdded
= FALSE
;
1564 CFArrayRef mySearchDomains
= NULL
;
1565 CFIndex n_resolvers
;
1566 CFMutableArrayRef resolvers
;
1567 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1568 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1570 // establish list of resolvers
1572 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1573 assert(resolvers
!= NULL
);
1575 // collect (and add) any "supplemental" resolver configurations
1577 add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
);
1579 // collect (and add) any "private" resolver configurations
1581 add_private_resolvers(resolvers
, privateResolvers
);
1583 // add the "default" resolver
1585 if (defaultResolver
!= NULL
) {
1588 servers
= CFDictionaryGetValue(defaultResolver
, kSCPropNetDNSServerAddresses
);
1589 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) {
1590 // if no DNS server addresses
1591 defaultResolver
= NULL
;
1595 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1597 // collect (and add) any "multicast" resolver configurations
1599 add_multicast_resolvers(resolvers
, multicastResolvers
);
1601 // collect (and add) any "scoped" resolver configurations
1603 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1605 // collect (and add) any "service-specific" resolver configurations
1607 add_service_specific_resolvers(resolvers
, services
);
1611 n_resolvers
= CFArrayGetCount(resolvers
);
1612 if (n_resolvers
> 1) {
1613 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1618 for (i
= n_resolvers
; --i
> 0; ) {
1619 CFDictionaryRef resolver
;
1621 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1622 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1623 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1624 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1625 // remove empty resolver
1626 CFArrayRemoveValueAtIndex(resolvers
, i
);
1631 // update the default resolver
1633 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1635 CFArrayGetValueAtIndex(resolvers
, 0));
1636 if (mySearchDomains
!= NULL
) {
1637 // add search domains to the default resolver
1638 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1639 CFRelease(mySearchDomains
);
1641 if (myOrderAdded
&& (n_resolvers
> 1)) {
1642 CFDictionaryRef resolver
;
1644 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1645 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1646 isScopedConfiguration(resolver
)) {
1647 // if not a supplemental "default" resolver (a domain name is
1648 // present) or if it's a scoped configuration
1649 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1652 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1653 CFRelease(myDefault
);
1655 // establish resolver configuration
1657 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1659 * if no default and no supplemental/scoped resolvers
1661 dns_create_config
= NULL
;
1663 uint32_t default_resolver_flags
= 0;
1664 Boolean have_default_flags
= FALSE
;
1667 * if default and/or supplemental/scoped resolvers are defined
1669 dns_create_config
= _dns_configuration_create();
1671 for (i
= 0; i
< n_resolvers
; i
++) {
1672 Boolean merge_default_flags
;
1673 CFDictionaryRef resolver
;
1674 dns_create_resolver_t _resolver
;
1676 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1678 merge_default_flags
= needsMergeWithDefaultConfiguration(resolver
);
1679 if (merge_default_flags
) {
1680 CFMutableDictionaryRef new_resolver
;
1682 if (!have_default_flags
) {
1683 CFDictionaryApplyFunction(services
,
1684 add_dns_resolver_flags
,
1685 &default_resolver_flags
);
1686 have_default_flags
= TRUE
;
1689 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
);
1690 merge_configuration_flags(new_resolver
, default_resolver_flags
);
1691 resolver
= new_resolver
;
1694 _resolver
= create_resolver(resolver
);
1695 _dns_configuration_add_resolver(&dns_create_config
, _resolver
);
1696 _dns_resolver_free(&_resolver
);
1698 if (merge_default_flags
) {
1699 CFRelease(resolver
);
1703 #if !TARGET_OS_IPHONE
1704 // add flatfile resolvers
1706 _dnsinfo_flatfile_set_flags(default_resolver_flags
);
1707 _dnsinfo_flatfile_add_resolvers(&dns_create_config
);
1708 #endif // !TARGET_OS_IPHONE
1711 // check if the configuration changed
1712 _dns_configuration_signature(&dns_create_config
, signature
, sizeof(signature
));
1713 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1714 // save [new] signature
1715 bcopy(signature
, signature_last
, sizeof(signature
));
1717 my_log(LOG_INFO
, "Updating DNS configuration");
1718 if (dns_create_config
!= NULL
) {
1719 dns_config_t
*dns_config
= NULL
;
1720 _dns_config_buf_t
*dns_config_buf
;
1723 n
= sizeof(_dns_config_buf_t
);
1724 n
+= ntohl(((_dns_config_buf_t
*)dns_create_config
)->n_attribute
);
1725 dns_config_buf
= _dns_configuration_buffer_create((void *)dns_create_config
, n
);
1726 if (dns_config_buf
!= NULL
) {
1727 dns_config
= _dns_configuration_buffer_expand(dns_config_buf
);
1728 if (dns_config
== NULL
) {
1729 // if we were unable to expand the configuration
1730 _dns_configuration_buffer_free(&dns_config_buf
);
1734 if (dns_config
!= NULL
) {
1735 _dns_configuration_log(dns_config
, TRUE
, NULL
);
1739 my_log(LOG_INFO
, "*** No DNS configuration");
1742 // save [new] configuration
1743 if (!_dns_configuration_store(&dns_create_config
)) {
1744 my_log(LOG_ERR
, "could not store configuration");
1751 if (dns_create_config
!= NULL
) {
1752 _dns_configuration_free(&dns_create_config
);
1755 CFRelease(resolvers
);
1760 #if !TARGET_OS_IPHONE
1761 static SCDynamicStoreRef dns_configuration_store
;
1762 static SCDynamicStoreCallBack dns_configuration_callout
;
1765 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1767 #pragma unused(port)
1769 #pragma unused(size)
1770 #pragma unused(info)
1771 os_activity_t activity
;
1772 static const CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1774 Boolean resolvers_now
;
1775 static Boolean resolvers_save
= FALSE
;
1776 struct stat statbuf
;
1778 activity
= os_activity_create("processing DNS configuration change",
1779 OS_ACTIVITY_CURRENT
,
1780 OS_ACTIVITY_FLAG_DEFAULT
);
1781 os_activity_scope(activity
);
1783 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1784 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1785 // if we did not (and still do not) have an "/etc/resolvers"
1786 // directory than this notification is the result of a change
1787 // to the "/etc" directory.
1790 resolvers_save
= resolvers_now
;
1792 my_log(LOG_INFO
, _PATH_RESOLVER_DIR
" changed");
1794 // fake a "DNS" change
1795 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1796 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1801 os_release(activity
);
1809 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1812 mach_port_t notify_port
;
1814 CFRunLoopSourceRef rls
;
1817 dns_configuration_store
= store
;
1818 dns_configuration_callout
= callout
;
1820 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1821 if (status
!= NOTIFY_STATUS_OK
) {
1822 my_log(LOG_ERR
, "notify_register_mach_port() failed");
1826 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1827 if (status
!= NOTIFY_STATUS_OK
) {
1828 my_log(LOG_ERR
, "notify_monitor_file() failed");
1829 (void)notify_cancel(notify_token
);
1833 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1835 dns_configuration_changed
,
1838 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1840 my_log(LOG_ERR
, "SCDynamicStoreCreateRunLoopSource() failed");
1842 (void)notify_cancel(notify_token
);
1845 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1851 #endif // !TARGET_OS_IPHONE
1856 dns_configuration_init(CFBundleRef bundle
)
1858 CFDictionaryRef dict
;
1860 dict
= CFBundleGetInfoDictionary(bundle
);
1861 if (isA_CFDictionary(dict
)) {
1862 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1863 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1865 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1866 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1874 #pragma mark Standalone test code
1880 split(const void * key
, const void * value
, void * context
)
1882 CFArrayRef components
;
1883 CFStringRef entity_id
;
1884 CFStringRef service_id
;
1885 CFMutableDictionaryRef state_dict
;
1887 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1888 service_id
= CFArrayGetValueAtIndex(components
, 3);
1889 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1890 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1891 if (state_dict
!= NULL
) {
1892 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1894 state_dict
= CFDictionaryCreateMutable(NULL
,
1896 &kCFTypeDictionaryKeyCallBacks
,
1897 &kCFTypeDictionaryValueCallBacks
);
1900 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1901 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1902 CFDictionaryRef dict
;
1903 CFStringRef interface
;
1905 if (CFEqual(entity_id
, kSCEntNetIPv4
)) {
1906 dict
= ipv4_dict_create(value
);
1909 dict
= ipv6_dict_create(value
);
1912 CFDictionarySetValue(state_dict
, entity_id
, dict
);
1915 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1916 if (interface
!= NULL
) {
1917 CFDictionaryRef dns
;
1918 CFMutableDictionaryRef new_dns
;
1920 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1922 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1924 new_dns
= CFDictionaryCreateMutable(NULL
,
1926 &kCFTypeDictionaryKeyCallBacks
,
1927 &kCFTypeDictionaryValueCallBacks
);
1929 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1930 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1933 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1934 CFDictionaryRef dns
;
1936 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1938 CFStringRef interface
;
1940 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1941 if (interface
!= NULL
) {
1942 CFMutableDictionaryRef new_dns
;
1944 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1945 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1946 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1949 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1952 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1955 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1958 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1959 CFRelease(state_dict
);
1960 CFRelease(components
);
1966 main(int argc
, char **argv
)
1968 CFDictionaryRef entities
;
1970 CFArrayRef multicast_resolvers
;
1971 CFStringRef pattern
;
1972 CFMutableArrayRef patterns
;
1973 CFStringRef primary
= NULL
;
1974 CFDictionaryRef primaryDNS
= NULL
;
1975 CFArrayRef private_resolvers
;
1976 CFArrayRef service_order
= NULL
;
1977 CFMutableDictionaryRef service_state_dict
;
1978 CFDictionaryRef setup_global_ipv4
;
1979 CFDictionaryRef state_global_ipv4
;
1980 SCDynamicStoreRef store
;
1984 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1986 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1988 // get IPv4, IPv6, and DNS entities
1989 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1990 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1991 kSCDynamicStoreDomainState
,
1994 CFArrayAppendValue(patterns
, pattern
);
1996 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1997 kSCDynamicStoreDomainState
,
2000 CFArrayAppendValue(patterns
, pattern
);
2002 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
2003 kSCDynamicStoreDomainState
,
2006 CFArrayAppendValue(patterns
, pattern
);
2008 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
2009 CFRelease(patterns
);
2011 service_state_dict
= CFDictionaryCreateMutable(NULL
,
2013 &kCFTypeDictionaryKeyCallBacks
,
2014 &kCFTypeDictionaryValueCallBacks
);
2015 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
2016 CFRelease(entities
);
2018 // get primary service ID
2019 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2020 kSCDynamicStoreDomainState
,
2022 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
2024 if (state_global_ipv4
!= NULL
) {
2025 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
2026 if (primary
!= NULL
) {
2027 CFDictionaryRef service_dict
;
2029 // get DNS configuration for primary service
2030 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
2031 if (service_dict
!= NULL
) {
2032 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
2038 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2039 kSCDynamicStoreDomainSetup
,
2041 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
2043 if (setup_global_ipv4
!= NULL
) {
2044 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
2047 // get multicast resolvers
2048 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
2049 kSCDynamicStoreDomainState
,
2051 CFSTR(kDNSServiceCompMulticastDNS
));
2052 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
2055 // get private resolvers
2056 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
2057 kSCDynamicStoreDomainState
,
2059 CFSTR(kDNSServiceCompPrivateDNS
));
2060 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
2063 // update DNS configuration
2064 dns_configuration_init(CFBundleGetMainBundle());
2065 (void)dns_configuration_set(primaryDNS
,
2068 multicast_resolvers
,
2072 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
2073 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
2074 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
2075 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
2076 CFRelease(service_state_dict
);