1/* 2 * Copyright (c) 2004-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * March 22, 2004 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31#include <TargetConditionals.h> 32#include <fcntl.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <unistd.h> 36#include <sys/types.h> 37#include <sys/socket.h> 38#include <sys/stat.h> 39#include <net/if.h> 40#include <netinet/in.h> 41#include <arpa/inet.h> 42#include <arpa/nameser.h> 43#include <resolv.h> 44#if !TARGET_OS_IPHONE 45#include <notify.h> 46extern uint32_t notify_monitor_file(int token, const char *name, int flags); 47#endif // !TARGET_OS_IPHONE 48#include <CommonCrypto/CommonDigest.h> 49 50#include <CoreFoundation/CoreFoundation.h> 51#include <SystemConfiguration/SystemConfiguration.h> 52#include <SystemConfiguration/SCPrivate.h> 53#include <SystemConfiguration/SCValidation.h> 54#include "ip_plugin.h" 55 56#include "dns-configuration.h" 57 58#include <dnsinfo.h> 59#include "dnsinfo_create.h" 60#include "dnsinfo_server.h" 61 62#ifdef MAIN 63#undef MAIN 64#include "dnsinfo_copy.c" 65#include "dnsinfo_internal.h" 66#define MAIN 67#define DNS_CONFIGURATION_DEBUG 68#endif // MAIN 69 70#include <dns_sd.h> 71#ifndef kDNSServiceCompMulticastDNS 72#define kDNSServiceCompMulticastDNS "MulticastDNS" 73#endif 74#ifndef kDNSServiceCompPrivateDNS 75#define kDNSServiceCompPrivateDNS "PrivateDNS" 76#endif 77 78#define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__") 79#define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__") 80#define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__") 81 82/* multicast DNS resolver configurations */ 83static CFNumberRef S_mdns_timeout = NULL; 84 85/* private DNS resolver configurations */ 86static CFNumberRef S_pdns_timeout = NULL; 87 88 89#pragma mark - 90#pragma mark DNS resolver flags 91 92 93static __inline__ boolean_t 94dns_resolver_flags_all_queries(uint32_t query_flags) 95{ 96 return ((query_flags & DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS) == DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS); 97} 98 99 100 101 102static void 103add_dns_query_flags(const void *key, const void *value, void *context) 104{ 105 CFDictionaryRef service = value; 106 uint32_t *query_flags = context; 107 108 109 // check if the service has v4 or v6 configured 110 111 if ((*query_flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS) == 0) { 112 CFDictionaryRef v4_dict; 113 114 v4_dict = CFDictionaryGetValue(service, kSCEntNetIPv4); 115 if (v4_dict != NULL) { 116 CFDictionaryRef v4_service; 117 118 v4_service = CFDictionaryGetValue(v4_dict, kIPv4DictService); 119 if (isA_CFDictionary(v4_service)) { 120 CFArrayRef if_addrs; 121 CFBooleanRef is_null; 122 123 is_null = CFDictionaryGetValue(v4_service, kIsNULL); 124 if_addrs = CFDictionaryGetValue(v4_service, kSCPropNetIPv4Addresses); 125 if (isA_CFBoolean(is_null) != NULL && CFBooleanGetValue(is_null)) { 126 // ignore this service 127 } 128 else if (isA_CFArray(if_addrs) != NULL) { 129 int i; 130 int count; 131 132 count = CFArrayGetCount(if_addrs); 133 for (i = 0; i < count; i++) { 134 CFStringRef if_addr; 135 struct in_addr v4_addr; 136 137 if_addr = CFArrayGetValueAtIndex(if_addrs, i); 138 if (isA_CFString(if_addr) == NULL) { 139 continue; 140 } 141 142 cfstring_to_ip(if_addr, &v4_addr); 143 if (!IN_LINKLOCAL(ntohl(v4_addr.s_addr))) { 144 // set the request v4 dns record bit 145 *query_flags |= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS; 146 break; 147 } 148 } 149 } 150 } 151 } 152 } 153 154 if ((*query_flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS) == 0) { 155 CFDictionaryRef v6_dict; 156 157 v6_dict = CFDictionaryGetValue(service, kSCEntNetIPv6); 158 if (isA_CFDictionary(v6_dict) != NULL) { 159 CFArrayRef if_addrs6; 160 CFBooleanRef is_null; 161 162 is_null = CFDictionaryGetValue(v6_dict, kIsNULL); 163 if_addrs6 = CFDictionaryGetValue(v6_dict, kSCPropNetIPv6Addresses); 164 if (isA_CFBoolean(is_null) != NULL && CFBooleanGetValue(is_null)) { 165 // ignore this service 166 } 167 else if (isA_CFArray(if_addrs6) != NULL) { 168 int i; 169 int count; 170 171 count = CFArrayGetCount(if_addrs6); 172 for (i = 0; i < count; i++) { 173 CFStringRef if_addr6; 174 struct in6_addr v6_addr; 175 176 if_addr6 = CFArrayGetValueAtIndex(if_addrs6, i); 177 if (isA_CFString(if_addr6) == NULL) { 178 continue; 179 } 180 181 cfstring_to_ip6(if_addr6, &v6_addr); 182 if (!IN6_IS_ADDR_LINKLOCAL(&v6_addr) 183 && !IN6_IS_ADDR_MC_LINKLOCAL(&v6_addr)) { 184 // set the request v6 dns record bit 185 *query_flags |= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS; 186 break; 187 } 188 } 189 } 190 } 191 } 192 193 194 return; 195} 196 197 198#pragma mark - 199#pragma mark DNS resolver configuration 200 201 202static void 203add_resolver(CFMutableArrayRef resolvers, CFMutableDictionaryRef resolver) 204{ 205 CFIndex i; 206 CFStringRef interface; 207 CFIndex n_resolvers; 208 CFNumberRef order; 209 uint32_t order_val = 0; 210 211 order = CFDictionaryGetValue(resolver, kSCPropNetDNSSearchOrder); 212 if (!isA_CFNumber(order) || 213 !CFNumberGetValue(order, kCFNumberSInt32Type, &order_val)) { 214 order = NULL; 215 order_val = 0; 216 } 217 218 n_resolvers = CFArrayGetCount(resolvers); 219 for (i = 0; i < n_resolvers; i++) { 220 CFDictionaryRef match_resolver; 221 222 match_resolver = CFArrayGetValueAtIndex(resolvers, i); 223 if (CFEqual(resolver, match_resolver)) { 224 // a real duplicate 225 return; 226 } 227 228 if (order != NULL) { 229 CFMutableDictionaryRef compare; 230 Boolean match; 231 232 compare = CFDictionaryCreateMutableCopy(NULL, 0, match_resolver); 233 CFDictionarySetValue(compare, kSCPropNetDNSSearchOrder, order); 234 match = CFEqual(resolver, compare); 235 CFRelease(compare); 236 if (match) { 237 CFNumberRef match_order; 238 uint32_t match_order_val = 0; 239 240 // if only the search order's are different 241 match_order = CFDictionaryGetValue(match_resolver, kSCPropNetDNSSearchOrder); 242 if (!isA_CFNumber(match_order) || 243 !CFNumberGetValue(match_order, kCFNumberSInt32Type, &match_order_val)) { 244 match_order_val = 0; 245 } 246 247 if (order_val < match_order_val ) { 248 // if we should prefer this match resolver, else just skip it 249 CFArraySetValueAtIndex(resolvers, i, resolver); 250 } 251 252 return; 253 } 254 } 255 } 256 257 order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_resolvers); 258 CFDictionarySetValue(resolver, DNS_CONFIGURATION_ORDER_KEY, order); 259 CFRelease(order); 260 261 interface = CFDictionaryGetValue(resolver, kSCPropInterfaceName); 262 if ((interface != NULL) && !CFEqual(interface, CFSTR("*"))) { 263 uint32_t flags; 264 unsigned int if_index = 0; 265 char if_name[IF_NAMESIZE]; 266 CFNumberRef num; 267 CFBooleanRef val; 268 269 if (_SC_cfstring_to_cstring(interface, 270 if_name, 271 sizeof(if_name), 272 kCFStringEncodingASCII) != NULL) { 273 if_index = if_nametoindex(if_name); 274 } 275 276 if ((if_index != 0) && 277 ( 278 // check if this is a "scoped" configuration 279 (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) && 280 isA_CFNumber(num) && 281 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) && 282 (flags & DNS_RESOLVER_FLAGS_SCOPED) != 0) 283 || 284 // check if we should scope all queries with this configuration 285 (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_SCOPED_QUERY_KEY, (const void **)&val) && 286 isA_CFBoolean(val) && 287 CFBooleanGetValue(val)) 288 ) 289 ) { 290 // if interface index available and it should be used 291 num = CFNumberCreate(NULL, kCFNumberIntType, &if_index); 292 CFDictionarySetValue(resolver, DNS_CONFIGURATION_IF_INDEX_KEY, num); 293 CFRelease(num); 294 } 295 } 296 297 CFArrayAppendValue(resolvers, resolver); 298 return; 299} 300 301 302static void 303add_supplemental(CFMutableArrayRef resolvers, CFDictionaryRef dns, uint32_t defaultOrder) 304{ 305 CFArrayRef domains; 306 CFIndex i; 307 CFIndex n_domains; 308 CFArrayRef orders; 309 310 domains = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomains); 311 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0; 312 if (n_domains == 0) { 313 return; 314 } 315 316 orders = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchOrders); 317 if (orders != NULL) { 318 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) { 319 return; 320 } 321 } 322 323 /* 324 * yes, this is a "supplemental" resolver configuration, expand 325 * the match domains and add each to the resolvers list. 326 */ 327 for (i = 0; i < n_domains; i++) { 328 CFStringRef match_domain; 329 CFNumberRef match_order; 330 CFMutableDictionaryRef match_resolver; 331 332 match_domain = CFArrayGetValueAtIndex(domains, i); 333 if (!isA_CFString(match_domain)) { 334 continue; 335 } 336 337 match_resolver = CFDictionaryCreateMutableCopy(NULL, 0, dns); 338 339 // set supplemental resolver "domain" 340 if (CFStringGetLength(match_domain) > 0) { 341 CFDictionarySetValue(match_resolver, kSCPropNetDNSDomainName, match_domain); 342 } else { 343 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSDomainName); 344 } 345 346 // set supplemental resolver "search_order" 347 match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL; 348 if (isA_CFNumber(match_order)) { 349 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, match_order); 350 } else if (!CFDictionaryContainsKey(match_resolver, kSCPropNetDNSSearchOrder)) { 351 CFNumberRef num; 352 353 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder); 354 CFDictionarySetValue(match_resolver, kSCPropNetDNSSearchOrder, num); 355 CFRelease(num); 356 357 defaultOrder++; // if multiple domains, maintain ordering 358 } 359 360 // remove keys we don't want in a supplemental resolver 361 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchDomains); 362 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSupplementalMatchOrders); 363 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSearchDomains); 364 CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSortList); 365 366 add_resolver(resolvers, match_resolver); 367 CFRelease(match_resolver); 368 } 369 370 return; 371} 372 373 374#define N_QUICK 32 375 376 377static void 378add_supplemental_resolvers(CFMutableArrayRef resolvers, 379 CFDictionaryRef services, 380 CFArrayRef service_order, 381 CFStringRef scoped_interface, 382 CFDictionaryRef scoped_service) 383{ 384 const void * keys_q[N_QUICK]; 385 const void ** keys = keys_q; 386 CFIndex i; 387 CFIndex n_order; 388 CFIndex n_services; 389 const void * vals_q[N_QUICK]; 390 const void ** vals = vals_q; 391 392 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0; 393 if (n_services == 0) { 394 return; // if no services 395 } 396 397 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 398 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0); 399 vals = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0); 400 } 401 402 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0; 403 404 CFDictionaryGetKeysAndValues(services, keys, vals); 405 for (i = 0; i < n_services; i++) { 406 uint32_t defaultOrder; 407 CFDictionaryRef dns; 408 CFStringRef interface; 409 uint32_t interface_flags; 410 CFMutableDictionaryRef newDNS = NULL; 411 CFDictionaryRef service = (CFDictionaryRef)vals[i]; 412 413 if (!isA_CFDictionary(service)) { 414 continue; 415 } 416 417 dns = CFDictionaryGetValue(service, kSCEntNetDNS); 418 dns = isA_CFDictionary(dns); 419 if (dns == NULL) { 420 continue; 421 } 422 423 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName); 424 425 if (scoped_interface != NULL) { 426 // 427 // we only want to add split/supplemental configurations 428 // for queries scoped to an interface if they are NOT 429 // associated with a "real" service 430 // 431 if (CFDictionaryContainsKey(service, kSCEntNetIPv4) || 432 CFDictionaryContainsKey(service, kSCEntNetIPv6)) { 433 continue; 434 } 435 436 // 437 // in addition, we don't want to add split/supplemental 438 // configurations for queries scoped to an interface if 439 // the configuration does not apply to all interfaces and 440 // the configuration is explicitly NOT for this interface 441 // 442 if (!_SC_CFEqual(interface, CFSTR("*")) && 443 !_SC_CFEqual(interface, scoped_interface)) { 444 continue; 445 } 446 447 // 448 // lastly, check if A/AAAA queries should be issued (based 449 // on the IP[v6] addresses). If we would not be issuing a 450 // query then don't bother adding the configuration. 451 // 452 interface_flags = 0; 453 add_dns_query_flags(NULL, scoped_service, &interface_flags); 454 if (interface_flags == 0) { 455 continue; 456 } 457 } 458 459 defaultOrder = DEFAULT_SEARCH_ORDER 460 - (DEFAULT_SEARCH_ORDER / 2) 461 + ((DEFAULT_SEARCH_ORDER / 1000) * i); 462 if ((n_order > 0) && 463 !CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) { 464 // push out services not specified in service order 465 defaultOrder += (DEFAULT_SEARCH_ORDER / 1000) * n_services; 466 } 467 468 /* 469 * Ensure that we have the correct InterfaceName in the DNS configuration 470 * 471 * scoped_interface [supplemental] interface DNS interface 472 * ================ ======================== ================= 473 * NULL NULL NULL (No change) 474 * NULL en0 NULL 475 * NULL * NULL 476 * en0 NULL "en0" 477 * en0 en0 "en0" (now mutable) 478 * en0 * "en0" 479 */ 480 if ((scoped_interface == NULL) && (interface == NULL)) { 481 newDNS = (CFMutableDictionaryRef)CFRetain(dns); 482 } else { 483 newDNS = CFDictionaryCreateMutableCopy(NULL, 0, dns); 484 if (scoped_interface != NULL) { 485 CFDictionarySetValue(newDNS, kSCPropInterfaceName, scoped_interface); 486 } else { 487 CFDictionaryRemoveValue(newDNS, kSCPropInterfaceName); 488 } 489 } 490 491 if (scoped_interface != NULL) { 492 uint32_t flags; 493 CFNumberRef num; 494 495 // set "scoped" configuration flag(s) 496 if (!CFDictionaryGetValueIfPresent(newDNS, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) || 497 !isA_CFNumber(num) || 498 !CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) { 499 flags = 0; 500 } 501 flags |= DNS_RESOLVER_FLAGS_SCOPED; 502 503 // add A/AAAA query flag(s) 504 flags |= interface_flags; 505 506 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags); 507 CFDictionarySetValue(newDNS, DNS_CONFIGURATION_FLAGS_KEY, num); 508 CFRelease(num); 509 } 510 511 // add [scoped] resolver entry 512 add_supplemental(resolvers, newDNS, defaultOrder); 513 CFRelease(newDNS); 514 } 515 516 if (keys != keys_q) { 517 CFAllocatorDeallocate(NULL, keys); 518 CFAllocatorDeallocate(NULL, vals); 519 } 520 521 return; 522} 523 524 525static void 526add_multicast_resolvers(CFMutableArrayRef resolvers, CFArrayRef multicastResolvers) 527{ 528 CFIndex i; 529 CFIndex n; 530 531 n = isA_CFArray(multicastResolvers) ? CFArrayGetCount(multicastResolvers) : 0; 532 for (i = 0; i < n; i++) { 533 uint32_t defaultOrder; 534 CFStringRef domain; 535 CFNumberRef num; 536 CFMutableDictionaryRef resolver; 537 538 domain = CFArrayGetValueAtIndex(multicastResolvers, i); 539 domain = _SC_trimDomain(domain); 540 if (domain == NULL) { 541 continue; 542 } 543 544 defaultOrder = DEFAULT_SEARCH_ORDER 545 + (DEFAULT_SEARCH_ORDER / 2) 546 + ((DEFAULT_SEARCH_ORDER / 1000) * i); 547 548 resolver = CFDictionaryCreateMutable(NULL, 549 0, 550 &kCFTypeDictionaryKeyCallBacks, 551 &kCFTypeDictionaryValueCallBacks); 552 CFDictionarySetValue(resolver, kSCPropNetDNSDomainName, domain); 553 CFDictionarySetValue(resolver, kSCPropNetDNSOptions, CFSTR("mdns")); 554 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder); 555 CFDictionarySetValue(resolver, kSCPropNetDNSSearchOrder, num); 556 CFRelease(num); 557 if (S_mdns_timeout != NULL) { 558 CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_mdns_timeout); 559 } 560 add_resolver(resolvers, resolver); 561 CFRelease(resolver); 562 CFRelease(domain); 563 } 564 565 return; 566} 567 568 569static void 570add_private_resolvers(CFMutableArrayRef resolvers, CFArrayRef privateResolvers) 571{ 572 CFIndex i; 573 CFIndex n; 574 575 n = isA_CFArray(privateResolvers) ? CFArrayGetCount(privateResolvers) : 0; 576 for (i = 0; i < n; i++) { 577 uint32_t defaultOrder; 578 CFStringRef domain; 579 CFNumberRef num; 580 CFMutableDictionaryRef resolver; 581 582 domain = CFArrayGetValueAtIndex(privateResolvers, i); 583 domain = _SC_trimDomain(domain); 584 if (domain == NULL) { 585 continue; 586 } 587 588 defaultOrder = DEFAULT_SEARCH_ORDER 589 - (DEFAULT_SEARCH_ORDER / 4) 590 + ((DEFAULT_SEARCH_ORDER / 1000) * i); 591 592 resolver = CFDictionaryCreateMutable(NULL, 593 0, 594 &kCFTypeDictionaryKeyCallBacks, 595 &kCFTypeDictionaryValueCallBacks); 596 CFDictionarySetValue(resolver, kSCPropNetDNSDomainName, domain); 597 CFDictionarySetValue(resolver, kSCPropNetDNSOptions, CFSTR("pdns")); 598 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder); 599 CFDictionarySetValue(resolver, kSCPropNetDNSSearchOrder, num); 600 CFRelease(num); 601 if (S_pdns_timeout != NULL) { 602 CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_pdns_timeout); 603 } 604 add_resolver(resolvers, resolver); 605 CFRelease(resolver); 606 CFRelease(domain); 607 } 608 609 return; 610} 611 612 613static CFComparisonResult 614compareBySearchOrder(const void *val1, const void *val2, void *context) 615{ 616 CFDictionaryRef dns1 = (CFDictionaryRef)val1; 617 CFDictionaryRef dns2 = (CFDictionaryRef)val2; 618 CFNumberRef num1; 619 CFNumberRef num2; 620 uint32_t order1 = DEFAULT_SEARCH_ORDER; 621 uint32_t order2 = DEFAULT_SEARCH_ORDER; 622 623 num1 = CFDictionaryGetValue(dns1, kSCPropNetDNSSearchOrder); 624 if (!isA_CFNumber(num1) || 625 !CFNumberGetValue(num1, kCFNumberSInt32Type, &order1)) { 626 order1 = DEFAULT_SEARCH_ORDER; 627 } 628 629 num2 = CFDictionaryGetValue(dns2, kSCPropNetDNSSearchOrder); 630 if (!isA_CFNumber(num2) || 631 !CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) { 632 order2 = DEFAULT_SEARCH_ORDER; 633 } 634 635 if (order1 == order2) { 636 // if same "SearchOrder", retain original orderring for configurations 637 if (CFDictionaryGetValueIfPresent(dns1, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num1) && 638 CFDictionaryGetValueIfPresent(dns2, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num2) && 639 isA_CFNumber(num1) && 640 isA_CFNumber(num2) && 641 CFNumberGetValue(num1, kCFNumberSInt32Type, &order1) && 642 CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) { 643 if (order1 == order2) { 644 return kCFCompareEqualTo; 645 } else { 646 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; 647 } 648 } 649 650 return kCFCompareEqualTo; 651 } 652 653 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; 654} 655 656 657static CF_RETURNS_RETAINED CFArrayRef 658extract_search_domains(CFMutableDictionaryRef defaultDomain, CFArrayRef supplemental) 659{ 660 CFStringRef defaultDomainName = NULL; 661 uint32_t defaultOrder = DEFAULT_SEARCH_ORDER; 662 CFArrayRef defaultSearchDomains = NULL; 663 CFIndex defaultSearchIndex = 0; 664 CFIndex i; 665 CFMutableArrayRef mySearchDomains; 666 CFMutableArrayRef mySupplemental = NULL; 667 CFIndex n_supplemental; 668 669 mySearchDomains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 670 671 if (defaultDomain != NULL) { 672 CFNumberRef num; 673 674 num = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSSearchOrder); 675 if (!isA_CFNumber(num) || 676 !CFNumberGetValue(num, kCFNumberSInt32Type, &defaultOrder)) { 677 defaultOrder = DEFAULT_SEARCH_ORDER; 678 } 679 680 defaultDomainName = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSDomainName); 681 defaultSearchDomains = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSSearchDomains); 682 } 683 684 // validate the provided "search" domains or move/expand/promote the "domain" name 685 if (isA_CFArray(defaultSearchDomains)) { 686 CFIndex n_search; 687 688 n_search = CFArrayGetCount(defaultSearchDomains); 689 for (i = 0; i < n_search; i++) { 690 CFStringRef search; 691 692 search = CFArrayGetValueAtIndex(defaultSearchDomains, i); 693 search = _SC_trimDomain(search); 694 if (search != NULL) { 695 CFArrayAppendValue(mySearchDomains, search); 696 CFRelease(search); 697 } 698 } 699 } else { 700 defaultDomainName = _SC_trimDomain(defaultDomainName); 701 if (defaultDomainName != NULL) { 702 CFStringRef defaultOptions; 703 char *domain; 704 int domain_parts = 1; 705 char *dp; 706 int ndots = 1; 707 708#define NDOTS_OPT "ndots=" 709#define NDOTS_OPT_LEN (sizeof("ndots=") - 1) 710 711 defaultOptions = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSOptions); 712 if (defaultOptions != NULL) { 713 char *cp; 714 char *options; 715 716 options = _SC_cfstring_to_cstring(defaultOptions, 717 NULL, 718 0, 719 kCFStringEncodingUTF8); 720 cp = strstr(options, NDOTS_OPT); 721 if ((cp != NULL) && 722 ((cp == options) || isspace(cp[-1])) && 723 ((cp[NDOTS_OPT_LEN] != '\0') && isdigit(cp[NDOTS_OPT_LEN]))) { 724 char *end; 725 long val; 726 727 cp += NDOTS_OPT_LEN; 728 errno = 0; 729 val = strtol(cp, &end, 10); 730 if ((*cp != '\0') && (cp != end) && (errno == 0) && 731 ((*end == '\0') || isspace(*end)) && (val > 0)) { 732 ndots = val; 733 } 734 } 735 CFAllocatorDeallocate(NULL, options); 736 } 737 738 domain = _SC_cfstring_to_cstring(defaultDomainName, 739 NULL, 740 0, 741 kCFStringEncodingUTF8); 742 CFRelease(defaultDomainName); 743 744 // count domain parts 745 for (dp = domain; *dp != '\0'; dp++) { 746 if (*dp == '.') { 747 domain_parts++; 748 } 749 } 750 751 // move "domain" to "search" list (and expand as needed) 752 i = LOCALDOMAINPARTS; 753 dp = domain; 754 do { 755 CFStringRef search; 756 CFStringRef str; 757 758 str = CFStringCreateWithCString(NULL, 759 dp, 760 kCFStringEncodingUTF8); 761 search = _SC_trimDomain(str); 762 CFRelease(str); 763 if (search != NULL) { 764 CFArrayAppendValue(mySearchDomains, search); 765 CFRelease(search); 766 } 767 768 dp = strchr(dp, '.') + 1; 769 } while (++i <= (domain_parts - ndots)); 770 CFAllocatorDeallocate(NULL, domain); 771 } 772 } 773 774 // add any supplemental "domain" names to the search list 775 n_supplemental = (supplemental != NULL) ? CFArrayGetCount(supplemental) : 0; 776 if (n_supplemental > 1) { 777 mySupplemental = CFArrayCreateMutableCopy(NULL, 0, supplemental); 778 CFArraySortValues(mySupplemental, 779 CFRangeMake(0, n_supplemental), 780 compareBySearchOrder, 781 NULL); 782 supplemental = mySupplemental; 783 } 784 for (i = 0; i < n_supplemental; i++) { 785 CFDictionaryRef dns; 786 CFIndex domainIndex; 787 int noSearch; 788 CFNumberRef num; 789 CFStringRef options; 790 CFStringRef supplementalDomain; 791 uint32_t supplementalOrder; 792 793 dns = CFArrayGetValueAtIndex(supplemental, i); 794 795 options = CFDictionaryGetValue(dns, kSCPropNetDNSOptions); 796 if (isA_CFString(options)) { 797 CFRange range; 798 799 if (CFEqual(options, CFSTR("pdns"))) { 800 // don't add private resolver domains to the search list 801 continue; 802 } 803 804 range = CFStringFind(options, CFSTR("interface="), 0); 805 if (range.location != kCFNotFound) { 806 // don't add scoped resolver domains to the search list 807 continue; 808 } 809 } 810 811 supplementalDomain = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName); 812 supplementalDomain = _SC_trimDomain(supplementalDomain); 813 if (supplementalDomain == NULL) { 814 continue; 815 } 816 817 num = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomainsNoSearch); 818 if (isA_CFNumber(num) && 819 CFNumberGetValue(num, kCFNumberIntType, &noSearch) && 820 (noSearch != 0)) { 821 CFRelease(supplementalDomain); 822 continue; 823 } 824 825 if (CFStringHasSuffix(supplementalDomain, CFSTR(".in-addr.arpa")) || 826 CFStringHasSuffix(supplementalDomain, CFSTR(".ip6.arpa" ))) { 827 CFRelease(supplementalDomain); 828 continue; 829 } 830 831 domainIndex = CFArrayGetFirstIndexOfValue(mySearchDomains, 832 CFRangeMake(0, CFArrayGetCount(mySearchDomains)), 833 supplementalDomain); 834 835 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder); 836 if (!isA_CFNumber(num) || 837 !CFNumberGetValue(num, kCFNumberSInt32Type, &supplementalOrder)) { 838 supplementalOrder = DEFAULT_SEARCH_ORDER; 839 } 840 841 if (supplementalOrder < defaultOrder) { 842 if (domainIndex != kCFNotFound) { 843 // if supplemental domain is already in the search list 844 CFArrayRemoveValueAtIndex(mySearchDomains, domainIndex); 845 if (domainIndex < defaultSearchIndex) { 846 defaultSearchIndex--; 847 } 848 } 849 CFArrayInsertValueAtIndex(mySearchDomains, 850 defaultSearchIndex, 851 supplementalDomain); 852 defaultSearchIndex++; 853 } else { 854 if (domainIndex == kCFNotFound) { 855 // add to the (end of the) search list 856 CFArrayAppendValue(mySearchDomains, supplementalDomain); 857 } 858 } 859 860 CFRelease(supplementalDomain); 861 } 862 if (mySupplemental != NULL) CFRelease(mySupplemental); 863 864 // update the "search" domains 865 if (CFArrayGetCount(mySearchDomains) == 0) { 866 CFRelease(mySearchDomains); 867 mySearchDomains = NULL; 868 } 869 870 // remove the "domain" name and "search" list 871 CFDictionaryRemoveValue(defaultDomain, kSCPropNetDNSDomainName); 872 CFDictionaryRemoveValue(defaultDomain, kSCPropNetDNSSearchDomains); 873 874 return mySearchDomains; 875} 876 877 878static void 879add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArrayRef service_order) 880{ 881 const void * keys_q[N_QUICK]; 882 const void ** keys = keys_q; 883 CFIndex i; 884 CFIndex n_order; 885 CFIndex n_services; 886 CFMutableArrayRef order; 887 CFMutableSetRef seen; 888 889 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0; 890 if (n_services == 0) { 891 return; // if no services 892 } 893 894 // ensure that we process all services in order 895 896 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0; 897 if (n_order > 0) { 898 order = CFArrayCreateMutableCopy(NULL, 0, service_order); 899 } else { 900 order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 901 } 902 903 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 904 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0); 905 } 906 CFDictionaryGetKeysAndValues(services, keys, NULL); 907 for (i = 0; i < n_services; i++) { 908 CFStringRef serviceID = (CFStringRef)keys[i]; 909 910 if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) { 911 CFArrayAppendValue(order, serviceID); 912 n_order++; 913 } 914 } 915 if (keys != keys_q) { 916 CFAllocatorDeallocate(NULL, keys); 917 } 918 919 // iterate over services 920 921 seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 922 for (i = 0; i < n_order; i++) { 923 CFDictionaryRef dns; 924 uint32_t flags; 925 char if_name[IF_NAMESIZE]; 926 CFStringRef interface; 927 CFMutableDictionaryRef newDNS; 928 CFNumberRef num; 929 CFArrayRef searchDomains; 930 CFDictionaryRef service; 931 CFStringRef serviceID; 932 uint32_t these_flags; 933 934 serviceID = CFArrayGetValueAtIndex(order, i); 935 service = CFDictionaryGetValue(services, serviceID); 936 if (!isA_CFDictionary(service)) { 937 // if no service 938 continue; 939 } 940 941 dns = CFDictionaryGetValue(service, kSCEntNetDNS); 942 if (!isA_CFDictionary(dns)) { 943 // if no DNS 944 continue; 945 } 946 947 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName); 948 if ((interface == NULL) || CFEqual(interface, CFSTR("*"))) { 949 // if no [scoped] interface or supplemental configuration w/match-all 950 continue; 951 } 952 953 if (CFDictionaryContainsKey(dns, kSCPropNetDNSServiceIdentifier)) { 954 // if this is a service-specific resolver 955 continue; 956 } 957 958 if (CFSetContainsValue(seen, interface)) { 959 // if we've already processed this [scoped] interface 960 continue; 961 } 962 CFSetSetValue(seen, interface); 963 964 if ((_SC_cfstring_to_cstring(interface, 965 if_name, 966 sizeof(if_name), 967 kCFStringEncodingASCII) == NULL) || 968 (if_nametoindex(if_name) == 0)) { 969 // if interface index not available 970 continue; 971 } 972 973 // add [scoped] resolver entry 974 newDNS = CFDictionaryCreateMutableCopy(NULL, 0, dns); 975 976 // set search list 977 searchDomains = extract_search_domains(newDNS, NULL); 978 if (searchDomains != NULL) { 979 CFDictionarySetValue(newDNS, kSCPropNetDNSSearchDomains, searchDomains); 980 CFRelease(searchDomains); 981 } 982 983 // set "scoped" configuration flag(s) 984 if (!CFDictionaryGetValueIfPresent(newDNS, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) || 985 !isA_CFNumber(num) || 986 !CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) { 987 flags = 0; 988 } 989 flags |= DNS_RESOLVER_FLAGS_SCOPED; 990 991 these_flags = 0; 992 add_dns_query_flags(serviceID, service, &these_flags); 993 if (these_flags == 0) { 994 goto skip; 995 } 996 flags |= these_flags; 997 998 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags); 999 CFDictionarySetValue(newDNS, DNS_CONFIGURATION_FLAGS_KEY, num); 1000 CFRelease(num); 1001 1002 // remove keys we don't want in a [scoped] resolver 1003 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchDomains); 1004 CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchOrders); 1005 1006 // add the [scoped] resolver 1007 add_resolver(scoped, newDNS); 1008 1009 // add any supplemental resolver configurations for this interface 1010 add_supplemental_resolvers(scoped, services, service_order, interface, service); 1011 1012 skip: 1013 CFRelease(newDNS); 1014 } 1015 1016 CFRelease(seen); 1017 CFRelease(order); 1018 return; 1019} 1020 1021 1022static void 1023add_service_specific_resolvers(CFMutableArrayRef resolvers, CFDictionaryRef services) 1024{ 1025 CFIndex services_count = (isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0); 1026 1027 if (services_count > 0) { 1028 CFIndex key_idx; 1029 CFStringRef keys_q[N_QUICK]; 1030 CFStringRef *keys = keys_q; 1031 CFMutableSetRef seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 1032 1033 if (services_count > (CFIndex)(sizeof(keys_q) / sizeof(keys_q[0]))) { 1034 keys = CFAllocatorAllocate(kCFAllocatorDefault, services_count * sizeof(keys[0]), 0); 1035 } 1036 1037 CFDictionaryGetKeysAndValues(services, (const void **)keys, NULL); 1038 1039 for (key_idx = 0; key_idx < services_count; key_idx++) { 1040 CFDictionaryRef service = CFDictionaryGetValue(services, keys[key_idx]); 1041 CFDictionaryRef dns = CFDictionaryGetValue(service, kSCEntNetDNS); 1042 1043 if (isA_CFDictionary(dns)) { 1044 CFNumberRef service_identifier = CFDictionaryGetValue(dns, kSCPropNetDNSServiceIdentifier); 1045 1046 if (isA_CFNumber(service_identifier)) { 1047 if (!CFSetContainsValue(seen, service_identifier)) { 1048 CFMutableDictionaryRef new_resolver = CFDictionaryCreateMutableCopy(NULL, 0, dns); 1049 CFNumberRef flags_num; 1050 int32_t flags = 0; 1051 1052 CFSetSetValue(seen, service_identifier); 1053 1054 if (!CFDictionaryGetValueIfPresent(new_resolver, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&flags_num) || 1055 !isA_CFNumber(flags_num) || 1056 !CFNumberGetValue(flags_num, kCFNumberSInt32Type, &flags)) { 1057 flags = 0; 1058 } 1059 1060 flags |= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC | DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS; 1061 1062 flags_num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags); 1063 CFDictionarySetValue(new_resolver, DNS_CONFIGURATION_FLAGS_KEY, flags_num); 1064 CFRelease(flags_num); 1065 1066 if (CFDictionaryContainsKey(new_resolver, kSCPropInterfaceName)) { 1067 CFDictionarySetValue(new_resolver, DNS_CONFIGURATION_SCOPED_QUERY_KEY, kCFBooleanTrue); 1068 } 1069 1070 CFDictionaryRemoveValue(new_resolver, kSCPropNetDNSSupplementalMatchDomains); 1071 CFDictionaryRemoveValue(new_resolver, kSCPropNetDNSSupplementalMatchOrders); 1072 1073 add_resolver(resolvers, new_resolver); 1074 CFRelease(new_resolver); 1075 } else { 1076 my_log(LOG_ERR, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping"); 1077 } 1078 } 1079 } 1080 } 1081 1082 if (keys != keys_q) { 1083 CFAllocatorDeallocate(kCFAllocatorDefault, keys); 1084 } 1085 CFRelease(seen); 1086 } 1087} 1088 1089 1090static void 1091add_default_resolver(CFMutableArrayRef resolvers, 1092 CFDictionaryRef defaultResolver, 1093 Boolean *orderAdded, 1094 CFArrayRef *searchDomains) 1095{ 1096 CFMutableDictionaryRef myDefault; 1097 uint32_t myOrder = DEFAULT_SEARCH_ORDER; 1098 CFNumberRef order; 1099 1100 if (defaultResolver == NULL) { 1101 myDefault = CFDictionaryCreateMutable(NULL, 1102 0, 1103 &kCFTypeDictionaryKeyCallBacks, 1104 &kCFTypeDictionaryValueCallBacks); 1105 } else { 1106 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver); 1107 } 1108 assert(myDefault != NULL); 1109 1110 // ensure that the default resolver has a search order 1111 1112 order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder); 1113 if (!isA_CFNumber(order) || 1114 !CFNumberGetValue(order, kCFNumberSInt32Type, &myOrder)) { 1115 myOrder = DEFAULT_SEARCH_ORDER; 1116 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder); 1117 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order); 1118 CFRelease(order); 1119 *orderAdded = TRUE; 1120 } 1121 1122 // extract the "search" domain list for the default resolver (and 1123 // any supplemental resolvers) 1124 1125 *searchDomains = extract_search_domains(myDefault, resolvers); 1126 1127 // add the default resolver 1128 1129 add_resolver(resolvers, myDefault); 1130 CFRelease(myDefault); 1131 return; 1132} 1133 1134 1135static dns_create_resolver_t 1136create_resolver(CFDictionaryRef dns) 1137{ 1138 CFArrayRef list; 1139 CFNumberRef num; 1140 dns_create_resolver_t _resolver; 1141 CFStringRef str; 1142 CFStringRef targetInterface = NULL; 1143 unsigned int targetInterfaceIndex = 0; 1144 1145 _resolver = _dns_resolver_create(); 1146 1147 // process domain 1148 str = CFDictionaryGetValue(dns, kSCPropNetDNSDomainName); 1149 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) { 1150 char domain[NS_MAXDNAME]; 1151 1152 if (_SC_cfstring_to_cstring(str, domain, sizeof(domain), kCFStringEncodingUTF8) != NULL) { 1153 _dns_resolver_set_domain(&_resolver, domain); 1154 } 1155 } 1156 1157 // process search domains 1158 list = CFDictionaryGetValue(dns, kSCPropNetDNSSearchDomains); 1159 if (isA_CFArray(list)) { 1160 CFIndex i; 1161 CFIndex n = CFArrayGetCount(list); 1162 1163 // add "search" domains 1164 for (i = 0; i < n; i++) { 1165 str = CFArrayGetValueAtIndex(list, i); 1166 if (isA_CFString(str) && (CFStringGetLength(str) > 0)) { 1167 char search[NS_MAXDNAME]; 1168 1169 if (_SC_cfstring_to_cstring(str, search, sizeof(search), kCFStringEncodingUTF8) != NULL) { 1170 _dns_resolver_add_search(&_resolver, search); 1171 } 1172 } 1173 } 1174 } 1175 1176 // process interface index 1177 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_IF_INDEX_KEY); 1178 if (isA_CFNumber(num)) { 1179 int if_index; 1180 1181 if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) { 1182 char if_name[IFNAMSIZ]; 1183 1184 _dns_resolver_set_if_index(&_resolver, if_index); 1185 1186 if ((if_index != 0) && 1187 (if_indextoname(if_index, if_name) != NULL)) { 1188 targetInterface = CFStringCreateWithCString(NULL, 1189 if_name, 1190 kCFStringEncodingASCII); 1191 targetInterfaceIndex = if_index; 1192 } 1193 } 1194 } 1195 1196 // process flags 1197 num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_FLAGS_KEY); 1198 if (isA_CFNumber(num)) { 1199 uint32_t flags; 1200 1201 if (CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) { 1202 _dns_resolver_set_flags(&_resolver, flags); 1203 } 1204 } 1205 1206 // process nameserver addresses 1207 // Note: the flags may be overwritten if the resolver has LOOPBACK addresses 1208 list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses); 1209 if (isA_CFArray(list)) { 1210 CFIndex i; 1211 CFIndex n = CFArrayGetCount(list); 1212 1213 for (i = 0; i < n; i++) { 1214 union { 1215 struct sockaddr sa; 1216 struct sockaddr_in sin; 1217 struct sockaddr_in6 sin6; 1218 } addr; 1219 char buf[64]; 1220 1221 str = CFArrayGetValueAtIndex(list, i); 1222 if (!isA_CFString(str)) { 1223 continue; 1224 } 1225 1226 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) { 1227 continue; 1228 } 1229 1230 if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) { 1231 continue; 1232 } 1233 1234 if ((addr.sa.sa_family == AF_INET6) && 1235 (IN6_IS_ADDR_LINKLOCAL(&addr.sin6.sin6_addr) || 1236 IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6.sin6_addr)) && 1237 (addr.sin6.sin6_scope_id == 0) && 1238 (targetInterfaceIndex != 0)) { 1239 // for link local [IPv6] addresses, if the scope id is not 1240 // set then we should use the interface associated with the 1241 // resolver configuration 1242 addr.sin6.sin6_scope_id = targetInterfaceIndex; 1243 } 1244 1245 _dns_resolver_add_nameserver(&_resolver, &addr.sa); 1246 } 1247 } 1248 1249 // process search order 1250 num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder); 1251 if (isA_CFNumber(num)) { 1252 uint32_t order; 1253 1254 if (CFNumberGetValue(num, kCFNumberSInt32Type, &order)) { 1255 _dns_resolver_set_order(&_resolver, order); 1256 } 1257 } 1258 1259 // process sortlist 1260 list = CFDictionaryGetValue(dns, kSCPropNetDNSSortList); 1261 if (isA_CFArray(list)) { 1262 CFIndex i; 1263 CFIndex n = CFArrayGetCount(list); 1264 1265 for (i = 0; i < n; i++) { 1266 char buf[128]; 1267 char *slash; 1268 dns_sortaddr_t sortaddr; 1269 1270 str = CFArrayGetValueAtIndex(list, i); 1271 if (!isA_CFString(str)) { 1272 continue; 1273 } 1274 1275 if (_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) { 1276 continue; 1277 } 1278 1279 slash = strchr(buf, '/'); 1280 if (slash != NULL) { 1281 *slash = '\0'; 1282 } 1283 1284 bzero(&sortaddr, sizeof(sortaddr)); 1285 if (inet_aton(buf, &sortaddr.address) != 1) { 1286 /* if address not valid */ 1287 continue; 1288 } 1289 1290 if (slash != NULL) { 1291 if (inet_aton(slash + 1, &sortaddr.mask) != 1) { 1292 /* if subnet mask not valid */ 1293 continue; 1294 } 1295 } else { 1296 in_addr_t a; 1297 in_addr_t m; 1298 1299 a = ntohl(sortaddr.address.s_addr); 1300 if (IN_CLASSA(a)) { 1301 m = IN_CLASSA_NET; 1302 } else if (IN_CLASSB(a)) { 1303 m = IN_CLASSB_NET; 1304 } else if (IN_CLASSC(a)) { 1305 m = IN_CLASSC_NET; 1306 } else { 1307 continue; 1308 } 1309 1310 sortaddr.mask.s_addr = htonl(m); 1311 } 1312 1313 _dns_resolver_add_sortaddr(&_resolver, &sortaddr); 1314 } 1315 } 1316 1317 // process port 1318 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerPort); 1319 if (isA_CFNumber(num)) { 1320 int port; 1321 1322 if (CFNumberGetValue(num, kCFNumberIntType, &port)) { 1323 _dns_resolver_set_port(&_resolver, (uint16_t)port); 1324 } 1325 } 1326 1327 // process timeout 1328 num = CFDictionaryGetValue(dns, kSCPropNetDNSServerTimeout); 1329 if (isA_CFNumber(num)) { 1330 int timeout; 1331 1332 if (CFNumberGetValue(num, kCFNumberIntType, &timeout)) { 1333 _dns_resolver_set_timeout(&_resolver, (uint32_t)timeout); 1334 } 1335 } 1336 1337 // process options 1338 str = CFDictionaryGetValue(dns, kSCPropNetDNSOptions); 1339 if (isA_CFString(str)) { 1340 char *options; 1341 1342 options = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8); 1343 if (options != NULL) { 1344 _dns_resolver_set_options(&_resolver, options); 1345 CFAllocatorDeallocate(NULL, options); 1346 } 1347 } 1348 1349 num = CFDictionaryGetValue(dns, kSCPropNetDNSServiceIdentifier); 1350 if (isA_CFNumber(num)) { 1351 int service_identifier; 1352 1353 if (CFNumberGetValue(num, kCFNumberIntType, &service_identifier)) { 1354 _dns_resolver_set_service_identifier(&_resolver, (uint32_t)service_identifier); 1355 } 1356 } 1357 1358 if (targetInterface != NULL) { 1359 CFRelease(targetInterface); 1360 } 1361 1362 return _resolver; 1363} 1364 1365 1366static __inline__ Boolean 1367isScopedConfiguration(CFDictionaryRef dns) 1368{ 1369 uint32_t flags; 1370 CFNumberRef num; 1371 1372 if ((dns != NULL) && 1373 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) && 1374 (num != NULL) && 1375 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) && 1376 ((flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)) { 1377 return TRUE; 1378 } 1379 1380 return FALSE; 1381} 1382 1383 1384static __inline__ Boolean 1385isServiceSpecificConfiguration(CFDictionaryRef dns) 1386{ 1387 uint32_t flags; 1388 CFNumberRef num; 1389 1390 if (dns != NULL && 1391 CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) && 1392 num != NULL && 1393 CFNumberGetValue(num, kCFNumberSInt32Type, &flags) && 1394 (flags & DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC)) 1395 { 1396 return TRUE; 1397 } 1398 1399 return FALSE; 1400} 1401 1402 1403static CFComparisonResult 1404compareDomain(const void *val1, const void *val2, void *context) 1405{ 1406 CFDictionaryRef dns1 = (CFDictionaryRef)val1; 1407 CFDictionaryRef dns2 = (CFDictionaryRef)val2; 1408 CFStringRef domain1; 1409 CFStringRef domain2; 1410 CFArrayRef labels1 = NULL; 1411 CFArrayRef labels2 = NULL; 1412 CFIndex n1; 1413 CFIndex n2; 1414 CFComparisonResult result; 1415 Boolean rev1; 1416 Boolean rev2; 1417 Boolean scoped1; 1418 Boolean scoped2; 1419 1420 // "default" domains sort before "supplemental" domains 1421 domain1 = CFDictionaryGetValue(dns1, kSCPropNetDNSDomainName); 1422 domain2 = CFDictionaryGetValue(dns2, kSCPropNetDNSDomainName); 1423 if (domain1 == NULL) { 1424 return kCFCompareLessThan; 1425 } else if (domain2 == NULL) { 1426 return kCFCompareGreaterThan; 1427 } 1428 1429 // sort non-scoped before scoped 1430 scoped1 = isScopedConfiguration(dns1); 1431 scoped2 = isScopedConfiguration(dns2); 1432 if (scoped1 != scoped2) { 1433 if (!scoped1) { 1434 return kCFCompareLessThan; 1435 } else { 1436 return kCFCompareGreaterThan; 1437 } 1438 } 1439 1440 // must have domain names for any further comparisons 1441 if ((domain1 == NULL) || (domain2 == NULL)) { 1442 return kCFCompareEqualTo; 1443 } 1444 1445 // forward (A, AAAA) domains sort before reverse (PTR) domains 1446 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa")); 1447 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa")); 1448 if (rev1 != rev2) { 1449 if (rev1) { 1450 return kCFCompareGreaterThan; 1451 } else { 1452 return kCFCompareLessThan; 1453 } 1454 } 1455 1456 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR(".")); 1457 n1 = CFArrayGetCount(labels1); 1458 1459 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR(".")); 1460 n2 = CFArrayGetCount(labels2); 1461 1462 while ((n1 > 0) && (n2 > 0)) { 1463 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1); 1464 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2); 1465 1466 // compare domain labels 1467 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive); 1468 if (result != kCFCompareEqualTo) { 1469 goto done; 1470 } 1471 } 1472 1473 // longer labels (corp.apple.com) sort before shorter labels (apple.com) 1474 if (n1 > n2) { 1475 result = kCFCompareLessThan; 1476 goto done; 1477 } else if (n1 < n2) { 1478 result = kCFCompareGreaterThan; 1479 goto done; 1480 } 1481 1482 // sort by search order 1483 result = compareBySearchOrder(val1, val2, context); 1484 1485 done : 1486 1487 if (labels1 != NULL) CFRelease(labels1); 1488 if (labels2 != NULL) CFRelease(labels2); 1489 return result; 1490} 1491 1492 1493__private_extern__ 1494Boolean 1495dns_configuration_set(CFDictionaryRef defaultResolver, 1496 CFDictionaryRef services, 1497 CFArrayRef serviceOrder, 1498 CFArrayRef multicastResolvers, 1499 CFArrayRef privateResolvers) 1500{ 1501 dns_create_config_t _config; 1502 Boolean changed = FALSE; 1503 uint32_t dns_resolver_flags = 0; 1504 CFIndex i; 1505 CFMutableDictionaryRef myDefault; 1506 Boolean myOrderAdded = FALSE; 1507 CFArrayRef mySearchDomains = NULL; 1508 CFIndex n_resolvers; 1509 CFMutableArrayRef resolvers; 1510 unsigned char signature[CC_SHA1_DIGEST_LENGTH]; 1511 static unsigned char signature_last[CC_SHA1_DIGEST_LENGTH]; 1512 1513 // establish list of resolvers 1514 1515 resolvers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1516 assert(resolvers != NULL); 1517 1518 // collect (and add) any "supplemental" resolver configurations 1519 1520 add_supplemental_resolvers(resolvers, services, serviceOrder, NULL, NULL); 1521 1522 // collect (and add) any "private" resolver configurations 1523 1524 add_private_resolvers(resolvers, privateResolvers); 1525 1526 // add the "default" resolver 1527 1528 add_default_resolver(resolvers, defaultResolver, &myOrderAdded, &mySearchDomains); 1529 1530 // collect (and add) any "multicast" resolver configurations 1531 1532 add_multicast_resolvers(resolvers, multicastResolvers); 1533 1534 // collect (and add) any "scoped" resolver configurations 1535 1536 add_scoped_resolvers(resolvers, services, serviceOrder); 1537 1538 // collect (and add) any "service-specific" resolver configurations 1539 1540 add_service_specific_resolvers(resolvers, services); 1541 1542 // sort resolvers 1543 1544 n_resolvers = CFArrayGetCount(resolvers); 1545 if (n_resolvers > 1) { 1546 CFArraySortValues(resolvers, CFRangeMake(0, n_resolvers), compareDomain, NULL); 1547 } 1548 1549 // cleanup 1550 1551 for (i = n_resolvers; --i > 0; ) { 1552 CFDictionaryRef resolver; 1553 1554 resolver = CFArrayGetValueAtIndex(resolvers, i); 1555 if (!CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) && 1556 !CFDictionaryContainsKey(resolver, kSCPropNetDNSSearchDomains) && 1557 !CFDictionaryContainsKey(resolver, kSCPropNetDNSServerAddresses)) { 1558 // remove empty resolver 1559 CFArrayRemoveValueAtIndex(resolvers, i); 1560 n_resolvers--; 1561 } 1562 } 1563 1564 // update the default resolver 1565 1566 myDefault = CFDictionaryCreateMutableCopy(NULL, 1567 0, 1568 CFArrayGetValueAtIndex(resolvers, 0)); 1569 if (mySearchDomains != NULL) { 1570 // add search domains to the default resolver 1571 CFDictionarySetValue(myDefault, kSCPropNetDNSSearchDomains, mySearchDomains); 1572 CFRelease(mySearchDomains); 1573 } 1574 if (myOrderAdded && (n_resolvers > 1)) { 1575 CFDictionaryRef resolver; 1576 1577 resolver = CFArrayGetValueAtIndex(resolvers, 1); 1578 if (CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) || 1579 isScopedConfiguration(resolver)) { 1580 // if not a supplemental "default" resolver (a domain name is 1581 // present) or if it's a scoped configuration 1582 CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder); 1583 } 1584 } 1585 CFArraySetValueAtIndex(resolvers, 0, myDefault); 1586 CFRelease(myDefault); 1587 1588 // establish resolver configuration 1589 1590 if ((defaultResolver == NULL) && (n_resolvers <= 1)) { 1591 /* 1592 * if no default and no supplemental/scoped resolvers 1593 */ 1594 _config = NULL; 1595 } else { 1596 /* 1597 * if default and/or supplemental/scoped resolvers are defined 1598 */ 1599 _config = _dns_configuration_create(); 1600 1601 CFDictionaryApplyFunction(services, add_dns_query_flags , &dns_resolver_flags); 1602 1603 for (i = 0; i < n_resolvers; i++) { 1604 boolean_t is_default_resolver; 1605 CFDictionaryRef resolver; 1606 dns_create_resolver_t _resolver; 1607 1608 resolver = CFArrayGetValueAtIndex(resolvers, i); 1609 1610 is_default_resolver = (!isScopedConfiguration(resolver) && !isServiceSpecificConfiguration(resolver)); 1611 if (is_default_resolver) { 1612 CFMutableDictionaryRef new_resolver; 1613 CFNumberRef num; 1614 1615 new_resolver = CFDictionaryCreateMutableCopy(NULL, 0, resolver); 1616 1617 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &dns_resolver_flags); 1618 CFDictionarySetValue(new_resolver, DNS_CONFIGURATION_FLAGS_KEY, num); 1619 CFRelease(num); 1620 1621 resolver = new_resolver; 1622 } 1623 1624 _resolver = create_resolver(resolver); 1625 _dns_configuration_add_resolver(&_config, _resolver); 1626 _dns_resolver_free(&_resolver); 1627 1628 if (is_default_resolver) { 1629 CFRelease(resolver); 1630 } 1631 } 1632 1633#if !TARGET_OS_IPHONE 1634 // add flatfile resolvers 1635 1636 _dnsinfo_flatfile_set_flags(dns_resolver_flags); 1637 _dnsinfo_flatfile_add_resolvers(&_config); 1638#endif // !TARGET_OS_IPHONE 1639 } 1640 1641#ifdef DNS_CONFIGURATION_DEBUG 1642 { 1643 uint8_t *buf; 1644 dns_config_t *config; 1645 _dns_config_buf_t *config_buf; 1646 uint32_t n_config; 1647 uint32_t n_padding; 1648 1649 config_buf = (_dns_config_buf_t *)_config; 1650 n_config = sizeof(_dns_config_buf_t) + ntohl(config_buf->n_attribute); 1651 n_padding = ntohl(config_buf->n_padding); 1652 buf = malloc(n_config + n_padding); 1653 bcopy((void *)config_buf, buf, n_config); 1654 bzero(&buf[n_config], n_padding); 1655 config = expand_config((_dns_config_buf_t *)buf); 1656 _dns_configuration_print(config); 1657 free(buf); 1658 } 1659#endif // DNS_CONFIGURATION_DEBUG 1660 1661 // check if the configuration changed 1662 _dns_configuration_signature(&_config, signature, sizeof(signature)); 1663 if (bcmp(signature, signature_last, sizeof(signature)) != 0) { 1664 // save [new] signature 1665 bcopy(signature, signature_last, sizeof(signature)); 1666 1667 // save [new] configuration 1668 if (!_dns_configuration_store(&_config)) { 1669 my_log(LOG_ERR, "dns_configuration_set: could not store configuration"); 1670 } 1671 1672 changed = TRUE; 1673 } 1674 1675 if (_config != NULL) _dns_configuration_free(&_config); 1676 1677 CFRelease(resolvers); 1678 return changed; 1679} 1680 1681 1682#if !TARGET_OS_IPHONE 1683static SCDynamicStoreRef dns_configuration_store; 1684static SCDynamicStoreCallBack dns_configuration_callout; 1685 1686static void 1687dns_configuration_changed(CFMachPortRef port, void *msg, CFIndex size, void *info) 1688{ 1689 CFStringRef key = CFSTR(_PATH_RESOLVER_DIR); 1690 CFArrayRef keys; 1691 Boolean resolvers_now; 1692 static Boolean resolvers_save = FALSE; 1693 struct stat statbuf; 1694 1695 resolvers_now = (stat(_PATH_RESOLVER_DIR, &statbuf) == 0); 1696 if (!resolvers_save && (resolvers_save == resolvers_now)) { 1697 // if we did not (and still do not) have an "/etc/resolvers" 1698 // directory than this notification is the result of a change 1699 // to the "/etc" directory. 1700 return; 1701 } 1702 resolvers_save = resolvers_now; 1703 1704 my_log(LOG_DEBUG, _PATH_RESOLVER_DIR " changed"); 1705 1706 // fake a "DNS" change 1707 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks); 1708 (*dns_configuration_callout)(dns_configuration_store, keys, NULL); 1709 CFRelease(keys); 1710 return; 1711} 1712 1713 1714__private_extern__ 1715void 1716dns_configuration_monitor(SCDynamicStoreRef store, SCDynamicStoreCallBack callout) 1717{ 1718 CFMachPortRef mp; 1719 mach_port_t notify_port; 1720 int notify_token; 1721 CFRunLoopSourceRef rls; 1722 uint32_t status; 1723 1724 dns_configuration_store = store; 1725 dns_configuration_callout = callout; 1726 1727 status = notify_register_mach_port(_PATH_RESOLVER_DIR, ¬ify_port, 0, ¬ify_token); 1728 if (status != NOTIFY_STATUS_OK) { 1729 my_log(LOG_ERR, "notify_register_mach_port() failed"); 1730 return; 1731 } 1732 1733 status = notify_monitor_file(notify_token, "/private" _PATH_RESOLVER_DIR, 0); 1734 if (status != NOTIFY_STATUS_OK) { 1735 my_log(LOG_ERR, "notify_monitor_file() failed"); 1736 (void)notify_cancel(notify_token); 1737 return; 1738 } 1739 1740 mp = _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration", 1741 notify_port, 1742 dns_configuration_changed, 1743 NULL); 1744 1745 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1); 1746 if (rls == NULL) { 1747 my_log(LOG_ERR, "SCDynamicStoreCreateRunLoopSource() failed"); 1748 CFRelease(mp); 1749 (void)notify_cancel(notify_token); 1750 return; 1751 } 1752 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 1753 CFRelease(rls); 1754 1755 CFRelease(mp); 1756 return; 1757} 1758#endif // !TARGET_OS_IPHONE 1759 1760 1761__private_extern__ 1762void 1763dns_configuration_init(CFBundleRef bundle) 1764{ 1765 CFDictionaryRef dict; 1766 1767 dict = CFBundleGetInfoDictionary(bundle); 1768 if (isA_CFDictionary(dict)) { 1769 S_mdns_timeout = CFDictionaryGetValue(dict, CFSTR("mdns_timeout")); 1770 S_mdns_timeout = isA_CFNumber(S_mdns_timeout); 1771 1772 S_pdns_timeout = CFDictionaryGetValue(dict, CFSTR("pdns_timeout")); 1773 S_pdns_timeout = isA_CFNumber(S_pdns_timeout); 1774 } 1775 1776 return; 1777} 1778 1779 1780#pragma mark - 1781#pragma mark Standalone test code 1782 1783 1784#ifdef MAIN 1785 1786static void 1787split(const void * key, const void * value, void * context) 1788{ 1789 CFArrayRef components; 1790 CFStringRef entity_id; 1791 CFStringRef service_id; 1792 CFMutableDictionaryRef state_dict; 1793 1794 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/")); 1795 service_id = CFArrayGetValueAtIndex(components, 3); 1796 entity_id = CFArrayGetValueAtIndex(components, 4); 1797 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id); 1798 if (state_dict != NULL) { 1799 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict); 1800 } else { 1801 state_dict = CFDictionaryCreateMutable(NULL, 1802 0, 1803 &kCFTypeDictionaryKeyCallBacks, 1804 &kCFTypeDictionaryValueCallBacks); 1805 } 1806 1807 if (CFEqual(entity_id, kSCEntNetIPv4) || 1808 CFEqual(entity_id, kSCEntNetIPv6)) { 1809 CFStringRef interface; 1810 1811 if (CFEqual(entity_id, kSCEntNetIPv4)) { 1812 CFMutableDictionaryRef ipv4_dict; 1813 1814 ipv4_dict = CFDictionaryCreateMutable(NULL, 1815 0, 1816 &kCFTypeDictionaryKeyCallBacks, 1817 &kCFTypeDictionaryValueCallBacks); 1818 CFDictionarySetValue(ipv4_dict, kIPv4DictService, (CFDictionaryRef)value); 1819 CFDictionarySetValue(state_dict, entity_id, ipv4_dict); 1820 CFRelease(ipv4_dict); 1821 } else { 1822 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value); 1823 } 1824 1825 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName); 1826 if (interface != NULL) { 1827 CFDictionaryRef dns; 1828 CFMutableDictionaryRef new_dns; 1829 1830 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS); 1831 if (dns != NULL) { 1832 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, dns); 1833 } else { 1834 new_dns = CFDictionaryCreateMutable(NULL, 1835 0, 1836 &kCFTypeDictionaryKeyCallBacks, 1837 &kCFTypeDictionaryValueCallBacks); 1838 } 1839 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface); 1840 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns); 1841 CFRelease(new_dns); 1842 } 1843 } else if (CFEqual(entity_id, kSCEntNetDNS)) { 1844 CFDictionaryRef dns; 1845 1846 dns = CFDictionaryGetValue(state_dict, kSCEntNetDNS); 1847 if (dns != NULL) { 1848 CFStringRef interface; 1849 1850 interface = CFDictionaryGetValue(dns, kSCPropInterfaceName); 1851 if (interface != NULL) { 1852 CFMutableDictionaryRef new_dns; 1853 1854 new_dns = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value); 1855 CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface); 1856 CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns); 1857 CFRelease(new_dns); 1858 } else { 1859 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value); 1860 } 1861 } else { 1862 CFDictionarySetValue(state_dict, kSCEntNetDNS, (CFDictionaryRef)value); 1863 } 1864 } else { 1865 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value); 1866 } 1867 1868 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict); 1869 CFRelease(state_dict); 1870 CFRelease(components); 1871 1872 return; 1873} 1874 1875int 1876main(int argc, char **argv) 1877{ 1878 CFDictionaryRef entities; 1879 CFStringRef key; 1880 CFArrayRef multicast_resolvers; 1881 CFStringRef pattern; 1882 CFMutableArrayRef patterns; 1883 CFStringRef primary = NULL; 1884 CFDictionaryRef primaryDNS = NULL; 1885 CFArrayRef private_resolvers; 1886 CFArrayRef service_order = NULL; 1887 CFMutableDictionaryRef service_state_dict; 1888 CFDictionaryRef setup_global_ipv4; 1889 CFDictionaryRef state_global_ipv4; 1890 SCDynamicStoreRef store; 1891 1892 _sc_log = FALSE; 1893 _sc_verbose = (argc > 1) ? TRUE : FALSE; 1894 1895 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL); 1896 1897 // get IPv4, IPv6, and DNS entities 1898 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1899 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 1900 kSCDynamicStoreDomainState, 1901 kSCCompAnyRegex, 1902 kSCEntNetIPv4); 1903 CFArrayAppendValue(patterns, pattern); 1904 CFRelease(pattern); 1905 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 1906 kSCDynamicStoreDomainState, 1907 kSCCompAnyRegex, 1908 kSCEntNetIPv6); 1909 CFArrayAppendValue(patterns, pattern); 1910 CFRelease(pattern); 1911 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 1912 kSCDynamicStoreDomainState, 1913 kSCCompAnyRegex, 1914 kSCEntNetDNS); 1915 CFArrayAppendValue(patterns, pattern); 1916 CFRelease(pattern); 1917 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns); 1918 CFRelease(patterns); 1919 1920 service_state_dict = CFDictionaryCreateMutable(NULL, 1921 0, 1922 &kCFTypeDictionaryKeyCallBacks, 1923 &kCFTypeDictionaryValueCallBacks); 1924 CFDictionaryApplyFunction(entities, split, service_state_dict); 1925 CFRelease(entities); 1926 1927 // get primary service ID 1928 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 1929 kSCDynamicStoreDomainState, 1930 kSCEntNetIPv4); 1931 state_global_ipv4 = SCDynamicStoreCopyValue(store, key); 1932 CFRelease(key); 1933 if (state_global_ipv4 != NULL) { 1934 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService); 1935 if (primary != NULL) { 1936 CFDictionaryRef service_dict; 1937 1938 // get DNS configuration for primary service 1939 service_dict = CFDictionaryGetValue(service_state_dict, primary); 1940 if (service_dict != NULL) { 1941 primaryDNS = CFDictionaryGetValue(service_dict, kSCEntNetDNS); 1942 } 1943 } 1944 } 1945 1946 // get serviceOrder 1947 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 1948 kSCDynamicStoreDomainSetup, 1949 kSCEntNetIPv4); 1950 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key); 1951 CFRelease(key); 1952 if (setup_global_ipv4 != NULL) { 1953 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder); 1954 } 1955 1956 // get multicast resolvers 1957 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"), 1958 kSCDynamicStoreDomainState, 1959 kSCCompNetwork, 1960 CFSTR(kDNSServiceCompMulticastDNS)); 1961 multicast_resolvers = SCDynamicStoreCopyValue(store, key); 1962 CFRelease(key); 1963 1964 // get private resolvers 1965 key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"), 1966 kSCDynamicStoreDomainState, 1967 kSCCompNetwork, 1968 CFSTR(kDNSServiceCompPrivateDNS)); 1969 private_resolvers = SCDynamicStoreCopyValue(store, key); 1970 CFRelease(key); 1971 1972 // update DNS configuration 1973 dns_configuration_init(CFBundleGetMainBundle()); 1974 (void)dns_configuration_set(primaryDNS, 1975 service_state_dict, 1976 service_order, 1977 multicast_resolvers, 1978 private_resolvers); 1979 1980 // cleanup 1981 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4); 1982 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4); 1983 if (multicast_resolvers != NULL) CFRelease(multicast_resolvers); 1984 if (private_resolvers != NULL) CFRelease(private_resolvers); 1985 CFRelease(service_state_dict); 1986 CFRelease(store); 1987 1988 /* not reached */ 1989 exit(0); 1990 return 0; 1991} 1992#endif 1993 1994