2 * Copyright (c) 2006, 2008, 2009, 2011-2015, 2017, 2018 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 #if __has_include(<nw/private.h>)
53 #include <nw/private.h>
54 #else // __has_include(<nw/private.h>)
55 #include <network/conninfo.h>
56 #endif // __has_include(<nw/private.h>)
58 #pragma mark SCNetworkSignature Supporting APIs
61 create_global_state_v4_key(void)
63 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
64 kSCDynamicStoreDomainState
,
70 create_global_setup_v4_key(void)
72 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
73 kSCDynamicStoreDomainSetup
,
78 create_ipv4_services_pattern(void)
80 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
81 kSCDynamicStoreDomainState
,
87 create_ipv6_services_pattern(void)
89 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
90 kSCDynamicStoreDomainState
,
95 static CFDictionaryRef
96 copy_services_for_address_family(CFAllocatorRef alloc
, int af
)
104 prop
= (af
== AF_INET
) ? kSCEntNetIPv4
: kSCEntNetIPv6
;
105 pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
106 kSCDynamicStoreDomainState
,
109 patterns
= CFArrayCreate(NULL
,
110 (const void * *)&pattern
, 1,
111 &kCFTypeArrayCallBacks
);
113 info
= SCDynamicStoreCopyMultiple(NULL
, NULL
, patterns
);
120 static CF_RETURNS_RETAINED CFStringRef
121 my_IPAddressToCFString(int af
, const void * src_p
)
123 char ntopbuf
[INET6_ADDRSTRLEN
];
125 if (inet_ntop(af
, src_p
, ntopbuf
, sizeof(ntopbuf
)) != NULL
) {
126 return (CFStringCreateWithCString(NULL
, ntopbuf
,
127 kCFStringEncodingASCII
));
135 #pragma mark SCNetworkSignature APIs
138 SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc
,
139 const struct sockaddr
* addr
)
141 #pragma unused(alloc)
142 CFStringRef ident
= NULL
;
143 CFDictionaryRef info
= NULL
;
144 CFStringRef global_state_v4_key
= NULL
;
145 CFDictionaryRef global_v4_state_dict
= NULL
;
146 CFArrayRef keys
= NULL
;
147 CFArrayRef patterns
= NULL
;
149 CFStringRef service
= NULL
;
150 CFDictionaryRef service_dict
= NULL
;
151 CFStringRef service_id
= NULL
;
152 struct sockaddr_in
* sin_p
;
153 CFStringRef v4_service_pattern
= NULL
;
155 /* only accept 0.0.0.0 (i.e. default) for now */
157 || addr
->sa_family
!= AF_INET
158 || addr
->sa_len
!= sizeof(struct sockaddr_in
)) {
159 _SCErrorSet(kSCStatusInvalidArgument
);
163 /* ALIGN: force alignment */
164 sin_p
= (struct sockaddr_in
*)(void *)addr
;
165 bcopy(&sin_p
->sin_addr
.s_addr
, &s_addr
, sizeof(s_addr
));
167 _SCErrorSet(kSCStatusInvalidArgument
);
171 global_state_v4_key
= create_global_state_v4_key();
172 keys
= CFArrayCreate(NULL
, (const void * *)&global_state_v4_key
,
173 1, &kCFTypeArrayCallBacks
);
175 v4_service_pattern
= create_ipv4_services_pattern();
176 patterns
= CFArrayCreate(NULL
, (const void * *)&v4_service_pattern
, 1,
177 &kCFTypeArrayCallBacks
);
179 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
182 || CFDictionaryGetCount(info
) == 0) {
186 global_v4_state_dict
= CFDictionaryGetValue(info
, global_state_v4_key
);
188 if (isA_CFDictionary(global_v4_state_dict
) == NULL
) {
192 service_id
= CFDictionaryGetValue(global_v4_state_dict
,
193 kSCDynamicStorePropNetPrimaryService
);
195 if (isA_CFString(service_id
) == NULL
) {
199 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
200 kSCDynamicStoreDomainState
,
201 service_id
, kSCEntNetIPv4
);
203 service_dict
= CFDictionaryGetValue(info
, service
);
206 if (isA_CFDictionary(service_dict
) == NULL
207 || CFDictionaryGetCount(service_dict
) == 0) {
211 ident
= CFDictionaryGetValue(service_dict
, kStoreKeyNetworkSignature
);
212 ident
= isA_CFString(ident
);
217 _SCErrorSet(kSCStatusFailed
);
222 if (global_state_v4_key
!= NULL
) {
223 CFRelease(global_state_v4_key
);
225 if (service
!= NULL
) {
231 if (patterns
!= NULL
) {
234 if (v4_service_pattern
!= NULL
) {
235 CFRelease(v4_service_pattern
);
240 CFArrayRef
/* of CFStringRef's */
241 SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc
)
243 #pragma unused(alloc)
244 CFMutableArrayRef active
= NULL
;
246 CFStringRef global_setup_v4_key
= NULL
;
247 CFDictionaryRef global_v4_dict
;
249 CFDictionaryRef info
= NULL
;
250 CFArrayRef keys
= NULL
;
251 CFMutableArrayRef patterns
= NULL
;
253 CFMutableDictionaryRef services_dict
= NULL
;
254 CFArrayRef service_order
;
255 CFStringRef v4_service_pattern
= NULL
;
256 CFStringRef v6_service_pattern
= NULL
;
257 const void * * values
= NULL
;
258 #define KEYS_STATIC_COUNT 10
259 const void * values_static
[KEYS_STATIC_COUNT
];
261 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
263 global_setup_v4_key
= create_global_setup_v4_key();
264 keys
= CFArrayCreate(NULL
, (const void * *)&global_setup_v4_key
, 1,
265 &kCFTypeArrayCallBacks
);
267 v4_service_pattern
= create_ipv4_services_pattern();
268 CFArrayAppendValue(patterns
, v4_service_pattern
);
270 v6_service_pattern
= create_ipv6_services_pattern();
271 CFArrayAppendValue(patterns
, v6_service_pattern
);
273 info
= SCDynamicStoreCopyMultiple(NULL
, keys
, patterns
);
276 || CFDictionaryGetCount(info
) == 0) {
280 services_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
282 * The service_dict should only contain services and once each
283 * service has been visited, it will be removed from the dictionary.
285 CFDictionaryRemoveValue(services_dict
, global_setup_v4_key
);
287 global_v4_dict
= CFDictionaryGetValue(info
, global_setup_v4_key
);
289 if (isA_CFDictionary(global_v4_dict
) != NULL
) {
290 service_order
= CFDictionaryGetValue(global_v4_dict
,
291 kSCPropNetServiceOrder
);
292 if (isA_CFArray(service_order
) != NULL
) {
293 count
= CFArrayGetCount(service_order
);
297 active
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
299 range
= CFRangeMake(0, 0);
301 for (i
= 0; i
< count
; i
++) {
303 CFStringRef network_sig
;
305 CFStringRef service_id
;
306 CFDictionaryRef service_info
;
307 CFStringRef afs
[2] = {kSCEntNetIPv4
, kSCEntNetIPv6
};
309 service_id
= CFArrayGetValueAtIndex(service_order
, i
);
311 if (isA_CFString(service_id
) == NULL
) {
315 for (j
= 0; j
< 2; j
++) {
316 service
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
317 kSCDynamicStoreDomainState
,
320 service_info
= CFDictionaryGetValue(services_dict
, service
);
322 /* Does this service have a signature? */
323 if (isA_CFDictionary(service_info
) != NULL
) {
324 network_sig
= CFDictionaryGetValue(service_info
, kStoreKeyNetworkSignature
);
325 if (isA_CFString(network_sig
) && !CFArrayContainsValue(active
, range
, network_sig
)) {
326 CFArrayAppendValue(active
, network_sig
);
330 CFDictionaryRemoveValue(services_dict
, service
);
336 count
= CFDictionaryGetCount(services_dict
);
338 if (count
> KEYS_STATIC_COUNT
) {
339 values
= (const void * *)malloc(sizeof(*values
) * count
);
341 values
= values_static
;
343 CFDictionaryGetKeysAndValues(services_dict
, NULL
,
344 (const void * *)values
);
347 for (i
= 0; i
< count
; i
++) {
348 CFStringRef network_sig
;
349 CFDictionaryRef service_dict
= (CFDictionaryRef
)values
[i
];
351 if (isA_CFDictionary(service_dict
) == NULL
) {
355 network_sig
= CFDictionaryGetValue(service_dict
,
356 kStoreKeyNetworkSignature
);
357 /* Does this service have a signature? */
358 if (isA_CFString(network_sig
) && !CFArrayContainsValue(active
, range
, network_sig
)) {
359 CFArrayAppendValue(active
, network_sig
);
368 if (services_dict
!= NULL
) {
369 CFRelease(services_dict
);
371 if (global_setup_v4_key
!= NULL
) {
372 CFRelease(global_setup_v4_key
);
374 if (v4_service_pattern
!= NULL
) {
375 CFRelease(v4_service_pattern
);
377 if (v6_service_pattern
!= NULL
) {
378 CFRelease(v6_service_pattern
);
380 if (values
!= NULL
&& values
!= values_static
) {
386 if (patterns
!= NULL
) {
389 if (active
!= NULL
&& CFArrayGetCount(active
) == 0) {
393 if (active
== NULL
) {
394 _SCErrorSet(kSCStatusFailed
);
401 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc
,
404 CFStringRef addresses_key
;
408 char if_name
[IFNAMSIZ
];
409 CFStringRef if_name_cf
= NULL
;
410 conninfo_t
* info
= NULL
;
411 const void * * keys
= NULL
;
412 #define KEYS_STATIC_COUNT 10
413 const void * keys_static
[KEYS_STATIC_COUNT
];
414 const void * local_ip_p
;
415 CFStringRef local_ip_str
= NULL
;
416 CFStringRef ret_signature
= NULL
;
417 CFDictionaryRef service_info
= NULL
;
418 int status
= kSCStatusFailed
;
420 if (copyconninfo(sock_fd
, SAE_CONNID_ANY
, &info
) != 0) {
421 status
= kSCStatusInvalidArgument
;
424 if ((info
->ci_flags
& CIF_CONNECTED
) == 0
425 || info
->ci_src
== NULL
) {
428 af
= info
->ci_src
->sa_family
;
431 addresses_key
= kSCPropNetIPv4Addresses
;
432 local_ip_p
= &((struct sockaddr_in
*)
433 (void *)info
->ci_src
)->sin_addr
;
436 addresses_key
= kSCPropNetIPv6Addresses
;
437 local_ip_p
= &((struct sockaddr_in6
*)
438 (void *)info
->ci_src
)->sin6_addr
;
441 status
= kSCStatusInvalidArgument
;
445 /* search for service with matching IP address and interface name */
446 service_info
= copy_services_for_address_family(alloc
, af
);
447 if (service_info
== NULL
) {
450 local_ip_str
= my_IPAddressToCFString(af
, local_ip_p
);
451 if (local_ip_str
== NULL
) {
454 if (info
->ci_ifindex
!= 0
455 && if_indextoname(info
->ci_ifindex
, if_name
) != NULL
) {
457 = CFStringCreateWithCString(NULL
, if_name
,
458 kCFStringEncodingASCII
);
460 count
= CFDictionaryGetCount(service_info
);
461 if (count
> KEYS_STATIC_COUNT
) {
462 keys
= (const void * *)malloc(sizeof(*keys
) * count
);
467 CFDictionaryGetKeysAndValues(service_info
, keys
, NULL
);
468 for (i
= 0; i
< count
; i
++) {
471 CFStringRef signature
;
472 CFDictionaryRef value
;
474 value
= CFDictionaryGetValue(service_info
, keys
[i
]);
475 if (isA_CFDictionary(value
) == NULL
) {
478 signature
= CFDictionaryGetValue(value
,
479 kStoreKeyNetworkSignature
);
480 if (isA_CFString(signature
) == NULL
) {
484 if (if_name_cf
!= NULL
) {
485 CFStringRef confirmed_if
;
488 this_if
= CFDictionaryGetValue(value
,
489 kSCPropInterfaceName
);
490 if (isA_CFString(this_if
) == NULL
491 || !CFEqual(this_if
, if_name_cf
)) {
492 /* no interface or it doesn't match */
496 = CFDictionaryGetValue(value
,
497 kSCPropConfirmedInterfaceName
);
498 if (isA_CFString(confirmed_if
) != NULL
499 && !CFEqual(confirmed_if
, if_name_cf
)) {
500 /* confirmed interface doesn't match */
505 addrs
= CFDictionaryGetValue(value
, addresses_key
);
506 if (isA_CFArray(addrs
) == NULL
) {
509 range
= CFRangeMake(0, CFArrayGetCount(addrs
));
510 if (CFArrayContainsValue(addrs
, range
, local_ip_str
)) {
511 ret_signature
= CFRetain(signature
);
512 status
= kSCStatusOK
;
521 if (if_name_cf
!= NULL
) {
522 CFRelease(if_name_cf
);
524 if (local_ip_str
!= NULL
) {
525 CFRelease(local_ip_str
);
527 if (keys
!= NULL
&& keys
!= keys_static
) {
530 if (service_info
!= NULL
) {
531 CFRelease(service_info
);
533 if (status
!= kSCStatusOK
) {
536 return (ret_signature
);