]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/proxy-configuration.c
configd-395.6.tar.gz
[apple/configd.git] / Plugins / IPMonitor / proxy-configuration.c
1 /*
2 * Copyright (c) 2011 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
41
42 #define DEFAULT_MATCH_ORDER 200000 /* match order for the "default" proxy configuration */
43
44
45 #define PROXY_MATCH_ORDER_KEY CFSTR("__MATCH_ORDER__")
46 #define ORDER_KEY CFSTR("__ORDER__")
47
48
49 static CFBooleanRef S_proxies_follow_dns = NULL;
50
51
52 static void
53 add_proxy(CFMutableArrayRef proxies, CFMutableDictionaryRef proxy)
54 {
55 CFIndex i;
56 CFIndex n_proxies;
57 CFNumberRef order;
58
59 n_proxies = CFArrayGetCount(proxies);
60 for (i = 0; i < n_proxies; i++) {
61 CFDictionaryRef match_proxy;
62
63 match_proxy = CFArrayGetValueAtIndex(proxies, i);
64 if (CFEqual(proxy, match_proxy)) {
65 // a real duplicate
66 return;
67 }
68 }
69
70 order = CFNumberCreate(NULL, kCFNumberIntType, &n_proxies);
71 CFDictionarySetValue(proxy, ORDER_KEY, order);
72 CFRelease(order);
73
74 CFArrayAppendValue(proxies, proxy);
75 return;
76 }
77
78
79 static void
80 add_supplemental(CFMutableArrayRef proxies, CFDictionaryRef proxy, uint32_t defaultOrder)
81 {
82 CFArrayRef domains;
83 CFIndex i;
84 CFIndex n_domains;
85 CFArrayRef orders;
86
87 domains = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchDomains);
88 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0;
89 if (n_domains == 0) {
90 return;
91 }
92
93 orders = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchOrders);
94 if (orders != NULL) {
95 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) {
96 return;
97 }
98 }
99
100 /*
101 * yes, this is a "supplemental" proxy configuration, expand
102 * the match domains and add each to the proxies list.
103 */
104 for (i = 0; i < n_domains; i++) {
105 CFStringRef match_domain;
106 CFNumberRef match_order;
107 CFMutableDictionaryRef match_proxy;
108
109 match_domain = CFArrayGetValueAtIndex(domains, i);
110 if (!isA_CFString(match_domain)) {
111 continue;
112 }
113
114 match_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
115
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);
121 } else {
122 CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomain);
123 }
124
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);
129 } else {
130 CFNumberRef num;
131
132 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
133 CFDictionarySetValue(match_proxy, PROXY_MATCH_ORDER_KEY, num);
134 CFRelease(num);
135
136 defaultOrder++; // if multiple domains, maintain ordering
137 }
138
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);
143
144 add_proxy(proxies, match_proxy);
145 CFRelease(match_proxy);
146 }
147
148 return;
149 }
150
151
152 #define N_QUICK 32
153
154
155 static void
156 add_supplemental_proxies(CFMutableArrayRef proxies, CFDictionaryRef services, CFArrayRef service_order)
157 {
158 const void * keys_q[N_QUICK];
159 const void ** keys = keys_q;
160 CFIndex i;
161 CFIndex n_order;
162 CFIndex n_services;
163 const void * vals_q[N_QUICK];
164 const void ** vals = vals_q;
165
166 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
167 if (n_services == 0) {
168 return; // if no services
169 }
170
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);
174 }
175
176 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
177
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];
184
185 if (!isA_CFDictionary(service)) {
186 continue;
187 }
188
189 proxy = CFDictionaryGetValue(service, kSCEntNetProxies);
190 if (!isA_CFDictionary(proxy)) {
191 continue;
192 }
193
194 if ((S_proxies_follow_dns != NULL) && CFBooleanGetValue(S_proxies_follow_dns)) {
195 CFDictionaryRef dns;
196 CFArrayRef matchDomains;
197 CFArrayRef matchOrders;
198
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);
209 } else {
210 CFDictionaryRemoveValue(proxyWithDNS, kSCPropNetProxiesSupplementalMatchOrders);
211 }
212 proxy = proxyWithDNS;
213 }
214 }
215
216 defaultOrder = DEFAULT_MATCH_ORDER
217 - (DEFAULT_MATCH_ORDER / 2)
218 + ((DEFAULT_MATCH_ORDER / 1000) * i);
219 if ((n_order > 0) &&
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;
223 }
224
225 add_supplemental(proxies, proxy, defaultOrder);
226 if (proxyWithDNS != NULL) CFRelease(proxyWithDNS);
227 }
228
229 if (keys != keys_q) {
230 CFAllocatorDeallocate(NULL, keys);
231 CFAllocatorDeallocate(NULL, vals);
232 }
233
234 return;
235 }
236
237
238 static CFComparisonResult
239 compareBySearchOrder(const void *val1, const void *val2, void *context)
240 {
241 CFDictionaryRef proxy1 = (CFDictionaryRef)val1;
242 CFDictionaryRef proxy2 = (CFDictionaryRef)val2;
243 CFNumberRef num1;
244 CFNumberRef num2;
245 uint32_t order1 = DEFAULT_MATCH_ORDER;
246 uint32_t order2 = DEFAULT_MATCH_ORDER;
247
248 num1 = CFDictionaryGetValue(proxy1, PROXY_MATCH_ORDER_KEY);
249 if (!isA_CFNumber(num1) ||
250 !CFNumberGetValue(num1, kCFNumberIntType, &order1)) {
251 order1 = DEFAULT_MATCH_ORDER;
252 }
253
254 num2 = CFDictionaryGetValue(proxy2, PROXY_MATCH_ORDER_KEY);
255 if (!isA_CFNumber(num2) ||
256 !CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
257 order2 = DEFAULT_MATCH_ORDER;
258 }
259
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;
270 } else {
271 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
272 }
273 }
274
275 return kCFCompareEqualTo;
276 }
277
278 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
279 }
280
281
282 static __inline__ Boolean
283 isSupplementalProxy(CFDictionaryRef proxy)
284 {
285 if ((proxy != NULL) &&
286 CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) {
287 return TRUE;
288 }
289
290 return FALSE;
291 }
292
293
294 static CFArrayRef
295 copy_supplemental_proxies(CFArrayRef proxies, Boolean skip)
296 {
297 CFIndex i;
298 CFIndex n_proxies;
299 CFMutableArrayRef supplemental = NULL;
300
301 // iterate over services
302
303 n_proxies = isA_CFArray(proxies) ? CFArrayGetCount(proxies) : 0;
304 for (i = 0; i < n_proxies; i++) {
305 CFDictionaryRef proxy;
306
307 proxy = CFArrayGetValueAtIndex(proxies, i);
308 if (!isSupplementalProxy(proxy)) {
309 // if not supplemental proxy (i.e. no match domain)
310 continue;
311 }
312
313 // add [supplemental] proxy entry
314 if (supplemental == NULL) {
315 supplemental = CFArrayCreateMutable(NULL,
316 0,
317 &kCFTypeArrayCallBacks);
318 }
319 CFArrayAppendValue(supplemental, proxy);
320 }
321
322 return supplemental;
323 }
324
325
326 static CFDictionaryRef
327 copy_scoped_proxies(CFDictionaryRef services, CFArrayRef service_order)
328 {
329 const void * keys_q[N_QUICK];
330 const void ** keys = keys_q;
331 CFIndex i;
332 CFIndex n_order;
333 CFIndex n_services;
334 CFMutableArrayRef order;
335 CFMutableDictionaryRef scoped = NULL;
336
337 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
338 if (n_services == 0) {
339 return NULL; // if no services
340 }
341
342 // ensure that we process all services in order
343
344 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
345 if (n_order > 0) {
346 order = CFArrayCreateMutableCopy(NULL, 0, service_order);
347 } else{
348 order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
349 }
350
351 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
352 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
353 }
354 CFDictionaryGetKeysAndValues(services, keys, NULL);
355 for (i = 0; i < n_services; i++) {
356 CFStringRef serviceID = (CFStringRef)keys[i];
357
358 if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) {
359 CFArrayAppendValue(order, serviceID);
360 n_order++;
361 }
362 }
363 if (keys != keys_q) {
364 CFAllocatorDeallocate(NULL, keys);
365 }
366
367 // iterate over services
368
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;
376
377 serviceID = CFArrayGetValueAtIndex(order, i);
378 service = CFDictionaryGetValue(services, serviceID);
379 if (!isA_CFDictionary(service)) {
380 // if no service
381 continue;
382 }
383
384 proxy = CFDictionaryGetValue(service, kSCEntNetProxies);
385 if (!isA_CFDictionary(proxy)) {
386 // if no proxy
387 continue;
388 }
389
390 interface = CFDictionaryGetValue(proxy, kSCPropInterfaceName);
391 if (interface == NULL) {
392 // if no [scoped] interface
393 continue;
394 }
395 if ((scoped != NULL) &&
396 CFDictionaryContainsKey(scoped, interface)) {
397 // if we've already processed this [scoped] interface
398 continue;
399 }
400
401 if ((_SC_cfstring_to_cstring(interface,
402 if_name,
403 sizeof(if_name),
404 kCFStringEncodingASCII) == NULL) ||
405 ((if_nametoindex(if_name)) == 0)) {
406 // if interface index not available
407 continue;
408 }
409
410 // add [scoped] proxy entry
411 // ... and remove keys we don't want in a [scoped] proxy
412 CFRetain(interface);
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,
419 0,
420 &kCFTypeDictionaryKeyCallBacks,
421 &kCFTypeDictionaryValueCallBacks);
422 }
423 CFDictionarySetValue(scoped, interface, newProxy);
424 CFRelease(newProxy);
425 CFRelease(interface);
426 }
427
428 CFRelease(order);
429 return scoped;
430 }
431
432
433 static void
434 add_default_proxy(CFMutableArrayRef proxies,
435 CFDictionaryRef defaultProxy,
436 Boolean *orderAdded)
437 {
438 CFMutableDictionaryRef myDefault;
439 uint32_t myOrder = DEFAULT_MATCH_ORDER;
440 CFNumberRef order = NULL;
441
442 if (defaultProxy == NULL) {
443 myDefault = CFDictionaryCreateMutable(NULL,
444 0,
445 &kCFTypeDictionaryKeyCallBacks,
446 &kCFTypeDictionaryValueCallBacks);
447 } else {
448 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultProxy);
449 CFDictionaryRemoveValue(myDefault, kSCPropInterfaceName);
450 order = CFDictionaryGetValue(myDefault, PROXY_MATCH_ORDER_KEY);
451 }
452
453 // ensure that the default proxy has a search order
454
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);
460 CFRelease(order);
461 *orderAdded = TRUE;
462 }
463
464 // add the default proxy
465
466 add_proxy(proxies, myDefault);
467 CFRelease(myDefault);
468 return;
469 }
470
471
472 static CFComparisonResult
473 compareDomain(const void *val1, const void *val2, void *context)
474 {
475 CFDictionaryRef proxy1 = (CFDictionaryRef)val1;
476 CFDictionaryRef proxy2 = (CFDictionaryRef)val2;
477 CFStringRef domain1;
478 CFStringRef domain2;
479 CFArrayRef labels1 = NULL;
480 CFArrayRef labels2 = NULL;
481 CFIndex n1;
482 CFIndex n2;
483 CFComparisonResult result;
484 Boolean rev1;
485 Boolean rev2;
486
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;
493 }
494 return kCFCompareLessThan;
495 } else if (domain2 == NULL) {
496 return kCFCompareGreaterThan;
497 }
498
499 // forward (A, AAAA) domains sort before reverse (PTR) domains
500 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa"));
501 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa"));
502 if (rev1 != rev2) {
503 if (rev1) {
504 return kCFCompareGreaterThan;
505 } else {
506 return kCFCompareLessThan;
507 }
508 }
509
510 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR("."));
511 n1 = CFArrayGetCount(labels1);
512
513 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR("."));
514 n2 = CFArrayGetCount(labels2);
515
516 while ((n1 > 0) && (n2 > 0)) {
517 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1);
518 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2);
519
520 // compare domain labels
521 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive);
522 if (result != kCFCompareEqualTo) {
523 goto done;
524 }
525 }
526
527 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
528 if (n1 > n2) {
529 result = kCFCompareLessThan;
530 goto done;
531 } else if (n1 < n2) {
532 result = kCFCompareGreaterThan;
533 goto done;
534 }
535
536 // sort by search order
537 result = compareBySearchOrder(val1, val2, context);
538
539 done :
540
541 if (labels1 != NULL) CFRelease(labels1);
542 if (labels2 != NULL) CFRelease(labels2);
543 return result;
544 }
545
546
547 __private_extern__
548 CFDictionaryRef
549 proxy_configuration_update(CFDictionaryRef defaultProxy,
550 CFDictionaryRef services,
551 CFArrayRef serviceOrder)
552 {
553 CFIndex i;
554 CFMutableDictionaryRef myDefault;
555 Boolean myOrderAdded = FALSE;
556 CFMutableDictionaryRef newProxy = NULL;
557 CFIndex n_proxies;
558 CFDictionaryRef proxy;
559 CFMutableArrayRef proxies;
560
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"));
564
565 // establish full list of proxies
566
567 proxies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
568
569 // collect (and add) any "supplemental" proxy configurations
570
571 add_supplemental_proxies(proxies, services, serviceOrder);
572
573 // add the "default" proxy
574
575 add_default_proxy(proxies, defaultProxy, &myOrderAdded);
576
577 // sort proxies, cleanup
578
579 n_proxies = CFArrayGetCount(proxies);
580 if (n_proxies > 1) {
581 CFArraySortValues(proxies, CFRangeMake(0, n_proxies), compareDomain, NULL);
582 }
583
584 // cleanup
585
586 for (i = n_proxies - 1; i >= 0; i--) {
587 proxy = CFArrayGetValueAtIndex(proxies, i);
588
589 if ((i > 0) &&
590 !CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) {
591 // remove non-supplemental proxy
592 CFArrayRemoveValueAtIndex(proxies, i);
593 n_proxies--;
594 continue;
595 }
596
597 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
598 CFDictionaryRemoveValue(newProxy, PROXY_MATCH_ORDER_KEY);
599 CFDictionaryRemoveValue(newProxy, ORDER_KEY);
600 CFArraySetValueAtIndex(proxies, i, newProxy);
601 CFRelease(newProxy);
602 }
603
604 // update the default proxy
605
606 myDefault = CFDictionaryCreateMutableCopy(NULL,
607 0,
608 CFArrayGetValueAtIndex(proxies, 0));
609 if (myOrderAdded && (n_proxies > 1)) {
610 CFDictionaryRef proxy;
611
612 proxy = CFArrayGetValueAtIndex(proxies, 1);
613 if (CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) {
614 // if not a supplemental "default" proxy (a match domain name is
615 // present)
616 CFDictionaryRemoveValue(myDefault, PROXY_MATCH_ORDER_KEY);
617 }
618 }
619 CFArraySetValueAtIndex(proxies, 0, myDefault);
620 CFRelease(myDefault);
621
622 // establish proxy configuration
623
624 if (n_proxies > 0) {
625 CFDictionaryRef scoped;
626 Boolean skip = FALSE;
627 CFArrayRef supplemental;
628
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);
635 skip = TRUE;
636 } else {
637 newProxy = CFDictionaryCreateMutable(NULL,
638 0,
639 &kCFTypeDictionaryKeyCallBacks,
640 &kCFTypeDictionaryValueCallBacks);
641 }
642
643 // collect (and add) any "supplemental" proxy configurations
644
645 supplemental = copy_supplemental_proxies(proxies, skip);
646 if (supplemental != NULL) {
647 CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, supplemental);
648 CFRelease(supplemental);
649 }
650
651 // collect (and add) any "scoped" proxy configurations
652
653 scoped = copy_scoped_proxies(services, serviceOrder);
654 if (scoped != NULL) {
655 CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, scoped);
656 CFRelease(scoped);
657 }
658 } else {
659 newProxy = NULL;
660 }
661
662 CFRelease(proxies);
663 return newProxy;
664 }
665
666
667 __private_extern__
668 void
669 proxy_configuration_init(CFBundleRef bundle)
670 {
671 CFDictionaryRef dict;
672
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);
677 }
678
679 return;
680 }
681
682
683 #ifdef MAIN
684
685 static void
686 mergeDict(const void *key, const void *value, void *context)
687 {
688 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
689
690 CFDictionarySetValue(newDict, key, value);
691 return;
692 }
693
694
695 static void
696 split(const void * key, const void * value, void * context)
697 {
698 CFArrayRef components;
699 CFStringRef entity_id;
700 CFStringRef service_id;
701 CFMutableDictionaryRef state_dict;
702
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);
709 } else {
710 state_dict = CFDictionaryCreateMutable(NULL,
711 0,
712 &kCFTypeDictionaryKeyCallBacks,
713 &kCFTypeDictionaryValueCallBacks);
714 }
715
716 if (CFEqual(entity_id, kSCEntNetIPv4) ||
717 CFEqual(entity_id, kSCEntNetIPv6)) {
718 CFStringRef interface;
719
720 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName);
721 if (interface != NULL) {
722 CFDictionaryRef proxy;
723 CFMutableDictionaryRef new_proxy;
724
725 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies);
726 if (proxy != NULL) {
727 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
728 } else {
729 new_proxy = CFDictionaryCreateMutable(NULL,
730 0,
731 &kCFTypeDictionaryKeyCallBacks,
732 &kCFTypeDictionaryValueCallBacks);
733 }
734 CFDictionarySetValue(new_proxy, kSCPropInterfaceName, interface);
735 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy);
736 CFRelease(new_proxy);
737 }
738 } else if (CFEqual(entity_id, kSCEntNetProxies)) {
739 CFDictionaryRef proxy;
740
741 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies);
742 if (proxy != NULL) {
743 CFStringRef domain;
744 CFMutableDictionaryRef new_proxy;
745
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);
752 } else {
753 // if we've already seen the State: key
754 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
755 CFDictionaryApplyFunction((CFDictionaryRef)value, mergeDict, new_proxy);
756 }
757 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy);
758 CFRelease(new_proxy);
759 } else {
760 CFDictionarySetValue(state_dict, kSCEntNetProxies, (CFDictionaryRef)value);
761 }
762 } else {
763 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
764 }
765
766 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
767 CFRelease(state_dict);
768 CFRelease(components);
769
770 return;
771 }
772
773 int
774 main(int argc, char **argv)
775 {
776 CFDictionaryRef entities;
777 CFStringRef key;
778 CFDictionaryRef newProxy = NULL;
779 CFStringRef pattern;
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;
788
789 _sc_log = FALSE;
790 _sc_verbose = (argc > 1) ? TRUE : FALSE;
791
792 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
793
794 // get IPv4, IPv6, and Proxies entities
795 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
796 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
797 kSCDynamicStoreDomainState,
798 kSCCompAnyRegex,
799 kSCEntNetIPv4);
800 CFArrayAppendValue(patterns, pattern);
801 CFRelease(pattern);
802 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
803 kSCDynamicStoreDomainState,
804 kSCCompAnyRegex,
805 kSCEntNetIPv6);
806 CFArrayAppendValue(patterns, pattern);
807 CFRelease(pattern);
808 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
809 kSCDynamicStoreDomainSetup,
810 kSCCompAnyRegex,
811 kSCEntNetProxies);
812 CFArrayAppendValue(patterns, pattern);
813 CFRelease(pattern);
814 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
815 kSCDynamicStoreDomainState,
816 kSCCompAnyRegex,
817 kSCEntNetProxies);
818 CFArrayAppendValue(patterns, pattern);
819 CFRelease(pattern);
820 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
821 CFRelease(patterns);
822
823 service_state_dict = CFDictionaryCreateMutable(NULL,
824 0,
825 &kCFTypeDictionaryKeyCallBacks,
826 &kCFTypeDictionaryValueCallBacks);
827 CFDictionaryApplyFunction(entities, split, service_state_dict);
828 CFRelease(entities);
829
830 // get primary service ID
831 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
832 kSCDynamicStoreDomainState,
833 kSCEntNetIPv4);
834 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
835 CFRelease(key);
836 if (state_global_ipv4 != NULL) {
837 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
838 if (primary != NULL) {
839 CFDictionaryRef service_dict;
840
841 // get proxy configuration for primary service
842 service_dict = CFDictionaryGetValue(service_state_dict, primary);
843 if (service_dict != NULL) {
844 CFDictionaryRef service_proxy;
845
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);
850 }
851 }
852 }
853 }
854
855 // get serviceOrder
856 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
857 kSCDynamicStoreDomainSetup,
858 kSCEntNetIPv4);
859 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
860 CFRelease(key);
861 if (setup_global_ipv4 != NULL) {
862 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
863 }
864
865 // update proxy configuration
866 proxy_configuration_init(CFBundleGetMainBundle());
867 newProxy = proxy_configuration_update(primary_proxy,
868 service_state_dict,
869 service_order);
870 if (newProxy != NULL) {
871 SCPrint(TRUE, stdout, CFSTR("%@\n"), newProxy);
872 CFRelease(newProxy);
873 }
874
875 // cleanup
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);
879 CFRelease(store);
880
881 /* not reached */
882 exit(0);
883 return 0;
884 }
885 #endif
886