]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/proxy-configuration.c
configd-888.30.2.tar.gz
[apple/configd.git] / Plugins / IPMonitor / proxy-configuration.c
1 /*
2 * Copyright (c) 2011-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * January 3, 2011 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <TargetConditionals.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <net/if.h>
35
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCPrivate.h>
39 #include <SystemConfiguration/SCValidation.h>
40 #include "ip_plugin.h"
41
42
43 #define DEFAULT_MATCH_ORDER 200000 /* match order for the "default" proxy configuration */
44
45
46 #define PROXY_MATCH_ORDER_KEY CFSTR("__MATCH_ORDER__")
47 #define ORDER_KEY CFSTR("__ORDER__")
48
49
50 CFBooleanRef G_supplemental_proxies_follow_dns = NULL;
51
52
53 static void
54 add_proxy(CFMutableArrayRef proxies, CFMutableDictionaryRef proxy)
55 {
56 CFIndex i;
57 CFIndex n_proxies;
58 CFNumberRef order;
59
60 n_proxies = CFArrayGetCount(proxies);
61 for (i = 0; i < n_proxies; i++) {
62 CFDictionaryRef match_proxy;
63
64 match_proxy = CFArrayGetValueAtIndex(proxies, i);
65 if (CFEqual(proxy, match_proxy)) {
66 // a real duplicate
67 return;
68 }
69 }
70
71 order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_proxies);
72 CFDictionarySetValue(proxy, ORDER_KEY, order);
73 CFRelease(order);
74
75 CFArrayAppendValue(proxies, proxy);
76 return;
77 }
78
79
80 static void
81 add_supplemental(CFMutableArrayRef proxies, CFDictionaryRef proxy, uint32_t defaultOrder)
82 {
83 CFArrayRef domains;
84 CFIndex i;
85 CFIndex n_domains;
86 CFArrayRef orders;
87
88 domains = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchDomains);
89 n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0;
90 if (n_domains == 0) {
91 return;
92 }
93
94 orders = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchOrders);
95 if (orders != NULL) {
96 if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) {
97 return;
98 }
99 }
100
101 /*
102 * yes, this is a "supplemental" proxy configuration, expand
103 * the match domains and add each to the proxies list.
104 */
105 for (i = 0; i < n_domains; i++) {
106 CFStringRef match_domain;
107 CFNumberRef match_order;
108 CFMutableDictionaryRef match_proxy;
109
110 match_domain = CFArrayGetValueAtIndex(domains, i);
111 if (!isA_CFString(match_domain)) {
112 continue;
113 }
114
115 match_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
116
117 // set supplemental proxy match "domain"
118 match_domain = _SC_trimDomain(match_domain);
119 if (match_domain != NULL) {
120 CFDictionarySetValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomain, match_domain);
121 CFRelease(match_domain);
122 } else {
123 CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomain);
124 }
125
126 // set supplemental proxy match "order"
127 match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL;
128 if (isA_CFNumber(match_order)) {
129 CFDictionarySetValue(match_proxy, PROXY_MATCH_ORDER_KEY, match_order);
130 } else {
131 CFNumberRef num;
132
133 num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder);
134 CFDictionarySetValue(match_proxy, PROXY_MATCH_ORDER_KEY, num);
135 CFRelease(num);
136
137 defaultOrder++; // if multiple domains, maintain ordering
138 }
139
140 // remove keys we don't want in a supplemental proxy
141 CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomains);
142 CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchOrders);
143 CFDictionaryRemoveValue(match_proxy, kSCPropInterfaceName);
144
145 add_proxy(proxies, match_proxy);
146 CFRelease(match_proxy);
147 }
148
149 return;
150 }
151
152
153 #define N_QUICK 32
154
155
156 static void
157 add_supplemental_proxies(CFMutableArrayRef proxies, CFDictionaryRef services, CFArrayRef service_order)
158 {
159 const void * keys_q[N_QUICK];
160 const void ** keys = keys_q;
161 CFIndex i;
162 CFIndex n_order;
163 CFIndex n_services;
164 const void * vals_q[N_QUICK];
165 const void ** vals = vals_q;
166
167 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
168 if (n_services == 0) {
169 return; // if no services
170 }
171
172 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
173 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
174 vals = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
175 }
176
177 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
178
179 CFDictionaryGetKeysAndValues(services, keys, vals);
180 for (i = 0; i < n_services; i++) {
181 uint32_t defaultOrder;
182 CFDictionaryRef proxy;
183 CFMutableDictionaryRef proxyWithDNS = NULL;
184 CFDictionaryRef service = (CFDictionaryRef)vals[i];
185
186 if (!isA_CFDictionary(service)) {
187 continue;
188 }
189
190 proxy = CFDictionaryGetValue(service, kSCEntNetProxies);
191 if (!isA_CFDictionary(proxy)) {
192 continue;
193 }
194
195 if ((G_supplemental_proxies_follow_dns != NULL) && CFBooleanGetValue(G_supplemental_proxies_follow_dns)) {
196 CFDictionaryRef dns;
197 CFArrayRef matchDomains;
198 CFArrayRef matchOrders;
199
200 if (!CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomains) &&
201 CFDictionaryGetValueIfPresent(service, kSCEntNetDNS, (const void **)&dns) &&
202 isA_CFDictionary(dns) &&
203 CFDictionaryGetValueIfPresent(dns, kSCPropNetDNSSupplementalMatchDomains, (const void **)&matchDomains) &&
204 isA_CFArray(matchDomains)) {
205 proxyWithDNS = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
206 CFDictionarySetValue(proxyWithDNS, kSCPropNetProxiesSupplementalMatchDomains, matchDomains);
207 if (CFDictionaryGetValueIfPresent(dns, kSCPropNetDNSSupplementalMatchOrders, (const void **)&matchOrders) &&
208 isA_CFArray(matchOrders)) {
209 CFDictionarySetValue(proxyWithDNS, kSCPropNetProxiesSupplementalMatchOrders, matchOrders);
210 } else {
211 CFDictionaryRemoveValue(proxyWithDNS, kSCPropNetProxiesSupplementalMatchOrders);
212 }
213 proxy = proxyWithDNS;
214 }
215 }
216
217 defaultOrder = DEFAULT_MATCH_ORDER
218 - (DEFAULT_MATCH_ORDER / 2)
219 + ((DEFAULT_MATCH_ORDER / 1000) * (uint32_t)i);
220 if ((n_order > 0) &&
221 !CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) {
222 // push out services not specified in service order
223 defaultOrder += (DEFAULT_MATCH_ORDER / 1000) * n_services;
224 }
225
226 add_supplemental(proxies, proxy, defaultOrder);
227 if (proxyWithDNS != NULL) CFRelease(proxyWithDNS);
228 }
229
230 if (keys != keys_q) {
231 CFAllocatorDeallocate(NULL, keys);
232 CFAllocatorDeallocate(NULL, vals);
233 }
234
235 return;
236 }
237
238
239 static CFComparisonResult
240 compareBySearchOrder(const void *val1, const void *val2, void *context)
241 {
242 CFDictionaryRef proxy1 = (CFDictionaryRef)val1;
243 CFDictionaryRef proxy2 = (CFDictionaryRef)val2;
244 CFNumberRef num1;
245 CFNumberRef num2;
246 uint32_t order1 = DEFAULT_MATCH_ORDER;
247 uint32_t order2 = DEFAULT_MATCH_ORDER;
248
249 num1 = CFDictionaryGetValue(proxy1, PROXY_MATCH_ORDER_KEY);
250 if (!isA_CFNumber(num1) ||
251 !CFNumberGetValue(num1, kCFNumberSInt32Type, &order1)) {
252 order1 = DEFAULT_MATCH_ORDER;
253 }
254
255 num2 = CFDictionaryGetValue(proxy2, PROXY_MATCH_ORDER_KEY);
256 if (!isA_CFNumber(num2) ||
257 !CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
258 order2 = DEFAULT_MATCH_ORDER;
259 }
260
261 if (order1 == order2) {
262 // if same match "order", retain original ordering for configurations
263 if (CFDictionaryGetValueIfPresent(proxy1, ORDER_KEY, (const void **)&num1) &&
264 CFDictionaryGetValueIfPresent(proxy2, ORDER_KEY, (const void **)&num2) &&
265 isA_CFNumber(num1) &&
266 isA_CFNumber(num2) &&
267 CFNumberGetValue(num1, kCFNumberSInt32Type, &order1) &&
268 CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
269 if (order1 == order2) {
270 return kCFCompareEqualTo;
271 } else {
272 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
273 }
274 }
275
276 return kCFCompareEqualTo;
277 }
278
279 return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan;
280 }
281
282
283 static __inline__ Boolean
284 isSupplementalProxy(CFDictionaryRef proxy)
285 {
286 if ((proxy != NULL) &&
287 CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) {
288 return TRUE;
289 }
290
291 return FALSE;
292 }
293
294
295 static CFArrayRef
296 copy_supplemental_proxies(CFArrayRef proxies, Boolean skip)
297 {
298 CFIndex i;
299 CFIndex n_proxies;
300 CFMutableArrayRef supplemental = NULL;
301
302 // iterate over services
303
304 n_proxies = isA_CFArray(proxies) ? CFArrayGetCount(proxies) : 0;
305 for (i = 0; i < n_proxies; i++) {
306 CFDictionaryRef proxy;
307
308 proxy = CFArrayGetValueAtIndex(proxies, i);
309 if (!isSupplementalProxy(proxy)) {
310 // if not supplemental proxy (i.e. no match domain)
311 continue;
312 }
313
314 // add [supplemental] proxy entry
315 if (supplemental == NULL) {
316 supplemental = CFArrayCreateMutable(NULL,
317 0,
318 &kCFTypeArrayCallBacks);
319 }
320 CFArrayAppendValue(supplemental, proxy);
321 }
322
323 return supplemental;
324 }
325
326
327 static CFArrayRef
328 service_order_copy_all(CFDictionaryRef services, CFArrayRef service_order)
329 {
330 const void * keys_q[N_QUICK];
331 const void ** keys = keys_q;
332 CFIndex i;
333 CFIndex n_order;
334 CFIndex n_services;
335 CFMutableArrayRef order;
336
337 // ensure that we process all services in order
338 n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
339 if (n_services == 0) {
340 // if no services
341 return NULL;
342 }
343
344 // ensure that we process all services in order
345
346 n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
347 if (n_order > 0) {
348 order = CFArrayCreateMutableCopy(NULL, 0, service_order);
349 } else {
350 order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
351 }
352
353 if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
354 keys = CFAllocatorAllocate(NULL, n_services * sizeof(CFTypeRef), 0);
355 }
356 CFDictionaryGetKeysAndValues(services, keys, NULL);
357 for (i = 0; i < n_services; i++) {
358 CFStringRef serviceID = (CFStringRef)keys[i];
359
360 if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) {
361 CFArrayAppendValue(order, serviceID);
362 n_order++;
363 }
364 }
365 if (keys != keys_q) {
366 CFAllocatorDeallocate(NULL, keys);
367 }
368
369 return order;
370 }
371
372
373 static CFDictionaryRef
374 copy_app_layer_vpn_proxies(CFDictionaryRef services, CFArrayRef order, CFDictionaryRef services_info)
375 {
376 CFMutableDictionaryRef app_layer_proxies = NULL;
377 CFIndex i;
378 CFIndex n_order;
379
380 if (!isA_CFDictionary(services_info)) {
381 return NULL;
382 }
383
384 // iterate over services
385
386 n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0;
387 for (i = 0; i < n_order; i++) {
388 CFMutableDictionaryRef newProxy;
389 CFDictionaryRef proxy;
390 CFDictionaryRef service;
391 CFStringRef serviceID;
392 CFNumberRef serviceSpecificIdentifier;
393 int serviceIdentifier = 0;
394 CFStringRef serviceIdentifierString;
395
396 serviceID = CFArrayGetValueAtIndex(order, i);
397 service = CFDictionaryGetValue(services, serviceID);
398 if (!isA_CFDictionary(service)) {
399 // if no service
400 continue;
401 }
402
403 proxy = CFDictionaryGetValue(service, kSCEntNetProxies);
404 if (!isA_CFDictionary(proxy)) {
405 // if no proxy
406 continue;
407 }
408
409 serviceSpecificIdentifier = CFDictionaryGetValue(proxy, kSCPropNetProxiesServiceSpecific);
410 if (!isA_CFNumber(serviceSpecificIdentifier) ||
411 !CFNumberGetValue(serviceSpecificIdentifier, kCFNumberIntType, &serviceIdentifier) ||
412 serviceIdentifier == 0) {
413 // if not a service-specific proxy configuration
414 continue;
415 }
416
417 serviceIdentifierString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), serviceIdentifier);
418 if (serviceIdentifierString == NULL) {
419 continue;
420 }
421 if ((app_layer_proxies != NULL) &&
422 CFDictionaryContainsKey(app_layer_proxies, serviceIdentifierString)) {
423 // if we've already processed this [app_layer_proxies] identifier
424 CFRelease(serviceIdentifierString);
425 continue;
426 }
427
428 // add [app_layer_proxies] proxy entry
429 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
430 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains);
431 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders);
432 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesServiceSpecific);
433 if (app_layer_proxies == NULL) {
434 app_layer_proxies = CFDictionaryCreateMutable(NULL,
435 0,
436 &kCFTypeDictionaryKeyCallBacks,
437 &kCFTypeDictionaryValueCallBacks);
438 }
439 CFDictionarySetValue(app_layer_proxies, serviceIdentifierString, newProxy);
440 CFRelease(serviceIdentifierString);
441 CFRelease(newProxy);
442 }
443
444 return app_layer_proxies;
445 }
446
447
448 static CFDictionaryRef
449 copy_scoped_proxies(CFDictionaryRef services, CFArrayRef order)
450 {
451 CFIndex i;
452 CFIndex n_order;
453 CFMutableDictionaryRef scoped = NULL;
454
455 // iterate over services
456
457 n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0;
458 for (i = 0; i < n_order; i++) {
459 char if_name[IF_NAMESIZE];
460 CFStringRef interface;
461 CFMutableDictionaryRef newProxy;
462 CFDictionaryRef proxy;
463 CFDictionaryRef service;
464 CFStringRef serviceID;
465
466 serviceID = CFArrayGetValueAtIndex(order, i);
467 service = CFDictionaryGetValue(services, serviceID);
468 if (!isA_CFDictionary(service)) {
469 // if no service
470 continue;
471 }
472
473 proxy = CFDictionaryGetValue(service, kSCEntNetProxies);
474 if (!isA_CFDictionary(proxy)) {
475 // if no proxy
476 continue;
477 }
478
479 interface = CFDictionaryGetValue(proxy, kSCPropInterfaceName);
480 if (interface == NULL) {
481 // if no [scoped] interface
482 continue;
483 }
484 if ((scoped != NULL) &&
485 CFDictionaryContainsKey(scoped, interface)) {
486 // if we've already processed this [scoped] interface
487 continue;
488 }
489
490 if ((_SC_cfstring_to_cstring(interface,
491 if_name,
492 sizeof(if_name),
493 kCFStringEncodingASCII) == NULL) ||
494 ((my_if_nametoindex(if_name)) == 0)) {
495 // if interface index not available
496 continue;
497 }
498
499 // add [scoped] proxy entry
500 // ... and remove keys we don't want in a [scoped] proxy
501 CFRetain(interface);
502 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
503 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains);
504 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders);
505 CFDictionaryRemoveValue(newProxy, kSCPropInterfaceName);
506 if (scoped == NULL) {
507 scoped = CFDictionaryCreateMutable(NULL,
508 0,
509 &kCFTypeDictionaryKeyCallBacks,
510 &kCFTypeDictionaryValueCallBacks);
511 }
512 CFDictionarySetValue(scoped, interface, newProxy);
513 CFRelease(newProxy);
514 CFRelease(interface);
515 }
516
517 return scoped;
518 }
519
520
521 static void
522 add_default_proxy(CFMutableArrayRef proxies,
523 CFDictionaryRef defaultProxy,
524 Boolean *orderAdded)
525 {
526 CFMutableDictionaryRef myDefault;
527 uint32_t myOrder = DEFAULT_MATCH_ORDER;
528 CFNumberRef order = NULL;
529
530 if (defaultProxy == NULL) {
531 myDefault = CFDictionaryCreateMutable(NULL,
532 0,
533 &kCFTypeDictionaryKeyCallBacks,
534 &kCFTypeDictionaryValueCallBacks);
535 } else {
536 myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultProxy);
537 CFDictionaryRemoveValue(myDefault, kSCPropInterfaceName);
538 order = CFDictionaryGetValue(myDefault, PROXY_MATCH_ORDER_KEY);
539 }
540
541 // ensure that the default proxy has a search order
542
543 if (!isA_CFNumber(order) ||
544 !CFNumberGetValue(order, kCFNumberSInt32Type, &myOrder)) {
545 myOrder = DEFAULT_MATCH_ORDER;
546 order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
547 CFDictionarySetValue(myDefault, PROXY_MATCH_ORDER_KEY, order);
548 CFRelease(order);
549 *orderAdded = TRUE;
550 }
551
552 // add the default proxy
553
554 add_proxy(proxies, myDefault);
555 CFRelease(myDefault);
556 return;
557 }
558
559
560 static CFComparisonResult
561 compareDomain(const void *val1, const void *val2, void *context)
562 {
563 CFDictionaryRef proxy1 = (CFDictionaryRef)val1;
564 CFDictionaryRef proxy2 = (CFDictionaryRef)val2;
565 CFStringRef domain1;
566 CFStringRef domain2;
567 CFArrayRef labels1 = NULL;
568 CFArrayRef labels2 = NULL;
569 CFIndex n1;
570 CFIndex n2;
571 CFComparisonResult result;
572 Boolean rev1;
573 Boolean rev2;
574
575 // "default" domains sort before "supplemental" domains
576 domain1 = CFDictionaryGetValue(proxy1, kSCPropNetProxiesSupplementalMatchDomain);
577 domain2 = CFDictionaryGetValue(proxy2, kSCPropNetProxiesSupplementalMatchDomain);
578 if (domain1 == NULL) {
579 if (domain2 == NULL) {
580 return kCFCompareEqualTo;
581 }
582 return kCFCompareLessThan;
583 } else if (domain2 == NULL) {
584 return kCFCompareGreaterThan;
585 }
586
587 // forward (A, AAAA) domains sort before reverse (PTR) domains
588 rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa"));
589 rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa"));
590 if (rev1 != rev2) {
591 if (rev1) {
592 return kCFCompareGreaterThan;
593 } else {
594 return kCFCompareLessThan;
595 }
596 }
597
598 labels1 = CFStringCreateArrayBySeparatingStrings(NULL, domain1, CFSTR("."));
599 n1 = CFArrayGetCount(labels1);
600
601 labels2 = CFStringCreateArrayBySeparatingStrings(NULL, domain2, CFSTR("."));
602 n2 = CFArrayGetCount(labels2);
603
604 while ((n1 > 0) && (n2 > 0)) {
605 CFStringRef label1 = CFArrayGetValueAtIndex(labels1, --n1);
606 CFStringRef label2 = CFArrayGetValueAtIndex(labels2, --n2);
607
608 // compare domain labels
609 result = CFStringCompare(label1, label2, kCFCompareCaseInsensitive);
610 if (result != kCFCompareEqualTo) {
611 goto done;
612 }
613 }
614
615 // longer labels (corp.apple.com) sort before shorter labels (apple.com)
616 if (n1 > n2) {
617 result = kCFCompareLessThan;
618 goto done;
619 } else if (n1 < n2) {
620 result = kCFCompareGreaterThan;
621 goto done;
622 }
623
624 // sort by search order
625 result = compareBySearchOrder(val1, val2, context);
626
627 done :
628
629 if (labels1 != NULL) CFRelease(labels1);
630 if (labels2 != NULL) CFRelease(labels2);
631 return result;
632 }
633
634
635 __private_extern__
636 CF_RETURNS_RETAINED CFDictionaryRef
637 proxy_configuration_update(CFDictionaryRef defaultProxy,
638 CFDictionaryRef services,
639 CFArrayRef serviceOrder,
640 CFDictionaryRef servicesInfo)
641 {
642 CFIndex i;
643 CFMutableDictionaryRef myDefault;
644 Boolean myOrderAdded = FALSE;
645 CFMutableDictionaryRef newProxy = NULL;
646 CFIndex n_proxies;
647 CFDictionaryRef proxy;
648 CFMutableArrayRef proxies;
649
650 // establish full list of proxies
651
652 proxies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
653
654 // collect (and add) any "supplemental" proxy configurations
655
656 add_supplemental_proxies(proxies, services, serviceOrder);
657
658 // add the "default" proxy
659
660 add_default_proxy(proxies, defaultProxy, &myOrderAdded);
661
662 // sort proxies, cleanup
663
664 n_proxies = CFArrayGetCount(proxies);
665 if (n_proxies > 1) {
666 CFArraySortValues(proxies, CFRangeMake(0, n_proxies), compareDomain, NULL);
667 }
668
669 // cleanup
670
671 for (i = n_proxies - 1; i >= 0; i--) {
672 proxy = CFArrayGetValueAtIndex(proxies, i);
673
674 if ((i > 0) &&
675 !CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) {
676 // remove non-supplemental proxy
677 CFArrayRemoveValueAtIndex(proxies, i);
678 n_proxies--;
679 continue;
680 }
681
682 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
683 CFDictionaryRemoveValue(newProxy, PROXY_MATCH_ORDER_KEY);
684 CFDictionaryRemoveValue(newProxy, ORDER_KEY);
685 CFArraySetValueAtIndex(proxies, i, newProxy);
686 CFRelease(newProxy);
687 }
688
689 // update the default proxy
690
691 myDefault = CFDictionaryCreateMutableCopy(NULL,
692 0,
693 CFArrayGetValueAtIndex(proxies, 0));
694 if (myOrderAdded && (n_proxies > 1)) {
695 CFDictionaryRef proxy;
696
697 proxy = CFArrayGetValueAtIndex(proxies, 1);
698 if (CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) {
699 // if not a supplemental "default" proxy (a match domain name is
700 // present)
701 CFDictionaryRemoveValue(myDefault, PROXY_MATCH_ORDER_KEY);
702 }
703 }
704 CFArraySetValueAtIndex(proxies, 0, myDefault);
705 CFRelease(myDefault);
706
707 // establish proxy configuration
708
709 if (n_proxies > 0) {
710 CFDictionaryRef app_layer;
711 CFDictionaryRef scoped;
712 CFArrayRef serviceOrderAll;
713 Boolean skip = FALSE;
714 CFArrayRef supplemental;
715
716 proxy = CFArrayGetValueAtIndex(proxies, 0);
717 if (!CFDictionaryContainsKey(proxy, kSCPropNetProxiesSupplementalMatchDomain)) {
718 // if we have "a" default (non-supplemental) proxy
719 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
720 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains);
721 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders);
722 skip = TRUE;
723 } else {
724 newProxy = CFDictionaryCreateMutable(NULL,
725 0,
726 &kCFTypeDictionaryKeyCallBacks,
727 &kCFTypeDictionaryValueCallBacks);
728 }
729
730 serviceOrderAll = service_order_copy_all(services, serviceOrder);
731
732 // collect (and add) any "supplemental" proxy configurations
733
734 supplemental = copy_supplemental_proxies(proxies, skip);
735 if (supplemental != NULL) {
736 CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, supplemental);
737 CFRelease(supplemental);
738 }
739
740 // collect (and add) any "scoped" proxy configurations
741
742 scoped = copy_scoped_proxies(services, serviceOrderAll);
743 if (scoped != NULL) {
744 CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, scoped);
745 CFRelease(scoped);
746 }
747
748 // collect (and add) any "services" based proxy configurations
749
750 app_layer = copy_app_layer_vpn_proxies(services, serviceOrderAll, servicesInfo);
751 if (app_layer != NULL) {
752 CFDictionarySetValue(newProxy, kSCPropNetProxiesServices, app_layer);
753 CFRelease(app_layer);
754 }
755
756 if (serviceOrderAll != NULL) {
757 CFRelease(serviceOrderAll);
758 }
759 } else {
760 newProxy = NULL;
761 }
762
763 CFRelease(proxies);
764 return newProxy;
765 }
766
767
768 __private_extern__
769 void
770 proxy_configuration_init(CFBundleRef bundle)
771 {
772 CFDictionaryRef dict;
773
774 dict = CFBundleGetInfoDictionary(bundle);
775 if (isA_CFDictionary(dict)) {
776 G_supplemental_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS"));
777 G_supplemental_proxies_follow_dns = isA_CFBoolean(G_supplemental_proxies_follow_dns);
778 }
779
780 return;
781 }
782
783
784 #pragma mark -
785 #pragma mark Standalone test code
786
787
788 #ifdef MAIN
789
790 static void
791 mergeDict(const void *key, const void *value, void *context)
792 {
793 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
794
795 CFDictionarySetValue(newDict, key, value);
796 return;
797 }
798
799
800 static void
801 split(const void * key, const void * value, void * context)
802 {
803 CFArrayRef components;
804 CFStringRef entity_id;
805 CFStringRef service_id;
806 CFMutableDictionaryRef state_dict;
807
808 components = CFStringCreateArrayBySeparatingStrings(NULL, (CFStringRef)key, CFSTR("/"));
809 service_id = CFArrayGetValueAtIndex(components, 3);
810 entity_id = CFArrayGetValueAtIndex(components, 4);
811 state_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(context, service_id);
812 if (state_dict != NULL) {
813 state_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
814 } else {
815 state_dict = CFDictionaryCreateMutable(NULL,
816 0,
817 &kCFTypeDictionaryKeyCallBacks,
818 &kCFTypeDictionaryValueCallBacks);
819 }
820
821 if (CFEqual(entity_id, kSCEntNetIPv4) ||
822 CFEqual(entity_id, kSCEntNetIPv6)) {
823 CFStringRef interface;
824
825 interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName);
826 if (interface != NULL) {
827 CFDictionaryRef proxy;
828 CFMutableDictionaryRef new_proxy;
829
830 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies);
831 if (proxy != NULL) {
832 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
833 } else {
834 new_proxy = CFDictionaryCreateMutable(NULL,
835 0,
836 &kCFTypeDictionaryKeyCallBacks,
837 &kCFTypeDictionaryValueCallBacks);
838 }
839 CFDictionarySetValue(new_proxy, kSCPropInterfaceName, interface);
840 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy);
841 CFRelease(new_proxy);
842 }
843 } else if (CFEqual(entity_id, kSCEntNetProxies)) {
844 CFDictionaryRef proxy;
845
846 proxy = CFDictionaryGetValue(state_dict, kSCEntNetProxies);
847 if (proxy != NULL) {
848 CFStringRef domain;
849 CFMutableDictionaryRef new_proxy;
850
851 // if we already have some Setup: or State: proxy content
852 domain = CFArrayGetValueAtIndex(components, 0);
853 if (CFEqual(domain, kSCDynamicStoreDomainState)) {
854 // if we've already seen the Setup: key
855 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
856 CFDictionaryApplyFunction(proxy, mergeDict, new_proxy);
857 } else {
858 // if we've already seen the State: key
859 new_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
860 CFDictionaryApplyFunction((CFDictionaryRef)value, mergeDict, new_proxy);
861 }
862 CFDictionarySetValue(state_dict, kSCEntNetProxies, new_proxy);
863 CFRelease(new_proxy);
864 } else {
865 CFDictionarySetValue(state_dict, kSCEntNetProxies, (CFDictionaryRef)value);
866 }
867 } else {
868 CFDictionarySetValue(state_dict, entity_id, (CFDictionaryRef)value);
869 }
870
871 CFDictionarySetValue((CFMutableDictionaryRef)context, service_id, state_dict);
872 CFRelease(state_dict);
873 CFRelease(components);
874
875 return;
876 }
877
878 int
879 main(int argc, char **argv)
880 {
881 CFDictionaryRef entities;
882 CFStringRef key;
883 CFDictionaryRef newProxy = NULL;
884 CFStringRef pattern;
885 CFMutableArrayRef patterns;
886 CFStringRef primary = NULL;
887 CFMutableDictionaryRef primary_proxy = NULL;
888 CFArrayRef service_order = NULL;
889 CFMutableDictionaryRef service_state_dict;
890 CFDictionaryRef setup_global_ipv4;
891 CFDictionaryRef state_global_ipv4;
892 SCDynamicStoreRef store;
893
894 _sc_log = FALSE;
895 _sc_verbose = (argc > 1) ? TRUE : FALSE;
896
897 store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
898
899 // get IPv4, IPv6, and Proxies entities
900 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
901 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
902 kSCDynamicStoreDomainState,
903 kSCCompAnyRegex,
904 kSCEntNetIPv4);
905 CFArrayAppendValue(patterns, pattern);
906 CFRelease(pattern);
907 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
908 kSCDynamicStoreDomainState,
909 kSCCompAnyRegex,
910 kSCEntNetIPv6);
911 CFArrayAppendValue(patterns, pattern);
912 CFRelease(pattern);
913 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
914 kSCDynamicStoreDomainSetup,
915 kSCCompAnyRegex,
916 kSCEntNetProxies);
917 CFArrayAppendValue(patterns, pattern);
918 CFRelease(pattern);
919 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
920 kSCDynamicStoreDomainState,
921 kSCCompAnyRegex,
922 kSCEntNetProxies);
923 CFArrayAppendValue(patterns, pattern);
924 CFRelease(pattern);
925 entities = SCDynamicStoreCopyMultiple(store, NULL, patterns);
926 CFRelease(patterns);
927
928 service_state_dict = CFDictionaryCreateMutable(NULL,
929 0,
930 &kCFTypeDictionaryKeyCallBacks,
931 &kCFTypeDictionaryValueCallBacks);
932 CFDictionaryApplyFunction(entities, split, service_state_dict);
933 CFRelease(entities);
934
935 // get primary service ID
936 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
937 kSCDynamicStoreDomainState,
938 kSCEntNetIPv4);
939 state_global_ipv4 = SCDynamicStoreCopyValue(store, key);
940 CFRelease(key);
941 if (state_global_ipv4 != NULL) {
942 primary = CFDictionaryGetValue(state_global_ipv4, kSCDynamicStorePropNetPrimaryService);
943 if (primary != NULL) {
944 CFDictionaryRef service_dict;
945
946 // get proxy configuration for primary service
947 service_dict = CFDictionaryGetValue(service_state_dict, primary);
948 if (service_dict != NULL) {
949 CFDictionaryRef service_proxy;
950
951 service_proxy = CFDictionaryGetValue(service_dict, kSCEntNetProxies);
952 if (service_proxy != NULL) {
953 primary_proxy = CFDictionaryCreateMutableCopy(NULL, 0, service_proxy);
954 CFDictionaryRemoveValue(primary_proxy, kSCPropInterfaceName);
955 }
956 }
957 }
958 }
959
960 // get serviceOrder
961 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
962 kSCDynamicStoreDomainSetup,
963 kSCEntNetIPv4);
964 setup_global_ipv4 = SCDynamicStoreCopyValue(store, key);
965 CFRelease(key);
966 if (setup_global_ipv4 != NULL) {
967 service_order = CFDictionaryGetValue(setup_global_ipv4, kSCPropNetServiceOrder);
968 }
969
970 // update proxy configuration
971 proxy_configuration_init(CFBundleGetMainBundle());
972 newProxy = proxy_configuration_update(primary_proxy,
973 service_state_dict,
974 service_order,
975 NULL);
976 if (newProxy != NULL) {
977 SCPrint(TRUE, stdout, CFSTR("%@\n"), newProxy);
978 CFRelease(newProxy);
979 }
980
981 // cleanup
982 if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
983 if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
984 CFRelease(service_state_dict);
985 CFRelease(store);
986
987 /* not reached */
988 exit(0);
989 return 0;
990 }
991 #endif
992