2 * Copyright (c) 2000-2004, 2006-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 18, 2001 Allan Nathanson <ajn@apple.com>
31 #include <TargetConditionals.h>
32 #include <SystemConfiguration/SystemConfiguration.h>
33 #include <SystemConfiguration/SCValidation.h>
34 #include <SystemConfiguration/SCPrivate.h>
42 SCDynamicStoreKeyCreateProxies(CFAllocatorRef allocator
)
44 return SCDynamicStoreKeyCreateNetworkGlobalEntity(allocator
,
45 kSCDynamicStoreDomainState
,
51 validate_proxy_content(CFMutableDictionaryRef proxies
,
52 CFStringRef proxy_enable
,
53 CFStringRef proxy_host
,
54 CFStringRef proxy_port
,
55 const char * proxy_service
,
56 int proxy_defaultport
)
61 num
= CFDictionaryGetValue(proxies
, proxy_enable
);
63 if (!isA_CFNumber(num
) ||
64 !CFNumberGetValue(num
, kCFNumberIntType
, &enabled
)) {
65 // if we don't like the enabled key/value
70 if (proxy_host
!= NULL
) {
73 host
= CFDictionaryGetValue(proxies
, proxy_host
);
74 if (((enabled
== 0) && (host
!= NULL
)) ||
75 ((enabled
!= 0) && !isA_CFString(host
))) {
76 // pass only valid proxy hosts and only when enabled
81 if (proxy_port
!= NULL
) {
84 port
= CFDictionaryGetValue(proxies
, proxy_port
);
85 if (((enabled
== 0) && (port
!= NULL
)) ||
86 ((enabled
!= 0) && (port
!= NULL
) && !isA_CFNumber(port
))) {
87 // pass only provided/valid proxy ports and only when enabled
91 if ((enabled
!= 0) && (port
== NULL
)) {
92 struct servent
*service
;
95 service
= getservbyname(proxy_service
, "tcp");
96 if (service
!= NULL
) {
97 s_port
= ntohs(service
->s_port
);
99 s_port
= proxy_defaultport
;
101 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &s_port
);
102 CFDictionarySetValue(proxies
, proxy_port
, num
);
112 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &enabled
);
113 CFDictionarySetValue(proxies
, proxy_enable
, num
);
115 if (proxy_host
!= NULL
) {
116 CFDictionaryRemoveValue(proxies
, proxy_host
);
118 if (proxy_port
!= NULL
) {
119 CFDictionaryRemoveValue(proxies
, proxy_port
);
127 normalize_scoped_proxy(const void *key
, const void *value
, void *context
);
131 normalize_supplemental_proxy(const void *value
, void *context
);
134 static CF_RETURNS_RETAINED CFDictionaryRef
135 __SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy
)
138 CFMutableDictionaryRef newProxy
;
140 CFDictionaryRef scoped
;
141 CFArrayRef supplemental
;
143 if (!isA_CFDictionary(proxy
)) {
144 proxy
= CFDictionaryCreate(NULL
,
148 &kCFTypeDictionaryKeyCallBacks
,
149 &kCFTypeDictionaryValueCallBacks
);
153 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
155 validate_proxy_content(newProxy
,
156 kSCPropNetProxiesFTPEnable
,
157 kSCPropNetProxiesFTPProxy
,
158 kSCPropNetProxiesFTPPort
,
161 validate_proxy_content(newProxy
,
162 kSCPropNetProxiesGopherEnable
,
163 kSCPropNetProxiesGopherProxy
,
164 kSCPropNetProxiesGopherPort
,
167 validate_proxy_content(newProxy
,
168 kSCPropNetProxiesHTTPEnable
,
169 kSCPropNetProxiesHTTPProxy
,
170 kSCPropNetProxiesHTTPPort
,
173 validate_proxy_content(newProxy
,
174 kSCPropNetProxiesHTTPSEnable
,
175 kSCPropNetProxiesHTTPSProxy
,
176 kSCPropNetProxiesHTTPSPort
,
179 validate_proxy_content(newProxy
,
180 kSCPropNetProxiesRTSPEnable
,
181 kSCPropNetProxiesRTSPProxy
,
182 kSCPropNetProxiesRTSPPort
,
185 validate_proxy_content(newProxy
,
186 kSCPropNetProxiesSOCKSEnable
,
187 kSCPropNetProxiesSOCKSProxy
,
188 kSCPropNetProxiesSOCKSPort
,
191 if (CFDictionaryContainsKey(newProxy
, kSCPropNetProxiesProxyAutoConfigURLString
)) {
192 validate_proxy_content(newProxy
,
193 kSCPropNetProxiesProxyAutoConfigEnable
,
194 kSCPropNetProxiesProxyAutoConfigURLString
,
199 // and we can't have both URLString and JavaScript keys
200 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesProxyAutoConfigJavaScript
);
202 validate_proxy_content(newProxy
,
203 kSCPropNetProxiesProxyAutoConfigEnable
,
204 kSCPropNetProxiesProxyAutoConfigJavaScript
,
209 validate_proxy_content(newProxy
,
210 kSCPropNetProxiesProxyAutoDiscoveryEnable
,
216 // validate FTP passive setting
217 num
= CFDictionaryGetValue(newProxy
, kSCPropNetProxiesFTPPassive
);
221 if (!isA_CFNumber(num
) ||
222 !CFNumberGetValue(num
, kCFNumberIntType
, &enabled
)) {
223 // if we don't like the enabled key/value
225 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &enabled
);
226 CFDictionarySetValue(newProxy
,
227 kSCPropNetProxiesFTPPassive
,
233 // validate proxy exception list
234 array
= CFDictionaryGetValue(newProxy
, kSCPropNetProxiesExceptionsList
);
239 n
= isA_CFArray(array
) ? CFArrayGetCount(array
) : 0;
240 for (i
= 0; i
< n
; i
++) {
243 str
= CFArrayGetValueAtIndex(array
, i
);
244 if (!isA_CFString(str
)) {
245 // if we don't like the array contents
252 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesExceptionsList
);
256 // validate exclude simple hostnames setting
257 num
= CFDictionaryGetValue(newProxy
, kSCPropNetProxiesExcludeSimpleHostnames
);
261 if (!isA_CFNumber(num
) ||
262 !CFNumberGetValue(num
, kCFNumberIntType
, &enabled
)) {
263 // if we don't like the enabled key/value
265 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &enabled
);
266 CFDictionarySetValue(newProxy
,
267 kSCPropNetProxiesExcludeSimpleHostnames
,
273 // cleanup scoped proxies
274 scoped
= CFDictionaryGetValue(newProxy
, kSCPropNetProxiesScoped
);
275 if (isA_CFDictionary(scoped
)) {
276 CFMutableDictionaryRef newScoped
;
278 newScoped
= CFDictionaryCreateMutable(NULL
,
280 &kCFTypeDictionaryKeyCallBacks
,
281 &kCFTypeDictionaryValueCallBacks
);
282 CFDictionaryApplyFunction(scoped
,
283 normalize_scoped_proxy
,
285 CFDictionarySetValue(newProxy
, kSCPropNetProxiesScoped
, newScoped
);
286 CFRelease(newScoped
);
289 // cleanup split/supplemental proxies
290 supplemental
= CFDictionaryGetValue(newProxy
, kSCPropNetProxiesSupplemental
);
291 if (isA_CFArray(supplemental
)) {
292 CFMutableArrayRef newSupplemental
;
294 newSupplemental
= CFArrayCreateMutable(NULL
,
296 &kCFTypeArrayCallBacks
);
297 CFArrayApplyFunction(supplemental
,
298 CFRangeMake(0, CFArrayGetCount(supplemental
)),
299 normalize_supplemental_proxy
,
301 CFDictionarySetValue(newProxy
, kSCPropNetProxiesSupplemental
, newSupplemental
);
302 CFRelease(newSupplemental
);
305 proxy
= CFDictionaryCreateCopy(NULL
,newProxy
);
313 normalize_scoped_proxy(const void *key
, const void *value
, void *context
)
315 CFStringRef interface
= (CFStringRef
)key
;
316 CFDictionaryRef proxy
= (CFDictionaryRef
)value
;
317 CFMutableDictionaryRef newScoped
= (CFMutableDictionaryRef
)context
;
319 proxy
= __SCNetworkProxiesCopyNormalized(proxy
);
320 CFDictionarySetValue(newScoped
, interface
, proxy
);
328 normalize_supplemental_proxy(const void *value
, void *context
)
330 CFDictionaryRef proxy
= (CFDictionaryRef
)value
;
331 CFMutableArrayRef newSupplemental
= (CFMutableArrayRef
)context
;
333 proxy
= __SCNetworkProxiesCopyNormalized(proxy
);
334 CFArrayAppendValue(newSupplemental
, proxy
);
342 SCDynamicStoreCopyProxies(SCDynamicStoreRef store
)
345 CFDictionaryRef proxies
;
348 /* copy proxy information from dynamic store */
350 key
= SCDynamicStoreKeyCreateProxies(NULL
);
351 proxies
= SCDynamicStoreCopyValue(store
, key
);
355 if (proxies
!= NULL
) {
356 CFDictionaryRef base
= proxies
;
358 proxies
= __SCNetworkProxiesCopyNormalized(base
);
361 proxies
= CFDictionaryCreate(NULL
,
365 &kCFTypeDictionaryKeyCallBacks
,
366 &kCFTypeDictionaryValueCallBacks
);
375 SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration
,
377 CFStringRef interface
)
379 CFMutableDictionaryRef newProxy
;
380 CFArrayRef proxies
= NULL
;
381 CFDictionaryRef proxy
;
382 int sc_status
= kSCStatusOK
;
383 CFStringRef trimmed
= NULL
;
385 if (!isA_CFDictionary(globalConfiguration
)) {
386 // if no proxy configuration
387 _SCErrorSet(kSCStatusOK
);
391 if (interface
!= NULL
) {
392 CFDictionaryRef scoped
;
394 if (!isA_CFString(interface
) ||
395 (CFStringGetLength(interface
) == 0)) {
396 _SCErrorSet(kSCStatusInvalidArgument
);
400 scoped
= CFDictionaryGetValue(globalConfiguration
, kSCPropNetProxiesScoped
);
401 if (scoped
== NULL
) {
402 // if no scoped proxy configurations
403 _SCErrorSet(kSCStatusOK
);
407 if (!isA_CFDictionary(scoped
)) {
408 // if corrupt proxy configuration
409 _SCErrorSet(kSCStatusFailed
);
413 proxy
= CFDictionaryGetValue(scoped
, interface
);
415 // if no scoped proxy configuration for this interface
416 _SCErrorSet(kSCStatusOK
);
420 if (!isA_CFDictionary(proxy
)) {
421 // if corrupt proxy configuration
422 _SCErrorSet(kSCStatusFailed
);
426 // return per-interface proxy configuration
427 proxies
= CFArrayCreate(NULL
, (const void **)&proxy
, 1, &kCFTypeArrayCallBacks
);
431 if (server
!= NULL
) {
433 CFMutableArrayRef matching
= NULL
;
436 CFArrayRef supplemental
;
438 trimmed
= _SC_trimDomain(server
);
439 if (trimmed
== NULL
) {
440 _SCErrorSet(kSCStatusInvalidArgument
);
445 server_len
= CFStringGetLength(server
);
447 supplemental
= CFDictionaryGetValue(globalConfiguration
, kSCPropNetProxiesSupplemental
);
448 if (supplemental
!= NULL
) {
449 if (!isA_CFArray(supplemental
)) {
450 // if corrupt proxy configuration
451 sc_status
= kSCStatusFailed
;
455 n
= CFArrayGetCount(supplemental
);
458 for (i
= 0; i
< n
; i
++) {
463 proxy
= CFArrayGetValueAtIndex(supplemental
, i
);
464 if (!isA_CFDictionary(proxy
)) {
465 // if corrupt proxy configuration
469 domain
= CFDictionaryGetValue(proxy
, kSCPropNetProxiesSupplementalMatchDomain
);
470 if (!isA_CFString(domain
)) {
471 // if corrupt proxy configuration
475 domain_len
= CFStringGetLength(domain
);
476 if (domain_len
> 0) {
477 if (!CFStringFindWithOptions(server
,
479 CFRangeMake(0, server_len
),
480 kCFCompareCaseInsensitive
|kCFCompareAnchored
|kCFCompareBackwards
,
482 // if server does not match this proxy domain (or host)
486 if ((server_len
> domain_len
) &&
487 !CFStringFindWithOptions(server
,
489 CFRangeMake(0, server_len
- domain_len
),
490 kCFCompareCaseInsensitive
|kCFCompareAnchored
|kCFCompareBackwards
,
492 // if server does not match this proxy domain
496 // // if this is a "default" (match all) proxy domain
499 if (matching
== NULL
) {
500 matching
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
502 n_matching
= CFArrayGetCount(matching
);
504 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
505 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplementalMatchDomain
);
506 if ((n_matching
== 0) ||
507 !CFArrayContainsValue(matching
, CFRangeMake(0, n_matching
), newProxy
)) {
508 // add this matching proxy
509 CFArrayAppendValue(matching
, newProxy
);
514 if (matching
!= NULL
) {
515 // if we have any supplemental match domains
516 proxies
= CFArrayCreateCopy(NULL
, matching
);
522 // no matches, return "global" proxy configuration
524 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, globalConfiguration
);
525 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesScoped
);
526 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplemental
);
527 proxies
= CFArrayCreate(NULL
, (const void **)&newProxy
, 1, &kCFTypeArrayCallBacks
);
532 if (sc_status
!= kSCStatusOK
) {
533 if (proxies
!= NULL
) {
537 _SCErrorSet(sc_status
);
539 if (trimmed
!= NULL
) CFRelease(trimmed
);