2 * Copyright (c) 2006, 2008, 2009, 2011-2015 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 * 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>
49 #include <sys/types.h>
50 #include <sys/socket.h>
52 #include <network/conninfo.h>
54 #pragma mark SCNetworkSignature Supporting APIs
57 create_global_state_v4_key(void)
59 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
60 kSCDynamicStoreDomainState
,
66 create_global_setup_v4_key(void)
68 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
69 kSCDynamicStoreDomainSetup
,
74 create_ipv4_services_pattern(void)
76 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
77 kSCDynamicStoreDomainState
,
83 create_ipv6_services_pattern(void)
85 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
86 kSCDynamicStoreDomainState
,
91 static CFDictionaryRef
92 copy_services_for_address_family(CFAllocatorRef alloc
,
100 prop
= (af
== AF_INET
) ? kSCEntNetIPv4
: kSCEntNetIPv6
;
101 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
102 kSCDynamicStoreDomainState
,
105 patterns
= CFArrayCreate(NULL
,
106 (const void * *)&pattern
, 1,
107 &kCFTypeArrayCallBacks
);
109 info
= SCDynamicStoreCopyMultiple(NULL
, NULL
, patterns
);
116 static CF_RETURNS_RETAINED CFStringRef
117 my_IPAddressToCFString(int af
, const void * src_p
)
119 char ntopbuf
[INET6_ADDRSTRLEN
];
121 if (inet_ntop(af
, src_p
, ntopbuf
, sizeof(ntopbuf
)) != NULL
) {
122 return (CFStringCreateWithCString(NULL
, ntopbuf
,
123 kCFStringEncodingASCII
));
131 #pragma mark SCNetworkSignature APIs
134 SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc
,
135 const struct sockaddr
* addr
)
137 CFStringRef ident
= NULL
;
138 CFDictionaryRef info
= NULL
;
139 CFStringRef global_state_v4_key
= NULL
;
140 CFDictionaryRef global_v4_state_dict
= NULL
;
141 CFArrayRef keys
= NULL
;
142 CFArrayRef patterns
= NULL
;
144 CFStringRef service
= NULL
;
145 CFDictionaryRef service_dict
= NULL
;
146 CFStringRef service_id
= NULL
;
147 struct sockaddr_in
* sin_p
;
148 CFStringRef v4_service_pattern
= NULL
;
150 /* only accept 0.0.0.0 (i.e. default) for now */
152 || addr
->sa_family
!= AF_INET
153 || addr
->sa_len
!= sizeof(struct sockaddr_in
)) {
154 _SCErrorSet(kSCStatusInvalidArgument
);
158 /* ALIGN: force alignment */
159 sin_p
= (struct sockaddr_in
*)(void *)addr
;
160 bcopy(&sin_p
->sin_addr
.s_addr
, &s_addr
, sizeof(s_addr
));
162 _SCErrorSet(kSCStatusInvalidArgument
);
166 global_state_v4_key
= create_global_state_v4_key();
167 keys
= CFArrayCreate(NULL
, (const void * *)&global_state_v4_key
,
168 1, &kCFTypeArrayCallBacks
);
170 v4_service_pattern
= create_ipv4_services_pattern();
171 patterns
= CFArrayCreate(NULL
, (const void * *)&v4_service_pattern
, 1,
172 &kCFTypeArrayCallBacks
);
174 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
177 || CFDictionaryGetCount(info
) == 0) {
181 global_v4_state_dict
= CFDictionaryGetValue(info
, global_state_v4_key
);
183 if (isA_CFDictionary(global_v4_state_dict
) == NULL
) {
187 service_id
= CFDictionaryGetValue(global_v4_state_dict
,
188 kSCDynamicStorePropNetPrimaryService
);
190 if (isA_CFString(service_id
) == NULL
) {
194 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
195 kSCDynamicStoreDomainState
,
196 service_id
, kSCEntNetIPv4
);
198 service_dict
= CFDictionaryGetValue(info
, service
);
201 if (isA_CFDictionary(service_dict
) == NULL
202 || CFDictionaryGetCount(service_dict
) == 0) {
206 ident
= CFDictionaryGetValue(service_dict
, kStoreKeyNetworkSignature
);
207 ident
= isA_CFString(ident
);
212 _SCErrorSet(kSCStatusFailed
);
217 if (global_state_v4_key
!= NULL
) {
218 CFRelease(global_state_v4_key
);
220 if (service
!= NULL
) {
226 if (patterns
!= NULL
) {
229 if (v4_service_pattern
!= NULL
) {
230 CFRelease(v4_service_pattern
);
235 CFArrayRef
/* of CFStringRef's */
236 SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc
)
238 CFMutableArrayRef active
= NULL
;
240 CFStringRef global_setup_v4_key
= NULL
;
241 CFDictionaryRef global_v4_dict
;
243 CFDictionaryRef info
= NULL
;
244 CFArrayRef keys
= NULL
;
245 CFMutableArrayRef patterns
= NULL
;
247 CFMutableDictionaryRef services_dict
= NULL
;
248 CFArrayRef service_order
;
249 CFStringRef v4_service_pattern
= NULL
;
250 CFStringRef v6_service_pattern
= NULL
;
251 const void * * values
= NULL
;
252 #define KEYS_STATIC_COUNT 10
253 const void * values_static
[KEYS_STATIC_COUNT
];
255 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
257 global_setup_v4_key
= create_global_setup_v4_key();
258 keys
= CFArrayCreate(NULL
, (const void * *)&global_setup_v4_key
, 1,
259 &kCFTypeArrayCallBacks
);
261 v4_service_pattern
= create_ipv4_services_pattern();
262 CFArrayAppendValue(patterns
, v4_service_pattern
);
264 v6_service_pattern
= create_ipv6_services_pattern();
265 CFArrayAppendValue(patterns
, v6_service_pattern
);
267 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
270 || CFDictionaryGetCount(info
) == 0) {
274 services_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
276 * The service_dict should only contain services and once each
277 * service has been visited, it will be removed from the dictionary.
279 CFDictionaryRemoveValue(services_dict
, global_setup_v4_key
);
281 global_v4_dict
= CFDictionaryGetValue(info
, global_setup_v4_key
);
283 if (isA_CFDictionary(global_v4_dict
) != NULL
) {
284 service_order
= CFDictionaryGetValue(global_v4_dict
,
285 kSCPropNetServiceOrder
);
286 if (isA_CFArray(service_order
) != NULL
) {
287 count
= CFArrayGetCount(service_order
);
291 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
293 range
= CFRangeMake(0, 0);
295 for (i
= 0; i
< count
; i
++) {
297 CFStringRef network_sig
;
299 CFStringRef service_id
;
300 CFDictionaryRef service_info
;
301 CFStringRef afs
[2] = {kSCEntNetIPv4
, kSCEntNetIPv6
};
303 service_id
= CFArrayGetValueAtIndex(service_order
, i
);
305 if (isA_CFString(service_id
) == NULL
) {
309 for (j
= 0; j
< 2; j
++) {
310 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
311 kSCDynamicStoreDomainState
,
314 service_info
= CFDictionaryGetValue(services_dict
, service
);
316 /* Does this service have a signature? */
317 if (isA_CFDictionary(service_info
) != NULL
) {
318 network_sig
= CFDictionaryGetValue(service_info
, kStoreKeyNetworkSignature
);
319 if (isA_CFString(network_sig
) && !CFArrayContainsValue(active
, range
, network_sig
)) {
320 CFArrayAppendValue(active
, network_sig
);
324 CFDictionaryRemoveValue(services_dict
, service
);
330 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
) && !CFArrayContainsValue(active
, range
, network_sig
)) {
353 CFArrayAppendValue(active
, network_sig
);
362 if (services_dict
!= NULL
) {
363 CFRelease(services_dict
);
365 if (global_setup_v4_key
!= NULL
) {
366 CFRelease(global_setup_v4_key
);
368 if (v4_service_pattern
!= NULL
) {
369 CFRelease(v4_service_pattern
);
371 if (v6_service_pattern
!= NULL
) {
372 CFRelease(v6_service_pattern
);
374 if (values
!= NULL
&& values
!= values_static
) {
380 if (patterns
!= NULL
) {
383 if (active
!= NULL
&& CFArrayGetCount(active
) == 0) {
387 if (active
== NULL
) {
388 _SCErrorSet(kSCStatusFailed
);
395 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc
,
398 CFStringRef addresses_key
;
402 char if_name
[IFNAMSIZ
];
403 CFStringRef if_name_cf
= NULL
;
404 conninfo_t
* info
= NULL
;
405 const void * * keys
= NULL
;
406 #define KEYS_STATIC_COUNT 10
407 const void * keys_static
[KEYS_STATIC_COUNT
];
408 const void * local_ip_p
;
409 CFStringRef local_ip_str
= NULL
;
410 CFStringRef ret_signature
= NULL
;
411 CFDictionaryRef service_info
= NULL
;
412 int status
= kSCStatusFailed
;
414 if (copyconninfo(sock_fd
, SAE_CONNID_ANY
, &info
) != 0) {
415 status
= kSCStatusInvalidArgument
;
418 if ((info
->ci_flags
& CIF_CONNECTED
) == 0
419 || info
->ci_src
== NULL
) {
422 af
= info
->ci_src
->sa_family
;
425 addresses_key
= kSCPropNetIPv4Addresses
;
426 local_ip_p
= &((struct sockaddr_in
*)
427 (void *)info
->ci_src
)->sin_addr
;
430 addresses_key
= kSCPropNetIPv6Addresses
;
431 local_ip_p
= &((struct sockaddr_in6
*)
432 (void *)info
->ci_src
)->sin6_addr
;
435 status
= kSCStatusInvalidArgument
;
439 /* search for service with matching IP address and interface name */
440 service_info
= copy_services_for_address_family(alloc
, af
);
441 if (service_info
== NULL
) {
444 local_ip_str
= my_IPAddressToCFString(af
, local_ip_p
);
445 if (local_ip_str
== NULL
) {
448 if (info
->ci_ifindex
!= 0
449 && if_indextoname(info
->ci_ifindex
, if_name
) != NULL
) {
451 = CFStringCreateWithCString(NULL
, if_name
,
452 kCFStringEncodingASCII
);
454 count
= CFDictionaryGetCount(service_info
);
455 if (count
> KEYS_STATIC_COUNT
) {
456 keys
= (const void * *)malloc(sizeof(*keys
) * count
);
461 CFDictionaryGetKeysAndValues(service_info
, keys
, NULL
);
462 for (i
= 0; i
< count
; i
++) {
465 CFStringRef signature
;
466 CFDictionaryRef value
;
468 value
= CFDictionaryGetValue(service_info
, keys
[i
]);
469 if (isA_CFDictionary(value
) == NULL
) {
472 signature
= CFDictionaryGetValue(value
,
473 kStoreKeyNetworkSignature
);
474 if (isA_CFString(signature
) == NULL
) {
478 if (if_name_cf
!= NULL
) {
479 CFStringRef confirmed_if
;
482 this_if
= CFDictionaryGetValue(value
,
483 kSCPropInterfaceName
);
484 if (isA_CFString(this_if
) == NULL
485 || !CFEqual(this_if
, if_name_cf
)) {
486 /* no interface or it doesn't match */
490 = CFDictionaryGetValue(value
,
491 kSCPropConfirmedInterfaceName
);
492 if (isA_CFString(confirmed_if
) != NULL
493 && !CFEqual(confirmed_if
, if_name_cf
)) {
494 /* confirmed interface doesn't match */
499 addrs
= CFDictionaryGetValue(value
, addresses_key
);
500 if (isA_CFArray(addrs
) == NULL
) {
503 range
= CFRangeMake(0, CFArrayGetCount(addrs
));
504 if (CFArrayContainsValue(addrs
, range
, local_ip_str
)) {
505 ret_signature
= CFRetain(signature
);
506 status
= kSCStatusOK
;
515 if (if_name_cf
!= NULL
) {
516 CFRelease(if_name_cf
);
518 if (local_ip_str
!= NULL
) {
519 CFRelease(local_ip_str
);
521 if (keys
!= NULL
&& keys
!= keys_static
) {
524 if (service_info
!= NULL
) {
525 CFRelease(service_info
);
527 if (status
!= kSCStatusOK
) {
530 return (ret_signature
);