2 * Copyright (c) 2011-2017, 2020 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * January 3, 2011 Allan Nathanson <ajn@apple.com>
31 #include <TargetConditionals.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
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"
43 #define DEFAULT_MATCH_ORDER 200000 /* match order for the "default" proxy configuration */
46 #define PROXY_MATCH_ORDER_KEY CFSTR("__MATCH_ORDER__")
47 #define ORDER_KEY CFSTR("__ORDER__")
50 CFBooleanRef G_supplemental_proxies_follow_dns
= NULL
;
54 add_proxy(CFMutableArrayRef proxies
, CFMutableDictionaryRef proxy
)
60 n_proxies
= CFArrayGetCount(proxies
);
61 for (i
= 0; i
< n_proxies
; i
++) {
62 CFDictionaryRef match_proxy
;
64 match_proxy
= CFArrayGetValueAtIndex(proxies
, i
);
65 if (CFEqual(proxy
, match_proxy
)) {
71 order
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &n_proxies
);
72 CFDictionarySetValue(proxy
, ORDER_KEY
, order
);
75 CFArrayAppendValue(proxies
, proxy
);
81 add_supplemental(CFMutableArrayRef proxies
, CFDictionaryRef proxy
, uint32_t defaultOrder
)
88 domains
= CFDictionaryGetValue(proxy
, kSCPropNetProxiesSupplementalMatchDomains
);
89 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
94 orders
= CFDictionaryGetValue(proxy
, kSCPropNetProxiesSupplementalMatchOrders
);
96 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
102 * yes, this is a "supplemental" proxy configuration, expand
103 * the match domains and add each to the proxies list.
105 for (i
= 0; i
< n_domains
; i
++) {
106 CFStringRef match_domain
;
107 CFNumberRef match_order
;
108 CFMutableDictionaryRef match_proxy
;
110 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
111 if (!isA_CFString(match_domain
)) {
115 match_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
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
);
123 CFDictionaryRemoveValue(match_proxy
, kSCPropNetProxiesSupplementalMatchDomain
);
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
);
133 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
134 CFDictionarySetValue(match_proxy
, PROXY_MATCH_ORDER_KEY
, num
);
137 defaultOrder
++; // if multiple domains, maintain ordering
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
);
145 add_proxy(proxies
, match_proxy
);
146 CFRelease(match_proxy
);
157 add_supplemental_proxies(CFMutableArrayRef proxies
, CFDictionaryRef services
, CFArrayRef service_order
)
159 const void * keys_q
[N_QUICK
];
160 const void ** keys
= keys_q
;
164 const void * vals_q
[N_QUICK
];
165 const void ** vals
= vals_q
;
167 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
168 if (n_services
== 0) {
169 return; // if no services
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);
177 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
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
];
186 if (!isA_CFDictionary(service
)) {
190 proxy
= CFDictionaryGetValue(service
, kSCEntNetProxies
);
191 if (!isA_CFDictionary(proxy
)) {
195 if ((G_supplemental_proxies_follow_dns
!= NULL
) && CFBooleanGetValue(G_supplemental_proxies_follow_dns
)) {
197 CFArrayRef matchDomains
;
198 CFArrayRef matchOrders
;
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
);
211 CFDictionaryRemoveValue(proxyWithDNS
, kSCPropNetProxiesSupplementalMatchOrders
);
213 proxy
= proxyWithDNS
;
217 defaultOrder
= DEFAULT_MATCH_ORDER
218 - (DEFAULT_MATCH_ORDER
/ 2)
219 + ((DEFAULT_MATCH_ORDER
/ 1000) * (uint32_t)i
);
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
;
226 add_supplemental(proxies
, proxy
, defaultOrder
);
227 if (proxyWithDNS
!= NULL
) CFRelease(proxyWithDNS
);
230 if (keys
!= keys_q
) {
231 CFAllocatorDeallocate(NULL
, keys
);
232 CFAllocatorDeallocate(NULL
, vals
);
239 static CFComparisonResult
240 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
242 #pragma unused(context)
243 CFDictionaryRef proxy1
= (CFDictionaryRef
)val1
;
244 CFDictionaryRef proxy2
= (CFDictionaryRef
)val2
;
247 uint32_t order1
= DEFAULT_MATCH_ORDER
;
248 uint32_t order2
= DEFAULT_MATCH_ORDER
;
250 num1
= CFDictionaryGetValue(proxy1
, PROXY_MATCH_ORDER_KEY
);
251 if (!isA_CFNumber(num1
) ||
252 !CFNumberGetValue(num1
, kCFNumberSInt32Type
, &order1
)) {
253 order1
= DEFAULT_MATCH_ORDER
;
256 num2
= CFDictionaryGetValue(proxy2
, PROXY_MATCH_ORDER_KEY
);
257 if (!isA_CFNumber(num2
) ||
258 !CFNumberGetValue(num2
, kCFNumberSInt32Type
, &order2
)) {
259 order2
= DEFAULT_MATCH_ORDER
;
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
;
273 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
277 return kCFCompareEqualTo
;
280 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
284 static __inline__ Boolean
285 isSupplementalProxy(CFDictionaryRef proxy
)
287 if ((proxy
!= NULL
) &&
288 CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomain
)) {
297 copy_supplemental_proxies(CFArrayRef proxies
, Boolean skip
)
302 CFMutableArrayRef supplemental
= NULL
;
304 // iterate over services
306 n_proxies
= isA_CFArray(proxies
) ? CFArrayGetCount(proxies
) : 0;
307 for (i
= 0; i
< n_proxies
; i
++) {
308 CFDictionaryRef proxy
;
310 proxy
= CFArrayGetValueAtIndex(proxies
, i
);
311 if (!isSupplementalProxy(proxy
)) {
312 // if not supplemental proxy (i.e. no match domain)
316 // add [supplemental] proxy entry
317 if (supplemental
== NULL
) {
318 supplemental
= CFArrayCreateMutable(NULL
,
320 &kCFTypeArrayCallBacks
);
322 CFArrayAppendValue(supplemental
, proxy
);
330 service_order_copy_all(CFDictionaryRef services
, CFArrayRef service_order
)
332 const void * keys_q
[N_QUICK
];
333 const void ** keys
= keys_q
;
337 CFMutableArrayRef order
;
339 // ensure that we process all services in order
340 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
341 if (n_services
== 0) {
346 // ensure that we process all services in order
348 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
350 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
352 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
355 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
356 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
358 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
359 for (i
= 0; i
< n_services
; i
++) {
360 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
362 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
363 CFArrayAppendValue(order
, serviceID
);
367 if (keys
!= keys_q
) {
368 CFAllocatorDeallocate(NULL
, keys
);
375 static CFDictionaryRef
376 copy_app_layer_vpn_proxies(CFDictionaryRef services
, CFArrayRef order
, CFDictionaryRef services_info
)
378 CFMutableDictionaryRef app_layer_proxies
= NULL
;
382 if (!isA_CFDictionary(services_info
)) {
386 // iterate over services
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
;
398 serviceID
= CFArrayGetValueAtIndex(order
, i
);
399 service
= CFDictionaryGetValue(services
, serviceID
);
400 if (!isA_CFDictionary(service
)) {
405 proxy
= CFDictionaryGetValue(service
, kSCEntNetProxies
);
406 if (!isA_CFDictionary(proxy
)) {
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
419 serviceIdentifierString
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%u"), serviceIdentifier
);
420 if (serviceIdentifierString
== NULL
) {
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
);
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
,
438 &kCFTypeDictionaryKeyCallBacks
,
439 &kCFTypeDictionaryValueCallBacks
);
441 CFDictionarySetValue(app_layer_proxies
, serviceIdentifierString
, newProxy
);
442 CFRelease(serviceIdentifierString
);
446 return app_layer_proxies
;
450 static CFDictionaryRef
451 copy_scoped_proxies(CFDictionaryRef services
, CFArrayRef order
)
455 CFMutableDictionaryRef scoped
= NULL
;
457 // iterate over services
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
;
468 serviceID
= CFArrayGetValueAtIndex(order
, i
);
469 service
= CFDictionaryGetValue(services
, serviceID
);
470 if (!isA_CFDictionary(service
)) {
475 proxy
= CFDictionaryGetValue(service
, kSCEntNetProxies
);
476 if (!isA_CFDictionary(proxy
)) {
481 interface
= CFDictionaryGetValue(proxy
, kSCPropInterfaceName
);
482 if (interface
== NULL
) {
483 // if no [scoped] interface
486 if ((scoped
!= NULL
) &&
487 CFDictionaryContainsKey(scoped
, interface
)) {
488 // if we've already processed this [scoped] interface
492 if ((_SC_cfstring_to_cstring(interface
,
495 kCFStringEncodingASCII
) == NULL
) ||
496 ((my_if_nametoindex(if_name
)) == 0)) {
497 // if interface index not available
501 // add [scoped] proxy entry
502 // ... and remove keys we don't want in a [scoped] proxy
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
,
511 &kCFTypeDictionaryKeyCallBacks
,
512 &kCFTypeDictionaryValueCallBacks
);
514 CFDictionarySetValue(scoped
, interface
, newProxy
);
516 CFRelease(interface
);
524 add_default_proxy(CFMutableArrayRef proxies
,
525 CFDictionaryRef defaultProxy
,
528 CFMutableDictionaryRef myDefault
;
529 uint32_t myOrder
= DEFAULT_MATCH_ORDER
;
530 CFNumberRef order
= NULL
;
532 if (defaultProxy
== NULL
) {
533 myDefault
= CFDictionaryCreateMutable(NULL
,
535 &kCFTypeDictionaryKeyCallBacks
,
536 &kCFTypeDictionaryValueCallBacks
);
538 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultProxy
);
539 CFDictionaryRemoveValue(myDefault
, kSCPropInterfaceName
);
540 order
= CFDictionaryGetValue(myDefault
, PROXY_MATCH_ORDER_KEY
);
543 // ensure that the default proxy has a search order
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
);
554 // add the default proxy
556 add_proxy(proxies
, myDefault
);
557 CFRelease(myDefault
);
562 static CFComparisonResult
563 compareDomain(const void *val1
, const void *val2
, void *context
)
565 CFDictionaryRef proxy1
= (CFDictionaryRef
)val1
;
566 CFDictionaryRef proxy2
= (CFDictionaryRef
)val2
;
569 CFArrayRef labels1
= NULL
;
570 CFArrayRef labels2
= NULL
;
573 CFComparisonResult result
;
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
;
584 return kCFCompareLessThan
;
585 } else if (domain2
== NULL
) {
586 return kCFCompareGreaterThan
;
589 // forward (A, AAAA) domains sort before reverse (PTR) domains
590 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
591 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
594 return kCFCompareGreaterThan
;
596 return kCFCompareLessThan
;
600 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
601 n1
= CFArrayGetCount(labels1
);
603 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
604 n2
= CFArrayGetCount(labels2
);
606 while ((n1
> 0) && (n2
> 0)) {
607 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
608 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
610 // compare domain labels
611 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
612 if (result
!= kCFCompareEqualTo
) {
617 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
619 result
= kCFCompareLessThan
;
621 } else if (n1
< n2
) {
622 result
= kCFCompareGreaterThan
;
626 // sort by search order
627 result
= compareBySearchOrder(val1
, val2
, context
);
631 if (labels1
!= NULL
) CFRelease(labels1
);
632 if (labels2
!= NULL
) CFRelease(labels2
);
638 CF_RETURNS_RETAINED CFDictionaryRef
639 proxy_configuration_update(CFDictionaryRef defaultProxy
,
640 CFDictionaryRef services
,
641 CFArrayRef serviceOrder
,
642 CFDictionaryRef servicesInfo
)
645 CFMutableDictionaryRef myDefault
;
646 Boolean myOrderAdded
= FALSE
;
647 CFMutableDictionaryRef newProxy
= NULL
;
649 CFDictionaryRef proxy
;
650 CFMutableArrayRef proxies
;
652 // establish full list of proxies
654 proxies
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
656 // collect (and add) any "supplemental" proxy configurations
658 add_supplemental_proxies(proxies
, services
, serviceOrder
);
660 // add the "default" proxy
662 add_default_proxy(proxies
, defaultProxy
, &myOrderAdded
);
664 // sort proxies, cleanup
666 n_proxies
= CFArrayGetCount(proxies
);
668 CFArraySortValues(proxies
, CFRangeMake(0, n_proxies
), compareDomain
, NULL
);
673 for (i
= n_proxies
- 1; i
>= 0; i
--) {
674 proxy
= CFArrayGetValueAtIndex(proxies
, i
);
677 !CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomain
)) {
678 // remove non-supplemental proxy
679 CFArrayRemoveValueAtIndex(proxies
, i
);
684 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
685 CFDictionaryRemoveValue(newProxy
, PROXY_MATCH_ORDER_KEY
);
686 CFDictionaryRemoveValue(newProxy
, ORDER_KEY
);
687 CFArraySetValueAtIndex(proxies
, i
, newProxy
);
691 // update the default proxy
693 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
695 CFArrayGetValueAtIndex(proxies
, 0));
696 if (myOrderAdded
&& (n_proxies
> 1)) {
697 CFDictionaryRef proxy
;
699 proxy
= CFArrayGetValueAtIndex(proxies
, 1);
700 if (CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomain
)) {
701 // if not a supplemental "default" proxy (a match domain name is
703 CFDictionaryRemoveValue(myDefault
, PROXY_MATCH_ORDER_KEY
);
706 CFArraySetValueAtIndex(proxies
, 0, myDefault
);
707 CFRelease(myDefault
);
709 // establish proxy configuration
712 CFDictionaryRef app_layer
;
713 CFDictionaryRef scoped
;
714 CFArrayRef serviceOrderAll
;
715 Boolean skip
= FALSE
;
716 CFArrayRef supplemental
;
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
);
726 newProxy
= CFDictionaryCreateMutable(NULL
,
728 &kCFTypeDictionaryKeyCallBacks
,
729 &kCFTypeDictionaryValueCallBacks
);
732 serviceOrderAll
= service_order_copy_all(services
, serviceOrder
);
734 // collect (and add) any "supplemental" proxy configurations
736 supplemental
= copy_supplemental_proxies(proxies
, skip
);
737 if (supplemental
!= NULL
) {
738 CFDictionarySetValue(newProxy
, kSCPropNetProxiesSupplemental
, supplemental
);
739 CFRelease(supplemental
);
742 // collect (and add) any "scoped" proxy configurations
744 scoped
= copy_scoped_proxies(services
, serviceOrderAll
);
745 if (scoped
!= NULL
) {
746 CFDictionarySetValue(newProxy
, kSCPropNetProxiesScoped
, scoped
);
750 // collect (and add) any "services" based proxy configurations
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
);
758 if (serviceOrderAll
!= NULL
) {
759 CFRelease(serviceOrderAll
);
772 proxy_configuration_init(CFBundleRef bundle
)
774 CFDictionaryRef dict
;
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
);
787 #pragma mark Standalone test code
793 mergeDict(const void *key
, const void *value
, void *context
)
795 CFMutableDictionaryRef newDict
= (CFMutableDictionaryRef
)context
;
797 CFDictionarySetValue(newDict
, key
, value
);
803 split(const void * key
, const void * value
, void * context
)
805 CFArrayRef components
;
806 CFStringRef entity_id
;
807 CFStringRef service_id
;
808 CFMutableDictionaryRef state_dict
;
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
);
817 state_dict
= CFDictionaryCreateMutable(NULL
,
819 &kCFTypeDictionaryKeyCallBacks
,
820 &kCFTypeDictionaryValueCallBacks
);
823 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
824 CFEqual(entity_id
, kSCEntNetIPv6
)) {
825 CFStringRef interface
;
827 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
828 if (interface
!= NULL
) {
829 CFDictionaryRef proxy
;
830 CFMutableDictionaryRef new_proxy
;
832 proxy
= CFDictionaryGetValue(state_dict
, kSCEntNetProxies
);
834 new_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
836 new_proxy
= CFDictionaryCreateMutable(NULL
,
838 &kCFTypeDictionaryKeyCallBacks
,
839 &kCFTypeDictionaryValueCallBacks
);
841 CFDictionarySetValue(new_proxy
, kSCPropInterfaceName
, interface
);
842 CFDictionarySetValue(state_dict
, kSCEntNetProxies
, new_proxy
);
843 CFRelease(new_proxy
);
845 } else if (CFEqual(entity_id
, kSCEntNetProxies
)) {
846 CFDictionaryRef proxy
;
848 proxy
= CFDictionaryGetValue(state_dict
, kSCEntNetProxies
);
851 CFMutableDictionaryRef new_proxy
;
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
);
860 // if we've already seen the State: key
861 new_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
862 CFDictionaryApplyFunction((CFDictionaryRef
)value
, mergeDict
, new_proxy
);
864 CFDictionarySetValue(state_dict
, kSCEntNetProxies
, new_proxy
);
865 CFRelease(new_proxy
);
867 CFDictionarySetValue(state_dict
, kSCEntNetProxies
, (CFDictionaryRef
)value
);
870 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
873 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
874 CFRelease(state_dict
);
875 CFRelease(components
);
881 main(int argc
, char **argv
)
883 CFDictionaryRef entities
;
885 CFDictionaryRef newProxy
= NULL
;
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
;
896 _sc_log
= kSCLogDestinationFile
;
897 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
899 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
901 // get IPv4, IPv6, and Proxies entities
902 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
903 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
904 kSCDynamicStoreDomainState
,
907 CFArrayAppendValue(patterns
, pattern
);
909 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
910 kSCDynamicStoreDomainState
,
913 CFArrayAppendValue(patterns
, pattern
);
915 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
916 kSCDynamicStoreDomainSetup
,
919 CFArrayAppendValue(patterns
, pattern
);
921 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
922 kSCDynamicStoreDomainState
,
925 CFArrayAppendValue(patterns
, pattern
);
927 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
930 service_state_dict
= CFDictionaryCreateMutable(NULL
,
932 &kCFTypeDictionaryKeyCallBacks
,
933 &kCFTypeDictionaryValueCallBacks
);
934 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
937 // get primary service ID
938 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
939 kSCDynamicStoreDomainState
,
941 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
943 if (state_global_ipv4
!= NULL
) {
944 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
945 if (primary
!= NULL
) {
946 CFDictionaryRef service_dict
;
948 // get proxy configuration for primary service
949 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
950 if (service_dict
!= NULL
) {
951 CFDictionaryRef service_proxy
;
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
);
963 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
964 kSCDynamicStoreDomainSetup
,
966 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
968 if (setup_global_ipv4
!= NULL
) {
969 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
972 // update proxy configuration
973 proxy_configuration_init(CFBundleGetMainBundle());
974 newProxy
= proxy_configuration_update(primary_proxy
,
978 if (newProxy
!= NULL
) {
979 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), newProxy
);
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
);