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