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