1/* 2 * Copyright (c) 2011-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 * January 3, 2011 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31#include <TargetConditionals.h> 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <net/if.h> 35 36#include <CoreFoundation/CoreFoundation.h> 37#include <SystemConfiguration/SystemConfiguration.h> 38#include <SystemConfiguration/SCPrivate.h> 39#include <SystemConfiguration/SCValidation.h> 40#include "ip_plugin.h" 41 42 43#define DEFAULT_MATCH_ORDER 200000 /* match order for the "default" proxy configuration */ 44 45 46#define PROXY_MATCH_ORDER_KEY CFSTR("__MATCH_ORDER__") 47#define ORDER_KEY CFSTR("__ORDER__") 48 49 50CFBooleanRef G_supplemental_proxies_follow_dns = NULL; 51 52 53static void 54add_proxy(CFMutableArrayRef proxies, CFMutableDictionaryRef proxy) 55{ 56 CFIndex i; 57 CFIndex n_proxies; 58 CFNumberRef order; 59 60 n_proxies = CFArrayGetCount(proxies); 61 for (i = 0; i < n_proxies; i++) { 62 CFDictionaryRef match_proxy; 63 64 match_proxy = CFArrayGetValueAtIndex(proxies, i); 65 if (CFEqual(proxy, match_proxy)) { 66 // a real duplicate 67 return; 68 } 69 } 70 71 order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_proxies); 72 CFDictionarySetValue(proxy, ORDER_KEY, order); 73 CFRelease(order); 74 75 CFArrayAppendValue(proxies, proxy); 76 return; 77} 78 79 80static void 81add_supplemental(CFMutableArrayRef proxies, CFDictionaryRef proxy, uint32_t defaultOrder) 82{ 83 CFArrayRef domains; 84 CFIndex i; 85 CFIndex n_domains; 86 CFArrayRef orders; 87 88 domains = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchDomains); 89 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0; 90 if (n_domains == 0) { 91 return; 92 } 93 94 orders = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchOrders); 95 if (orders != NULL) { 96 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) { 97 return; 98 } 99 } 100 101 /* 102 * yes, this is a "supplemental" proxy configuration, expand 103 * the match domains and add each to the proxies list. 104 */ 105 for (i = 0; i < n_domains; i++) { 106 CFStringRef match_domain; 107 CFNumberRef match_order; 108 CFMutableDictionaryRef match_proxy; 109 110 match_domain = CFArrayGetValueAtIndex(domains, i); 111 if (!isA_CFString(match_domain)) { 112 continue; 113 } 114 115 match_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 116 117 // set supplemental proxy match "domain" 118 match_domain = _SC_trimDomain(match_domain); 119 if (match_domain != NULL) { 120 CFDictionarySetValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomain, match_domain); 121 CFRelease(match_domain); 122 } else { 123 CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomain); 124 } 125 126 // set supplemental proxy match "order" 127 match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL; 128 if (isA_CFNumber(match_order)) { 129 CFDictionarySetValue(match_proxy, PROXY_MATCH_ORDER_KEY, match_order); 130 } else { 131 CFNumberRef num; 132 133 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder); 134 CFDictionarySetValue(match_proxy, PROXY_MATCH_ORDER_KEY, num); 135 CFRelease(num); 136 137 defaultOrder++; // if multiple domains, maintain ordering 138 } 139 140 // remove keys we don't want in a supplemental proxy 141 CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomains); 142 CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchOrders); 143 CFDictionaryRemoveValue(match_proxy, kSCPropInterfaceName); 144 145 add_proxy(proxies, match_proxy); 146 CFRelease(match_proxy); 147 } 148 149 return; 150} 151 152 153#define N_QUICK 32 154 155 156static void 157add_supplemental_proxies(CFMutableArrayRef proxies, CFDictionaryRef services, CFArrayRef service_order) 158{ 159 const void * keys_q[N_QUICK]; 160 const void ** keys = keys_q; 161 CFIndex i; 162 CFIndex n_order; 163 CFIndex n_services; 164 const void * vals_q[N_QUICK]; 165 const void ** vals = vals_q; 166 167 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0; 168 if (n_services == 0) { 169 return; // if no services 170 } 171 172 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 173 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0); 174 vals = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0); 175 } 176 177 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0; 178 179 CFDictionaryGetKeysAndValues(services, keys, vals); 180 for (i = 0; i < n_services; i++) { 181 uint32_t defaultOrder; 182 CFDictionaryRef proxy; 183 CFMutableDictionaryRef proxyWithDNS = NULL; 184 CFDictionaryRef service = (CFDictionaryRef)vals[i]; 185 186 if (!isA_CFDictionary(service)) { 187 continue; 188 } 189 190 proxy = CFDictionaryGetValue(service, kSCEntNetProxies); 191 if (!isA_CFDictionary(proxy)) { 192 continue; 193 } 194 195 if ((G_supplemental_proxies_follow_dns != NULL) && CFBooleanGetValue(G_supplemental_proxies_follow_dns)) { 196 CFDictionaryRef dns; 197 CFArrayRef matchDomains; 198 CFArrayRef matchOrders; 199 200 if (!CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomains) && 201 CFDictionaryGetValueIfPresent(service, kSCEntNetDNS, (const void **)&dns) && 202 isA_CFDictionary(dns) && 203 CFDictionaryGetValueIfPresent(dns, kSCPropNetDNSSupplementalMatchDomains, (const void **)&matchDomains) && 204 isA_CFArray(matchDomains)) { 205 proxyWithDNS = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 206 CFDictionarySetValue(proxyWithDNS, kSCPropNetProxiesSupplementalMatchDomains, matchDomains); 207 if (CFDictionaryGetValueIfPresent(dns, kSCPropNetDNSSupplementalMatchOrders, (const void **)&matchOrders) && 208 isA_CFArray(matchOrders)) { 209 CFDictionarySetValue(proxyWithDNS, kSCPropNetProxiesSupplementalMatchOrders, matchOrders); 210 } else { 211 CFDictionaryRemoveValue(proxyWithDNS, kSCPropNetProxiesSupplementalMatchOrders); 212 } 213 proxy = proxyWithDNS; 214 } 215 } 216 217 defaultOrder = DEFAULT_MATCH_ORDER 218 - (DEFAULT_MATCH_ORDER / 2) 219 + ((DEFAULT_MATCH_ORDER / 1000) * (uint32_t)i); 220 if ((n_order > 0) && 221 !CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) { 222 // push out services not specified in service order 223 defaultOrder += (DEFAULT_MATCH_ORDER / 1000) * n_services; 224 } 225 226 add_supplemental(proxies, proxy, defaultOrder); 227 if (proxyWithDNS != NULL) CFRelease(proxyWithDNS); 228 } 229 230 if (keys != keys_q) { 231 CFAllocatorDeallocate(NULL, keys); 232 CFAllocatorDeallocate(NULL, vals); 233 } 234 235 return; 236} 237 238 239static CFComparisonResult 240compareBySearchOrder(const void *val1, const void *val2, void *context) 241{ 242 CFDictionaryRef proxy1 = (CFDictionaryRef)val1; 243 CFDictionaryRef proxy2 = (CFDictionaryRef)val2; 244 CFNumberRef num1; 245 CFNumberRef num2; 246 uint32_t order1 = DEFAULT_MATCH_ORDER; 247 uint32_t order2 = DEFAULT_MATCH_ORDER; 248 249 num1 = CFDictionaryGetValue(proxy1, PROXY_MATCH_ORDER_KEY); 250 if (!isA_CFNumber(num1) || 251 !CFNumberGetValue(num1, kCFNumberIntType, &order1)) { 252 order1 = DEFAULT_MATCH_ORDER; 253 } 254 255 num2 = CFDictionaryGetValue(proxy2, PROXY_MATCH_ORDER_KEY); 256 if (!isA_CFNumber(num2) || 257 !CFNumberGetValue(num2, kCFNumberIntType, &order2)) { 258 order2 = DEFAULT_MATCH_ORDER; 259 } 260 261 if (order1 == order2) { 262 // if same match "order", retain original ordering for configurations 263 if (CFDictionaryGetValueIfPresent(proxy1, ORDER_KEY, (const void **)&num1) && 264 CFDictionaryGetValueIfPresent(proxy2, ORDER_KEY, (const void **)&num2) && 265 isA_CFNumber(num1) && 266 isA_CFNumber(num2) && 267 CFNumberGetValue(num1, kCFNumberIntType, &order1) && 268 CFNumberGetValue(num2, kCFNumberIntType, &order2)) { 269 if (order1 == order2) { 270 return kCFCompareEqualTo; 271 } else { 272 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; 273 } 274 } 275 276 return kCFCompareEqualTo; 277 } 278 279 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; 280} 281 282 283static __inline__ Boolean 284isSupplementalProxy(CFDictionaryRef proxy) 285{ 286 if ((proxy != NULL) && 287 CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 288 return TRUE; 289 } 290 291 return FALSE; 292} 293 294 295static CFArrayRef 296copy_supplemental_proxies(CFArrayRef proxies, Boolean skip) 297{ 298 CFIndex i; 299 CFIndex n_proxies; 300 CFMutableArrayRef supplemental = NULL; 301 302 // iterate over services 303 304 n_proxies = isA_CFArray(proxies) ? CFArrayGetCount(proxies) : 0; 305 for (i = 0; i < n_proxies; i++) { 306 CFDictionaryRef proxy; 307 308 proxy = CFArrayGetValueAtIndex(proxies, i); 309 if (!isSupplementalProxy(proxy)) { 310 // if not supplemental proxy (i.e. no match domain) 311 continue; 312 } 313 314 // add [supplemental] proxy entry 315 if (supplemental == NULL) { 316 supplemental = CFArrayCreateMutable(NULL, 317 0, 318 &kCFTypeArrayCallBacks); 319 } 320 CFArrayAppendValue(supplemental, proxy); 321 } 322 323 return supplemental; 324} 325 326 327static CFArrayRef 328service_order_copy_all(CFDictionaryRef services, CFArrayRef service_order) 329{ 330 const void * keys_q[N_QUICK]; 331 const void ** keys = keys_q; 332 CFIndex i; 333 CFIndex n_order; 334 CFIndex n_services; 335 CFMutableArrayRef order; 336 337 // ensure that we process all services in order 338 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0; 339 if (n_services == 0) { 340 // if no services 341 return NULL; 342 } 343 344 // ensure that we process all services in order 345 346 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0; 347 if (n_order > 0) { 348 order = CFArrayCreateMutableCopy(NULL, 0, service_order); 349 } else { 350 order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 351 } 352 353 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 354 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0); 355 } 356 CFDictionaryGetKeysAndValues(services, keys, NULL); 357 for (i = 0; i < n_services; i++) { 358 CFStringRef serviceID = (CFStringRef)keys[i]; 359 360 if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) { 361 CFArrayAppendValue(order, serviceID); 362 n_order++; 363 } 364 } 365 if (keys != keys_q) { 366 CFAllocatorDeallocate(NULL, keys); 367 } 368 369 return order; 370} 371 372 373static CFDictionaryRef 374copy_app_layer_vpn_proxies(CFDictionaryRef services, CFArrayRef order, CFDictionaryRef services_info) 375{ 376 CFMutableDictionaryRef app_layer_proxies = NULL; 377 CFIndex i; 378 CFIndex n_order; 379 380 if (!isA_CFDictionary(services_info)) { 381 return NULL; 382 } 383 384 // iterate over services 385 386 n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0; 387 for (i = 0; i < n_order; i++) { 388 CFMutableDictionaryRef newProxy; 389 CFDictionaryRef proxy; 390 CFDictionaryRef service; 391 CFStringRef serviceID; 392 CFDictionaryRef vpn; 393 CFStringRef vpn_key; 394 395 serviceID = CFArrayGetValueAtIndex(order, i); 396 service = CFDictionaryGetValue(services, serviceID); 397 if (!isA_CFDictionary(service)) { 398 // if no service 399 continue; 400 } 401 402 proxy = CFDictionaryGetValue(service, kSCEntNetProxies); 403 if (!isA_CFDictionary(proxy)) { 404 // if no proxy 405 continue; 406 } 407 408 vpn_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 409 kSCDynamicStoreDomainSetup, 410 serviceID, 411 kSCEntNetVPN); 412 vpn = CFDictionaryGetValue(services_info, vpn_key); 413 CFRelease(vpn_key); 414 415 if (!isA_CFDictionary(vpn) || !CFDictionaryContainsKey(vpn, kSCPropNetVPNAppRules)) { 416 // if not App Layer vpn 417 continue; 418 } 419 420 if ((app_layer_proxies != NULL) && 421 CFDictionaryContainsKey(app_layer_proxies, serviceID)) { 422 // if we've already processed this [app_layer_proxies] interface 423 continue; 424 } 425 426 // add [app_layer_proxies] proxy entry 427 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 428 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains); 429 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders); 430 if (app_layer_proxies == NULL) { 431 app_layer_proxies = CFDictionaryCreateMutable(NULL, 432 0, 433 &kCFTypeDictionaryKeyCallBacks, 434 &kCFTypeDictionaryValueCallBacks); 435 } 436 CFDictionarySetValue(app_layer_proxies, serviceID, newProxy); 437 CFRelease(newProxy); 438 } 439 440 return app_layer_proxies; 441} 442 443 444static CFDictionaryRef 445copy_scoped_proxies(CFDictionaryRef services, CFArrayRef order) 446{ 447 CFIndex i; 448 CFIndex n_order; 449 CFMutableDictionaryRef scoped = NULL; 450 451 // iterate over services 452 453 n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0; 454 for (i = 0; i < n_order; i++) { 455 char if_name[IF_NAMESIZE]; 456 CFStringRef interface; 457 CFMutableDictionaryRef newProxy; 458 CFDictionaryRef proxy; 459 CFDictionaryRef service; 460 CFStringRef serviceID; 461 462 serviceID = CFArrayGetValueAtIndex(order, i); 463 service = CFDictionaryGetValue(services, serviceID); 464 if (!isA_CFDictionary(service)) { 465 // if no service 466 continue; 467 } 468 469 proxy = CFDictionaryGetValue(service, kSCEntNetProxies); 470 if (!isA_CFDictionary(proxy)) { 471 // if no proxy 472 continue; 473 } 474 475 interface = CFDictionaryGetValue(proxy, kSCPropInterfaceName); 476 if (interface == NULL) { 477 // if no [scoped] interface 478 continue; 479 } 480 if ((scoped != NULL) && 481 CFDictionaryContainsKey(scoped, interface)) { 482 // if we've already processed this [scoped] interface 483 continue; 484 } 485 486 if ((_SC_cfstring_to_cstring(interface, 487 if_name, 488 sizeof(if_name), 489 kCFStringEncodingASCII) == NULL) || 490 ((my_if_nametoindex(if_name)) == 0)) { 491 // if interface index not available 492 continue; 493 } 494 495 // add [scoped] proxy entry 496 // ... and remove keys we don't want in a [scoped] proxy 497 CFRetain(interface); 498 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 499 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains); 500 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders); 501 CFDictionaryRemoveValue(newProxy, kSCPropInterfaceName); 502 if (scoped == NULL) { 503 scoped = CFDictionaryCreateMutable(NULL, 504 0, 505 &kCFTypeDictionaryKeyCallBacks, 506 &kCFTypeDictionaryValueCallBacks); 507 } 508 CFDictionarySetValue(scoped, interface, newProxy); 509 CFRelease(newProxy); 510 CFRelease(interface); 511 } 512 513 return scoped; 514} 515 516 517static void 518add_default_proxy(CFMutableArrayRef proxies, 519 CFDictionaryRef defaultProxy, 520 Boolean *orderAdded) 521{ 522 CFMutableDictionaryRef myDefault; 523 uint32_t myOrder = DEFAULT_MATCH_ORDER; 524 CFNumberRef order = NULL; 525 526 if (defaultProxy == NULL) { 527 myDefault = CFDictionaryCreateMutable(NULL, 528 0, 529 &kCFTypeDictionaryKeyCallBacks, 530 &kCFTypeDictionaryValueCallBacks); 531 } else { 532 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultProxy); 533 CFDictionaryRemoveValue(myDefault, kSCPropInterfaceName); 534 order = CFDictionaryGetValue(myDefault, PROXY_MATCH_ORDER_KEY); 535 } 536 537 // ensure that the default proxy has a search order 538 539 if (!isA_CFNumber(order) || 540 !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) { 541 myOrder = DEFAULT_MATCH_ORDER; 542 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder); 543 CFDictionarySetValue(myDefault, PROXY_MATCH_ORDER_KEY, order); 544 CFRelease(order); 545 *orderAdded = TRUE; 546 } 547 548 // add the default proxy 549 550 add_proxy(proxies, myDefault); 551 CFRelease(myDefault); 552 return; 553} 554 555 556static CFComparisonResult 557compareDomain(const void *val1, const void *val2, void *context) 558{ 559 CFDictionaryRef proxy1 = (CFDictionaryRef)val1; 560 CFDictionaryRef proxy2 = (CFDictionaryRef)val2; 561 CFStringRef domain1; 562 CFStringRef domain2; 563 CFArrayRef labels1 = NULL; 564 CFArrayRef labels2 = NULL; 565 CFIndex n1; 566 CFIndex n2; 567 CFComparisonResult result; 568 Boolean rev1; 569 Boolean rev2; 570 571 // "default" domains sort before "supplemental" domains 572 domain1 = CFDictionaryGetValue(proxy1, kSCPropNetProxiesSupplementalMatchDomain); 573 domain2 = CFDictionaryGetValue(proxy2, kSCPropNetProxiesSupplementalMatchDomain); 574 if (domain1 == NULL) { 575 if (domain2 == NULL) { 576 return kCFCompareEqualTo; 577 } 578 return kCFCompareLessThan; 579 } else if (domain2 == NULL) { 580 return kCFCompareGreaterThan; 581 } 582 583 // forward (A, AAAA) domains sort before reverse (PTR) domains 584 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa")); 585 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa")); 586 if (rev1 != rev2) { 587 if (rev1) { 588 return kCFCompareGreaterThan; 589 } else { 590 return kCFCompareLessThan; 591 } 592 } 593 594 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR(".")); 595 n1 = CFArrayGetCount(labels1); 596 597 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR(".")); 598 n2 = CFArrayGetCount(labels2); 599 600 while ((n1 > 0) && (n2 > 0)) { 601 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1); 602 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2); 603 604 // compare domain labels 605 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive); 606 if (result != kCFCompareEqualTo) { 607 goto done; 608 } 609 } 610 611 // longer labels (corp.apple.com) sort before shorter labels (apple.com) 612 if (n1 > n2) { 613 result = kCFCompareLessThan; 614 goto done; 615 } else if (n1 < n2) { 616 result = kCFCompareGreaterThan; 617 goto done; 618 } 619 620 // sort by search order 621 result = compareBySearchOrder(val1, val2, context); 622 623 done : 624 625 if (labels1 != NULL) CFRelease(labels1); 626 if (labels2 != NULL) CFRelease(labels2); 627 return result; 628} 629 630 631__private_extern__ 632CF_RETURNS_RETAINED CFDictionaryRef 633proxy_configuration_update(CFDictionaryRef defaultProxy, 634 CFDictionaryRef services, 635 CFArrayRef serviceOrder, 636 CFDictionaryRef servicesInfo) 637{ 638 CFIndex i; 639 CFMutableDictionaryRef myDefault; 640 Boolean myOrderAdded = FALSE; 641 CFMutableDictionaryRef newProxy = NULL; 642 CFIndex n_proxies; 643 CFDictionaryRef proxy; 644 CFMutableArrayRef proxies; 645 646 // establish full list of proxies 647 648 proxies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 649 650 // collect (and add) any "supplemental" proxy configurations 651 652 add_supplemental_proxies(proxies, services, serviceOrder); 653 654 // add the "default" proxy 655 656 add_default_proxy(proxies, defaultProxy, &myOrderAdded); 657 658 // sort proxies, cleanup 659 660 n_proxies = CFArrayGetCount(proxies); 661 if (n_proxies > 1) { 662 CFArraySortValues(proxies, CFRangeMake(0, n_proxies), compareDomain, NULL); 663 } 664 665 // cleanup 666 667 for (i = n_proxies - 1; i >= 0; i--) { 668 proxy = CFArrayGetValueAtIndex(proxies, i); 669 670 if ((i > 0) && 671 !CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 672 // remove non-supplemental proxy 673 CFArrayRemoveValueAtIndex(proxies, i); 674 n_proxies--; 675 continue; 676 } 677 678 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 679 CFDictionaryRemoveValue(newProxy, PROXY_MATCH_ORDER_KEY); 680 CFDictionaryRemoveValue(newProxy, ORDER_KEY); 681 CFArraySetValueAtIndex(proxies, i, newProxy); 682 CFRelease(newProxy); 683 } 684 685 // update the default proxy 686 687 myDefault = CFDictionaryCreateMutableCopy(NULL, 688 0, 689 CFArrayGetValueAtIndex(proxies, 0)); 690 if (myOrderAdded && (n_proxies > 1)) { 691 CFDictionaryRef proxy; 692 693 proxy = CFArrayGetValueAtIndex(proxies, 1); 694 if (CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 695 // if not a supplemental "default" proxy (a match domain name is 696 // present) 697 CFDictionaryRemoveValue(myDefault, PROXY_MATCH_ORDER_KEY); 698 } 699 } 700 CFArraySetValueAtIndex(proxies, 0, myDefault); 701 CFRelease(myDefault); 702 703 // establish proxy configuration 704 705 if (n_proxies > 0) { 706 CFDictionaryRef app_layer; 707 CFDictionaryRef scoped; 708 CFArrayRef serviceOrderAll; 709 Boolean skip = FALSE; 710 CFArrayRef supplemental; 711 712 proxy = CFArrayGetValueAtIndex(proxies, 0); 713 if (!CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 714 // if we have "a" default (non-supplemental) proxy 715 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 716 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains); 717 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders); 718 skip = TRUE; 719 } else { 720 newProxy = CFDictionaryCreateMutable(NULL, 721 0, 722 &kCFTypeDictionaryKeyCallBacks, 723 &kCFTypeDictionaryValueCallBacks); 724 } 725 726 serviceOrderAll = service_order_copy_all(services, serviceOrder); 727 728 // collect (and add) any "supplemental" proxy configurations 729 730 supplemental = copy_supplemental_proxies(proxies, skip); 731 if (supplemental != NULL) { 732 CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, supplemental); 733 CFRelease(supplemental); 734 } 735 736 // collect (and add) any "scoped" proxy configurations 737 738 scoped = copy_scoped_proxies(services, serviceOrderAll); 739 if (scoped != NULL) { 740 CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, scoped); 741 CFRelease(scoped); 742 } 743 744 // collect (and add) any "services" based proxy configurations 745 746 app_layer = copy_app_layer_vpn_proxies(services, serviceOrderAll, servicesInfo); 747 if (app_layer != NULL) { 748 CFDictionarySetValue(newProxy, kSCPropNetProxiesServices, app_layer); 749 CFRelease(app_layer); 750 } 751 752 if (serviceOrderAll != NULL) { 753 CFRelease(serviceOrderAll); 754 } 755 } else { 756 newProxy = NULL; 757 } 758 759 CFRelease(proxies); 760 return newProxy; 761} 762 763 764__private_extern__ 765void 766proxy_configuration_init(CFBundleRef bundle) 767{ 768 CFDictionaryRef dict; 769 770 dict = CFBundleGetInfoDictionary(bundle); 771 if (isA_CFDictionary(dict)) { 772 G_supplemental_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS")); 773 G_supplemental_proxies_follow_dns = isA_CFBoolean(G_supplemental_proxies_follow_dns); 774 } 775 776 return; 777} 778 779 780#pragma mark - 781#pragma mark Standalone test code 782 783 784#ifdef MAIN 785 786static void 787mergeDict(const void *key, const void *value, void *context) 788{ 789 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context; 790 791 CFDictionarySetValue(newDict, key, value); 792 return; 793} 794 795 796static void 797split(const void * key, const void * value, void * context) 798{ 799 CFArrayRef components; 800 CFStringRef entity_id; 801 CFStringRef service_id; 802 CFMutableDictionaryRef state_dict; 803 804 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/")); 805 service_id = CFArrayGetValueAtIndex(components, 3); 806 entity_id = CFArrayGetValueAtIndex(components, 4); 807 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id); 808 if (state_dict != NULL) { 809 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict); 810 } else { 811 state_dict = CFDictionaryCreateMutable(NULL, 812 0, 813 &kCFTypeDictionaryKeyCallBacks, 814 &kCFTypeDictionaryValueCallBacks); 815 } 816 817 if (CFEqual(entity_id, kSCEntNetIPv4) || 818 CFEqual(entity_id, kSCEntNetIPv6)) { 819 CFStringRef interface; 820 821 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName); 822 if (interface != NULL) { 823 CFDictionaryRef proxy; 824 CFMutableDictionaryRef new_proxy; 825 826 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies); 827 if (proxy != NULL) { 828 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 829 } else { 830 new_proxy = CFDictionaryCreateMutable(NULL, 831 0, 832 &kCFTypeDictionaryKeyCallBacks, 833 &kCFTypeDictionaryValueCallBacks); 834 } 835 CFDictionarySetValue(new_proxy, kSCPropInterfaceName, interface); 836 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy); 837 CFRelease(new_proxy); 838 } 839 } else if (CFEqual(entity_id, kSCEntNetProxies)) { 840 CFDictionaryRef proxy; 841 842 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies); 843 if (proxy != NULL) { 844 CFStringRef domain; 845 CFMutableDictionaryRef new_proxy; 846 847 // if we already have some Setup: or State: proxy content 848 domain = CFArrayGetValueAtIndex(components, 0); 849 if (CFEqual(domain, kSCDynamicStoreDomainState)) { 850 // if we've already seen the Setup: key 851 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value); 852 CFDictionaryApplyFunction(proxy, mergeDict, new_proxy); 853 } else { 854 // if we've already seen the State: key 855 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 856 CFDictionaryApplyFunction((CFDictionaryRef)value, mergeDict, new_proxy); 857 } 858 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy); 859 CFRelease(new_proxy); 860 } else { 861 CFDictionarySetValue(state_dict, kSCEntNetProxies, (CFDictionaryRef)value); 862 } 863 } else { 864 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value); 865 } 866 867 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict); 868 CFRelease(state_dict); 869 CFRelease(components); 870 871 return; 872} 873 874int 875main(int argc, char **argv) 876{ 877 CFDictionaryRef entities; 878 CFStringRef key; 879 CFDictionaryRef newProxy = NULL; 880 CFStringRef pattern; 881 CFMutableArrayRef patterns; 882 CFStringRef primary = NULL; 883 CFMutableDictionaryRef primary_proxy = NULL; 884 CFArrayRef service_order = NULL; 885 CFMutableDictionaryRef service_state_dict; 886 CFDictionaryRef setup_global_ipv4; 887 CFDictionaryRef state_global_ipv4; 888 SCDynamicStoreRef store; 889 890 _sc_log = FALSE; 891 _sc_verbose = (argc > 1) ? TRUE : FALSE; 892 893 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL); 894 895 // get IPv4, IPv6, and Proxies entities 896 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 897 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 898 kSCDynamicStoreDomainState, 899 kSCCompAnyRegex, 900 kSCEntNetIPv4); 901 CFArrayAppendValue(patterns, pattern); 902 CFRelease(pattern); 903 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 904 kSCDynamicStoreDomainState, 905 kSCCompAnyRegex, 906 kSCEntNetIPv6); 907 CFArrayAppendValue(patterns, pattern); 908 CFRelease(pattern); 909 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 910 kSCDynamicStoreDomainSetup, 911 kSCCompAnyRegex, 912 kSCEntNetProxies); 913 CFArrayAppendValue(patterns, pattern); 914 CFRelease(pattern); 915 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 916 kSCDynamicStoreDomainState, 917 kSCCompAnyRegex, 918 kSCEntNetProxies); 919 CFArrayAppendValue(patterns, pattern); 920 CFRelease(pattern); 921 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns); 922 CFRelease(patterns); 923 924 service_state_dict = CFDictionaryCreateMutable(NULL, 925 0, 926 &kCFTypeDictionaryKeyCallBacks, 927 &kCFTypeDictionaryValueCallBacks); 928 CFDictionaryApplyFunction(entities, split, service_state_dict); 929 CFRelease(entities); 930 931 // get primary service ID 932 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 933 kSCDynamicStoreDomainState, 934 kSCEntNetIPv4); 935 state_global_ipv4 = SCDynamicStoreCopyValue(store, key); 936 CFRelease(key); 937 if (state_global_ipv4 != NULL) { 938 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService); 939 if (primary != NULL) { 940 CFDictionaryRef service_dict; 941 942 // get proxy configuration for primary service 943 service_dict = CFDictionaryGetValue(service_state_dict, primary); 944 if (service_dict != NULL) { 945 CFDictionaryRef service_proxy; 946 947 service_proxy = CFDictionaryGetValue(service_dict, kSCEntNetProxies); 948 if (service_proxy != NULL) { 949 primary_proxy = CFDictionaryCreateMutableCopy(NULL, 0, service_proxy); 950 CFDictionaryRemoveValue(primary_proxy, kSCPropInterfaceName); 951 } 952 } 953 } 954 } 955 956 // get serviceOrder 957 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 958 kSCDynamicStoreDomainSetup, 959 kSCEntNetIPv4); 960 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key); 961 CFRelease(key); 962 if (setup_global_ipv4 != NULL) { 963 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder); 964 } 965 966 // update proxy configuration 967 proxy_configuration_init(CFBundleGetMainBundle()); 968 newProxy = proxy_configuration_update(primary_proxy, 969 service_state_dict, 970 service_order, 971 NULL); 972 if (newProxy != NULL) { 973 SCPrint(TRUE, stdout, CFSTR("%@\n"), newProxy); 974 CFRelease(newProxy); 975 } 976 977 // cleanup 978 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4); 979 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4); 980 CFRelease(service_state_dict); 981 CFRelease(store); 982 983 /* not reached */ 984 exit(0); 985 return 0; 986} 987#endif 988 989