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