1/* 2 * Copyright (c) 2006, 2008, 2009, 2011-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * SCNetworkSignature.c 26 * - implementation of SCNetworkSignatureRef API that allows access to 27 network identification information 28 * 29 */ 30/* 31 * Modification History 32 * 33 * November 6, 2006 Dieter Siegmund (dieter@apple.com) 34 * - initial revision 35 */ 36 37 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> 51#include <net/if.h> 52#include <network/conninfo.h> 53 54#pragma mark SCNetworkSignature Supporting APIs 55 56static CFStringRef 57create_global_state_v4_key(void) 58{ 59 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 60 kSCDynamicStoreDomainState, 61 kSCEntNetIPv4); 62 63} 64 65static CFStringRef 66create_global_setup_v4_key(void) 67{ 68 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 69 kSCDynamicStoreDomainSetup, 70 kSCEntNetIPv4); 71} 72 73static CFStringRef 74create_ipv4_services_pattern(void) 75{ 76 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 77 kSCDynamicStoreDomainState, 78 kSCCompAnyRegex, 79 kSCEntNetIPv4); 80} 81 82static CFStringRef 83create_ipv6_services_pattern(void) 84{ 85 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 86 kSCDynamicStoreDomainState, 87 kSCCompAnyRegex, 88 kSCEntNetIPv6); 89} 90 91static CFDictionaryRef 92copy_services_for_address_family(CFAllocatorRef alloc, 93 int af) 94{ 95 CFDictionaryRef info; 96 CFArrayRef patterns; 97 CFStringRef pattern; 98 CFStringRef prop; 99 100 prop = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6; 101 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 102 kSCDynamicStoreDomainState, 103 kSCCompAnyRegex, 104 prop); 105 patterns = CFArrayCreate(NULL, 106 (const void * *)&pattern, 1, 107 &kCFTypeArrayCallBacks); 108 CFRelease(pattern); 109 info = SCDynamicStoreCopyMultiple(NULL, NULL, patterns); 110 CFRelease(patterns); 111 112 return (info); 113} 114 115 116static CF_RETURNS_RETAINED CFStringRef 117my_IPAddressToCFString(int af, const void * src_p) 118{ 119 char ntopbuf[INET6_ADDRSTRLEN]; 120 121 if (inet_ntop(af, src_p, ntopbuf, sizeof(ntopbuf)) != NULL) { 122 return (CFStringCreateWithCString(NULL, ntopbuf, 123 kCFStringEncodingASCII)); 124 } 125 return (NULL); 126} 127 128#pragma mark - 129 130 131#pragma mark SCNetworkSignature APIs 132 133CFStringRef 134SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc, 135 const struct sockaddr * addr) 136{ 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; 143 in_addr_t s_addr; 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; 149 150 /* only accept 0.0.0.0 (i.e. default) for now */ 151 if (addr == NULL 152 || addr->sa_family != AF_INET 153 || addr->sa_len != sizeof(struct sockaddr_in)) { 154 _SCErrorSet(kSCStatusInvalidArgument); 155 goto done; 156 } 157 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)); 161 if (s_addr != 0) { 162 _SCErrorSet(kSCStatusInvalidArgument); 163 goto done; 164 } 165 166 global_state_v4_key = create_global_state_v4_key(); 167 keys = CFArrayCreate(NULL, (const void * *)&global_state_v4_key, 168 1, &kCFTypeArrayCallBacks); 169 170 v4_service_pattern = create_ipv4_services_pattern(); 171 patterns = CFArrayCreate(NULL, (const void * *)&v4_service_pattern, 1, 172 &kCFTypeArrayCallBacks); 173 174 info = SCDynamicStoreCopyMultiple(NULL, keys, patterns); 175 176 if (info == NULL 177 || CFDictionaryGetCount(info) == 0) { 178 goto done; 179 } 180 181 global_v4_state_dict = CFDictionaryGetValue(info, global_state_v4_key); 182 183 if (isA_CFDictionary(global_v4_state_dict) == NULL) { 184 goto done; 185 } 186 187 service_id = CFDictionaryGetValue(global_v4_state_dict, 188 kSCDynamicStorePropNetPrimaryService); 189 190 if (isA_CFString(service_id) == NULL) { 191 goto done; 192 } 193 194 service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 195 kSCDynamicStoreDomainState, 196 service_id, kSCEntNetIPv4); 197 198 service_dict = CFDictionaryGetValue(info, service); 199 200 201 if (isA_CFDictionary(service_dict) == NULL 202 || CFDictionaryGetCount(service_dict) == 0) { 203 goto done; 204 } 205 206 ident = CFDictionaryGetValue(service_dict, kStoreKeyNetworkSignature); 207 ident = isA_CFString(ident); 208done: 209 if (ident != NULL) { 210 CFRetain(ident); 211 } else { 212 _SCErrorSet(kSCStatusFailed); 213 } 214 if (info != NULL) { 215 CFRelease(info); 216 } 217 if (global_state_v4_key != NULL) { 218 CFRelease(global_state_v4_key); 219 } 220 if (service != NULL) { 221 CFRelease(service); 222 } 223 if (keys != NULL) { 224 CFRelease(keys); 225 } 226 if (patterns != NULL) { 227 CFRelease(patterns); 228 } 229 if (v4_service_pattern != NULL) { 230 CFRelease(v4_service_pattern); 231 } 232 return (ident); 233} 234 235CFArrayRef /* of CFStringRef's */ 236SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc) 237{ 238 CFMutableArrayRef active = NULL; 239 CFIndex count = 0; 240 CFStringRef global_setup_v4_key = NULL; 241 CFDictionaryRef global_v4_dict; 242 int i; 243 CFDictionaryRef info = NULL; 244 CFArrayRef keys = NULL; 245 CFMutableArrayRef patterns = NULL; 246 CFRange range; 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]; 254 255 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 256 257 global_setup_v4_key = create_global_setup_v4_key(); 258 keys = CFArrayCreate(NULL, (const void * *)&global_setup_v4_key, 1, 259 &kCFTypeArrayCallBacks); 260 261 v4_service_pattern = create_ipv4_services_pattern(); 262 CFArrayAppendValue(patterns, v4_service_pattern); 263 264 v6_service_pattern = create_ipv6_services_pattern(); 265 CFArrayAppendValue(patterns, v6_service_pattern); 266 267 info = SCDynamicStoreCopyMultiple(NULL, keys, patterns); 268 269 if (info == NULL 270 || CFDictionaryGetCount(info) == 0) { 271 goto done; 272 } 273 274 services_dict = CFDictionaryCreateMutableCopy(NULL, 0, info); 275 /* 276 * The service_dict should only contain services and once each 277 * service has been visited, it will be removed from the dictionary. 278 */ 279 CFDictionaryRemoveValue(services_dict, global_setup_v4_key); 280 281 global_v4_dict = CFDictionaryGetValue(info, global_setup_v4_key); 282 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); 288 } 289 } 290 291 active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 292 293 range = CFRangeMake(0, 0); 294 295 for (i = 0; i < count ; i++) { 296 int j; 297 CFStringRef network_sig; 298 CFStringRef service; 299 CFStringRef service_id; 300 CFDictionaryRef service_info; 301 CFStringRef afs[2] = {kSCEntNetIPv4, kSCEntNetIPv6}; 302 303 service_id = CFArrayGetValueAtIndex(service_order, i); 304 305 if (isA_CFString(service_id) == NULL) { 306 continue; 307 } 308 309 for (j = 0; j < 2; j++) { 310 service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 311 kSCDynamicStoreDomainState, 312 service_id, afs[j]); 313 314 service_info = CFDictionaryGetValue(services_dict, service); 315 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); 322 network_sig = NULL; 323 range.length++; 324 } 325 CFDictionaryRemoveValue(services_dict, service); 326 } 327 CFRelease(service); 328 } 329 } 330 331 count = CFDictionaryGetCount(services_dict); 332 if (count != 0) { 333 if (count > KEYS_STATIC_COUNT) { 334 values = (const void * *)malloc(sizeof(*values) * count); 335 } else { 336 values = values_static; 337 } 338 CFDictionaryGetKeysAndValues(services_dict, NULL, 339 (const void * *)values); 340 } 341 342 for (i = 0; i < count; i++) { 343 CFStringRef network_sig; 344 CFDictionaryRef service_dict = (CFDictionaryRef)values[i]; 345 346 if (isA_CFDictionary(service_dict) == NULL) { 347 continue; 348 } 349 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); 356 range.length++; 357 network_sig = NULL; 358 } 359 } 360 done: 361 if (info != NULL) { 362 CFRelease(info); 363 } 364 if (services_dict != NULL) { 365 CFRelease(services_dict); 366 } 367 if (global_setup_v4_key != NULL) { 368 CFRelease(global_setup_v4_key); 369 } 370 if (v4_service_pattern != NULL) { 371 CFRelease(v4_service_pattern); 372 } 373 if (v6_service_pattern != NULL) { 374 CFRelease(v6_service_pattern); 375 } 376 if (values != NULL && values != values_static) { 377 free(values); 378 } 379 if (keys != NULL) { 380 CFRelease(keys); 381 } 382 if (patterns != NULL) { 383 CFRelease(patterns); 384 } 385 if (active != NULL && CFArrayGetCount(active) == 0) { 386 CFRelease(active); 387 active = NULL; 388 } 389 if (active == NULL) { 390 _SCErrorSet(kSCStatusFailed); 391 } 392 return (active); 393} 394 395 396CFStringRef 397SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc, 398 int sock_fd) 399{ 400 CFStringRef addresses_key; 401 int af; 402 CFIndex count; 403 int i; 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; 415 416 if (copyconninfo(sock_fd, CONNID_ANY, &info) != 0) { 417 status = kSCStatusInvalidArgument; 418 goto done; 419 } 420 if ((info->ci_flags & CIF_CONNECTED) == 0 421 || info->ci_src == NULL) { 422 goto done; 423 } 424 af = info->ci_src->sa_family; 425 switch (af) { 426 case AF_INET: 427 addresses_key = kSCPropNetIPv4Addresses; 428 local_ip_p = &((struct sockaddr_in *) 429 (void *)info->ci_src)->sin_addr; 430 break; 431 case AF_INET6: 432 addresses_key = kSCPropNetIPv6Addresses; 433 local_ip_p = &((struct sockaddr_in6 *) 434 (void *)info->ci_src)->sin6_addr; 435 break; 436 default: 437 status = kSCStatusInvalidArgument; 438 goto done; 439 } 440 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) { 444 goto done; 445 } 446 local_ip_str = my_IPAddressToCFString(af, local_ip_p); 447 if (local_ip_str == NULL) { 448 goto done; 449 } 450 if (info->ci_ifindex != 0 451 && if_indextoname(info->ci_ifindex, if_name) != NULL) { 452 if_name_cf 453 = CFStringCreateWithCString(NULL, if_name, 454 kCFStringEncodingASCII); 455 } 456 count = CFDictionaryGetCount(service_info); 457 if (count > KEYS_STATIC_COUNT) { 458 keys = (const void * *)malloc(sizeof(*keys) * count); 459 } 460 else { 461 keys = keys_static; 462 } 463 CFDictionaryGetKeysAndValues(service_info, keys, NULL); 464 for (i = 0; i < count; i++) { 465 CFArrayRef addrs; 466 CFRange range; 467 CFStringRef signature; 468 CFDictionaryRef value; 469 470 value = CFDictionaryGetValue(service_info, keys[i]); 471 if (isA_CFDictionary(value) == NULL) { 472 continue; 473 } 474 signature = CFDictionaryGetValue(value, 475 kStoreKeyNetworkSignature); 476 if (isA_CFString(signature) == NULL) { 477 /* no signature */ 478 continue; 479 } 480 if (if_name_cf != NULL) { 481 CFStringRef confirmed_if; 482 CFStringRef this_if; 483 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 */ 489 continue; 490 } 491 confirmed_if 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 */ 497 continue; 498 } 499 } 500 501 addrs = CFDictionaryGetValue(value, addresses_key); 502 if (isA_CFArray(addrs) == NULL) { 503 continue; 504 } 505 range = CFRangeMake(0, CFArrayGetCount(addrs)); 506 if (CFArrayContainsValue(addrs, range, local_ip_str)) { 507 ret_signature = CFRetain(signature); 508 status = kSCStatusOK; 509 break; 510 } 511 } 512 513 done: 514 if (info != NULL) { 515 freeconninfo(info); 516 } 517 if (if_name_cf != NULL) { 518 CFRelease(if_name_cf); 519 } 520 if (local_ip_str != NULL) { 521 CFRelease(local_ip_str); 522 } 523 if (keys != NULL && keys != keys_static) { 524 free(keys); 525 } 526 if (service_info != NULL) { 527 CFRelease(service_info); 528 } 529 if (status != kSCStatusOK) { 530 _SCErrorSet(status); 531 } 532 return (ret_signature); 533} 534 535#pragma mark - 536