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_SERVICE_SPECIFIC
| DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
1025 flags_num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
);
1026 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, flags_num
);
1027 CFRelease(flags_num
);
1029 if (CFDictionaryContainsKey(new_resolver
, kSCPropInterfaceName
)) {
1030 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
);
1033 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
1034 CFDictionaryRemoveValue(new_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
1036 add_resolver_signature(new_resolver
, "Service", serviceID
, 0);
1037 add_resolver(resolvers
, new_resolver
);
1038 CFRelease(new_resolver
);
1042 if (keys
!= keys_q
) {
1043 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
);
1044 CFAllocatorDeallocate(kCFAllocatorDefault
, vals
);
1052 add_default_resolver(CFMutableArrayRef resolvers
,
1053 CFDictionaryRef defaultResolver
,
1054 Boolean
*orderAdded
,
1055 CFArrayRef
*searchDomains
)
1057 CFMutableDictionaryRef myDefault
;
1058 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
1061 if (defaultResolver
== NULL
) {
1062 myDefault
= CFDictionaryCreateMutable(NULL
,
1064 &kCFTypeDictionaryKeyCallBacks
,
1065 &kCFTypeDictionaryValueCallBacks
);
1067 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
1069 assert(myDefault
!= NULL
);
1071 // ensure that the default resolver has a search order
1073 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
1074 if (!isA_CFNumber(order
) ||
1075 !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) {
1076 myOrder
= DEFAULT_SEARCH_ORDER
;
1077 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
1078 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
1083 // extract the "search" domain list for the default resolver (and
1084 // any supplemental resolvers)
1086 *searchDomains
= extract_search_domains(myDefault
, resolvers
);
1088 // add the default resolver
1090 add_resolver_signature(myDefault
, "Default", NULL
, 0);
1091 add_resolver(resolvers
, myDefault
);
1092 CFRelease(myDefault
);
1097 static dns_create_resolver_t
1098 create_resolver(CFDictionaryRef dns
)
1102 dns_create_resolver_t _resolver
;
1104 CFStringRef targetInterface
= NULL
;
1105 unsigned int targetInterfaceIndex
= 0;
1107 _resolver
= _dns_resolver_create();
1110 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
1111 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1112 char domain
[NS_MAXDNAME
];
1114 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
1115 _dns_resolver_set_domain(&_resolver
, domain
);
1119 // process search domains
1120 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
1121 if (isA_CFArray(list
)) {
1123 CFIndex n
= CFArrayGetCount(list
);
1125 // add "search" domains
1126 for (i
= 0; i
< n
; i
++) {
1127 str
= CFArrayGetValueAtIndex(list
, i
);
1128 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1129 char search
[NS_MAXDNAME
];
1131 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
1132 _dns_resolver_add_search(&_resolver
, search
);
1138 // process interface index
1139 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
);
1140 if (isA_CFNumber(num
)) {
1143 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) {
1144 char if_name
[IFNAMSIZ
];
1146 _dns_resolver_set_if_index(&_resolver
, if_index
);
1148 if ((if_index
!= 0) &&
1149 (my_if_indextoname(if_index
, if_name
) != NULL
)) {
1150 targetInterface
= CFStringCreateWithCString(NULL
,
1152 kCFStringEncodingASCII
);
1153 targetInterfaceIndex
= if_index
;
1159 num
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
);
1160 if (isA_CFNumber(num
)) {
1163 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
1164 _dns_resolver_set_flags(&_resolver
, flags
);
1168 // process nameserver addresses
1169 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
1170 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
1171 if (isA_CFArray(list
)) {
1173 CFIndex n
= CFArrayGetCount(list
);
1175 for (i
= 0; i
< n
; i
++) {
1178 struct sockaddr_in sin
;
1179 struct sockaddr_in6 sin6
;
1183 str
= CFArrayGetValueAtIndex(list
, i
);
1184 if (!isA_CFString(str
)) {
1188 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1192 if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) {
1196 if ((addr
.sa
.sa_family
== AF_INET6
) &&
1197 IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) &&
1198 (addr
.sin6
.sin6_scope_id
== 0) &&
1199 (targetInterfaceIndex
!= 0)) {
1200 // for link local [IPv6] addresses, if the scope id is not
1201 // set then we should use the interface associated with the
1202 // resolver configuration
1203 addr
.sin6
.sin6_scope_id
= targetInterfaceIndex
;
1206 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
1210 // process search order
1211 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
1212 if (isA_CFNumber(num
)) {
1215 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) {
1216 _dns_resolver_set_order(&_resolver
, order
);
1221 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
1222 if (isA_CFArray(list
)) {
1224 CFIndex n
= CFArrayGetCount(list
);
1226 for (i
= 0; i
< n
; i
++) {
1229 dns_sortaddr_t sortaddr
;
1231 str
= CFArrayGetValueAtIndex(list
, i
);
1232 if (!isA_CFString(str
)) {
1236 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
1240 slash
= strchr(buf
, '/');
1241 if (slash
!= NULL
) {
1245 bzero(&sortaddr
, sizeof(sortaddr
));
1246 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
1247 /* if address not valid */
1251 if (slash
!= NULL
) {
1252 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
1253 /* if subnet mask not valid */
1260 a
= ntohl(sortaddr
.address
.s_addr
);
1263 } else if (IN_CLASSB(a
)) {
1265 } else if (IN_CLASSC(a
)) {
1271 sortaddr
.mask
.s_addr
= htonl(m
);
1274 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
1279 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
1280 if (isA_CFNumber(num
)) {
1283 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
1284 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
1289 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
1290 if (isA_CFNumber(num
)) {
1293 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
1294 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
1299 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
1300 if (isA_CFString(str
)) {
1303 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1304 if (options
!= NULL
) {
1305 _dns_resolver_set_options(&_resolver
, options
);
1306 CFAllocatorDeallocate(NULL
, options
);
1310 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
);
1311 if (isA_CFNumber(num
)) {
1312 int dns_service_identifier
;
1314 if (CFNumberGetValue(num
, kCFNumberIntType
, &dns_service_identifier
)) {
1315 _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)dns_service_identifier
);
1319 // process configuration ID
1320 str
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_CONFIGURATION_ID
);
1321 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
1324 cID
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
1326 _dns_resolver_set_configuration_identifier(&_resolver
, cID
);
1327 CFAllocatorDeallocate(NULL
, cID
);
1331 if (targetInterface
!= NULL
) {
1332 CFRelease(targetInterface
);
1339 static __inline__ Boolean
1340 isDefaultConfiguration(CFDictionaryRef dns
)
1345 if ((dns
!= NULL
) &&
1346 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1348 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1349 (((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0) ||
1350 ((flags
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
) != 0))
1352 // if scoped or service-specific
1361 static __inline__ Boolean
1362 isScopedConfiguration(CFDictionaryRef dns
)
1367 if ((dns
!= NULL
) &&
1368 CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) &&
1370 CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) &&
1371 ((flags
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) {
1380 static CFComparisonResult
1381 compareDomain(const void *val1
, const void *val2
, void *context
)
1383 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
1384 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
1385 CFStringRef domain1
;
1386 CFStringRef domain2
;
1387 CFArrayRef labels1
= NULL
;
1388 CFArrayRef labels2
= NULL
;
1391 CFComparisonResult result
;
1397 // "default" domains sort before "supplemental" domains
1398 domain1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
);
1399 domain2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
);
1400 if (domain1
== NULL
) {
1401 return kCFCompareLessThan
;
1402 } else if (domain2
== NULL
) {
1403 return kCFCompareGreaterThan
;
1406 // sort non-scoped before scoped
1407 scoped1
= isScopedConfiguration(dns1
);
1408 scoped2
= isScopedConfiguration(dns2
);
1409 if (scoped1
!= scoped2
) {
1411 return kCFCompareLessThan
;
1413 return kCFCompareGreaterThan
;
1417 // must have domain names for any further comparisons
1418 if ((domain1
== NULL
) || (domain2
== NULL
)) {
1419 return kCFCompareEqualTo
;
1422 // forward (A, AAAA) domains sort before reverse (PTR) domains
1423 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
1424 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
1427 return kCFCompareGreaterThan
;
1429 return kCFCompareLessThan
;
1433 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
1434 n1
= CFArrayGetCount(labels1
);
1436 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
1437 n2
= CFArrayGetCount(labels2
);
1439 while ((n1
> 0) && (n2
> 0)) {
1440 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
1441 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
1443 // compare domain labels
1444 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
1445 if (result
!= kCFCompareEqualTo
) {
1450 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
1452 result
= kCFCompareLessThan
;
1454 } else if (n1
< n2
) {
1455 result
= kCFCompareGreaterThan
;
1459 // sort by search order
1460 result
= compareBySearchOrder(val1
, val2
, context
);
1464 if (labels1
!= NULL
) CFRelease(labels1
);
1465 if (labels2
!= NULL
) CFRelease(labels2
);
1472 dns_configuration_set(CFDictionaryRef defaultResolver
,
1473 CFDictionaryRef services
,
1474 CFArrayRef serviceOrder
,
1475 CFArrayRef multicastResolvers
,
1476 CFArrayRef privateResolvers
)
1478 dns_create_config_t _config
;
1479 Boolean changed
= FALSE
;
1480 uint32_t dns_resolver_flags
= 0;
1482 CFMutableDictionaryRef myDefault
;
1483 Boolean myOrderAdded
= FALSE
;
1484 CFArrayRef mySearchDomains
= NULL
;
1485 CFIndex n_resolvers
;
1486 CFMutableArrayRef resolvers
;
1487 unsigned char signature
[CC_SHA1_DIGEST_LENGTH
];
1488 static unsigned char signature_last
[CC_SHA1_DIGEST_LENGTH
];
1490 // establish list of resolvers
1492 resolvers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1493 assert(resolvers
!= NULL
);
1495 // collect (and add) any "supplemental" resolver configurations
1497 add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
);
1499 // collect (and add) any "private" resolver configurations
1501 add_private_resolvers(resolvers
, privateResolvers
);
1503 // add the "default" resolver
1505 add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
);
1507 // collect (and add) any "multicast" resolver configurations
1509 add_multicast_resolvers(resolvers
, multicastResolvers
);
1511 // collect (and add) any "scoped" resolver configurations
1513 add_scoped_resolvers(resolvers
, services
, serviceOrder
);
1515 // collect (and add) any "service-specific" resolver configurations
1517 add_service_specific_resolvers(resolvers
, services
);
1521 n_resolvers
= CFArrayGetCount(resolvers
);
1522 if (n_resolvers
> 1) {
1523 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
);
1528 for (i
= n_resolvers
; --i
> 0; ) {
1529 CFDictionaryRef resolver
;
1531 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1532 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) &&
1533 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) &&
1534 !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) {
1535 // remove empty resolver
1536 CFArrayRemoveValueAtIndex(resolvers
, i
);
1541 // update the default resolver
1543 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
1545 CFArrayGetValueAtIndex(resolvers
, 0));
1546 if (mySearchDomains
!= NULL
) {
1547 // add search domains to the default resolver
1548 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
1549 CFRelease(mySearchDomains
);
1551 if (myOrderAdded
&& (n_resolvers
> 1)) {
1552 CFDictionaryRef resolver
;
1554 resolver
= CFArrayGetValueAtIndex(resolvers
, 1);
1555 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) ||
1556 isScopedConfiguration(resolver
)) {
1557 // if not a supplemental "default" resolver (a domain name is
1558 // present) or if it's a scoped configuration
1559 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
1562 CFArraySetValueAtIndex(resolvers
, 0, myDefault
);
1563 CFRelease(myDefault
);
1565 // establish resolver configuration
1567 if ((defaultResolver
== NULL
) && (n_resolvers
<= 1)) {
1569 * if no default and no supplemental/scoped resolvers
1574 * if default and/or supplemental/scoped resolvers are defined
1576 _config
= _dns_configuration_create();
1578 CFDictionaryApplyFunction(services
, add_dns_resolver_flags
, &dns_resolver_flags
);
1580 for (i
= 0; i
< n_resolvers
; i
++) {
1581 boolean_t is_default_resolver
;
1582 CFDictionaryRef resolver
;
1583 dns_create_resolver_t _resolver
;
1585 resolver
= CFArrayGetValueAtIndex(resolvers
, i
);
1587 is_default_resolver
= isDefaultConfiguration(resolver
);
1588 if (is_default_resolver
) {
1589 CFMutableDictionaryRef new_resolver
;
1592 new_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
);
1594 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &dns_resolver_flags
);
1595 CFDictionarySetValue(new_resolver
, DNS_CONFIGURATION_FLAGS_KEY
, num
);
1598 resolver
= new_resolver
;
1601 _resolver
= create_resolver(resolver
);
1602 _dns_configuration_add_resolver(&_config
, _resolver
);
1603 _dns_resolver_free(&_resolver
);
1605 if (is_default_resolver
) {
1606 CFRelease(resolver
);
1610 #if !TARGET_OS_IPHONE
1611 // add flatfile resolvers
1613 _dnsinfo_flatfile_set_flags(dns_resolver_flags
);
1614 _dnsinfo_flatfile_add_resolvers(&_config
);
1615 #endif // !TARGET_OS_IPHONE
1618 // check if the configuration changed
1619 _dns_configuration_signature(&_config
, signature
, sizeof(signature
));
1620 if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) {
1621 // save [new] signature
1622 bcopy(signature
, signature_last
, sizeof(signature
));
1624 my_log(LOG_INFO
, "Updating DNS configuration");
1625 if (_config
!= NULL
) {
1627 dns_config_t
*config
;
1628 _dns_config_buf_t
*config_buf
;
1632 config_buf
= (_dns_config_buf_t
*)_config
;
1633 n_config
= sizeof(_dns_config_buf_t
) + ntohl(config_buf
->n_attribute
);
1634 n_padding
= ntohl(config_buf
->n_padding
);
1635 buf
= malloc(n_config
+ n_padding
);
1636 bcopy((void *)config_buf
, buf
, n_config
);
1637 bzero(&buf
[n_config
], n_padding
);
1638 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
1639 config
= _dns_configuration_expand_config((_dns_config_buf_t
*)(void *)buf
);
1640 _dns_configuration_log(config
, TRUE
);
1643 my_log(LOG_INFO
, "*** No DNS configuration");
1646 // save [new] configuration
1647 if (!_dns_configuration_store(&_config
)) {
1648 my_log(LOG_ERR
, "could not store configuration");
1655 if (_config
!= NULL
) _dns_configuration_free(&_config
);
1657 CFRelease(resolvers
);
1662 #if !TARGET_OS_IPHONE
1663 static SCDynamicStoreRef dns_configuration_store
;
1664 static SCDynamicStoreCallBack dns_configuration_callout
;
1667 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1669 os_activity_t activity_id
;
1670 static const CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1672 Boolean resolvers_now
;
1673 static Boolean resolvers_save
= FALSE
;
1674 struct stat statbuf
;
1676 activity_id
= os_activity_start("processing DNS configuration change",
1677 OS_ACTIVITY_FLAG_DEFAULT
);
1679 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1680 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1681 // if we did not (and still do not) have an "/etc/resolvers"
1682 // directory than this notification is the result of a change
1683 // to the "/etc" directory.
1686 resolvers_save
= resolvers_now
;
1688 my_log(LOG_INFO
, _PATH_RESOLVER_DIR
" changed");
1690 // fake a "DNS" change
1691 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1692 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1697 os_activity_end(activity_id
);
1705 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1708 mach_port_t notify_port
;
1710 CFRunLoopSourceRef rls
;
1713 dns_configuration_store
= store
;
1714 dns_configuration_callout
= callout
;
1716 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1717 if (status
!= NOTIFY_STATUS_OK
) {
1718 my_log(LOG_ERR
, "notify_register_mach_port() failed");
1722 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1723 if (status
!= NOTIFY_STATUS_OK
) {
1724 my_log(LOG_ERR
, "notify_monitor_file() failed");
1725 (void)notify_cancel(notify_token
);
1729 mp
= _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
1731 dns_configuration_changed
,
1734 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1736 my_log(LOG_ERR
, "SCDynamicStoreCreateRunLoopSource() failed");
1738 (void)notify_cancel(notify_token
);
1741 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1747 #endif // !TARGET_OS_IPHONE
1752 dns_configuration_init(CFBundleRef bundle
)
1754 CFDictionaryRef dict
;
1756 dict
= CFBundleGetInfoDictionary(bundle
);
1757 if (isA_CFDictionary(dict
)) {
1758 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1759 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1761 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1762 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1770 #pragma mark Standalone test code
1776 split(const void * key
, const void * value
, void * context
)
1778 CFArrayRef components
;
1779 CFStringRef entity_id
;
1780 CFStringRef service_id
;
1781 CFMutableDictionaryRef state_dict
;
1783 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1784 service_id
= CFArrayGetValueAtIndex(components
, 3);
1785 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1786 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
1787 if (state_dict
!= NULL
) {
1788 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
1790 state_dict
= CFDictionaryCreateMutable(NULL
,
1792 &kCFTypeDictionaryKeyCallBacks
,
1793 &kCFTypeDictionaryValueCallBacks
);
1796 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
1797 CFEqual(entity_id
, kSCEntNetIPv6
)) {
1798 CFDictionaryRef dict
;
1799 CFStringRef interface
;
1801 if (CFEqual(entity_id
, kSCEntNetIPv4
)) {
1802 dict
= ipv4_dict_create(value
);
1805 dict
= ipv6_dict_create(value
);
1808 CFDictionarySetValue(state_dict
, entity_id
, dict
);
1811 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
1812 if (interface
!= NULL
) {
1813 CFDictionaryRef dns
;
1814 CFMutableDictionaryRef new_dns
;
1816 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1818 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
1820 new_dns
= CFDictionaryCreateMutable(NULL
,
1822 &kCFTypeDictionaryKeyCallBacks
,
1823 &kCFTypeDictionaryValueCallBacks
);
1825 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1826 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1829 } else if (CFEqual(entity_id
, kSCEntNetDNS
)) {
1830 CFDictionaryRef dns
;
1832 dns
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
);
1834 CFStringRef interface
;
1836 interface
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
);
1837 if (interface
!= NULL
) {
1838 CFMutableDictionaryRef new_dns
;
1840 new_dns
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
1841 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
);
1842 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
);
1845 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1848 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
);
1851 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1854 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1855 CFRelease(state_dict
);
1856 CFRelease(components
);
1862 main(int argc
, char **argv
)
1864 CFDictionaryRef entities
;
1866 CFArrayRef multicast_resolvers
;
1867 CFStringRef pattern
;
1868 CFMutableArrayRef patterns
;
1869 CFStringRef primary
= NULL
;
1870 CFDictionaryRef primaryDNS
= NULL
;
1871 CFArrayRef private_resolvers
;
1872 CFArrayRef service_order
= NULL
;
1873 CFMutableDictionaryRef service_state_dict
;
1874 CFDictionaryRef setup_global_ipv4
;
1875 CFDictionaryRef state_global_ipv4
;
1876 SCDynamicStoreRef store
;
1880 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1882 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1884 // get IPv4, IPv6, and DNS entities
1885 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1886 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1887 kSCDynamicStoreDomainState
,
1890 CFArrayAppendValue(patterns
, pattern
);
1892 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1893 kSCDynamicStoreDomainState
,
1896 CFArrayAppendValue(patterns
, pattern
);
1898 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1899 kSCDynamicStoreDomainState
,
1902 CFArrayAppendValue(patterns
, pattern
);
1904 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1905 CFRelease(patterns
);
1907 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1909 &kCFTypeDictionaryKeyCallBacks
,
1910 &kCFTypeDictionaryValueCallBacks
);
1911 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1912 CFRelease(entities
);
1914 // get primary service ID
1915 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1916 kSCDynamicStoreDomainState
,
1918 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1920 if (state_global_ipv4
!= NULL
) {
1921 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1922 if (primary
!= NULL
) {
1923 CFDictionaryRef service_dict
;
1925 // get DNS configuration for primary service
1926 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1927 if (service_dict
!= NULL
) {
1928 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1934 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1935 kSCDynamicStoreDomainSetup
,
1937 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1939 if (setup_global_ipv4
!= NULL
) {
1940 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1943 // get multicast resolvers
1944 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1945 kSCDynamicStoreDomainState
,
1947 CFSTR(kDNSServiceCompMulticastDNS
));
1948 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1951 // get private resolvers
1952 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1953 kSCDynamicStoreDomainState
,
1955 CFSTR(kDNSServiceCompPrivateDNS
));
1956 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1959 // update DNS configuration
1960 dns_configuration_init(CFBundleGetMainBundle());
1961 (void)dns_configuration_set(primaryDNS
,
1964 multicast_resolvers
,
1968 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1969 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1970 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
1971 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1972 CFRelease(service_state_dict
);