1/* 2 * Copyright (c) 2000, 2001, 2003-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 * Modification History 26 * 27 * July 9, 2001 Allan Nathanson <ajn@apple.com> 28 * - added "-r" option for checking network reachability 29 * - added "-w" option to check/wait for the presence of a 30 * dynamic store key. 31 * 32 * June 1, 2001 Allan Nathanson <ajn@apple.com> 33 * - public API conversion 34 * 35 * November 9, 2000 Allan Nathanson <ajn@apple.com> 36 * - initial revision 37 */ 38 39#include "scutil.h" 40#include "prefs.h" 41#include "tests.h" 42 43#include <netdb.h> 44#include <netdb_async.h> 45#include <notify.h> 46#include <sys/time.h> 47#include <net/if.h> 48#include <netinet/in.h> 49#include <arpa/inet.h> 50 51#include <dnsinfo.h> 52#include "dnsinfo_internal.h" 53#include <network_information.h> 54#include "SCNetworkReachabilityInternal.h" 55#include <CommonCrypto/CommonDigest.h> 56 57 58static Boolean resolver_bypass; 59 60 61static CF_RETURNS_RETAINED CFMutableDictionaryRef 62_setupReachabilityOptions(int argc, char **argv, const char *interface) 63{ 64 int i; 65 CFMutableDictionaryRef options; 66 67 options = CFDictionaryCreateMutable(NULL, 68 0, 69 &kCFTypeDictionaryKeyCallBacks, 70 &kCFTypeDictionaryValueCallBacks); 71 72 for (i = 0; i < argc; i++) { 73 if (strcasecmp(argv[i], "interface") == 0) { 74 if (++i >= argc) { 75 SCPrint(TRUE, stderr, CFSTR("No interface\n")); 76 CFRelease(options); 77 exit(1); 78 } 79 80 interface = argv[i]; 81 continue; 82 } 83 84 85 if (strcasecmp(argv[i], "server") == 0) { 86 CFDictionarySetValue(options, 87 kSCNetworkReachabilityOptionServerBypass, 88 kCFBooleanFalse); 89 continue; 90 } else if (strcasecmp(argv[i], "no-server") == 0) { 91 CFDictionarySetValue(options, 92 kSCNetworkReachabilityOptionServerBypass, 93 kCFBooleanTrue); 94 continue; 95 } 96 97 98 if (strcasecmp(argv[i], "no-connection-on-demand") == 0) { 99 CFDictionarySetValue(options, 100 kSCNetworkReachabilityOptionConnectionOnDemandBypass, 101 kCFBooleanTrue); 102 continue; 103 } 104 105 if (strcasecmp(argv[i], "no-resolve") == 0) { 106 CFDictionarySetValue(options, 107 kSCNetworkReachabilityOptionResolverBypass, 108 kCFBooleanTrue); 109 resolver_bypass = TRUE; 110 continue; 111 } 112 113 if (strcasecmp(argv[i], "ptr") == 0) { 114 CFDictionarySetValue(options, 115 kSCNetworkReachabilityOptionPTRAddress, 116 kCFBooleanTrue); 117 continue; 118 } 119 120 if (strlen(argv[i]) == 0) { 121 continue; 122 } 123 124 SCPrint(TRUE, stderr, CFSTR("Unrecognized option: %s\n"), argv[i]); 125 CFRelease(options); 126 exit(1); 127 } 128 129 if (interface != NULL) { 130 CFStringRef str; 131 132 if (if_nametoindex(interface) == 0) { 133 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface); 134 exit(1); 135 } 136 137 str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII); 138 CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str); 139 CFRelease(str); 140 } 141 142 if (CFDictionaryGetCount(options) == 0) { 143 CFRelease(options); 144 options = NULL; 145 } 146 147 return options; 148} 149 150 151static SCNetworkReachabilityRef 152_setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) 153{ 154 const char *ip_address = argv[0]; 155 char *ip_addressN = NULL; 156 const char *interface; 157 CFMutableDictionaryRef options = NULL; 158 const char *remote_address = NULL; 159 char *remote_addressN= NULL; 160 const char *remote_interface; 161 struct sockaddr_in sin; 162 struct sockaddr_in6 sin6; 163 SCNetworkReachabilityRef target = NULL; 164 165 bzero(&sin, sizeof(sin)); 166 sin.sin_len = sizeof(sin); 167 sin.sin_family = AF_INET; 168 169 bzero(&sin6, sizeof(sin6)); 170 sin6.sin6_len = sizeof(sin6); 171 sin6.sin6_family = AF_INET6; 172 173 interface = strchr(ip_address, '%'); 174 if (interface != NULL) { 175 ip_addressN = strdup(ip_address); 176 ip_addressN[interface - ip_address] = '\0'; 177 ip_address = ip_addressN; 178 interface++; 179 } 180 181 if ((argc > 1) && (strlen(argv[1]) > 0)) { 182 remote_address = argv[1]; 183 184 remote_interface = strchr(remote_address, '%'); 185 if (remote_interface != NULL) { 186 remote_addressN = strdup(remote_address); 187 remote_addressN[remote_interface - remote_address] = '\0'; 188 remote_address = remote_addressN; 189 remote_interface++; 190 } 191 } 192 193 if (inet_aton(ip_address, &sin.sin_addr) == 1) { 194 struct sockaddr_in r_sin; 195 196 if (argc > 1) { 197 bzero(&r_sin, sizeof(r_sin)); 198 r_sin.sin_len = sizeof(r_sin); 199 r_sin.sin_family = AF_INET; 200 } 201 202 if ((argc == 1) 203 || (remote_address == NULL) 204 || (inet_aton(remote_address, &r_sin.sin_addr) == 0)) { 205 if (argc > 2) { 206 options = _setupReachabilityOptions(argc - 2, argv + 2, interface); 207 } 208 if (options == NULL) { 209 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin); 210 if (context != NULL) { 211 context->info = "by address"; 212 } 213 } else { 214 CFDataRef data; 215 216 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin)); 217 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); 218 CFRelease(data); 219 220 if (context != NULL) { 221 if (CFDictionaryContainsKey(options, 222 kSCNetworkReachabilityOptionInterface)) { 223 if (CFDictionaryGetCount(options) == 2) { 224 context->info = "by address w/scope"; 225 } else { 226 context->info = "by address w/scope and options"; 227 } 228 } else { 229 context->info = "by address w/options"; 230 } 231 } 232 } 233 } else { 234 if (remote_interface != NULL) { 235 if ((interface != NULL) && (strcmp(interface, remote_interface) != 0)) { 236 SCPrint(TRUE, stderr, 237 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"), 238 interface, 239 remote_interface); 240 exit(1); 241 } 242 243 interface = remote_interface; 244 } 245 246 options = _setupReachabilityOptions(argc - 2, argv + 2, interface); 247 if (options == NULL) { 248 target = SCNetworkReachabilityCreateWithAddressPair(NULL, 249 (struct sockaddr *)&sin, 250 (struct sockaddr *)&r_sin); 251 if (context != NULL) { 252 context->info = "by address pair"; 253 } 254 } else { 255 CFDataRef data; 256 257 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin)); 258 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data); 259 CFRelease(data); 260 data = CFDataCreate(NULL, (const UInt8 *)&r_sin, sizeof(r_sin)); 261 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); 262 CFRelease(data); 263 264 if (context != NULL) { 265 if (CFDictionaryContainsKey(options, 266 kSCNetworkReachabilityOptionInterface)) { 267 if (CFDictionaryGetCount(options) == 3) { 268 context->info = "by address pair w/scope"; 269 } else { 270 context->info = "by address pair w/scope and options"; 271 } 272 } else { 273 context->info = "by address pair w/options"; 274 } 275 } 276 } 277 } 278 } else if (inet_pton(AF_INET6, ip_address, &sin6.sin6_addr) == 1) { 279 struct sockaddr_in6 r_sin6; 280 281 if (interface != NULL) { 282 sin6.sin6_scope_id = if_nametoindex(interface); 283 } 284 285 if (argc > 1) { 286 bzero(&r_sin6, sizeof(r_sin6)); 287 r_sin6.sin6_len = sizeof(r_sin6); 288 r_sin6.sin6_family = AF_INET6; 289 } 290 291 if ((argc == 1) 292 || (remote_address == NULL) 293 || (inet_pton(AF_INET6, remote_address, &r_sin6.sin6_addr) == 0)) { 294 if (argc > 2) { 295 options = _setupReachabilityOptions(argc - 2, argv + 2, NULL); 296 } 297 if (options == NULL) { 298 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6); 299 if (context != NULL) { 300 context->info = "by (v6) address"; 301 } 302 } else { 303 CFDataRef data; 304 305 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6)); 306 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); 307 CFRelease(data); 308 309 if (context != NULL) { 310 context->info = "by (v6) address w/options"; 311 } 312 } 313 } else { 314 if (remote_interface != NULL) { 315 r_sin6.sin6_scope_id = if_nametoindex(remote_interface); 316 317 if ((interface != NULL) && (strcmp(interface, remote_interface) != 0)) { 318 SCPrint(TRUE, stderr, 319 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"), 320 interface, 321 remote_interface); 322 exit(1); 323 } 324 } 325 326 options = _setupReachabilityOptions(argc - 2, argv + 2, NULL); 327 if (options == NULL) { 328 target = SCNetworkReachabilityCreateWithAddressPair(NULL, 329 (struct sockaddr *)&sin6, 330 (struct sockaddr *)&r_sin6); 331 if (context != NULL) { 332 context->info = "by (v6) address pair"; 333 } 334 } else { 335 CFDataRef data; 336 337 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6)); 338 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data); 339 CFRelease(data); 340 data = CFDataCreate(NULL, (const UInt8 *)&r_sin6, sizeof(r_sin6)); 341 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); 342 CFRelease(data); 343 344 if (context != NULL) { 345 context->info = "by (v6) address pair w/options"; 346 } 347 } 348 } 349 } else { 350 if (argc == 1) { 351 target = SCNetworkReachabilityCreateWithName(NULL, argv[0]); 352 if (context != NULL) { 353 context->info = "by name"; 354 } 355 } else { 356 options = _setupReachabilityOptions(argc - 1, argv + 1, NULL); 357 if (options == NULL) { 358 target = SCNetworkReachabilityCreateWithName(NULL, argv[0]); 359 if (context != NULL) { 360 context->info = "by name"; 361 } 362 } else { 363 CFStringRef str; 364 365 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); 366 CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str); 367 CFRelease(str); 368 369 if (context != NULL) { 370 context->info = "by name w/options"; 371 } 372 } 373 } 374 } 375 376 if (ip_addressN != NULL) { 377 free(ip_addressN); 378 } 379 380 if (remote_addressN != NULL) { 381 free(remote_addressN); 382 } 383 384 if ((target == NULL) && (options != NULL)) { 385 if (CFDictionaryContainsKey(options, kSCNetworkReachabilityOptionPTRAddress)) { 386 CFDataRef address; 387 388 address = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionRemoteAddress); 389 if (address == NULL) { 390 SCPrint(TRUE, stderr, CFSTR("No address\n")); 391 exit(1); 392 } 393 CFDictionarySetValue(options, kSCNetworkReachabilityOptionPTRAddress, address); 394 CFDictionaryRemoveValue(options, kSCNetworkReachabilityOptionRemoteAddress); 395 396 if (context != NULL) { 397 CFIndex n = CFDictionaryGetCount(options); 398 399 if (n == 1) { 400 context->info = "by PTR"; 401 } else if (CFDictionaryContainsKey(options, 402 kSCNetworkReachabilityOptionInterface)) { 403 if (n == 2) { 404 context->info = "by PTR w/scope"; 405 } else { 406 context->info = "by PTR w/scope and options"; 407 } 408 } else { 409 context->info = "by PTR w/options"; 410 } 411 } 412 } 413 414 target = SCNetworkReachabilityCreateWithOptions(NULL, options); 415 CFRelease(options); 416 } 417 418 return target; 419} 420 421 422static void 423_printReachability(SCNetworkReachabilityRef target) 424{ 425 SCNetworkReachabilityFlags flags; 426 Boolean ok; 427 428 ok = SCNetworkReachabilityGetFlags(target, &flags); 429 if (!ok) { 430 SCPrint(TRUE, stderr, CFSTR(" could not determine reachability, %s\n"), SCErrorString(SCError())); 431 return; 432 } 433 434 SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x ("), flags); 435 __SCNetworkReachabilityPrintFlags(flags); 436 SCPrint(_sc_debug, stdout, CFSTR(")")); 437 SCPrint(TRUE, stdout, CFSTR("\n")); 438 439 if (resolver_bypass) { 440 int if_index; 441 442 if_index = SCNetworkReachabilityGetInterfaceIndex(target); 443 SCPrint(_sc_debug, stdout, CFSTR("interface index = %d\n"), if_index); 444 } 445 446 return; 447} 448 449 450__private_extern__ 451void 452do_checkReachability(int argc, char **argv) 453{ 454 SCNetworkReachabilityRef target; 455 456 target = _setupReachability(argc, argv, NULL); 457 if (target == NULL) { 458 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError())); 459 exit(1); 460 } 461 462 _printReachability(target); 463 CFRelease(target); 464 exit(0); 465} 466 467 468static void 469_printNWIFlags(nwi_ifstate_flags flags) 470{ 471 if (flags == 0) { 472 return; 473 } 474 475 SCPrint(TRUE, stdout, CFSTR(" (")); 476 if (flags & NWI_IFSTATE_FLAGS_HAS_IPV4) { 477 SCPrint(TRUE, stdout, CFSTR("IPv4")); 478 flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV4; 479 SCPrint(flags != 0, stdout, CFSTR(",")); 480 } 481 if (flags & NWI_IFSTATE_FLAGS_HAS_IPV6) { 482 SCPrint(TRUE, stdout, CFSTR("IPv6")); 483 flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV6; 484 SCPrint(flags != 0, stdout, CFSTR(",")); 485 } 486 if (flags & NWI_IFSTATE_FLAGS_HAS_DNS) { 487 SCPrint(TRUE, stdout, CFSTR("DNS")); 488 flags &= ~NWI_IFSTATE_FLAGS_HAS_DNS; 489 SCPrint(flags != 0, stdout, CFSTR(",")); 490 } 491 if (flags != 0) { 492 SCPrint(TRUE, stdout, CFSTR("%p"), (void *)flags); 493 } 494 SCPrint(TRUE, stdout, CFSTR(")")); 495 496 return; 497} 498 499 500static void 501_printNWIInfo(nwi_ifstate_t ifstate) 502{ 503 nwi_ifstate_flags ifstate_flags = nwi_ifstate_get_flags(ifstate); 504 SCNetworkReachabilityFlags reach_flags = nwi_ifstate_get_reachability_flags(ifstate); 505 const uint8_t *signature; 506 int signature_length; 507 const struct sockaddr *vpn_addr = nwi_ifstate_get_vpn_server(ifstate); 508 509 SCPrint(TRUE, stdout, 510 CFSTR(" %7s : flags %p"), 511 nwi_ifstate_get_ifname(ifstate), 512 (void *)ifstate_flags); 513 _printNWIFlags(ifstate_flags); 514 515 SCPrint(TRUE, stdout, CFSTR("\n reach 0x%08x ("), reach_flags); 516 __SCNetworkReachabilityPrintFlags(reach_flags); 517 SCPrint(TRUE, stdout, CFSTR(")")); 518 519 if (vpn_addr != NULL) { 520 char vpn_ntopbuf[INET6_ADDRSTRLEN]; 521 522 _SC_sockaddr_to_string(vpn_addr, vpn_ntopbuf, sizeof(vpn_ntopbuf)); 523 SCPrint(TRUE, stdout, CFSTR("\n VPN server: %s"), vpn_ntopbuf); 524 } 525 526 signature = nwi_ifstate_get_signature(ifstate, AF_UNSPEC, &signature_length); 527 if (signature != NULL) { 528 CFDataRef digest = NULL; 529 530 digest = CFDataCreate(NULL, signature, CC_SHA1_DIGEST_LENGTH); 531 SCPrint(TRUE, stdout, CFSTR("\n Signature Hash: %@"), digest); 532 CFRelease(digest); 533 } else { 534 SCPrint(TRUE, stdout, CFSTR("\n Signature Hash: <empty>")); 535 } 536 537 SCPrint(TRUE, stdout, CFSTR("\n generation %llu\n"), 538 nwi_ifstate_get_generation(ifstate)); 539 540 return; 541} 542 543 544static void 545_printNWIReachInfo(nwi_state_t state, int af) 546{ 547 uint32_t reach_flags; 548 549 reach_flags = nwi_state_get_reachability_flags(state, af); 550 SCPrint(TRUE, stdout, CFSTR("\n REACH : flags 0x%08x ("), reach_flags); 551 __SCNetworkReachabilityPrintFlags(reach_flags); 552 SCPrint(TRUE, stdout, CFSTR(")\n")); 553 554 return; 555} 556 557 558static void 559do_printNWI(int argc, char **argv, nwi_state_t state) 560{ 561 nwi_ifstate_t ifstate; 562 563 if (state == NULL) { 564 SCPrint(TRUE, stdout, CFSTR("No network information\n")); 565 return; 566 } 567 568 if (argc > 0) { 569 ifstate = nwi_state_get_ifstate(state, argv[0]); 570 if (ifstate != NULL) { 571 _printNWIInfo(ifstate); 572 } else { 573 SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]); 574 } 575 return; 576 } 577 578 SCPrint(TRUE, stdout, CFSTR("Network information (generation %llu)"), 579 nwi_state_get_generation(state)); 580 581 SCPrint(TRUE, stdout, CFSTR("\nIPv4 network interface information\n")); 582 583 ifstate = nwi_state_get_first_ifstate(state, AF_INET); 584 if (ifstate == NULL) { 585 SCPrint(TRUE, stdout, CFSTR(" No IPv4 states found\n")); 586 } else { 587 while (ifstate != NULL) { 588 _printNWIInfo(ifstate); 589 ifstate = nwi_ifstate_get_next(ifstate, AF_INET); 590 } 591 } 592 _printNWIReachInfo(state, AF_INET); 593 594 SCPrint(TRUE, stdout, CFSTR("\nIPv6 network interface information\n")); 595 596 ifstate = nwi_state_get_first_ifstate(state, AF_INET6); 597 if (ifstate == NULL) { 598 SCPrint(TRUE, stdout, CFSTR(" No IPv6 states found\n")); 599 } else { 600 while (ifstate != NULL) { 601 _printNWIInfo(ifstate); 602 ifstate = nwi_ifstate_get_next(ifstate, AF_INET6); 603 } 604 } 605 _printNWIReachInfo(state, AF_INET6); 606 607 return; 608} 609 610 611__private_extern__ 612void 613do_showNWI(int argc, char **argv) 614{ 615 nwi_state_t state; 616 617 state = nwi_state_copy(); 618 do_printNWI(argc, argv, state); 619 if (state != NULL) { 620 nwi_state_release(state); 621 } else { 622 exit(1); 623 } 624 625 exit(0); 626} 627 628 629__private_extern__ 630void 631do_watchNWI(int argc, char **argv) 632{ 633 nwi_state_t state; 634 int status; 635 int token; 636 637 state = nwi_state_copy(); 638 do_printNWI(argc, argv, state); 639 if (state != NULL) { 640 nwi_state_release(state); 641 } 642 643 status = notify_register_dispatch(nwi_state_get_notify_key(), 644 &token, 645 dispatch_get_main_queue(), 646 ^(int token){ 647 nwi_state_t state; 648 struct tm tm_now; 649 struct timeval tv_now; 650 651 (void)gettimeofday(&tv_now, NULL); 652 (void)localtime_r(&tv_now.tv_sec, &tm_now); 653 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), 654 tm_now.tm_hour, 655 tm_now.tm_min, 656 tm_now.tm_sec, 657 tv_now.tv_usec / 1000); 658 659 state = nwi_state_copy(); 660 do_printNWI(argc, argv, state); 661 if (state != NULL) { 662 nwi_state_release(state); 663 } 664 }); 665 if (status != NOTIFY_STATUS_OK) { 666 SCLog(TRUE, LOG_INFO, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u"), status); 667 exit(1); 668 } 669 670 CFRunLoopRun(); 671 exit(0); 672} 673 674 675static void 676callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) 677{ 678 static int n = 3; 679 struct tm tm_now; 680 struct timeval tv_now; 681 682 (void)gettimeofday(&tv_now, NULL); 683 (void)localtime_r(&tv_now.tv_sec, &tm_now); 684 685 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), 686 tm_now.tm_hour, 687 tm_now.tm_min, 688 tm_now.tm_sec, 689 tv_now.tv_usec / 1000); 690 SCPrint(TRUE, stdout, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n++, flags, (char *)info); 691 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target); 692 _printReachability(target); 693 SCPrint(TRUE, stdout, CFSTR("\n")); 694 return; 695} 696 697 698__private_extern__ 699void 700do_watchReachability(int argc, char **argv) 701{ 702 SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; 703 SCNetworkReachabilityRef target; 704 SCNetworkReachabilityRef target_async; 705 706 target = _setupReachability(argc, argv, NULL); 707 if (target == NULL) { 708 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError())); 709 exit(1); 710 } 711 712 target_async = _setupReachability(argc, argv, &context); 713 if (target_async == NULL) { 714 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError())); 715 exit(1); 716 } 717 718 // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags() 719 // until after the "target" has been scheduled on a run loop. Otherwise, we'll 720 // end up making a synchronous DNS request and that's not what we want. 721 // 722 // To test the case were an application first calls SCNetworkReachabilityGetFlags() 723 // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable. 724 if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL) { 725 CFRelease(target_async); 726 target_async = CFRetain(target); 727 } 728 729 // Direct check of reachability 730 SCPrint(TRUE, stdout, CFSTR(" 0: direct\n")); 731 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target); 732 _printReachability(target); 733 CFRelease(target); 734 SCPrint(TRUE, stdout, CFSTR("\n")); 735 736 // schedule the target 737 SCPrint(TRUE, stdout, CFSTR(" 1: start\n")); 738 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async); 739// _printReachability(target_async); 740 SCPrint(TRUE, stdout, CFSTR("\n")); 741 742 if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) { 743 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError())); 744 exit(1); 745 } 746 747 if (doDispatch) { 748 if (!SCNetworkReachabilitySetDispatchQueue(target_async, dispatch_get_main_queue())) { 749 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError())); 750 exit(1); 751 } 752 } else { 753 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { 754 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError())); 755 exit(1); 756 } 757 } 758 759 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags() 760 // to get the current status. For "names", a DNS lookup has already been initiated. 761 SCPrint(TRUE, stdout, CFSTR(" 2: on %s\n"), doDispatch ? "dispatch queue" : "runloop"); 762 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async); 763 _printReachability(target_async); 764 SCPrint(TRUE, stdout, CFSTR("\n")); 765 766 CFRunLoopRun(); 767 exit(0); 768} 769 770 771static void 772do_printDNSConfiguration(int argc, char **argv, dns_config_t *dns_config) 773{ 774 SCNetworkReachabilityRef target; 775 776 if (dns_config == NULL) { 777 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n")); 778 return; 779 } 780 781 if (argc > 1) { 782 int dns_config_index = -1; 783 SCNetworkReachabilityFlags flags = 0; 784 Boolean haveDNS = FALSE; 785 Boolean ok = FALSE; 786 dns_resolver_t *resolver; 787 uint32_t resolver_if_index; 788 SCNetworkReachabilityPrivateRef targetPrivate; 789 790 target = _setupReachability(argc, argv, NULL); 791 792 targetPrivate = (SCNetworkReachabilityPrivateRef)target; 793 794 if (targetPrivate->type != reachabilityTypeName) { 795 SCPrint(TRUE, stdout, CFSTR("\"%s\" is not a hostname.\n"), argv[0]); 796 exit(1); 797 } 798 799 ok = __SC_checkResolverReachabilityInternal(&store, &flags, 800 &haveDNS, targetPrivate->name, 801 &resolver_if_index, &dns_config_index); 802 803 if (!ok) { 804 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available.\n" )); 805 return; 806 } 807 808 SCPrint(TRUE, stdout, CFSTR("DNS configuration for %s\n"), 809 targetPrivate->name); 810 811 if (targetPrivate->if_index == 0) { 812 resolver = dns_config->resolver[dns_config_index]; 813 } else { 814 resolver = dns_config->scoped_resolver[dns_config_index]; 815 } 816 817 _dns_resolver_print(resolver, dns_config_index + 1); 818 819 if (target != NULL) CFRelease(target); 820 } else { 821 _dns_configuration_print(dns_config); 822 } 823 824 if (_sc_debug) { 825 SCPrint(TRUE, stdout, CFSTR("\ngeneration = %llu\n"), dns_config->generation); 826 } 827 828 return; 829} 830 831 832__private_extern__ 833void 834do_showDNSConfiguration(int argc, char **argv) 835{ 836 dns_config_t *dns_config; 837 838 dns_config = dns_configuration_copy(); 839 do_printDNSConfiguration(argc, argv, dns_config); 840 if (dns_config != NULL) { 841 dns_configuration_free(dns_config); 842 } else { 843 exit(1); 844 } 845 846 exit(0); 847} 848 849 850__private_extern__ 851void 852do_watchDNSConfiguration(int argc, char **argv) 853{ 854 dns_config_t *dns_config; 855 int status; 856 int token; 857 858 dns_config = dns_configuration_copy(); 859 do_printDNSConfiguration(argc, argv, dns_config); 860 if (dns_config != NULL) { 861 dns_configuration_free(dns_config); 862 } 863 864 status = notify_register_dispatch(dns_configuration_notify_key(), 865 &token, 866 dispatch_get_main_queue(), 867 ^(int token){ 868 dns_config_t *dns_config; 869 struct tm tm_now; 870 struct timeval tv_now; 871 872 (void)gettimeofday(&tv_now, NULL); 873 (void)localtime_r(&tv_now.tv_sec, &tm_now); 874 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), 875 tm_now.tm_hour, 876 tm_now.tm_min, 877 tm_now.tm_sec, 878 tv_now.tv_usec / 1000); 879 880 dns_config = dns_configuration_copy(); 881 do_printDNSConfiguration(argc, argv, dns_config); 882 if (dns_config != NULL) { 883 dns_configuration_free(dns_config); 884 } 885 }); 886 if (status != NOTIFY_STATUS_OK) { 887 SCLog(TRUE, LOG_INFO, CFSTR("notify_register_dispatch() failed for DNS configuration changes, status=%u"), status); 888 exit(1); 889 } 890 891 CFRunLoopRun(); 892 exit(0); 893} 894 895 896static void 897showProxy(CFDictionaryRef proxy) 898{ 899 CFMutableDictionaryRef cleaned = NULL; 900 901 if (!_sc_debug) { 902 cleaned = CFDictionaryCreateMutableCopy(NULL, 0, proxy); 903 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesScoped); 904 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesServices); 905 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesSupplemental); 906 proxy = cleaned; 907 } 908 909 SCPrint(TRUE, stdout, CFSTR("%@\n"), proxy); 910 if (cleaned != NULL) CFRelease(cleaned); 911 return; 912} 913 914 915__private_extern__ 916void 917do_showProxyConfiguration(int argc, char **argv) 918{ 919 CFMutableDictionaryRef options = NULL; 920 CFDictionaryRef proxies; 921 922 if (getenv("BYPASS_GLOBAL_PROXY") != NULL) { 923 options = CFDictionaryCreateMutable(NULL, 0, 924 &kCFTypeDictionaryKeyCallBacks, 925 &kCFTypeDictionaryValueCallBacks); 926 CFDictionaryAddValue(options, kSCProxiesNoGlobal, kCFBooleanTrue); 927 } 928 929 proxies = SCDynamicStoreCopyProxiesWithOptions(NULL, options); 930 931 if (options != NULL) { 932 CFRelease(options); 933 } 934 935 if (proxies != NULL) { 936 CFStringRef interface = NULL; 937 CFStringRef server = NULL; 938 939 while (argc > 0) { 940 if (strcasecmp(argv[0], "interface") == 0) { 941 argv++; 942 argc--; 943 944 if (argc < 1) { 945 SCPrint(TRUE, stderr, CFSTR("No interface\n")); 946 exit(1); 947 } 948 949 if (if_nametoindex(argv[0]) == 0) { 950 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[0]); 951 exit(1); 952 } 953 954 interface = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); 955 argv++; 956 argc--; 957 } else { 958 if (server != NULL) { 959 CFRelease(server); 960 } 961 962 server = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); 963 argv++; 964 argc--; 965 } 966 } 967 968 if ((server != NULL) || (interface != NULL)) { 969 CFArrayRef matching; 970 971 matching = SCNetworkProxiesCopyMatching(proxies, server, interface); 972 if (matching != NULL) { 973 CFIndex i; 974 CFIndex n; 975 976 if (server != NULL) { 977 if (interface != NULL) { 978 SCPrint(TRUE, stdout, 979 CFSTR("server = %@, interface = %@\n"), 980 server, 981 interface); 982 } else { 983 SCPrint(TRUE, stdout, 984 CFSTR("server = %@\n"), 985 server); 986 } 987 } else { 988 SCPrint(TRUE, stdout, 989 CFSTR("interface = %@\n"), 990 interface); 991 } 992 993 n = CFArrayGetCount(matching); 994 for (i = 0; i < n; i++) { 995 CFDictionaryRef proxy; 996 997 proxy = CFArrayGetValueAtIndex(matching, i); 998 SCPrint(TRUE, stdout, CFSTR("\nproxy #%ld\n"), i + 1); 999 showProxy(proxy); 1000 } 1001 1002 CFRelease(matching); 1003 } else { 1004 SCPrint(TRUE, stdout, CFSTR("No matching proxy configurations\n")); 1005 } 1006 } else { 1007 showProxy(proxies); 1008 } 1009 1010 if (interface != NULL) CFRelease(interface); 1011 if (server != NULL) CFRelease(server); 1012 CFRelease(proxies); 1013 } else { 1014 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n")); 1015 } 1016 1017 exit(0); 1018} 1019 1020 1021__private_extern__ 1022void 1023do_snapshot(int argc, char **argv) 1024{ 1025 if (!SCDynamicStoreSnapshot(store)) { 1026 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); 1027 } 1028 1029 (void) _SCNetworkReachabilityServer_snapshot(); 1030 1031 return; 1032} 1033 1034 1035__private_extern__ 1036void 1037do_renew(char *if_name) 1038{ 1039 CFArrayRef services; 1040 Boolean ok = FALSE; 1041 1042 if ((if_name == NULL) || (strlen(if_name) == 0)) { 1043 SCPrint(TRUE, stderr, CFSTR("No interface name\n")); 1044 exit(1); 1045 } 1046 1047 if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL) { 1048 CFArrayRef interfaces; 1049 1050 interfaces = SCNetworkInterfaceCopyAll(); 1051 if (interfaces != NULL) { 1052 CFIndex i; 1053 CFStringRef match_name; 1054 CFIndex n; 1055 1056 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII); 1057 assert(match_name != NULL); 1058 1059 n = CFArrayGetCount(interfaces); 1060 for (i = 0; i < n; i++) { 1061 CFStringRef bsd_name; 1062 SCNetworkInterfaceRef interface; 1063 1064 interface = CFArrayGetValueAtIndex(interfaces, i); 1065 bsd_name = SCNetworkInterfaceGetBSDName(interface); 1066 if (_SC_CFEqual(bsd_name, match_name)) { 1067 // if match 1068 ok = SCNetworkInterfaceForceConfigurationRefresh(interface); 1069 if (!ok) { 1070 int status; 1071 1072 status = SCError(); 1073 if (status != kSCStatusAccessError) { 1074 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(status)); 1075 exit(1); 1076 } 1077 1078 // ... and if can't write the SCDynamicStore, try w/prefs 1079 } 1080 1081 break; 1082 } 1083 } 1084 1085 CFRelease(match_name); 1086 CFRelease(interfaces); 1087 } 1088 1089 if (ok) { 1090 exit(0); 1091 } 1092 } 1093 1094 do_prefs_init(); /* initialization */ 1095 do_prefs_open(0, NULL); /* open default prefs */ 1096 1097 services = SCNetworkServiceCopyAll(prefs); 1098 if (services != NULL) { 1099 CFIndex i; 1100 CFStringRef match_name; 1101 CFIndex n; 1102 1103 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII); 1104 assert(match_name != NULL); 1105 1106 n = CFArrayGetCount(services); 1107 for (i = 0; i < n; i++) { 1108 CFStringRef bsd_name; 1109 SCNetworkInterfaceRef interface; 1110 SCNetworkServiceRef service; 1111 1112 service = CFArrayGetValueAtIndex(services, i); 1113 interface = SCNetworkServiceGetInterface(service); 1114 if (interface == NULL) { 1115 // if no interface 1116 continue; 1117 } 1118 1119 bsd_name = SCNetworkInterfaceGetBSDName(interface); 1120 if (_SC_CFEqual(bsd_name, match_name)) { 1121 // if match 1122 ok = SCNetworkInterfaceForceConfigurationRefresh(interface); 1123 if (!ok) { 1124 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(SCError())); 1125 exit(1); 1126 } 1127 1128 break; 1129 } 1130 } 1131 1132 CFRelease(match_name); 1133 CFRelease(services); 1134 } 1135 1136 if (!ok) { 1137 SCPrint(TRUE, stderr, CFSTR("No interface\n")); 1138 exit(1); 1139 } 1140 1141 _prefs_close(); 1142 exit(0); 1143} 1144 1145 1146static void 1147waitKeyFound() 1148{ 1149 exit(0); 1150} 1151 1152 1153static void 1154waitTimeout(int sigraised) 1155{ 1156 exit(1); 1157} 1158 1159 1160__private_extern__ 1161void 1162do_wait(char *waitKey, int timeout) 1163{ 1164 struct itimerval itv; 1165 CFStringRef key; 1166 CFMutableArrayRef keys; 1167 Boolean ok; 1168 1169 store = SCDynamicStoreCreate(NULL, CFSTR("scutil (wait)"), waitKeyFound, NULL); 1170 if (store == NULL) { 1171 SCPrint(TRUE, stderr, 1172 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError())); 1173 exit(1); 1174 } 1175 1176 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8); 1177 1178 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1179 CFArrayAppendValue(keys, key); 1180 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL); 1181 CFRelease(keys); 1182 if (!ok) { 1183 SCPrint(TRUE, stderr, 1184 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError())); 1185 exit(1); 1186 } 1187 1188 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); 1189 if (!notifyRls) { 1190 SCPrint(TRUE, stderr, 1191 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError())); 1192 exit(1); 1193 } 1194 1195 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode); 1196 1197 value = SCDynamicStoreCopyValue(store, key); 1198 if (value) { 1199 /* if the key is already present */ 1200 exit(0); 1201 } 1202 CFRelease(key); 1203 1204 if (timeout > 0) { 1205 signal(SIGALRM, waitTimeout); 1206 bzero(&itv, sizeof(itv)); 1207 itv.it_value.tv_sec = timeout; 1208 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { 1209 SCPrint(TRUE, stderr, 1210 CFSTR("setitimer() failed: %s\n"), strerror(errno)); 1211 exit(1); 1212 } 1213 } 1214 1215 CFRunLoopRun(); 1216} 1217 1218#ifdef TEST_DNS_CONFIGURATION 1219 1220Boolean doDispatch = FALSE; 1221CFRunLoopSourceRef notifyRls = NULL; 1222SCDynamicStoreRef store = NULL; 1223CFPropertyListRef value = NULL; 1224 1225int 1226main(int argc, char **argv) 1227{ 1228 dns_config_t *dns_config; 1229 1230fprintf(stdout, "copy configuration\n"); 1231 dns_config = dns_configuration_copy(); 1232 if (dns_config != NULL) { 1233 1234fprintf(stdout, "sleeping for 120 seconds\n"); 1235sleep(120); 1236 1237fprintf(stdout, "sending ack\n"); 1238 _dns_configuration_ack(dns_config, "TEST_DNS_CONFIGURATION"); 1239 1240fprintf(stdout, "sleeping for 120 seconds\n"); 1241sleep(120); 1242 1243 dns_configuration_free(dns_config); 1244 } 1245 1246 do_showDNSConfiguration(argc, argv); 1247 exit(0); 1248} 1249 1250#endif // TEST_DNS_CONFIGURATION 1251