2 * Copyright (c) 2004-2009 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
49 #include <CoreFoundation/CoreFoundation.h>
50 #include <SystemConfiguration/SystemConfiguration.h>
51 #include <SystemConfiguration/SCPrivate.h>
52 #include <SystemConfiguration/SCValidation.h>
55 #include <dnsinfo_create.h>
58 #ifndef kDNSServiceCompMulticastDNS
59 #define kDNSServiceCompMulticastDNS "MulticastDNS"
61 #ifndef kDNSServiceCompPrivateDNS
62 #define kDNSServiceCompPrivateDNS "PrivateDNS"
65 /* multicast DNS resolver configurations */
66 static CFNumberRef S_mdns_timeout
= NULL
;
68 /* private DNS resolver configurations */
69 static CFNumberRef S_pdns_timeout
= NULL
;
73 add_resolver(CFMutableArrayRef supplemental
, CFMutableDictionaryRef resolver
)
76 CFIndex n_supplemental
;
78 uint32_t order_val
= 0;
80 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
81 if (!isA_CFNumber(order
) ||
82 !CFNumberGetValue(order
, kCFNumberIntType
, &order_val
)) {
87 n_supplemental
= CFArrayGetCount(supplemental
);
88 for (i
= 0; i
< n_supplemental
; i
++) {
89 CFDictionaryRef supplemental_resolver
;
91 supplemental_resolver
= CFArrayGetValueAtIndex(supplemental
, i
);
92 if (CFEqual(resolver
, supplemental_resolver
)) {
98 CFMutableDictionaryRef compare
;
101 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, supplemental_resolver
);
102 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
103 match
= CFEqual(resolver
, compare
);
106 CFNumberRef supplemental_order
;
107 uint32_t supplemental_order_val
= 0;
109 // if only the search order's are different
110 supplemental_order
= CFDictionaryGetValue(supplemental_resolver
, kSCPropNetDNSSearchOrder
);
111 if (!isA_CFNumber(supplemental_order
) ||
112 !CFNumberGetValue(supplemental_order
, kCFNumberIntType
, &supplemental_order_val
)) {
113 supplemental_order_val
= 0;
116 if (order_val
< supplemental_order_val
) {
117 // if we should prefer this match resolver, else just skip it
118 CFArraySetValueAtIndex(supplemental
, i
, resolver
);
126 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &n_supplemental
);
127 CFDictionarySetValue(resolver
, CFSTR("*ORDER*"), order
);
130 CFArrayAppendValue(supplemental
, resolver
);
136 add_supplemental(CFMutableArrayRef supplemental
, CFDictionaryRef dns
, uint32_t defaultOrder
)
143 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
144 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
145 if (n_domains
== 0) {
149 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
150 if (orders
!= NULL
) {
151 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
157 * yes, this is a "supplemental" resolver configuration, expand
158 * the match domains and add each to the supplemental list.
160 for (i
= 0; i
< n_domains
; i
++) {
161 CFStringRef match_domain
;
162 CFNumberRef match_order
;
163 CFMutableDictionaryRef match_resolver
;
165 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
166 if (!isA_CFString(match_domain
)) {
170 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
172 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
174 // remove keys we don't want in a supplemental resolver
175 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
176 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
177 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
178 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
180 // set supplemental resolver "domain"
181 if (CFStringGetLength(match_domain
) > 0) {
182 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
184 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
187 // set supplemental resolver "search_order"
188 if (isA_CFNumber(match_order
)) {
189 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
190 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
193 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
194 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
197 defaultOrder
++; // if multiple domains, maintain ordering
199 add_resolver(supplemental
, match_resolver
);
200 CFRelease(match_resolver
);
211 add_supplemental_resolvers(CFMutableArrayRef supplemental
, CFDictionaryRef services
, CFArrayRef service_order
)
213 const void * keys_q
[N_QUICK
];
214 const void ** keys
= keys_q
;
218 const void * vals_q
[N_QUICK
];
219 const void ** vals
= vals_q
;
221 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
222 if (n_services
== 0) {
223 return; // if no services
226 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
227 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
228 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
231 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
233 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
234 for (i
= 0; i
< n_services
; i
++) {
235 uint32_t defaultOrder
;
237 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
239 if (!isA_CFDictionary(service
)) {
243 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
244 if (!isA_CFDictionary(dns
)) {
248 defaultOrder
= DEFAULT_SEARCH_ORDER
249 - (DEFAULT_SEARCH_ORDER
/ 2)
250 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
252 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
253 // push out services not specified in service order
254 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
257 add_supplemental(supplemental
, dns
, defaultOrder
);
260 if (keys
!= keys_q
) {
261 CFAllocatorDeallocate(NULL
, keys
);
262 CFAllocatorDeallocate(NULL
, vals
);
270 add_multicast_resolvers(CFMutableArrayRef supplemental
, CFArrayRef multicastResolvers
)
275 n
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0;
276 for (i
= 0; i
< n
; i
++) {
277 uint32_t defaultOrder
;
280 CFMutableDictionaryRef resolver
;
282 domain
= CFArrayGetValueAtIndex(multicastResolvers
, i
);
283 if (!isA_CFString(domain
) || (CFStringGetLength(domain
) == 0)) {
287 defaultOrder
= DEFAULT_SEARCH_ORDER
288 + (DEFAULT_SEARCH_ORDER
/ 2)
289 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
291 resolver
= CFDictionaryCreateMutable(NULL
,
293 &kCFTypeDictionaryKeyCallBacks
,
294 &kCFTypeDictionaryValueCallBacks
);
295 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
296 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns"));
297 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
298 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
300 if (S_mdns_timeout
!= NULL
) {
301 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
);
303 add_resolver(supplemental
, resolver
);
312 add_private_resolvers(CFMutableArrayRef supplemental
, CFArrayRef privateResolvers
)
317 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
318 for (i
= 0; i
< n
; i
++) {
319 uint32_t defaultOrder
;
322 CFMutableDictionaryRef resolver
;
324 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
325 if (!isA_CFString(domain
) || (CFStringGetLength(domain
) == 0)) {
329 defaultOrder
= DEFAULT_SEARCH_ORDER
330 - (DEFAULT_SEARCH_ORDER
/ 4)
331 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
333 resolver
= CFDictionaryCreateMutable(NULL
,
335 &kCFTypeDictionaryKeyCallBacks
,
336 &kCFTypeDictionaryValueCallBacks
);
337 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
338 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
339 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
340 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
342 if (S_pdns_timeout
!= NULL
) {
343 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
345 add_resolver(supplemental
, resolver
);
353 static CFComparisonResult
354 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
356 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
357 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
360 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
361 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
363 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
364 if (!isA_CFNumber(num1
) ||
365 !CFNumberGetValue(num1
, kCFNumberIntType
, &order1
)) {
366 order1
= DEFAULT_SEARCH_ORDER
;
369 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
370 if (!isA_CFNumber(num2
) ||
371 !CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
372 order2
= DEFAULT_SEARCH_ORDER
;
375 if (order1
== order2
) {
376 // if same "SearchOrder", retain original orderring for configurations
377 if (CFDictionaryGetValueIfPresent(dns1
, CFSTR("*ORDER*"), (const void **)&num1
) &&
378 CFDictionaryGetValueIfPresent(dns2
, CFSTR("*ORDER*"), (const void **)&num2
) &&
379 isA_CFNumber(num1
) &&
380 isA_CFNumber(num2
) &&
381 CFNumberGetValue(num1
, kCFNumberIntType
, &order1
) &&
382 CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
383 if (order1
== order2
) {
384 return kCFCompareEqualTo
;
386 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
390 return kCFCompareEqualTo
;
393 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
398 trimDomain(CFStringRef domain
)
402 if (!isA_CFString(domain
)) {
406 // remove any leading/trailing dots
407 length
= CFStringGetLength(domain
);
409 (CFStringFindWithOptions(domain
,
414 CFStringFindWithOptions(domain
,
416 CFRangeMake(0, length
),
417 kCFCompareAnchored
|kCFCompareBackwards
,
419 CFMutableStringRef trimmed
;
421 trimmed
= CFStringCreateMutableCopy(NULL
, 0, domain
);
422 CFStringTrim(trimmed
, CFSTR("."));
423 domain
= (CFStringRef
)trimmed
;
424 length
= CFStringGetLength(domain
);
439 update_search_domains(CFMutableDictionaryRef
*defaultDomain
, CFArrayRef supplemental
)
441 CFStringRef defaultDomainName
= NULL
;
442 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
443 CFArrayRef defaultSearchDomains
= NULL
;
444 CFIndex defaultSearchIndex
= 0;
446 CFMutableArrayRef mySearchDomains
;
447 CFMutableArrayRef mySupplemental
= NULL
;
448 CFIndex n_supplemental
;
449 Boolean searchDomainAdded
= FALSE
;
451 n_supplemental
= CFArrayGetCount(supplemental
);
452 if (n_supplemental
== 0) {
453 // if no supplemental domains
457 if (*defaultDomain
!= NULL
) {
460 num
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSSearchOrder
);
461 if (!isA_CFNumber(num
) ||
462 !CFNumberGetValue(num
, kCFNumberIntType
, &defaultOrder
)) {
463 defaultOrder
= DEFAULT_SEARCH_ORDER
;
466 defaultDomainName
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSDomainName
);
467 defaultSearchDomains
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSSearchDomains
);
470 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
472 if (isA_CFArray(defaultSearchDomains
)) {
475 n_search
= CFArrayGetCount(defaultSearchDomains
);
476 for (i
= 0; i
< n_search
; i
++) {
479 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
480 search
= trimDomain(search
);
481 if (search
!= NULL
) {
482 CFArrayAppendValue(mySearchDomains
, search
);
487 defaultDomainName
= trimDomain(defaultDomainName
);
488 if (defaultDomainName
!= NULL
) {
490 int domain_parts
= 1;
493 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
496 kCFStringEncodingUTF8
);
497 CFRelease(defaultDomainName
);
499 // count domain parts
500 for (dp
= domain
; *dp
!= '\0'; dp
++) {
507 for (i
= LOCALDOMAINPARTS
; i
<= domain_parts
; i
++) {
510 search
= CFStringCreateWithCString(NULL
,
512 kCFStringEncodingUTF8
);
513 CFArrayAppendValue(mySearchDomains
, search
);
516 dp
= strchr(dp
, '.') + 1;
519 CFAllocatorDeallocate(NULL
, domain
);
523 if (n_supplemental
> 1) {
524 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
525 CFArraySortValues(mySupplemental
,
526 CFRangeMake(0, n_supplemental
),
527 compareBySearchOrder
,
529 supplemental
= mySupplemental
;
532 for (i
= 0; i
< n_supplemental
; i
++) {
537 CFStringRef supplementalDomain
;
538 uint32_t supplementalOrder
;
540 dns
= CFArrayGetValueAtIndex(supplemental
, i
);
542 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
543 if (isA_CFString(options
)) {
546 if (CFEqual(options
, CFSTR("pdns"))) {
547 // don't add private resolver domains to the search list
551 range
= CFStringFind(options
, CFSTR("interface="), 0);
552 if (range
.location
!= kCFNotFound
) {
553 // don't add scoped resolver domains to the search list
558 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
559 supplementalDomain
= trimDomain(supplementalDomain
);
560 if (supplementalDomain
== NULL
) {
564 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
565 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
566 CFRelease(supplementalDomain
);
570 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
571 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
574 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
575 if (!isA_CFNumber(num
) ||
576 !CFNumberGetValue(num
, kCFNumberIntType
, &supplementalOrder
)) {
577 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
580 if (supplementalOrder
< defaultOrder
) {
581 if (domainIndex
!= kCFNotFound
) {
582 // if supplemental domain is already in the search list
583 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
584 if (domainIndex
< defaultSearchIndex
) {
585 defaultSearchIndex
--;
588 CFArrayInsertValueAtIndex(mySearchDomains
,
591 defaultSearchIndex
++;
592 searchDomainAdded
= TRUE
;
594 if (domainIndex
== kCFNotFound
) {
595 // add to the (end of the) search list
596 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
597 searchDomainAdded
= TRUE
;
601 CFRelease(supplementalDomain
);
604 if (searchDomainAdded
) {
605 if (*defaultDomain
== NULL
) {
606 *defaultDomain
= CFDictionaryCreateMutable(NULL
,
608 &kCFTypeDictionaryKeyCallBacks
,
609 &kCFTypeDictionaryValueCallBacks
);
611 CFDictionarySetValue(*defaultDomain
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
614 CFRelease(mySearchDomains
);
615 if (mySupplemental
!= NULL
) CFRelease(mySupplemental
);
620 static dns_create_resolver_t
621 create_resolver(CFDictionaryRef dns
)
625 dns_create_resolver_t _resolver
;
628 _resolver
= _dns_resolver_create();
631 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
632 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
633 char domain
[NS_MAXDNAME
];
635 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
636 _dns_resolver_set_domain(&_resolver
, domain
);
640 // process search domains
641 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
642 if (isA_CFArray(list
)) {
644 CFIndex n
= CFArrayGetCount(list
);
646 // add "search" domains
647 for (i
= 0; i
< n
; i
++) {
648 str
= CFArrayGetValueAtIndex(list
, i
);
649 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
650 char search
[NS_MAXDNAME
];
652 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
653 _dns_resolver_add_search(&_resolver
, search
);
659 // process nameserver addresses
660 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
661 if (isA_CFArray(list
)) {
663 CFIndex n
= CFArrayGetCount(list
);
665 for (i
= 0; i
< n
; i
++) {
668 struct sockaddr_in sin
;
669 struct sockaddr_in6 sin6
;
673 str
= CFArrayGetValueAtIndex(list
, i
);
674 if (!isA_CFString(str
)) {
678 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
682 bzero(&addr
, sizeof(addr
));
683 if (inet_aton(buf
, &addr
.sin
.sin_addr
) == 1) {
684 /* if IPv4 address */
685 addr
.sin
.sin_len
= sizeof(addr
.sin
);
686 addr
.sin
.sin_family
= AF_INET
;
687 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
688 } else if (inet_pton(AF_INET6
, buf
, &addr
.sin6
.sin6_addr
) == 1) {
689 /* if IPv6 address */
692 p
= strchr(buf
, '%');
694 addr
.sin6
.sin6_scope_id
= if_nametoindex(p
+ 1);
697 addr
.sin6
.sin6_len
= sizeof(addr
.sin6
);
698 addr
.sin6
.sin6_family
= AF_INET6
;
699 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
706 // process search order
707 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
708 if (isA_CFNumber(num
)) {
711 if (CFNumberGetValue(num
, kCFNumberIntType
, &order
)) {
712 _dns_resolver_set_order(&_resolver
, order
);
717 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
);
718 if (isA_CFArray(list
)) {
720 CFIndex n
= CFArrayGetCount(list
);
722 for (i
= 0; i
< n
; i
++) {
725 dns_sortaddr_t sortaddr
;
727 str
= CFArrayGetValueAtIndex(list
, i
);
728 if (!isA_CFString(str
)) {
732 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
736 slash
= strchr(buf
, '/');
741 bzero(&sortaddr
, sizeof(sortaddr
));
742 if (inet_aton(buf
, &sortaddr
.address
) != 1) {
743 /* if address not valid */
748 if (inet_aton(slash
+ 1, &sortaddr
.mask
) != 1) {
749 /* if subnet mask not valid */
756 a
= ntohl(sortaddr
.address
.s_addr
);
759 } else if (IN_CLASSB(a
)) {
761 } else if (IN_CLASSC(a
)) {
767 sortaddr
.mask
.s_addr
= htonl(m
);
770 _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
);
775 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
776 if (isA_CFNumber(num
)) {
779 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
780 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
785 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
786 if (isA_CFNumber(num
)) {
789 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
790 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
795 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
796 if (isA_CFString(str
)) {
799 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
800 if (options
!= NULL
) {
801 _dns_resolver_set_options(&_resolver
, options
);
802 CFAllocatorDeallocate(NULL
, options
);
812 dns_configuration_set(CFDictionaryRef defaultResolver
,
813 CFDictionaryRef services
,
814 CFArrayRef serviceOrder
,
815 CFArrayRef multicastResolvers
,
816 CFArrayRef privateResolvers
)
819 CFMutableDictionaryRef myDefault
;
820 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
821 Boolean myOrderAdded
= FALSE
;
822 CFIndex n_supplemental
;
824 dns_create_resolver_t resolver
;
825 CFMutableArrayRef supplemental
;
827 #ifdef SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
828 CFStringRef myDomain
= NULL
;
830 #endif // SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
832 if (defaultResolver
== NULL
) {
833 myDefault
= CFDictionaryCreateMutable(NULL
,
835 &kCFTypeDictionaryKeyCallBacks
,
836 &kCFTypeDictionaryValueCallBacks
);
838 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
840 // ensure that the default resolver has a search order
842 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
843 if (!isA_CFNumber(order
) ||
844 !CFNumberGetValue(order
, kCFNumberIntType
, &myOrder
)) {
846 myOrder
= DEFAULT_SEARCH_ORDER
;
847 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
848 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
853 // establish list of supplemental resolvers
855 supplemental
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
857 // identify search[] list and/or domain name
859 #ifdef SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
860 search
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchDomains
);
861 if (isA_CFArray(search
) && (CFArrayGetCount(search
) > 0)) {
862 myDomain
= CFArrayGetValueAtIndex(search
, 0);
863 myDomain
= isA_CFString(myDomain
);
866 if (myDomain
== NULL
) {
867 myDomain
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSDomainName
);
868 myDomain
= isA_CFString(myDomain
);
871 // add match for default domain
873 if (myDomain
!= NULL
) {
874 CFMutableDictionaryRef mySupplemental
;
876 mySupplemental
= CFDictionaryCreateMutableCopy(NULL
, 0, myDefault
);
877 CFDictionarySetValue (mySupplemental
, kSCPropNetDNSDomainName
, myDomain
);
878 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSearchDomains
);
879 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSupplementalMatchDomains
);
880 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSupplementalMatchOrders
);
881 add_resolver(supplemental
, mySupplemental
);
882 CFRelease(mySupplemental
);
884 #endif // SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
886 // collect (and add) any supplemental resolver configurations
888 add_supplemental_resolvers(supplemental
, services
, serviceOrder
);
890 // collect (and add) any "private" resolver configurations
892 add_private_resolvers(supplemental
, privateResolvers
);
894 // update the "search" list
896 update_search_domains(&myDefault
, supplemental
);
898 // collect (and add) any "multicast" resolver configurations
900 add_multicast_resolvers(supplemental
, multicastResolvers
);
902 // check if the "match for default domain" (above) is really needed
904 #ifdef SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
905 if (myDomain
!= NULL
) {
906 Boolean sharedDomain
= FALSE
;
908 n_supplemental
= CFArrayGetCount(supplemental
);
909 for (i
= 1; i
< n_supplemental
; i
++) {
911 CFDictionaryRef mySupplemental
;
913 mySupplemental
= CFArrayGetValueAtIndex(supplemental
, i
);
914 domain
= CFDictionaryGetValue(mySupplemental
, kSCPropNetDNSDomainName
);
915 if (isA_CFString(domain
)) {
916 if (CFEqual(myDomain
, domain
)) {
921 if (CFStringHasSuffix(myDomain
, domain
)) {
924 dotIndex
= CFStringGetLength(myDomain
) - CFStringGetLength(domain
) - 1;
928 dot
= CFStringGetCharacterAtIndex(myDomain
, dotIndex
);
929 if (dot
== (UniChar
)'.') {
939 // if the default resolver domain name is not shared
940 CFArrayRemoveValueAtIndex(supplemental
, 0);
943 #endif // SPECIAL_HANDLING_FOR_DEFAULT_DOMAIN
945 // establish resolver configuration
947 n_supplemental
= CFArrayGetCount(supplemental
);
948 if ((defaultResolver
== NULL
) && (n_supplemental
== 0)) {
950 * if no default or supplemental resolvers
952 if (!_dns_configuration_store(NULL
)) {
953 SCLog(TRUE
, LOG_ERR
, CFSTR("dns_configuration_set: could not store configuration"));
956 dns_create_config_t _config
;
959 * if default and/or supplemental resolvers are defined
961 _config
= _dns_configuration_create();
963 // add [default] resolver
965 if ((n_supplemental
== 0) && myOrderAdded
) {
966 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
968 resolver
= create_resolver(myDefault
);
969 _dns_configuration_add_resolver(&_config
, resolver
);
970 _dns_resolver_free(&resolver
);
972 // add [supplemental] resolvers
974 for (i
= 0; i
< n_supplemental
; i
++) {
975 CFDictionaryRef supplementalResolver
;
977 supplementalResolver
= CFArrayGetValueAtIndex(supplemental
, i
);
978 resolver
= create_resolver(supplementalResolver
);
979 _dns_configuration_add_resolver(&_config
, resolver
);
980 _dns_resolver_free(&resolver
);
983 #if !TARGET_OS_IPHONE
984 // add flatfile resolvers
986 _dnsinfo_flatfile_add_resolvers(&_config
);
987 #endif // !TARGET_OS_IPHONE
989 // save configuration
991 if (!_dns_configuration_store(&_config
)) {
992 SCLog(TRUE
, LOG_ERR
, CFSTR("dns_configuration_set: could not store configuration"));
995 _dns_configuration_free(&_config
);
998 CFRelease(myDefault
);
999 CFRelease(supplemental
);
1005 #if !TARGET_OS_IPHONE
1006 static SCDynamicStoreRef dns_configuration_store
;
1007 static SCDynamicStoreCallBack dns_configuration_callout
;
1010 dns_configuration_changed(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1012 CFStringRef key
= CFSTR(_PATH_RESOLVER_DIR
);
1014 Boolean resolvers_now
;
1015 static Boolean resolvers_save
= FALSE
;
1016 struct stat statbuf
;
1018 resolvers_now
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0);
1019 if (!resolvers_save
&& (resolvers_save
== resolvers_now
)) {
1020 // if we did not (and still do not) have an "/etc/resolvers"
1021 // directory than this notification is the result of a change
1022 // to the "/etc" directory.
1025 resolvers_save
= resolvers_now
;
1027 SCLog(TRUE
, LOG_DEBUG
, CFSTR(_PATH_RESOLVER_DIR
" changed"));
1029 // fake a "DNS" change
1030 keys
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
1031 (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
);
1039 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
)
1042 mach_port_t notify_port
;
1044 CFRunLoopSourceRef rls
;
1047 dns_configuration_store
= store
;
1048 dns_configuration_callout
= callout
;
1050 status
= notify_register_mach_port(_PATH_RESOLVER_DIR
, ¬ify_port
, 0, ¬ify_token
);
1051 if (status
!= NOTIFY_STATUS_OK
) {
1052 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("notify_register_mach_port() failed"));
1056 status
= notify_monitor_file(notify_token
, "/private" _PATH_RESOLVER_DIR
, 0);
1057 if (status
!= NOTIFY_STATUS_OK
) {
1058 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("notify_monitor_file() failed"));
1059 (void)notify_cancel(notify_token
);
1063 mp
= CFMachPortCreateWithPort(NULL
, notify_port
, dns_configuration_changed
, NULL
, NULL
);
1065 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("CFMachPortCreateWithPort() failed"));
1066 (void)notify_cancel(notify_token
);
1070 rls
= CFMachPortCreateRunLoopSource(NULL
, mp
, -1);
1072 SCLOG(NULL
, NULL
, ASL_LEVEL_ERR
, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1074 (void)notify_cancel(notify_token
);
1077 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1083 #endif // !TARGET_OS_IPHONE
1088 dns_configuration_init(CFBundleRef bundle
)
1090 CFDictionaryRef dict
;
1092 dict
= CFBundleGetInfoDictionary(bundle
);
1093 if (isA_CFDictionary(dict
)) {
1094 S_mdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout"));
1095 S_mdns_timeout
= isA_CFNumber(S_mdns_timeout
);
1097 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
1098 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
1109 split(const void * key
, const void * value
, void * context
)
1111 CFArrayRef components
;
1112 CFStringRef entity_id
;
1113 CFStringRef service_id
;
1114 CFMutableDictionaryRef state_dict
;
1116 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
1117 service_id
= CFArrayGetValueAtIndex(components
, 3);
1118 entity_id
= CFArrayGetValueAtIndex(components
, 4);
1119 state_dict
= CFDictionaryCreateMutable(NULL
,
1121 &kCFTypeDictionaryKeyCallBacks
,
1122 &kCFTypeDictionaryValueCallBacks
);
1123 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
1124 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
1125 CFRelease(state_dict
);
1126 CFRelease(components
);
1132 main(int argc
, char **argv
)
1134 CFDictionaryRef entities
;
1136 CFArrayRef multicast_resolvers
;
1137 CFStringRef pattern
;
1138 CFMutableArrayRef patterns
;
1139 CFStringRef primary
= NULL
;
1140 CFDictionaryRef primaryDNS
= NULL
;
1141 CFArrayRef private_resolvers
;
1142 CFArrayRef service_order
= NULL
;
1143 CFMutableDictionaryRef service_state_dict
;
1144 CFDictionaryRef setup_global_ipv4
;
1145 CFDictionaryRef state_global_ipv4
;
1146 SCDynamicStoreRef store
;
1149 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1151 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1154 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1155 kSCDynamicStoreDomainState
,
1158 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1159 CFArrayAppendValue(patterns
, pattern
);
1161 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1162 CFRelease(patterns
);
1164 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1166 &kCFTypeDictionaryKeyCallBacks
,
1167 &kCFTypeDictionaryValueCallBacks
);
1168 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1169 CFRelease(entities
);
1171 // get primary service ID
1172 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1173 kSCDynamicStoreDomainState
,
1175 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1177 if (state_global_ipv4
!= NULL
) {
1178 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1179 if (primary
!= NULL
) {
1180 CFDictionaryRef service_dict
;
1182 // get DNS configuration for primary service
1183 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1184 if (service_dict
!= NULL
) {
1185 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1191 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1192 kSCDynamicStoreDomainSetup
,
1194 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1196 if (setup_global_ipv4
!= NULL
) {
1197 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1200 // get multicast resolvers
1201 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1202 kSCDynamicStoreDomainState
,
1204 CFSTR(kDNSServiceCompMulticastDNS
));
1205 multicast_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1208 // get private resolvers
1209 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1210 kSCDynamicStoreDomainState
,
1212 CFSTR(kDNSServiceCompPrivateDNS
));
1213 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1216 // update DNS configuration
1217 dns_configuration_init(CFBundleGetMainBundle());
1218 dns_configuration_set(primaryDNS
,
1221 multicast_resolvers
,
1225 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1226 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1227 if (multicast_resolvers
!= NULL
) CFRelease(multicast_resolvers
);
1228 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1229 CFRelease(service_state_dict
);