]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCProxies.c
configd-1061.80.3.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCProxies.c
1 /*
2 * Copyright (c) 2000-2004, 2006-2013, 2015, 2016 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 * May 18, 2001 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <TargetConditionals.h>
32 #include <SystemConfiguration/SystemConfiguration.h>
33 #include <SystemConfiguration/SCValidation.h>
34 #include <SystemConfiguration/SCPrivate.h>
35 #include <SystemConfiguration/VPNAppLayerPrivate.h>
36
37 #include <netdb.h>
38 #if !TARGET_OS_SIMULATOR
39 #include <ne_session.h>
40 #endif // !TARGET_OS_SIMULATOR
41
42 CFStringRef
43 SCDynamicStoreKeyCreateProxies(CFAllocatorRef allocator)
44 {
45 return SCDynamicStoreKeyCreateNetworkGlobalEntity(allocator,
46 kSCDynamicStoreDomainState,
47 kSCEntNetProxies);
48 }
49
50
51 static void
52 validate_proxy_content(CFMutableDictionaryRef proxies,
53 CFStringRef proxy_enable,
54 CFStringRef proxy_host,
55 CFStringRef proxy_port,
56 const char * proxy_service,
57 int proxy_defaultport)
58 {
59 int enabled = 0;
60 CFNumberRef num;
61
62 num = CFDictionaryGetValue(proxies, proxy_enable);
63 if (num != NULL) {
64 if (!isA_CFNumber(num) ||
65 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
66 goto disable; // if we don't like the enabled key/value
67 }
68 }
69
70 if (proxy_host != NULL) {
71 CFStringRef host;
72
73 host = CFDictionaryGetValue(proxies, proxy_host);
74 if ((enabled == 0) && (host != NULL)) {
75 goto disable; // if not enabled, remove provided key/value
76 }
77
78 if ((enabled != 0) &&
79 (!isA_CFString(host) || (CFStringGetLength(host) == 0))) {
80 goto disable; // if enabled, not provided (or not valid)
81 }
82 }
83
84 if (proxy_port != NULL) {
85 CFNumberRef port;
86 int s_port = 0;
87
88 port = CFDictionaryGetValue(proxies, proxy_port);
89 if ((enabled == 0) && (port != NULL)) {
90 goto disable; // if not enabled, remove provided key/value
91 }
92
93 if ((enabled != 0) && (port != NULL)) {
94 if (!isA_CFNumber(port) ||
95 !CFNumberGetValue(port, kCFNumberIntType, &s_port) ||
96 (s_port > UINT16_MAX)) {
97 goto disable; // if enabled, not provided (or not valid)
98 }
99
100 if (s_port == 0) {
101 port = NULL; // if no port # provided, use default
102 }
103 }
104
105 if ((enabled != 0) && (port == NULL)) {
106 struct servent *service;
107
108 service = getservbyname(proxy_service, "tcp");
109 if (service != NULL) {
110 s_port = ntohs(service->s_port);
111 } else {
112 s_port = proxy_defaultport;
113 }
114 num = CFNumberCreate(NULL, kCFNumberIntType, &s_port);
115 CFDictionarySetValue(proxies, proxy_port, num);
116 CFRelease(num);
117 }
118 }
119
120 return;
121
122 disable :
123
124 enabled = 0;
125 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
126 CFDictionarySetValue(proxies, proxy_enable, num);
127 CFRelease(num);
128 if (proxy_host != NULL) {
129 CFDictionaryRemoveValue(proxies, proxy_host);
130 }
131 if (proxy_port != NULL) {
132 CFDictionaryRemoveValue(proxies, proxy_port);
133 }
134
135 return;
136 }
137
138
139 static void
140 normalize_scoped_proxy(const void *key, const void *value, void *context);
141
142
143 static void
144 normalize_services_proxy(const void *key, const void *value, void *context);
145
146
147 static void
148 normalize_supplemental_proxy(const void *value, void *context);
149
150
151 static CF_RETURNS_RETAINED CFDictionaryRef
152 __SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy)
153 {
154 CFArrayRef array;
155 CFMutableDictionaryRef newProxy;
156 CFNumberRef num;
157 CFDictionaryRef scoped;
158 CFDictionaryRef services;
159 CFArrayRef supplemental;
160
161 if (!isA_CFDictionary(proxy)) {
162 proxy = CFDictionaryCreate(NULL,
163 NULL,
164 NULL,
165 0,
166 &kCFTypeDictionaryKeyCallBacks,
167 &kCFTypeDictionaryValueCallBacks);
168 return proxy;
169 }
170
171 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
172
173 validate_proxy_content(newProxy,
174 kSCPropNetProxiesFTPEnable,
175 kSCPropNetProxiesFTPProxy,
176 kSCPropNetProxiesFTPPort,
177 "ftp",
178 21);
179 validate_proxy_content(newProxy,
180 kSCPropNetProxiesGopherEnable,
181 kSCPropNetProxiesGopherProxy,
182 kSCPropNetProxiesGopherPort,
183 "gopher",
184 70);
185 validate_proxy_content(newProxy,
186 kSCPropNetProxiesHTTPEnable,
187 kSCPropNetProxiesHTTPProxy,
188 kSCPropNetProxiesHTTPPort,
189 "http",
190 80);
191 validate_proxy_content(newProxy,
192 kSCPropNetProxiesHTTPSEnable,
193 kSCPropNetProxiesHTTPSProxy,
194 kSCPropNetProxiesHTTPSPort,
195 "https",
196 443);
197 validate_proxy_content(newProxy,
198 kSCPropNetProxiesRTSPEnable,
199 kSCPropNetProxiesRTSPProxy,
200 kSCPropNetProxiesRTSPPort,
201 "rtsp",
202 554);
203 validate_proxy_content(newProxy,
204 kSCPropNetProxiesSOCKSEnable,
205 kSCPropNetProxiesSOCKSProxy,
206 kSCPropNetProxiesSOCKSPort,
207 "socks",
208 1080);
209 if (CFDictionaryContainsKey(newProxy, kSCPropNetProxiesProxyAutoConfigURLString)) {
210 validate_proxy_content(newProxy,
211 kSCPropNetProxiesProxyAutoConfigEnable,
212 kSCPropNetProxiesProxyAutoConfigURLString,
213 NULL,
214 NULL,
215 0);
216
217 // and we can't have both URLString and JavaScript keys
218 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesProxyAutoConfigJavaScript);
219 } else {
220 validate_proxy_content(newProxy,
221 kSCPropNetProxiesProxyAutoConfigEnable,
222 kSCPropNetProxiesProxyAutoConfigJavaScript,
223 NULL,
224 NULL,
225 0);
226 }
227 validate_proxy_content(newProxy,
228 kSCPropNetProxiesProxyAutoDiscoveryEnable,
229 NULL,
230 NULL,
231 NULL,
232 0);
233
234 validate_proxy_content(newProxy,
235 kSCPropNetProxiesFallBackAllowed,
236 NULL,
237 NULL,
238 NULL,
239 0);
240
241 // validate FTP passive setting
242 num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesFTPPassive);
243 if (num != NULL) {
244 int enabled = 0;
245
246 if (!isA_CFNumber(num) ||
247 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
248 // if we don't like the enabled key/value
249 enabled = 1;
250 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
251 CFDictionarySetValue(newProxy,
252 kSCPropNetProxiesFTPPassive,
253 num);
254 CFRelease(num);
255 }
256 }
257
258 // validate proxy exception list
259 array = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExceptionsList);
260 if (array != NULL) {
261 CFIndex i;
262 CFIndex n;
263
264 n = isA_CFArray(array) ? CFArrayGetCount(array) : 0;
265 for (i = 0; i < n; i++) {
266 CFStringRef str;
267
268 str = CFArrayGetValueAtIndex(array, i);
269 if (!isA_CFString(str) || (CFStringGetLength(str) == 0)) {
270 // if we don't like the array contents
271 n = 0;
272 break;
273 }
274 }
275
276 if (n == 0) {
277 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesExceptionsList);
278 }
279 }
280
281 // validate exclude simple hostnames setting
282 num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExcludeSimpleHostnames);
283 if (num != NULL) {
284 int enabled;
285
286 if (!isA_CFNumber(num) ||
287 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
288 // if we don't like the enabled key/value
289 enabled = 0;
290 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
291 CFDictionarySetValue(newProxy,
292 kSCPropNetProxiesExcludeSimpleHostnames,
293 num);
294 CFRelease(num);
295 }
296 }
297
298 // cleanup scoped proxies
299 scoped = CFDictionaryGetValue(newProxy, kSCPropNetProxiesScoped);
300 if (isA_CFDictionary(scoped)) {
301 CFMutableDictionaryRef newScoped;
302
303 newScoped = CFDictionaryCreateMutable(NULL,
304 0,
305 &kCFTypeDictionaryKeyCallBacks,
306 &kCFTypeDictionaryValueCallBacks);
307 CFDictionaryApplyFunction(scoped,
308 normalize_scoped_proxy,
309 newScoped);
310 CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, newScoped);
311 CFRelease(newScoped);
312 }
313
314 // cleanup services proxies
315 services = CFDictionaryGetValue(newProxy, kSCPropNetProxiesServices);
316 if (isA_CFDictionary(services)) {
317 CFMutableDictionaryRef newServices;
318
319 newServices = CFDictionaryCreateMutable(NULL,
320 0,
321 &kCFTypeDictionaryKeyCallBacks,
322 &kCFTypeDictionaryValueCallBacks);
323 CFDictionaryApplyFunction(services,
324 normalize_services_proxy,
325 newServices);
326 CFDictionarySetValue(newProxy, kSCPropNetProxiesServices, newServices);
327 CFRelease(newServices);
328 }
329
330 // cleanup split/supplemental proxies
331 supplemental = CFDictionaryGetValue(newProxy, kSCPropNetProxiesSupplemental);
332 if (isA_CFArray(supplemental)) {
333 CFMutableArrayRef newSupplemental;
334
335 newSupplemental = CFArrayCreateMutable(NULL,
336 0,
337 &kCFTypeArrayCallBacks);
338 CFArrayApplyFunction(supplemental,
339 CFRangeMake(0, CFArrayGetCount(supplemental)),
340 normalize_supplemental_proxy,
341 newSupplemental);
342 CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, newSupplemental);
343 CFRelease(newSupplemental);
344 }
345
346 proxy = CFDictionaryCreateCopy(NULL,newProxy);
347 CFRelease(newProxy);
348
349 return proxy;
350 }
351
352
353 static void
354 normalize_scoped_proxy(const void *key, const void *value, void *context)
355 {
356 CFStringRef interface = (CFStringRef)key;
357 CFDictionaryRef proxy = (CFDictionaryRef)value;
358 CFMutableDictionaryRef newScoped = (CFMutableDictionaryRef)context;
359
360 proxy = __SCNetworkProxiesCopyNormalized(proxy);
361 CFDictionarySetValue(newScoped, interface, proxy);
362 CFRelease(proxy);
363
364 return;
365 }
366
367 static void
368 normalize_services_proxy(const void *key, const void *value, void *context)
369 {
370 CFNumberRef serviceIndex = (CFNumberRef)key;
371 CFDictionaryRef proxy = (CFDictionaryRef)value;
372 CFMutableDictionaryRef newServices = (CFMutableDictionaryRef)context;
373
374 proxy = __SCNetworkProxiesCopyNormalized(proxy);
375 CFDictionarySetValue(newServices, serviceIndex, proxy);
376 CFRelease(proxy);
377
378 return;
379 }
380
381 static void
382 normalize_supplemental_proxy(const void *value, void *context)
383 {
384 CFDictionaryRef proxy = (CFDictionaryRef)value;
385 CFMutableArrayRef newSupplemental = (CFMutableArrayRef)context;
386
387 proxy = __SCNetworkProxiesCopyNormalized(proxy);
388 CFArrayAppendValue(newSupplemental, proxy);
389 CFRelease(proxy);
390
391 return;
392 }
393
394 CFDictionaryRef
395 SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
396 {
397 return SCDynamicStoreCopyProxiesWithOptions(store, NULL);
398 }
399
400 const CFStringRef kSCProxiesNoGlobal = CFSTR("NO_GLOBAL");
401
402 CFDictionaryRef
403 SCDynamicStoreCopyProxiesWithOptions(SCDynamicStoreRef store, CFDictionaryRef options)
404 {
405 Boolean bypass = FALSE;
406 CFStringRef key;
407 CFDictionaryRef proxies = NULL;
408
409 if (options != NULL) {
410 CFBooleanRef bypassGlobalOption;
411
412 if (!isA_CFDictionary(options)) {
413 _SCErrorSet(kSCStatusInvalidArgument);
414 return NULL;
415 }
416
417 bypassGlobalOption = CFDictionaryGetValue(options, kSCProxiesNoGlobal);
418 if (isA_CFBoolean(bypassGlobalOption) && CFBooleanGetValue(bypassGlobalOption)) {
419 bypass = TRUE;
420 }
421 }
422
423
424 /* copy proxy information from dynamic store */
425
426 key = SCDynamicStoreKeyCreateProxies(NULL);
427 proxies = SCDynamicStoreCopyValue(store, key);
428 CFRelease(key);
429
430 if (isA_CFDictionary(proxies) &&
431 CFDictionaryContainsKey(proxies, kSCPropNetProxiesBypassAllowed)) {
432 CFMutableDictionaryRef newProxies;
433
434 newProxies = CFDictionaryCreateMutableCopy(NULL, 0, proxies);
435 CFRelease(proxies);
436
437 /*
438 * Remove kSCPropNetProxiesBypassAllowed property from network
439 * service based configurations.
440 */
441 CFDictionaryRemoveValue(newProxies, kSCPropNetProxiesBypassAllowed);
442 proxies = newProxies;
443 }
444
445
446 if (proxies != NULL) {
447 CFDictionaryRef base = proxies;
448
449 proxies = __SCNetworkProxiesCopyNormalized(base);
450 CFRelease(base);
451 } else {
452 proxies = CFDictionaryCreate(NULL,
453 NULL,
454 NULL,
455 0,
456 &kCFTypeDictionaryKeyCallBacks,
457 &kCFTypeDictionaryValueCallBacks);
458 }
459
460 return proxies;
461 }
462
463
464 static CFArrayRef
465 _SCNetworkProxiesCopyMatchingInternal(CFDictionaryRef globalConfiguration,
466 CFStringRef server,
467 CFStringRef interface,
468 CFDictionaryRef options)
469 {
470 CFMutableDictionaryRef newProxy;
471 uuid_t match_uuid;
472 CFArrayRef proxies = NULL;
473 CFDictionaryRef proxy;
474 int sc_status = kSCStatusOK;
475 CFStringRef trimmed = NULL;
476
477
478 if (!isA_CFDictionary(globalConfiguration)) {
479 // if no proxy configuration
480 _SCErrorSet(kSCStatusOK);
481 return NULL;
482 }
483
484 uuid_clear(match_uuid);
485
486 if (isA_CFDictionary(options)) {
487 CFUUIDRef euuid;
488
489 interface = CFDictionaryGetValue(options, kSCProxiesMatchInterface);
490 interface = isA_CFString(interface);
491
492 server = CFDictionaryGetValue(options, kSCProxiesMatchServer);
493 server = isA_CFString(server);
494
495 euuid = CFDictionaryGetValue(options, kSCProxiesMatchExecutableUUID);
496 euuid = isA_CFType(euuid, CFUUIDGetTypeID());
497 if (euuid != NULL) {
498 CFUUIDBytes uuid_bytes = CFUUIDGetUUIDBytes(euuid);
499 uuid_copy(match_uuid, (const uint8_t *)&uuid_bytes);
500 }
501 }
502
503 if (interface != NULL) {
504 CFDictionaryRef scoped;
505
506 if (!isA_CFString(interface) ||
507 (CFStringGetLength(interface) == 0)) {
508 _SCErrorSet(kSCStatusInvalidArgument);
509 return NULL;
510 }
511
512 scoped = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesScoped);
513 if (scoped == NULL) {
514 #if !TARGET_OS_SIMULATOR
515 if (CFDictionaryContainsKey(globalConfiguration, kSCPropNetProxiesBypassAllowed) &&
516 ne_session_always_on_vpn_configs_present()) {
517 /*
518 * The kSCPropNetProxiesBypassAllowed key will be present
519 * for managed proxy configurations where bypassing is *not*
520 * allowed.
521 *
522 * Also (for now), forcing the use of the managed proxy
523 * configurations will only be done with AOVPN present.
524 */
525 goto useDefault;
526 }
527 #endif // !TARGET_OS_SIMULATOR
528
529 // if no scoped proxy configurations
530 _SCErrorSet(kSCStatusOK);
531 return NULL;
532 }
533
534 if (!isA_CFDictionary(scoped)) {
535 // if corrupt proxy configuration
536 _SCErrorSet(kSCStatusFailed);
537 return NULL;
538 }
539
540 proxy = CFDictionaryGetValue(scoped, interface);
541 if (proxy == NULL) {
542 // if no scoped proxy configuration for this interface
543 _SCErrorSet(kSCStatusOK);
544 return NULL;
545 }
546
547 if (!isA_CFDictionary(proxy)) {
548 // if corrupt proxy configuration
549 _SCErrorSet(kSCStatusFailed);
550 return NULL;
551 }
552
553 // return per-interface proxy configuration
554 proxies = CFArrayCreate(NULL, (const void **)&proxy, 1, &kCFTypeArrayCallBacks);
555 return proxies;
556 }
557
558
559 if (server != NULL) {
560 CFIndex i;
561 CFMutableArrayRef matching = NULL;
562 CFIndex n = 0;
563 CFIndex server_len;
564 CFArrayRef supplemental;
565
566 trimmed = _SC_trimDomain(server);
567 if (trimmed == NULL) {
568 _SCErrorSet(kSCStatusInvalidArgument);
569 return NULL;
570 }
571
572 server = trimmed;
573 server_len = CFStringGetLength(server);
574
575 supplemental = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesSupplemental);
576 if (supplemental != NULL) {
577 if (!isA_CFArray(supplemental)) {
578 // if corrupt proxy configuration
579 sc_status = kSCStatusFailed;
580 goto done;
581 }
582
583 n = CFArrayGetCount(supplemental);
584 }
585
586 for (i = 0; i < n; i++) {
587 CFStringRef domain;
588 CFIndex domain_len;
589 CFIndex n_matching;
590
591 proxy = CFArrayGetValueAtIndex(supplemental, i);
592 if (!isA_CFDictionary(proxy)) {
593 // if corrupt proxy configuration
594 continue;
595 }
596
597 domain = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchDomain);
598 if (!isA_CFString(domain)) {
599 // if corrupt proxy configuration
600 continue;
601 }
602
603 domain_len = CFStringGetLength(domain);
604 if (domain_len > 0) {
605 if (!CFStringFindWithOptions(server,
606 domain,
607 CFRangeMake(0, server_len),
608 kCFCompareCaseInsensitive|kCFCompareAnchored|kCFCompareBackwards,
609 NULL)) {
610 // if server does not match this proxy domain (or host)
611 continue;
612 }
613
614 if ((server_len > domain_len) &&
615 !CFStringFindWithOptions(server,
616 CFSTR("."),
617 CFRangeMake(0, server_len - domain_len),
618 kCFCompareCaseInsensitive|kCFCompareAnchored|kCFCompareBackwards,
619 NULL)) {
620 // if server does not match this proxy domain
621 continue;
622 }
623 // } else {
624 // // if this is a "default" (match all) proxy domain
625 }
626
627 if (matching == NULL) {
628 matching = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
629 }
630 n_matching = CFArrayGetCount(matching);
631
632 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
633 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomain);
634 if ((n_matching == 0) ||
635 !CFArrayContainsValue(matching, CFRangeMake(0, n_matching), newProxy)) {
636 // add this matching proxy
637 CFArrayAppendValue(matching, newProxy);
638 }
639 CFRelease(newProxy);
640 }
641
642 if (matching != NULL) {
643 // if we have any supplemental match domains
644 proxies = CFArrayCreateCopy(NULL, matching);
645 CFRelease(matching);
646 goto done;
647 }
648 }
649
650 // no matches, return "global" proxy configuration
651
652 #if !TARGET_OS_SIMULATOR
653 useDefault :
654 #endif // !TARGET_OS_SIMULATOR
655
656 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, globalConfiguration);
657 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesScoped);
658 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesServices);
659 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplemental);
660 proxies = CFArrayCreate(NULL, (const void **)&newProxy, 1, &kCFTypeArrayCallBacks);
661 CFRelease(newProxy);
662
663 done :
664
665 if (sc_status != kSCStatusOK) {
666 _SCErrorSet(sc_status);
667
668 // Note: if we are returning an error then we must
669 // return w/proxies==NULL. At present, there
670 // is no code (above) that would get here with
671 // proxies!=NULL so we don't need to take any
672 // action but future coder's should beware :-)
673 // if (proxies != NULL) {
674 // CFRelease(proxies);
675 // proxies = NULL;
676 // }
677 }
678 if (trimmed != NULL) CFRelease(trimmed);
679
680 return proxies;
681 }
682
683 CFDataRef
684 SCNetworkProxiesCreateProxyAgentData(CFDictionaryRef proxyConfig)
685 {
686 CFDataRef result = NULL;
687 CFArrayRef newProxy = NULL;
688
689 if (!isA_CFDictionary(proxyConfig)) {
690 SC_log(LOG_ERR, "Invalid proxy configuration");
691 _SCErrorSet(kSCStatusInvalidArgument);
692 return NULL;
693 }
694
695 newProxy = CFArrayCreate(NULL, (const void **)&proxyConfig, 1, &kCFTypeArrayCallBacks);
696 (void)_SCSerialize(newProxy, &result, NULL, NULL);
697 CFRelease(newProxy);
698
699 return result;
700 }
701
702 CFArrayRef
703 SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration,
704 CFStringRef server,
705 CFStringRef interface)
706 {
707 return _SCNetworkProxiesCopyMatchingInternal(globalConfiguration, server, interface, NULL);
708 }
709
710 CFArrayRef
711 SCNetworkProxiesCopyMatchingWithOptions(CFDictionaryRef globalConfiguration,
712 CFDictionaryRef options)
713 {
714 return _SCNetworkProxiesCopyMatchingInternal(globalConfiguration, NULL, NULL, options);
715 }