this repo has no description
at fixPythonPipStalling 668 lines 18 kB view raw
1/* 2 * Copyright (c) 2017-2019 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 * Modification History 26 * 27 * April 17, 2017 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31 32#include "nat64-configuration.h" 33 34#include <TargetConditionals.h> 35#include <CoreFoundation/CoreFoundation.h> 36#include <SystemConfiguration/SystemConfiguration.h> 37#include <SystemConfiguration/SCPrivate.h> 38#if TEST_NAT64_CONFIGURATION 39static Boolean G_set_prefixes_force_failure; 40#define my_if_nametoindex if_nametoindex 41#else 42#include "ip_plugin.h" 43#endif 44 45#define INET6 1 46 47#include <string.h> 48#include <net/if.h> 49#include <sys/ioctl.h> 50#include <sys/socket.h> 51#include <sys/sockio.h> 52#include <netinet/in.h> 53#include <nw/private.h> 54#include <sys/queue.h> 55 56 57/** 58 ** Support functions 59 **/ 60static dispatch_queue_t 61nat64_dispatch_queue(void) 62{ 63 static dispatch_once_t once; 64 static dispatch_queue_t q; 65 66 dispatch_once(&once, ^{ 67 q = dispatch_queue_create("nat64 prefix request queue", NULL); 68 }); 69 70 return q; 71} 72 73static Boolean 74_nat64_prefix_set(const char *if_name, 75 int32_t num_prefixes, 76 nw_nat64_prefix_t *prefixes) 77{ 78 struct if_nat64req req; 79 int ret; 80 int s; 81 82 // pass NAT64 prefixes to the kernel 83 memset(&req, 0, sizeof(req)); 84 strlcpy(req.ifnat64_name, if_name, sizeof(req.ifnat64_name)); 85 86 if (num_prefixes == 0) { 87 SC_log(LOG_NOTICE, "%s: nat64 prefix unavailable", if_name); 88 } 89 90 for (int32_t i = 0; i < num_prefixes; i++) { 91 char prefix_str[NW_NAT64_PREFIX_STR_LENGTH] = {0}; 92 93 nw_nat64_write_prefix_to_string(&prefixes[i], prefix_str, sizeof(prefix_str)); 94 SC_log(LOG_NOTICE, "%s: nat64 prefix[%d] = %s", if_name, i, prefix_str); 95 96 if (i < NAT64_MAX_NUM_PREFIXES) { 97 req.ifnat64_prefixes[i].prefix_len = prefixes[i].length; 98 memcpy(&req.ifnat64_prefixes[i].ipv6_prefix, 99 &prefixes[i].data, 100 MIN(sizeof(req.ifnat64_prefixes[i].ipv6_prefix), sizeof(prefixes[i].data))); // MIN(16, 12) 101 } 102 } 103 104 s = socket(AF_INET, SOCK_DGRAM, 0); 105 if (s == -1) { 106 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); 107 return (FALSE); 108 } 109 ret = ioctl(s, SIOCSIFNAT64PREFIX, &req); 110 close(s); 111 if (ret == -1) { 112 if ((errno != ENOENT) || (num_prefixes != 0)) { 113 SC_log(LOG_ERR, "%s: ioctl(SIOCSIFNAT64PREFIX) failed: %s", if_name, strerror(errno)); 114 } 115 return (FALSE); 116 } 117 118 SC_log(LOG_NOTICE, "%s: nat64 prefix%s updated", if_name, (num_prefixes != 1) ? "es" : ""); 119 return (TRUE); 120} 121 122 123static void 124_nat64_prefix_post(CFStringRef interface, 125 int32_t num_prefixes, 126 nw_nat64_prefix_t *prefixes, 127 CFAbsoluteTime start_time) 128{ 129#if TEST_NAT64_CONFIGURATION 130#pragma unused(interface) 131#pragma unused(num_prefixes) 132#pragma unused(prefixes) 133#pragma unused(start_time) 134 return; 135#else /* TEST_NAT64_CONFIGURATION */ 136 137 CFStringRef key; 138 139 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 140 kSCDynamicStoreDomainState, 141 interface, 142 kSCEntNetNAT64); 143 if (num_prefixes >= 0) { 144 CFDateRef date; 145 CFMutableDictionaryRef plat_dict; 146 147 plat_dict = CFDictionaryCreateMutable(NULL, 148 0, 149 &kCFTypeDictionaryKeyCallBacks, 150 &kCFTypeDictionaryValueCallBacks); 151 /* prefixes (if available) */ 152 if (num_prefixes > 0) { 153 CFMutableArrayRef prefix_array; 154 155 prefix_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 156 for (int32_t i = 0; i < num_prefixes; i++) { 157 char prefix_str[NW_NAT64_PREFIX_STR_LENGTH] = {0}; 158 CFStringRef str; 159 160 nw_nat64_write_prefix_to_string(&prefixes[i], prefix_str, sizeof(prefix_str)); 161 str = CFStringCreateWithCString(NULL, prefix_str, kCFStringEncodingASCII); 162 CFArrayAppendValue(prefix_array, str); 163 CFRelease(str); 164 } 165 CFDictionarySetValue(plat_dict, kSCPropNetNAT64PrefixList, prefix_array); 166 CFRelease(prefix_array); 167 } 168 /* start time */ 169 date = CFDateCreate(NULL, start_time); 170 CFDictionarySetValue(plat_dict, 171 kSCPropNetNAT64PLATDiscoveryStartTime, 172 date); 173 CFRelease(date); 174 175 /* completion time */ 176 date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); 177 CFDictionarySetValue(plat_dict, 178 kSCPropNetNAT64PLATDiscoveryCompletionTime, 179 date); 180 CFRelease(date); 181 182 (void)SCDynamicStoreSetValue(NULL, key, plat_dict); 183 SC_log(LOG_NOTICE, "%@: PLAT discovery complete %@", 184 interface, plat_dict); 185 CFRelease(plat_dict); 186 } else { 187 (void)SCDynamicStoreRemoveValue(NULL, key); 188 } 189 CFRelease(key); 190#endif /* TEST_NAT64_CONFIGURATION */ 191 return; 192} 193 194static nw_nat64_prefixes_resolver_t 195_nat64_resolver_create(unsigned int if_index) 196{ 197 nw_interface_t interface; 198 nw_parameters_t params; 199 nw_nat64_prefixes_resolver_t resolver; 200 201 params = nw_parameters_create(); 202 interface = nw_interface_create_with_index(if_index); 203 if (interface == NULL) { 204 SC_log(LOG_NOTICE, 205 "nw_interface_create_with_index(%u) failed", 206 if_index); 207 return (NULL); 208 } 209 nw_parameters_require_interface(params, interface); 210 nw_parameters_set_required_address_family(params, AF_INET6); 211 nw_release(interface); 212 resolver = nw_nat64_prefixes_resolver_create(params); 213 nw_release(params); 214 return (resolver); 215} 216 217/** 218 ** NAT64PrefixRequest 219 **/ 220struct NAT64PrefixRequest; 221typedef struct NAT64PrefixRequest NAT64PrefixRequest, * NAT64PrefixRequestRef; 222#define NAT64PrefixRequest_LIST_ENTRY LIST_ENTRY(NAT64PrefixRequest) 223#define NAT64PrefixRequest_LIST_HEAD LIST_HEAD(NAT64PrefixRequestHead, \ 224 NAT64PrefixRequest) 225static NAT64PrefixRequest_LIST_HEAD S_request_head; 226static struct NAT64PrefixRequestHead * S_request_head_p = &S_request_head; 227 228typedef CF_ENUM(uint16_t, RequestFlags) { 229 kRequestFlagsNone = 0x0000, 230 kRequestFlagsValid = 0x0001, 231}; 232 233struct NAT64PrefixRequest { 234 NAT64PrefixRequest_LIST_ENTRY link; 235 nw_nat64_prefixes_resolver_t resolver; 236 const char * if_name; 237 CFStringRef if_name_cf; 238 unsigned int if_index; 239 unsigned int retain_count; 240 RequestFlags flags; 241}; 242 243static Boolean 244NAT64PrefixRequestFlagsIsSet(NAT64PrefixRequestRef request, RequestFlags flags) 245{ 246 return ((request->flags & flags) != 0); 247} 248 249static void 250NAT64PrefixRequestFlagsSet(NAT64PrefixRequestRef request, RequestFlags flags) 251{ 252 request->flags |= flags; 253} 254 255static void 256NAT64PrefixRequestFlagsClear(NAT64PrefixRequestRef request, RequestFlags flags) 257{ 258 request->flags &= ~flags; 259} 260 261static NAT64PrefixRequestRef 262NAT64PrefixRequestFindInterface(CFStringRef if_name_cf) 263{ 264 NAT64PrefixRequestRef scan; 265 266 LIST_FOREACH(scan, S_request_head_p, link) { 267 if (CFEqual(if_name_cf, scan->if_name_cf)) { 268 return (scan); 269 } 270 } 271 return (NULL); 272} 273 274static void 275NAT64PrefixRequestRetain(NAT64PrefixRequestRef request) 276{ 277 request->retain_count++; 278 SC_log(LOG_DEBUG, "%s: %s %p %u", 279 request->if_name, __FUNCTION__, 280 request, request->retain_count); 281 return; 282} 283 284static NAT64PrefixRequestRef 285NAT64PrefixRequestCreate(CFStringRef if_name_cf) 286{ 287 unsigned int if_index; 288 char * if_name; 289 NAT64PrefixRequestRef request; 290 291 if_name = _SC_cfstring_to_cstring(if_name_cf, NULL, 0, 292 kCFStringEncodingASCII); 293 if (if_name == NULL) { 294 SC_log(LOG_ERR, 295 "%@: could not convert interface name", 296 if_name_cf); 297 return (NULL); 298 } 299 if_index = my_if_nametoindex(if_name); 300 if (if_index == 0) { 301 SC_log(LOG_NOTICE, 302 "%s: interface does not exist", if_name); 303 CFAllocatorDeallocate(NULL, if_name); 304 return (NULL); 305 } 306 request = malloc(sizeof(*request)); 307 SC_log(LOG_DEBUG, "%@: %s %p", if_name_cf, __FUNCTION__, request); 308 bzero(request, sizeof(*request)); 309 request->if_name_cf = CFRetain(if_name_cf); 310 request->if_name = if_name; 311 request->if_index = if_index; 312 LIST_INSERT_HEAD(S_request_head_p, request, link); 313 NAT64PrefixRequestFlagsSet(request, kRequestFlagsValid); 314 NAT64PrefixRequestRetain(request); 315 return (request); 316} 317 318static void 319NAT64PrefixRequestStopResolver(NAT64PrefixRequestRef request) 320{ 321 if (request->resolver != NULL) { 322 SC_log(LOG_DEBUG, "%s: %s", 323 request->if_name, __FUNCTION__); 324 nw_nat64_prefixes_resolver_cancel(request->resolver); 325 nw_release(request->resolver); 326 request->resolver = NULL; 327 } 328 return; 329} 330 331static void 332NAT64PrefixRequestInvalidate(NAT64PrefixRequestRef request) 333{ 334 SC_log(LOG_DEBUG, "%s: %s", request->if_name, __FUNCTION__); 335 NAT64PrefixRequestStopResolver(request); 336 if (NAT64PrefixRequestFlagsIsSet(request, kRequestFlagsValid)) { 337 NAT64PrefixRequestFlagsClear(request, kRequestFlagsValid); 338 LIST_REMOVE(request, link); 339 } 340 return; 341} 342 343static void 344NAT64PrefixRequestRelease(NAT64PrefixRequestRef request) 345{ 346 if (request->retain_count == 0) { 347 SC_log(LOG_ERR, "%s: retain count is zero %p", 348 __FUNCTION__, request); 349 return; 350 } 351 request->retain_count--; 352 SC_log(LOG_DEBUG, 353 "%s: %s %p %u", 354 request->if_name, __FUNCTION__, request, request->retain_count); 355 if (request->retain_count != 0) { 356 return; 357 } 358 NAT64PrefixRequestInvalidate(request); 359 SC_log(LOG_DEBUG, "%s %s: deallocate %p", 360 request->if_name, __FUNCTION__, request); 361 if (request->if_name_cf != NULL) { 362 CFRelease(request->if_name_cf); 363 request->if_name_cf = NULL; 364 } 365 if (request->if_name != NULL) { 366 CFAllocatorDeallocate(NULL, (void *)request->if_name); 367 request->if_name = NULL; 368 } 369 free(request); 370 return; 371} 372 373static void 374NAT64PrefixRequestStart(NAT64PrefixRequestRef request) 375{ 376 dispatch_block_t cancel_handler; 377 nw_nat64_copy_prefixes_block_t handler; 378 nw_nat64_prefixes_resolver_t resolver; 379 CFAbsoluteTime start_time; 380 381 SC_log(LOG_INFO, "%s: %s", request->if_name, __FUNCTION__); 382 if (request->resolver != NULL) { 383 SC_log(LOG_DEBUG, "%s %s: resolver is already active", 384 request->if_name, __FUNCTION__); 385 return; 386 } 387 resolver = _nat64_resolver_create(request->if_index); 388 if (resolver == NULL) { 389 return; 390 } 391 NAT64PrefixRequestRetain(request); 392 cancel_handler = ^{ 393 SC_log(LOG_DEBUG, "%s: NAT64 resolver cancelled", 394 request->if_name); 395 NAT64PrefixRequestRelease(request); 396 return; 397 }; 398 start_time = CFAbsoluteTimeGetCurrent(); 399 handler = ^(int32_t num_prefixes, nw_nat64_prefix_t *prefixes) { 400 Boolean remove_resolver = FALSE; 401 402 if (!NAT64PrefixRequestFlagsIsSet(request, 403 kRequestFlagsValid)) { 404 SC_log(LOG_INFO, "%s: NAT64 request is stale %p", 405 request->if_name, request); 406 return; 407 } 408 if (prefixes != NULL) { 409 /* set prefixes on the interface */ 410 _nat64_prefix_set(request->if_name, 411 num_prefixes, prefixes); 412 remove_resolver = TRUE; 413 } else { 414 SC_log(LOG_ERR, "%s: NAT64 no prefixes", 415 request->if_name); 416 } 417 _nat64_prefix_post(request->if_name_cf, 418 num_prefixes, prefixes, start_time); 419#if TEST_NAT64_CONFIGURATION 420 if (G_set_prefixes_force_failure) { 421 remove_resolver = TRUE; 422 } 423#endif /* TEST_NAT64_CONFIGURATION */ 424 if (remove_resolver) { 425 /* remove resolver */ 426 NAT64PrefixRequestInvalidate(request); 427 NAT64PrefixRequestRelease(request); 428 return; 429 } 430 }; 431 nw_nat64_prefixes_resolver_set_cancel_handler(resolver, cancel_handler); 432 nw_nat64_prefixes_resolver_set_update_handler(resolver, 433 nat64_dispatch_queue(), 434 handler); 435 nw_nat64_prefixes_resolver_start(resolver); 436 request->resolver = resolver; 437 return; 438} 439 440/** 441 ** Set iterators 442 **/ 443static void 444_nat64_process_prefix_request(const void *value, void *context) 445{ 446#pragma unused(context) 447 CFStringRef interface = (CFStringRef)value; 448 NAT64PrefixRequestRef request; 449 450 request = NAT64PrefixRequestFindInterface(interface); 451 if (request != NULL) { 452 return; 453 } 454 455 /* start a new request */ 456 request = NAT64PrefixRequestCreate(interface); 457 if (request != NULL) { 458 NAT64PrefixRequestStart(request); 459 } 460 return; 461} 462 463static void 464_nat64_process_prefix_update(const void *value, void *context) 465{ 466#pragma unused(context) 467 CFStringRef interface = (CFStringRef)value; 468 NAT64PrefixRequestRef request; 469 470 request = NAT64PrefixRequestFindInterface(interface); 471 if (request == NULL) { 472 SC_log(LOG_DEBUG, "%@ %s: no existing request", 473 interface, __FUNCTION__); 474 return; 475 } 476 477 /* destroy the old one, start a new one */ 478 SC_log(LOG_INFO, "%@: %s", interface, __FUNCTION__); 479 NAT64PrefixRequestInvalidate(request); 480 NAT64PrefixRequestRelease(request); 481 482 /* start a new request */ 483 request = NAT64PrefixRequestCreate(interface); 484 if (request != NULL) { 485 NAT64PrefixRequestStart(request); 486 } 487 return; 488} 489 490static void 491_nat64_process_cancel_request(const void * value, void * context) 492{ 493#pragma unused(context) 494 CFStringRef interface = (CFStringRef)value; 495 NAT64PrefixRequestRef request; 496 497 /* if there's an in-flight request, remove it */ 498 request = NAT64PrefixRequestFindInterface(interface); 499 if (request == NULL) { 500 /* no resolver */ 501 SC_log(LOG_DEBUG, "%@ %s: no active NAT64 request", 502 interface, __FUNCTION__); 503 return; 504 } 505 SC_log(LOG_DEBUG, "%s %s: removing NAT64 request", 506 request->if_name, __FUNCTION__); 507 _nat64_prefix_set(request->if_name, 0, NULL); 508 NAT64PrefixRequestInvalidate(request); 509 NAT64PrefixRequestRelease(request); 510 return; 511} 512 513 514#pragma mark - 515#pragma mark NAT64 prefix functions (for IPMonitor) 516 517 518__private_extern__ 519Boolean 520is_nat64_prefix_request(CFStringRef change, CFStringRef *interface) 521{ 522 CFArrayRef components; 523 static CFStringRef prefix = NULL; 524 Boolean yn = FALSE; 525 static dispatch_once_t once; 526 527 dispatch_once(&once, ^{ 528 prefix = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState); 529 }); 530 531 *interface = NULL; 532 if (!CFStringHasPrefix(change, prefix) || 533 !CFStringHasSuffix(change, kSCEntNetNAT64PrefixRequest)) { 534 return FALSE; 535 } 536 537 components = CFStringCreateArrayBySeparatingStrings(NULL, change, CFSTR("/")); 538 if (CFArrayGetCount(components) == 5) { 539 *interface = CFArrayGetValueAtIndex(components, 3); 540 CFRetain(*interface); 541 yn = TRUE; 542 } 543 CFRelease(components); 544 545 return yn; 546} 547 548 549__private_extern__ void 550nat64_prefix_request_add_pattern(CFMutableArrayRef patterns) 551{ 552 CFStringRef pattern; 553 554 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 555 kSCDynamicStoreDomainState, 556 kSCCompAnyRegex, 557 kSCEntNetNAT64PrefixRequest); 558 CFArrayAppendValue(patterns, pattern); 559 CFRelease(pattern); 560 return; 561} 562 563static void 564nat64_configuration_update_locked(CFSetRef requests, CFSetRef updates, 565 CFSetRef cancellations) 566{ 567 if (cancellations != NULL) { 568 CFSetApplyFunction(cancellations, 569 _nat64_process_cancel_request, 570 NULL); 571 } 572 // for any interface that changed, refresh the nat64 prefix 573 if (updates != NULL) { 574 CFSetApplyFunction(updates, _nat64_process_prefix_update, NULL); 575 } 576 577 // for any requested interface, query the nat64 prefix 578 if (requests != NULL) { 579 CFSetApplyFunction(requests, _nat64_process_prefix_request, 580 NULL); 581 } 582 return; 583} 584 585__private_extern__ 586void 587nat64_configuration_update(CFSetRef requests, CFSetRef updates, 588 CFSetRef cancellations) 589{ 590 dispatch_block_t update_block; 591 592 if (requests != NULL) { 593 CFRetain(requests); 594 } 595 if (updates != NULL) { 596 CFRetain(updates); 597 } 598 if (cancellations != NULL) { 599 CFRetain(cancellations); 600 } 601 update_block = ^{ 602 SC_log(LOG_DEBUG, 603 "NAT64 requests %@ updates %@ cancellations %@", 604 requests, updates, cancellations); 605 nat64_configuration_update_locked(requests, updates, 606 cancellations); 607 if (requests != NULL) { 608 CFRelease(requests); 609 } 610 if (updates != NULL) { 611 CFRelease(updates); 612 } 613 if (cancellations != NULL) { 614 CFRelease(cancellations); 615 } 616 }; 617 dispatch_async(nat64_dispatch_queue(), update_block); 618 return; 619} 620 621#if TEST_NAT64_CONFIGURATION 622int 623main(int argc, char * argv[]) 624{ 625 CFStringRef if_name_cf; 626 CFMutableSetRef set; 627 628 set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 629 for (int i = 1; i < argc; i++) { 630 if_name_cf = CFStringCreateWithCString(NULL, 631 argv[i], 632 kCFStringEncodingASCII); 633 CFSetAddValue(set, if_name_cf); 634 CFRelease(if_name_cf); 635 } 636 if (CFSetGetCount(set) == 0) { 637 fprintf(stderr, "nothing to do\n"); 638 exit(0); 639 } 640 SC_log(LOG_NOTICE, "Starting %@", set); 641 nat64_configuration_update(set, NULL, NULL); 642 sleep(2); 643 644 SC_log(LOG_NOTICE, "Starting 2 %@", set); 645 nat64_configuration_update(set, NULL, NULL); 646 sleep(2); 647 648 SC_log(LOG_NOTICE, "Updating"); 649 nat64_configuration_update(NULL, set, NULL); 650 sleep(2); 651 652 SC_log(LOG_NOTICE, "Cancelling"); 653 nat64_configuration_update(NULL, NULL, set); 654 sleep(2); 655 656 G_set_prefixes_force_failure = TRUE; 657 SC_log(LOG_NOTICE, "Starting (with forced failure) %@", set); 658 nat64_configuration_update(set, NULL, NULL); 659 sleep(2); 660 661 SC_log(LOG_NOTICE, "Starting (with forced failure 2) %@", set); 662 nat64_configuration_update(set, NULL, NULL); 663 664 dispatch_main(); 665 exit(0); 666 return (0); 667} 668#endif /* TEST_NAT64_CONFIGURATION */