2 * Copyright (c) 2004-2015 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 #ifndef kDNSServiceCompMulticastDNS
68 #define kDNSServiceCompMulticastDNS "MulticastDNS"
70 #ifndef kDNSServiceCompPrivateDNS
71 #define kDNSServiceCompPrivateDNS "PrivateDNS"
74 #define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
75 #define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
76 #define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
78 /* multicast DNS resolver configurations */
79 static CFNumberRef S_mdns_timeout
= NULL
;
81 /* private DNS resolver configurations */
82 static CFNumberRef S_pdns_timeout
= NULL
;
86 #pragma mark DNS resolver flags
92 dns_resolver_flags_service(CFDictionaryRef service
, uint32_t resolver_flags
)
95 // check if the service has v4 configured
96 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
) == 0) &&
97 service_contains_protocol(service
, AF_INET
)) {
98 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
;
101 // check if the service has v6 configured
102 if (((resolver_flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
) == 0) &&
103 service_contains_protocol(service
, AF_INET6
)) {
104 resolver_flags
|= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
;
107 return resolver_flags
;
112 add_dns_resolver_flags(const void *key
, const void *value
, void *context
)
114 CFDictionaryRef service
= (CFDictionaryRef
)value
;
115 // CFStringRef serviceID = (CFStringRef)key;
116 uint32_t *resolver_flags
= (uint32_t *)context
;
118 if (service_is_scoped_only(service
)) {
122 // update resovler flags based on configured (and available) protocols
123 *resolver_flags
= dns_resolver_flags_service(service
, *resolver_flags
);
129 #pragma mark DNS resolver configuration
133 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
)
136 CFStringRef interface
;
139 uint32_t order_val
= 0;
141 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
142 if (!isA_CFNumber(order
) ||
143 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &order_val
)) {
148 n_resolvers
= CFArrayGetCount(resolvers
);
149 for (i
= 0; i
< n_resolvers
; i
++) {
150 CFDictionaryRef match_resolver
;
152 match_resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
153 if (CFEqual(resolver
, match_resolver
)) {
159 CFMutableDictionaryRef compare
;
162 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
);
163 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
164 match
= CFEqual(resolver
, compare
);
167 CFNumberRef match_order
;
168 uint32_t match_order_val
= 0;
170 // if only the search order's are different
171 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
172 if (!isA_CFNumber(match_order
) ||
173 !CFNumberGetValue(match_order
, kCFNumberSInt32Type
, &match_order_val
)) {
177 if (order_val
< match_order_val
) {
178 // if we should prefer this match resolver, else just skip it
179 CFArraySetValueAtIndex(resolvers
, i
, resolver
);
187 order
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_resolvers
);
188 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_ORDER_KEY
, order
);
191 interface
= CFDictionaryGetValue(resolver
, kSCPropInterfaceName
);
192 if ((interface
!= NULL
) && !CFEqual(interface
, CFSTR("*"))) {
194 unsigned int if_index
= 0;
195 char if_name
[IF_NAMESIZE
];
199 if (_SC_cfstring_to_cstring(interface
,
202 kCFStringEncodingASCII
) != NULL
) {
203 if_index
= my_if_nametoindex(if_name
);
206 if ((if_index
!= 0) &&
208 // check if this is a "scoped" configuration
209 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
211 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
212 (flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)
214 // check if we should scope all queries with this configuration
215 (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
216 isA_CFBoolean(val
) &&
217 CFBooleanGetValue(val
))
220 // if interface index available and it should be used
221 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
);
222 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_IF_INDEX_KEY
, num
);
227 CFArrayAppendValue(resolvers
, resolver
);
232 #define DNS_CONFIGURATION_CONFIGURATION_ID CFSTR("__CONFIGURATION_ID__")
236 add_resolver_signature(CFMutableDictionaryRef resolver
, const char *rType
, CFStringRef cID
, CFIndex rIndex
)
240 str
= CFStringCreateWithFormat(NULL
, NULL
,
241 CFSTR("%s:%s%@ %ld"),
243 (cID
!= NULL
) ? " " : "",
244 (cID
!= NULL
) ? cID
: CFSTR(""),
246 CFDictionarySetValue(resolver
, DNS_CONFIGURATION_CONFIGURATION_ID
, str
);
254 add_supplemental(CFMutableArrayRef resolvers
,
255 CFStringRef serviceID
,
257 uint32_t defaultOrder
,
265 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
266 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
267 if (n_domains
== 0) {
271 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
272 if (orders
!= NULL
) {
273 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
279 * yes, this is a "supplemental" resolver configuration, expand
280 * the match domains and add each to the resolvers list.
282 for (i
= 0; i
< n_domains
; i
++) {
283 CFStringRef match_domain
;
284 CFNumberRef match_order
;
285 CFMutableDictionaryRef match_resolver
;
287 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
288 if (!isA_CFString(match_domain
)) {
292 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
294 // set supplemental resolver "domain"
295 if (CFStringGetLength(match_domain
) > 0) {
296 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
298 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
301 // set supplemental resolver "search_order"
302 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
303 if (isA_CFNumber(match_order
)) {
304 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
305 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
308 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
309 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
312 defaultOrder
++; // if multiple domains, maintain ordering
315 // remove keys we don't want in a supplemental resolver
316 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
317 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
318 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
319 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
321 add_resolver_signature(match_resolver
,
322 scoped
? "Supplemental/Scoped" : "Supplemental",
325 add_resolver(resolvers
, match_resolver
);
326 CFRelease(match_resolver
);
337 add_supplemental_resolvers(CFMutableArrayRef resolvers
,
338 CFDictionaryRef services
,
339 CFArrayRef service_order
,
340 CFStringRef scoped_interface
,
341 CFDictionaryRef scoped_service
)
343 const void * keys_q
[N_QUICK
];
344 const void ** keys
= keys_q
;
348 const void * vals_q
[N_QUICK
];
349 const void ** vals
= vals_q
;
351 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
352 if (n_services
== 0) {
353 return; // if no services
356 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
357 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
358 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
361 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
363 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
364 for (i
= 0; i
< n_services
; i
++) {
365 uint32_t defaultOrder
;
367 uint32_t dns_resolver_flags
;
368 CFStringRef interface
;
369 CFMutableDictionaryRef newDNS
= NULL
;
370 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
371 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
373 if (!isA_CFDictionary(service
)) {
377 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
378 dns
= isA_CFDictionary(dns
);
383 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
385 if (scoped_interface
!= NULL
) {
387 // we only want to add split/supplemental configurations
388 // for queries scoped to an interface if they are NOT
389 // associated with a "real" service
391 if (CFDictionaryContainsKey(service
, kSCEntNetIPv4
) ||
392 CFDictionaryContainsKey(service
, kSCEntNetIPv6
)) {
397 // in addition, we don't want to add split/supplemental
398 // configurations for queries scoped to an interface if
399 // the configuration does not apply to all interfaces and
400 // the configuration is explicitly NOT for this interface
402 if (!_SC_CFEqual(interface
, CFSTR("*")) &&
403 !_SC_CFEqual(interface
, scoped_interface
)) {
408 // lastly, check if A/AAAA queries should be issued (based
409 // on the IP[v6] addresses). If we would not be issuing a
410 // query then don't bother adding the configuration.
412 dns_resolver_flags
= dns_resolver_flags_service(scoped_service
, 0);
413 if (dns_resolver_flags
== 0) {
418 defaultOrder
= DEFAULT_SEARCH_ORDER
419 - (DEFAULT_SEARCH_ORDER
/ 2)
420 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
422 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
423 // push out services not specified in service order
424 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
428 * Ensure that we have the correct InterfaceName in the DNS configuration
430 * scoped_interface [supplemental] interface Trusted config DNS interface
431 * ================ ======================== ============== =================
432 * NULL NULL No NULL (No change)
435 * NULL NULL Yes NULL (No change)
436 * NULL en0 Yes en0 (trusted config w/interface)
438 * en0 NULL N/A en0 (scoped interface)
439 * en0 en0 N/A en0 (scoped interface)
440 * en0 * N/A en0 (scoped interface)
442 if ((scoped_interface
== NULL
) && (interface
== NULL
)) {
443 newDNS
= (CFMutableDictionaryRef
)CFRetain(dns
);
447 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
448 if (scoped_interface
!= NULL
) {
449 CFDictionarySetValue(newDNS
, kSCPropInterfaceName
, scoped_interface
);
450 } else if ((interface
!= NULL
) &&
451 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) &&
452 isA_CFBoolean(val
) &&
453 CFBooleanGetValue(val
)) {
454 // leave the [trusted configuration] InterfaceName in place
456 CFDictionaryRemoveValue(newDNS
, kSCPropInterfaceName
);
460 if (scoped_interface
!= NULL
) {
464 // set "scoped" configuration flag(s)
465 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
466 !isA_CFNumber(num
) ||
467 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
470 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
472 // add "Request A/AAAA query" flag(s)
473 flags
|= dns_resolver_flags
;
475 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
476 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
480 // add [scoped] resolver entry
481 add_supplemental(resolvers
, serviceID
, newDNS
, defaultOrder
, (scoped_interface
!= NULL
));
485 if (keys
!= keys_q
) {
486 CFAllocatorDeallocate(NULL
, keys
);
487 CFAllocatorDeallocate(NULL
, vals
);
495 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
)
500 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
501 for (i
= 0; i
< n
; i
++) {
502 uint32_t defaultOrder
;
505 CFMutableDictionaryRef resolver
;
507 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
508 domain
= _SC_trimDomain(domain
);
509 if (domain
== NULL
) {
513 defaultOrder
= DEFAULT_SEARCH_ORDER
514 + (DEFAULT_SEARCH_ORDER
/ 2)
515 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
517 resolver
= CFDictionaryCreateMutable(NULL
,
519 &kCFTypeDictionaryKeyCallBacks
,
520 &kCFTypeDictionaryValueCallBacks
);
521 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
522 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
523 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
524 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
526 if (S_mdns_timeout
!= NULL
) {
527 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
529 add_resolver_signature(resolver
, "Multicast DNS", NULL
, i
);
530 add_resolver(resolvers
, resolver
);
540 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
)
545 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
546 for (i
= 0; i
< n
; i
++) {
547 uint32_t defaultOrder
;
550 CFMutableDictionaryRef resolver
;
552 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
553 domain
= _SC_trimDomain(domain
);
554 if (domain
== NULL
) {
558 defaultOrder
= DEFAULT_SEARCH_ORDER
559 - (DEFAULT_SEARCH_ORDER
/ 4)
560 + ((DEFAULT_SEARCH_ORDER
/ 1000) * (uint32_t)i
);
562 resolver
= CFDictionaryCreateMutable(NULL
,
564 &kCFTypeDictionaryKeyCallBacks
,
565 &kCFTypeDictionaryValueCallBacks
);
566 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
567 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
568 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
569 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
571 if (S_pdns_timeout
!= NULL
) {
572 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
574 add_resolver_signature(resolver
, "Private DNS", NULL
, i
);
575 add_resolver(resolvers
, resolver
);
584 static CFComparisonResult
585 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
587 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
588 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
591 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
592 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
594 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
595 if (!isA_CFNumber(num1
) ||
596 !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) {
597 order1
= DEFAULT_SEARCH_ORDER
;
600 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
601 if (!isA_CFNumber(num2
) ||
602 !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
603 order2
= DEFAULT_SEARCH_ORDER
;
606 if (order1
== order2
) {
607 // if same "SearchOrder", retain original orderring for configurations
608 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) &&
609 CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) &&
610 isA_CFNumber(num1
) &&
611 isA_CFNumber(num2
) &&
612 CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
) &&
613 CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
614 if (order1
== order2
) {
615 return kCFCompareEqualTo
;
617 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
621 return kCFCompareEqualTo
;
624 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
628 static CF_RETURNS_RETAINED CFArrayRef
629 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
)
631 CFStringRef defaultDomainName
= NULL
;
632 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
633 CFArrayRef defaultSearchDomains
= NULL
;
634 CFIndex defaultSearchIndex
= 0;
636 CFMutableArrayRef mySearchDomains
;
637 CFMutableArrayRef mySupplemental
= NULL
;
638 CFIndex n_supplemental
;
640 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
642 if (defaultDomain
!= NULL
) {
645 num
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
);
646 if (!isA_CFNumber(num
) ||
647 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &defaultOrder
)) {
648 defaultOrder
= DEFAULT_SEARCH_ORDER
;
651 defaultDomainName
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
);
652 defaultSearchDomains
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
655 // validate the provided "search" domains or move/expand/promote the "domain" name
656 if (isA_CFArray(defaultSearchDomains
)) {
659 n_search
= CFArrayGetCount(defaultSearchDomains
);
660 for (i
= 0; i
< n_search
; i
++) {
663 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
664 search
= _SC_trimDomain(search
);
665 if (search
!= NULL
) {
666 CFArrayAppendValue(mySearchDomains
, search
);
671 defaultDomainName
= _SC_trimDomain(defaultDomainName
);
672 if (defaultDomainName
!= NULL
) {
674 int domain_parts
= 1;
678 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
681 kCFStringEncodingUTF8
);
682 CFRelease(defaultDomainName
);
684 // count domain parts
685 for (dp
= domain
; *dp
!= '\0'; dp
++) {
691 // move "domain" to "search" list (and expand as needed)
692 i
= LOCALDOMAINPARTS
;
698 str
= CFStringCreateWithCString(NULL
,
700 kCFStringEncodingUTF8
);
701 search
= _SC_trimDomain(str
);
703 if (search
!= NULL
) {
704 CFArrayAppendValue(mySearchDomains
, search
);
708 dp
= strchr(dp
, '.') + 1;
709 } while (++i
<= (domain_parts
- ndots
));
710 CFAllocatorDeallocate(NULL
, domain
);
714 // add any supplemental "domain" names to the search list
715 n_supplemental
= (supplemental
!= NULL
) ? CFArrayGetCount(supplemental
) : 0;
716 if (n_supplemental
> 1) {
717 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
718 CFArraySortValues(mySupplemental
,
719 CFRangeMake(0, n_supplemental
),
720 compareBySearchOrder
,
722 supplemental
= mySupplemental
;
724 for (i
= 0; i
< n_supplemental
; i
++) {
730 CFStringRef supplementalDomain
;
731 uint32_t supplementalOrder
;
733 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
735 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
736 if (isA_CFString(options
)) {
739 if (CFEqual(options
, CFSTR("pdns"))) {
740 // don't add private resolver domains to the search list
744 range
= CFStringFind(options
, CFSTR("interface="), 0);
745 if (range
.location
!= kCFNotFound
) {
746 // don't add scoped resolver domains to the search list
751 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
752 supplementalDomain
= _SC_trimDomain(supplementalDomain
);
753 if (supplementalDomain
== NULL
) {
757 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomainsNoSearch
);
758 if (isA_CFNumber(num
) &&
759 CFNumberGetValue(num
, kCFNumberIntType
, &noSearch
) &&
761 CFRelease(supplementalDomain
);
765 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
766 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
767 CFRelease(supplementalDomain
);
771 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
772 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
775 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
776 if (!isA_CFNumber(num
) ||
777 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &supplementalOrder
)) {
778 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
781 if (supplementalOrder
< defaultOrder
) {
782 if (domainIndex
!= kCFNotFound
) {
783 // if supplemental domain is already in the search list
784 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
785 if (domainIndex
< defaultSearchIndex
) {
786 defaultSearchIndex
--;
789 CFArrayInsertValueAtIndex(mySearchDomains
,
792 defaultSearchIndex
++;
794 if (domainIndex
== kCFNotFound
) {
795 // add to the (end of the) search list
796 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
800 CFRelease(supplementalDomain
);
802 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
804 // update the "search" domains
805 if (CFArrayGetCount(mySearchDomains
) == 0) {
806 CFRelease(mySearchDomains
);
807 mySearchDomains
= NULL
;
810 // remove the "domain" name and "search" list
811 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
);
812 CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
);
814 return mySearchDomains
;
819 add_scoped_resolvers(CFMutableArrayRef scoped
,
820 CFDictionaryRef services
,
821 CFArrayRef service_order
)
823 const void * keys_q
[N_QUICK
];
824 const void ** keys
= keys_q
;
828 CFMutableArrayRef order
;
829 CFMutableSetRef seen
;
831 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
832 if (n_services
== 0) {
833 return; // if no services
836 // ensure that we process all services in order
838 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
840 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
842 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
845 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
846 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
848 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
849 for (i
= 0; i
< n_services
; i
++) {
850 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
852 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
853 CFArrayAppendValue(order
, serviceID
);
857 if (keys
!= keys_q
) {
858 CFAllocatorDeallocate(NULL
, keys
);
861 // iterate over services
863 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
864 for (i
= 0; i
< n_order
; i
++) {
866 uint32_t dns_resolver_flags
;
868 char if_name
[IF_NAMESIZE
];
869 CFStringRef interface
;
870 CFMutableDictionaryRef newDNS
;
872 CFArrayRef searchDomains
;
873 CFDictionaryRef service
;
874 CFStringRef serviceID
;
876 serviceID
= CFArrayGetValueAtIndex(order
, i
);
877 service
= CFDictionaryGetValue(services
, serviceID
);
878 if (!isA_CFDictionary(service
)) {
883 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
884 if (!isA_CFDictionary(dns
)) {
889 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
890 if ((interface
== NULL
) || CFEqual(interface
, CFSTR("*"))) {
891 // if no [scoped] interface or supplemental configuration w/match-all
895 if (CFDictionaryContainsKey(dns
, kSCPropNetDNSServiceIdentifier
)) {
896 // if this is a service-specific resolver
900 if (CFSetContainsValue(seen
, interface
)) {
901 // if we've already processed this [scoped] interface
904 CFSetSetValue(seen
, interface
);
906 if ((_SC_cfstring_to_cstring(interface
,
909 kCFStringEncodingASCII
) == NULL
) ||
910 (my_if_nametoindex(if_name
) == 0)) {
911 // if interface index not available
915 // add [scoped] resolver entry
916 newDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
919 searchDomains
= extract_search_domains(newDNS
, NULL
);
920 if (searchDomains
!= NULL
) {
921 CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
);
922 CFRelease(searchDomains
);
925 // set "scoped" configuration flag(s)
926 if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) ||
927 !isA_CFNumber(num
) ||
928 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
931 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
933 // add "Request A/AAAA query" flag(s)
934 dns_resolver_flags
= dns_resolver_flags_service(service
, 0);
935 if (dns_resolver_flags
== 0) {
938 flags
|= dns_resolver_flags
;
940 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
941 CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
944 // remove keys we don't want in a [scoped] resolver
945 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
);
946 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
);
948 // add the [scoped] resolver
949 add_resolver_signature(newDNS
, "Scoped", serviceID
, 0);
950 add_resolver(scoped
, newDNS
);
952 // add any supplemental resolver configurations for this interface
953 add_supplemental_resolvers(scoped
, services
, service_order
, interface
, service
);
966 add_service_specific_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
)
969 CFStringRef keys_q
[N_QUICK
];
970 CFStringRef
*keys
= keys_q
;
972 CFMutableSetRef seen
;
973 CFDictionaryRef vals_q
[N_QUICK
];
974 CFDictionaryRef
*vals
= vals_q
;
976 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
977 if (n_services
== 0) {
978 return; // if no services
981 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(keys_q
[0]))) {
982 keys
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(keys
[0]), 0);
983 vals
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services
* sizeof(vals
[0]), 0);
985 CFDictionaryGetKeysAndValues(services
, (const void **)keys
, (const void **)vals
);
987 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
988 for (i
= 0; i
< n_services
; i
++) {
990 CFNumberRef dns_service_identifier
;
991 CFNumberRef flags_num
;
993 CFMutableDictionaryRef new_resolver
;
994 CFDictionaryRef service
= vals
[i
];
995 CFStringRef serviceID
= keys
[i
];
997 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
998 if (!isA_CFDictionary(dns
)) {
1003 dns_service_identifier
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1004 if (!isA_CFNumber(dns_service_identifier
)) {
1005 // if no DNS [vpn] Service Identifier
1009 if (CFSetContainsValue(seen
, dns_service_identifier
)) {
1010 my_log(LOG_ERR
, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
1013 CFSetSetValue(seen
, dns_service_identifier
);
1015 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1017 if (!CFDictionaryGetValueIfPresent(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&flags_num
) ||
1018 !isA_CFNumber(flags_num
) ||
1019 !CFNumberGetValue(flags_num
, kCFNumberSInt32Type
, &flags
)) {
1023 flags
|= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
1025 if (CFDictionaryContainsKey(new_resolver
, kSCPropInterfaceName
)) {
1026 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
);
1027 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSServiceIdentifier
);
1028 flags
|= DNS_RESOLVER_FLAGS_SCOPED
;
1030 flags
|= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
;
1033 flags_num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
1034 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, flags_num
);
1035 CFRelease(flags_num
);
1037 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
1038 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
1040 add_resolver_signature(new_resolver
, "Service", serviceID
, 0);
1041 add_resolver(resolvers
, new_resolver
);
1042 CFRelease(new_resolver
);
1046 if (keys
!= keys_q
) {
1047 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
);
1048 CFAllocatorDeallocate(kCFAllocatorDefault
, vals
);
1056 add_default_resolver(CFMutableArrayRef resolvers
,
1057 CFDictionaryRef defaultResolver
,
1058 Boolean
*orderAdded
,
1059 CFArrayRef
*searchDomains
)
1061 CFMutableDictionaryRef myDefault
;
1062 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
1065 if (defaultResolver
== NULL
) {
1066 myDefault
= CFDictionaryCreateMutable(NULL
,
1068 &kCFTypeDictionaryKeyCallBacks
,
1069 &kCFTypeDictionaryValueCallBacks
);
1071 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
1073 assert(myDefault
!= NULL
);
1075 // ensure that the default resolver has a search order
1077 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
1078 if (!isA_CFNumber(order
) ||
1079 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) {
1080 myOrder
= DEFAULT_SEARCH_ORDER
;
1081 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
1082 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
1087 // extract the "search" domain list for the default resolver (and
1088 // any supplemental resolvers)
1090 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
1092 // add the default resolver
1094 add_resolver_signature(myDefault
, "Default", NULL
, 0);
1095 add_resolver(resolvers
, myDefault
);
1096 CFRelease(myDefault
);
1101 static dns_create_resolver_t
1102 create_resolver(CFDictionaryRef dns
)
1106 dns_create_resolver_t _resolver
;
1108 CFStringRef targetInterface
= NULL
;
1109 unsigned int targetInterfaceIndex
= 0;
1111 _resolver
= _dns_resolver_create();
1114 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
1115 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1116 char domain
[NS_MAXDNAME
];
1118 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
1119 _dns_resolver_set_domain(&_resolver
, domain
);
1123 // process search domains
1124 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
1125 if (isA_CFArray(list
)) {
1127 CFIndex n
= CFArrayGetCount(list
);
1129 // add "search" domains
1130 for (i
= 0; i
< n
; i
++) {
1131 str
= CFArrayGetValueAtIndex(list
, i
);
1132 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1133 char search
[NS_MAXDNAME
];
1135 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
1136 _dns_resolver_add_search(&_resolver
, search
);
1142 // process interface index
1143 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
1144 if (isA_CFNumber(num
)) {
1147 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
1148 char if_name
[IFNAMSIZ
];
1150 _dns_resolver_set_if_index(&_resolver
, if_index
);
1152 if ((if_index
!= 0) &&
1153 (my_if_indextoname(if_index
, if_name
) != NULL
)) {
1154 targetInterface
= CFStringCreateWithCString(NULL
,
1156 kCFStringEncodingASCII
);
1157 targetInterfaceIndex
= if_index
;
1163 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1164 if (isA_CFNumber(num
)) {
1167 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1168 _dns_resolver_set_flags(&_resolver
, flags
);
1172 // process nameserver addresses
1173 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1174 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
1175 if (isA_CFArray(list
)) {
1177 CFIndex n
= CFArrayGetCount(list
);
1179 for (i
= 0; i
< n
; i
++) {
1182 struct sockaddr_in sin
;
1183 struct sockaddr_in6 sin6
;
1187 str
= CFArrayGetValueAtIndex(list
, i
);
1188 if (!isA_CFString(str
)) {
1192 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1196 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
1200 if ((addr
.sa
.sa_family
== AF_INET6
) &&
1201 IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) &&
1202 (addr
.sin6
.sin6_scope_id
== 0) &&
1203 (targetInterfaceIndex
!= 0)) {
1204 // for link local [IPv6] addresses, if the scope id is not
1205 // set then we should use the interface associated with the
1206 // resolver configuration
1207 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
1210 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
1214 // process search order
1215 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
1216 if (isA_CFNumber(num
)) {
1219 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) {
1220 _dns_resolver_set_order(&_resolver
, order
);
1225 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
1226 if (isA_CFArray(list
)) {
1228 CFIndex n
= CFArrayGetCount(list
);
1230 for (i
= 0; i
< n
; i
++) {
1233 dns_sortaddr_t sortaddr
;
1235 str
= CFArrayGetValueAtIndex(list
, i
);
1236 if (!isA_CFString(str
)) {
1240 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1244 slash
= strchr(buf
, '/');
1245 if (slash
!= NULL
) {
1249 bzero(&sortaddr
, sizeof(sortaddr
));
1250 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
1251 /* if address not valid */
1255 if (slash
!= NULL
) {
1256 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1257 /* if subnet mask not valid */
1264 a
= ntohl(sortaddr
.address
.s_addr
);
1267 } else if (IN_CLASSB(a
)) {
1269 } else if (IN_CLASSC(a
)) {
1275 sortaddr
.mask
.s_addr
= htonl(m
);
1278 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1283 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1284 if (isA_CFNumber(num
)) {
1287 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1288 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1293 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1294 if (isA_CFNumber(num
)) {
1297 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1298 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1303 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1304 if (isA_CFString(str
)) {
1307 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1308 if (options
!= NULL
) {
1309 _dns_resolver_set_options(&_resolver
, options
);
1310 CFAllocatorDeallocate(NULL
, options
);
1314 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1315 if (isA_CFNumber(num
)) {
1316 int dns_service_identifier
;
1318 if (CFNumberGetValue(num
, kCFNumberIntType
, &dns_service_identifier
)) {
1319 _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)dns_service_identifier
);
1323 // process configuration ID
1324 str
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_CONFIGURATION_ID
);
1325 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1328 cID
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1330 _dns_resolver_set_configuration_identifier(&_resolver
, cID
);
1331 CFAllocatorDeallocate(NULL
, cID
);
1335 if (targetInterface
!= NULL
) {
1336 CFRelease(targetInterface
);
1343 static __inline__ Boolean
1344 isDefaultConfiguration(CFDictionaryRef dns
)
1349 if ((dns
!= NULL
) &&
1350 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1352 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1353 (((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0) ||
1354 ((flags
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
) != 0))
1356 // if scoped or service-specific
1365 static __inline__ Boolean
1366 isScopedConfiguration(CFDictionaryRef dns
)
1371 if ((dns
!= NULL
) &&
1372 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1374 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1375 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1384 static CFComparisonResult
1385 compareDomain(const void *val1
, const void *val2
, void *context
)
1387 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1388 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1389 CFStringRef domain1
;
1390 CFStringRef domain2
;
1391 CFArrayRef labels1
= NULL
;
1392 CFArrayRef labels2
= NULL
;
1395 CFComparisonResult result
;
1401 // "default" domains sort before "supplemental" domains
1402 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1403 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1404 if (domain1
== NULL
) {
1405 return kCFCompareLessThan
;
1406 } else if (domain2
== NULL
) {
1407 return kCFCompareGreaterThan
;
1410 // sort non-scoped before scoped
1411 scoped1
= isScopedConfiguration(dns1
);
1412 scoped2
= isScopedConfiguration(dns2
);
1413 if (scoped1
!= scoped2
) {
1415 return kCFCompareLessThan
;
1417 return kCFCompareGreaterThan
;
1421 // must have domain names for any further comparisons
1422 if ((domain1
== NULL
) || (domain2
== NULL
)) {
1423 return kCFCompareEqualTo
;
1426 // forward (A, AAAA) domains sort before reverse (PTR) domains
1427 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1428 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1431 return kCFCompareGreaterThan
;
1433 return kCFCompareLessThan
;
1437 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1438 n1
= CFArrayGetCount(labels1
);
1440 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1441 n2
= CFArrayGetCount(labels2
);
1443 while ((n1
> 0) && (n2
> 0)) {
1444 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1445 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1447 // compare domain labels
1448 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1449 if (result
!= kCFCompareEqualTo
) {
1454 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1456 result
= kCFCompareLessThan
;
1458 } else if (n1
< n2
) {
1459 result
= kCFCompareGreaterThan
;
1463 // sort by search order
1464 result
= compareBySearchOrder(val1
, val2
, context
);
1468 if (labels1
!= NULL
) CFRelease(labels1
);
1469 if (labels2
!= NULL
) CFRelease(labels2
);
1476 dns_configuration_set(CFDictionaryRef defaultResolver
,
1477 CFDictionaryRef services
,
1478 CFArrayRef serviceOrder
,
1479 CFArrayRef multicastResolvers
,
1480 CFArrayRef privateResolvers
)
1482 dns_create_config_t _config
;
1483 Boolean changed
= FALSE
;
1484 uint32_t dns_resolver_flags
= 0;
1486 CFMutableDictionaryRef myDefault
;
1487 Boolean myOrderAdded
= FALSE
;
1488 CFArrayRef mySearchDomains
= NULL
;
1489 CFIndex n_resolvers
;
1490 CFMutableArrayRef resolvers
;
1491 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1492 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1494 // establish list of resolvers
1496 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1497 assert(resolvers
!= NULL
);
1499 // collect (and add) any "supplemental" resolver configurations
1501 add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
);
1503 // collect (and add) any "private" resolver configurations
1505 add_private_resolvers(resolvers
, privateResolvers
);
1507 // add the "default" resolver
1509 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1511 // collect (and add) any "multicast" resolver configurations
1513 add_multicast_resolvers(resolvers
, multicastResolvers
);
1515 // collect (and add) any "scoped" resolver configurations
1517 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1519 // collect (and add) any "service-specific" resolver configurations
1521 add_service_specific_resolvers(resolvers
, services
);
1525 n_resolvers
= CFArrayGetCount(resolvers
);
1526 if (n_resolvers
> 1) {
1527 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1532 for (i
= n_resolvers
; --i
> 0; ) {
1533 CFDictionaryRef resolver
;
1535 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1536 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1537 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1538 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1539 // remove empty resolver
1540 CFArrayRemoveValueAtIndex(resolvers
, i
);
1545 // update the default resolver
1547 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1549 CFArrayGetValueAtIndex(resolvers
, 0));
1550 if (mySearchDomains
!= NULL
) {
1551 // add search domains to the default resolver
1552 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1553 CFRelease(mySearchDomains
);
1555 if (myOrderAdded
&& (n_resolvers
> 1)) {
1556 CFDictionaryRef resolver
;
1558 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1559 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1560 isScopedConfiguration(resolver
)) {
1561 // if not a supplemental "default" resolver (a domain name is
1562 // present) or if it's a scoped configuration
1563 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1566 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1567 CFRelease(myDefault
);
1569 // establish resolver configuration
1571 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1573 * if no default and no supplemental/scoped resolvers
1578 * if default and/or supplemental/scoped resolvers are defined
1580 _config
= _dns_configuration_create();
1582 CFDictionaryApplyFunction(services
, add_dns_resolver_flags
, &dns_resolver_flags
);
1584 for (i
= 0; i
< n_resolvers
; i
++) {
1585 boolean_t is_default_resolver
;
1586 CFDictionaryRef resolver
;
1587 dns_create_resolver_t _resolver
;
1589 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1591 is_default_resolver
= isDefaultConfiguration(resolver
);
1592 if (is_default_resolver
) {
1593 CFMutableDictionaryRef new_resolver
;
1596 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
);
1598 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &dns_resolver_flags
);
1599 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
1602 resolver
= new_resolver
;
1605 _resolver
= create_resolver(resolver
);
1606 _dns_configuration_add_resolver(&_config
, _resolver
);
1607 _dns_resolver_free(&_resolver
);
1609 if (is_default_resolver
) {
1610 CFRelease(resolver
);
1614 #if !TARGET_OS_IPHONE
1615 // add flatfile resolvers
1617 _dnsinfo_flatfile_set_flags(dns_resolver_flags
);
1618 _dnsinfo_flatfile_add_resolvers(&_config
);
1619 #endif // !TARGET_OS_IPHONE
1622 // check if the configuration changed
1623 _dns_configuration_signature(&_config
, signature
, sizeof(signature
));
1624 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1625 // save [new] signature
1626 bcopy(signature
, signature_last
, sizeof(signature
));
1628 my_log(LOG_INFO
, "Updating DNS configuration");
1629 if (_config
!= NULL
) {
1631 dns_config_t
*config
;
1632 _dns_config_buf_t
*config_buf
;
1636 config_buf
= (_dns_config_buf_t
*)_config
;
1637 n_config
= sizeof(_dns_config_buf_t
) + ntohl(config_buf
->n_attribute
);
1638 n_padding
= ntohl(config_buf
->n_padding
);
1639 buf
= malloc(n_config
+ n_padding
);
1640 bcopy((void *)config_buf
, buf
, n_config
);
1641 bzero(&buf
[n_config
], n_padding
);
1642 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
1643 config
= _dns_configuration_expand_config((_dns_config_buf_t
*)(void *)buf
);
1644 _dns_configuration_log(config
, TRUE
);
1647 my_log(LOG_INFO
, "*** No DNS configuration");
1650 // save [new] configuration
1651 if (!_dns_configuration_store(&_config
)) {
1652 my_log(LOG_ERR
, "could not store configuration");
1659 if (_config
!= NULL
) _dns_configuration_free(&_config
);
1661 CFRelease(resolvers
);
1666 #if !TARGET_OS_IPHONE
1667 static SCDynamicStoreRef dns_configuration_store
;
1668 static SCDynamicStoreCallBack dns_configuration_callout
;
1671 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1673 os_activity_t activity_id
;
1674 static const CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1676 Boolean resolvers_now
;
1677 static Boolean resolvers_save
= FALSE
;
1678 struct stat statbuf
;
1680 activity_id
= os_activity_start("processing DNS configuration change",
1681 OS_ACTIVITY_FLAG_DEFAULT
);
1683 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1684 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1685 // if we did not (and still do not) have an "/etc/resolvers"
1686 // directory than this notification is the result of a change
1687 // to the "/etc" directory.
1690 resolvers_save
= resolvers_now
;
1692 my_log(LOG_INFO
, _PATH_RESOLVER_DIR
" changed");
1694 // fake a "DNS" change
1695 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1696 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1701 os_activity_end(activity_id
);
1709 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1712 mach_port_t notify_port
;
1714 CFRunLoopSourceRef rls
;
1717 dns_configuration_store
= store
;
1718 dns_configuration_callout
= callout
;
1720 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1721 if (status
!= NOTIFY_STATUS_OK
) {
1722 my_log(LOG_ERR
, "notify_register_mach_port() failed");
1726 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1727 if (status
!= NOTIFY_STATUS_OK
) {
1728 my_log(LOG_ERR
, "notify_monitor_file() failed");
1729 (void)notify_cancel(notify_token
);
1733 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1735 dns_configuration_changed
,
1738 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1740 my_log(LOG_ERR
, "SCDynamicStoreCreateRunLoopSource() failed");
1742 (void)notify_cancel(notify_token
);
1745 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1751 #endif // !TARGET_OS_IPHONE
1756 dns_configuration_init(CFBundleRef bundle
)
1758 CFDictionaryRef dict
;
1760 dict
= CFBundleGetInfoDictionary(bundle
);
1761 if (isA_CFDictionary(dict
)) {
1762 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1763 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1765 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1766 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1774 #pragma mark Standalone test code
1780 split(const void * key
, const void * value
, void * context
)
1782 CFArrayRef components
;
1783 CFStringRef entity_id
;
1784 CFStringRef service_id
;
1785 CFMutableDictionaryRef state_dict
;
1787 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1788 service_id
= CFArrayGetValueAtIndex(components
, 3);
1789 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1790 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1791 if (state_dict
!= NULL
) {
1792 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1794 state_dict
= CFDictionaryCreateMutable(NULL
,
1796 &kCFTypeDictionaryKeyCallBacks
,
1797 &kCFTypeDictionaryValueCallBacks
);
1800 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1801 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1802 CFDictionaryRef dict
;
1803 CFStringRef interface
;
1805 if (CFEqual(entity_id
, kSCEntNetIPv4
)) {
1806 dict
= ipv4_dict_create(value
);
1809 dict
= ipv6_dict_create(value
);
1812 CFDictionarySetValue(state_dict
, entity_id
, dict
);
1815 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1816 if (interface
!= NULL
) {
1817 CFDictionaryRef dns
;
1818 CFMutableDictionaryRef new_dns
;
1820 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1822 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1824 new_dns
= CFDictionaryCreateMutable(NULL
,
1826 &kCFTypeDictionaryKeyCallBacks
,
1827 &kCFTypeDictionaryValueCallBacks
);
1829 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1830 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1833 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1834 CFDictionaryRef dns
;
1836 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1838 CFStringRef interface
;
1840 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1841 if (interface
!= NULL
) {
1842 CFMutableDictionaryRef new_dns
;
1844 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1845 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1846 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1849 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1852 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1855 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1858 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1859 CFRelease(state_dict
);
1860 CFRelease(components
);
1866 main(int argc
, char **argv
)
1868 CFDictionaryRef entities
;
1870 CFArrayRef multicast_resolvers
;
1871 CFStringRef pattern
;
1872 CFMutableArrayRef patterns
;
1873 CFStringRef primary
= NULL
;
1874 CFDictionaryRef primaryDNS
= NULL
;
1875 CFArrayRef private_resolvers
;
1876 CFArrayRef service_order
= NULL
;
1877 CFMutableDictionaryRef service_state_dict
;
1878 CFDictionaryRef setup_global_ipv4
;
1879 CFDictionaryRef state_global_ipv4
;
1880 SCDynamicStoreRef store
;
1884 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1886 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1888 // get IPv4, IPv6, and DNS entities
1889 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1890 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1891 kSCDynamicStoreDomainState
,
1894 CFArrayAppendValue(patterns
, pattern
);
1896 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1897 kSCDynamicStoreDomainState
,
1900 CFArrayAppendValue(patterns
, pattern
);
1902 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1903 kSCDynamicStoreDomainState
,
1906 CFArrayAppendValue(patterns
, pattern
);
1908 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1909 CFRelease(patterns
);
1911 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1913 &kCFTypeDictionaryKeyCallBacks
,
1914 &kCFTypeDictionaryValueCallBacks
);
1915 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1916 CFRelease(entities
);
1918 // get primary service ID
1919 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1920 kSCDynamicStoreDomainState
,
1922 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1924 if (state_global_ipv4
!= NULL
) {
1925 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1926 if (primary
!= NULL
) {
1927 CFDictionaryRef service_dict
;
1929 // get DNS configuration for primary service
1930 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1931 if (service_dict
!= NULL
) {
1932 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1938 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1939 kSCDynamicStoreDomainSetup
,
1941 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1943 if (setup_global_ipv4
!= NULL
) {
1944 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1947 // get multicast resolvers
1948 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1949 kSCDynamicStoreDomainState
,
1951 CFSTR(kDNSServiceCompMulticastDNS
));
1952 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1955 // get private resolvers
1956 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1957 kSCDynamicStoreDomainState
,
1959 CFSTR(kDNSServiceCompPrivateDNS
));
1960 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1963 // update DNS configuration
1964 dns_configuration_init(CFBundleGetMainBundle());
1965 (void)dns_configuration_set(primaryDNS
,
1968 multicast_resolvers
,
1972 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1973 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1974 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
1975 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1976 CFRelease(service_state_dict
);