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
87 dns_resolver_flags_service(CFDictionaryRef service
, uint32_t resolver_flags
)
90 // check if the service has v4 configured
91 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
) == 0) &&
92 service_contains_protocol(service
, AF_INET
)) {
93 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
;
96 // check if the service has v6 configured
97 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
) == 0) &&
98 service_contains_protocol(service
, AF_INET6
)) {
99 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
;
102 return resolver_flags
;
107 add_dns_resolver_flags(const void *key
, const void *value
, void *context
)
109 CFDictionaryRef service
= (CFDictionaryRef
)value
;
110 // CFStringRef serviceID = (CFStringRef)key;
111 uint32_t *resolver_flags
= (uint32_t *)context
;
113 if (service_is_scoped_only(service
)) {
117 // update resovler flags based on configured (and available) protocols
118 *resolver_flags
= dns_resolver_flags_service(service
, *resolver_flags
);
124 #pragma mark DNS resolver configuration
128 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
)
131 CFStringRef interface
;
134 uint32_t order_val
= 0;
136 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
137 if (!isA_CFNumber(order
) ||
138 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &order_val
)) {
143 n_resolvers
= CFArrayGetCount(resolvers
);
144 for (i
= 0; i
< n_resolvers
; i
++) {
145 CFDictionaryRef match_resolver
;
147 match_resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
148 if (CFEqual(resolver
, match_resolver
)) {
154 CFMutableDictionaryRef compare
;
157 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
);
158 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
159 match
= CFEqual(resolver
, compare
);
162 CFNumberRef match_order
;
163 uint32_t match_order_val
= 0;
165 // if only the search order's are different
166 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
167 if (!isA_CFNumber(match_order
) ||
168 !CFNumberGetValue(match_order
, kCFNumberSInt32Type
, &match_order_val
)) {
172 if (order_val
< match_order_val
) {
173 // if we should prefer this match resolver, else just skip it
174 CFArraySetValueAtIndex(resolvers
, i
, resolver
);
182 order
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_resolvers
);
183 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_ORDER_KEY
, order
);
186 interface
= CFDictionaryGetValue(resolver
, kSCPropInterfaceName
);
187 if ((interface
!= NULL
) && !CFEqual(interface
, CFSTR("*"))) {
189 unsigned int if_index
= 0;
190 char if_name
[IF_NAMESIZE
];
194 if (_SC_cfstring_to_cstring(interface
,
197 kCFStringEncodingASCII
) != NULL
) {
198 if_index
= my_if_nametoindex(if_name
);
201 if ((if_index
!= 0) &&
203 // check if this is a "scoped" configuration
204 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
206 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
207 (flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)
209 // check if we should scope all queries with this configuration
210 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
211 isA_CFBoolean(val
) &&
212 CFBooleanGetValue(val
))
215 // if interface index available and it should be used
216 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
);
217 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_IF_INDEX_KEY
, num
);
222 CFArrayAppendValue(resolvers
, resolver
);
227 #define DNS_CONFIGURATION_CONFIGURATION_ID CFSTR("__CONFIGURATION_ID__")
231 add_resolver_signature(CFMutableDictionaryRef resolver
, const char *rType
, CFStringRef cID
, CFIndex rIndex
)
235 str
= CFStringCreateWithFormat(NULL
, NULL
,
236 CFSTR("%s:%s%@ %ld"),
238 (cID
!= NULL
) ? " " : "",
239 (cID
!= NULL
) ? cID
: CFSTR(""),
241 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_CONFIGURATION_ID
, str
);
249 add_supplemental(CFMutableArrayRef resolvers
,
250 CFStringRef serviceID
,
252 uint32_t defaultOrder
,
260 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
261 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
262 if (n_domains
== 0) {
266 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
267 if (orders
!= NULL
) {
268 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
274 * yes, this is a "supplemental" resolver configuration, expand
275 * the match domains and add each to the resolvers list.
277 for (i
= 0; i
< n_domains
; i
++) {
278 CFStringRef match_domain
;
279 CFNumberRef match_order
;
280 CFMutableDictionaryRef match_resolver
;
282 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
283 if (!isA_CFString(match_domain
)) {
287 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
289 // set supplemental resolver "domain"
290 if (CFStringGetLength(match_domain
) > 0) {
291 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
293 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
296 // set supplemental resolver "search_order"
297 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
298 if (isA_CFNumber(match_order
)) {
299 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
300 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
303 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
304 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
307 defaultOrder
++; // if multiple domains, maintain ordering
310 // remove keys we don't want in a supplemental resolver
311 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
312 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
313 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
314 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
316 add_resolver_signature(match_resolver
,
317 scoped
? "Supplemental/Scoped" : "Supplemental",
320 add_resolver(resolvers
, match_resolver
);
321 CFRelease(match_resolver
);
332 add_supplemental_resolvers(CFMutableArrayRef resolvers
,
333 CFDictionaryRef services
,
334 CFArrayRef service_order
,
335 CFStringRef scoped_interface
,
336 CFDictionaryRef scoped_service
)
338 const void * keys_q
[N_QUICK
];
339 const void ** keys
= keys_q
;
343 const void * vals_q
[N_QUICK
];
344 const void ** vals
= vals_q
;
346 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
347 if (n_services
== 0) {
348 return; // if no services
351 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
352 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
353 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
356 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
358 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
359 for (i
= 0; i
< n_services
; i
++) {
360 uint32_t defaultOrder
;
362 uint32_t dns_resolver_flags
;
363 CFStringRef interface
;
364 CFMutableDictionaryRef newDNS
= NULL
;
365 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
366 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
368 if (!isA_CFDictionary(service
)) {
372 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
373 dns
= isA_CFDictionary(dns
);
378 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
380 if (scoped_interface
!= NULL
) {
382 // we only want to add split/supplemental configurations
383 // for queries scoped to an interface if they are NOT
384 // associated with a "real" service
386 if (CFDictionaryContainsKey(service
, kSCEntNetIPv4
) ||
387 CFDictionaryContainsKey(service
, kSCEntNetIPv6
)) {
392 // in addition, we don't want to add split/supplemental
393 // configurations for queries scoped to an interface if
394 // the configuration does not apply to all interfaces and
395 // the configuration is explicitly NOT for this interface
397 if (!_SC_CFEqual(interface
, CFSTR("*")) &&
398 !_SC_CFEqual(interface
, scoped_interface
)) {
403 // lastly, check if A/AAAA queries should be issued (based
404 // on the IP[v6] addresses). If we would not be issuing a
405 // query then don't bother adding the configuration.
407 dns_resolver_flags
= dns_resolver_flags_service(scoped_service
, 0);
408 if (dns_resolver_flags
== 0) {
413 defaultOrder
= DEFAULT_SEARCH_ORDER
414 - (DEFAULT_SEARCH_ORDER
/ 2)
415 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
417 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
418 // push out services not specified in service order
419 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
423 * Ensure that we have the correct InterfaceName in the DNS configuration
425 * scoped_interface [supplemental] interface Trusted config DNS interface
426 * ================ ======================== ============== =================
427 * NULL NULL No NULL (No change)
430 * NULL NULL Yes NULL (No change)
431 * NULL en0 Yes en0 (trusted config w/interface)
433 * en0 NULL N/A en0 (scoped interface)
434 * en0 en0 N/A en0 (scoped interface)
435 * en0 * N/A en0 (scoped interface)
437 if ((scoped_interface
== NULL
) && (interface
== NULL
)) {
438 newDNS
= (CFMutableDictionaryRef
)CFRetain(dns
);
442 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
443 if (scoped_interface
!= NULL
) {
444 CFDictionarySetValue(newDNS
, kSCPropInterfaceName
, scoped_interface
);
445 } else if ((interface
!= NULL
) &&
446 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
447 isA_CFBoolean(val
) &&
448 CFBooleanGetValue(val
)) {
449 // leave the [trusted configuration] InterfaceName in place
451 CFDictionaryRemoveValue(newDNS
, kSCPropInterfaceName
);
455 if (scoped_interface
!= NULL
) {
459 // set "scoped" configuration flag(s)
460 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
461 !isA_CFNumber(num
) ||
462 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
465 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
467 // add "Request A/AAAA query" flag(s)
468 flags
|= dns_resolver_flags
;
470 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
471 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
475 // add [scoped] resolver entry
476 add_supplemental(resolvers
, serviceID
, newDNS
, defaultOrder
, (scoped_interface
!= NULL
));
480 if (keys
!= keys_q
) {
481 CFAllocatorDeallocate(NULL
, keys
);
482 CFAllocatorDeallocate(NULL
, vals
);
490 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
495 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
496 for (i
= 0; i
< n
; i
++) {
497 uint32_t defaultOrder
;
500 CFMutableDictionaryRef resolver
;
502 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
503 domain
= _SC_trimDomain(domain
);
504 if (domain
== NULL
) {
508 defaultOrder
= DEFAULT_SEARCH_ORDER
509 + (DEFAULT_SEARCH_ORDER
/ 2)
510 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
512 resolver
= CFDictionaryCreateMutable(NULL
,
514 &kCFTypeDictionaryKeyCallBacks
,
515 &kCFTypeDictionaryValueCallBacks
);
516 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
517 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
518 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
519 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
521 if (S_mdns_timeout
!= NULL
) {
522 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
524 add_resolver_signature(resolver
, "Multicast DNS", NULL
, i
);
525 add_resolver(resolvers
, resolver
);
535 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
540 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
541 for (i
= 0; i
< n
; i
++) {
542 uint32_t defaultOrder
;
545 CFMutableDictionaryRef resolver
;
547 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
548 domain
= _SC_trimDomain(domain
);
549 if (domain
== NULL
) {
553 defaultOrder
= DEFAULT_SEARCH_ORDER
554 - (DEFAULT_SEARCH_ORDER
/ 4)
555 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
557 resolver
= CFDictionaryCreateMutable(NULL
,
559 &kCFTypeDictionaryKeyCallBacks
,
560 &kCFTypeDictionaryValueCallBacks
);
561 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
562 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
563 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
564 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
566 if (S_pdns_timeout
!= NULL
) {
567 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
569 add_resolver_signature(resolver
, "Private DNS", NULL
, i
);
570 add_resolver(resolvers
, resolver
);
579 static CFComparisonResult
580 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
582 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
583 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
586 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
587 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
589 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
590 if (!isA_CFNumber(num1
) ||
591 !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) {
592 order1
= DEFAULT_SEARCH_ORDER
;
595 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
596 if (!isA_CFNumber(num2
) ||
597 !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
598 order2
= DEFAULT_SEARCH_ORDER
;
601 if (order1
== order2
) {
602 // if same "SearchOrder", retain original orderring for configurations
603 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) &&
604 CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) &&
605 isA_CFNumber(num1
) &&
606 isA_CFNumber(num2
) &&
607 CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
) &&
608 CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
609 if (order1
== order2
) {
610 return kCFCompareEqualTo
;
612 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
616 return kCFCompareEqualTo
;
619 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
623 static CF_RETURNS_RETAINED CFArrayRef
624 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
626 CFStringRef defaultDomainName
= NULL
;
627 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
628 CFArrayRef defaultSearchDomains
= NULL
;
629 CFIndex defaultSearchIndex
= 0;
631 CFMutableArrayRef mySearchDomains
;
632 CFMutableArrayRef mySupplemental
= NULL
;
633 CFIndex n_supplemental
;
635 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
637 if (defaultDomain
!= NULL
) {
640 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
641 if (!isA_CFNumber(num
) ||
642 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &defaultOrder
)) {
643 defaultOrder
= DEFAULT_SEARCH_ORDER
;
646 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
647 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
650 // validate the provided "search" domains or move/expand/promote the "domain" name
651 if (isA_CFArray(defaultSearchDomains
)) {
654 n_search
= CFArrayGetCount(defaultSearchDomains
);
655 for (i
= 0; i
< n_search
; i
++) {
658 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
659 search
= _SC_trimDomain(search
);
660 if (search
!= NULL
) {
661 CFArrayAppendValue(mySearchDomains
, search
);
666 defaultDomainName
= _SC_trimDomain(defaultDomainName
);
667 if (defaultDomainName
!= NULL
) {
669 int domain_parts
= 1;
673 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
676 kCFStringEncodingUTF8
);
677 CFRelease(defaultDomainName
);
679 // count domain parts
680 for (dp
= domain
; *dp
!= '\0'; dp
++) {
686 // move "domain" to "search" list (and expand as needed)
687 i
= LOCALDOMAINPARTS
;
693 str
= CFStringCreateWithCString(NULL
,
695 kCFStringEncodingUTF8
);
696 search
= _SC_trimDomain(str
);
698 if (search
!= NULL
) {
699 CFArrayAppendValue(mySearchDomains
, search
);
703 dp
= strchr(dp
, '.') + 1;
704 } while (++i
<= (domain_parts
- ndots
));
705 CFAllocatorDeallocate(NULL
, domain
);
709 // add any supplemental "domain" names to the search list
710 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
711 if (n_supplemental
> 1) {
712 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
713 CFArraySortValues(mySupplemental
,
714 CFRangeMake(0, n_supplemental
),
715 compareBySearchOrder
,
717 supplemental
= mySupplemental
;
719 for (i
= 0; i
< n_supplemental
; i
++) {
725 CFStringRef supplementalDomain
;
726 uint32_t supplementalOrder
;
728 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
730 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
731 if (isA_CFString(options
)) {
734 if (CFEqual(options
, CFSTR("pdns"))) {
735 // don't add private resolver domains to the search list
739 range
= CFStringFind(options
, CFSTR("interface="), 0);
740 if (range
.location
!= kCFNotFound
) {
741 // don't add scoped resolver domains to the search list
746 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
747 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
748 if (supplementalDomain
== NULL
) {
752 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomainsNoSearch
);
753 if (isA_CFNumber(num
) &&
754 CFNumberGetValue(num
, kCFNumberIntType
, &noSearch
) &&
756 CFRelease(supplementalDomain
);
760 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
761 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
762 CFRelease(supplementalDomain
);
766 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
767 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
770 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
771 if (!isA_CFNumber(num
) ||
772 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &supplementalOrder
)) {
773 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
776 if (supplementalOrder
< defaultOrder
) {
777 if (domainIndex
!= kCFNotFound
) {
778 // if supplemental domain is already in the search list
779 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
780 if (domainIndex
< defaultSearchIndex
) {
781 defaultSearchIndex
--;
784 CFArrayInsertValueAtIndex(mySearchDomains
,
787 defaultSearchIndex
++;
789 if (domainIndex
== kCFNotFound
) {
790 // add to the (end of the) search list
791 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
795 CFRelease(supplementalDomain
);
797 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
799 // update the "search" domains
800 if (CFArrayGetCount(mySearchDomains
) == 0) {
801 CFRelease(mySearchDomains
);
802 mySearchDomains
= NULL
;
805 // remove the "domain" name and "search" list
806 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
807 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
809 return mySearchDomains
;
814 add_scoped_resolvers(CFMutableArrayRef scoped
,
815 CFDictionaryRef services
,
816 CFArrayRef service_order
)
818 const void * keys_q
[N_QUICK
];
819 const void ** keys
= keys_q
;
823 CFMutableArrayRef order
;
824 CFMutableSetRef seen
;
826 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
827 if (n_services
== 0) {
828 return; // if no services
831 // ensure that we process all services in order
833 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
835 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
837 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
840 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
841 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
843 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
844 for (i
= 0; i
< n_services
; i
++) {
845 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
847 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
848 CFArrayAppendValue(order
, serviceID
);
852 if (keys
!= keys_q
) {
853 CFAllocatorDeallocate(NULL
, keys
);
856 // iterate over services
858 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
859 for (i
= 0; i
< n_order
; i
++) {
861 uint32_t dns_resolver_flags
;
863 char if_name
[IF_NAMESIZE
];
864 CFStringRef interface
;
865 CFMutableDictionaryRef newDNS
;
867 CFArrayRef searchDomains
;
868 CFDictionaryRef service
;
869 CFStringRef serviceID
;
871 serviceID
= CFArrayGetValueAtIndex(order
, i
);
872 service
= CFDictionaryGetValue(services
, serviceID
);
873 if (!isA_CFDictionary(service
)) {
878 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
879 if (!isA_CFDictionary(dns
)) {
884 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
885 if ((interface
== NULL
) || CFEqual(interface
, CFSTR("*"))) {
886 // if no [scoped] interface or supplemental configuration w/match-all
890 if (CFDictionaryContainsKey(dns
, kSCPropNetDNSServiceIdentifier
)) {
891 // if this is a service-specific resolver
895 if (CFSetContainsValue(seen
, interface
)) {
896 // if we've already processed this [scoped] interface
899 CFSetSetValue(seen
, interface
);
901 if ((_SC_cfstring_to_cstring(interface
,
904 kCFStringEncodingASCII
) == NULL
) ||
905 (my_if_nametoindex(if_name
) == 0)) {
906 // if interface index not available
910 // add [scoped] resolver entry
911 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
914 searchDomains
= extract_search_domains(newDNS
, NULL
);
915 if (searchDomains
!= NULL
) {
916 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
917 CFRelease(searchDomains
);
920 // set "scoped" configuration flag(s)
921 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
922 !isA_CFNumber(num
) ||
923 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
926 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
928 // add "Request A/AAAA query" flag(s)
929 dns_resolver_flags
= dns_resolver_flags_service(service
, 0);
930 if (dns_resolver_flags
== 0) {
933 flags
|= dns_resolver_flags
;
935 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
936 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
939 // remove keys we don't want in a [scoped] resolver
940 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
941 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
943 // add the [scoped] resolver
944 add_resolver_signature(newDNS
, "Scoped", serviceID
, 0);
945 add_resolver(scoped
, newDNS
);
947 // add any supplemental resolver configurations for this interface
948 add_supplemental_resolvers(scoped
, services
, service_order
, interface
, service
);
961 add_service_specific_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
)
964 CFStringRef keys_q
[N_QUICK
];
965 CFStringRef
*keys
= keys_q
;
967 CFMutableSetRef seen
;
968 CFDictionaryRef vals_q
[N_QUICK
];
969 CFDictionaryRef
*vals
= vals_q
;
971 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
972 if (n_services
== 0) {
973 return; // if no services
976 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(keys_q
[0]))) {
977 keys
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(keys
[0]), 0);
978 vals
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(vals
[0]), 0);
980 CFDictionaryGetKeysAndValues(services
, (const void **)keys
, (const void **)vals
);
982 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
983 for (i
= 0; i
< n_services
; i
++) {
985 CFNumberRef dns_service_identifier
;
986 CFNumberRef flags_num
;
988 CFMutableDictionaryRef new_resolver
;
989 CFDictionaryRef service
= vals
[i
];
990 CFStringRef serviceID
= keys
[i
];
992 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
993 if (!isA_CFDictionary(dns
)) {
998 dns_service_identifier
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
999 if (!isA_CFNumber(dns_service_identifier
)) {
1000 // if no DNS [vpn] Service Identifier
1004 if (CFSetContainsValue(seen
, dns_service_identifier
)) {
1005 my_log(LOG_ERR
, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
1008 CFSetSetValue(seen
, dns_service_identifier
);
1010 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1012 if (!CFDictionaryGetValueIfPresent(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&flags_num
) ||
1013 !isA_CFNumber(flags_num
) ||
1014 !CFNumberGetValue(flags_num
, kCFNumberSInt32Type
, &flags
)) {
1018 flags
|= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
1020 if (CFDictionaryContainsKey(new_resolver
, kSCPropInterfaceName
)) {
1021 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
);
1022 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSServiceIdentifier
);
1023 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
1025 flags
|= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
;
1028 flags_num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
1029 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, flags_num
);
1030 CFRelease(flags_num
);
1032 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
1033 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
1035 add_resolver_signature(new_resolver
, "Service", serviceID
, 0);
1036 add_resolver(resolvers
, new_resolver
);
1037 CFRelease(new_resolver
);
1041 if (keys
!= keys_q
) {
1042 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
);
1043 CFAllocatorDeallocate(kCFAllocatorDefault
, vals
);
1051 add_default_resolver(CFMutableArrayRef resolvers
,
1052 CFDictionaryRef defaultResolver
,
1053 Boolean
*orderAdded
,
1054 CFArrayRef
*searchDomains
)
1056 CFMutableDictionaryRef myDefault
;
1057 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
1060 if (defaultResolver
== NULL
) {
1061 myDefault
= CFDictionaryCreateMutable(NULL
,
1063 &kCFTypeDictionaryKeyCallBacks
,
1064 &kCFTypeDictionaryValueCallBacks
);
1066 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
1068 assert(myDefault
!= NULL
);
1070 // ensure that the default resolver has a search order
1072 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
1073 if (!isA_CFNumber(order
) ||
1074 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) {
1075 myOrder
= DEFAULT_SEARCH_ORDER
;
1076 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
1077 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
1082 // extract the "search" domain list for the default resolver (and
1083 // any supplemental resolvers)
1085 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
1087 // add the default resolver
1089 add_resolver_signature(myDefault
, "Default", NULL
, 0);
1090 add_resolver(resolvers
, myDefault
);
1091 CFRelease(myDefault
);
1096 static dns_create_resolver_t
1097 create_resolver(CFDictionaryRef dns
)
1101 dns_create_resolver_t _resolver
;
1103 CFStringRef targetInterface
= NULL
;
1104 unsigned int targetInterfaceIndex
= 0;
1106 _resolver
= _dns_resolver_create();
1109 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
1110 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1111 char domain
[NS_MAXDNAME
];
1113 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
1114 _dns_resolver_set_domain(&_resolver
, domain
);
1118 // process search domains
1119 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
1120 if (isA_CFArray(list
)) {
1122 CFIndex n
= CFArrayGetCount(list
);
1124 // add "search" domains
1125 for (i
= 0; i
< n
; i
++) {
1126 str
= CFArrayGetValueAtIndex(list
, i
);
1127 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1128 char search
[NS_MAXDNAME
];
1130 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
1131 _dns_resolver_add_search(&_resolver
, search
);
1137 // process interface index
1138 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
1139 if (isA_CFNumber(num
)) {
1142 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
1143 char if_name
[IFNAMSIZ
];
1145 _dns_resolver_set_if_index(&_resolver
, if_index
);
1147 if ((if_index
!= 0) &&
1148 (my_if_indextoname(if_index
, if_name
) != NULL
)) {
1149 targetInterface
= CFStringCreateWithCString(NULL
,
1151 kCFStringEncodingASCII
);
1152 targetInterfaceIndex
= if_index
;
1158 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1159 if (isA_CFNumber(num
)) {
1162 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1163 _dns_resolver_set_flags(&_resolver
, flags
);
1167 // process nameserver addresses
1168 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1169 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
1170 if (isA_CFArray(list
)) {
1172 CFIndex n
= CFArrayGetCount(list
);
1174 for (i
= 0; i
< n
; i
++) {
1177 struct sockaddr_in sin
;
1178 struct sockaddr_in6 sin6
;
1182 str
= CFArrayGetValueAtIndex(list
, i
);
1183 if (!isA_CFString(str
)) {
1187 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1191 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
1195 if ((addr
.sa
.sa_family
== AF_INET6
) &&
1196 IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) &&
1197 (addr
.sin6
.sin6_scope_id
== 0) &&
1198 (targetInterfaceIndex
!= 0)) {
1199 // for link local [IPv6] addresses, if the scope id is not
1200 // set then we should use the interface associated with the
1201 // resolver configuration
1202 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
1205 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
1209 // process search order
1210 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
1211 if (isA_CFNumber(num
)) {
1214 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) {
1215 _dns_resolver_set_order(&_resolver
, order
);
1220 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
1221 if (isA_CFArray(list
)) {
1223 CFIndex n
= CFArrayGetCount(list
);
1225 for (i
= 0; i
< n
; i
++) {
1228 dns_sortaddr_t sortaddr
;
1230 str
= CFArrayGetValueAtIndex(list
, i
);
1231 if (!isA_CFString(str
)) {
1235 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1239 slash
= strchr(buf
, '/');
1240 if (slash
!= NULL
) {
1244 bzero(&sortaddr
, sizeof(sortaddr
));
1245 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
1246 /* if address not valid */
1250 if (slash
!= NULL
) {
1251 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1252 /* if subnet mask not valid */
1259 a
= ntohl(sortaddr
.address
.s_addr
);
1262 } else if (IN_CLASSB(a
)) {
1264 } else if (IN_CLASSC(a
)) {
1270 sortaddr
.mask
.s_addr
= htonl(m
);
1273 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1278 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1279 if (isA_CFNumber(num
)) {
1282 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1283 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1288 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1289 if (isA_CFNumber(num
)) {
1292 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1293 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1298 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1299 if (isA_CFString(str
)) {
1302 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1303 if (options
!= NULL
) {
1304 _dns_resolver_set_options(&_resolver
, options
);
1305 CFAllocatorDeallocate(NULL
, options
);
1309 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1310 if (isA_CFNumber(num
)) {
1311 int dns_service_identifier
;
1313 if (CFNumberGetValue(num
, kCFNumberIntType
, &dns_service_identifier
)) {
1314 _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)dns_service_identifier
);
1318 // process configuration ID
1319 str
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_CONFIGURATION_ID
);
1320 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1323 cID
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1325 _dns_resolver_set_configuration_identifier(&_resolver
, cID
);
1326 CFAllocatorDeallocate(NULL
, cID
);
1330 if (targetInterface
!= NULL
) {
1331 CFRelease(targetInterface
);
1338 static __inline__ Boolean
1339 isDefaultConfiguration(CFDictionaryRef dns
)
1344 if ((dns
!= NULL
) &&
1345 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1347 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1348 (((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0) ||
1349 ((flags
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
) != 0))
1351 // if scoped or service-specific
1360 static __inline__ Boolean
1361 isScopedConfiguration(CFDictionaryRef dns
)
1366 if ((dns
!= NULL
) &&
1367 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1369 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1370 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1379 static CFComparisonResult
1380 compareDomain(const void *val1
, const void *val2
, void *context
)
1382 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1383 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1384 CFStringRef domain1
;
1385 CFStringRef domain2
;
1386 CFArrayRef labels1
= NULL
;
1387 CFArrayRef labels2
= NULL
;
1390 CFComparisonResult result
;
1396 // "default" domains sort before "supplemental" domains
1397 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1398 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1399 if (domain1
== NULL
) {
1400 return kCFCompareLessThan
;
1401 } else if (domain2
== NULL
) {
1402 return kCFCompareGreaterThan
;
1405 // sort non-scoped before scoped
1406 scoped1
= isScopedConfiguration(dns1
);
1407 scoped2
= isScopedConfiguration(dns2
);
1408 if (scoped1
!= scoped2
) {
1410 return kCFCompareLessThan
;
1412 return kCFCompareGreaterThan
;
1416 // forward (A, AAAA) domains sort before reverse (PTR) domains
1417 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1418 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1421 return kCFCompareGreaterThan
;
1423 return kCFCompareLessThan
;
1427 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1428 n1
= CFArrayGetCount(labels1
);
1430 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1431 n2
= CFArrayGetCount(labels2
);
1433 while ((n1
> 0) && (n2
> 0)) {
1434 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1435 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1437 // compare domain labels
1438 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1439 if (result
!= kCFCompareEqualTo
) {
1444 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1446 result
= kCFCompareLessThan
;
1448 } else if (n1
< n2
) {
1449 result
= kCFCompareGreaterThan
;
1453 // sort by search order
1454 result
= compareBySearchOrder(val1
, val2
, context
);
1458 if (labels1
!= NULL
) CFRelease(labels1
);
1459 if (labels2
!= NULL
) CFRelease(labels2
);
1466 dns_configuration_set(CFDictionaryRef defaultResolver
,
1467 CFDictionaryRef services
,
1468 CFArrayRef serviceOrder
,
1469 CFArrayRef multicastResolvers
,
1470 CFArrayRef privateResolvers
)
1472 dns_create_config_t _config
;
1473 Boolean changed
= FALSE
;
1474 uint32_t dns_resolver_flags
= 0;
1476 CFMutableDictionaryRef myDefault
;
1477 Boolean myOrderAdded
= FALSE
;
1478 CFArrayRef mySearchDomains
= NULL
;
1479 CFIndex n_resolvers
;
1480 CFMutableArrayRef resolvers
;
1481 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1482 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1484 // establish list of resolvers
1486 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1487 assert(resolvers
!= NULL
);
1489 // collect (and add) any "supplemental" resolver configurations
1491 add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
);
1493 // collect (and add) any "private" resolver configurations
1495 add_private_resolvers(resolvers
, privateResolvers
);
1497 // add the "default" resolver
1499 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1501 // collect (and add) any "multicast" resolver configurations
1503 add_multicast_resolvers(resolvers
, multicastResolvers
);
1505 // collect (and add) any "scoped" resolver configurations
1507 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1509 // collect (and add) any "service-specific" resolver configurations
1511 add_service_specific_resolvers(resolvers
, services
);
1515 n_resolvers
= CFArrayGetCount(resolvers
);
1516 if (n_resolvers
> 1) {
1517 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1522 for (i
= n_resolvers
; --i
> 0; ) {
1523 CFDictionaryRef resolver
;
1525 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1526 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1527 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1528 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1529 // remove empty resolver
1530 CFArrayRemoveValueAtIndex(resolvers
, i
);
1535 // update the default resolver
1537 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1539 CFArrayGetValueAtIndex(resolvers
, 0));
1540 if (mySearchDomains
!= NULL
) {
1541 // add search domains to the default resolver
1542 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1543 CFRelease(mySearchDomains
);
1545 if (myOrderAdded
&& (n_resolvers
> 1)) {
1546 CFDictionaryRef resolver
;
1548 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1549 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1550 isScopedConfiguration(resolver
)) {
1551 // if not a supplemental "default" resolver (a domain name is
1552 // present) or if it's a scoped configuration
1553 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1556 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1557 CFRelease(myDefault
);
1559 // establish resolver configuration
1561 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1563 * if no default and no supplemental/scoped resolvers
1568 * if default and/or supplemental/scoped resolvers are defined
1570 _config
= _dns_configuration_create();
1572 CFDictionaryApplyFunction(services
, add_dns_resolver_flags
, &dns_resolver_flags
);
1574 for (i
= 0; i
< n_resolvers
; i
++) {
1575 boolean_t is_default_resolver
;
1576 CFDictionaryRef resolver
;
1577 dns_create_resolver_t _resolver
;
1579 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1581 is_default_resolver
= isDefaultConfiguration(resolver
);
1582 if (is_default_resolver
) {
1583 CFMutableDictionaryRef new_resolver
;
1586 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
);
1588 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &dns_resolver_flags
);
1589 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
1592 resolver
= new_resolver
;
1595 _resolver
= create_resolver(resolver
);
1596 _dns_configuration_add_resolver(&_config
, _resolver
);
1597 _dns_resolver_free(&_resolver
);
1599 if (is_default_resolver
) {
1600 CFRelease(resolver
);
1604 #if !TARGET_OS_IPHONE
1605 // add flatfile resolvers
1607 _dnsinfo_flatfile_set_flags(dns_resolver_flags
);
1608 _dnsinfo_flatfile_add_resolvers(&_config
);
1609 #endif // !TARGET_OS_IPHONE
1612 // check if the configuration changed
1613 _dns_configuration_signature(&_config
, signature
, sizeof(signature
));
1614 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1615 // save [new] signature
1616 bcopy(signature
, signature_last
, sizeof(signature
));
1618 my_log(LOG_INFO
, "Updating DNS configuration");
1619 if (_config
!= NULL
) {
1621 dns_config_t
*config
;
1622 _dns_config_buf_t
*config_buf
;
1626 config_buf
= (_dns_config_buf_t
*)_config
;
1627 n_config
= sizeof(_dns_config_buf_t
) + ntohl(config_buf
->n_attribute
);
1628 n_padding
= ntohl(config_buf
->n_padding
);
1629 buf
= malloc(n_config
+ n_padding
);
1630 bcopy((void *)config_buf
, buf
, n_config
);
1631 bzero(&buf
[n_config
], n_padding
);
1632 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
1633 config
= _dns_configuration_expand_config((_dns_config_buf_t
*)(void *)buf
);
1634 _dns_configuration_log(config
, TRUE
);
1637 my_log(LOG_INFO
, "*** No DNS configuration");
1640 // save [new] configuration
1641 if (!_dns_configuration_store(&_config
)) {
1642 my_log(LOG_ERR
, "could not store configuration");
1649 if (_config
!= NULL
) _dns_configuration_free(&_config
);
1651 CFRelease(resolvers
);
1656 #if !TARGET_OS_IPHONE
1657 static SCDynamicStoreRef dns_configuration_store
;
1658 static SCDynamicStoreCallBack dns_configuration_callout
;
1661 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1663 os_activity_t activity
;
1664 static const CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1666 Boolean resolvers_now
;
1667 static Boolean resolvers_save
= FALSE
;
1668 struct stat statbuf
;
1670 activity
= os_activity_create("processing DNS configuration change",
1671 OS_ACTIVITY_CURRENT
,
1672 OS_ACTIVITY_FLAG_DEFAULT
);
1673 os_activity_scope(activity
);
1675 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1676 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1677 // if we did not (and still do not) have an "/etc/resolvers"
1678 // directory than this notification is the result of a change
1679 // to the "/etc" directory.
1682 resolvers_save
= resolvers_now
;
1684 my_log(LOG_INFO
, _PATH_RESOLVER_DIR
" changed");
1686 // fake a "DNS" change
1687 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1688 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1693 os_release(activity
);
1701 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1704 mach_port_t notify_port
;
1706 CFRunLoopSourceRef rls
;
1709 dns_configuration_store
= store
;
1710 dns_configuration_callout
= callout
;
1712 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1713 if (status
!= NOTIFY_STATUS_OK
) {
1714 my_log(LOG_ERR
, "notify_register_mach_port() failed");
1718 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1719 if (status
!= NOTIFY_STATUS_OK
) {
1720 my_log(LOG_ERR
, "notify_monitor_file() failed");
1721 (void)notify_cancel(notify_token
);
1725 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1727 dns_configuration_changed
,
1730 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1732 my_log(LOG_ERR
, "SCDynamicStoreCreateRunLoopSource() failed");
1734 (void)notify_cancel(notify_token
);
1737 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1743 #endif // !TARGET_OS_IPHONE
1748 dns_configuration_init(CFBundleRef bundle
)
1750 CFDictionaryRef dict
;
1752 dict
= CFBundleGetInfoDictionary(bundle
);
1753 if (isA_CFDictionary(dict
)) {
1754 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1755 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1757 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1758 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1766 #pragma mark Standalone test code
1772 split(const void * key
, const void * value
, void * context
)
1774 CFArrayRef components
;
1775 CFStringRef entity_id
;
1776 CFStringRef service_id
;
1777 CFMutableDictionaryRef state_dict
;
1779 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1780 service_id
= CFArrayGetValueAtIndex(components
, 3);
1781 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1782 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1783 if (state_dict
!= NULL
) {
1784 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1786 state_dict
= CFDictionaryCreateMutable(NULL
,
1788 &kCFTypeDictionaryKeyCallBacks
,
1789 &kCFTypeDictionaryValueCallBacks
);
1792 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1793 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1794 CFDictionaryRef dict
;
1795 CFStringRef interface
;
1797 if (CFEqual(entity_id
, kSCEntNetIPv4
)) {
1798 dict
= ipv4_dict_create(value
);
1801 dict
= ipv6_dict_create(value
);
1804 CFDictionarySetValue(state_dict
, entity_id
, dict
);
1807 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1808 if (interface
!= NULL
) {
1809 CFDictionaryRef dns
;
1810 CFMutableDictionaryRef new_dns
;
1812 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1814 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1816 new_dns
= CFDictionaryCreateMutable(NULL
,
1818 &kCFTypeDictionaryKeyCallBacks
,
1819 &kCFTypeDictionaryValueCallBacks
);
1821 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1822 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1825 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1826 CFDictionaryRef dns
;
1828 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1830 CFStringRef interface
;
1832 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1833 if (interface
!= NULL
) {
1834 CFMutableDictionaryRef new_dns
;
1836 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1837 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1838 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1841 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1844 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1847 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1850 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1851 CFRelease(state_dict
);
1852 CFRelease(components
);
1858 main(int argc
, char **argv
)
1860 CFDictionaryRef entities
;
1862 CFArrayRef multicast_resolvers
;
1863 CFStringRef pattern
;
1864 CFMutableArrayRef patterns
;
1865 CFStringRef primary
= NULL
;
1866 CFDictionaryRef primaryDNS
= NULL
;
1867 CFArrayRef private_resolvers
;
1868 CFArrayRef service_order
= NULL
;
1869 CFMutableDictionaryRef service_state_dict
;
1870 CFDictionaryRef setup_global_ipv4
;
1871 CFDictionaryRef state_global_ipv4
;
1872 SCDynamicStoreRef store
;
1876 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1878 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1880 // get IPv4, IPv6, and DNS entities
1881 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1882 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1883 kSCDynamicStoreDomainState
,
1886 CFArrayAppendValue(patterns
, pattern
);
1888 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1889 kSCDynamicStoreDomainState
,
1892 CFArrayAppendValue(patterns
, pattern
);
1894 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1895 kSCDynamicStoreDomainState
,
1898 CFArrayAppendValue(patterns
, pattern
);
1900 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1901 CFRelease(patterns
);
1903 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1905 &kCFTypeDictionaryKeyCallBacks
,
1906 &kCFTypeDictionaryValueCallBacks
);
1907 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1908 CFRelease(entities
);
1910 // get primary service ID
1911 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1912 kSCDynamicStoreDomainState
,
1914 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1916 if (state_global_ipv4
!= NULL
) {
1917 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1918 if (primary
!= NULL
) {
1919 CFDictionaryRef service_dict
;
1921 // get DNS configuration for primary service
1922 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1923 if (service_dict
!= NULL
) {
1924 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1930 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1931 kSCDynamicStoreDomainSetup
,
1933 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1935 if (setup_global_ipv4
!= NULL
) {
1936 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1939 // get multicast resolvers
1940 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1941 kSCDynamicStoreDomainState
,
1943 CFSTR(kDNSServiceCompMulticastDNS
));
1944 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1947 // get private resolvers
1948 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1949 kSCDynamicStoreDomainState
,
1951 CFSTR(kDNSServiceCompPrivateDNS
));
1952 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1955 // update DNS configuration
1956 dns_configuration_init(CFBundleGetMainBundle());
1957 (void)dns_configuration_set(primaryDNS
,
1960 multicast_resolvers
,
1964 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1965 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1966 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
1967 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1968 CFRelease(service_state_dict
);