2  * Copyright (c) 2004-2020 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> 
  44 #include <CommonCrypto/CommonDigest.h> 
  46 #include <CoreFoundation/CoreFoundation.h> 
  47 #include <SystemConfiguration/SystemConfiguration.h> 
  48 #include <SystemConfiguration/SCPrivate.h> 
  49 #include <SystemConfiguration/SCValidation.h> 
  50 #include "ip_plugin.h" 
  52 #include "dns-configuration.h" 
  55 #include "dnsinfo_create.h" 
  56 #include "dnsinfo_internal.h" 
  57 #include "dnsinfo_logging.h" 
  58 #include "dnsinfo_private.h" 
  59 #include "dnsinfo_server.h" 
  61 #include <network_information.h> 
  64 #include <dns_sd_private.h> 
  67 #include <CoreServices/CoreServices.h> 
  68 #else   // TARGET_OS_IPHONE 
  69 #include <FSEvents/FSEvents.h> 
  70 #endif  // TARGET_OS_IPHONE 
  72 #define DNS_CONFIGURATION_FLAGS_KEY     CFSTR("__FLAGS__") 
  73 #define DNS_CONFIGURATION_IF_INDEX_KEY  CFSTR("__IF_INDEX__") 
  74 #define DNS_CONFIGURATION_ORDER_KEY     CFSTR("__ORDER__") 
  76 /* multicast DNS resolver configurations */ 
  77 static  CFNumberRef     S_mdns_timeout  
= NULL
; 
  79 /* private DNS resolver configurations */ 
  80 static  CFNumberRef     S_pdns_timeout  
= NULL
; 
  84 #pragma mark DNS resolver flags 
  87 static __inline__ boolean_t
 
  88 dns_resolver_flags_all_queries(uint32_t query_flags
) 
  90         return ((query_flags 
& DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
) == DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
); 
  97 dns_resolver_flags_service(CFDictionaryRef service
, uint32_t resolver_flags
) 
 100         // check if the service has v4 configured 
 101         if (((resolver_flags 
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
) == 0) && 
 102             service_is_routable(service
, AF_INET
)) { 
 103                 resolver_flags 
|= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
; 
 106         // check if the service has v6 configured 
 107         if (((resolver_flags 
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
) == 0) && 
 108             service_is_routable(service
, AF_INET6
)) { 
 109                 resolver_flags 
|= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
; 
 112         return resolver_flags
; 
 117 add_dns_resolver_flags(const void *key
, const void *value
, void *context
) 
 120         CFDictionaryRef service         
= (CFDictionaryRef
)value
; 
 121 //      CFStringRef     serviceID       = (CFStringRef)key; 
 122         uint32_t        *resolver_flags 
= (uint32_t *)context
; 
 124         if (service_is_scoped_only(service
)) { 
 128         // update resovler flags based on configured (and available) protocols 
 129         *resolver_flags 
= dns_resolver_flags_service(service
, *resolver_flags
); 
 135 #pragma mark DNS resolver configuration 
 139 add_resolver(CFMutableArrayRef resolvers
, CFMutableDictionaryRef resolver
) 
 142         CFStringRef     interface
; 
 145         uint32_t        order_val       
= 0; 
 147         order 
= CFDictionaryGetValue(resolver
, kSCPropNetDNSSearchOrder
); 
 148         if (!isA_CFNumber(order
) || 
 149             !CFNumberGetValue(order
, kCFNumberSInt32Type
, &order_val
)) { 
 154         n_resolvers 
= CFArrayGetCount(resolvers
); 
 155         for (i 
= 0; i 
< n_resolvers
; i
++) { 
 156                 CFDictionaryRef         match_resolver
; 
 158                 match_resolver 
= CFArrayGetValueAtIndex(resolvers
, i
); 
 159                 if (CFEqual(resolver
, match_resolver
)) { 
 165                         CFMutableDictionaryRef  compare
; 
 168                         compare 
= CFDictionaryCreateMutableCopy(NULL
, 0, match_resolver
); 
 169                         CFDictionarySetValue(compare
, kSCPropNetDNSSearchOrder
, order
); 
 170                         match 
= CFEqual(resolver
, compare
); 
 173                                 CFNumberRef     match_order
; 
 174                                 uint32_t        match_order_val 
= 0; 
 176                                 // if only the search order's are different 
 177                                 match_order 
= CFDictionaryGetValue(match_resolver
, kSCPropNetDNSSearchOrder
); 
 178                                 if (!isA_CFNumber(match_order
) || 
 179                                     !CFNumberGetValue(match_order
, kCFNumberSInt32Type
, &match_order_val
)) { 
 183                                 if (order_val 
< match_order_val 
) { 
 184                                         // if we should prefer this match resolver, else just skip it 
 185                                         CFArraySetValueAtIndex(resolvers
, i
, resolver
); 
 193         order 
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_resolvers
); 
 194         CFDictionarySetValue(resolver
, DNS_CONFIGURATION_ORDER_KEY
, order
); 
 197         interface 
= CFDictionaryGetValue(resolver
, kSCPropInterfaceName
); 
 198         if ((interface 
!= NULL
) && !CFEqual(interface
, CFSTR("*"))) { 
 200                 unsigned int    if_index                
= 0; 
 201                 char            if_name
[IF_NAMESIZE
]; 
 205                 if (_SC_cfstring_to_cstring(interface
, 
 208                                             kCFStringEncodingASCII
) != NULL
) { 
 209                         if_index 
= my_if_nametoindex(if_name
); 
 212                 if ((if_index 
!= 0) && 
 214                      // check if this is a "scoped" configuration 
 215                      (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) && 
 217                       CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) && 
 218                       (flags 
& DNS_RESOLVER_FLAGS_SCOPED
) != 0) 
 220                      // check if we should scope all queries with this configuration 
 221                      (CFDictionaryGetValueIfPresent(resolver
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) && 
 222                       isA_CFBoolean(val
) && 
 223                       CFBooleanGetValue(val
)) 
 226                         // if interface index available and it should be used 
 227                         num 
= CFNumberCreate(NULL
, kCFNumberIntType
, &if_index
); 
 228                         CFDictionarySetValue(resolver
, DNS_CONFIGURATION_IF_INDEX_KEY
, num
); 
 233         CFArrayAppendValue(resolvers
, resolver
); 
 238 #define DNS_CONFIGURATION_CONFIGURATION_ID      CFSTR("__CONFIGURATION_ID__") 
 242 add_resolver_signature(CFMutableDictionaryRef resolver
, const char *rType
, CFStringRef cID
, CFIndex rIndex
) 
 246         str 
= CFStringCreateWithFormat(NULL
, NULL
, 
 247                                        CFSTR("%s:%s%@ %ld"), 
 249                                        (cID 
!= NULL
) ? " " : "", 
 250                                        (cID 
!= NULL
) ? cID 
: CFSTR(""), 
 252         CFDictionarySetValue(resolver
, DNS_CONFIGURATION_CONFIGURATION_ID
, str
); 
 260 add_supplemental(CFMutableArrayRef      resolvers
, 
 261                  CFStringRef            serviceID
, 
 263                  uint32_t               defaultOrder
, 
 272         domains 
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomains
); 
 273         n_domains 
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0; 
 274         if (n_domains 
== 0) { 
 275                 // if no supplemental match domains 
 279         orders 
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchOrders
); 
 280         if (orders 
!= NULL
) { 
 281                 if (!isA_CFArray(orders
) || (n_domains 
!= CFArrayGetCount(orders
))) { 
 282                         // if supplemental match orders... but too many/not enough 
 287         servers 
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
); 
 288         if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) { 
 289                 // if no DNS server addresses 
 294          * yes, this is a "supplemental" resolver configuration, expand 
 295          * the match domains and add each to the resolvers list. 
 297         for (i 
= 0; i 
< n_domains
; i
++) { 
 298                 CFStringRef             match_domain
; 
 299                 CFNumberRef             match_order
; 
 300                 CFMutableDictionaryRef  match_resolver
; 
 302                 match_domain 
= CFArrayGetValueAtIndex(domains
, i
); 
 303                 if (!isA_CFString(match_domain
)) { 
 307                 match_resolver 
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
); 
 309                 // set supplemental resolver "domain" 
 310                 if (CFStringGetLength(match_domain
) > 0) { 
 311                         CFDictionarySetValue(match_resolver
, kSCPropNetDNSDomainName
, match_domain
); 
 313                         CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSDomainName
); 
 316                 // set supplemental resolver "search_order" 
 317                 match_order 
= (orders 
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
; 
 318                 if (isA_CFNumber(match_order
)) { 
 319                         CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, match_order
); 
 320                 } else if (!CFDictionaryContainsKey(match_resolver
, kSCPropNetDNSSearchOrder
)) { 
 323                         num 
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
); 
 324                         CFDictionarySetValue(match_resolver
, kSCPropNetDNSSearchOrder
, num
); 
 327                         defaultOrder
++;         // if multiple domains, maintain ordering 
 330                 // remove keys we don't want in a supplemental resolver 
 331                 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchDomains
); 
 332                 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSupplementalMatchOrders
); 
 333                 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSearchDomains
); 
 334                 CFDictionaryRemoveValue(match_resolver
, kSCPropNetDNSSortList
); 
 336                 add_resolver_signature(match_resolver
, 
 337                                        scoped 
? "Supplemental/Scoped" : "Supplemental", 
 340                 add_resolver(resolvers
, match_resolver
); 
 341                 CFRelease(match_resolver
); 
 352 merge_configuration_flags(CFMutableDictionaryRef newDNS
, uint32_t mergeFlags
) 
 357         if (!CFDictionaryGetValueIfPresent(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) || 
 358             !isA_CFNumber(num
) || 
 359             !CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) { 
 365         num 
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &flags
); 
 366         CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_FLAGS_KEY
, num
); 
 374 add_supplemental_resolvers(CFMutableArrayRef    resolvers
, 
 375                            CFDictionaryRef      services
, 
 376                            CFArrayRef           service_order
, 
 377                            CFStringRef          scoped_interface
, 
 378                            CFDictionaryRef      scoped_service
) 
 380         const void *            keys_q
[N_QUICK
]; 
 381         const void **           keys    
= keys_q
; 
 385         const void *            vals_q
[N_QUICK
]; 
 386         const void **           vals    
= vals_q
; 
 388         n_services 
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0; 
 389         if (n_services 
== 0) { 
 390                 return;         // if no services 
 393         if (n_services 
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) { 
 394                 keys 
= CFAllocatorAllocate(NULL
, n_services 
* sizeof(CFTypeRef
), 0); 
 395                 vals 
= CFAllocatorAllocate(NULL
, n_services 
* sizeof(CFTypeRef
), 0); 
 398         n_order 
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0; 
 400         CFDictionaryGetKeysAndValues(services
, keys
, vals
); 
 401         for (i 
= 0; i 
< n_services
; i
++) { 
 402                 uint32_t                defaultOrder
; 
 404                 uint32_t                dns_resolver_flags
; 
 405                 CFStringRef             interface
; 
 406                 CFMutableDictionaryRef  newDNS          
= NULL
; 
 408                 CFDictionaryRef         service         
= (CFDictionaryRef
)vals
[i
]; 
 409                 CFStringRef             serviceID       
= (CFStringRef
)keys
[i
]; 
 410                 Boolean                 trusted         
= FALSE
;        // trusted config w/interface 
 412                 if (!isA_CFDictionary(service
)) { 
 416                 dns 
= CFDictionaryGetValue(service
, kSCEntNetDNS
); 
 417                 dns 
= isA_CFDictionary(dns
); 
 422                 interface 
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
); 
 424                 if (scoped_interface 
!= NULL
) { 
 426                         // we only want to add split/supplemental configurations 
 427                         // for queries scoped to an interface if they are NOT 
 428                         // associated with a "real" service 
 430                         if (CFDictionaryContainsKey(service
, kSCEntNetIPv4
) || 
 431                             CFDictionaryContainsKey(service
, kSCEntNetIPv6
)) { 
 436                         // in addition, we don't want to add split/supplemental 
 437                         // configurations for queries scoped to an interface if 
 438                         // the configuration does not apply to all interfaces and 
 439                         // the configuration is explicitly NOT for this interface 
 441                         if (!_SC_CFEqual(interface
, CFSTR("*")) && 
 442                             !_SC_CFEqual(interface
, scoped_interface
)) { 
 447                         // lastly, check if A/AAAA queries should be issued (based 
 448                         // on the IP[v6] addresses).  If we would not be issuing a 
 449                         // query then don't bother adding the configuration. 
 451                         dns_resolver_flags 
= dns_resolver_flags_service(scoped_service
, 0); 
 452                         if (dns_resolver_flags 
== 0) { 
 457                 defaultOrder 
= DEFAULT_SEARCH_ORDER
 
 458                                - (DEFAULT_SEARCH_ORDER 
/ 2) 
 459                                + ((DEFAULT_SEARCH_ORDER 
/ 1000) * (uint32_t)i
); 
 461                     !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) { 
 462                         // push out services not specified in service order 
 463                         defaultOrder 
+= (DEFAULT_SEARCH_ORDER 
/ 1000) * n_services
; 
 467                  * Ensure that we have the correct InterfaceName in the DNS configuration 
 469                  * scoped_interface  [supplemental] interface  Trusted config  DNS interface 
 470                  * ================  ========================  ==============  ================= 
 471                  * NULL              NULL                      No              NULL (No change) 
 474                  * NULL              NULL                      Yes             NULL (No change) 
 475                  * NULL              en0                       Yes             en0  (trusted config w/interface) 
 477                  * en0               NULL                      N/A             en0  (scoped interface) 
 478                  * en0               en0                       N/A             en0  (scoped interface) 
 479                  * en0               *                         N/A             en0  (scoped interface) 
 481                 if ((scoped_interface 
== NULL
) && (interface 
== NULL
)) { 
 482                         newDNS 
= (CFMutableDictionaryRef
)CFRetain(dns
); 
 486                         newDNS 
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
); 
 487                         if (scoped_interface 
!= NULL
) { 
 488                                 CFDictionarySetValue(newDNS
, kSCPropInterfaceName
, scoped_interface
); 
 489                         } else if ((interface 
!= NULL
) && 
 490                                    CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, (const void **)&val
) && 
 491                                    isA_CFBoolean(val
) && 
 492                                    CFBooleanGetValue(val
)) { 
 493                                 // leave the [trusted configuration] InterfaceName in place 
 496                                 CFDictionaryRemoveValue(newDNS
, kSCPropInterfaceName
); 
 500                 // set "supplemental" flag 
 501                 newFlags 
= DNS_RESOLVER_FLAGS_SUPPLEMENTAL
; 
 503                 if (scoped_interface 
!= NULL
) { 
 504                         // set "scoped" configuration flag 
 505                         newFlags 
|= DNS_RESOLVER_FLAGS_SCOPED
; 
 507                         // add "Request A/AAAA query" flag(s) 
 508                         newFlags 
|= dns_resolver_flags
; 
 509                 } else if (trusted
) { 
 510                         // use the DNS query flags from the supplemental match service 
 511                         newFlags 
|= dns_resolver_flags_service(service
, 0); 
 514                 merge_configuration_flags(newDNS
, newFlags
); 
 516                 // add [scoped] resolver entry 
 517                 add_supplemental(resolvers
, serviceID
, newDNS
, defaultOrder
, (scoped_interface 
!= NULL
)); 
 521         if (keys 
!= keys_q
) { 
 522                 CFAllocatorDeallocate(NULL
, keys
); 
 523                 CFAllocatorDeallocate(NULL
, vals
); 
 531 add_multicast_resolvers(CFMutableArrayRef resolvers
, CFArrayRef multicastResolvers
) 
 536         n 
= isA_CFArray(multicastResolvers
) ? CFArrayGetCount(multicastResolvers
) : 0; 
 537         for (i 
= 0; i 
< n
; i
++) { 
 538                 uint32_t                defaultOrder
; 
 541                 CFMutableDictionaryRef  resolver
; 
 543                 domain 
= CFArrayGetValueAtIndex(multicastResolvers
, i
); 
 544                 domain 
= _SC_trimDomain(domain
); 
 545                 if (domain 
== NULL
) { 
 549                 defaultOrder 
= DEFAULT_SEARCH_ORDER
 
 550                 + (DEFAULT_SEARCH_ORDER 
/ 2) 
 551                 + ((DEFAULT_SEARCH_ORDER 
/ 1000) * (uint32_t)i
); 
 553                 resolver 
= CFDictionaryCreateMutable(NULL
, 
 555                                                      &kCFTypeDictionaryKeyCallBacks
, 
 556                                                      &kCFTypeDictionaryValueCallBacks
); 
 557                 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
); 
 558                 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("mdns")); 
 559                 num 
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
); 
 560                 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
); 
 562                 if (S_mdns_timeout 
!= NULL
) { 
 563                         CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_mdns_timeout
); 
 565                 add_resolver_signature(resolver
, "Multicast DNS", NULL
, i
); 
 566                 add_resolver(resolvers
, resolver
); 
 576 add_private_resolvers(CFMutableArrayRef resolvers
, CFArrayRef privateResolvers
) 
 581         n 
= isA_CFArray(privateResolvers
) ? CFArrayGetCount(privateResolvers
) : 0; 
 582         for (i 
= 0; i 
< n
; i
++) { 
 583                 uint32_t                defaultOrder
; 
 586                 CFMutableDictionaryRef  resolver
; 
 588                 domain 
= CFArrayGetValueAtIndex(privateResolvers
, i
); 
 589                 domain 
= _SC_trimDomain(domain
); 
 590                 if (domain 
== NULL
) { 
 594                 defaultOrder 
= DEFAULT_SEARCH_ORDER
 
 595                                - (DEFAULT_SEARCH_ORDER 
/ 4) 
 596                                + ((DEFAULT_SEARCH_ORDER 
/ 1000) * (uint32_t)i
); 
 598                 resolver 
= CFDictionaryCreateMutable(NULL
, 
 600                                                      &kCFTypeDictionaryKeyCallBacks
, 
 601                                                      &kCFTypeDictionaryValueCallBacks
); 
 602                 CFDictionarySetValue(resolver
, kSCPropNetDNSDomainName
, domain
); 
 603                 CFDictionarySetValue(resolver
, kSCPropNetDNSOptions
, CFSTR("pdns")); 
 604                 num 
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
); 
 605                 CFDictionarySetValue(resolver
, kSCPropNetDNSSearchOrder
, num
); 
 607                 if (S_pdns_timeout 
!= NULL
) { 
 608                         CFDictionarySetValue(resolver
, kSCPropNetDNSServerTimeout
, S_pdns_timeout
); 
 610                 add_resolver_signature(resolver
, "Private DNS", NULL
, i
); 
 611                 add_resolver(resolvers
, resolver
); 
 620 static CFComparisonResult
 
 621 compareBySearchOrder(const void *val1
, const void *val2
, void *context
) 
 623 #pragma unused(context) 
 624         CFDictionaryRef dns1    
= (CFDictionaryRef
)val1
; 
 625         CFDictionaryRef dns2    
= (CFDictionaryRef
)val2
; 
 628         uint32_t        order1  
= DEFAULT_SEARCH_ORDER
; 
 629         uint32_t        order2  
= DEFAULT_SEARCH_ORDER
; 
 631         num1 
= CFDictionaryGetValue(dns1
, kSCPropNetDNSSearchOrder
); 
 632         if (!isA_CFNumber(num1
) || 
 633             !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) { 
 634                 order1 
= DEFAULT_SEARCH_ORDER
; 
 637         num2 
= CFDictionaryGetValue(dns2
, kSCPropNetDNSSearchOrder
); 
 638         if (!isA_CFNumber(num2
) || 
 639             !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) { 
 640                 order2 
= DEFAULT_SEARCH_ORDER
; 
 643         if (order1 
== order2
) { 
 644                 // if same "SearchOrder", retain original orderring for configurations 
 645                 if (CFDictionaryGetValueIfPresent(dns1
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num1
) && 
 646                     CFDictionaryGetValueIfPresent(dns2
, DNS_CONFIGURATION_ORDER_KEY
, (const void **)&num2
) && 
 647                     isA_CFNumber(num1
) && 
 648                     isA_CFNumber(num2
) && 
 649                     CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
) && 
 650                     CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) { 
 651                         if (order1 
== order2
) { 
 652                                 return kCFCompareEqualTo
; 
 654                                 return (order1 
< order2
) ? kCFCompareLessThan 
: kCFCompareGreaterThan
; 
 658                 return kCFCompareEqualTo
; 
 661         return (order1 
< order2
) ? kCFCompareLessThan 
: kCFCompareGreaterThan
; 
 665 static CF_RETURNS_RETAINED CFArrayRef
 
 666 extract_search_domains(CFMutableDictionaryRef defaultDomain
, CFArrayRef supplemental
) 
 668         CFStringRef             defaultDomainName       
= NULL
; 
 669         uint32_t                defaultOrder            
= DEFAULT_SEARCH_ORDER
; 
 670         CFArrayRef              defaultSearchDomains    
= NULL
; 
 671         CFIndex                 defaultSearchIndex      
= 0; 
 672         CFMutableArrayRef       mySearchDomains
; 
 673         CFMutableArrayRef       mySupplemental          
= NULL
; 
 674         CFIndex                 n_supplemental
; 
 675         CFStringRef             trimmedDomainName
; 
 677         mySearchDomains 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 679         if (defaultDomain 
!= NULL
) { 
 682                 num 
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchOrder
); 
 683                 if (!isA_CFNumber(num
) || 
 684                     !CFNumberGetValue(num
, kCFNumberSInt32Type
, &defaultOrder
)) { 
 685                         defaultOrder 
= DEFAULT_SEARCH_ORDER
; 
 688                 defaultDomainName    
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSDomainName
); 
 689                 defaultSearchDomains 
= CFDictionaryGetValue(defaultDomain
, kSCPropNetDNSSearchDomains
); 
 692         // validate the provided "search" domains or move/expand/promote the "domain" name 
 693         if (isA_CFArray(defaultSearchDomains
)) { 
 696                 n_search 
= CFArrayGetCount(defaultSearchDomains
); 
 697                 for (int i 
= 0; i 
< n_search
; i
++) { 
 700                         search 
= CFArrayGetValueAtIndex(defaultSearchDomains
, i
); 
 701                         search 
= _SC_trimDomain(search
); 
 702                         if (search 
!= NULL
) { 
 703                                 CFArrayAppendValue(mySearchDomains
, search
); 
 708                 trimmedDomainName 
= _SC_trimDomain(defaultDomainName
); 
 709 #ifdef  PERFORM_DOMAIN_EXPANSION 
 711                  * With BIND 4.8.3 (and earlier) resolvers, the default search list included 
 712                  * the default domain and each of its parent domains with two or more labels. 
 714                 if ((trimmedDomainName 
!= NULL
) && 
 715                     CFStringHasSuffix(defaultDomainName
, CFSTR("."))) { 
 716                         // if "domain" name is fully qualified 
 717                         CFArrayAppendValue(mySearchDomains
, trimmedDomainName
); 
 718                         CFRelease(trimmedDomainName
); 
 719                 } else if (trimmedDomainName 
!= NULL
) { 
 721                         int             domain_parts    
= 1; 
 725                         domain 
= _SC_cfstring_to_cstring(trimmedDomainName
, 
 728                                                          kCFStringEncodingUTF8
); 
 729                         CFRelease(trimmedDomainName
); 
 731                         // count domain parts 
 732                         for (dp 
= domain
; *dp 
!= '\0'; dp
++) { 
 738                         // move "domain" to "search" list (and expand as needed) 
 744                                 str 
= CFStringCreateWithCString(NULL
, 
 746                                                                 kCFStringEncodingUTF8
); 
 747                                 search 
= _SC_trimDomain(str
); 
 749                                 if (search 
!= NULL
) { 
 750                                         CFArrayAppendValue(mySearchDomains
, search
); 
 754                                 dp 
= strchr(dp
, '.') + 1; 
 755                         } while (domain_parts
-- > 2); 
 756                         CFAllocatorDeallocate(NULL
, domain
); 
 758 #else   // PERFORM_DOMAIN_EXPANSION 
 760                  * With BIND 4.9.3 (and later) resolvers, the default search list included 
 761                  * just the default domain. 
 763                 if (trimmedDomainName 
!= NULL
) { 
 764                         CFArrayAppendValue(mySearchDomains
, trimmedDomainName
); 
 765                         CFRelease(trimmedDomainName
); 
 767 #endif  // PERFORM_DOMAIN_EXPANSION 
 770         // add any supplemental "domain" names to the search list 
 771         n_supplemental 
= (supplemental 
!= NULL
) ? CFArrayGetCount(supplemental
) : 0; 
 772         if (n_supplemental 
> 1) { 
 773                 mySupplemental 
= CFArrayCreateMutableCopy(NULL
, 0, supplemental
); 
 774                 CFArraySortValues(mySupplemental
, 
 775                                   CFRangeMake(0, n_supplemental
), 
 776                                   compareBySearchOrder
, 
 778                 supplemental 
= mySupplemental
; 
 780         for (int i 
= 0; i 
< n_supplemental
; i
++) { 
 786                 CFStringRef     supplementalDomain
; 
 787                 uint32_t        supplementalOrder
; 
 789                 dns 
= CFArrayGetValueAtIndex(supplemental
, i
); 
 791                 options 
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
); 
 792                 if (isA_CFString(options
)) { 
 795                         if (CFEqual(options
, CFSTR("pdns"))) { 
 796                                 // don't add private resolver domains to the search list 
 800                         range 
= CFStringFind(options
, CFSTR("interface="), 0); 
 801                         if (range
.location 
!= kCFNotFound
) { 
 802                                 // don't add scoped resolver domains to the search list 
 807                 supplementalDomain 
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
); 
 808                 supplementalDomain 
= _SC_trimDomain(supplementalDomain
); 
 809                 if (supplementalDomain 
== NULL
) { 
 813                 num 
= CFDictionaryGetValue(dns
, kSCPropNetDNSSupplementalMatchDomainsNoSearch
); 
 814                 if (isA_CFNumber(num
) && 
 815                     CFNumberGetValue(num
, kCFNumberIntType
, &noSearch
) && 
 817                         CFRelease(supplementalDomain
); 
 821                 if (CFStringHasSuffix(supplementalDomain
, CFSTR(".in-addr.arpa")) || 
 822                     CFStringHasSuffix(supplementalDomain
, CFSTR(".ip6.arpa"    ))) { 
 823                         CFRelease(supplementalDomain
); 
 827                 domainIndex 
= CFArrayGetFirstIndexOfValue(mySearchDomains
, 
 828                                                           CFRangeMake(0, CFArrayGetCount(mySearchDomains
)), 
 831                 num 
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
); 
 832                 if (!isA_CFNumber(num
) || 
 833                     !CFNumberGetValue(num
, kCFNumberSInt32Type
, &supplementalOrder
)) { 
 834                         supplementalOrder 
= DEFAULT_SEARCH_ORDER
; 
 837                 if (supplementalOrder 
< defaultOrder
) { 
 838                         if (domainIndex 
!= kCFNotFound
) { 
 839                                 // if supplemental domain is already in the search list 
 840                                 CFArrayRemoveValueAtIndex(mySearchDomains
, domainIndex
); 
 841                                 if (domainIndex 
< defaultSearchIndex
) { 
 842                                         defaultSearchIndex
--; 
 845                         CFArrayInsertValueAtIndex(mySearchDomains
, 
 848                         defaultSearchIndex
++; 
 850                         if (domainIndex 
== kCFNotFound
) { 
 851                                 // add to the (end of the) search list 
 852                                 CFArrayAppendValue(mySearchDomains
, supplementalDomain
); 
 856                 CFRelease(supplementalDomain
); 
 858         if (mySupplemental 
!= NULL
) CFRelease(mySupplemental
); 
 860         // update the "search" domains 
 861         if (CFArrayGetCount(mySearchDomains
) == 0) { 
 862                 CFRelease(mySearchDomains
); 
 863                 mySearchDomains 
= NULL
; 
 866         // remove the "domain" name and "search" list 
 867         CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSDomainName
); 
 868         CFDictionaryRemoveValue(defaultDomain
, kSCPropNetDNSSearchDomains
); 
 870         return mySearchDomains
; 
 875 add_scoped_resolvers(CFMutableArrayRef  scoped
, 
 876                      CFDictionaryRef    services
, 
 877                      CFArrayRef         service_order
) 
 879         const void *            keys_q
[N_QUICK
]; 
 880         const void **           keys    
= keys_q
; 
 884         CFMutableArrayRef       order
; 
 885         CFMutableSetRef         seen
; 
 887         n_services 
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0; 
 888         if (n_services 
== 0) { 
 889                 return;         // if no services 
 892         // ensure that we process all services in order 
 894         n_order 
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0; 
 896                 order 
= CFArrayCreateMutableCopy(NULL
, 0, service_order
); 
 898                 order 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 901         if (n_services 
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) { 
 902                 keys 
= CFAllocatorAllocate(NULL
, n_services 
* sizeof(CFTypeRef
), 0); 
 904         CFDictionaryGetKeysAndValues(services
, keys
, NULL
); 
 905         for (i 
= 0; i 
< n_services
; i
++) { 
 906                 CFStringRef     serviceID 
= (CFStringRef
)keys
[i
]; 
 908                 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) { 
 909                         CFArrayAppendValue(order
, serviceID
); 
 913         if (keys 
!= keys_q
) { 
 914                 CFAllocatorDeallocate(NULL
, keys
); 
 917         // iterate over services 
 919         seen 
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
); 
 920         for (i 
= 0; i 
< n_order
; i
++) { 
 922                 uint32_t                dns_resolver_flags
; 
 923                 char                    if_name
[IF_NAMESIZE
]; 
 924                 CFStringRef             interface
; 
 925                 CFMutableDictionaryRef  newDNS
; 
 927                 CFArrayRef              searchDomains
; 
 928                 CFDictionaryRef         service
; 
 929                 CFStringRef             serviceID
; 
 932                 serviceID 
= CFArrayGetValueAtIndex(order
, i
); 
 933                 service 
= CFDictionaryGetValue(services
, serviceID
); 
 934                 if (!isA_CFDictionary(service
)) { 
 939                 dns 
= CFDictionaryGetValue(service
, kSCEntNetDNS
); 
 940                 if (!isA_CFDictionary(dns
)) { 
 945                 servers 
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
); 
 946                 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) { 
 947                         // if no DNS server addresses 
 951                 interface 
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
); 
 952                 if ((interface 
== NULL
) || CFEqual(interface
, CFSTR("*"))) { 
 953                         // if no [scoped] interface or supplemental configuration w/match-all 
 957                 if (CFDictionaryContainsKey(dns
, kSCPropNetDNSServiceIdentifier
)) { 
 958                         // if this is a service-specific resolver 
 962                 if (CFSetContainsValue(seen
, interface
)) { 
 963                         // if we've already processed this [scoped] interface 
 966                 CFSetSetValue(seen
, interface
); 
 968                 if ((_SC_cfstring_to_cstring(interface
, 
 971                                              kCFStringEncodingASCII
) == NULL
) || 
 972                     (my_if_nametoindex(if_name
) == 0)) { 
 973                         // if interface index not available 
 977                 // add [scoped] resolver entry 
 978                 newDNS 
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
); 
 981                 searchDomains 
= extract_search_domains(newDNS
, NULL
); 
 982                 if (searchDomains 
!= NULL
) { 
 983                         CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
); 
 984                         CFRelease(searchDomains
); 
 987                 // get "Request A/AAAA query" flag(s) 
 988                 dns_resolver_flags 
= dns_resolver_flags_service(service
, 0); 
 989                 if (dns_resolver_flags 
== 0) { 
 993                 // set "scoped" configuration flag 
 994                 newFlags 
= DNS_RESOLVER_FLAGS_SCOPED
; 
 996                 // add "Request A/AAAA query" flag(s) 
 997                 newFlags 
|= dns_resolver_flags
; 
 999                 merge_configuration_flags(newDNS
, newFlags
); 
1001                 // remove keys we don't want in a [scoped] resolver 
1002                 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
); 
1003                 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
); 
1005                 // add the [scoped] resolver 
1006                 add_resolver_signature(newDNS
, "Scoped", serviceID
, 0); 
1007                 add_resolver(scoped
, newDNS
); 
1009                 // add any supplemental resolver configurations for this interface 
1010                 add_supplemental_resolvers(scoped
, services
, service_order
, interface
, service
); 
1023 add_service_specific_resolvers(CFMutableArrayRef resolvers
, CFDictionaryRef services
) 
1026         CFStringRef             keys_q
[N_QUICK
]; 
1027         CFStringRef             
*keys   
= keys_q
; 
1029         CFMutableSetRef         seen
; 
1030         CFDictionaryRef         vals_q
[N_QUICK
]; 
1031         CFDictionaryRef         
*vals   
= vals_q
; 
1033         n_services 
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0; 
1034         if (n_services 
== 0) { 
1035                 return;         // if no services 
1038         if (n_services 
> (CFIndex
)(sizeof(keys_q
) / sizeof(keys_q
[0]))) { 
1039                 keys 
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services 
* sizeof(keys
[0]), 0); 
1040                 vals 
= CFAllocatorAllocate(kCFAllocatorDefault
, n_services 
* sizeof(vals
[0]), 0); 
1042         CFDictionaryGetKeysAndValues(services
, (const void **)keys
, (const void **)vals
); 
1044         seen 
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
); 
1045         for (i 
= 0; i 
< n_services
; i
++) { 
1046                 CFDictionaryRef         dns
; 
1047                 CFNumberRef             dns_service_identifier
; 
1048                 CFMutableDictionaryRef  newDNS
; 
1049                 uint32_t                newFlags                
= 0; 
1050                 CFDictionaryRef         service                 
= vals
[i
]; 
1051                 CFStringRef             serviceID               
= keys
[i
]; 
1052                 CFArrayRef              searchDomains
; 
1054                 dns 
= CFDictionaryGetValue(service
, kSCEntNetDNS
); 
1055                 if (!isA_CFDictionary(dns
)) { 
1060                 dns_service_identifier  
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
); 
1061                 if (!isA_CFNumber(dns_service_identifier
)) { 
1062                         // if no DNS [vpn] Service Identifier 
1066                 if (CFSetContainsValue(seen
, dns_service_identifier
)) { 
1067                         my_log(LOG_ERR
, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping"); 
1070                 CFSetSetValue(seen
, dns_service_identifier
); 
1072                 newDNS 
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
); 
1074                 // add "Request A/AAAA query" flag(s) 
1075                 newFlags 
|= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
; 
1078                 searchDomains 
= extract_search_domains(newDNS
, NULL
); 
1079                 if (searchDomains 
!= NULL
) { 
1080                         CFDictionarySetValue(newDNS
, kSCPropNetDNSSearchDomains
, searchDomains
); 
1081                         CFRelease(searchDomains
); 
1082                         searchDomains 
= NULL
; 
1085                 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchDomains
); 
1086                 CFDictionaryRemoveValue(newDNS
, kSCPropNetDNSSupplementalMatchOrders
); 
1088                 if (CFDictionaryContainsKey(newDNS
, kSCPropInterfaceName
)) { 
1089                         CFMutableDictionaryRef  interfaceScopedDNS
; 
1090                         uint32_t                interfaceScopedFlags
; 
1092                         // The dictionary has an interface, so add a interface-scoped resolver 
1094                         CFDictionarySetValue(newDNS
, DNS_CONFIGURATION_SCOPED_QUERY_KEY
, kCFBooleanTrue
); 
1096                         interfaceScopedDNS 
= CFDictionaryCreateMutableCopy(NULL
, 0, newDNS
); 
1097                         interfaceScopedFlags 
= newFlags
; 
1099                         // set "scoped" configuration flag 
1100                         interfaceScopedFlags 
|= DNS_RESOLVER_FLAGS_SCOPED
; 
1101                         merge_configuration_flags(interfaceScopedDNS
, interfaceScopedFlags
); 
1103                         CFDictionaryRemoveValue(interfaceScopedDNS
, kSCPropNetDNSServiceIdentifier
); 
1105                         add_resolver_signature(interfaceScopedDNS
, "Service", serviceID
, 0); 
1106                         add_resolver(resolvers
, interfaceScopedDNS
); 
1107                         CFRelease(interfaceScopedDNS
); 
1110                 // set "service specific" configuration flag 
1111                 newFlags 
|= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
; 
1112                 merge_configuration_flags(newDNS
, newFlags
); 
1114                 add_resolver_signature(newDNS
, "Service", serviceID
, 0); 
1115                 add_resolver(resolvers
, newDNS
); 
1120         if (keys 
!= keys_q
) { 
1121                 CFAllocatorDeallocate(kCFAllocatorDefault
, keys
); 
1122                 CFAllocatorDeallocate(kCFAllocatorDefault
, vals
); 
1130 add_default_resolver(CFMutableArrayRef  resolvers
, 
1131                      CFDictionaryRef    defaultResolver
, 
1132                      Boolean            
*orderAdded
, 
1133                      CFArrayRef         
*searchDomains
) 
1135         CFMutableDictionaryRef  myDefault
; 
1136         uint32_t                myOrder 
= DEFAULT_SEARCH_ORDER
; 
1139         if (defaultResolver 
== NULL
) { 
1140                 myDefault 
= CFDictionaryCreateMutable(NULL
, 
1142                                                       &kCFTypeDictionaryKeyCallBacks
, 
1143                                                       &kCFTypeDictionaryValueCallBacks
); 
1145                 myDefault 
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultResolver
); 
1147         assert(myDefault 
!= NULL
); 
1149         // ensure that the default resolver has a search order 
1151         order 
= CFDictionaryGetValue(myDefault
, kSCPropNetDNSSearchOrder
); 
1152         if (!isA_CFNumber(order
) || 
1153             !CFNumberGetValue(order
, kCFNumberSInt32Type
, &myOrder
)) { 
1154                 myOrder 
= DEFAULT_SEARCH_ORDER
; 
1155                 order 
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
); 
1156                 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchOrder
, order
); 
1161         // extract the "search" domain list for the default resolver (and 
1162         // any supplemental resolvers) 
1164         *searchDomains 
= extract_search_domains(myDefault
, resolvers
); 
1166         // add the default resolver 
1168         add_resolver_signature(myDefault
, "Default", NULL
, 0); 
1169         add_resolver(resolvers
, myDefault
); 
1170         CFRelease(myDefault
); 
1175 static dns_create_resolver_t
 
1176 create_resolver(CFDictionaryRef dns
) 
1180         dns_create_resolver_t   _resolver
; 
1182         CFStringRef             targetInterface         
= NULL
; 
1183         unsigned int            targetInterfaceIndex    
= 0; 
1185         _resolver 
= _dns_resolver_create(); 
1188         str 
= CFDictionaryGetValue(dns
, kSCPropNetDNSDomainName
); 
1189         if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) { 
1190                 char    domain
[NS_MAXDNAME
]; 
1192                 if (_SC_cfstring_to_cstring(str
, domain
, sizeof(domain
), kCFStringEncodingUTF8
) != NULL
) { 
1193                         _dns_resolver_set_domain(&_resolver
, domain
); 
1197         // process search domains 
1198         list 
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchDomains
); 
1199         if (isA_CFArray(list
)) { 
1201                 CFIndex n       
= CFArrayGetCount(list
); 
1203                 // add "search" domains 
1204                 for (i 
= 0; i 
< n
; i
++) { 
1205                         str 
= CFArrayGetValueAtIndex(list
, i
); 
1206                         if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) { 
1207                                 char    search
[NS_MAXDNAME
]; 
1209                                 if (_SC_cfstring_to_cstring(str
, search
, sizeof(search
), kCFStringEncodingUTF8
) != NULL
) { 
1210                                         _dns_resolver_add_search(&_resolver
, search
); 
1216         // process interface index 
1217         num 
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_IF_INDEX_KEY
); 
1218         if (isA_CFNumber(num
)) { 
1221                 if (CFNumberGetValue(num
, kCFNumberIntType
, &if_index
)) { 
1223                         const char      *if_name        
= NULL
; 
1225                         if (if_index 
!= 0) { 
1226                                 if_name 
= my_if_indextoname(if_index
, buf
); 
1227                                 if (if_name 
!= NULL
) { 
1228                                         targetInterface 
= CFStringCreateWithCString(NULL
, 
1230                                                                                     kCFStringEncodingASCII
); 
1231                                         targetInterfaceIndex 
= if_index
; 
1235                         _dns_resolver_set_if_index(&_resolver
, if_index
, if_name
); 
1240         num 
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_FLAGS_KEY
); 
1241         if (isA_CFNumber(num
)) { 
1244                 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) { 
1245                         _dns_resolver_set_flags(&_resolver
, flags
); 
1249         // process nameserver addresses 
1250         // Note: the flags may be overwritten if the resolver has LOOPBACK addresses 
1251         list 
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerAddresses
); 
1252         if (isA_CFArray(list
)) { 
1254                 CFIndex n       
= CFArrayGetCount(list
); 
1256                 for (i 
= 0; i 
< n
; i
++) { 
1259                                 struct sockaddr_in      sin
; 
1260                                 struct sockaddr_in6     sin6
; 
1264                         str 
= CFArrayGetValueAtIndex(list
, i
); 
1265                         if (!isA_CFString(str
)) { 
1269                         if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) { 
1273                         if (_SC_string_to_sockaddr(buf
, AF_UNSPEC
, (void *)&addr
, sizeof(addr
)) == NULL
) { 
1277                         if ((addr
.sa
.sa_family 
== AF_INET6
) && 
1278                             IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
.sin6_addr
) && 
1279                             (addr
.sin6
.sin6_scope_id 
== 0) && 
1280                             (targetInterfaceIndex 
!= 0)) { 
1281                                 // for link local [IPv6] addresses, if the scope id is not 
1282                                 // set then we should use the interface associated with the 
1283                                 // resolver configuration 
1284                                 addr
.sin6
.sin6_scope_id 
= targetInterfaceIndex
; 
1287                         _dns_resolver_add_nameserver(&_resolver
, &addr
.sa
); 
1291         // process search order 
1292         num 
= CFDictionaryGetValue(dns
, kSCPropNetDNSSearchOrder
); 
1293         if (isA_CFNumber(num
)) { 
1296                 if (CFNumberGetValue(num
, kCFNumberSInt32Type
, &order
)) { 
1297                         _dns_resolver_set_order(&_resolver
, order
); 
1302         list 
= CFDictionaryGetValue(dns
, kSCPropNetDNSSortList
); 
1303         if (isA_CFArray(list
)) { 
1305                 CFIndex n       
= CFArrayGetCount(list
); 
1307                 for (i 
= 0; i 
< n
; i
++) { 
1310                         dns_sortaddr_t  sortaddr
; 
1312                         str 
= CFArrayGetValueAtIndex(list
, i
); 
1313                         if (!isA_CFString(str
)) { 
1317                         if (_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
) == NULL
) { 
1321                         slash 
= strchr(buf
, '/'); 
1322                         if (slash 
!= NULL
) { 
1326                         memset(&sortaddr
, 0, sizeof(sortaddr
)); 
1327                         if (inet_aton(buf
, &sortaddr
.address
) != 1) { 
1328                                 /* if address not valid */ 
1332                         if (slash 
!= NULL
) { 
1333                                 if (inet_aton(slash 
+ 1, &sortaddr
.mask
) != 1) { 
1334                                         /* if subnet mask not valid */ 
1341                                 a 
= ntohl(sortaddr
.address
.s_addr
); 
1344                                 } else if (IN_CLASSB(a
)) { 
1346                                 } else if (IN_CLASSC(a
)) { 
1352                                 sortaddr
.mask
.s_addr 
= htonl(m
); 
1355                         _dns_resolver_add_sortaddr(&_resolver
, &sortaddr
); 
1360         num 
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerPort
); 
1361         if (isA_CFNumber(num
)) { 
1364                 if (CFNumberGetValue(num
, kCFNumberIntType
, &port
)) { 
1365                         _dns_resolver_set_port(&_resolver
, (uint16_t)port
); 
1370         num 
= CFDictionaryGetValue(dns
, kSCPropNetDNSServerTimeout
); 
1371         if (isA_CFNumber(num
)) { 
1374                 if (CFNumberGetValue(num
, kCFNumberIntType
, &timeout
)) { 
1375                         _dns_resolver_set_timeout(&_resolver
, (uint32_t)timeout
); 
1380         str 
= CFDictionaryGetValue(dns
, kSCPropNetDNSOptions
); 
1381         if (isA_CFString(str
)) { 
1384                 options 
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
); 
1385                 if (options 
!= NULL
) { 
1386                         _dns_resolver_set_options(&_resolver
, options
); 
1387                         CFAllocatorDeallocate(NULL
, options
); 
1391         num 
= CFDictionaryGetValue(dns
, kSCPropNetDNSServiceIdentifier
); 
1392         if (isA_CFNumber(num
)) { 
1393                 int     dns_service_identifier
; 
1395                 if (CFNumberGetValue(num
, kCFNumberIntType
, &dns_service_identifier
)) { 
1396                         _dns_resolver_set_service_identifier(&_resolver
, (uint32_t)dns_service_identifier
); 
1400         // process configuration ID 
1401         str 
= CFDictionaryGetValue(dns
, DNS_CONFIGURATION_CONFIGURATION_ID
); 
1402         if (isA_CFString(str
) && (CFStringGetLength(str
) > 0)) { 
1405                 cID 
= _SC_cfstring_to_cstring(str
, NULL
, 0, kCFStringEncodingUTF8
); 
1407                         _dns_resolver_set_configuration_identifier(&_resolver
, cID
); 
1408                         CFAllocatorDeallocate(NULL
, cID
); 
1412         if (targetInterface 
!= NULL
) { 
1413                 CFRelease(targetInterface
); 
1420 static __inline__ Boolean
 
1421 isScopedConfiguration(CFDictionaryRef dns
) 
1426         if ((dns 
!= NULL
) && 
1427             CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) && 
1429             CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
) && 
1430             ((flags 
& DNS_RESOLVER_FLAGS_SCOPED
) != 0)) { 
1439 static CFComparisonResult
 
1440 compareDomain(const void *val1
, const void *val2
, void *context
) 
1442         CFDictionaryRef         dns1    
= (CFDictionaryRef
)val1
; 
1443         CFDictionaryRef         dns2    
= (CFDictionaryRef
)val2
; 
1444         CFStringRef             domain1
; 
1445         CFStringRef             domain2
; 
1446         CFArrayRef              labels1 
= NULL
; 
1447         CFArrayRef              labels2 
= NULL
; 
1450         CFComparisonResult      result
; 
1456         // "default" domains sort before "supplemental" domains 
1457         domain1 
= CFDictionaryGetValue(dns1
, kSCPropNetDNSDomainName
); 
1458         domain2 
= CFDictionaryGetValue(dns2
, kSCPropNetDNSDomainName
); 
1459         if (domain1 
== NULL
) { 
1460                 return kCFCompareLessThan
; 
1461         } else if (domain2 
== NULL
) { 
1462                 return kCFCompareGreaterThan
; 
1465         // sort non-scoped before scoped 
1466         scoped1 
= isScopedConfiguration(dns1
); 
1467         scoped2 
= isScopedConfiguration(dns2
); 
1468         if (scoped1 
!= scoped2
) { 
1470                         return kCFCompareLessThan
; 
1472                         return kCFCompareGreaterThan
; 
1476         // forward (A, AAAA) domains sort before reverse (PTR) domains 
1477         rev1 
= CFStringHasSuffix(domain1
, CFSTR(".arpa")); 
1478         rev2 
= CFStringHasSuffix(domain2
, CFSTR(".arpa")); 
1481                         return kCFCompareGreaterThan
; 
1483                         return kCFCompareLessThan
; 
1487         labels1 
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR(".")); 
1488         n1 
= CFArrayGetCount(labels1
); 
1490         labels2 
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR(".")); 
1491         n2 
= CFArrayGetCount(labels2
); 
1493         while ((n1 
> 0) && (n2 
> 0)) { 
1494                 CFStringRef     label1  
= CFArrayGetValueAtIndex(labels1
, --n1
); 
1495                 CFStringRef     label2  
= CFArrayGetValueAtIndex(labels2
, --n2
); 
1497                 // compare domain labels 
1498                 result 
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
); 
1499                 if (result 
!= kCFCompareEqualTo
) { 
1504         // longer labels (corp.apple.com) sort before shorter labels (apple.com) 
1506                 result 
= kCFCompareLessThan
; 
1508         } else if (n1 
< n2
) { 
1509                 result 
= kCFCompareGreaterThan
; 
1513         // sort by search order 
1514         result 
= compareBySearchOrder(val1
, val2
, context
); 
1518         if (labels1 
!= NULL
) CFRelease(labels1
); 
1519         if (labels2 
!= NULL
) CFRelease(labels2
); 
1524 static __inline__ Boolean
 
1525 needsMergeWithDefaultConfiguration(CFDictionaryRef dns
) 
1530         if ((dns 
!= NULL
) && 
1531             CFDictionaryGetValueIfPresent(dns
, DNS_CONFIGURATION_FLAGS_KEY
, (const void **)&num
) && 
1533             CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) { 
1535                 // check if merge needed (at all) 
1536                 if (dns_resolver_flags_all_queries(flags
)) { 
1537                         // if we are already querying for both A/AAAA 
1541                 // check if scoped or service-specific 
1542                 if (((flags 
& DNS_RESOLVER_FLAGS_SCOPED          
) != 0) || 
1543                     ((flags 
& DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC
) != 0)) { 
1555 dns_configuration_set(CFDictionaryRef   defaultResolver
, 
1556                       CFDictionaryRef   services
, 
1557                       CFArrayRef        serviceOrder
, 
1558                       CFArrayRef        multicastResolvers
, 
1559                       CFArrayRef        privateResolvers
, 
1560                       CFDictionaryRef   
*globalResolver
) 
1562         dns_create_config_t     dns_create_config
; 
1563         Boolean                 changed                 
= FALSE
; 
1565         CFMutableDictionaryRef  myDefault
; 
1566         Boolean                 myOrderAdded            
= FALSE
; 
1567         CFArrayRef              mySearchDomains         
= NULL
; 
1568         CFIndex                 n_resolvers
; 
1569         CFMutableArrayRef       resolvers
; 
1570         unsigned char           signature
[CC_SHA256_DIGEST_LENGTH
]; 
1571         static unsigned char    signature_last
[CC_SHA256_DIGEST_LENGTH
]; 
1573         // establish list of resolvers 
1575         resolvers 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
1576         assert(resolvers 
!= NULL
); 
1578         // collect (and add) any "supplemental" resolver configurations 
1580         add_supplemental_resolvers(resolvers
, services
, serviceOrder
, NULL
, NULL
); 
1582         // collect (and add) any "private" resolver configurations 
1584         add_private_resolvers(resolvers
, privateResolvers
); 
1586         // add the "default" resolver 
1588         if (defaultResolver 
!= NULL
) { 
1591                 servers 
= CFDictionaryGetValue(defaultResolver
, kSCPropNetDNSServerAddresses
); 
1592                 if (!isA_CFArray(servers
) || (CFArrayGetCount(servers
) == 0)) { 
1593                         // if no DNS server addresses 
1594                         defaultResolver 
= NULL
; 
1598         add_default_resolver(resolvers
, defaultResolver
, &myOrderAdded
, &mySearchDomains
); 
1600         // collect (and add) any "multicast" resolver configurations 
1602         add_multicast_resolvers(resolvers
, multicastResolvers
); 
1604         // collect (and add) any "scoped" resolver configurations 
1606         add_scoped_resolvers(resolvers
, services
, serviceOrder
); 
1608         // collect (and add) any "service-specific" resolver configurations 
1610         add_service_specific_resolvers(resolvers
, services
); 
1614         n_resolvers 
= CFArrayGetCount(resolvers
); 
1615         if (n_resolvers 
> 1) { 
1616                 CFArraySortValues(resolvers
, CFRangeMake(0, n_resolvers
), compareDomain
, NULL
); 
1621         for (i 
= n_resolvers
; --i 
> 0; ) { 
1622                 CFDictionaryRef resolver
; 
1624                 resolver 
= CFArrayGetValueAtIndex(resolvers
, i
); 
1625                 if (!CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) && 
1626                     !CFDictionaryContainsKey(resolver
, kSCPropNetDNSSearchDomains
) && 
1627                     !CFDictionaryContainsKey(resolver
, kSCPropNetDNSServerAddresses
)) { 
1628                         // remove empty resolver 
1629                         CFArrayRemoveValueAtIndex(resolvers
, i
); 
1634         // update the default resolver 
1636         myDefault 
= CFDictionaryCreateMutableCopy(NULL
, 
1638                                                   CFArrayGetValueAtIndex(resolvers
, 0)); 
1639         if (mySearchDomains 
!= NULL
) { 
1640                 // add search domains to the default resolver 
1641                 CFDictionarySetValue(myDefault
, kSCPropNetDNSSearchDomains
, mySearchDomains
); 
1642                 CFRelease(mySearchDomains
); 
1644         if (myOrderAdded 
&& (n_resolvers 
> 1)) { 
1645                 CFDictionaryRef resolver
; 
1647                 resolver 
= CFArrayGetValueAtIndex(resolvers
, 1); 
1648                 if (CFDictionaryContainsKey(resolver
, kSCPropNetDNSDomainName
) || 
1649                     isScopedConfiguration(resolver
)) { 
1650                         // if not a supplemental "default" resolver (a domain name is 
1651                         // present) or if it's a scoped configuration 
1652                         CFDictionaryRemoveValue(myDefault
, kSCPropNetDNSSearchOrder
); 
1655         CFArraySetValueAtIndex(resolvers
, 0, myDefault
); 
1656         CFRelease(myDefault
); 
1658         // establish resolver configuration 
1660         if ((defaultResolver 
== NULL
) && (n_resolvers 
<= 1)) { 
1662                  * if no default and no supplemental/scoped resolvers 
1664                 dns_create_config 
= NULL
; 
1666                 uint32_t        default_resolver_flags  
= 0; 
1667                 Boolean         have_default_flags      
= FALSE
; 
1670                  * if default and/or supplemental/scoped resolvers are defined 
1672                 dns_create_config 
= _dns_configuration_create(); 
1674                 for (i 
= 0; i 
< n_resolvers
; i
++) { 
1675                         Boolean                 merge_default_flags
; 
1676                         CFDictionaryRef         resolver
; 
1677                         dns_create_resolver_t   _resolver
; 
1679                         resolver 
= CFArrayGetValueAtIndex(resolvers
, i
); 
1681                         merge_default_flags 
= needsMergeWithDefaultConfiguration(resolver
); 
1682                         if (merge_default_flags
) { 
1683                                 CFMutableDictionaryRef  new_resolver
; 
1685                                 if (!have_default_flags
) { 
1686                                         CFDictionaryApplyFunction(services
, 
1687                                                                   add_dns_resolver_flags
, 
1688                                                                   &default_resolver_flags
); 
1689                                         have_default_flags 
= TRUE
; 
1692                                 new_resolver 
= CFDictionaryCreateMutableCopy(NULL
, 0, resolver
); 
1693                                 merge_configuration_flags(new_resolver
, default_resolver_flags
); 
1694                                 resolver 
= new_resolver
; 
1698                                 *globalResolver 
= CFRetain(resolver
); 
1701                         _resolver 
= create_resolver(resolver
); 
1702                         _dns_configuration_add_resolver(&dns_create_config
, _resolver
); 
1703                         _dns_resolver_free(&_resolver
); 
1705                         if (merge_default_flags
) { 
1706                                 CFRelease(resolver
); 
1710                 // add flatfile resolvers 
1712                 _dnsinfo_flatfile_set_flags(default_resolver_flags
); 
1713                 _dnsinfo_flatfile_add_resolvers(&dns_create_config
); 
1716         // check if the configuration changed 
1717         _dns_configuration_signature(&dns_create_config
, signature
, sizeof(signature
)); 
1718         if (bcmp(signature
, signature_last
, sizeof(signature
)) != 0) { 
1719                 // save [new] signature 
1720                 memcpy(signature_last
, signature
, sizeof(signature
)); 
1722                 my_log(LOG_INFO
, "Updating DNS configuration"); 
1723                 if (dns_create_config 
!= NULL
) { 
1724                         dns_config_t            
*dns_config     
= NULL
; 
1725                         _dns_config_buf_t       
*dns_config_buf
; 
1728                         n 
= sizeof(_dns_config_buf_t
); 
1729                         n 
+= ntohl(((_dns_config_buf_t 
*)dns_create_config
)->n_attribute
); 
1730                         dns_config_buf 
= _dns_configuration_buffer_create((void *)dns_create_config
, n
); 
1731                         if (dns_config_buf 
!= NULL
) { 
1732                                 dns_config 
= _dns_configuration_buffer_expand(dns_config_buf
); 
1733                                 if (dns_config 
== NULL
) { 
1734                                         // if we were unable to expand the configuration 
1735                                         _dns_configuration_buffer_free(&dns_config_buf
); 
1739                         if (dns_config 
!= NULL
) { 
1740                                 _dns_configuration_log(dns_config
, TRUE
, NULL
); 
1744                         my_log(LOG_INFO
, "*** No DNS configuration"); 
1747                 // save [new] configuration 
1748                 if (!_dns_configuration_store(&dns_create_config
)) { 
1749                         my_log(LOG_ERR
, "could not store configuration"); 
1756         if (dns_create_config 
!= NULL
) { 
1757                 _dns_configuration_free(&dns_create_config
); 
1760         CFRelease(resolvers
); 
1765 static SCDynamicStoreRef        dns_configuration_store
; 
1766 static SCDynamicStoreCallBack   dns_configuration_callout
; 
1769 dns_configuration_changed(ConstFSEventStreamRef         streamRef
, 
1770                           void                          *clientCallBackInfo
, 
1773                           const FSEventStreamEventFlags 
*eventFlags
, 
1774                           const FSEventStreamEventId    
*eventIds
) 
1776 #pragma unused(streamRef) 
1777 #pragma unused(clientCallBackInfo) 
1778 #pragma unused(numEvents) 
1779 #pragma unused(eventPaths) 
1780 #pragma unused(eventFlags) 
1781 #pragma unused(eventIds) 
1782         static const CFStringRef        key     
= CFSTR(_PATH_RESOLVER_DIR
); 
1784         Boolean                         resolvers_now
; 
1785         static Boolean                  resolvers_save  
= FALSE
; 
1786         struct stat                     statbuf
; 
1788         resolvers_now 
= (stat(_PATH_RESOLVER_DIR
, &statbuf
) == 0); 
1789         if (!resolvers_save 
&& (resolvers_save 
== resolvers_now
)) { 
1790                 // if we did not (and still do not) have an "/etc/resolvers" 
1791                 // directory than this notification is the result of a change 
1792                 // to the "/etc" directory. 
1795         resolvers_save 
= resolvers_now
; 
1797         my_log(LOG_INFO
, _PATH_RESOLVER_DIR 
" changed"); 
1799         // fake a "DNS" change 
1800         keys 
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
); 
1801         (*dns_configuration_callout
)(dns_configuration_store
, keys
, NULL
); 
1809 normalize_path(const char *file_name
, char resolved_name
[PATH_MAX
]) 
1812         char    path
[PATH_MAX
]; 
1814         strlcpy(path
, file_name
, sizeof(path
)); 
1815         if (realpath(path
, resolved_name
) != NULL
) { 
1816                 // if the path exists 
1820         ch 
= strrchr(path
, '/'); 
1823                 if (realpath(path
, resolved_name
) != NULL
) { 
1824                         // if a parent path exists 
1825                         strlcat(resolved_name
, "/", PATH_MAX
); 
1826                         strlcat(resolved_name
, ch
+1, PATH_MAX
); 
1837 dns_configuration_monitor(SCDynamicStoreRef store
, SCDynamicStoreCallBack callout
) 
1839         FSEventStreamContext            context 
= { 0,          // version 
1843                                                     NULL 
};     // copyDescription 
1844         FSEventStreamCreateFlags        flags   
= kFSEventStreamCreateFlagUseCFTypes
 
1845                                                   | kFSEventStreamCreateFlagFileEvents
 
1846                                                   | kFSEventStreamCreateFlagWatchRoot
; 
1847         FSEventStreamRef                monitor
; 
1849         CFMutableArrayRef               paths
; 
1850         char                            resolver_directory_path
[PATH_MAX
]; 
1852         if (!normalize_path(_PATH_RESOLVER_DIR
, resolver_directory_path
)) { 
1853                 my_log(LOG_ERR
, "Not monitoring \"%s\", could not resolve directory path", _PATH_RESOLVER_DIR
); 
1857         dns_configuration_store   
= store
; 
1858         dns_configuration_callout 
= callout
; 
1860         paths 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
1861         path 
= CFStringCreateWithCString(NULL
, resolver_directory_path
, kCFStringEncodingUTF8
); 
1862         CFArrayAppendValue(paths
, path
); 
1865         monitor 
= FSEventStreamCreate(NULL
,                             // allocator 
1866                                       dns_configuration_changed
,        // callback 
1867                                       &context
,                         // context 
1868                                       paths
,                            // pathsToWatch (CFArray) 
1869                                       kFSEventStreamEventIdSinceNow
,    // sinceWhen 
1875         FSEventStreamScheduleWithRunLoop(monitor
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
); 
1876         FSEventStreamStart(monitor
); 
1884 dns_configuration_init(CFBundleRef bundle
) 
1886         CFDictionaryRef dict
; 
1888         dict 
= CFBundleGetInfoDictionary(bundle
); 
1889         if (isA_CFDictionary(dict
)) { 
1890                 S_mdns_timeout 
= CFDictionaryGetValue(dict
, CFSTR("mdns_timeout")); 
1891                 S_mdns_timeout 
= isA_CFNumber(S_mdns_timeout
); 
1893                 S_pdns_timeout 
= CFDictionaryGetValue(dict
, CFSTR("pdns_timeout")); 
1894                 S_pdns_timeout 
= isA_CFNumber(S_pdns_timeout
); 
1902 #pragma mark Standalone test code 
1908 split(const void * key
, const void * value
, void * context
) 
1910         CFArrayRef              components
; 
1911         CFStringRef             entity_id
; 
1912         CFStringRef             service_id
; 
1913         CFMutableDictionaryRef  state_dict
; 
1915         components 
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/")); 
1916         service_id 
= CFArrayGetValueAtIndex(components
, 3); 
1917         entity_id  
= CFArrayGetValueAtIndex(components
, 4); 
1918         state_dict 
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
); 
1919         if (state_dict 
!= NULL
) { 
1920                 state_dict 
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
); 
1922                 state_dict 
= CFDictionaryCreateMutable(NULL
, 
1924                                                        &kCFTypeDictionaryKeyCallBacks
, 
1925                                                        &kCFTypeDictionaryValueCallBacks
); 
1928         if (CFEqual(entity_id
, kSCEntNetIPv4
) || 
1929             CFEqual(entity_id
, kSCEntNetIPv6
)) { 
1930                 CFDictionaryRef         dict
; 
1931                 CFStringRef             interface
; 
1933                 if (CFEqual(entity_id
, kSCEntNetIPv4
)) { 
1934                         dict 
= ipv4_dict_create(value
); 
1937                         dict 
= ipv6_dict_create(value
); 
1940                         CFDictionarySetValue(state_dict
, entity_id
, dict
); 
1943                 interface 
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
); 
1944                 if (interface 
!= NULL
) { 
1945                         CFDictionaryRef         dns
; 
1946                         CFMutableDictionaryRef  new_dns
; 
1948                         dns 
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
); 
1950                                 new_dns 
= CFDictionaryCreateMutableCopy(NULL
, 0, dns
); 
1952                                 new_dns 
= CFDictionaryCreateMutable(NULL
, 
1954                                                                     &kCFTypeDictionaryKeyCallBacks
, 
1955                                                                     &kCFTypeDictionaryValueCallBacks
); 
1957                         CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
); 
1958                         CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
); 
1961         } else if (CFEqual(entity_id
, kSCEntNetDNS
)) { 
1962                 CFDictionaryRef dns
; 
1964                 dns 
= CFDictionaryGetValue(state_dict
, kSCEntNetDNS
); 
1966                         CFStringRef     interface
; 
1968                         interface 
= CFDictionaryGetValue(dns
, kSCPropInterfaceName
); 
1969                         if (interface 
!= NULL
) { 
1970                                 CFMutableDictionaryRef  new_dns
; 
1972                                 new_dns 
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
); 
1973                                 CFDictionarySetValue(new_dns
, kSCPropInterfaceName
, interface
); 
1974                                 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, new_dns
); 
1977                                 CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
); 
1980                         CFDictionarySetValue(state_dict
, kSCEntNetDNS
, (CFDictionaryRef
)value
); 
1983                 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
); 
1986         CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
); 
1987         CFRelease(state_dict
); 
1988         CFRelease(components
); 
1994 main(int argc
, char **argv
) 
1996         CFDictionaryRef         entities
; 
1997         CFDictionaryRef         globalResolver  
= NULL
; 
1999         CFArrayRef              multicast_resolvers
; 
2000         CFStringRef             pattern
; 
2001         CFMutableArrayRef       patterns
; 
2002         CFStringRef             primary         
= NULL
; 
2003         CFDictionaryRef         primaryDNS      
= NULL
; 
2004         CFArrayRef              private_resolvers
; 
2005         CFArrayRef              service_order   
= NULL
; 
2006         CFMutableDictionaryRef  service_state_dict
; 
2007         CFDictionaryRef         setup_global_ipv4
; 
2008         CFDictionaryRef         state_global_ipv4
; 
2009         SCDynamicStoreRef       store
; 
2012         _sc_log     
= kSCLogDestinationFile
; 
2013         _sc_verbose 
= (argc 
> 1) ? TRUE 
: FALSE
; 
2015         store 
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
); 
2017         // get IPv4, IPv6, and DNS entities 
2018         patterns 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
2019         pattern 
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, 
2020                                                               kSCDynamicStoreDomainState
, 
2023         CFArrayAppendValue(patterns
, pattern
); 
2025         pattern 
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, 
2026                                                               kSCDynamicStoreDomainState
, 
2029         CFArrayAppendValue(patterns
, pattern
); 
2031         pattern 
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, 
2032                                                               kSCDynamicStoreDomainState
, 
2035         CFArrayAppendValue(patterns
, pattern
); 
2037         entities 
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
); 
2038         CFRelease(patterns
); 
2040         service_state_dict 
= CFDictionaryCreateMutable(NULL
, 
2042                                                        &kCFTypeDictionaryKeyCallBacks
, 
2043                                                        &kCFTypeDictionaryValueCallBacks
); 
2044         CFDictionaryApplyFunction(entities
, split
, service_state_dict
); 
2045         CFRelease(entities
); 
2047         // get primary service ID 
2048         key 
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, 
2049                                                          kSCDynamicStoreDomainState
, 
2051         state_global_ipv4 
= SCDynamicStoreCopyValue(store
, key
); 
2053         if (state_global_ipv4 
!= NULL
) { 
2054                 primary 
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
); 
2055                 if (primary 
!= NULL
) { 
2056                         CFDictionaryRef service_dict
; 
2058                         // get DNS configuration for primary service 
2059                         service_dict 
= CFDictionaryGetValue(service_state_dict
, primary
); 
2060                         if (service_dict 
!= NULL
) { 
2061                                 primaryDNS 
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
); 
2067         key 
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, 
2068                                                          kSCDynamicStoreDomainSetup
, 
2070         setup_global_ipv4 
= SCDynamicStoreCopyValue(store
, key
); 
2072         if (setup_global_ipv4 
!= NULL
) { 
2073                 service_order 
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
); 
2076         // get multicast resolvers 
2077         key 
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"), 
2078                                       kSCDynamicStoreDomainState
, 
2080                                       CFSTR(kDNSServiceCompMulticastDNS
)); 
2081         multicast_resolvers 
= SCDynamicStoreCopyValue(store
, key
); 
2084         // get private resolvers 
2085         key 
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"), 
2086                                       kSCDynamicStoreDomainState
, 
2088                                       CFSTR(kDNSServiceCompPrivateDNS
)); 
2089         private_resolvers 
= SCDynamicStoreCopyValue(store
, key
); 
2092         // update DNS configuration 
2093         dns_configuration_init(CFBundleGetMainBundle()); 
2094         (void)dns_configuration_set(primaryDNS
, 
2097                                     multicast_resolvers
, 
2102         if (setup_global_ipv4 
!= NULL
)  CFRelease(setup_global_ipv4
); 
2103         if (state_global_ipv4 
!= NULL
)  CFRelease(state_global_ipv4
); 
2104         if (multicast_resolvers 
!= NULL
) CFRelease(multicast_resolvers
); 
2105         if (private_resolvers 
!= NULL
)  CFRelease(private_resolvers
); 
2106         if (globalResolver 
!= NULL
)     CFRelease(globalResolver
); 
2107         CFRelease(service_state_dict
);