2 * Copyright (c) 2006, 2008, 2009, 2011-2019 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 <nw/private.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
, int af
)
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 #pragma unused(alloc)
138 CFStringRef ident
= NULL
;
139 CFDictionaryRef info
= NULL
;
140 CFStringRef global_state_v4_key
= NULL
;
141 CFDictionaryRef global_v4_state_dict
= NULL
;
142 CFArrayRef keys
= NULL
;
143 CFArrayRef patterns
= NULL
;
145 CFStringRef service
= NULL
;
146 CFDictionaryRef service_dict
= NULL
;
147 CFStringRef service_id
= NULL
;
148 struct sockaddr_in
* sin_p
;
149 CFStringRef v4_service_pattern
= NULL
;
151 /* only accept 0.0.0.0 (i.e. default) for now */
153 || addr
->sa_family
!= AF_INET
154 || addr
->sa_len
!= sizeof(struct sockaddr_in
)) {
155 _SCErrorSet(kSCStatusInvalidArgument
);
159 /* ALIGN: force alignment */
160 sin_p
= (struct sockaddr_in
*)(void *)addr
;
161 memcpy(&s_addr
, &sin_p
->sin_addr
.s_addr
, sizeof(s_addr
));
163 _SCErrorSet(kSCStatusInvalidArgument
);
167 global_state_v4_key
= create_global_state_v4_key();
168 keys
= CFArrayCreate(NULL
, (const void * *)&global_state_v4_key
,
169 1, &kCFTypeArrayCallBacks
);
171 v4_service_pattern
= create_ipv4_services_pattern();
172 patterns
= CFArrayCreate(NULL
, (const void * *)&v4_service_pattern
, 1,
173 &kCFTypeArrayCallBacks
);
175 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
178 || CFDictionaryGetCount(info
) == 0) {
182 global_v4_state_dict
= CFDictionaryGetValue(info
, global_state_v4_key
);
184 if (isA_CFDictionary(global_v4_state_dict
) == NULL
) {
188 service_id
= CFDictionaryGetValue(global_v4_state_dict
,
189 kSCDynamicStorePropNetPrimaryService
);
191 if (isA_CFString(service_id
) == NULL
) {
195 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
196 kSCDynamicStoreDomainState
,
197 service_id
, kSCEntNetIPv4
);
199 service_dict
= CFDictionaryGetValue(info
, service
);
202 if (isA_CFDictionary(service_dict
) == NULL
203 || CFDictionaryGetCount(service_dict
) == 0) {
207 ident
= CFDictionaryGetValue(service_dict
, kStoreKeyNetworkSignature
);
208 ident
= isA_CFString(ident
);
213 _SCErrorSet(kSCStatusFailed
);
218 if (global_state_v4_key
!= NULL
) {
219 CFRelease(global_state_v4_key
);
221 if (service
!= NULL
) {
227 if (patterns
!= NULL
) {
230 if (v4_service_pattern
!= NULL
) {
231 CFRelease(v4_service_pattern
);
236 CFArrayRef
/* of CFStringRef's */
237 SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc
)
239 #pragma unused(alloc)
240 CFMutableArrayRef active
= NULL
;
242 CFStringRef global_setup_v4_key
= NULL
;
243 CFDictionaryRef global_v4_dict
;
245 CFDictionaryRef info
= NULL
;
246 CFArrayRef keys
= NULL
;
247 CFMutableArrayRef patterns
= NULL
;
249 CFMutableDictionaryRef services_dict
= NULL
;
250 CFArrayRef service_order
;
251 CFStringRef v4_service_pattern
= NULL
;
252 CFStringRef v6_service_pattern
= NULL
;
253 const void * * values
= NULL
;
254 #define KEYS_STATIC_COUNT 10
255 const void * values_static
[KEYS_STATIC_COUNT
];
257 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
259 global_setup_v4_key
= create_global_setup_v4_key();
260 keys
= CFArrayCreate(NULL
, (const void * *)&global_setup_v4_key
, 1,
261 &kCFTypeArrayCallBacks
);
263 v4_service_pattern
= create_ipv4_services_pattern();
264 CFArrayAppendValue(patterns
, v4_service_pattern
);
266 v6_service_pattern
= create_ipv6_services_pattern();
267 CFArrayAppendValue(patterns
, v6_service_pattern
);
269 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
272 || CFDictionaryGetCount(info
) == 0) {
276 services_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
278 * The service_dict should only contain services and once each
279 * service has been visited, it will be removed from the dictionary.
281 CFDictionaryRemoveValue(services_dict
, global_setup_v4_key
);
283 global_v4_dict
= CFDictionaryGetValue(info
, global_setup_v4_key
);
285 if (isA_CFDictionary(global_v4_dict
) != NULL
) {
286 service_order
= CFDictionaryGetValue(global_v4_dict
,
287 kSCPropNetServiceOrder
);
288 if (isA_CFArray(service_order
) != NULL
) {
289 count
= CFArrayGetCount(service_order
);
293 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
295 range
= CFRangeMake(0, 0);
297 for (i
= 0; i
< count
; i
++) {
299 CFStringRef network_sig
;
301 CFStringRef service_id
;
302 CFDictionaryRef service_info
;
303 CFStringRef afs
[2] = {kSCEntNetIPv4
, kSCEntNetIPv6
};
305 service_id
= CFArrayGetValueAtIndex(service_order
, i
);
307 if (isA_CFString(service_id
) == NULL
) {
311 for (j
= 0; j
< 2; j
++) {
312 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
313 kSCDynamicStoreDomainState
,
316 service_info
= CFDictionaryGetValue(services_dict
, service
);
318 /* Does this service have a signature? */
319 if (isA_CFDictionary(service_info
) != NULL
) {
320 network_sig
= CFDictionaryGetValue(service_info
, kStoreKeyNetworkSignature
);
321 if (isA_CFString(network_sig
) && !CFArrayContainsValue(active
, range
, network_sig
)) {
322 CFArrayAppendValue(active
, network_sig
);
326 CFDictionaryRemoveValue(services_dict
, service
);
332 count
= CFDictionaryGetCount(services_dict
);
334 if (count
> KEYS_STATIC_COUNT
) {
335 values
= (const void * *)malloc(sizeof(*values
) * count
);
337 values
= values_static
;
339 CFDictionaryGetKeysAndValues(services_dict
, NULL
,
340 (const void * *)values
);
343 for (i
= 0; i
< count
; i
++) {
344 CFStringRef network_sig
;
345 CFDictionaryRef service_dict
= (CFDictionaryRef
)values
[i
];
347 if (isA_CFDictionary(service_dict
) == NULL
) {
351 network_sig
= CFDictionaryGetValue(service_dict
,
352 kStoreKeyNetworkSignature
);
353 /* Does this service have a signature? */
354 if (isA_CFString(network_sig
) && !CFArrayContainsValue(active
, range
, network_sig
)) {
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
, SAE_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
);