2 * Copyright (c) 2006, 2008, 2009, 2011-2014 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
) != NULL
320 && CFArrayContainsValue(active
, range
, network_sig
) == FALSE
) {
321 CFArrayAppendValue(active
, network_sig
);
325 CFDictionaryRemoveValue(services_dict
, service
);
331 count
= CFDictionaryGetCount(services_dict
);
333 if (count
> KEYS_STATIC_COUNT
) {
334 values
= (const void * *)malloc(sizeof(*values
) * count
);
336 values
= values_static
;
338 CFDictionaryGetKeysAndValues(services_dict
, NULL
,
339 (const void * *)values
);
342 for (i
= 0; i
< count
; i
++) {
343 CFStringRef network_sig
;
344 CFDictionaryRef service_dict
= (CFDictionaryRef
)values
[i
];
346 if (isA_CFDictionary(service_dict
) == NULL
) {
350 network_sig
= CFDictionaryGetValue(service_dict
,
351 kStoreKeyNetworkSignature
);
352 /* Does this service have a signature? */
353 if (isA_CFString(network_sig
) != NULL
354 && CFArrayContainsValue(active
, range
, network_sig
) == FALSE
) {
355 CFArrayAppendValue(active
, network_sig
);
364 if (services_dict
!= NULL
) {
365 CFRelease(services_dict
);
367 if (global_setup_v4_key
!= NULL
) {
368 CFRelease(global_setup_v4_key
);
370 if (v4_service_pattern
!= NULL
) {
371 CFRelease(v4_service_pattern
);
373 if (v6_service_pattern
!= NULL
) {
374 CFRelease(v6_service_pattern
);
376 if (values
!= NULL
&& values
!= values_static
) {
382 if (patterns
!= NULL
) {
385 if (active
!= NULL
&& CFArrayGetCount(active
) == 0) {
389 if (active
== NULL
) {
390 _SCErrorSet(kSCStatusFailed
);
397 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc
,
400 CFStringRef addresses_key
;
404 char if_name
[IFNAMSIZ
];
405 CFStringRef if_name_cf
= NULL
;
406 conninfo_t
* info
= NULL
;
407 const void * * keys
= NULL
;
408 #define KEYS_STATIC_COUNT 10
409 const void * keys_static
[KEYS_STATIC_COUNT
];
410 const void * local_ip_p
;
411 CFStringRef local_ip_str
= NULL
;
412 CFStringRef ret_signature
= NULL
;
413 CFDictionaryRef service_info
= NULL
;
414 int status
= kSCStatusFailed
;
416 if (copyconninfo(sock_fd
, CONNID_ANY
, &info
) != 0) {
417 status
= kSCStatusInvalidArgument
;
420 if ((info
->ci_flags
& CIF_CONNECTED
) == 0
421 || info
->ci_src
== NULL
) {
424 af
= info
->ci_src
->sa_family
;
427 addresses_key
= kSCPropNetIPv4Addresses
;
428 local_ip_p
= &((struct sockaddr_in
*)
429 (void *)info
->ci_src
)->sin_addr
;
432 addresses_key
= kSCPropNetIPv6Addresses
;
433 local_ip_p
= &((struct sockaddr_in6
*)
434 (void *)info
->ci_src
)->sin6_addr
;
437 status
= kSCStatusInvalidArgument
;
441 /* search for service with matching IP address and interface name */
442 service_info
= copy_services_for_address_family(alloc
, af
);
443 if (service_info
== NULL
) {
446 local_ip_str
= my_IPAddressToCFString(af
, local_ip_p
);
447 if (local_ip_str
== NULL
) {
450 if (info
->ci_ifindex
!= 0
451 && if_indextoname(info
->ci_ifindex
, if_name
) != NULL
) {
453 = CFStringCreateWithCString(NULL
, if_name
,
454 kCFStringEncodingASCII
);
456 count
= CFDictionaryGetCount(service_info
);
457 if (count
> KEYS_STATIC_COUNT
) {
458 keys
= (const void * *)malloc(sizeof(*keys
) * count
);
463 CFDictionaryGetKeysAndValues(service_info
, keys
, NULL
);
464 for (i
= 0; i
< count
; i
++) {
467 CFStringRef signature
;
468 CFDictionaryRef value
;
470 value
= CFDictionaryGetValue(service_info
, keys
[i
]);
471 if (isA_CFDictionary(value
) == NULL
) {
474 signature
= CFDictionaryGetValue(value
,
475 kStoreKeyNetworkSignature
);
476 if (isA_CFString(signature
) == NULL
) {
480 if (if_name_cf
!= NULL
) {
481 CFStringRef confirmed_if
;
484 this_if
= CFDictionaryGetValue(value
,
485 kSCPropInterfaceName
);
486 if (isA_CFString(this_if
) == NULL
487 || !CFEqual(this_if
, if_name_cf
)) {
488 /* no interface or it doesn't match */
492 = CFDictionaryGetValue(value
,
493 kSCPropConfirmedInterfaceName
);
494 if (isA_CFString(confirmed_if
) != NULL
495 && !CFEqual(confirmed_if
, if_name_cf
)) {
496 /* confirmed interface doesn't match */
501 addrs
= CFDictionaryGetValue(value
, addresses_key
);
502 if (isA_CFArray(addrs
) == NULL
) {
505 range
= CFRangeMake(0, CFArrayGetCount(addrs
));
506 if (CFArrayContainsValue(addrs
, range
, local_ip_str
)) {
507 ret_signature
= CFRetain(signature
);
508 status
= kSCStatusOK
;
517 if (if_name_cf
!= NULL
) {
518 CFRelease(if_name_cf
);
520 if (local_ip_str
!= NULL
) {
521 CFRelease(local_ip_str
);
523 if (keys
!= NULL
&& keys
!= keys_static
) {
526 if (service_info
!= NULL
) {
527 CFRelease(service_info
);
529 if (status
!= kSCStatusOK
) {
532 return (ret_signature
);