2 * Copyright (c) 2011 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>
42 #define DEFAULT_MATCH_ORDER 200000 /* match order for the "default" proxy configuration */
45 #define PROXY_MATCH_ORDER_KEY CFSTR("__MATCH_ORDER__")
46 #define ORDER_KEY CFSTR("__ORDER__")
49 static CFBooleanRef S_proxies_follow_dns
= NULL
;
53 add_proxy(CFMutableArrayRef proxies
, CFMutableDictionaryRef proxy
)
59 n_proxies
= CFArrayGetCount(proxies
);
60 for (i
= 0; i
< n_proxies
; i
++) {
61 CFDictionaryRef match_proxy
;
63 match_proxy
= CFArrayGetValueAtIndex(proxies
, i
);
64 if (CFEqual(proxy
, match_proxy
)) {
70 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &n_proxies
);
71 CFDictionarySetValue(proxy
, ORDER_KEY
, order
);
74 CFArrayAppendValue(proxies
, proxy
);
80 add_supplemental(CFMutableArrayRef proxies
, CFDictionaryRef proxy
, uint32_t defaultOrder
)
87 domains
= CFDictionaryGetValue(proxy
, kSCPropNetProxiesSupplementalMatchDomains
);
88 n_domains
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
93 orders
= CFDictionaryGetValue(proxy
, kSCPropNetProxiesSupplementalMatchOrders
);
95 if (!isA_CFArray(orders
) || (n_domains
!= CFArrayGetCount(orders
))) {
101 * yes, this is a "supplemental" proxy configuration, expand
102 * the match domains and add each to the proxies list.
104 for (i
= 0; i
< n_domains
; i
++) {
105 CFStringRef match_domain
;
106 CFNumberRef match_order
;
107 CFMutableDictionaryRef match_proxy
;
109 match_domain
= CFArrayGetValueAtIndex(domains
, i
);
110 if (!isA_CFString(match_domain
)) {
114 match_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
116 // set supplemental proxy match "domain"
117 match_domain
= _SC_trimDomain(match_domain
);
118 if (match_domain
!= NULL
) {
119 CFDictionarySetValue(match_proxy
, kSCPropNetProxiesSupplementalMatchDomain
, match_domain
);
120 CFRelease(match_domain
);
122 CFDictionaryRemoveValue(match_proxy
, kSCPropNetProxiesSupplementalMatchDomain
);
125 // set supplemental proxy match "order"
126 match_order
= (orders
!= NULL
) ? CFArrayGetValueAtIndex(orders
, i
) : NULL
;
127 if (isA_CFNumber(match_order
)) {
128 CFDictionarySetValue(match_proxy
, PROXY_MATCH_ORDER_KEY
, match_order
);
132 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &defaultOrder
);
133 CFDictionarySetValue(match_proxy
, PROXY_MATCH_ORDER_KEY
, num
);
136 defaultOrder
++; // if multiple domains, maintain ordering
139 // remove keys we don't want in a supplemental proxy
140 CFDictionaryRemoveValue(match_proxy
, kSCPropNetProxiesSupplementalMatchDomains
);
141 CFDictionaryRemoveValue(match_proxy
, kSCPropNetProxiesSupplementalMatchOrders
);
142 CFDictionaryRemoveValue(match_proxy
, kSCPropInterfaceName
);
144 add_proxy(proxies
, match_proxy
);
145 CFRelease(match_proxy
);
156 add_supplemental_proxies(CFMutableArrayRef proxies
, CFDictionaryRef services
, CFArrayRef service_order
)
158 const void * keys_q
[N_QUICK
];
159 const void ** keys
= keys_q
;
163 const void * vals_q
[N_QUICK
];
164 const void ** vals
= vals_q
;
166 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
167 if (n_services
== 0) {
168 return; // if no services
171 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
172 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
173 vals
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
176 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
178 CFDictionaryGetKeysAndValues(services
, keys
, vals
);
179 for (i
= 0; i
< n_services
; i
++) {
180 uint32_t defaultOrder
;
181 CFDictionaryRef proxy
;
182 CFMutableDictionaryRef proxyWithDNS
= NULL
;
183 CFDictionaryRef service
= (CFDictionaryRef
)vals
[i
];
185 if (!isA_CFDictionary(service
)) {
189 proxy
= CFDictionaryGetValue(service
, kSCEntNetProxies
);
190 if (!isA_CFDictionary(proxy
)) {
194 if ((S_proxies_follow_dns
!= NULL
) && CFBooleanGetValue(S_proxies_follow_dns
)) {
196 CFArrayRef matchDomains
;
197 CFArrayRef matchOrders
;
199 if (!CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomains
) &&
200 CFDictionaryGetValueIfPresent(service
, kSCEntNetDNS
, (const void **)&dns
) &&
201 isA_CFDictionary(dns
) &&
202 CFDictionaryGetValueIfPresent(dns
, kSCPropNetDNSSupplementalMatchDomains
, (const void **)&matchDomains
) &&
203 isA_CFArray(matchDomains
)) {
204 proxyWithDNS
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
205 CFDictionarySetValue(proxyWithDNS
, kSCPropNetProxiesSupplementalMatchDomains
, matchDomains
);
206 if (CFDictionaryGetValueIfPresent(dns
, kSCPropNetDNSSupplementalMatchOrders
, (const void **)&matchOrders
) &&
207 isA_CFArray(matchOrders
)) {
208 CFDictionarySetValue(proxyWithDNS
, kSCPropNetProxiesSupplementalMatchOrders
, matchOrders
);
210 CFDictionaryRemoveValue(proxyWithDNS
, kSCPropNetProxiesSupplementalMatchOrders
);
212 proxy
= proxyWithDNS
;
216 defaultOrder
= DEFAULT_MATCH_ORDER
217 - (DEFAULT_MATCH_ORDER
/ 2)
218 + ((DEFAULT_MATCH_ORDER
/ 1000) * i
);
220 !CFArrayContainsValue(service_order
, CFRangeMake(0, n_order
), keys
[i
])) {
221 // push out services not specified in service order
222 defaultOrder
+= (DEFAULT_MATCH_ORDER
/ 1000) * n_services
;
225 add_supplemental(proxies
, proxy
, defaultOrder
);
226 if (proxyWithDNS
!= NULL
) CFRelease(proxyWithDNS
);
229 if (keys
!= keys_q
) {
230 CFAllocatorDeallocate(NULL
, keys
);
231 CFAllocatorDeallocate(NULL
, vals
);
238 static CFComparisonResult
239 compareBySearchOrder(const void *val1
, const void *val2
, void *context
)
241 CFDictionaryRef proxy1
= (CFDictionaryRef
)val1
;
242 CFDictionaryRef proxy2
= (CFDictionaryRef
)val2
;
245 uint32_t order1
= DEFAULT_MATCH_ORDER
;
246 uint32_t order2
= DEFAULT_MATCH_ORDER
;
248 num1
= CFDictionaryGetValue(proxy1
, PROXY_MATCH_ORDER_KEY
);
249 if (!isA_CFNumber(num1
) ||
250 !CFNumberGetValue(num1
, kCFNumberIntType
, &order1
)) {
251 order1
= DEFAULT_MATCH_ORDER
;
254 num2
= CFDictionaryGetValue(proxy2
, PROXY_MATCH_ORDER_KEY
);
255 if (!isA_CFNumber(num2
) ||
256 !CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
257 order2
= DEFAULT_MATCH_ORDER
;
260 if (order1
== order2
) {
261 // if same match "order", retain original ordering for configurations
262 if (CFDictionaryGetValueIfPresent(proxy1
, ORDER_KEY
, (const void **)&num1
) &&
263 CFDictionaryGetValueIfPresent(proxy2
, ORDER_KEY
, (const void **)&num2
) &&
264 isA_CFNumber(num1
) &&
265 isA_CFNumber(num2
) &&
266 CFNumberGetValue(num1
, kCFNumberIntType
, &order1
) &&
267 CFNumberGetValue(num2
, kCFNumberIntType
, &order2
)) {
268 if (order1
== order2
) {
269 return kCFCompareEqualTo
;
271 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
275 return kCFCompareEqualTo
;
278 return (order1
< order2
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
282 static __inline__ Boolean
283 isSupplementalProxy(CFDictionaryRef proxy
)
285 if ((proxy
!= NULL
) &&
286 CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomain
)) {
295 copy_supplemental_proxies(CFArrayRef proxies
, Boolean skip
)
299 CFMutableArrayRef supplemental
= NULL
;
301 // iterate over services
303 n_proxies
= isA_CFArray(proxies
) ? CFArrayGetCount(proxies
) : 0;
304 for (i
= 0; i
< n_proxies
; i
++) {
305 CFDictionaryRef proxy
;
307 proxy
= CFArrayGetValueAtIndex(proxies
, i
);
308 if (!isSupplementalProxy(proxy
)) {
309 // if not supplemental proxy (i.e. no match domain)
313 // add [supplemental] proxy entry
314 if (supplemental
== NULL
) {
315 supplemental
= CFArrayCreateMutable(NULL
,
317 &kCFTypeArrayCallBacks
);
319 CFArrayAppendValue(supplemental
, proxy
);
326 static CFDictionaryRef
327 copy_scoped_proxies(CFDictionaryRef services
, CFArrayRef service_order
)
329 const void * keys_q
[N_QUICK
];
330 const void ** keys
= keys_q
;
334 CFMutableArrayRef order
;
335 CFMutableDictionaryRef scoped
= NULL
;
337 n_services
= isA_CFDictionary(services
) ? CFDictionaryGetCount(services
) : 0;
338 if (n_services
== 0) {
339 return NULL
; // if no services
342 // ensure that we process all services in order
344 n_order
= isA_CFArray(service_order
) ? CFArrayGetCount(service_order
) : 0;
346 order
= CFArrayCreateMutableCopy(NULL
, 0, service_order
);
348 order
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
351 if (n_services
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
352 keys
= CFAllocatorAllocate(NULL
, n_services
* sizeof(CFTypeRef
), 0);
354 CFDictionaryGetKeysAndValues(services
, keys
, NULL
);
355 for (i
= 0; i
< n_services
; i
++) {
356 CFStringRef serviceID
= (CFStringRef
)keys
[i
];
358 if (!CFArrayContainsValue(order
, CFRangeMake(0, n_order
), serviceID
)) {
359 CFArrayAppendValue(order
, serviceID
);
363 if (keys
!= keys_q
) {
364 CFAllocatorDeallocate(NULL
, keys
);
367 // iterate over services
369 for (i
= 0; i
< n_order
; i
++) {
370 CFDictionaryRef proxy
;
371 char if_name
[IF_NAMESIZE
];
372 CFStringRef interface
;
373 CFMutableDictionaryRef newProxy
;
374 CFDictionaryRef service
;
375 CFStringRef serviceID
;
377 serviceID
= CFArrayGetValueAtIndex(order
, i
);
378 service
= CFDictionaryGetValue(services
, serviceID
);
379 if (!isA_CFDictionary(service
)) {
384 proxy
= CFDictionaryGetValue(service
, kSCEntNetProxies
);
385 if (!isA_CFDictionary(proxy
)) {
390 interface
= CFDictionaryGetValue(proxy
, kSCPropInterfaceName
);
391 if (interface
== NULL
) {
392 // if no [scoped] interface
395 if ((scoped
!= NULL
) &&
396 CFDictionaryContainsKey(scoped
, interface
)) {
397 // if we've already processed this [scoped] interface
401 if ((_SC_cfstring_to_cstring(interface
,
404 kCFStringEncodingASCII
) == NULL
) ||
405 ((if_nametoindex(if_name
)) == 0)) {
406 // if interface index not available
410 // add [scoped] proxy entry
411 // ... and remove keys we don't want in a [scoped] proxy
413 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
414 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplementalMatchDomains
);
415 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplementalMatchOrders
);
416 CFDictionaryRemoveValue(newProxy
, kSCPropInterfaceName
);
417 if (scoped
== NULL
) {
418 scoped
= CFDictionaryCreateMutable(NULL
,
420 &kCFTypeDictionaryKeyCallBacks
,
421 &kCFTypeDictionaryValueCallBacks
);
423 CFDictionarySetValue(scoped
, interface
, newProxy
);
425 CFRelease(interface
);
434 add_default_proxy(CFMutableArrayRef proxies
,
435 CFDictionaryRef defaultProxy
,
438 CFMutableDictionaryRef myDefault
;
439 uint32_t myOrder
= DEFAULT_MATCH_ORDER
;
440 CFNumberRef order
= NULL
;
442 if (defaultProxy
== NULL
) {
443 myDefault
= CFDictionaryCreateMutable(NULL
,
445 &kCFTypeDictionaryKeyCallBacks
,
446 &kCFTypeDictionaryValueCallBacks
);
448 myDefault
= CFDictionaryCreateMutableCopy(NULL
, 0, defaultProxy
);
449 CFDictionaryRemoveValue(myDefault
, kSCPropInterfaceName
);
450 order
= CFDictionaryGetValue(myDefault
, PROXY_MATCH_ORDER_KEY
);
453 // ensure that the default proxy has a search order
455 if (!isA_CFNumber(order
) ||
456 !CFNumberGetValue(order
, kCFNumberIntType
, &myOrder
)) {
457 myOrder
= DEFAULT_MATCH_ORDER
;
458 order
= CFNumberCreate(NULL
, kCFNumberIntType
, &myOrder
);
459 CFDictionarySetValue(myDefault
, PROXY_MATCH_ORDER_KEY
, order
);
464 // add the default proxy
466 add_proxy(proxies
, myDefault
);
467 CFRelease(myDefault
);
472 static CFComparisonResult
473 compareDomain(const void *val1
, const void *val2
, void *context
)
475 CFDictionaryRef proxy1
= (CFDictionaryRef
)val1
;
476 CFDictionaryRef proxy2
= (CFDictionaryRef
)val2
;
479 CFArrayRef labels1
= NULL
;
480 CFArrayRef labels2
= NULL
;
483 CFComparisonResult result
;
487 // "default" domains sort before "supplemental" domains
488 domain1
= CFDictionaryGetValue(proxy1
, kSCPropNetProxiesSupplementalMatchDomain
);
489 domain2
= CFDictionaryGetValue(proxy2
, kSCPropNetProxiesSupplementalMatchDomain
);
490 if (domain1
== NULL
) {
491 if (domain2
== NULL
) {
492 return kCFCompareEqualTo
;
494 return kCFCompareLessThan
;
495 } else if (domain2
== NULL
) {
496 return kCFCompareGreaterThan
;
499 // forward (A, AAAA) domains sort before reverse (PTR) domains
500 rev1
= CFStringHasSuffix(domain1
, CFSTR(".arpa"));
501 rev2
= CFStringHasSuffix(domain2
, CFSTR(".arpa"));
504 return kCFCompareGreaterThan
;
506 return kCFCompareLessThan
;
510 labels1
= CFStringCreateArrayBySeparatingStrings(NULL
, domain1
, CFSTR("."));
511 n1
= CFArrayGetCount(labels1
);
513 labels2
= CFStringCreateArrayBySeparatingStrings(NULL
, domain2
, CFSTR("."));
514 n2
= CFArrayGetCount(labels2
);
516 while ((n1
> 0) && (n2
> 0)) {
517 CFStringRef label1
= CFArrayGetValueAtIndex(labels1
, --n1
);
518 CFStringRef label2
= CFArrayGetValueAtIndex(labels2
, --n2
);
520 // compare domain labels
521 result
= CFStringCompare(label1
, label2
, kCFCompareCaseInsensitive
);
522 if (result
!= kCFCompareEqualTo
) {
527 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
529 result
= kCFCompareLessThan
;
531 } else if (n1
< n2
) {
532 result
= kCFCompareGreaterThan
;
536 // sort by search order
537 result
= compareBySearchOrder(val1
, val2
, context
);
541 if (labels1
!= NULL
) CFRelease(labels1
);
542 if (labels2
!= NULL
) CFRelease(labels2
);
549 proxy_configuration_update(CFDictionaryRef defaultProxy
,
550 CFDictionaryRef services
,
551 CFArrayRef serviceOrder
)
554 CFMutableDictionaryRef myDefault
;
555 Boolean myOrderAdded
= FALSE
;
556 CFMutableDictionaryRef newProxy
= NULL
;
558 CFDictionaryRef proxy
;
559 CFMutableArrayRef proxies
;
561 SCLog(TRUE
, LOG_DEBUG
, CFSTR("defaultProxy : %@"), defaultProxy
? defaultProxy
: (CFTypeRef
)CFSTR("NULL"));
562 SCLog(TRUE
, LOG_DEBUG
, CFSTR("services : %@"), services
? services
: (CFTypeRef
)CFSTR("NULL"));
563 SCLog(TRUE
, LOG_DEBUG
, CFSTR("serviceOrder : %@"), serviceOrder
? serviceOrder
: (CFTypeRef
)CFSTR("NULL"));
565 // establish full list of proxies
567 proxies
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
569 // collect (and add) any "supplemental" proxy configurations
571 add_supplemental_proxies(proxies
, services
, serviceOrder
);
573 // add the "default" proxy
575 add_default_proxy(proxies
, defaultProxy
, &myOrderAdded
);
577 // sort proxies, cleanup
579 n_proxies
= CFArrayGetCount(proxies
);
581 CFArraySortValues(proxies
, CFRangeMake(0, n_proxies
), compareDomain
, NULL
);
586 for (i
= n_proxies
- 1; i
>= 0; i
--) {
587 proxy
= CFArrayGetValueAtIndex(proxies
, i
);
590 !CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomain
)) {
591 // remove non-supplemental proxy
592 CFArrayRemoveValueAtIndex(proxies
, i
);
597 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
598 CFDictionaryRemoveValue(newProxy
, PROXY_MATCH_ORDER_KEY
);
599 CFDictionaryRemoveValue(newProxy
, ORDER_KEY
);
600 CFArraySetValueAtIndex(proxies
, i
, newProxy
);
604 // update the default proxy
606 myDefault
= CFDictionaryCreateMutableCopy(NULL
,
608 CFArrayGetValueAtIndex(proxies
, 0));
609 if (myOrderAdded
&& (n_proxies
> 1)) {
610 CFDictionaryRef proxy
;
612 proxy
= CFArrayGetValueAtIndex(proxies
, 1);
613 if (CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomain
)) {
614 // if not a supplemental "default" proxy (a match domain name is
616 CFDictionaryRemoveValue(myDefault
, PROXY_MATCH_ORDER_KEY
);
619 CFArraySetValueAtIndex(proxies
, 0, myDefault
);
620 CFRelease(myDefault
);
622 // establish proxy configuration
625 CFDictionaryRef scoped
;
626 Boolean skip
= FALSE
;
627 CFArrayRef supplemental
;
629 proxy
= CFArrayGetValueAtIndex(proxies
, 0);
630 if (!CFDictionaryContainsKey(proxy
, kSCPropNetProxiesSupplementalMatchDomain
)) {
631 // if we have "a" default (non-supplemental) proxy
632 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
633 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplementalMatchDomains
);
634 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplementalMatchOrders
);
637 newProxy
= CFDictionaryCreateMutable(NULL
,
639 &kCFTypeDictionaryKeyCallBacks
,
640 &kCFTypeDictionaryValueCallBacks
);
643 // collect (and add) any "supplemental" proxy configurations
645 supplemental
= copy_supplemental_proxies(proxies
, skip
);
646 if (supplemental
!= NULL
) {
647 CFDictionarySetValue(newProxy
, kSCPropNetProxiesSupplemental
, supplemental
);
648 CFRelease(supplemental
);
651 // collect (and add) any "scoped" proxy configurations
653 scoped
= copy_scoped_proxies(services
, serviceOrder
);
654 if (scoped
!= NULL
) {
655 CFDictionarySetValue(newProxy
, kSCPropNetProxiesScoped
, scoped
);
669 proxy_configuration_init(CFBundleRef bundle
)
671 CFDictionaryRef dict
;
673 dict
= CFBundleGetInfoDictionary(bundle
);
674 if (isA_CFDictionary(dict
)) {
675 S_proxies_follow_dns
= CFDictionaryGetValue(dict
, CFSTR("SupplementalProxiesFollowSupplementalDNS"));
676 S_proxies_follow_dns
= isA_CFBoolean(S_proxies_follow_dns
);
686 mergeDict(const void *key
, const void *value
, void *context
)
688 CFMutableDictionaryRef newDict
= (CFMutableDictionaryRef
)context
;
690 CFDictionarySetValue(newDict
, key
, value
);
696 split(const void * key
, const void * value
, void * context
)
698 CFArrayRef components
;
699 CFStringRef entity_id
;
700 CFStringRef service_id
;
701 CFMutableDictionaryRef state_dict
;
703 components
= CFStringCreateArrayBySeparatingStrings(NULL
, (CFStringRef
)key
, CFSTR("/"));
704 service_id
= CFArrayGetValueAtIndex(components
, 3);
705 entity_id
= CFArrayGetValueAtIndex(components
, 4);
706 state_dict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(context
, service_id
);
707 if (state_dict
!= NULL
) {
708 state_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
710 state_dict
= CFDictionaryCreateMutable(NULL
,
712 &kCFTypeDictionaryKeyCallBacks
,
713 &kCFTypeDictionaryValueCallBacks
);
716 if (CFEqual(entity_id
, kSCEntNetIPv4
) ||
717 CFEqual(entity_id
, kSCEntNetIPv6
)) {
718 CFStringRef interface
;
720 interface
= CFDictionaryGetValue((CFDictionaryRef
)value
, kSCPropInterfaceName
);
721 if (interface
!= NULL
) {
722 CFDictionaryRef proxy
;
723 CFMutableDictionaryRef new_proxy
;
725 proxy
= CFDictionaryGetValue(state_dict
, kSCEntNetProxies
);
727 new_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
729 new_proxy
= CFDictionaryCreateMutable(NULL
,
731 &kCFTypeDictionaryKeyCallBacks
,
732 &kCFTypeDictionaryValueCallBacks
);
734 CFDictionarySetValue(new_proxy
, kSCPropInterfaceName
, interface
);
735 CFDictionarySetValue(state_dict
, kSCEntNetProxies
, new_proxy
);
736 CFRelease(new_proxy
);
738 } else if (CFEqual(entity_id
, kSCEntNetProxies
)) {
739 CFDictionaryRef proxy
;
741 proxy
= CFDictionaryGetValue(state_dict
, kSCEntNetProxies
);
744 CFMutableDictionaryRef new_proxy
;
746 // if we already have some Setup: or State: proxy content
747 domain
= CFArrayGetValueAtIndex(components
, 0);
748 if (CFEqual(domain
, kSCDynamicStoreDomainState
)) {
749 // if we've already seen the Setup: key
750 new_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, (CFDictionaryRef
)value
);
751 CFDictionaryApplyFunction(proxy
, mergeDict
, new_proxy
);
753 // if we've already seen the State: key
754 new_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
755 CFDictionaryApplyFunction((CFDictionaryRef
)value
, mergeDict
, new_proxy
);
757 CFDictionarySetValue(state_dict
, kSCEntNetProxies
, new_proxy
);
758 CFRelease(new_proxy
);
760 CFDictionarySetValue(state_dict
, kSCEntNetProxies
, (CFDictionaryRef
)value
);
763 CFDictionarySetValue(state_dict
, entity_id
, (CFDictionaryRef
)value
);
766 CFDictionarySetValue((CFMutableDictionaryRef
)context
, service_id
, state_dict
);
767 CFRelease(state_dict
);
768 CFRelease(components
);
774 main(int argc
, char **argv
)
776 CFDictionaryRef entities
;
778 CFDictionaryRef newProxy
= NULL
;
780 CFMutableArrayRef patterns
;
781 CFStringRef primary
= NULL
;
782 CFMutableDictionaryRef primary_proxy
= NULL
;
783 CFArrayRef service_order
= NULL
;
784 CFMutableDictionaryRef service_state_dict
;
785 CFDictionaryRef setup_global_ipv4
;
786 CFDictionaryRef state_global_ipv4
;
787 SCDynamicStoreRef store
;
790 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
792 store
= SCDynamicStoreCreate(NULL
, CFSTR("TEST"), NULL
, NULL
);
794 // get IPv4, IPv6, and Proxies entities
795 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
796 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
797 kSCDynamicStoreDomainState
,
800 CFArrayAppendValue(patterns
, pattern
);
802 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
803 kSCDynamicStoreDomainState
,
806 CFArrayAppendValue(patterns
, pattern
);
808 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
809 kSCDynamicStoreDomainSetup
,
812 CFArrayAppendValue(patterns
, pattern
);
814 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
815 kSCDynamicStoreDomainState
,
818 CFArrayAppendValue(patterns
, pattern
);
820 entities
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
823 service_state_dict
= CFDictionaryCreateMutable(NULL
,
825 &kCFTypeDictionaryKeyCallBacks
,
826 &kCFTypeDictionaryValueCallBacks
);
827 CFDictionaryApplyFunction(entities
, split
, service_state_dict
);
830 // get primary service ID
831 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
832 kSCDynamicStoreDomainState
,
834 state_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
836 if (state_global_ipv4
!= NULL
) {
837 primary
= CFDictionaryGetValue(state_global_ipv4
, kSCDynamicStorePropNetPrimaryService
);
838 if (primary
!= NULL
) {
839 CFDictionaryRef service_dict
;
841 // get proxy configuration for primary service
842 service_dict
= CFDictionaryGetValue(service_state_dict
, primary
);
843 if (service_dict
!= NULL
) {
844 CFDictionaryRef service_proxy
;
846 service_proxy
= CFDictionaryGetValue(service_dict
, kSCEntNetProxies
);
847 if (service_proxy
!= NULL
) {
848 primary_proxy
= CFDictionaryCreateMutableCopy(NULL
, 0, service_proxy
);
849 CFDictionaryRemoveValue(primary_proxy
, kSCPropInterfaceName
);
856 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
857 kSCDynamicStoreDomainSetup
,
859 setup_global_ipv4
= SCDynamicStoreCopyValue(store
, key
);
861 if (setup_global_ipv4
!= NULL
) {
862 service_order
= CFDictionaryGetValue(setup_global_ipv4
, kSCPropNetServiceOrder
);
865 // update proxy configuration
866 proxy_configuration_init(CFBundleGetMainBundle());
867 newProxy
= proxy_configuration_update(primary_proxy
,
870 if (newProxy
!= NULL
) {
871 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), newProxy
);
876 if (setup_global_ipv4
!= NULL
) CFRelease(setup_global_ipv4
);
877 if (state_global_ipv4
!= NULL
) CFRelease(state_global_ipv4
);
878 CFRelease(service_state_dict
);