2 * Copyright (c) 2004-2016 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
,
267 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
268 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
269 if (n_domains
== 0) {
273 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
274 if (orders
!= NULL
) {
275 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
281 * yes, this is a "supplemental" resolver configuration, expand
282 * the match domains and add each to the resolvers list.
284 for (i
= 0; i
< n_domains
; i
++) {
285 CFStringRef match_domain
;
286 CFNumberRef match_order
;
287 CFMutableDictionaryRef match_resolver
;
289 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
290 if (!isA_CFString(match_domain
)) {
294 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
296 // set supplemental resolver "domain"
297 if (CFStringGetLength(match_domain
) > 0) {
298 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
300 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
303 // set supplemental resolver "search_order"
304 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
305 if (isA_CFNumber(match_order
)) {
306 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
307 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
310 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
311 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
314 defaultOrder
++; // if multiple domains, maintain ordering
317 // remove keys we don't want in a supplemental resolver
318 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
319 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
320 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
321 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
323 add_resolver_signature(match_resolver
,
324 scoped
? "Supplemental/Scoped" : "Supplemental",
327 add_resolver(resolvers
, match_resolver
);
328 CFRelease(match_resolver
);
339 merge_configuration_flags(CFMutableDictionaryRef newDNS
, uint32_t mergeFlags
)
344 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
345 !isA_CFNumber(num
) ||
346 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
352 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
353 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
361 add_supplemental_resolvers(CFMutableArrayRef resolvers
,
362 CFDictionaryRef services
,
363 CFArrayRef service_order
,
364 CFStringRef scoped_interface
,
365 CFDictionaryRef scoped_service
)
367 const void * keys_q
[N_QUICK
];
368 const void ** keys
= keys_q
;
372 const void * vals_q
[N_QUICK
];
373 const void ** vals
= vals_q
;
375 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
376 if (n_services
== 0) {
377 return; // if no services
380 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
381 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
382 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
385 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
387 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
388 for (i
= 0; i
< n_services
; i
++) {
389 uint32_t defaultOrder
;
391 uint32_t dns_resolver_flags
;
392 CFStringRef interface
;
393 CFMutableDictionaryRef newDNS
= NULL
;
395 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
396 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
397 Boolean trusted
= FALSE
; // trusted config w/interface
399 if (!isA_CFDictionary(service
)) {
403 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
404 dns
= isA_CFDictionary(dns
);
409 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
411 if (scoped_interface
!= NULL
) {
413 // we only want to add split/supplemental configurations
414 // for queries scoped to an interface if they are NOT
415 // associated with a "real" service
417 if (CFDictionaryContainsKey(service
, kSCEntNetIPv4
) ||
418 CFDictionaryContainsKey(service
, kSCEntNetIPv6
)) {
423 // in addition, we don't want to add split/supplemental
424 // configurations for queries scoped to an interface if
425 // the configuration does not apply to all interfaces and
426 // the configuration is explicitly NOT for this interface
428 if (!_SC_CFEqual(interface
, CFSTR("*")) &&
429 !_SC_CFEqual(interface
, scoped_interface
)) {
434 // lastly, check if A/AAAA queries should be issued (based
435 // on the IP[v6] addresses). If we would not be issuing a
436 // query then don't bother adding the configuration.
438 dns_resolver_flags
= dns_resolver_flags_service(scoped_service
, 0);
439 if (dns_resolver_flags
== 0) {
444 defaultOrder
= DEFAULT_SEARCH_ORDER
445 - (DEFAULT_SEARCH_ORDER
/ 2)
446 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
448 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
449 // push out services not specified in service order
450 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
454 * Ensure that we have the correct InterfaceName in the DNS configuration
456 * scoped_interface [supplemental] interface Trusted config DNS interface
457 * ================ ======================== ============== =================
458 * NULL NULL No NULL (No change)
461 * NULL NULL Yes NULL (No change)
462 * NULL en0 Yes en0 (trusted config w/interface)
464 * en0 NULL N/A en0 (scoped interface)
465 * en0 en0 N/A en0 (scoped interface)
466 * en0 * N/A en0 (scoped interface)
468 if ((scoped_interface
== NULL
) && (interface
== NULL
)) {
469 newDNS
= (CFMutableDictionaryRef
)CFRetain(dns
);
473 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
474 if (scoped_interface
!= NULL
) {
475 CFDictionarySetValue(newDNS
, kSCPropInterfaceName
, scoped_interface
);
476 } else if ((interface
!= NULL
) &&
477 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
478 isA_CFBoolean(val
) &&
479 CFBooleanGetValue(val
)) {
480 // leave the [trusted configuration] InterfaceName in place
483 CFDictionaryRemoveValue(newDNS
, kSCPropInterfaceName
);
487 // set "supplemental" flag
488 newFlags
= DNS_RESOLVER_FLAGS_SUPPLEMENTAL
;
490 if (scoped_interface
!= NULL
) {
491 // set "scoped" configuration flag
492 newFlags
|= DNS_RESOLVER_FLAGS_SCOPED
;
494 // add "Request A/AAAA query" flag(s)
495 newFlags
|= dns_resolver_flags
;
496 } else if (trusted
) {
497 // use the DNS query flags from the supplemental match service
498 newFlags
|= dns_resolver_flags_service(service
, 0);
501 merge_configuration_flags(newDNS
, newFlags
);
503 // add [scoped] resolver entry
504 add_supplemental(resolvers
, serviceID
, newDNS
, defaultOrder
, (scoped_interface
!= NULL
));
508 if (keys
!= keys_q
) {
509 CFAllocatorDeallocate(NULL
, keys
);
510 CFAllocatorDeallocate(NULL
, vals
);
518 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
523 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
524 for (i
= 0; i
< n
; i
++) {
525 uint32_t defaultOrder
;
528 CFMutableDictionaryRef resolver
;
530 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
531 domain
= _SC_trimDomain(domain
);
532 if (domain
== NULL
) {
536 defaultOrder
= DEFAULT_SEARCH_ORDER
537 + (DEFAULT_SEARCH_ORDER
/ 2)
538 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
540 resolver
= CFDictionaryCreateMutable(NULL
,
542 &kCFTypeDictionaryKeyCallBacks
,
543 &kCFTypeDictionaryValueCallBacks
);
544 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
545 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
546 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
547 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
549 if (S_mdns_timeout
!= NULL
) {
550 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
552 add_resolver_signature(resolver
, "Multicast DNS", NULL
, i
);
553 add_resolver(resolvers
, resolver
);
563 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
568 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
569 for (i
= 0; i
< n
; i
++) {
570 uint32_t defaultOrder
;
573 CFMutableDictionaryRef resolver
;
575 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
576 domain
= _SC_trimDomain(domain
);
577 if (domain
== NULL
) {
581 defaultOrder
= DEFAULT_SEARCH_ORDER
582 - (DEFAULT_SEARCH_ORDER
/ 4)
583 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
585 resolver
= CFDictionaryCreateMutable(NULL
,
587 &kCFTypeDictionaryKeyCallBacks
,
588 &kCFTypeDictionaryValueCallBacks
);
589 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
590 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
591 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
592 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
594 if (S_pdns_timeout
!= NULL
) {
595 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
597 add_resolver_signature(resolver
, "Private DNS", NULL
, i
);
598 add_resolver(resolvers
, resolver
);
607 static CFComparisonResult
608 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
610 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
611 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
614 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
615 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
617 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
618 if (!isA_CFNumber(num1
) ||
619 !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) {
620 order1
= DEFAULT_SEARCH_ORDER
;
623 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
624 if (!isA_CFNumber(num2
) ||
625 !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
626 order2
= DEFAULT_SEARCH_ORDER
;
629 if (order1
== order2
) {
630 // if same "SearchOrder", retain original orderring for configurations
631 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) &&
632 CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) &&
633 isA_CFNumber(num1
) &&
634 isA_CFNumber(num2
) &&
635 CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
) &&
636 CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
637 if (order1
== order2
) {
638 return kCFCompareEqualTo
;
640 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
644 return kCFCompareEqualTo
;
647 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
651 static CF_RETURNS_RETAINED CFArrayRef
652 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
654 CFStringRef defaultDomainName
= NULL
;
655 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
656 CFArrayRef defaultSearchDomains
= NULL
;
657 CFIndex defaultSearchIndex
= 0;
659 CFMutableArrayRef mySearchDomains
;
660 CFMutableArrayRef mySupplemental
= NULL
;
661 CFIndex n_supplemental
;
663 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
665 if (defaultDomain
!= NULL
) {
668 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
669 if (!isA_CFNumber(num
) ||
670 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &defaultOrder
)) {
671 defaultOrder
= DEFAULT_SEARCH_ORDER
;
674 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
675 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
678 // validate the provided "search" domains or move/expand/promote the "domain" name
679 if (isA_CFArray(defaultSearchDomains
)) {
682 n_search
= CFArrayGetCount(defaultSearchDomains
);
683 for (i
= 0; i
< n_search
; i
++) {
686 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
687 search
= _SC_trimDomain(search
);
688 if (search
!= NULL
) {
689 CFArrayAppendValue(mySearchDomains
, search
);
694 defaultDomainName
= _SC_trimDomain(defaultDomainName
);
695 if (defaultDomainName
!= NULL
) {
697 int domain_parts
= 1;
701 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
704 kCFStringEncodingUTF8
);
705 CFRelease(defaultDomainName
);
707 // count domain parts
708 for (dp
= domain
; *dp
!= '\0'; dp
++) {
714 // move "domain" to "search" list (and expand as needed)
715 i
= LOCALDOMAINPARTS
;
721 str
= CFStringCreateWithCString(NULL
,
723 kCFStringEncodingUTF8
);
724 search
= _SC_trimDomain(str
);
726 if (search
!= NULL
) {
727 CFArrayAppendValue(mySearchDomains
, search
);
731 dp
= strchr(dp
, '.') + 1;
732 } while (++i
<= (domain_parts
- ndots
));
733 CFAllocatorDeallocate(NULL
, domain
);
737 // add any supplemental "domain" names to the search list
738 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
739 if (n_supplemental
> 1) {
740 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
741 CFArraySortValues(mySupplemental
,
742 CFRangeMake(0, n_supplemental
),
743 compareBySearchOrder
,
745 supplemental
= mySupplemental
;
747 for (i
= 0; i
< n_supplemental
; i
++) {
753 CFStringRef supplementalDomain
;
754 uint32_t supplementalOrder
;
756 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
758 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
759 if (isA_CFString(options
)) {
762 if (CFEqual(options
, CFSTR("pdns"))) {
763 // don't add private resolver domains to the search list
767 range
= CFStringFind(options
, CFSTR("interface="), 0);
768 if (range
.location
!= kCFNotFound
) {
769 // don't add scoped resolver domains to the search list
774 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
775 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
776 if (supplementalDomain
== NULL
) {
780 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomainsNoSearch
);
781 if (isA_CFNumber(num
) &&
782 CFNumberGetValue(num
, kCFNumberIntType
, &noSearch
) &&
784 CFRelease(supplementalDomain
);
788 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
789 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
790 CFRelease(supplementalDomain
);
794 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
795 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
798 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
799 if (!isA_CFNumber(num
) ||
800 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &supplementalOrder
)) {
801 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
804 if (supplementalOrder
< defaultOrder
) {
805 if (domainIndex
!= kCFNotFound
) {
806 // if supplemental domain is already in the search list
807 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
808 if (domainIndex
< defaultSearchIndex
) {
809 defaultSearchIndex
--;
812 CFArrayInsertValueAtIndex(mySearchDomains
,
815 defaultSearchIndex
++;
817 if (domainIndex
== kCFNotFound
) {
818 // add to the (end of the) search list
819 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
823 CFRelease(supplementalDomain
);
825 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
827 // update the "search" domains
828 if (CFArrayGetCount(mySearchDomains
) == 0) {
829 CFRelease(mySearchDomains
);
830 mySearchDomains
= NULL
;
833 // remove the "domain" name and "search" list
834 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
835 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
837 return mySearchDomains
;
842 add_scoped_resolvers(CFMutableArrayRef scoped
,
843 CFDictionaryRef services
,
844 CFArrayRef service_order
)
846 const void * keys_q
[N_QUICK
];
847 const void ** keys
= keys_q
;
851 CFMutableArrayRef order
;
852 CFMutableSetRef seen
;
854 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
855 if (n_services
== 0) {
856 return; // if no services
859 // ensure that we process all services in order
861 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
863 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
865 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
868 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
869 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
871 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
872 for (i
= 0; i
< n_services
; i
++) {
873 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
875 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
876 CFArrayAppendValue(order
, serviceID
);
880 if (keys
!= keys_q
) {
881 CFAllocatorDeallocate(NULL
, keys
);
884 // iterate over services
886 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
887 for (i
= 0; i
< n_order
; i
++) {
889 uint32_t dns_resolver_flags
;
890 char if_name
[IF_NAMESIZE
];
891 CFStringRef interface
;
892 CFMutableDictionaryRef newDNS
;
894 CFArrayRef searchDomains
;
895 CFDictionaryRef service
;
896 CFStringRef serviceID
;
898 serviceID
= CFArrayGetValueAtIndex(order
, i
);
899 service
= CFDictionaryGetValue(services
, serviceID
);
900 if (!isA_CFDictionary(service
)) {
905 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
906 if (!isA_CFDictionary(dns
)) {
911 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
912 if ((interface
== NULL
) || CFEqual(interface
, CFSTR("*"))) {
913 // if no [scoped] interface or supplemental configuration w/match-all
917 if (CFDictionaryContainsKey(dns
, kSCPropNetDNSServiceIdentifier
)) {
918 // if this is a service-specific resolver
922 if (CFSetContainsValue(seen
, interface
)) {
923 // if we've already processed this [scoped] interface
926 CFSetSetValue(seen
, interface
);
928 if ((_SC_cfstring_to_cstring(interface
,
931 kCFStringEncodingASCII
) == NULL
) ||
932 (my_if_nametoindex(if_name
) == 0)) {
933 // if interface index not available
937 // add [scoped] resolver entry
938 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
941 searchDomains
= extract_search_domains(newDNS
, NULL
);
942 if (searchDomains
!= NULL
) {
943 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
944 CFRelease(searchDomains
);
947 // get "Request A/AAAA query" flag(s)
948 dns_resolver_flags
= dns_resolver_flags_service(service
, 0);
949 if (dns_resolver_flags
== 0) {
953 // set "scoped" configuration flag
954 newFlags
= DNS_RESOLVER_FLAGS_SCOPED
;
956 // add "Request A/AAAA query" flag(s)
957 newFlags
|= dns_resolver_flags
;
959 merge_configuration_flags(newDNS
, newFlags
);
961 // remove keys we don't want in a [scoped] resolver
962 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
963 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
965 // add the [scoped] resolver
966 add_resolver_signature(newDNS
, "Scoped", serviceID
, 0);
967 add_resolver(scoped
, newDNS
);
969 // add any supplemental resolver configurations for this interface
970 add_supplemental_resolvers(scoped
, services
, service_order
, interface
, service
);
983 add_service_specific_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
)
986 CFStringRef keys_q
[N_QUICK
];
987 CFStringRef
*keys
= keys_q
;
989 CFMutableSetRef seen
;
990 CFDictionaryRef vals_q
[N_QUICK
];
991 CFDictionaryRef
*vals
= vals_q
;
993 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
994 if (n_services
== 0) {
995 return; // if no services
998 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(keys_q
[0]))) {
999 keys
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(keys
[0]), 0);
1000 vals
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(vals
[0]), 0);
1002 CFDictionaryGetKeysAndValues(services
, (const void **)keys
, (const void **)vals
);
1004 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1005 for (i
= 0; i
< n_services
; i
++) {
1006 CFDictionaryRef dns
;
1007 CFNumberRef dns_service_identifier
;
1008 CFMutableDictionaryRef newDNS
;
1009 uint32_t newFlags
= 0;
1010 CFDictionaryRef service
= vals
[i
];
1011 CFStringRef serviceID
= keys
[i
];
1013 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
1014 if (!isA_CFDictionary(dns
)) {
1019 dns_service_identifier
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1020 if (!isA_CFNumber(dns_service_identifier
)) {
1021 // if no DNS [vpn] Service Identifier
1025 if (CFSetContainsValue(seen
, dns_service_identifier
)) {
1026 my_log(LOG_ERR
, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
1029 CFSetSetValue(seen
, dns_service_identifier
);
1031 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1033 if (CFDictionaryContainsKey(newDNS
, kSCPropInterfaceName
)) {
1034 CFArrayRef searchDomains
;
1036 // set "scoped" configuration flag
1037 newFlags
|= DNS_RESOLVER_FLAGS_SCOPED
;
1039 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
);
1040 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSServiceIdentifier
);
1043 searchDomains
= extract_search_domains(newDNS
, NULL
);
1044 if (searchDomains
!= NULL
) {
1045 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
1046 CFRelease(searchDomains
);
1049 // set "service specific" configuration flag
1050 newFlags
|= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
;
1053 // add "Request A/AAAA query" flag(s)
1054 newFlags
|= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
1056 merge_configuration_flags(newDNS
, newFlags
);
1058 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
1059 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
1061 add_resolver_signature(newDNS
, "Service", serviceID
, 0);
1062 add_resolver(resolvers
, newDNS
);
1067 if (keys
!= keys_q
) {
1068 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
);
1069 CFAllocatorDeallocate(kCFAllocatorDefault
, vals
);
1077 add_default_resolver(CFMutableArrayRef resolvers
,
1078 CFDictionaryRef defaultResolver
,
1079 Boolean
*orderAdded
,
1080 CFArrayRef
*searchDomains
)
1082 CFMutableDictionaryRef myDefault
;
1083 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
1086 if (defaultResolver
== NULL
) {
1087 myDefault
= CFDictionaryCreateMutable(NULL
,
1089 &kCFTypeDictionaryKeyCallBacks
,
1090 &kCFTypeDictionaryValueCallBacks
);
1092 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
1094 assert(myDefault
!= NULL
);
1096 // ensure that the default resolver has a search order
1098 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
1099 if (!isA_CFNumber(order
) ||
1100 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) {
1101 myOrder
= DEFAULT_SEARCH_ORDER
;
1102 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
1103 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
1108 // extract the "search" domain list for the default resolver (and
1109 // any supplemental resolvers)
1111 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
1113 // add the default resolver
1115 add_resolver_signature(myDefault
, "Default", NULL
, 0);
1116 add_resolver(resolvers
, myDefault
);
1117 CFRelease(myDefault
);
1122 static dns_create_resolver_t
1123 create_resolver(CFDictionaryRef dns
)
1127 dns_create_resolver_t _resolver
;
1129 CFStringRef targetInterface
= NULL
;
1130 unsigned int targetInterfaceIndex
= 0;
1132 _resolver
= _dns_resolver_create();
1135 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
1136 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1137 char domain
[NS_MAXDNAME
];
1139 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
1140 _dns_resolver_set_domain(&_resolver
, domain
);
1144 // process search domains
1145 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
1146 if (isA_CFArray(list
)) {
1148 CFIndex n
= CFArrayGetCount(list
);
1150 // add "search" domains
1151 for (i
= 0; i
< n
; i
++) {
1152 str
= CFArrayGetValueAtIndex(list
, i
);
1153 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1154 char search
[NS_MAXDNAME
];
1156 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
1157 _dns_resolver_add_search(&_resolver
, search
);
1163 // process interface index
1164 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
1165 if (isA_CFNumber(num
)) {
1168 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
1169 char if_name
[IFNAMSIZ
];
1171 _dns_resolver_set_if_index(&_resolver
, if_index
);
1173 if ((if_index
!= 0) &&
1174 (my_if_indextoname(if_index
, if_name
) != NULL
)) {
1175 targetInterface
= CFStringCreateWithCString(NULL
,
1177 kCFStringEncodingASCII
);
1178 targetInterfaceIndex
= if_index
;
1184 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1185 if (isA_CFNumber(num
)) {
1188 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1189 _dns_resolver_set_flags(&_resolver
, flags
);
1193 // process nameserver addresses
1194 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1195 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
1196 if (isA_CFArray(list
)) {
1198 CFIndex n
= CFArrayGetCount(list
);
1200 for (i
= 0; i
< n
; i
++) {
1203 struct sockaddr_in sin
;
1204 struct sockaddr_in6 sin6
;
1208 str
= CFArrayGetValueAtIndex(list
, i
);
1209 if (!isA_CFString(str
)) {
1213 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1217 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
1221 if ((addr
.sa
.sa_family
== AF_INET6
) &&
1222 IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) &&
1223 (addr
.sin6
.sin6_scope_id
== 0) &&
1224 (targetInterfaceIndex
!= 0)) {
1225 // for link local [IPv6] addresses, if the scope id is not
1226 // set then we should use the interface associated with the
1227 // resolver configuration
1228 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
1231 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
1235 // process search order
1236 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
1237 if (isA_CFNumber(num
)) {
1240 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) {
1241 _dns_resolver_set_order(&_resolver
, order
);
1246 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
1247 if (isA_CFArray(list
)) {
1249 CFIndex n
= CFArrayGetCount(list
);
1251 for (i
= 0; i
< n
; i
++) {
1254 dns_sortaddr_t sortaddr
;
1256 str
= CFArrayGetValueAtIndex(list
, i
);
1257 if (!isA_CFString(str
)) {
1261 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1265 slash
= strchr(buf
, '/');
1266 if (slash
!= NULL
) {
1270 bzero(&sortaddr
, sizeof(sortaddr
));
1271 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
1272 /* if address not valid */
1276 if (slash
!= NULL
) {
1277 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1278 /* if subnet mask not valid */
1285 a
= ntohl(sortaddr
.address
.s_addr
);
1288 } else if (IN_CLASSB(a
)) {
1290 } else if (IN_CLASSC(a
)) {
1296 sortaddr
.mask
.s_addr
= htonl(m
);
1299 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1304 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1305 if (isA_CFNumber(num
)) {
1308 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1309 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1314 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1315 if (isA_CFNumber(num
)) {
1318 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1319 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1324 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1325 if (isA_CFString(str
)) {
1328 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1329 if (options
!= NULL
) {
1330 _dns_resolver_set_options(&_resolver
, options
);
1331 CFAllocatorDeallocate(NULL
, options
);
1335 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1336 if (isA_CFNumber(num
)) {
1337 int dns_service_identifier
;
1339 if (CFNumberGetValue(num
, kCFNumberIntType
, &dns_service_identifier
)) {
1340 _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)dns_service_identifier
);
1344 // process configuration ID
1345 str
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_CONFIGURATION_ID
);
1346 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1349 cID
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1351 _dns_resolver_set_configuration_identifier(&_resolver
, cID
);
1352 CFAllocatorDeallocate(NULL
, cID
);
1356 if (targetInterface
!= NULL
) {
1357 CFRelease(targetInterface
);
1364 static __inline__ Boolean
1365 isScopedConfiguration(CFDictionaryRef dns
)
1370 if ((dns
!= NULL
) &&
1371 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1373 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1374 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1383 static CFComparisonResult
1384 compareDomain(const void *val1
, const void *val2
, void *context
)
1386 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1387 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1388 CFStringRef domain1
;
1389 CFStringRef domain2
;
1390 CFArrayRef labels1
= NULL
;
1391 CFArrayRef labels2
= NULL
;
1394 CFComparisonResult result
;
1400 // "default" domains sort before "supplemental" domains
1401 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1402 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1403 if (domain1
== NULL
) {
1404 return kCFCompareLessThan
;
1405 } else if (domain2
== NULL
) {
1406 return kCFCompareGreaterThan
;
1409 // sort non-scoped before scoped
1410 scoped1
= isScopedConfiguration(dns1
);
1411 scoped2
= isScopedConfiguration(dns2
);
1412 if (scoped1
!= scoped2
) {
1414 return kCFCompareLessThan
;
1416 return kCFCompareGreaterThan
;
1420 // forward (A, AAAA) domains sort before reverse (PTR) domains
1421 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1422 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1425 return kCFCompareGreaterThan
;
1427 return kCFCompareLessThan
;
1431 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1432 n1
= CFArrayGetCount(labels1
);
1434 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1435 n2
= CFArrayGetCount(labels2
);
1437 while ((n1
> 0) && (n2
> 0)) {
1438 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1439 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1441 // compare domain labels
1442 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1443 if (result
!= kCFCompareEqualTo
) {
1448 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1450 result
= kCFCompareLessThan
;
1452 } else if (n1
< n2
) {
1453 result
= kCFCompareGreaterThan
;
1457 // sort by search order
1458 result
= compareBySearchOrder(val1
, val2
, context
);
1462 if (labels1
!= NULL
) CFRelease(labels1
);
1463 if (labels2
!= NULL
) CFRelease(labels2
);
1468 static __inline__ Boolean
1469 needsMergeWithDefaultConfiguration(CFDictionaryRef dns
)
1474 if ((dns
!= NULL
) &&
1475 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1477 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1479 // check if merge needed (at all)
1480 if (dns_resolver_flags_all_queries(flags
)) {
1481 // if we are already querying for both A/AAAA
1485 // check if scoped or service-specific
1486 if (((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0) ||
1487 ((flags
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
) != 0)) {
1499 dns_configuration_set(CFDictionaryRef defaultResolver
,
1500 CFDictionaryRef services
,
1501 CFArrayRef serviceOrder
,
1502 CFArrayRef multicastResolvers
,
1503 CFArrayRef privateResolvers
)
1505 dns_create_config_t _config
;
1506 Boolean changed
= FALSE
;
1508 CFMutableDictionaryRef myDefault
;
1509 Boolean myOrderAdded
= FALSE
;
1510 CFArrayRef mySearchDomains
= NULL
;
1511 CFIndex n_resolvers
;
1512 CFMutableArrayRef resolvers
;
1513 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1514 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1516 // establish list of resolvers
1518 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1519 assert(resolvers
!= NULL
);
1521 // collect (and add) any "supplemental" resolver configurations
1523 add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
);
1525 // collect (and add) any "private" resolver configurations
1527 add_private_resolvers(resolvers
, privateResolvers
);
1529 // add the "default" resolver
1531 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1533 // collect (and add) any "multicast" resolver configurations
1535 add_multicast_resolvers(resolvers
, multicastResolvers
);
1537 // collect (and add) any "scoped" resolver configurations
1539 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1541 // collect (and add) any "service-specific" resolver configurations
1543 add_service_specific_resolvers(resolvers
, services
);
1547 n_resolvers
= CFArrayGetCount(resolvers
);
1548 if (n_resolvers
> 1) {
1549 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1554 for (i
= n_resolvers
; --i
> 0; ) {
1555 CFDictionaryRef resolver
;
1557 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1558 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1559 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1560 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1561 // remove empty resolver
1562 CFArrayRemoveValueAtIndex(resolvers
, i
);
1567 // update the default resolver
1569 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1571 CFArrayGetValueAtIndex(resolvers
, 0));
1572 if (mySearchDomains
!= NULL
) {
1573 // add search domains to the default resolver
1574 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1575 CFRelease(mySearchDomains
);
1577 if (myOrderAdded
&& (n_resolvers
> 1)) {
1578 CFDictionaryRef resolver
;
1580 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1581 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1582 isScopedConfiguration(resolver
)) {
1583 // if not a supplemental "default" resolver (a domain name is
1584 // present) or if it's a scoped configuration
1585 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1588 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1589 CFRelease(myDefault
);
1591 // establish resolver configuration
1593 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1595 * if no default and no supplemental/scoped resolvers
1599 uint32_t default_resolver_flags
= 0;
1600 Boolean have_default_flags
= FALSE
;
1603 * if default and/or supplemental/scoped resolvers are defined
1605 _config
= _dns_configuration_create();
1607 for (i
= 0; i
< n_resolvers
; i
++) {
1608 Boolean merge_default_flags
;
1609 CFDictionaryRef resolver
;
1610 dns_create_resolver_t _resolver
;
1612 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1614 merge_default_flags
= needsMergeWithDefaultConfiguration(resolver
);
1615 if (merge_default_flags
) {
1616 CFMutableDictionaryRef new_resolver
;
1618 if (!have_default_flags
) {
1619 CFDictionaryApplyFunction(services
,
1620 add_dns_resolver_flags
,
1621 &default_resolver_flags
);
1622 have_default_flags
= TRUE
;
1625 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
);
1626 merge_configuration_flags(new_resolver
, default_resolver_flags
);
1627 resolver
= new_resolver
;
1630 _resolver
= create_resolver(resolver
);
1631 _dns_configuration_add_resolver(&_config
, _resolver
);
1632 _dns_resolver_free(&_resolver
);
1634 if (merge_default_flags
) {
1635 CFRelease(resolver
);
1639 #if !TARGET_OS_IPHONE
1640 // add flatfile resolvers
1642 _dnsinfo_flatfile_set_flags(default_resolver_flags
);
1643 _dnsinfo_flatfile_add_resolvers(&_config
);
1644 #endif // !TARGET_OS_IPHONE
1647 // check if the configuration changed
1648 _dns_configuration_signature(&_config
, signature
, sizeof(signature
));
1649 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1650 // save [new] signature
1651 bcopy(signature
, signature_last
, sizeof(signature
));
1653 my_log(LOG_INFO
, "Updating DNS configuration");
1654 if (_config
!= NULL
) {
1656 dns_config_t
*config
;
1657 _dns_config_buf_t
*config_buf
;
1661 config_buf
= (_dns_config_buf_t
*)_config
;
1662 n_config
= sizeof(_dns_config_buf_t
) + ntohl(config_buf
->n_attribute
);
1663 n_padding
= ntohl(config_buf
->n_padding
);
1664 buf
= malloc(n_config
+ n_padding
);
1665 bcopy((void *)config_buf
, buf
, n_config
);
1666 bzero(&buf
[n_config
], n_padding
);
1667 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
1668 config
= _dns_configuration_expand_config((_dns_config_buf_t
*)(void *)buf
);
1669 _dns_configuration_log(config
, TRUE
);
1672 my_log(LOG_INFO
, "*** No DNS configuration");
1675 // save [new] configuration
1676 if (!_dns_configuration_store(&_config
)) {
1677 my_log(LOG_ERR
, "could not store configuration");
1684 if (_config
!= NULL
) _dns_configuration_free(&_config
);
1686 CFRelease(resolvers
);
1691 #if !TARGET_OS_IPHONE
1692 static SCDynamicStoreRef dns_configuration_store
;
1693 static SCDynamicStoreCallBack dns_configuration_callout
;
1696 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1698 os_activity_t activity
;
1699 static const CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1701 Boolean resolvers_now
;
1702 static Boolean resolvers_save
= FALSE
;
1703 struct stat statbuf
;
1705 activity
= os_activity_create("processing DNS configuration change",
1706 OS_ACTIVITY_CURRENT
,
1707 OS_ACTIVITY_FLAG_DEFAULT
);
1708 os_activity_scope(activity
);
1710 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1711 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1712 // if we did not (and still do not) have an "/etc/resolvers"
1713 // directory than this notification is the result of a change
1714 // to the "/etc" directory.
1717 resolvers_save
= resolvers_now
;
1719 my_log(LOG_INFO
, _PATH_RESOLVER_DIR
" changed");
1721 // fake a "DNS" change
1722 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1723 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1728 os_release(activity
);
1736 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1739 mach_port_t notify_port
;
1741 CFRunLoopSourceRef rls
;
1744 dns_configuration_store
= store
;
1745 dns_configuration_callout
= callout
;
1747 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1748 if (status
!= NOTIFY_STATUS_OK
) {
1749 my_log(LOG_ERR
, "notify_register_mach_port() failed");
1753 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1754 if (status
!= NOTIFY_STATUS_OK
) {
1755 my_log(LOG_ERR
, "notify_monitor_file() failed");
1756 (void)notify_cancel(notify_token
);
1760 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1762 dns_configuration_changed
,
1765 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1767 my_log(LOG_ERR
, "SCDynamicStoreCreateRunLoopSource() failed");
1769 (void)notify_cancel(notify_token
);
1772 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1778 #endif // !TARGET_OS_IPHONE
1783 dns_configuration_init(CFBundleRef bundle
)
1785 CFDictionaryRef dict
;
1787 dict
= CFBundleGetInfoDictionary(bundle
);
1788 if (isA_CFDictionary(dict
)) {
1789 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1790 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1792 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1793 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1801 #pragma mark Standalone test code
1807 split(const void * key
, const void * value
, void * context
)
1809 CFArrayRef components
;
1810 CFStringRef entity_id
;
1811 CFStringRef service_id
;
1812 CFMutableDictionaryRef state_dict
;
1814 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1815 service_id
= CFArrayGetValueAtIndex(components
, 3);
1816 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1817 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1818 if (state_dict
!= NULL
) {
1819 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1821 state_dict
= CFDictionaryCreateMutable(NULL
,
1823 &kCFTypeDictionaryKeyCallBacks
,
1824 &kCFTypeDictionaryValueCallBacks
);
1827 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1828 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1829 CFDictionaryRef dict
;
1830 CFStringRef interface
;
1832 if (CFEqual(entity_id
, kSCEntNetIPv4
)) {
1833 dict
= ipv4_dict_create(value
);
1836 dict
= ipv6_dict_create(value
);
1839 CFDictionarySetValue(state_dict
, entity_id
, dict
);
1842 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1843 if (interface
!= NULL
) {
1844 CFDictionaryRef dns
;
1845 CFMutableDictionaryRef new_dns
;
1847 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1849 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1851 new_dns
= CFDictionaryCreateMutable(NULL
,
1853 &kCFTypeDictionaryKeyCallBacks
,
1854 &kCFTypeDictionaryValueCallBacks
);
1856 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1857 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1860 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1861 CFDictionaryRef dns
;
1863 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1865 CFStringRef interface
;
1867 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1868 if (interface
!= NULL
) {
1869 CFMutableDictionaryRef new_dns
;
1871 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1872 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1873 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1876 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1879 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1882 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1885 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1886 CFRelease(state_dict
);
1887 CFRelease(components
);
1893 main(int argc
, char **argv
)
1895 CFDictionaryRef entities
;
1897 CFArrayRef multicast_resolvers
;
1898 CFStringRef pattern
;
1899 CFMutableArrayRef patterns
;
1900 CFStringRef primary
= NULL
;
1901 CFDictionaryRef primaryDNS
= NULL
;
1902 CFArrayRef private_resolvers
;
1903 CFArrayRef service_order
= NULL
;
1904 CFMutableDictionaryRef service_state_dict
;
1905 CFDictionaryRef setup_global_ipv4
;
1906 CFDictionaryRef state_global_ipv4
;
1907 SCDynamicStoreRef store
;
1911 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1913 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1915 // get IPv4, IPv6, and DNS entities
1916 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1917 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1918 kSCDynamicStoreDomainState
,
1921 CFArrayAppendValue(patterns
, pattern
);
1923 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1924 kSCDynamicStoreDomainState
,
1927 CFArrayAppendValue(patterns
, pattern
);
1929 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1930 kSCDynamicStoreDomainState
,
1933 CFArrayAppendValue(patterns
, pattern
);
1935 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1936 CFRelease(patterns
);
1938 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1940 &kCFTypeDictionaryKeyCallBacks
,
1941 &kCFTypeDictionaryValueCallBacks
);
1942 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1943 CFRelease(entities
);
1945 // get primary service ID
1946 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1947 kSCDynamicStoreDomainState
,
1949 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1951 if (state_global_ipv4
!= NULL
) {
1952 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1953 if (primary
!= NULL
) {
1954 CFDictionaryRef service_dict
;
1956 // get DNS configuration for primary service
1957 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1958 if (service_dict
!= NULL
) {
1959 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1965 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1966 kSCDynamicStoreDomainSetup
,
1968 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1970 if (setup_global_ipv4
!= NULL
) {
1971 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1974 // get multicast resolvers
1975 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1976 kSCDynamicStoreDomainState
,
1978 CFSTR(kDNSServiceCompMulticastDNS
));
1979 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1982 // get private resolvers
1983 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1984 kSCDynamicStoreDomainState
,
1986 CFSTR(kDNSServiceCompPrivateDNS
));
1987 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1990 // update DNS configuration
1991 dns_configuration_init(CFBundleGetMainBundle());
1992 (void)dns_configuration_set(primaryDNS
,
1995 multicast_resolvers
,
1999 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
2000 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
2001 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
2002 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
2003 CFRelease(service_state_dict
);