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_private.h"
60 #include "dnsinfo_internal.h"
61 #include "dnsinfo_create.h"
62 #include "dnsinfo_server.h"
64 #include <network_information.h>
67 #include <dns_sd_private.h>
69 #define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
70 #define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
71 #define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
73 /* multicast DNS resolver configurations */
74 static CFNumberRef S_mdns_timeout
= NULL
;
76 /* private DNS resolver configurations */
77 static CFNumberRef S_pdns_timeout
= NULL
;
81 #pragma mark DNS resolver flags
84 static __inline__ boolean_t
85 dns_resolver_flags_all_queries(uint32_t query_flags
)
87 return ((query_flags
& DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
) == DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
);
94 dns_resolver_flags_service(CFDictionaryRef service
, uint32_t resolver_flags
)
97 // check if the service has v4 configured
98 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
) == 0) &&
99 service_contains_protocol(service
, AF_INET
)) {
100 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
;
103 // check if the service has v6 configured
104 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
) == 0) &&
105 service_contains_protocol(service
, AF_INET6
)) {
106 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
;
109 return resolver_flags
;
114 add_dns_resolver_flags(const void *key
, const void *value
, void *context
)
116 CFDictionaryRef service
= (CFDictionaryRef
)value
;
117 // CFStringRef serviceID = (CFStringRef)key;
118 uint32_t *resolver_flags
= (uint32_t *)context
;
120 if (service_is_scoped_only(service
)) {
124 // update resovler flags based on configured (and available) protocols
125 *resolver_flags
= dns_resolver_flags_service(service
, *resolver_flags
);
131 #pragma mark DNS resolver configuration
135 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
)
138 CFStringRef interface
;
141 uint32_t order_val
= 0;
143 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
144 if (!isA_CFNumber(order
) ||
145 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &order_val
)) {
150 n_resolvers
= CFArrayGetCount(resolvers
);
151 for (i
= 0; i
< n_resolvers
; i
++) {
152 CFDictionaryRef match_resolver
;
154 match_resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
155 if (CFEqual(resolver
, match_resolver
)) {
161 CFMutableDictionaryRef compare
;
164 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
);
165 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
166 match
= CFEqual(resolver
, compare
);
169 CFNumberRef match_order
;
170 uint32_t match_order_val
= 0;
172 // if only the search order's are different
173 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
174 if (!isA_CFNumber(match_order
) ||
175 !CFNumberGetValue(match_order
, kCFNumberSInt32Type
, &match_order_val
)) {
179 if (order_val
< match_order_val
) {
180 // if we should prefer this match resolver, else just skip it
181 CFArraySetValueAtIndex(resolvers
, i
, resolver
);
189 order
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_resolvers
);
190 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_ORDER_KEY
, order
);
193 interface
= CFDictionaryGetValue(resolver
, kSCPropInterfaceName
);
194 if ((interface
!= NULL
) && !CFEqual(interface
, CFSTR("*"))) {
196 unsigned int if_index
= 0;
197 char if_name
[IF_NAMESIZE
];
201 if (_SC_cfstring_to_cstring(interface
,
204 kCFStringEncodingASCII
) != NULL
) {
205 if_index
= my_if_nametoindex(if_name
);
208 if ((if_index
!= 0) &&
210 // check if this is a "scoped" configuration
211 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
213 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
214 (flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)
216 // check if we should scope all queries with this configuration
217 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
218 isA_CFBoolean(val
) &&
219 CFBooleanGetValue(val
))
222 // if interface index available and it should be used
223 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
);
224 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_IF_INDEX_KEY
, num
);
229 CFArrayAppendValue(resolvers
, resolver
);
234 #define DNS_CONFIGURATION_CONFIGURATION_ID CFSTR("__CONFIGURATION_ID__")
238 add_resolver_signature(CFMutableDictionaryRef resolver
, const char *rType
, CFStringRef cID
, CFIndex rIndex
)
242 str
= CFStringCreateWithFormat(NULL
, NULL
,
243 CFSTR("%s:%s%@ %ld"),
245 (cID
!= NULL
) ? " " : "",
246 (cID
!= NULL
) ? cID
: CFSTR(""),
248 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_CONFIGURATION_ID
, str
);
256 add_supplemental(CFMutableArrayRef resolvers
,
257 CFStringRef serviceID
,
259 uint32_t defaultOrder
,
268 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
269 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
270 if (n_domains
== 0) {
271 // if no supplemental match domains
275 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
276 if (orders
!= NULL
) {
277 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
278 // if supplemental match orders... but too many/not enough
283 servers
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
284 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) {
285 // if no DNS server addresses
290 * yes, this is a "supplemental" resolver configuration, expand
291 * the match domains and add each to the resolvers list.
293 for (i
= 0; i
< n_domains
; i
++) {
294 CFStringRef match_domain
;
295 CFNumberRef match_order
;
296 CFMutableDictionaryRef match_resolver
;
298 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
299 if (!isA_CFString(match_domain
)) {
303 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
305 // set supplemental resolver "domain"
306 if (CFStringGetLength(match_domain
) > 0) {
307 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
309 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
312 // set supplemental resolver "search_order"
313 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
314 if (isA_CFNumber(match_order
)) {
315 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
316 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
319 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
320 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
323 defaultOrder
++; // if multiple domains, maintain ordering
326 // remove keys we don't want in a supplemental resolver
327 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
328 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
329 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
330 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
332 add_resolver_signature(match_resolver
,
333 scoped
? "Supplemental/Scoped" : "Supplemental",
336 add_resolver(resolvers
, match_resolver
);
337 CFRelease(match_resolver
);
348 merge_configuration_flags(CFMutableDictionaryRef newDNS
, uint32_t mergeFlags
)
353 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
354 !isA_CFNumber(num
) ||
355 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
361 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
362 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
370 add_supplemental_resolvers(CFMutableArrayRef resolvers
,
371 CFDictionaryRef services
,
372 CFArrayRef service_order
,
373 CFStringRef scoped_interface
,
374 CFDictionaryRef scoped_service
)
376 const void * keys_q
[N_QUICK
];
377 const void ** keys
= keys_q
;
381 const void * vals_q
[N_QUICK
];
382 const void ** vals
= vals_q
;
384 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
385 if (n_services
== 0) {
386 return; // if no services
389 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
390 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
391 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
394 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
396 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
397 for (i
= 0; i
< n_services
; i
++) {
398 uint32_t defaultOrder
;
400 uint32_t dns_resolver_flags
;
401 CFStringRef interface
;
402 CFMutableDictionaryRef newDNS
= NULL
;
404 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
405 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
406 Boolean trusted
= FALSE
; // trusted config w/interface
408 if (!isA_CFDictionary(service
)) {
412 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
413 dns
= isA_CFDictionary(dns
);
418 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
420 if (scoped_interface
!= NULL
) {
422 // we only want to add split/supplemental configurations
423 // for queries scoped to an interface if they are NOT
424 // associated with a "real" service
426 if (CFDictionaryContainsKey(service
, kSCEntNetIPv4
) ||
427 CFDictionaryContainsKey(service
, kSCEntNetIPv6
)) {
432 // in addition, we don't want to add split/supplemental
433 // configurations for queries scoped to an interface if
434 // the configuration does not apply to all interfaces and
435 // the configuration is explicitly NOT for this interface
437 if (!_SC_CFEqual(interface
, CFSTR("*")) &&
438 !_SC_CFEqual(interface
, scoped_interface
)) {
443 // lastly, check if A/AAAA queries should be issued (based
444 // on the IP[v6] addresses). If we would not be issuing a
445 // query then don't bother adding the configuration.
447 dns_resolver_flags
= dns_resolver_flags_service(scoped_service
, 0);
448 if (dns_resolver_flags
== 0) {
453 defaultOrder
= DEFAULT_SEARCH_ORDER
454 - (DEFAULT_SEARCH_ORDER
/ 2)
455 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
457 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
458 // push out services not specified in service order
459 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
463 * Ensure that we have the correct InterfaceName in the DNS configuration
465 * scoped_interface [supplemental] interface Trusted config DNS interface
466 * ================ ======================== ============== =================
467 * NULL NULL No NULL (No change)
470 * NULL NULL Yes NULL (No change)
471 * NULL en0 Yes en0 (trusted config w/interface)
473 * en0 NULL N/A en0 (scoped interface)
474 * en0 en0 N/A en0 (scoped interface)
475 * en0 * N/A en0 (scoped interface)
477 if ((scoped_interface
== NULL
) && (interface
== NULL
)) {
478 newDNS
= (CFMutableDictionaryRef
)CFRetain(dns
);
482 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
483 if (scoped_interface
!= NULL
) {
484 CFDictionarySetValue(newDNS
, kSCPropInterfaceName
, scoped_interface
);
485 } else if ((interface
!= NULL
) &&
486 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
487 isA_CFBoolean(val
) &&
488 CFBooleanGetValue(val
)) {
489 // leave the [trusted configuration] InterfaceName in place
492 CFDictionaryRemoveValue(newDNS
, kSCPropInterfaceName
);
496 // set "supplemental" flag
497 newFlags
= DNS_RESOLVER_FLAGS_SUPPLEMENTAL
;
499 if (scoped_interface
!= NULL
) {
500 // set "scoped" configuration flag
501 newFlags
|= DNS_RESOLVER_FLAGS_SCOPED
;
503 // add "Request A/AAAA query" flag(s)
504 newFlags
|= dns_resolver_flags
;
505 } else if (trusted
) {
506 // use the DNS query flags from the supplemental match service
507 newFlags
|= dns_resolver_flags_service(service
, 0);
510 merge_configuration_flags(newDNS
, newFlags
);
512 // add [scoped] resolver entry
513 add_supplemental(resolvers
, serviceID
, newDNS
, defaultOrder
, (scoped_interface
!= NULL
));
517 if (keys
!= keys_q
) {
518 CFAllocatorDeallocate(NULL
, keys
);
519 CFAllocatorDeallocate(NULL
, vals
);
527 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
532 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
533 for (i
= 0; i
< n
; i
++) {
534 uint32_t defaultOrder
;
537 CFMutableDictionaryRef resolver
;
539 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
540 domain
= _SC_trimDomain(domain
);
541 if (domain
== NULL
) {
545 defaultOrder
= DEFAULT_SEARCH_ORDER
546 + (DEFAULT_SEARCH_ORDER
/ 2)
547 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
549 resolver
= CFDictionaryCreateMutable(NULL
,
551 &kCFTypeDictionaryKeyCallBacks
,
552 &kCFTypeDictionaryValueCallBacks
);
553 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
554 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
555 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
556 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
558 if (S_mdns_timeout
!= NULL
) {
559 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
561 add_resolver_signature(resolver
, "Multicast DNS", NULL
, i
);
562 add_resolver(resolvers
, resolver
);
572 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
577 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
578 for (i
= 0; i
< n
; i
++) {
579 uint32_t defaultOrder
;
582 CFMutableDictionaryRef resolver
;
584 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
585 domain
= _SC_trimDomain(domain
);
586 if (domain
== NULL
) {
590 defaultOrder
= DEFAULT_SEARCH_ORDER
591 - (DEFAULT_SEARCH_ORDER
/ 4)
592 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
594 resolver
= CFDictionaryCreateMutable(NULL
,
596 &kCFTypeDictionaryKeyCallBacks
,
597 &kCFTypeDictionaryValueCallBacks
);
598 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
599 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
600 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
601 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
603 if (S_pdns_timeout
!= NULL
) {
604 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
606 add_resolver_signature(resolver
, "Private DNS", NULL
, i
);
607 add_resolver(resolvers
, resolver
);
616 static CFComparisonResult
617 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
619 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
620 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
623 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
624 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
626 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
627 if (!isA_CFNumber(num1
) ||
628 !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) {
629 order1
= DEFAULT_SEARCH_ORDER
;
632 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
633 if (!isA_CFNumber(num2
) ||
634 !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
635 order2
= DEFAULT_SEARCH_ORDER
;
638 if (order1
== order2
) {
639 // if same "SearchOrder", retain original orderring for configurations
640 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) &&
641 CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) &&
642 isA_CFNumber(num1
) &&
643 isA_CFNumber(num2
) &&
644 CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
) &&
645 CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
646 if (order1
== order2
) {
647 return kCFCompareEqualTo
;
649 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
653 return kCFCompareEqualTo
;
656 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
660 static CF_RETURNS_RETAINED CFArrayRef
661 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
663 CFStringRef defaultDomainName
= NULL
;
664 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
665 CFArrayRef defaultSearchDomains
= NULL
;
666 CFIndex defaultSearchIndex
= 0;
668 CFMutableArrayRef mySearchDomains
;
669 CFMutableArrayRef mySupplemental
= NULL
;
670 CFIndex n_supplemental
;
672 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
674 if (defaultDomain
!= NULL
) {
677 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
678 if (!isA_CFNumber(num
) ||
679 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &defaultOrder
)) {
680 defaultOrder
= DEFAULT_SEARCH_ORDER
;
683 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
684 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
687 // validate the provided "search" domains or move/expand/promote the "domain" name
688 if (isA_CFArray(defaultSearchDomains
)) {
691 n_search
= CFArrayGetCount(defaultSearchDomains
);
692 for (i
= 0; i
< n_search
; i
++) {
695 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
696 search
= _SC_trimDomain(search
);
697 if (search
!= NULL
) {
698 CFArrayAppendValue(mySearchDomains
, search
);
703 defaultDomainName
= _SC_trimDomain(defaultDomainName
);
704 if (defaultDomainName
!= NULL
) {
706 int domain_parts
= 1;
710 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
713 kCFStringEncodingUTF8
);
714 CFRelease(defaultDomainName
);
716 // count domain parts
717 for (dp
= domain
; *dp
!= '\0'; dp
++) {
723 // move "domain" to "search" list (and expand as needed)
724 i
= LOCALDOMAINPARTS
;
730 str
= CFStringCreateWithCString(NULL
,
732 kCFStringEncodingUTF8
);
733 search
= _SC_trimDomain(str
);
735 if (search
!= NULL
) {
736 CFArrayAppendValue(mySearchDomains
, search
);
740 dp
= strchr(dp
, '.') + 1;
741 } while (++i
<= (domain_parts
- ndots
));
742 CFAllocatorDeallocate(NULL
, domain
);
746 // add any supplemental "domain" names to the search list
747 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
748 if (n_supplemental
> 1) {
749 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
750 CFArraySortValues(mySupplemental
,
751 CFRangeMake(0, n_supplemental
),
752 compareBySearchOrder
,
754 supplemental
= mySupplemental
;
756 for (i
= 0; i
< n_supplemental
; i
++) {
762 CFStringRef supplementalDomain
;
763 uint32_t supplementalOrder
;
765 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
767 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
768 if (isA_CFString(options
)) {
771 if (CFEqual(options
, CFSTR("pdns"))) {
772 // don't add private resolver domains to the search list
776 range
= CFStringFind(options
, CFSTR("interface="), 0);
777 if (range
.location
!= kCFNotFound
) {
778 // don't add scoped resolver domains to the search list
783 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
784 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
785 if (supplementalDomain
== NULL
) {
789 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomainsNoSearch
);
790 if (isA_CFNumber(num
) &&
791 CFNumberGetValue(num
, kCFNumberIntType
, &noSearch
) &&
793 CFRelease(supplementalDomain
);
797 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
798 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
799 CFRelease(supplementalDomain
);
803 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
804 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
807 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
808 if (!isA_CFNumber(num
) ||
809 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &supplementalOrder
)) {
810 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
813 if (supplementalOrder
< defaultOrder
) {
814 if (domainIndex
!= kCFNotFound
) {
815 // if supplemental domain is already in the search list
816 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
817 if (domainIndex
< defaultSearchIndex
) {
818 defaultSearchIndex
--;
821 CFArrayInsertValueAtIndex(mySearchDomains
,
824 defaultSearchIndex
++;
826 if (domainIndex
== kCFNotFound
) {
827 // add to the (end of the) search list
828 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
832 CFRelease(supplementalDomain
);
834 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
836 // update the "search" domains
837 if (CFArrayGetCount(mySearchDomains
) == 0) {
838 CFRelease(mySearchDomains
);
839 mySearchDomains
= NULL
;
842 // remove the "domain" name and "search" list
843 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
844 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
846 return mySearchDomains
;
851 add_scoped_resolvers(CFMutableArrayRef scoped
,
852 CFDictionaryRef services
,
853 CFArrayRef service_order
)
855 const void * keys_q
[N_QUICK
];
856 const void ** keys
= keys_q
;
860 CFMutableArrayRef order
;
861 CFMutableSetRef seen
;
863 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
864 if (n_services
== 0) {
865 return; // if no services
868 // ensure that we process all services in order
870 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
872 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
874 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
877 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
878 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
880 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
881 for (i
= 0; i
< n_services
; i
++) {
882 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
884 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
885 CFArrayAppendValue(order
, serviceID
);
889 if (keys
!= keys_q
) {
890 CFAllocatorDeallocate(NULL
, keys
);
893 // iterate over services
895 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
896 for (i
= 0; i
< n_order
; i
++) {
898 uint32_t dns_resolver_flags
;
899 char if_name
[IF_NAMESIZE
];
900 CFStringRef interface
;
901 CFMutableDictionaryRef newDNS
;
903 CFArrayRef searchDomains
;
904 CFDictionaryRef service
;
905 CFStringRef serviceID
;
908 serviceID
= CFArrayGetValueAtIndex(order
, i
);
909 service
= CFDictionaryGetValue(services
, serviceID
);
910 if (!isA_CFDictionary(service
)) {
915 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
916 if (!isA_CFDictionary(dns
)) {
921 servers
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
922 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) {
923 // if no DNS server addresses
927 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
928 if ((interface
== NULL
) || CFEqual(interface
, CFSTR("*"))) {
929 // if no [scoped] interface or supplemental configuration w/match-all
933 if (CFDictionaryContainsKey(dns
, kSCPropNetDNSServiceIdentifier
)) {
934 // if this is a service-specific resolver
938 if (CFSetContainsValue(seen
, interface
)) {
939 // if we've already processed this [scoped] interface
942 CFSetSetValue(seen
, interface
);
944 if ((_SC_cfstring_to_cstring(interface
,
947 kCFStringEncodingASCII
) == NULL
) ||
948 (my_if_nametoindex(if_name
) == 0)) {
949 // if interface index not available
953 // add [scoped] resolver entry
954 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
957 searchDomains
= extract_search_domains(newDNS
, NULL
);
958 if (searchDomains
!= NULL
) {
959 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
960 CFRelease(searchDomains
);
963 // get "Request A/AAAA query" flag(s)
964 dns_resolver_flags
= dns_resolver_flags_service(service
, 0);
965 if (dns_resolver_flags
== 0) {
969 // set "scoped" configuration flag
970 newFlags
= DNS_RESOLVER_FLAGS_SCOPED
;
972 // add "Request A/AAAA query" flag(s)
973 newFlags
|= dns_resolver_flags
;
975 merge_configuration_flags(newDNS
, newFlags
);
977 // remove keys we don't want in a [scoped] resolver
978 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
979 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
981 // add the [scoped] resolver
982 add_resolver_signature(newDNS
, "Scoped", serviceID
, 0);
983 add_resolver(scoped
, newDNS
);
985 // add any supplemental resolver configurations for this interface
986 add_supplemental_resolvers(scoped
, services
, service_order
, interface
, service
);
999 add_service_specific_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
)
1002 CFStringRef keys_q
[N_QUICK
];
1003 CFStringRef
*keys
= keys_q
;
1005 CFMutableSetRef seen
;
1006 CFDictionaryRef vals_q
[N_QUICK
];
1007 CFDictionaryRef
*vals
= vals_q
;
1009 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
1010 if (n_services
== 0) {
1011 return; // if no services
1014 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(keys_q
[0]))) {
1015 keys
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(keys
[0]), 0);
1016 vals
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(vals
[0]), 0);
1018 CFDictionaryGetKeysAndValues(services
, (const void **)keys
, (const void **)vals
);
1020 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1021 for (i
= 0; i
< n_services
; i
++) {
1022 CFDictionaryRef dns
;
1023 CFNumberRef dns_service_identifier
;
1024 CFMutableDictionaryRef newDNS
;
1025 uint32_t newFlags
= 0;
1026 CFDictionaryRef service
= vals
[i
];
1027 CFStringRef serviceID
= keys
[i
];
1029 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
1030 if (!isA_CFDictionary(dns
)) {
1035 dns_service_identifier
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1036 if (!isA_CFNumber(dns_service_identifier
)) {
1037 // if no DNS [vpn] Service Identifier
1041 if (CFSetContainsValue(seen
, dns_service_identifier
)) {
1042 my_log(LOG_ERR
, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
1045 CFSetSetValue(seen
, dns_service_identifier
);
1047 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1049 if (CFDictionaryContainsKey(newDNS
, kSCPropInterfaceName
)) {
1050 CFArrayRef searchDomains
;
1052 // set "scoped" configuration flag
1053 newFlags
|= DNS_RESOLVER_FLAGS_SCOPED
;
1055 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
);
1056 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSServiceIdentifier
);
1059 searchDomains
= extract_search_domains(newDNS
, NULL
);
1060 if (searchDomains
!= NULL
) {
1061 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
1062 CFRelease(searchDomains
);
1065 // set "service specific" configuration flag
1066 newFlags
|= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
;
1069 // add "Request A/AAAA query" flag(s)
1070 newFlags
|= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
1072 merge_configuration_flags(newDNS
, newFlags
);
1074 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
1075 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
1077 add_resolver_signature(newDNS
, "Service", serviceID
, 0);
1078 add_resolver(resolvers
, newDNS
);
1083 if (keys
!= keys_q
) {
1084 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
);
1085 CFAllocatorDeallocate(kCFAllocatorDefault
, vals
);
1093 add_default_resolver(CFMutableArrayRef resolvers
,
1094 CFDictionaryRef defaultResolver
,
1095 Boolean
*orderAdded
,
1096 CFArrayRef
*searchDomains
)
1098 CFMutableDictionaryRef myDefault
;
1099 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
1102 if (defaultResolver
== NULL
) {
1103 myDefault
= CFDictionaryCreateMutable(NULL
,
1105 &kCFTypeDictionaryKeyCallBacks
,
1106 &kCFTypeDictionaryValueCallBacks
);
1108 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
1110 assert(myDefault
!= NULL
);
1112 // ensure that the default resolver has a search order
1114 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
1115 if (!isA_CFNumber(order
) ||
1116 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) {
1117 myOrder
= DEFAULT_SEARCH_ORDER
;
1118 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
1119 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
1124 // extract the "search" domain list for the default resolver (and
1125 // any supplemental resolvers)
1127 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
1129 // add the default resolver
1131 add_resolver_signature(myDefault
, "Default", NULL
, 0);
1132 add_resolver(resolvers
, myDefault
);
1133 CFRelease(myDefault
);
1138 static dns_create_resolver_t
1139 create_resolver(CFDictionaryRef dns
)
1143 dns_create_resolver_t _resolver
;
1145 CFStringRef targetInterface
= NULL
;
1146 unsigned int targetInterfaceIndex
= 0;
1148 _resolver
= _dns_resolver_create();
1151 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
1152 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1153 char domain
[NS_MAXDNAME
];
1155 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
1156 _dns_resolver_set_domain(&_resolver
, domain
);
1160 // process search domains
1161 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
1162 if (isA_CFArray(list
)) {
1164 CFIndex n
= CFArrayGetCount(list
);
1166 // add "search" domains
1167 for (i
= 0; i
< n
; i
++) {
1168 str
= CFArrayGetValueAtIndex(list
, i
);
1169 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1170 char search
[NS_MAXDNAME
];
1172 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
1173 _dns_resolver_add_search(&_resolver
, search
);
1179 // process interface index
1180 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
1181 if (isA_CFNumber(num
)) {
1184 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
1185 char if_name
[IFNAMSIZ
];
1187 _dns_resolver_set_if_index(&_resolver
, if_index
);
1189 if ((if_index
!= 0) &&
1190 (my_if_indextoname(if_index
, if_name
) != NULL
)) {
1191 targetInterface
= CFStringCreateWithCString(NULL
,
1193 kCFStringEncodingASCII
);
1194 targetInterfaceIndex
= if_index
;
1200 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1201 if (isA_CFNumber(num
)) {
1204 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1205 _dns_resolver_set_flags(&_resolver
, flags
);
1209 // process nameserver addresses
1210 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1211 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
1212 if (isA_CFArray(list
)) {
1214 CFIndex n
= CFArrayGetCount(list
);
1216 for (i
= 0; i
< n
; i
++) {
1219 struct sockaddr_in sin
;
1220 struct sockaddr_in6 sin6
;
1224 str
= CFArrayGetValueAtIndex(list
, i
);
1225 if (!isA_CFString(str
)) {
1229 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1233 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
1237 if ((addr
.sa
.sa_family
== AF_INET6
) &&
1238 IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) &&
1239 (addr
.sin6
.sin6_scope_id
== 0) &&
1240 (targetInterfaceIndex
!= 0)) {
1241 // for link local [IPv6] addresses, if the scope id is not
1242 // set then we should use the interface associated with the
1243 // resolver configuration
1244 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
1247 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
1251 // process search order
1252 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
1253 if (isA_CFNumber(num
)) {
1256 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) {
1257 _dns_resolver_set_order(&_resolver
, order
);
1262 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
1263 if (isA_CFArray(list
)) {
1265 CFIndex n
= CFArrayGetCount(list
);
1267 for (i
= 0; i
< n
; i
++) {
1270 dns_sortaddr_t sortaddr
;
1272 str
= CFArrayGetValueAtIndex(list
, i
);
1273 if (!isA_CFString(str
)) {
1277 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1281 slash
= strchr(buf
, '/');
1282 if (slash
!= NULL
) {
1286 bzero(&sortaddr
, sizeof(sortaddr
));
1287 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
1288 /* if address not valid */
1292 if (slash
!= NULL
) {
1293 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1294 /* if subnet mask not valid */
1301 a
= ntohl(sortaddr
.address
.s_addr
);
1304 } else if (IN_CLASSB(a
)) {
1306 } else if (IN_CLASSC(a
)) {
1312 sortaddr
.mask
.s_addr
= htonl(m
);
1315 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1320 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1321 if (isA_CFNumber(num
)) {
1324 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1325 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1330 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1331 if (isA_CFNumber(num
)) {
1334 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1335 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1340 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1341 if (isA_CFString(str
)) {
1344 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1345 if (options
!= NULL
) {
1346 _dns_resolver_set_options(&_resolver
, options
);
1347 CFAllocatorDeallocate(NULL
, options
);
1351 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1352 if (isA_CFNumber(num
)) {
1353 int dns_service_identifier
;
1355 if (CFNumberGetValue(num
, kCFNumberIntType
, &dns_service_identifier
)) {
1356 _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)dns_service_identifier
);
1360 // process configuration ID
1361 str
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_CONFIGURATION_ID
);
1362 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1365 cID
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1367 _dns_resolver_set_configuration_identifier(&_resolver
, cID
);
1368 CFAllocatorDeallocate(NULL
, cID
);
1372 if (targetInterface
!= NULL
) {
1373 CFRelease(targetInterface
);
1380 static __inline__ Boolean
1381 isScopedConfiguration(CFDictionaryRef dns
)
1386 if ((dns
!= NULL
) &&
1387 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1389 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1390 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1399 static CFComparisonResult
1400 compareDomain(const void *val1
, const void *val2
, void *context
)
1402 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1403 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1404 CFStringRef domain1
;
1405 CFStringRef domain2
;
1406 CFArrayRef labels1
= NULL
;
1407 CFArrayRef labels2
= NULL
;
1410 CFComparisonResult result
;
1416 // "default" domains sort before "supplemental" domains
1417 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1418 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1419 if (domain1
== NULL
) {
1420 return kCFCompareLessThan
;
1421 } else if (domain2
== NULL
) {
1422 return kCFCompareGreaterThan
;
1425 // sort non-scoped before scoped
1426 scoped1
= isScopedConfiguration(dns1
);
1427 scoped2
= isScopedConfiguration(dns2
);
1428 if (scoped1
!= scoped2
) {
1430 return kCFCompareLessThan
;
1432 return kCFCompareGreaterThan
;
1436 // forward (A, AAAA) domains sort before reverse (PTR) domains
1437 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1438 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1441 return kCFCompareGreaterThan
;
1443 return kCFCompareLessThan
;
1447 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1448 n1
= CFArrayGetCount(labels1
);
1450 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1451 n2
= CFArrayGetCount(labels2
);
1453 while ((n1
> 0) && (n2
> 0)) {
1454 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1455 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1457 // compare domain labels
1458 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1459 if (result
!= kCFCompareEqualTo
) {
1464 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1466 result
= kCFCompareLessThan
;
1468 } else if (n1
< n2
) {
1469 result
= kCFCompareGreaterThan
;
1473 // sort by search order
1474 result
= compareBySearchOrder(val1
, val2
, context
);
1478 if (labels1
!= NULL
) CFRelease(labels1
);
1479 if (labels2
!= NULL
) CFRelease(labels2
);
1484 static __inline__ Boolean
1485 needsMergeWithDefaultConfiguration(CFDictionaryRef dns
)
1490 if ((dns
!= NULL
) &&
1491 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1493 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1495 // check if merge needed (at all)
1496 if (dns_resolver_flags_all_queries(flags
)) {
1497 // if we are already querying for both A/AAAA
1501 // check if scoped or service-specific
1502 if (((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0) ||
1503 ((flags
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
) != 0)) {
1515 dns_configuration_set(CFDictionaryRef defaultResolver
,
1516 CFDictionaryRef services
,
1517 CFArrayRef serviceOrder
,
1518 CFArrayRef multicastResolvers
,
1519 CFArrayRef privateResolvers
)
1521 dns_create_config_t _config
;
1522 Boolean changed
= FALSE
;
1524 CFMutableDictionaryRef myDefault
;
1525 Boolean myOrderAdded
= FALSE
;
1526 CFArrayRef mySearchDomains
= NULL
;
1527 CFIndex n_resolvers
;
1528 CFMutableArrayRef resolvers
;
1529 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1530 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1532 // establish list of resolvers
1534 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1535 assert(resolvers
!= NULL
);
1537 // collect (and add) any "supplemental" resolver configurations
1539 add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
);
1541 // collect (and add) any "private" resolver configurations
1543 add_private_resolvers(resolvers
, privateResolvers
);
1545 // add the "default" resolver
1547 if (defaultResolver
!= NULL
) {
1550 servers
= CFDictionaryGetValue(defaultResolver
, kSCPropNetDNSServerAddresses
);
1551 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) {
1552 // if no DNS server addresses
1553 defaultResolver
= NULL
;
1557 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1559 // collect (and add) any "multicast" resolver configurations
1561 add_multicast_resolvers(resolvers
, multicastResolvers
);
1563 // collect (and add) any "scoped" resolver configurations
1565 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1567 // collect (and add) any "service-specific" resolver configurations
1569 add_service_specific_resolvers(resolvers
, services
);
1573 n_resolvers
= CFArrayGetCount(resolvers
);
1574 if (n_resolvers
> 1) {
1575 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1580 for (i
= n_resolvers
; --i
> 0; ) {
1581 CFDictionaryRef resolver
;
1583 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1584 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1585 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1586 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1587 // remove empty resolver
1588 CFArrayRemoveValueAtIndex(resolvers
, i
);
1593 // update the default resolver
1595 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1597 CFArrayGetValueAtIndex(resolvers
, 0));
1598 if (mySearchDomains
!= NULL
) {
1599 // add search domains to the default resolver
1600 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1601 CFRelease(mySearchDomains
);
1603 if (myOrderAdded
&& (n_resolvers
> 1)) {
1604 CFDictionaryRef resolver
;
1606 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1607 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1608 isScopedConfiguration(resolver
)) {
1609 // if not a supplemental "default" resolver (a domain name is
1610 // present) or if it's a scoped configuration
1611 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1614 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1615 CFRelease(myDefault
);
1617 // establish resolver configuration
1619 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1621 * if no default and no supplemental/scoped resolvers
1625 uint32_t default_resolver_flags
= 0;
1626 Boolean have_default_flags
= FALSE
;
1629 * if default and/or supplemental/scoped resolvers are defined
1631 _config
= _dns_configuration_create();
1633 for (i
= 0; i
< n_resolvers
; i
++) {
1634 Boolean merge_default_flags
;
1635 CFDictionaryRef resolver
;
1636 dns_create_resolver_t _resolver
;
1638 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1640 merge_default_flags
= needsMergeWithDefaultConfiguration(resolver
);
1641 if (merge_default_flags
) {
1642 CFMutableDictionaryRef new_resolver
;
1644 if (!have_default_flags
) {
1645 CFDictionaryApplyFunction(services
,
1646 add_dns_resolver_flags
,
1647 &default_resolver_flags
);
1648 have_default_flags
= TRUE
;
1651 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
);
1652 merge_configuration_flags(new_resolver
, default_resolver_flags
);
1653 resolver
= new_resolver
;
1656 _resolver
= create_resolver(resolver
);
1657 _dns_configuration_add_resolver(&_config
, _resolver
);
1658 _dns_resolver_free(&_resolver
);
1660 if (merge_default_flags
) {
1661 CFRelease(resolver
);
1665 #if !TARGET_OS_IPHONE
1666 // add flatfile resolvers
1668 _dnsinfo_flatfile_set_flags(default_resolver_flags
);
1669 _dnsinfo_flatfile_add_resolvers(&_config
);
1670 #endif // !TARGET_OS_IPHONE
1673 // check if the configuration changed
1674 _dns_configuration_signature(&_config
, signature
, sizeof(signature
));
1675 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1676 // save [new] signature
1677 bcopy(signature
, signature_last
, sizeof(signature
));
1679 my_log(LOG_INFO
, "Updating DNS configuration");
1680 if (_config
!= NULL
) {
1682 dns_config_t
*config
;
1683 _dns_config_buf_t
*config_buf
;
1687 config_buf
= (_dns_config_buf_t
*)_config
;
1688 n_config
= sizeof(_dns_config_buf_t
) + ntohl(config_buf
->n_attribute
);
1689 n_padding
= ntohl(config_buf
->n_padding
);
1690 buf
= malloc(n_config
+ n_padding
);
1691 bcopy((void *)config_buf
, buf
, n_config
);
1692 bzero(&buf
[n_config
], n_padding
);
1693 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
1694 config
= _dns_configuration_expand_config((_dns_config_buf_t
*)(void *)buf
);
1695 _dns_configuration_log(config
, TRUE
);
1698 my_log(LOG_INFO
, "*** No DNS configuration");
1701 // save [new] configuration
1702 if (!_dns_configuration_store(&_config
)) {
1703 my_log(LOG_ERR
, "could not store configuration");
1710 if (_config
!= NULL
) _dns_configuration_free(&_config
);
1712 CFRelease(resolvers
);
1717 #if !TARGET_OS_IPHONE
1718 static SCDynamicStoreRef dns_configuration_store
;
1719 static SCDynamicStoreCallBack dns_configuration_callout
;
1722 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1724 os_activity_t activity
;
1725 static const CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1727 Boolean resolvers_now
;
1728 static Boolean resolvers_save
= FALSE
;
1729 struct stat statbuf
;
1731 activity
= os_activity_create("processing DNS configuration change",
1732 OS_ACTIVITY_CURRENT
,
1733 OS_ACTIVITY_FLAG_DEFAULT
);
1734 os_activity_scope(activity
);
1736 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1737 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1738 // if we did not (and still do not) have an "/etc/resolvers"
1739 // directory than this notification is the result of a change
1740 // to the "/etc" directory.
1743 resolvers_save
= resolvers_now
;
1745 my_log(LOG_INFO
, _PATH_RESOLVER_DIR
" changed");
1747 // fake a "DNS" change
1748 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1749 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1754 os_release(activity
);
1762 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1765 mach_port_t notify_port
;
1767 CFRunLoopSourceRef rls
;
1770 dns_configuration_store
= store
;
1771 dns_configuration_callout
= callout
;
1773 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1774 if (status
!= NOTIFY_STATUS_OK
) {
1775 my_log(LOG_ERR
, "notify_register_mach_port() failed");
1779 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1780 if (status
!= NOTIFY_STATUS_OK
) {
1781 my_log(LOG_ERR
, "notify_monitor_file() failed");
1782 (void)notify_cancel(notify_token
);
1786 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1788 dns_configuration_changed
,
1791 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1793 my_log(LOG_ERR
, "SCDynamicStoreCreateRunLoopSource() failed");
1795 (void)notify_cancel(notify_token
);
1798 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1804 #endif // !TARGET_OS_IPHONE
1809 dns_configuration_init(CFBundleRef bundle
)
1811 CFDictionaryRef dict
;
1813 dict
= CFBundleGetInfoDictionary(bundle
);
1814 if (isA_CFDictionary(dict
)) {
1815 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1816 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1818 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1819 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1827 #pragma mark Standalone test code
1833 split(const void * key
, const void * value
, void * context
)
1835 CFArrayRef components
;
1836 CFStringRef entity_id
;
1837 CFStringRef service_id
;
1838 CFMutableDictionaryRef state_dict
;
1840 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1841 service_id
= CFArrayGetValueAtIndex(components
, 3);
1842 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1843 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1844 if (state_dict
!= NULL
) {
1845 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1847 state_dict
= CFDictionaryCreateMutable(NULL
,
1849 &kCFTypeDictionaryKeyCallBacks
,
1850 &kCFTypeDictionaryValueCallBacks
);
1853 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1854 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1855 CFDictionaryRef dict
;
1856 CFStringRef interface
;
1858 if (CFEqual(entity_id
, kSCEntNetIPv4
)) {
1859 dict
= ipv4_dict_create(value
);
1862 dict
= ipv6_dict_create(value
);
1865 CFDictionarySetValue(state_dict
, entity_id
, dict
);
1868 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1869 if (interface
!= NULL
) {
1870 CFDictionaryRef dns
;
1871 CFMutableDictionaryRef new_dns
;
1873 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1875 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1877 new_dns
= CFDictionaryCreateMutable(NULL
,
1879 &kCFTypeDictionaryKeyCallBacks
,
1880 &kCFTypeDictionaryValueCallBacks
);
1882 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1883 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1886 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1887 CFDictionaryRef dns
;
1889 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1891 CFStringRef interface
;
1893 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1894 if (interface
!= NULL
) {
1895 CFMutableDictionaryRef new_dns
;
1897 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1898 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1899 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1902 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1905 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1908 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1911 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1912 CFRelease(state_dict
);
1913 CFRelease(components
);
1919 main(int argc
, char **argv
)
1921 CFDictionaryRef entities
;
1923 CFArrayRef multicast_resolvers
;
1924 CFStringRef pattern
;
1925 CFMutableArrayRef patterns
;
1926 CFStringRef primary
= NULL
;
1927 CFDictionaryRef primaryDNS
= NULL
;
1928 CFArrayRef private_resolvers
;
1929 CFArrayRef service_order
= NULL
;
1930 CFMutableDictionaryRef service_state_dict
;
1931 CFDictionaryRef setup_global_ipv4
;
1932 CFDictionaryRef state_global_ipv4
;
1933 SCDynamicStoreRef store
;
1937 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1939 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1941 // get IPv4, IPv6, and DNS entities
1942 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1943 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1944 kSCDynamicStoreDomainState
,
1947 CFArrayAppendValue(patterns
, pattern
);
1949 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1950 kSCDynamicStoreDomainState
,
1953 CFArrayAppendValue(patterns
, pattern
);
1955 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1956 kSCDynamicStoreDomainState
,
1959 CFArrayAppendValue(patterns
, pattern
);
1961 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1962 CFRelease(patterns
);
1964 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1966 &kCFTypeDictionaryKeyCallBacks
,
1967 &kCFTypeDictionaryValueCallBacks
);
1968 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1969 CFRelease(entities
);
1971 // get primary service ID
1972 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1973 kSCDynamicStoreDomainState
,
1975 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1977 if (state_global_ipv4
!= NULL
) {
1978 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1979 if (primary
!= NULL
) {
1980 CFDictionaryRef service_dict
;
1982 // get DNS configuration for primary service
1983 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1984 if (service_dict
!= NULL
) {
1985 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1991 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1992 kSCDynamicStoreDomainSetup
,
1994 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1996 if (setup_global_ipv4
!= NULL
) {
1997 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
2000 // get multicast resolvers
2001 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
2002 kSCDynamicStoreDomainState
,
2004 CFSTR(kDNSServiceCompMulticastDNS
));
2005 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
2008 // get private resolvers
2009 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
2010 kSCDynamicStoreDomainState
,
2012 CFSTR(kDNSServiceCompPrivateDNS
));
2013 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
2016 // update DNS configuration
2017 dns_configuration_init(CFBundleGetMainBundle());
2018 (void)dns_configuration_set(primaryDNS
,
2021 multicast_resolvers
,
2025 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
2026 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
2027 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
2028 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
2029 CFRelease(service_state_dict
);