2 * Copyright (c) 2004 Apple Computer, 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 /* pre-defined (supplemental) resolver configurations */
54 static CFArrayRef S_predefined
= NULL
;
58 add_supplemental(CFMutableArrayRef supplemental
, CFDictionaryRef dns
, uint32_t defaultOrder
)
66 domains
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
);
67 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
72 orders
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
);
74 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
80 * yes, this is a "supplemental" resolver configuration, expand
81 * the match domains and add each to the supplemental list.
83 for (i
= 0; i
< n_domains
; i
++) {
85 CFStringRef match_domain
;
86 CFNumberRef match_order
;
87 uint32_t match_order_val
= 0;
88 CFMutableDictionaryRef match_resolver
;
89 CFIndex n_supplemental
;
91 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
92 if (!isA_CFString(match_domain
)) {
96 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
98 match_resolver
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
);
99 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
);
100 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
);
101 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
);
102 CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
);
103 if (isA_CFNumber(match_order
)) {
104 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
);
105 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) {
108 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
109 CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
);
112 defaultOrder
++; // if multiple domains, maintain ordering
115 match_order
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
);
116 if (!isA_CFNumber(match_order
) ||
117 !CFNumberGetValue(match_order
, kCFNumberIntType
, &match_order_val
)) {
122 n_supplemental
= CFArrayGetCount(supplemental
);
123 for (j
= 0; j
< n_supplemental
; j
++) {
124 CFMutableDictionaryRef compare
;
126 CFDictionaryRef supplemental_resolver
;
128 supplemental_resolver
= CFArrayGetValueAtIndex(supplemental
, j
);
129 if (CFEqual(match_resolver
, supplemental_resolver
)) {
131 CFRelease(match_resolver
);
132 match_resolver
= NULL
;
136 compare
= CFDictionaryCreateMutableCopy(NULL
, 0, supplemental_resolver
);
137 if (match_order
!= NULL
) {
138 CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, match_order
);
140 match
= CFEqual(match_resolver
, compare
);
144 CFNumberRef supplemental_order
;
145 uint32_t supplemental_order_val
= 0;
147 // if only the search order's are different
148 supplemental_order
= CFDictionaryGetValue(supplemental_resolver
, kSCPropNetDNSSearchOrder
);
149 if (!isA_CFNumber(supplemental_order
) ||
150 !CFNumberGetValue(supplemental_order
, kCFNumberIntType
, &supplemental_order_val
)) {
151 supplemental_order_val
= 0;
154 if (match_order_val
< supplemental_order_val
) {
155 // if we should prefer this match resolver, else just skip it
156 CFArraySetValueAtIndex(supplemental
, j
, match_resolver
);
159 CFRelease(match_resolver
);
160 match_resolver
= NULL
;
165 if (match_resolver
!= NULL
) {
166 CFArrayAppendValue(supplemental
, match_resolver
);
167 CFRelease(match_resolver
);
176 add_predefined_resolvers(CFMutableArrayRef supplemental
)
181 if (S_predefined
== NULL
) {
185 n
= CFArrayGetCount(S_predefined
);
186 for (i
= 0; i
< n
; i
++) {
187 uint32_t defaultOrder
;
190 dns
= CFArrayGetValueAtIndex(S_predefined
, i
);
191 if (!isA_CFDictionary(dns
)) {
195 defaultOrder
= DEFAULT_SEARCH_ORDER
+
196 (DEFAULT_SEARCH_ORDER
/ 2) +
197 ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
198 add_supplemental(supplemental
, dns
, defaultOrder
);
209 add_supplemental_resolvers(CFMutableArrayRef supplemental
, CFDictionaryRef services
, CFArrayRef service_order
)
211 const void * keys_q
[N_QUICK
];
212 const void ** keys
= keys_q
;
216 const void * vals_q
[N_QUICK
];
217 const void ** vals
= vals_q
;
219 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
220 if (n_services
== 0) {
221 return; // if no services
224 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
225 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
226 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
229 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
231 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
232 for (i
= 0; i
< n_services
; i
++) {
233 uint32_t defaultOrder
;
235 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
237 if (!isA_CFDictionary(service
)) {
241 dns
= CFDictionaryGetValue(service
, kSCEntNetDNS
);
242 if (!isA_CFDictionary(dns
)) {
246 defaultOrder
= DEFAULT_SEARCH_ORDER
-
247 (DEFAULT_SEARCH_ORDER
/ 2) +
248 ((DEFAULT_SEARCH_ORDER
/ 1000) * i
);
250 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
251 // push out services not specified in service order
252 defaultOrder
+= (DEFAULT_SEARCH_ORDER
/ 1000) * n_services
;
255 add_supplemental(supplemental
, dns
, defaultOrder
);
258 if (keys
!= keys_q
) {
259 CFAllocatorDeallocate(NULL
, keys
);
260 CFAllocatorDeallocate(NULL
, vals
);
267 static CFComparisonResult
268 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
270 CFDictionaryRef dns1
= (CFDictionaryRef
)val1
;
271 CFDictionaryRef dns2
= (CFDictionaryRef
)val2
;
273 uint32_t order1
= DEFAULT_SEARCH_ORDER
;
274 uint32_t order2
= DEFAULT_SEARCH_ORDER
;
276 num
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
);
277 if (!isA_CFNumber(num
) ||
278 !CFNumberGetValue(num
, kCFNumberIntType
, &order1
)) {
279 order1
= DEFAULT_SEARCH_ORDER
;
282 num
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
);
283 if (!isA_CFNumber(num
) ||
284 !CFNumberGetValue(num
, kCFNumberIntType
, &order2
)) {
285 order2
= DEFAULT_SEARCH_ORDER
;
288 if (order1
== order2
) {
289 return kCFCompareEqualTo
;
292 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
297 trimDomain(CFStringRef domain
)
301 Boolean trimmed
= FALSE
;
303 if (!isA_CFString(domain
)) {
307 // remove trailing dots
308 length
= CFStringGetLength(domain
);
309 while (CFStringFindWithOptions(domain
,
311 CFRangeMake(0, length
),
312 kCFCompareAnchored
|kCFCompareBackwards
,
315 length
= range
.location
;
323 domain
= CFStringCreateWithSubstring(NULL
, domain
, CFRangeMake(0, length
));
333 update_search_domains(CFMutableDictionaryRef
*defaultDomain
, CFArrayRef supplemental
)
335 CFStringRef defaultDomainName
= NULL
;
336 uint32_t defaultOrder
= DEFAULT_SEARCH_ORDER
;
337 CFArrayRef defaultSearchDomains
= NULL
;
338 CFIndex defaultSearchIndex
= 0;
340 CFMutableArrayRef mySearchDomains
;
341 CFMutableArrayRef mySupplemental
= (CFMutableArrayRef
)supplemental
;
342 CFIndex n_supplemental
;
343 Boolean searchDomainAdded
= FALSE
;
345 n_supplemental
= CFArrayGetCount(supplemental
);
346 if (n_supplemental
== 0) {
347 // if no supplemental domains
351 if (*defaultDomain
!= NULL
) {
354 num
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSSearchOrder
);
355 if (!isA_CFNumber(num
) ||
356 !CFNumberGetValue(num
, kCFNumberIntType
, &defaultOrder
)) {
357 defaultOrder
= DEFAULT_SEARCH_ORDER
;
360 defaultDomainName
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSDomainName
);
361 defaultSearchDomains
= CFDictionaryGetValue(*defaultDomain
, kSCPropNetDNSSearchDomains
);
364 mySearchDomains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
366 if (isA_CFArray(defaultSearchDomains
)) {
369 n_search
= CFArrayGetCount(defaultSearchDomains
);
370 for (i
= 0; i
< n_search
; i
++) {
373 search
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
);
374 search
= trimDomain(search
);
375 if (search
!= NULL
) {
376 CFArrayAppendValue(mySearchDomains
, search
);
381 defaultDomainName
= trimDomain(defaultDomainName
);
382 if (defaultDomainName
!= NULL
) {
384 int domain_parts
= 1;
387 domain
= _SC_cfstring_to_cstring(defaultDomainName
,
390 kCFStringEncodingUTF8
);
391 CFRelease(defaultDomainName
);
393 // count domain parts
394 for (dp
= domain
; *dp
!= '\0'; dp
++) {
401 for (i
= LOCALDOMAINPARTS
; i
<= domain_parts
; i
++) {
404 search
= CFStringCreateWithCString(NULL
,
406 kCFStringEncodingUTF8
);
407 CFArrayAppendValue(mySearchDomains
, search
);
410 dp
= strchr(dp
, '.') + 1;
413 CFAllocatorDeallocate(NULL
, domain
);
417 if (n_supplemental
> 1) {
418 mySupplemental
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
);
419 CFArraySortValues(mySupplemental
,
420 CFRangeMake(0, n_supplemental
),
421 compareBySearchOrder
,
425 for (i
= 0; i
< n_supplemental
; i
++) {
429 CFStringRef supplementalDomain
;
430 uint32_t supplementalOrder
;
432 dns
= CFArrayGetValueAtIndex(mySupplemental
, i
);
434 supplementalDomain
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
435 supplementalDomain
= trimDomain(supplementalDomain
);
436 if (supplementalDomain
== NULL
) {
440 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) ||
441 CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa" ))) {
442 CFRelease(supplementalDomain
);
446 domainIndex
= CFArrayGetFirstIndexOfValue(mySearchDomains
,
447 CFRangeMake(0, CFArrayGetCount(mySearchDomains
)),
450 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
451 if (!isA_CFNumber(num
) ||
452 !CFNumberGetValue(num
, kCFNumberIntType
, &supplementalOrder
)) {
453 supplementalOrder
= DEFAULT_SEARCH_ORDER
;
456 if (supplementalOrder
< defaultOrder
) {
457 if (domainIndex
!= kCFNotFound
) {
458 // if supplemental domain is already in the search list
459 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
);
460 if (domainIndex
< defaultSearchIndex
) {
461 defaultSearchIndex
--;
464 CFArrayInsertValueAtIndex(mySearchDomains
,
467 defaultSearchIndex
++;
468 searchDomainAdded
= TRUE
;
470 if (domainIndex
== kCFNotFound
) {
471 // add to the (end of the) search list
472 CFArrayAppendValue(mySearchDomains
, supplementalDomain
);
473 searchDomainAdded
= TRUE
;
477 CFRelease(supplementalDomain
);
480 if (searchDomainAdded
) {
481 if (*defaultDomain
== NULL
) {
482 *defaultDomain
= CFDictionaryCreateMutable(NULL
,
484 &kCFTypeDictionaryKeyCallBacks
,
485 &kCFTypeDictionaryValueCallBacks
);
487 CFDictionarySetValue(*defaultDomain
, kSCPropNetDNSSearchDomains
, mySearchDomains
);
490 CFRelease(mySearchDomains
);
491 if (mySupplemental
!= supplemental
) CFRelease(mySupplemental
);
496 static dns_create_resolver_t
497 create_resolver(CFDictionaryRef dns
)
501 dns_create_resolver_t _resolver
;
504 _resolver
= _dns_resolver_create();
507 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
);
508 if (isA_CFString(str
)) {
509 char domain
[NS_MAXDNAME
];
511 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) {
512 _dns_resolver_set_domain(&_resolver
, domain
);
516 // process search domains
517 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
);
518 if (isA_CFArray(list
)) {
520 CFIndex n
= CFArrayGetCount(list
);
522 // add "search" domains
523 for (i
= 0; i
< n
; i
++) {
524 str
= CFArrayGetValueAtIndex(list
, i
);
525 if (isA_CFString(str
)) {
526 char search
[NS_MAXDNAME
];
528 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) {
529 _dns_resolver_add_search(&_resolver
, search
);
535 // process nameserver addresses
536 list
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
);
537 if (isA_CFArray(list
)) {
539 CFIndex n
= CFArrayGetCount(list
);
541 for (i
= 0; i
< n
; i
++) {
544 struct sockaddr_in sin
;
545 struct sockaddr_in6 sin6
;
549 str
= CFArrayGetValueAtIndex(list
, i
);
550 if (!isA_CFString(str
)) {
554 if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) {
558 bzero(&addr
, sizeof(addr
));
559 if (inet_aton(buf
, &addr
.sin
.sin_addr
) == 1) {
560 /* if IPv4 address */
561 addr
.sin
.sin_len
= sizeof(addr
.sin
);
562 addr
.sin
.sin_family
= AF_INET
;
563 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
564 } else if (inet_pton(AF_INET6
, buf
, &addr
.sin6
.sin6_addr
) == 1) {
565 /* if IPv6 address */
568 p
= strchr(buf
, '%');
570 addr
.sin6
.sin6_scope_id
= if_nametoindex(p
+ 1);
573 addr
.sin6
.sin6_len
= sizeof(addr
.sin6
);
574 addr
.sin6
.sin6_family
= AF_INET6
;
575 _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
);
582 // process search order
583 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
);
584 if (isA_CFNumber(num
)) {
587 if (CFNumberGetValue(num
, kCFNumberIntType
, &order
)) {
588 _dns_resolver_set_order(&_resolver
, order
);
593 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
);
594 if (isA_CFNumber(num
)) {
597 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) {
598 _dns_resolver_set_port(&_resolver
, (uint16_t)port
);
603 num
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
);
604 if (isA_CFNumber(num
)) {
607 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) {
608 _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
);
613 str
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
);
614 if (isA_CFString(str
)) {
617 options
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
);
618 if (options
!= NULL
) {
619 _dns_resolver_set_options(&_resolver
, options
);
620 CFAllocatorDeallocate(NULL
, options
);
630 dns_configuration_set(CFDictionaryRef defaultResolver
,
631 CFDictionaryRef services
,
632 CFArrayRef serviceOrder
)
635 CFMutableDictionaryRef myDefault
;
636 CFStringRef myDomain
= NULL
;
637 uint32_t myOrder
= DEFAULT_SEARCH_ORDER
;
638 Boolean myOrderAdded
= FALSE
;
639 CFIndex n_supplemental
;
641 dns_create_resolver_t resolver
;
643 CFMutableArrayRef supplemental
;
645 if (defaultResolver
== NULL
) {
646 myDefault
= CFDictionaryCreateMutable(NULL
,
648 &kCFTypeDictionaryKeyCallBacks
,
649 &kCFTypeDictionaryValueCallBacks
);
651 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
);
653 // ensure that the default resolver has a search order
655 order
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
);
656 if (!isA_CFNumber(order
) ||
657 !CFNumberGetValue(order
, kCFNumberIntType
, &myOrder
)) {
659 myOrder
= DEFAULT_SEARCH_ORDER
;
660 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
661 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
);
666 // establish list of supplemental resolvers
668 supplemental
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
670 // identify search[] list and/or domain name
672 search
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchDomains
);
673 if (isA_CFArray(search
) && (CFArrayGetCount(search
) > 0)) {
674 myDomain
= CFArrayGetValueAtIndex(search
, 0);
675 myDomain
= isA_CFString(myDomain
);
678 if (myDomain
== NULL
) {
679 myDomain
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSDomainName
);
680 myDomain
= isA_CFString(myDomain
);
683 // add match for default domain
685 if (myDomain
!= NULL
) {
686 CFMutableDictionaryRef mySupplemental
;
688 mySupplemental
= CFDictionaryCreateMutableCopy(NULL
, 0, myDefault
);
689 CFDictionarySetValue (mySupplemental
, kSCPropNetDNSDomainName
, myDomain
);
690 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSearchDomains
);
691 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSupplementalMatchDomains
);
692 CFDictionaryRemoveValue(mySupplemental
, kSCPropNetDNSSupplementalMatchOrders
);
693 CFArrayAppendValue(supplemental
, mySupplemental
);
694 CFRelease(mySupplemental
);
697 // collect (and add) any supplemental resolver configurations
699 add_supplemental_resolvers(supplemental
, services
, serviceOrder
);
701 // update the "search" list
703 update_search_domains(&myDefault
, supplemental
);
705 // add any pre-defined resolver configurations
707 add_predefined_resolvers(supplemental
);
709 // check if the "match for default domain" (above) is really needed
711 if (myDomain
!= NULL
) {
712 Boolean sharedDomain
= FALSE
;
714 n_supplemental
= CFArrayGetCount(supplemental
);
715 for (i
= 1; i
< n_supplemental
; i
++) {
717 CFDictionaryRef mySupplemental
;
719 mySupplemental
= CFArrayGetValueAtIndex(supplemental
, i
);
720 domain
= CFDictionaryGetValue(mySupplemental
, kSCPropNetDNSDomainName
);
721 if (isA_CFString(domain
)) {
722 if (CFEqual(myDomain
, domain
)) {
727 if (CFStringHasSuffix(myDomain
, domain
)) {
730 dotIndex
= CFStringGetLength(myDomain
) - CFStringGetLength(domain
) - 1;
734 dot
= CFStringGetCharacterAtIndex(myDomain
, dotIndex
);
735 if (dot
== (UniChar
)'.') {
745 // if the default resolver domain name is not shared
746 CFArrayRemoveValueAtIndex(supplemental
, 0);
750 // establish resolver configuration
752 n_supplemental
= CFArrayGetCount(supplemental
);
753 if ((defaultResolver
== NULL
) && (n_supplemental
== 0)) {
755 * if no default or supplemental resolvers
757 if (!_dns_configuration_store(NULL
)) {
758 SCLog(TRUE
, LOG_ERR
, CFSTR("set_dns_configuration: could not store configuration"));
761 dns_create_config_t _config
;
764 * if default and/or supplemental resolvers are defined
766 _config
= _dns_configuration_create();
768 // add [default] resolver
770 if ((n_supplemental
== 0) && myOrderAdded
) {
771 CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
);
773 resolver
= create_resolver(myDefault
);
774 _dns_configuration_add_resolver(&_config
, resolver
);
775 _dns_resolver_free(&resolver
);
777 // add [supplemental] resolvers
779 for (i
= 0; i
< n_supplemental
; i
++) {
780 CFDictionaryRef supplementalResolver
;
782 supplementalResolver
= CFArrayGetValueAtIndex(supplemental
, i
);
783 resolver
= create_resolver(supplementalResolver
);
784 _dns_configuration_add_resolver(&_config
, resolver
);
785 _dns_resolver_free(&resolver
);
788 // save configuration
790 if (!_dns_configuration_store(&_config
)) {
791 SCLog(TRUE
, LOG_ERR
, CFSTR("set_dns_configuration() failed: could not store configuration"));
794 _dns_configuration_free(&_config
);
797 CFRelease(myDefault
);
798 CFRelease(supplemental
);
805 load_predefined_resolvers(CFBundleRef bundle
)
809 CFStringRef xmlError
= NULL
;
810 CFDataRef xmlResolvers
= NULL
;
812 url
= CFBundleCopyResourceURL(bundle
, CFSTR("Resolvers"), CFSTR("plist"), NULL
);
817 ok
= CFURLCreateDataAndPropertiesFromResource(NULL
, url
, &xmlResolvers
, NULL
, NULL
, NULL
);
819 if (!ok
|| (xmlResolvers
== NULL
)) {
823 /* convert the XML data into a property list */
824 S_predefined
= CFPropertyListCreateFromXMLData(NULL
, xmlResolvers
, kCFPropertyListImmutable
, &xmlError
);
825 CFRelease(xmlResolvers
);
826 if (S_predefined
== NULL
) {
827 if (xmlError
!= NULL
) {
828 SCLog(TRUE
, LOG_DEBUG
, CFSTR("add_predefined_resolvers: %@"), xmlError
);
834 if (!isA_CFArray(S_predefined
)) {
835 CFRelease(S_predefined
);
846 dns_configuration_init(CFBundleRef bundle
)
848 load_predefined_resolvers(bundle
);