this repo has no description
at fixPythonPipStalling 994 lines 29 kB view raw
1/* 2 * Copyright (c) 2011-2017 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#pragma unused(context) 243 CFDictionaryRef proxy1 = (CFDictionaryRef)val1; 244 CFDictionaryRef proxy2 = (CFDictionaryRef)val2; 245 CFNumberRef num1; 246 CFNumberRef num2; 247 uint32_t order1 = DEFAULT_MATCH_ORDER; 248 uint32_t order2 = DEFAULT_MATCH_ORDER; 249 250 num1 = CFDictionaryGetValue(proxy1, PROXY_MATCH_ORDER_KEY); 251 if (!isA_CFNumber(num1) || 252 !CFNumberGetValue(num1, kCFNumberSInt32Type, &order1)) { 253 order1 = DEFAULT_MATCH_ORDER; 254 } 255 256 num2 = CFDictionaryGetValue(proxy2, PROXY_MATCH_ORDER_KEY); 257 if (!isA_CFNumber(num2) || 258 !CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) { 259 order2 = DEFAULT_MATCH_ORDER; 260 } 261 262 if (order1 == order2) { 263 // if same match "order", retain original ordering for configurations 264 if (CFDictionaryGetValueIfPresent(proxy1, ORDER_KEY, (const void **)&num1) && 265 CFDictionaryGetValueIfPresent(proxy2, ORDER_KEY, (const void **)&num2) && 266 isA_CFNumber(num1) && 267 isA_CFNumber(num2) && 268 CFNumberGetValue(num1, kCFNumberSInt32Type, &order1) && 269 CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) { 270 if (order1 == order2) { 271 return kCFCompareEqualTo; 272 } else { 273 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; 274 } 275 } 276 277 return kCFCompareEqualTo; 278 } 279 280 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; 281} 282 283 284static __inline__ Boolean 285isSupplementalProxy(CFDictionaryRef proxy) 286{ 287 if ((proxy != NULL) && 288 CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 289 return TRUE; 290 } 291 292 return FALSE; 293} 294 295 296static CFArrayRef 297copy_supplemental_proxies(CFArrayRef proxies, Boolean skip) 298{ 299#pragma unused(skip) 300 CFIndex i; 301 CFIndex n_proxies; 302 CFMutableArrayRef supplemental = NULL; 303 304 // iterate over services 305 306 n_proxies = isA_CFArray(proxies) ? CFArrayGetCount(proxies) : 0; 307 for (i = 0; i < n_proxies; i++) { 308 CFDictionaryRef proxy; 309 310 proxy = CFArrayGetValueAtIndex(proxies, i); 311 if (!isSupplementalProxy(proxy)) { 312 // if not supplemental proxy (i.e. no match domain) 313 continue; 314 } 315 316 // add [supplemental] proxy entry 317 if (supplemental == NULL) { 318 supplemental = CFArrayCreateMutable(NULL, 319 0, 320 &kCFTypeArrayCallBacks); 321 } 322 CFArrayAppendValue(supplemental, proxy); 323 } 324 325 return supplemental; 326} 327 328 329static CFArrayRef 330service_order_copy_all(CFDictionaryRef services, CFArrayRef service_order) 331{ 332 const void * keys_q[N_QUICK]; 333 const void ** keys = keys_q; 334 CFIndex i; 335 CFIndex n_order; 336 CFIndex n_services; 337 CFMutableArrayRef order; 338 339 // ensure that we process all services in order 340 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0; 341 if (n_services == 0) { 342 // if no services 343 return NULL; 344 } 345 346 // ensure that we process all services in order 347 348 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0; 349 if (n_order > 0) { 350 order = CFArrayCreateMutableCopy(NULL, 0, service_order); 351 } else { 352 order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 353 } 354 355 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 356 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0); 357 } 358 CFDictionaryGetKeysAndValues(services, keys, NULL); 359 for (i = 0; i < n_services; i++) { 360 CFStringRef serviceID = (CFStringRef)keys[i]; 361 362 if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) { 363 CFArrayAppendValue(order, serviceID); 364 n_order++; 365 } 366 } 367 if (keys != keys_q) { 368 CFAllocatorDeallocate(NULL, keys); 369 } 370 371 return order; 372} 373 374 375static CFDictionaryRef 376copy_app_layer_vpn_proxies(CFDictionaryRef services, CFArrayRef order, CFDictionaryRef services_info) 377{ 378 CFMutableDictionaryRef app_layer_proxies = NULL; 379 CFIndex i; 380 CFIndex n_order; 381 382 if (!isA_CFDictionary(services_info)) { 383 return NULL; 384 } 385 386 // iterate over services 387 388 n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0; 389 for (i = 0; i < n_order; i++) { 390 CFMutableDictionaryRef newProxy; 391 CFDictionaryRef proxy; 392 CFDictionaryRef service; 393 CFStringRef serviceID; 394 CFNumberRef serviceSpecificIdentifier; 395 int serviceIdentifier = 0; 396 CFStringRef serviceIdentifierString; 397 398 serviceID = CFArrayGetValueAtIndex(order, i); 399 service = CFDictionaryGetValue(services, serviceID); 400 if (!isA_CFDictionary(service)) { 401 // if no service 402 continue; 403 } 404 405 proxy = CFDictionaryGetValue(service, kSCEntNetProxies); 406 if (!isA_CFDictionary(proxy)) { 407 // if no proxy 408 continue; 409 } 410 411 serviceSpecificIdentifier = CFDictionaryGetValue(proxy, kSCPropNetProxiesServiceSpecific); 412 if (!isA_CFNumber(serviceSpecificIdentifier) || 413 !CFNumberGetValue(serviceSpecificIdentifier, kCFNumberIntType, &serviceIdentifier) || 414 serviceIdentifier == 0) { 415 // if not a service-specific proxy configuration 416 continue; 417 } 418 419 serviceIdentifierString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), serviceIdentifier); 420 if (serviceIdentifierString == NULL) { 421 continue; 422 } 423 if ((app_layer_proxies != NULL) && 424 CFDictionaryContainsKey(app_layer_proxies, serviceIdentifierString)) { 425 // if we've already processed this [app_layer_proxies] identifier 426 CFRelease(serviceIdentifierString); 427 continue; 428 } 429 430 // add [app_layer_proxies] proxy entry 431 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 432 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains); 433 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders); 434 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesServiceSpecific); 435 if (app_layer_proxies == NULL) { 436 app_layer_proxies = CFDictionaryCreateMutable(NULL, 437 0, 438 &kCFTypeDictionaryKeyCallBacks, 439 &kCFTypeDictionaryValueCallBacks); 440 } 441 CFDictionarySetValue(app_layer_proxies, serviceIdentifierString, newProxy); 442 CFRelease(serviceIdentifierString); 443 CFRelease(newProxy); 444 } 445 446 return app_layer_proxies; 447} 448 449 450static CFDictionaryRef 451copy_scoped_proxies(CFDictionaryRef services, CFArrayRef order) 452{ 453 CFIndex i; 454 CFIndex n_order; 455 CFMutableDictionaryRef scoped = NULL; 456 457 // iterate over services 458 459 n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0; 460 for (i = 0; i < n_order; i++) { 461 char if_name[IF_NAMESIZE]; 462 CFStringRef interface; 463 CFMutableDictionaryRef newProxy; 464 CFDictionaryRef proxy; 465 CFDictionaryRef service; 466 CFStringRef serviceID; 467 468 serviceID = CFArrayGetValueAtIndex(order, i); 469 service = CFDictionaryGetValue(services, serviceID); 470 if (!isA_CFDictionary(service)) { 471 // if no service 472 continue; 473 } 474 475 proxy = CFDictionaryGetValue(service, kSCEntNetProxies); 476 if (!isA_CFDictionary(proxy)) { 477 // if no proxy 478 continue; 479 } 480 481 interface = CFDictionaryGetValue(proxy, kSCPropInterfaceName); 482 if (interface == NULL) { 483 // if no [scoped] interface 484 continue; 485 } 486 if ((scoped != NULL) && 487 CFDictionaryContainsKey(scoped, interface)) { 488 // if we've already processed this [scoped] interface 489 continue; 490 } 491 492 if ((_SC_cfstring_to_cstring(interface, 493 if_name, 494 sizeof(if_name), 495 kCFStringEncodingASCII) == NULL) || 496 ((my_if_nametoindex(if_name)) == 0)) { 497 // if interface index not available 498 continue; 499 } 500 501 // add [scoped] proxy entry 502 // ... and remove keys we don't want in a [scoped] proxy 503 CFRetain(interface); 504 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 505 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains); 506 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders); 507 CFDictionaryRemoveValue(newProxy, kSCPropInterfaceName); 508 if (scoped == NULL) { 509 scoped = CFDictionaryCreateMutable(NULL, 510 0, 511 &kCFTypeDictionaryKeyCallBacks, 512 &kCFTypeDictionaryValueCallBacks); 513 } 514 CFDictionarySetValue(scoped, interface, newProxy); 515 CFRelease(newProxy); 516 CFRelease(interface); 517 } 518 519 return scoped; 520} 521 522 523static void 524add_default_proxy(CFMutableArrayRef proxies, 525 CFDictionaryRef defaultProxy, 526 Boolean *orderAdded) 527{ 528 CFMutableDictionaryRef myDefault; 529 uint32_t myOrder = DEFAULT_MATCH_ORDER; 530 CFNumberRef order = NULL; 531 532 if (defaultProxy == NULL) { 533 myDefault = CFDictionaryCreateMutable(NULL, 534 0, 535 &kCFTypeDictionaryKeyCallBacks, 536 &kCFTypeDictionaryValueCallBacks); 537 } else { 538 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultProxy); 539 CFDictionaryRemoveValue(myDefault, kSCPropInterfaceName); 540 order = CFDictionaryGetValue(myDefault, PROXY_MATCH_ORDER_KEY); 541 } 542 543 // ensure that the default proxy has a search order 544 545 if (!isA_CFNumber(order) || 546 !CFNumberGetValue(order, kCFNumberSInt32Type, &myOrder)) { 547 myOrder = DEFAULT_MATCH_ORDER; 548 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder); 549 CFDictionarySetValue(myDefault, PROXY_MATCH_ORDER_KEY, order); 550 CFRelease(order); 551 *orderAdded = TRUE; 552 } 553 554 // add the default proxy 555 556 add_proxy(proxies, myDefault); 557 CFRelease(myDefault); 558 return; 559} 560 561 562static CFComparisonResult 563compareDomain(const void *val1, const void *val2, void *context) 564{ 565 CFDictionaryRef proxy1 = (CFDictionaryRef)val1; 566 CFDictionaryRef proxy2 = (CFDictionaryRef)val2; 567 CFStringRef domain1; 568 CFStringRef domain2; 569 CFArrayRef labels1 = NULL; 570 CFArrayRef labels2 = NULL; 571 CFIndex n1; 572 CFIndex n2; 573 CFComparisonResult result; 574 Boolean rev1; 575 Boolean rev2; 576 577 // "default" domains sort before "supplemental" domains 578 domain1 = CFDictionaryGetValue(proxy1, kSCPropNetProxiesSupplementalMatchDomain); 579 domain2 = CFDictionaryGetValue(proxy2, kSCPropNetProxiesSupplementalMatchDomain); 580 if (domain1 == NULL) { 581 if (domain2 == NULL) { 582 return kCFCompareEqualTo; 583 } 584 return kCFCompareLessThan; 585 } else if (domain2 == NULL) { 586 return kCFCompareGreaterThan; 587 } 588 589 // forward (A, AAAA) domains sort before reverse (PTR) domains 590 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa")); 591 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa")); 592 if (rev1 != rev2) { 593 if (rev1) { 594 return kCFCompareGreaterThan; 595 } else { 596 return kCFCompareLessThan; 597 } 598 } 599 600 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR(".")); 601 n1 = CFArrayGetCount(labels1); 602 603 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR(".")); 604 n2 = CFArrayGetCount(labels2); 605 606 while ((n1 > 0) && (n2 > 0)) { 607 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1); 608 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2); 609 610 // compare domain labels 611 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive); 612 if (result != kCFCompareEqualTo) { 613 goto done; 614 } 615 } 616 617 // longer labels (corp.apple.com) sort before shorter labels (apple.com) 618 if (n1 > n2) { 619 result = kCFCompareLessThan; 620 goto done; 621 } else if (n1 < n2) { 622 result = kCFCompareGreaterThan; 623 goto done; 624 } 625 626 // sort by search order 627 result = compareBySearchOrder(val1, val2, context); 628 629 done : 630 631 if (labels1 != NULL) CFRelease(labels1); 632 if (labels2 != NULL) CFRelease(labels2); 633 return result; 634} 635 636 637__private_extern__ 638CF_RETURNS_RETAINED CFDictionaryRef 639proxy_configuration_update(CFDictionaryRef defaultProxy, 640 CFDictionaryRef services, 641 CFArrayRef serviceOrder, 642 CFDictionaryRef servicesInfo) 643{ 644 CFIndex i; 645 CFMutableDictionaryRef myDefault; 646 Boolean myOrderAdded = FALSE; 647 CFMutableDictionaryRef newProxy = NULL; 648 CFIndex n_proxies; 649 CFDictionaryRef proxy; 650 CFMutableArrayRef proxies; 651 652 // establish full list of proxies 653 654 proxies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 655 656 // collect (and add) any "supplemental" proxy configurations 657 658 add_supplemental_proxies(proxies, services, serviceOrder); 659 660 // add the "default" proxy 661 662 add_default_proxy(proxies, defaultProxy, &myOrderAdded); 663 664 // sort proxies, cleanup 665 666 n_proxies = CFArrayGetCount(proxies); 667 if (n_proxies > 1) { 668 CFArraySortValues(proxies, CFRangeMake(0, n_proxies), compareDomain, NULL); 669 } 670 671 // cleanup 672 673 for (i = n_proxies - 1; i >= 0; i--) { 674 proxy = CFArrayGetValueAtIndex(proxies, i); 675 676 if ((i > 0) && 677 !CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 678 // remove non-supplemental proxy 679 CFArrayRemoveValueAtIndex(proxies, i); 680 n_proxies--; 681 continue; 682 } 683 684 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 685 CFDictionaryRemoveValue(newProxy, PROXY_MATCH_ORDER_KEY); 686 CFDictionaryRemoveValue(newProxy, ORDER_KEY); 687 CFArraySetValueAtIndex(proxies, i, newProxy); 688 CFRelease(newProxy); 689 } 690 691 // update the default proxy 692 693 myDefault = CFDictionaryCreateMutableCopy(NULL, 694 0, 695 CFArrayGetValueAtIndex(proxies, 0)); 696 if (myOrderAdded && (n_proxies > 1)) { 697 CFDictionaryRef proxy; 698 699 proxy = CFArrayGetValueAtIndex(proxies, 1); 700 if (CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 701 // if not a supplemental "default" proxy (a match domain name is 702 // present) 703 CFDictionaryRemoveValue(myDefault, PROXY_MATCH_ORDER_KEY); 704 } 705 } 706 CFArraySetValueAtIndex(proxies, 0, myDefault); 707 CFRelease(myDefault); 708 709 // establish proxy configuration 710 711 if (n_proxies > 0) { 712 CFDictionaryRef app_layer; 713 CFDictionaryRef scoped; 714 CFArrayRef serviceOrderAll; 715 Boolean skip = FALSE; 716 CFArrayRef supplemental; 717 718 proxy = CFArrayGetValueAtIndex(proxies, 0); 719 if (!CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) { 720 // if we have "a" default (non-supplemental) proxy 721 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 722 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains); 723 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders); 724 skip = TRUE; 725 } else { 726 newProxy = CFDictionaryCreateMutable(NULL, 727 0, 728 &kCFTypeDictionaryKeyCallBacks, 729 &kCFTypeDictionaryValueCallBacks); 730 } 731 732 serviceOrderAll = service_order_copy_all(services, serviceOrder); 733 734 // collect (and add) any "supplemental" proxy configurations 735 736 supplemental = copy_supplemental_proxies(proxies, skip); 737 if (supplemental != NULL) { 738 CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, supplemental); 739 CFRelease(supplemental); 740 } 741 742 // collect (and add) any "scoped" proxy configurations 743 744 scoped = copy_scoped_proxies(services, serviceOrderAll); 745 if (scoped != NULL) { 746 CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, scoped); 747 CFRelease(scoped); 748 } 749 750 // collect (and add) any "services" based proxy configurations 751 752 app_layer = copy_app_layer_vpn_proxies(services, serviceOrderAll, servicesInfo); 753 if (app_layer != NULL) { 754 CFDictionarySetValue(newProxy, kSCPropNetProxiesServices, app_layer); 755 CFRelease(app_layer); 756 } 757 758 if (serviceOrderAll != NULL) { 759 CFRelease(serviceOrderAll); 760 } 761 } else { 762 newProxy = NULL; 763 } 764 765 CFRelease(proxies); 766 return newProxy; 767} 768 769 770__private_extern__ 771void 772proxy_configuration_init(CFBundleRef bundle) 773{ 774 CFDictionaryRef dict; 775 776 dict = CFBundleGetInfoDictionary(bundle); 777 if (isA_CFDictionary(dict)) { 778 G_supplemental_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS")); 779 G_supplemental_proxies_follow_dns = isA_CFBoolean(G_supplemental_proxies_follow_dns); 780 } 781 782 return; 783} 784 785 786#pragma mark - 787#pragma mark Standalone test code 788 789 790#ifdef MAIN 791 792static void 793mergeDict(const void *key, const void *value, void *context) 794{ 795 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context; 796 797 CFDictionarySetValue(newDict, key, value); 798 return; 799} 800 801 802static void 803split(const void * key, const void * value, void * context) 804{ 805 CFArrayRef components; 806 CFStringRef entity_id; 807 CFStringRef service_id; 808 CFMutableDictionaryRef state_dict; 809 810 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/")); 811 service_id = CFArrayGetValueAtIndex(components, 3); 812 entity_id = CFArrayGetValueAtIndex(components, 4); 813 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id); 814 if (state_dict != NULL) { 815 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict); 816 } else { 817 state_dict = CFDictionaryCreateMutable(NULL, 818 0, 819 &kCFTypeDictionaryKeyCallBacks, 820 &kCFTypeDictionaryValueCallBacks); 821 } 822 823 if (CFEqual(entity_id, kSCEntNetIPv4) || 824 CFEqual(entity_id, kSCEntNetIPv6)) { 825 CFStringRef interface; 826 827 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName); 828 if (interface != NULL) { 829 CFDictionaryRef proxy; 830 CFMutableDictionaryRef new_proxy; 831 832 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies); 833 if (proxy != NULL) { 834 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 835 } else { 836 new_proxy = CFDictionaryCreateMutable(NULL, 837 0, 838 &kCFTypeDictionaryKeyCallBacks, 839 &kCFTypeDictionaryValueCallBacks); 840 } 841 CFDictionarySetValue(new_proxy, kSCPropInterfaceName, interface); 842 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy); 843 CFRelease(new_proxy); 844 } 845 } else if (CFEqual(entity_id, kSCEntNetProxies)) { 846 CFDictionaryRef proxy; 847 848 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies); 849 if (proxy != NULL) { 850 CFStringRef domain; 851 CFMutableDictionaryRef new_proxy; 852 853 // if we already have some Setup: or State: proxy content 854 domain = CFArrayGetValueAtIndex(components, 0); 855 if (CFEqual(domain, kSCDynamicStoreDomainState)) { 856 // if we've already seen the Setup: key 857 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value); 858 CFDictionaryApplyFunction(proxy, mergeDict, new_proxy); 859 } else { 860 // if we've already seen the State: key 861 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 862 CFDictionaryApplyFunction((CFDictionaryRef)value, mergeDict, new_proxy); 863 } 864 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy); 865 CFRelease(new_proxy); 866 } else { 867 CFDictionarySetValue(state_dict, kSCEntNetProxies, (CFDictionaryRef)value); 868 } 869 } else { 870 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value); 871 } 872 873 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict); 874 CFRelease(state_dict); 875 CFRelease(components); 876 877 return; 878} 879 880int 881main(int argc, char **argv) 882{ 883 CFDictionaryRef entities; 884 CFStringRef key; 885 CFDictionaryRef newProxy = NULL; 886 CFStringRef pattern; 887 CFMutableArrayRef patterns; 888 CFStringRef primary = NULL; 889 CFMutableDictionaryRef primary_proxy = NULL; 890 CFArrayRef service_order = NULL; 891 CFMutableDictionaryRef service_state_dict; 892 CFDictionaryRef setup_global_ipv4; 893 CFDictionaryRef state_global_ipv4; 894 SCDynamicStoreRef store; 895 896 _sc_log = FALSE; 897 _sc_verbose = (argc > 1) ? TRUE : FALSE; 898 899 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL); 900 901 // get IPv4, IPv6, and Proxies entities 902 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 903 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 904 kSCDynamicStoreDomainState, 905 kSCCompAnyRegex, 906 kSCEntNetIPv4); 907 CFArrayAppendValue(patterns, pattern); 908 CFRelease(pattern); 909 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 910 kSCDynamicStoreDomainState, 911 kSCCompAnyRegex, 912 kSCEntNetIPv6); 913 CFArrayAppendValue(patterns, pattern); 914 CFRelease(pattern); 915 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 916 kSCDynamicStoreDomainSetup, 917 kSCCompAnyRegex, 918 kSCEntNetProxies); 919 CFArrayAppendValue(patterns, pattern); 920 CFRelease(pattern); 921 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 922 kSCDynamicStoreDomainState, 923 kSCCompAnyRegex, 924 kSCEntNetProxies); 925 CFArrayAppendValue(patterns, pattern); 926 CFRelease(pattern); 927 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns); 928 CFRelease(patterns); 929 930 service_state_dict = CFDictionaryCreateMutable(NULL, 931 0, 932 &kCFTypeDictionaryKeyCallBacks, 933 &kCFTypeDictionaryValueCallBacks); 934 CFDictionaryApplyFunction(entities, split, service_state_dict); 935 CFRelease(entities); 936 937 // get primary service ID 938 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 939 kSCDynamicStoreDomainState, 940 kSCEntNetIPv4); 941 state_global_ipv4 = SCDynamicStoreCopyValue(store, key); 942 CFRelease(key); 943 if (state_global_ipv4 != NULL) { 944 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService); 945 if (primary != NULL) { 946 CFDictionaryRef service_dict; 947 948 // get proxy configuration for primary service 949 service_dict = CFDictionaryGetValue(service_state_dict, primary); 950 if (service_dict != NULL) { 951 CFDictionaryRef service_proxy; 952 953 service_proxy = CFDictionaryGetValue(service_dict, kSCEntNetProxies); 954 if (service_proxy != NULL) { 955 primary_proxy = CFDictionaryCreateMutableCopy(NULL, 0, service_proxy); 956 CFDictionaryRemoveValue(primary_proxy, kSCPropInterfaceName); 957 } 958 } 959 } 960 } 961 962 // get serviceOrder 963 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 964 kSCDynamicStoreDomainSetup, 965 kSCEntNetIPv4); 966 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key); 967 CFRelease(key); 968 if (setup_global_ipv4 != NULL) { 969 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder); 970 } 971 972 // update proxy configuration 973 proxy_configuration_init(CFBundleGetMainBundle()); 974 newProxy = proxy_configuration_update(primary_proxy, 975 service_state_dict, 976 service_order, 977 NULL); 978 if (newProxy != NULL) { 979 SCPrint(TRUE, stdout, CFSTR("%@\n"), newProxy); 980 CFRelease(newProxy); 981 } 982 983 // cleanup 984 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4); 985 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4); 986 CFRelease(service_state_dict); 987 CFRelease(store); 988 989 /* not reached */ 990 exit(0); 991 return 0; 992} 993#endif 994