2 * Copyright (c) 2006, 2011 Apple Computer, 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 * SCNetworkSignature.c
26 * - implementation of SCNetworkSignatureRef API that allows access to
27 network identification information
31 * Modification History
33 * November 6, 2006 Dieter Siegmund (dieter@apple.com)
38 #include <netinet/in.h>
39 #include <CoreFoundation/CFDictionary.h>
40 #include <CoreFoundation/CFString.h>
41 #include <CoreFoundation/CFArray.h>
42 #include <CoreFoundation/CFRuntime.h>
43 #include <SystemConfiguration/SCDynamicStore.h>
44 #include <SystemConfiguration/SCValidation.h>
45 #include <SystemConfiguration/SCPrivate.h>
46 #include "SCNetworkSignature.h"
47 #include "SCNetworkSignaturePrivate.h"
48 #include <arpa/inet.h>
50 const char * kSCNetworkSignatureActiveChangedNotifyName
= NETWORK_ID_KEY
".active";
52 #pragma mark SCNetworkSignature Supporting APIs
55 create_global_state_v4_key(void)
57 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
58 kSCDynamicStoreDomainState
,
64 create_global_setup_v4_key(void)
66 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
67 kSCDynamicStoreDomainSetup
,
72 create_ipv4_services_pattern(void)
74 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
75 kSCDynamicStoreDomainState
,
81 create_ipv6_services_pattern(void)
83 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
84 kSCDynamicStoreDomainState
,
89 static CFDictionaryRef
90 copy_services_for_address_family(CFAllocatorRef alloc
,
98 prop
= (af
== AF_INET
) ? kSCEntNetIPv4
: kSCEntNetIPv6
;
99 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
100 kSCDynamicStoreDomainState
,
103 patterns
= CFArrayCreate(NULL
,
104 (const void * *)&pattern
, 1,
105 &kCFTypeArrayCallBacks
);
107 info
= SCDynamicStoreCopyMultiple(NULL
, NULL
, patterns
);
114 static CF_RETURNS_RETAINED CFStringRef
115 my_IPAddressToCFString(int af
, const void * src_p
)
117 char ntopbuf
[INET6_ADDRSTRLEN
];
119 if (inet_ntop(af
, src_p
, ntopbuf
, sizeof(ntopbuf
)) != NULL
) {
120 return (CFStringCreateWithCString(NULL
, ntopbuf
,
121 kCFStringEncodingASCII
));
129 #pragma mark SCNetworkSignature APIs
132 SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc
,
133 const struct sockaddr
* addr
)
135 CFStringRef ident
= NULL
;
136 CFDictionaryRef info
= NULL
;
137 CFStringRef global_state_v4_key
= NULL
;
138 CFDictionaryRef global_v4_state_dict
= NULL
;
139 CFArrayRef keys
= NULL
;
140 CFArrayRef patterns
= NULL
;
142 CFStringRef service
= NULL
;
143 CFDictionaryRef service_dict
= NULL
;
144 CFStringRef service_id
= NULL
;
145 struct sockaddr_in
* sin_p
;
146 CFStringRef v4_service_pattern
= NULL
;
148 /* only accept 0.0.0.0 (i.e. default) for now */
150 || addr
->sa_family
!= AF_INET
151 || addr
->sa_len
!= sizeof(struct sockaddr_in
)){
152 _SCErrorSet(kSCStatusInvalidArgument
);
156 /* ALIGN: force alignment */
157 sin_p
= (struct sockaddr_in
*)(void *)addr
;
158 bcopy(&sin_p
->sin_addr
.s_addr
, &s_addr
, sizeof(s_addr
));
160 _SCErrorSet(kSCStatusInvalidArgument
);
164 global_state_v4_key
= create_global_state_v4_key();
165 keys
= CFArrayCreate(NULL
, (const void * *)&global_state_v4_key
,
166 1, &kCFTypeArrayCallBacks
);
168 v4_service_pattern
= create_ipv4_services_pattern();
169 patterns
= CFArrayCreate(NULL
, (const void * *)&v4_service_pattern
, 1,
170 &kCFTypeArrayCallBacks
);
172 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
175 || CFDictionaryGetCount(info
) == 0) {
179 global_v4_state_dict
= CFDictionaryGetValue(info
, global_state_v4_key
);
181 if (isA_CFDictionary(global_v4_state_dict
) == NULL
) {
185 service_id
= CFDictionaryGetValue(global_v4_state_dict
,
186 kSCDynamicStorePropNetPrimaryService
);
188 if (isA_CFString(service_id
) == NULL
) {
192 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
193 kSCDynamicStoreDomainState
,
194 service_id
, kSCEntNetIPv4
);
196 service_dict
= CFDictionaryGetValue(info
, service
);
199 if (isA_CFDictionary(service_dict
) == NULL
200 || CFDictionaryGetCount(service_dict
) == 0) {
204 ident
= CFDictionaryGetValue(service_dict
, kStoreKeyNetworkSignature
);
205 ident
= isA_CFString(ident
);
210 _SCErrorSet(kSCStatusFailed
);
215 if (global_state_v4_key
!= NULL
) {
216 CFRelease(global_state_v4_key
);
218 if (service
!= NULL
) {
224 if (patterns
!= NULL
) {
227 if (v4_service_pattern
!= NULL
) {
228 CFRelease(v4_service_pattern
);
233 CFArrayRef
/* of CFStringRef's */
234 SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc
)
236 CFMutableArrayRef active
= NULL
;
238 CFStringRef global_setup_v4_key
= NULL
;
239 CFDictionaryRef global_v4_dict
;
241 CFDictionaryRef info
= NULL
;
242 CFArrayRef keys
= NULL
;
243 CFMutableArrayRef patterns
= NULL
;
245 CFMutableDictionaryRef services_dict
= NULL
;
246 CFArrayRef service_order
;
247 CFStringRef v4_service_pattern
= NULL
;
248 CFStringRef v6_service_pattern
= NULL
;
249 const void * * values
= NULL
;
250 #define KEYS_STATIC_COUNT 10
251 const void * values_static
[KEYS_STATIC_COUNT
];
253 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
255 global_setup_v4_key
= create_global_setup_v4_key();
256 keys
= CFArrayCreate(NULL
, (const void * *)&global_setup_v4_key
, 1,
257 &kCFTypeArrayCallBacks
);
259 v4_service_pattern
= create_ipv4_services_pattern();
260 CFArrayAppendValue(patterns
, v4_service_pattern
);
262 v6_service_pattern
= create_ipv6_services_pattern();
263 CFArrayAppendValue(patterns
, v6_service_pattern
);
265 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
268 || CFDictionaryGetCount(info
) == 0) {
272 services_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
274 * The service_dict should only contain services and once each
275 * service has been visited, it will be removed from the dictionary.
277 CFDictionaryRemoveValue(services_dict
, global_setup_v4_key
);
279 global_v4_dict
= CFDictionaryGetValue(info
, global_setup_v4_key
);
281 if (isA_CFDictionary(global_v4_dict
) == NULL
) {
282 service_order
= CFDictionaryGetValue(global_v4_dict
,
283 kSCPropNetServiceOrder
);
284 if (isA_CFArray(service_order
) != NULL
) {
285 count
= CFArrayGetCount(service_order
);
289 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
291 range
= CFRangeMake(0, 0);
293 for (i
= 0; i
< count
; i
++) {
295 CFStringRef network_sig
;
297 CFStringRef service_id
;
298 CFDictionaryRef service_info
;
299 CFStringRef afs
[2] = {kSCEntNetIPv4
, kSCEntNetIPv6
};
301 service_id
= CFArrayGetValueAtIndex(service_order
, i
);
303 if (isA_CFString(service_id
) == NULL
) {
307 for (j
= 0; j
< 2; j
++) {
308 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
309 kSCDynamicStoreDomainState
,
312 service_info
= CFDictionaryGetValue(services_dict
, service
);
314 /* Does this service have a signature? */
315 if (isA_CFDictionary(service_info
) != NULL
) {
316 network_sig
= CFDictionaryGetValue(service_info
, kStoreKeyNetworkSignature
);
317 if (isA_CFString(network_sig
) != NULL
318 && CFArrayContainsValue(active
, range
, network_sig
) == FALSE
) {
319 CFArrayAppendValue(active
, network_sig
);
323 CFDictionaryRemoveValue(services_dict
, service
);
329 count
= CFDictionaryGetCount(services_dict
);
332 if (count
> KEYS_STATIC_COUNT
) {
333 values
= (const void * *)malloc(sizeof(*values
) * count
);
335 values
= values_static
;
337 CFDictionaryGetKeysAndValues(services_dict
, NULL
,
338 (const void * *)values
);
341 for (i
= 0; i
< count
; i
++) {
342 CFStringRef network_sig
;
343 CFDictionaryRef service_dict
= (CFDictionaryRef
)values
[i
];
345 if (isA_CFDictionary(service_dict
) == NULL
) {
349 network_sig
= CFDictionaryGetValue(service_dict
,
350 kStoreKeyNetworkSignature
);
351 /* Does this service have a signature? */
352 if (isA_CFString(network_sig
) != NULL
353 && CFArrayContainsValue(active
, range
, network_sig
) == FALSE
) {
354 CFArrayAppendValue(active
, network_sig
);
363 if (services_dict
!= NULL
) {
364 CFRelease(services_dict
);
366 if (global_setup_v4_key
!= NULL
) {
367 CFRelease(global_setup_v4_key
);
369 if (v4_service_pattern
!= NULL
) {
370 CFRelease(v4_service_pattern
);
372 if (v6_service_pattern
!= NULL
) {
373 CFRelease(v6_service_pattern
);
375 if (values
!= NULL
&& values
!= values_static
) {
381 if (patterns
!= NULL
) {
384 if (active
!= NULL
&& CFArrayGetCount(active
) == 0) {
388 if (active
== NULL
) {
389 _SCErrorSet(kSCStatusFailed
);
396 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc
,
399 CFStringRef addresses_key
;
403 const void * * keys
= NULL
;
404 #define KEYS_STATIC_COUNT 10
405 const void * keys_static
[KEYS_STATIC_COUNT
];
406 const void * local_ip_p
;
407 CFStringRef local_ip_str
= NULL
;
408 CFStringRef ret_signature
= NULL
;
409 CFDictionaryRef service_info
= NULL
;
411 struct sockaddr_in inet
;
412 struct sockaddr_in6 inet6
;
415 socklen_t ss_len
= sizeof(ss
);
416 int status
= kSCStatusFailed
;
418 if (getsockname(sock_fd
, &ss
.sa
, &ss_len
) != 0) {
419 status
= kSCStatusInvalidArgument
;
422 af
= ss
.inet
.sin_family
;
425 addresses_key
= kSCPropNetIPv4Addresses
;
426 local_ip_p
= &ss
.inet
.sin_addr
;
429 addresses_key
= kSCPropNetIPv6Addresses
;
430 local_ip_p
= &ss
.inet6
.sin6_addr
;
433 status
= kSCStatusInvalidArgument
;
437 /* find a service matching the local IP and get its network signature */
438 service_info
= copy_services_for_address_family(alloc
, af
);
439 if (service_info
== NULL
) {
442 local_ip_str
= my_IPAddressToCFString(af
, local_ip_p
);
443 if (local_ip_str
== NULL
) {
446 count
= CFDictionaryGetCount(service_info
);
447 if (count
> KEYS_STATIC_COUNT
) {
448 keys
= (const void * *)malloc(sizeof(*keys
) * count
);
453 CFDictionaryGetKeysAndValues(service_info
, keys
, NULL
);
454 for (i
= 0; i
< count
; i
++) {
457 CFStringRef signature
;
458 CFDictionaryRef value
;
460 value
= CFDictionaryGetValue(service_info
, keys
[i
]);
461 if (isA_CFDictionary(value
) == NULL
) {
464 signature
= CFDictionaryGetValue(value
,
465 kStoreKeyNetworkSignature
);
466 if (isA_CFString(signature
) == NULL
) {
470 addrs
= CFDictionaryGetValue(value
, addresses_key
);
471 if (isA_CFArray(addrs
) == NULL
) {
474 range
= CFRangeMake(0, CFArrayGetCount(addrs
));
475 if (CFArrayContainsValue(addrs
, range
, local_ip_str
)) {
476 ret_signature
= CFRetain(signature
);
477 status
= kSCStatusOK
;
483 if (local_ip_str
!= NULL
) {
484 CFRelease(local_ip_str
);
486 if (keys
!= NULL
&& keys
!= keys_static
) {
489 if (service_info
!= NULL
) {
490 CFRelease(service_info
);
492 if (status
!= kSCStatusOK
) {
495 return (ret_signature
);