2 * Copyright (c) 2004-2007 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>
35 #include <sys/types.h>
36 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <arpa/nameser.h>
44 #include <CoreFoundation/CoreFoundation.h>
45 #include <SystemConfiguration/SystemConfiguration.h>
46 #include <SystemConfiguration/SCPrivate.h>
47 #include <SystemConfiguration/SCValidation.h>
50 #include <dnsinfo_create.h>
53 #ifndef kDNSServiceCompPrivateDNS
54 #define kDNSServiceCompPrivateDNS "PrivateDNS"
57 /* pre-defined (supplemental) resolver configurations */
58 static CFArrayRef S_predefined
= NULL
;
60 /* private DNS resolver configurations */
61 static CFNumberRef S_pdns_timeout
= NULL
;
65 add_resolver(CFMutableArrayRef supplemental
, CFMutableDictionaryRef resolver
)
68 CFIndex n_supplemental
;
70 uint32_t order_val
= 0;
72 order
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
);
73 if (!isA_CFNumber(order
) ||
74 !CFNumberGetValue(order
, kCFNumberIntType
, &order_val
)) {
79 n_supplemental
= CFArrayGetCount(supplemental
);
80 for (i
= 0; i
< n_supplemental
; i
++) {
81 CFDictionaryRef supplemental_resolver
;
83 supplemental_resolver
= CFArrayGetValueAtIndex(supplemental
, i
);
84 if (CFEqual(resolver
, supplemental_resolver
)) {
90 CFMutableDictionaryRef compare
;
93 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, supplemental_resolver
);
94 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
);
95 match
= CFEqual(resolver
, compare
);
98 CFNumberRef supplemental_order
;
99 uint32_t supplemental_order_val
= 0;
101 // if only the search order's are different
102 supplemental_order
= CFDictionaryGetValue(supplemental_resolver
, kSCPropNetDNSSearchOrder
);
103 if (!isA_CFNumber(supplemental_order
) ||
104 !CFNumberGetValue(supplemental_order
, kCFNumberIntType
, &supplemental_order_val
)) {
105 supplemental_order_val
= 0;
108 if (order_val
< supplemental_order_val
) {
109 // if we should prefer this match resolver, else just skip it
110 CFArraySetValueAtIndex(supplemental
, i
, resolver
);
118 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &n_supplemental
);
119 CFDictionarySetValue(resolver
, CFSTR("*ORDER*"), order
);
122 CFArrayAppendValue(supplemental
, resolver
);
128 add_supplemental(CFMutableArrayRef supplemental
, CFDictionaryRef dns
, uint32_t defaultOrder
)
135 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
136 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
137 if (n_domains
== 0) {
141 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
142 if (orders
!= NULL
) {
143 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
149 * yes, this is a "supplemental" resolver configuration, expand
150 * the match domains and add each to the supplemental list.
152 for (i
= 0; i
< n_domains
; i
++) {
153 CFStringRef match_domain
;
154 CFNumberRef match_order
;
155 CFMutableDictionaryRef match_resolver
;
157 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
158 if (!isA_CFString(match_domain
)) {
162 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
164 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
166 // remove keys we don't want in a supplemental resolver
167 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
168 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
169 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
170 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
);
172 // set supplemental resolver "domain"
173 if (CFStringGetLength(match_domain
) > 0) {
174 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
176 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
);
179 // set supplemental resolver "search_order"
180 if (isA_CFNumber(match_order
)) {
181 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
182 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
185 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
186 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
189 defaultOrder
++; // if multiple domains, maintain ordering
191 add_resolver(supplemental
, match_resolver
);
192 CFRelease(match_resolver
);
200 add_predefined_resolvers(CFMutableArrayRef supplemental
)
205 if (S_predefined
== NULL
) {
209 n
= CFArrayGetCount(S_predefined
);
210 for (i
= 0; i
< n
; i
++) {
211 uint32_t defaultOrder
;
214 dns
= CFArrayGetValueAtIndex(S_predefined
, i
);
215 if (!isA_CFDictionary(dns
)) {
219 defaultOrder
= DEFAULT_SEARCH_ORDER
220 + (DEFAULT_SEARCH_ORDER
/ 2)
221 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
222 add_supplemental(supplemental
, dns
, defaultOrder
);
233 add_supplemental_resolvers(CFMutableArrayRef supplemental
, CFDictionaryRef services
, CFArrayRef service_order
)
235 const void * keys_q
[N_QUICK
];
236 const void ** keys
= keys_q
;
240 const void * vals_q
[N_QUICK
];
241 const void ** vals
= vals_q
;
243 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
244 if (n_services
== 0) {
245 return; // if no services
248 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
249 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
250 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
253 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
255 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
256 for (i
= 0; i
< n_services
; i
++) {
257 uint32_t defaultOrder
;
259 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
261 if (!isA_CFDictionary(service
)) {
265 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
266 if (!isA_CFDictionary(dns
)) {
270 defaultOrder
= DEFAULT_SEARCH_ORDER
271 - (DEFAULT_SEARCH_ORDER
/ 2)
272 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
274 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
275 // push out services not specified in service order
276 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
279 add_supplemental(supplemental
, dns
, defaultOrder
);
282 if (keys
!= keys_q
) {
283 CFAllocatorDeallocate(NULL
, keys
);
284 CFAllocatorDeallocate(NULL
, vals
);
292 add_private_resolvers(CFMutableArrayRef supplemental
, CFArrayRef privateResolvers
)
297 n
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0;
298 for (i
= 0; i
< n
; i
++) {
299 uint32_t defaultOrder
;
302 CFMutableDictionaryRef resolver
;
304 domain
= CFArrayGetValueAtIndex(privateResolvers
, i
);
305 if (!isA_CFString(domain
) || (CFStringGetLength(domain
) == 0)) {
309 defaultOrder
= DEFAULT_SEARCH_ORDER
310 - (DEFAULT_SEARCH_ORDER
/ 4)
311 + ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
313 resolver
= CFDictionaryCreateMutable(NULL
,
315 &kCFTypeDictionaryKeyCallBacks
,
316 &kCFTypeDictionaryValueCallBacks
);
317 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
);
318 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns"));
319 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
320 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
);
322 if (S_pdns_timeout
!= NULL
) {
323 CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
);
325 add_resolver(supplemental
, resolver
);
333 static CFComparisonResult
334 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
336 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
337 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
340 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
341 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
343 num1
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
344 if (!isA_CFNumber(num1
) ||
345 !CFNumberGetValue(num1
, kCFNumberIntType
, &order1
)) {
346 order1
= DEFAULT_SEARCH_ORDER
;
349 num2
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
350 if (!isA_CFNumber(num2
) ||
351 !CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
352 order2
= DEFAULT_SEARCH_ORDER
;
355 if (order1
== order2
) {
356 // if same "SearchOrder", retain original orderring for configurations
357 if (CFDictionaryGetValueIfPresent(dns1
, CFSTR("*ORDER*"), (const void **)&num1
) &&
358 CFDictionaryGetValueIfPresent(dns2
, CFSTR("*ORDER*"), (const void **)&num2
) &&
359 isA_CFNumber(num1
) &&
360 isA_CFNumber(num2
) &&
361 CFNumberGetValue(num1
, kCFNumberIntType
, &order1
) &&
362 CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
363 if (order1
== order2
) {
364 return kCFCompareEqualTo
;
366 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
370 return kCFCompareEqualTo
;
373 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
378 trimDomain(CFStringRef domain
)
382 if (!isA_CFString(domain
)) {
386 // remove any leading/trailing dots
387 length
= CFStringGetLength(domain
);
389 (CFStringFindWithOptions(domain
,
394 CFStringFindWithOptions(domain
,
396 CFRangeMake(0, length
),
397 kCFCompareAnchored
|kCFCompareBackwards
,
399 CFMutableStringRef trimmed
;
401 trimmed
= CFStringCreateMutableCopy(NULL
, 0, domain
);
402 CFStringTrim(trimmed
, CFSTR("."));
403 domain
= (CFStringRef
)trimmed
;
404 length
= CFStringGetLength(domain
);
419 update_search_domains(CFMutableDictionaryRef
*defaultDomain
, CFArrayRef supplemental
)
421 CFStringRef defaultDomainName
= NULL
;
422 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
423 CFArrayRef defaultSearchDomains
= NULL
;
424 CFIndex defaultSearchIndex
= 0;
426 CFMutableArrayRef mySearchDomains
;
427 CFMutableArrayRef mySupplemental
= (CFMutableArrayRef
)supplemental
;
428 CFIndex n_supplemental
;
429 Boolean searchDomainAdded
= FALSE
;
431 n_supplemental
= CFArrayGetCount(supplemental
);
432 if (n_supplemental
== 0) {
433 // if no supplemental domains
437 if (*defaultDomain
!= NULL
) {
440 num
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSSearchOrder
);
441 if (!isA_CFNumber(num
) ||
442 !CFNumberGetValue(num
, kCFNumberIntType
, &defaultOrder
)) {
443 defaultOrder
= DEFAULT_SEARCH_ORDER
;
446 defaultDomainName
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSDomainName
);
447 defaultSearchDomains
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSSearchDomains
);
450 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
452 if (isA_CFArray(defaultSearchDomains
)) {
455 n_search
= CFArrayGetCount(defaultSearchDomains
);
456 for (i
= 0; i
< n_search
; i
++) {
459 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
460 search
= trimDomain(search
);
461 if (search
!= NULL
) {
462 CFArrayAppendValue(mySearchDomains
, search
);
467 defaultDomainName
= trimDomain(defaultDomainName
);
468 if (defaultDomainName
!= NULL
) {
470 int domain_parts
= 1;
473 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
476 kCFStringEncodingUTF8
);
477 CFRelease(defaultDomainName
);
479 // count domain parts
480 for (dp
= domain
; *dp
!= '\0'; dp
++) {
487 for (i
= LOCALDOMAINPARTS
; i
<= domain_parts
; i
++) {
490 search
= CFStringCreateWithCString(NULL
,
492 kCFStringEncodingUTF8
);
493 CFArrayAppendValue(mySearchDomains
, search
);
496 dp
= strchr(dp
, '.') + 1;
499 CFAllocatorDeallocate(NULL
, domain
);
503 if (n_supplemental
> 1) {
504 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
505 CFArraySortValues(mySupplemental
,
506 CFRangeMake(0, n_supplemental
),
507 compareBySearchOrder
,
511 for (i
= 0; i
< n_supplemental
; i
++) {
516 CFStringRef supplementalDomain
;
517 uint32_t supplementalOrder
;
519 dns
= CFArrayGetValueAtIndex(mySupplemental
, i
);
521 options
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
522 if (isA_CFString(options
) && CFEqual(options
, CFSTR("pdns"))) {
523 // don't add private resolver domains to the search list
527 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
528 supplementalDomain
= trimDomain(supplementalDomain
);
529 if (supplementalDomain
== NULL
) {
533 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
534 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
535 CFRelease(supplementalDomain
);
539 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
540 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
543 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
544 if (!isA_CFNumber(num
) ||
545 !CFNumberGetValue(num
, kCFNumberIntType
, &supplementalOrder
)) {
546 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
549 if (supplementalOrder
< defaultOrder
) {
550 if (domainIndex
!= kCFNotFound
) {
551 // if supplemental domain is already in the search list
552 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
553 if (domainIndex
< defaultSearchIndex
) {
554 defaultSearchIndex
--;
557 CFArrayInsertValueAtIndex(mySearchDomains
,
560 defaultSearchIndex
++;
561 searchDomainAdded
= TRUE
;
563 if (domainIndex
== kCFNotFound
) {
564 // add to the (end of the) search list
565 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
566 searchDomainAdded
= TRUE
;
570 CFRelease(supplementalDomain
);
573 if (searchDomainAdded
) {
574 if (*defaultDomain
== NULL
) {
575 *defaultDomain
= CFDictionaryCreateMutable(NULL
,
577 &kCFTypeDictionaryKeyCallBacks
,
578 &kCFTypeDictionaryValueCallBacks
);
580 CFDictionarySetValue(*defaultDomain
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
583 CFRelease(mySearchDomains
);
584 if (mySupplemental
!= supplemental
) CFRelease(mySupplemental
);
589 static dns_create_resolver_t
590 create_resolver(CFDictionaryRef dns
)
594 dns_create_resolver_t _resolver
;
597 _resolver
= _dns_resolver_create();
600 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
601 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
602 char domain
[NS_MAXDNAME
];
604 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
605 _dns_resolver_set_domain(&_resolver
, domain
);
609 // process search domains
610 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
611 if (isA_CFArray(list
)) {
613 CFIndex n
= CFArrayGetCount(list
);
615 // add "search" domains
616 for (i
= 0; i
< n
; i
++) {
617 str
= CFArrayGetValueAtIndex(list
, i
);
618 if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) {
619 char search
[NS_MAXDNAME
];
621 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
622 _dns_resolver_add_search(&_resolver
, search
);
628 // process nameserver addresses
629 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
630 if (isA_CFArray(list
)) {
632 CFIndex n
= CFArrayGetCount(list
);
634 for (i
= 0; i
< n
; i
++) {
637 struct sockaddr_in sin
;
638 struct sockaddr_in6 sin6
;
642 str
= CFArrayGetValueAtIndex(list
, i
);
643 if (!isA_CFString(str
)) {
647 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
651 bzero(&addr
, sizeof(addr
));
652 if (inet_aton(buf
, &addr
.sin
.sin_addr
) == 1) {
653 /* if IPv4 address */
654 addr
.sin
.sin_len
= sizeof(addr
.sin
);
655 addr
.sin
.sin_family
= AF_INET
;
656 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
657 } else if (inet_pton(AF_INET6
, buf
, &addr
.sin6
.sin6_addr
) == 1) {
658 /* if IPv6 address */
661 p
= strchr(buf
, '%');
663 addr
.sin6
.sin6_scope_id
= if_nametoindex(p
+ 1);
666 addr
.sin6
.sin6_len
= sizeof(addr
.sin6
);
667 addr
.sin6
.sin6_family
= AF_INET6
;
668 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
675 // process search order
676 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
677 if (isA_CFNumber(num
)) {
680 if (CFNumberGetValue(num
, kCFNumberIntType
, &order
)) {
681 _dns_resolver_set_order(&_resolver
, order
);
686 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
687 if (isA_CFNumber(num
)) {
690 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
691 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
696 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
697 if (isA_CFNumber(num
)) {
700 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
701 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
706 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
707 if (isA_CFString(str
)) {
710 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
711 if (options
!= NULL
) {
712 _dns_resolver_set_options(&_resolver
, options
);
713 CFAllocatorDeallocate(NULL
, options
);
723 dns_configuration_set(CFDictionaryRef defaultResolver
,
724 CFDictionaryRef services
,
725 CFArrayRef serviceOrder
,
726 CFArrayRef privateResolvers
)
729 CFMutableDictionaryRef myDefault
;
730 CFStringRef myDomain
= NULL
;
731 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
732 Boolean myOrderAdded
= FALSE
;
733 CFIndex n_supplemental
;
735 dns_create_resolver_t resolver
;
737 CFMutableArrayRef supplemental
;
739 if (defaultResolver
== NULL
) {
740 myDefault
= CFDictionaryCreateMutable(NULL
,
742 &kCFTypeDictionaryKeyCallBacks
,
743 &kCFTypeDictionaryValueCallBacks
);
745 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
747 // ensure that the default resolver has a search order
749 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
750 if (!isA_CFNumber(order
) ||
751 !CFNumberGetValue(order
, kCFNumberIntType
, &myOrder
)) {
753 myOrder
= DEFAULT_SEARCH_ORDER
;
754 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
755 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
760 // establish list of supplemental resolvers
762 supplemental
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
764 // identify search[] list and/or domain name
766 search
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchDomains
);
767 if (isA_CFArray(search
) && (CFArrayGetCount(search
) > 0)) {
768 myDomain
= CFArrayGetValueAtIndex(search
, 0);
769 myDomain
= isA_CFString(myDomain
);
772 if (myDomain
== NULL
) {
773 myDomain
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSDomainName
);
774 myDomain
= isA_CFString(myDomain
);
777 // add match for default domain
779 if (myDomain
!= NULL
) {
780 CFMutableDictionaryRef mySupplemental
;
782 mySupplemental
= CFDictionaryCreateMutableCopy(NULL
, 0, myDefault
);
783 CFDictionarySetValue (mySupplemental
, kSCPropNetDNSDomainName
, myDomain
);
784 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSearchDomains
);
785 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSupplementalMatchDomains
);
786 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSupplementalMatchOrders
);
787 add_resolver(supplemental
, mySupplemental
);
788 CFRelease(mySupplemental
);
791 // collect (and add) any supplemental resolver configurations
793 add_supplemental_resolvers(supplemental
, services
, serviceOrder
);
795 // collect (and add) any "private" resolver configurations
797 add_private_resolvers(supplemental
, privateResolvers
);
799 // update the "search" list
801 update_search_domains(&myDefault
, supplemental
);
803 // add any pre-defined resolver configurations
805 add_predefined_resolvers(supplemental
);
807 // check if the "match for default domain" (above) is really needed
809 if (myDomain
!= NULL
) {
810 Boolean sharedDomain
= FALSE
;
812 n_supplemental
= CFArrayGetCount(supplemental
);
813 for (i
= 1; i
< n_supplemental
; i
++) {
815 CFDictionaryRef mySupplemental
;
817 mySupplemental
= CFArrayGetValueAtIndex(supplemental
, i
);
818 domain
= CFDictionaryGetValue(mySupplemental
, kSCPropNetDNSDomainName
);
819 if (isA_CFString(domain
)) {
820 if (CFEqual(myDomain
, domain
)) {
825 if (CFStringHasSuffix(myDomain
, domain
)) {
828 dotIndex
= CFStringGetLength(myDomain
) - CFStringGetLength(domain
) - 1;
832 dot
= CFStringGetCharacterAtIndex(myDomain
, dotIndex
);
833 if (dot
== (UniChar
)'.') {
843 // if the default resolver domain name is not shared
844 CFArrayRemoveValueAtIndex(supplemental
, 0);
848 // establish resolver configuration
850 n_supplemental
= CFArrayGetCount(supplemental
);
851 if ((defaultResolver
== NULL
) && (n_supplemental
== 0)) {
853 * if no default or supplemental resolvers
855 if (!_dns_configuration_store(NULL
)) {
856 SCLog(TRUE
, LOG_ERR
, CFSTR("dns_configuration_set: could not store configuration"));
859 dns_create_config_t _config
;
862 * if default and/or supplemental resolvers are defined
864 _config
= _dns_configuration_create();
866 // add [default] resolver
868 if ((n_supplemental
== 0) && myOrderAdded
) {
869 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
871 resolver
= create_resolver(myDefault
);
872 _dns_configuration_add_resolver(&_config
, resolver
);
873 _dns_resolver_free(&resolver
);
875 // add [supplemental] resolvers
877 for (i
= 0; i
< n_supplemental
; i
++) {
878 CFDictionaryRef supplementalResolver
;
880 supplementalResolver
= CFArrayGetValueAtIndex(supplemental
, i
);
881 resolver
= create_resolver(supplementalResolver
);
882 _dns_configuration_add_resolver(&_config
, resolver
);
883 _dns_resolver_free(&resolver
);
886 // save configuration
888 if (!_dns_configuration_store(&_config
)) {
889 SCLog(TRUE
, LOG_ERR
, CFSTR("dns_configuration_set: could not store configuration"));
892 _dns_configuration_free(&_config
);
895 CFRelease(myDefault
);
896 CFRelease(supplemental
);
903 load_predefined_resolvers(CFBundleRef bundle
)
907 CFStringRef xmlError
= NULL
;
908 CFDataRef xmlResolvers
= NULL
;
910 url
= CFBundleCopyResourceURL(bundle
, CFSTR("Resolvers"), CFSTR("plist"), NULL
);
915 ok
= CFURLCreateDataAndPropertiesFromResource(NULL
, url
, &xmlResolvers
, NULL
, NULL
, NULL
);
917 if (!ok
|| (xmlResolvers
== NULL
)) {
921 /* convert the XML data into a property list */
922 S_predefined
= CFPropertyListCreateFromXMLData(NULL
, xmlResolvers
, kCFPropertyListImmutable
, &xmlError
);
923 CFRelease(xmlResolvers
);
924 if (S_predefined
== NULL
) {
925 if (xmlError
!= NULL
) {
926 SCLog(TRUE
, LOG_DEBUG
, CFSTR("add_predefined_resolvers: %@"), xmlError
);
932 if (!isA_CFArray(S_predefined
)) {
933 CFRelease(S_predefined
);
944 dns_configuration_init(CFBundleRef bundle
)
946 CFDictionaryRef dict
;
948 dict
= CFBundleGetInfoDictionary(bundle
);
949 if (isA_CFDictionary(dict
)) {
950 S_pdns_timeout
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout"));
951 S_pdns_timeout
= isA_CFNumber(S_pdns_timeout
);
954 load_predefined_resolvers(bundle
);
963 split(const void * key
, const void * value
, void * context
)
965 CFArrayRef components
;
966 CFStringRef entity_id
;
967 CFStringRef service_id
;
968 CFMutableDictionaryRef state_dict
;
970 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
971 service_id
= CFArrayGetValueAtIndex(components
, 3);
972 entity_id
= CFArrayGetValueAtIndex(components
, 4);
973 state_dict
= CFDictionaryCreateMutable(NULL
,
975 &kCFTypeDictionaryKeyCallBacks
,
976 &kCFTypeDictionaryValueCallBacks
);
977 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
978 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
979 CFRelease(state_dict
);
980 CFRelease(components
);
986 main(int argc
, char **argv
)
988 CFDictionaryRef entities
;
991 CFMutableArrayRef patterns
;
992 CFStringRef primary
= NULL
;
993 CFDictionaryRef primaryDNS
= NULL
;
994 CFArrayRef private_resolvers
;
995 CFArrayRef service_order
= NULL
;
996 CFMutableDictionaryRef service_state_dict
;
997 CFDictionaryRef setup_global_ipv4
;
998 CFDictionaryRef state_global_ipv4
;
999 SCDynamicStoreRef store
;
1002 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1004 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
1007 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1008 kSCDynamicStoreDomainState
,
1011 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1012 CFArrayAppendValue(patterns
, pattern
);
1014 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1015 CFRelease(patterns
);
1017 service_state_dict
= CFDictionaryCreateMutable(NULL
,
1019 &kCFTypeDictionaryKeyCallBacks
,
1020 &kCFTypeDictionaryValueCallBacks
);
1021 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
1022 CFRelease(entities
);
1024 // get primary service ID
1025 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1026 kSCDynamicStoreDomainState
,
1028 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1030 if (state_global_ipv4
!= NULL
) {
1031 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
1032 if (primary
!= NULL
) {
1033 CFDictionaryRef service_dict
;
1035 // get DNS configuration for primary service
1036 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
1037 if (service_dict
!= NULL
) {
1038 primaryDNS
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1044 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
1045 kSCDynamicStoreDomainSetup
,
1047 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
1049 if (setup_global_ipv4
!= NULL
) {
1050 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
1053 // get private resolvers
1054 key
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
1055 kSCDynamicStoreDomainState
,
1057 CFSTR(kDNSServiceCompPrivateDNS
));
1058 private_resolvers
= SCDynamicStoreCopyValue(store
, key
);
1061 // update DNS configuration
1062 dns_configuration_init(CFBundleGetMainBundle());
1063 dns_configuration_set(primaryDNS
, service_state_dict
, service_order
, private_resolvers
);
1066 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
1067 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
1068 if (private_resolvers
!= NULL
) CFRelease(private_resolvers
);
1069 CFRelease(service_state_dict
);