2 * Copyright (c) 2000, 2001, 2003-2015 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 * Modification History
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
32 * June 1, 2001 Allan Nathanson <ajn@apple.com>
33 * - public API conversion
35 * November 9, 2000 Allan Nathanson <ajn@apple.com>
44 #include <netdb_async.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
51 #define my_log(__level, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
54 #include "dnsinfo_internal.h"
55 #include <network_information.h>
56 #include "network_information_priv.h"
57 #include "SCNetworkReachabilityInternal.h"
58 #include <CommonCrypto/CommonDigest.h>
61 static Boolean resolver_bypass
;
64 static CF_RETURNS_RETAINED CFMutableDictionaryRef
65 _setupReachabilityOptions(int argc
, char **argv
, const char *interface
)
68 CFMutableDictionaryRef options
;
70 options
= CFDictionaryCreateMutable(NULL
,
72 &kCFTypeDictionaryKeyCallBacks
,
73 &kCFTypeDictionaryValueCallBacks
);
75 for (i
= 0; i
< argc
; i
++) {
76 if (strcasecmp(argv
[i
], "interface") == 0) {
78 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
88 if (strcasecmp(argv
[i
], "server") == 0) {
89 CFDictionarySetValue(options
,
90 kSCNetworkReachabilityOptionServerBypass
,
93 } else if (strcasecmp(argv
[i
], "no-server") == 0) {
94 CFDictionarySetValue(options
,
95 kSCNetworkReachabilityOptionServerBypass
,
100 if (strcasecmp(argv
[i
], "no-connection-on-demand") == 0) {
101 CFDictionarySetValue(options
,
102 kSCNetworkReachabilityOptionConnectionOnDemandBypass
,
107 if (strcasecmp(argv
[i
], "no-resolve") == 0) {
108 CFDictionarySetValue(options
,
109 kSCNetworkReachabilityOptionResolverBypass
,
111 resolver_bypass
= TRUE
;
115 if (strcasecmp(argv
[i
], "ptr") == 0) {
116 CFDictionarySetValue(options
,
117 kSCNetworkReachabilityOptionPTRAddress
,
122 if (strlen(argv
[i
]) == 0) {
126 SCPrint(TRUE
, stderr
, CFSTR("Unrecognized option: %s\n"), argv
[i
]);
131 if (interface
!= NULL
) {
134 if (if_nametoindex(interface
) == 0) {
135 SCPrint(TRUE
, stderr
, CFSTR("No interface: %s\n"), interface
);
139 str
= CFStringCreateWithCString(NULL
, interface
, kCFStringEncodingASCII
);
140 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionInterface
, str
);
144 if (CFDictionaryGetCount(options
) == 0) {
153 static SCNetworkReachabilityRef
154 _setupReachability(int argc
, char **argv
, SCNetworkReachabilityContext
*context
)
156 const char *ip_address
= argv
[0];
157 char *ip_addressN
= NULL
;
158 const char *interface
;
159 CFMutableDictionaryRef options
= NULL
;
160 const char *remote_address
= NULL
;
161 char *remote_addressN
= NULL
;
162 const char *remote_interface
;
163 struct sockaddr_in sin
;
164 struct sockaddr_in6 sin6
;
165 SCNetworkReachabilityRef target
= NULL
;
167 bzero(&sin
, sizeof(sin
));
168 sin
.sin_len
= sizeof(sin
);
169 sin
.sin_family
= AF_INET
;
171 bzero(&sin6
, sizeof(sin6
));
172 sin6
.sin6_len
= sizeof(sin6
);
173 sin6
.sin6_family
= AF_INET6
;
175 interface
= strchr(ip_address
, '%');
176 if (interface
!= NULL
) {
177 ip_addressN
= strdup(ip_address
);
178 ip_addressN
[interface
- ip_address
] = '\0';
179 ip_address
= ip_addressN
;
183 if ((argc
> 1) && (strlen(argv
[1]) > 0)) {
184 remote_address
= argv
[1];
186 remote_interface
= strchr(remote_address
, '%');
187 if (remote_interface
!= NULL
) {
188 remote_addressN
= strdup(remote_address
);
189 remote_addressN
[remote_interface
- remote_address
] = '\0';
190 remote_address
= remote_addressN
;
195 if (inet_aton(ip_address
, &sin
.sin_addr
) == 1) {
196 struct sockaddr_in r_sin
;
199 bzero(&r_sin
, sizeof(r_sin
));
200 r_sin
.sin_len
= sizeof(r_sin
);
201 r_sin
.sin_family
= AF_INET
;
205 || (remote_address
== NULL
)
206 || (inet_aton(remote_address
, &r_sin
.sin_addr
) == 0)) {
208 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, interface
);
210 if (options
== NULL
) {
211 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin
);
212 if (context
!= NULL
) {
213 context
->info
= "by address";
218 data
= CFDataCreate(NULL
, (const UInt8
*)&sin
, sizeof(sin
));
219 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
222 if (context
!= NULL
) {
223 if (CFDictionaryContainsKey(options
,
224 kSCNetworkReachabilityOptionInterface
)) {
225 if (CFDictionaryGetCount(options
) == 2) {
226 context
->info
= "by address w/scope";
228 context
->info
= "by address w/scope and options";
231 context
->info
= "by address w/options";
236 if (remote_interface
!= NULL
) {
237 if ((interface
!= NULL
) && (strcmp(interface
, remote_interface
) != 0)) {
238 SCPrint(TRUE
, stderr
,
239 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
245 interface
= remote_interface
;
248 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, interface
);
249 if (options
== NULL
) {
250 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
251 (struct sockaddr
*)&sin
,
252 (struct sockaddr
*)&r_sin
);
253 if (context
!= NULL
) {
254 context
->info
= "by address pair";
259 data
= CFDataCreate(NULL
, (const UInt8
*)&sin
, sizeof(sin
));
260 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionLocalAddress
, data
);
262 data
= CFDataCreate(NULL
, (const UInt8
*)&r_sin
, sizeof(r_sin
));
263 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
266 if (context
!= NULL
) {
267 if (CFDictionaryContainsKey(options
,
268 kSCNetworkReachabilityOptionInterface
)) {
269 if (CFDictionaryGetCount(options
) == 3) {
270 context
->info
= "by address pair w/scope";
272 context
->info
= "by address pair w/scope and options";
275 context
->info
= "by address pair w/options";
280 } else if (inet_pton(AF_INET6
, ip_address
, &sin6
.sin6_addr
) == 1) {
281 struct sockaddr_in6 r_sin6
;
283 if (interface
!= NULL
) {
284 sin6
.sin6_scope_id
= if_nametoindex(interface
);
288 bzero(&r_sin6
, sizeof(r_sin6
));
289 r_sin6
.sin6_len
= sizeof(r_sin6
);
290 r_sin6
.sin6_family
= AF_INET6
;
294 || (remote_address
== NULL
)
295 || (inet_pton(AF_INET6
, remote_address
, &r_sin6
.sin6_addr
) == 0)) {
297 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, NULL
);
299 if (options
== NULL
) {
300 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin6
);
301 if (context
!= NULL
) {
302 context
->info
= "by (v6) address";
307 data
= CFDataCreate(NULL
, (const UInt8
*)&sin6
, sizeof(sin6
));
308 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
311 if (context
!= NULL
) {
312 context
->info
= "by (v6) address w/options";
316 if (remote_interface
!= NULL
) {
317 r_sin6
.sin6_scope_id
= if_nametoindex(remote_interface
);
319 if ((interface
!= NULL
) && (strcmp(interface
, remote_interface
) != 0)) {
320 SCPrint(TRUE
, stderr
,
321 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
328 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, NULL
);
329 if (options
== NULL
) {
330 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
331 (struct sockaddr
*)&sin6
,
332 (struct sockaddr
*)&r_sin6
);
333 if (context
!= NULL
) {
334 context
->info
= "by (v6) address pair";
339 data
= CFDataCreate(NULL
, (const UInt8
*)&sin6
, sizeof(sin6
));
340 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionLocalAddress
, data
);
342 data
= CFDataCreate(NULL
, (const UInt8
*)&r_sin6
, sizeof(r_sin6
));
343 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
346 if (context
!= NULL
) {
347 context
->info
= "by (v6) address pair w/options";
353 target
= SCNetworkReachabilityCreateWithName(NULL
, argv
[0]);
354 if (context
!= NULL
) {
355 context
->info
= "by name";
358 options
= _setupReachabilityOptions(argc
- 1, argv
+ 1, NULL
);
359 if (options
== NULL
) {
360 target
= SCNetworkReachabilityCreateWithName(NULL
, argv
[0]);
361 if (context
!= NULL
) {
362 context
->info
= "by name";
367 str
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
368 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionNodeName
, str
);
371 if (context
!= NULL
) {
372 context
->info
= "by name w/options";
378 if (ip_addressN
!= NULL
) {
382 if (remote_addressN
!= NULL
) {
383 free(remote_addressN
);
386 if ((target
== NULL
) && (options
!= NULL
)) {
387 if (CFDictionaryContainsKey(options
, kSCNetworkReachabilityOptionPTRAddress
)) {
390 address
= CFDictionaryGetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
);
391 if (address
== NULL
) {
392 SCPrint(TRUE
, stderr
, CFSTR("No address\n"));
395 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionPTRAddress
, address
);
396 CFDictionaryRemoveValue(options
, kSCNetworkReachabilityOptionRemoteAddress
);
398 if (context
!= NULL
) {
399 CFIndex n
= CFDictionaryGetCount(options
);
402 context
->info
= "by PTR";
403 } else if (CFDictionaryContainsKey(options
,
404 kSCNetworkReachabilityOptionInterface
)) {
406 context
->info
= "by PTR w/scope";
408 context
->info
= "by PTR w/scope and options";
411 context
->info
= "by PTR w/options";
416 target
= SCNetworkReachabilityCreateWithOptions(NULL
, options
);
425 _printReachability(SCNetworkReachabilityRef target
)
427 SCNetworkReachabilityFlags flags
;
431 ok
= SCNetworkReachabilityGetFlags(target
, &flags
);
433 SCPrint(TRUE
, stderr
, CFSTR(" could not determine reachability, %s\n"), SCErrorString(SCError()));
437 str
= __SCNetworkReachabilityCopyFlags(flags
, CFSTR("flags = "), _sc_debug
);
438 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), str
);
441 if (resolver_bypass
&& _sc_debug
) {
444 if_index
= SCNetworkReachabilityGetInterfaceIndex(target
);
445 SCPrint(TRUE
, stdout
, CFSTR("interface index = %d\n"), if_index
);
454 do_checkReachability(int argc
, char **argv
)
456 SCNetworkReachabilityRef target
;
458 target
= _setupReachability(argc
, argv
, NULL
);
459 if (target
== NULL
) {
460 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
464 _printReachability(target
);
471 _printNWIFlags(nwi_ifstate_flags flags
)
473 flags
&= NWI_IFSTATE_FLAGS_MASK
;
478 SCPrint(TRUE
, stdout
, CFSTR(" ("));
479 if (flags
& NWI_IFSTATE_FLAGS_HAS_IPV4
) {
480 SCPrint(TRUE
, stdout
, CFSTR("IPv4"));
481 flags
&= ~NWI_IFSTATE_FLAGS_HAS_IPV4
;
482 SCPrint(flags
!= 0, stdout
, CFSTR(","));
484 if (flags
& NWI_IFSTATE_FLAGS_HAS_IPV6
) {
485 SCPrint(TRUE
, stdout
, CFSTR("IPv6"));
486 flags
&= ~NWI_IFSTATE_FLAGS_HAS_IPV6
;
487 SCPrint(flags
!= 0, stdout
, CFSTR(","));
489 if (flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) {
490 SCPrint(TRUE
, stdout
, CFSTR("DNS"));
491 flags
&= ~NWI_IFSTATE_FLAGS_HAS_DNS
;
492 SCPrint(flags
!= 0, stdout
, CFSTR(","));
494 if (flags
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) {
495 SCPrint(TRUE
, stdout
, CFSTR("NOT-IN-LIST"));
496 flags
&= ~NWI_IFSTATE_FLAGS_NOT_IN_LIST
;
497 SCPrint(flags
!= 0, stdout
, CFSTR(","));
499 if (flags
& NWI_IFSTATE_FLAGS_HAS_SIGNATURE
) {
500 SCPrint(TRUE
, stdout
, CFSTR("SIGNATURE"));
501 flags
&= ~NWI_IFSTATE_FLAGS_HAS_SIGNATURE
;
502 SCPrint(flags
!= 0, stdout
, CFSTR(","));
504 if (flags
& NWI_IFSTATE_FLAGS_NOT_IN_IFLIST
) {
505 SCPrint(TRUE
, stdout
, CFSTR("NOT-IN-IFLIST"));
506 flags
&= ~NWI_IFSTATE_FLAGS_NOT_IN_IFLIST
;
507 SCPrint(flags
!= 0, stdout
, CFSTR(","));
510 SCPrint(TRUE
, stdout
, CFSTR("%p"), (void *)flags
);
512 SCPrint(TRUE
, stdout
, CFSTR(")"));
519 _printNWIInfo(nwi_ifstate_t ifstate
)
521 nwi_ifstate_flags ifstate_flags
;
522 SCNetworkReachabilityFlags reach_flags
= nwi_ifstate_get_reachability_flags(ifstate
);
523 const uint8_t *signature
;
524 int signature_length
;
526 const struct sockaddr
*vpn_addr
= nwi_ifstate_get_vpn_server(ifstate
);
528 ifstate_flags
= nwi_ifstate_get_flags(ifstate
);
530 ifstate_flags
|= ifstate
->flags
;
533 SCPrint(TRUE
, stdout
,
534 CFSTR(" %7s : flags %p"),
535 nwi_ifstate_get_ifname(ifstate
),
536 (void *)ifstate_flags
);
537 _printNWIFlags(ifstate_flags
);
539 str
= __SCNetworkReachabilityCopyFlags(reach_flags
, CFSTR(" reach "), TRUE
);
540 SCPrint(TRUE
, stdout
, CFSTR("\n%@"), str
);
543 if (vpn_addr
!= NULL
) {
544 char vpn_ntopbuf
[INET6_ADDRSTRLEN
];
546 _SC_sockaddr_to_string(vpn_addr
, vpn_ntopbuf
, sizeof(vpn_ntopbuf
));
547 SCPrint(TRUE
, stdout
, CFSTR("\n VPN server: %s"), vpn_ntopbuf
);
550 signature
= nwi_ifstate_get_signature(ifstate
, AF_UNSPEC
, &signature_length
);
551 if (signature
!= NULL
) {
552 CFDataRef digest
= NULL
;
554 digest
= CFDataCreate(NULL
, signature
, CC_SHA1_DIGEST_LENGTH
);
555 SCPrint(TRUE
, stdout
, CFSTR("\n Signature Hash: %@"), digest
);
558 SCPrint(TRUE
, stdout
, CFSTR("\n Signature Hash: <empty>"));
561 SCPrint(TRUE
, stdout
, CFSTR("\n generation %llu\n"),
562 nwi_ifstate_get_generation(ifstate
));
569 _printNWIReachInfo(nwi_state_t state
, int af
)
571 uint32_t reach_flags
;
574 reach_flags
= nwi_state_get_reachability_flags(state
, af
);
576 str
= __SCNetworkReachabilityCopyFlags(reach_flags
, CFSTR(" REACH : flags "), TRUE
);
577 SCPrint(TRUE
, stdout
, CFSTR("\n%@\n"), str
);
585 do_printNWI(int argc
, char **argv
, nwi_state_t state
)
588 nwi_ifstate_t ifstate
;
591 SCPrint(TRUE
, stdout
, CFSTR("No network information\n"));
596 ifstate
= nwi_state_get_ifstate(state
, argv
[0]);
597 if (ifstate
!= NULL
) {
600 _printNWIInfo(ifstate
);
602 alias
= nwi_ifstate_get_alias(ifstate
,
603 ifstate
->af
== AF_INET
? AF_INET6
: AF_INET
);
605 SCPrint(TRUE
, stdout
, CFSTR("\n"));
606 _printNWIInfo(alias
);
609 SCPrint(TRUE
, stdout
, CFSTR("No network information (for %s)\n"), argv
[0]);
614 SCPrint(TRUE
, stdout
, CFSTR("Network information (generation %llu)"),
615 nwi_state_get_generation(state
));
617 SCPrint(TRUE
, stdout
, CFSTR("\nIPv4 network interface information\n"));
619 ifstate
= nwi_state_get_first_ifstate(state
, AF_INET
);
620 if (ifstate
== NULL
) {
621 SCPrint(TRUE
, stdout
, CFSTR(" No IPv4 states found\n"));
623 while (ifstate
!= NULL
) {
624 _printNWIInfo(ifstate
);
625 ifstate
= nwi_ifstate_get_next(ifstate
, AF_INET
);
628 _printNWIReachInfo(state
, AF_INET
);
630 SCPrint(TRUE
, stdout
, CFSTR("\nIPv6 network interface information\n"));
632 ifstate
= nwi_state_get_first_ifstate(state
, AF_INET6
);
633 if (ifstate
== NULL
) {
634 SCPrint(TRUE
, stdout
, CFSTR(" No IPv6 states found\n"));
636 while (ifstate
!= NULL
) {
637 _printNWIInfo(ifstate
);
638 ifstate
= nwi_ifstate_get_next(ifstate
, AF_INET6
);
641 _printNWIReachInfo(state
, AF_INET6
);
643 count
= nwi_state_get_interface_names(state
, NULL
, 0);
645 const char * names
[count
];
647 count
= nwi_state_get_interface_names(state
, names
, count
);
651 printf("\nNetwork interfaces:");
652 for (i
= 0; i
< count
; i
++) {
653 printf(" %s", names
[i
]);
664 do_showNWI(int argc
, char **argv
)
668 state
= nwi_state_copy();
669 do_printNWI(argc
, argv
, state
);
671 nwi_state_release(state
);
682 do_watchNWI(int argc
, char **argv
)
688 state
= nwi_state_copy();
689 do_printNWI(argc
, argv
, state
);
691 nwi_state_release(state
);
694 status
= notify_register_dispatch(nwi_state_get_notify_key(),
696 dispatch_get_main_queue(),
700 struct timeval tv_now
;
702 (void)gettimeofday(&tv_now
, NULL
);
703 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
704 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
708 tv_now
.tv_usec
/ 1000);
710 state
= nwi_state_copy();
711 do_printNWI(argc
, argv
, state
);
713 nwi_state_release(state
);
716 if (status
!= NOTIFY_STATUS_OK
) {
717 SC_log(LOG_INFO
, "notify_register_dispatch() failed for nwi changes, status=%u", status
);
727 callout(SCNetworkReachabilityRef target
, SCNetworkReachabilityFlags flags
, void *info
)
731 struct timeval tv_now
;
733 (void)gettimeofday(&tv_now
, NULL
);
734 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
736 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
740 tv_now
.tv_usec
/ 1000);
741 SCPrint(TRUE
, stdout
, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n
++, flags
, (char *)info
);
742 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
743 _printReachability(target
);
744 SCPrint(TRUE
, stdout
, CFSTR("\n"));
751 do_watchReachability(int argc
, char **argv
)
753 SCNetworkReachabilityContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
754 SCNetworkReachabilityRef target
;
755 SCNetworkReachabilityRef target_async
;
757 target
= _setupReachability(argc
, argv
, NULL
);
758 if (target
== NULL
) {
759 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
763 target_async
= _setupReachability(argc
, argv
, &context
);
764 if (target_async
== NULL
) {
765 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
769 // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags()
770 // until after the "target" has been scheduled on a run loop. Otherwise, we'll
771 // end up making a synchronous DNS request and that's not what we want.
773 // To test the case were an application first calls SCNetworkReachabilityGetFlags()
774 // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable.
775 if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL
) {
776 CFRelease(target_async
);
777 target_async
= CFRetain(target
);
780 // Direct check of reachability
781 SCPrint(TRUE
, stdout
, CFSTR(" 0: direct\n"));
782 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
783 _printReachability(target
);
785 SCPrint(TRUE
, stdout
, CFSTR("\n"));
787 // schedule the target
788 SCPrint(TRUE
, stdout
, CFSTR(" 1: start\n"));
789 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
790 // _printReachability(target_async);
791 SCPrint(TRUE
, stdout
, CFSTR("\n"));
793 if (!SCNetworkReachabilitySetCallback(target_async
, callout
, &context
)) {
794 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
799 if (!SCNetworkReachabilitySetDispatchQueue(target_async
, dispatch_get_main_queue())) {
800 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
804 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
805 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
810 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags()
811 // to get the current status. For "names", a DNS lookup has already been initiated.
812 SCPrint(TRUE
, stdout
, CFSTR(" 2: on %s\n"), doDispatch
? "dispatch queue" : "runloop");
813 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
814 _printReachability(target_async
);
815 SCPrint(TRUE
, stdout
, CFSTR("\n"));
823 do_printDNSConfiguration(int argc
, char **argv
, dns_config_t
*dns_config
)
827 if (dns_config
== NULL
) {
828 SCPrint(TRUE
, stdout
, CFSTR("No DNS configuration available\n"));
832 _sc_log_save
= _sc_log
;
834 _dns_configuration_log(dns_config
, _sc_debug
);
835 _sc_log
= _sc_log_save
;
838 SCPrint(TRUE
, stdout
, CFSTR("\ngeneration = %llu\n"), dns_config
->generation
);
847 do_showDNSConfiguration(int argc
, char **argv
)
849 dns_config_t
*dns_config
;
851 dns_config
= dns_configuration_copy();
852 do_printDNSConfiguration(argc
, argv
, dns_config
);
853 if (dns_config
!= NULL
) {
854 dns_configuration_free(dns_config
);
865 do_watchDNSConfiguration(int argc
, char **argv
)
867 dns_config_t
*dns_config
;
871 dns_config
= dns_configuration_copy();
872 do_printDNSConfiguration(argc
, argv
, dns_config
);
873 if (dns_config
!= NULL
) {
874 dns_configuration_free(dns_config
);
877 status
= notify_register_dispatch(dns_configuration_notify_key(),
879 dispatch_get_main_queue(),
881 dns_config_t
*dns_config
;
883 struct timeval tv_now
;
885 (void)gettimeofday(&tv_now
, NULL
);
886 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
887 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
891 tv_now
.tv_usec
/ 1000);
893 dns_config
= dns_configuration_copy();
894 do_printDNSConfiguration(argc
, argv
, dns_config
);
895 if (dns_config
!= NULL
) {
896 dns_configuration_free(dns_config
);
899 if (status
!= NOTIFY_STATUS_OK
) {
900 SC_log(LOG_INFO
, "notify_register_dispatch() failed for DNS configuration changes, status=%u", status
);
910 showProxy(CFDictionaryRef proxy
)
912 CFMutableDictionaryRef cleaned
= NULL
;
915 cleaned
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
916 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesScoped
);
917 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesServices
);
918 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesSupplemental
);
922 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), proxy
);
923 if (cleaned
!= NULL
) CFRelease(cleaned
);
930 do_showProxyConfiguration(int argc
, char **argv
)
932 CFMutableDictionaryRef options
= NULL
;
933 CFDictionaryRef proxies
;
935 if (getenv("BYPASS_GLOBAL_PROXY") != NULL
) {
936 options
= CFDictionaryCreateMutable(NULL
, 0,
937 &kCFTypeDictionaryKeyCallBacks
,
938 &kCFTypeDictionaryValueCallBacks
);
939 CFDictionaryAddValue(options
, kSCProxiesNoGlobal
, kCFBooleanTrue
);
942 proxies
= SCDynamicStoreCopyProxiesWithOptions(NULL
, options
);
944 if (options
!= NULL
) {
948 if (proxies
!= NULL
) {
949 CFStringRef interface
= NULL
;
950 CFStringRef server
= NULL
;
953 if (strcasecmp(argv
[0], "interface") == 0) {
958 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
962 if (if_nametoindex(argv
[0]) == 0) {
963 SCPrint(TRUE
, stderr
, CFSTR("No interface: %s\n"), argv
[0]);
967 interface
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
971 if (server
!= NULL
) {
975 server
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
981 if ((server
!= NULL
) || (interface
!= NULL
)) {
984 matching
= SCNetworkProxiesCopyMatching(proxies
, server
, interface
);
985 if (matching
!= NULL
) {
989 if (server
!= NULL
) {
990 if (interface
!= NULL
) {
991 SCPrint(TRUE
, stdout
,
992 CFSTR("server = %@, interface = %@\n"),
996 SCPrint(TRUE
, stdout
,
997 CFSTR("server = %@\n"),
1001 SCPrint(TRUE
, stdout
,
1002 CFSTR("interface = %@\n"),
1006 n
= CFArrayGetCount(matching
);
1007 for (i
= 0; i
< n
; i
++) {
1008 CFDictionaryRef proxy
;
1010 proxy
= CFArrayGetValueAtIndex(matching
, i
);
1011 SCPrint(TRUE
, stdout
, CFSTR("\nproxy #%ld\n"), i
+ 1);
1015 CFRelease(matching
);
1017 SCPrint(TRUE
, stdout
, CFSTR("No matching proxy configurations\n"));
1023 if (interface
!= NULL
) CFRelease(interface
);
1024 if (server
!= NULL
) CFRelease(server
);
1027 SCPrint(TRUE
, stdout
, CFSTR("No proxy configuration available\n"));
1036 do_snapshot(int argc
, char **argv
)
1038 if (!SCDynamicStoreSnapshot(store
)) {
1039 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
1048 do_renew(char *if_name
)
1050 CFArrayRef services
;
1053 if ((if_name
== NULL
) || (strlen(if_name
) == 0)) {
1054 SCPrint(TRUE
, stderr
, CFSTR("No interface name\n"));
1058 if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL
) {
1059 CFArrayRef interfaces
;
1061 interfaces
= SCNetworkInterfaceCopyAll();
1062 if (interfaces
!= NULL
) {
1064 CFStringRef match_name
;
1067 match_name
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
1068 assert(match_name
!= NULL
);
1070 n
= CFArrayGetCount(interfaces
);
1071 for (i
= 0; i
< n
; i
++) {
1072 CFStringRef bsd_name
;
1073 SCNetworkInterfaceRef interface
;
1075 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1076 bsd_name
= SCNetworkInterfaceGetBSDName(interface
);
1077 if (_SC_CFEqual(bsd_name
, match_name
)) {
1079 ok
= SCNetworkInterfaceForceConfigurationRefresh(interface
);
1084 if (status
!= kSCStatusAccessError
) {
1085 SCPrint(TRUE
, stderr
, CFSTR("%s\n"), SCErrorString(status
));
1089 // ... and if can't write the SCDynamicStore, try w/prefs
1096 CFRelease(match_name
);
1097 CFRelease(interfaces
);
1105 do_prefs_init(); /* initialization */
1106 do_prefs_open(0, NULL
); /* open default prefs */
1108 services
= SCNetworkServiceCopyAll(prefs
);
1109 if (services
!= NULL
) {
1111 CFStringRef match_name
;
1114 match_name
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
1115 assert(match_name
!= NULL
);
1117 n
= CFArrayGetCount(services
);
1118 for (i
= 0; i
< n
; i
++) {
1119 CFStringRef bsd_name
;
1120 SCNetworkInterfaceRef interface
;
1121 SCNetworkServiceRef service
;
1123 service
= CFArrayGetValueAtIndex(services
, i
);
1124 interface
= SCNetworkServiceGetInterface(service
);
1125 if (interface
== NULL
) {
1130 bsd_name
= SCNetworkInterfaceGetBSDName(interface
);
1131 if (_SC_CFEqual(bsd_name
, match_name
)) {
1133 ok
= SCNetworkInterfaceForceConfigurationRefresh(interface
);
1135 SCPrint(TRUE
, stderr
, CFSTR("%s\n"), SCErrorString(SCError()));
1143 CFRelease(match_name
);
1144 CFRelease(services
);
1148 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
1165 waitTimeout(int sigraised
)
1173 do_wait(char *waitKey
, int timeout
)
1175 struct itimerval itv
;
1177 CFMutableArrayRef keys
;
1180 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil (wait)"), waitKeyFound
, NULL
);
1181 if (store
== NULL
) {
1182 SCPrint(TRUE
, stderr
,
1183 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1187 key
= CFStringCreateWithCString(NULL
, waitKey
, kCFStringEncodingUTF8
);
1189 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1190 CFArrayAppendValue(keys
, key
);
1191 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
1194 SCPrint(TRUE
, stderr
,
1195 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1199 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1201 SCPrint(TRUE
, stderr
,
1202 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1206 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
1208 value
= SCDynamicStoreCopyValue(store
, key
);
1210 /* if the key is already present */
1216 signal(SIGALRM
, waitTimeout
);
1217 bzero(&itv
, sizeof(itv
));
1218 itv
.it_value
.tv_sec
= timeout
;
1219 if (setitimer(ITIMER_REAL
, &itv
, NULL
) == -1) {
1220 SCPrint(TRUE
, stderr
,
1221 CFSTR("setitimer() failed: %s\n"), strerror(errno
));
1229 #ifdef TEST_DNS_CONFIGURATION
1231 Boolean doDispatch
= FALSE
;
1232 CFRunLoopSourceRef notifyRls
= NULL
;
1233 SCDynamicStoreRef store
= NULL
;
1234 CFPropertyListRef value
= NULL
;
1237 main(int argc
, char **argv
)
1239 dns_config_t
*dns_config
;
1241 fprintf(stdout
, "copy configuration\n");
1242 dns_config
= dns_configuration_copy();
1243 if (dns_config
!= NULL
) {
1245 fprintf(stdout
, "sleeping for 120 seconds\n");
1248 fprintf(stdout
, "sending ack\n");
1249 _dns_configuration_ack(dns_config
, "TEST_DNS_CONFIGURATION");
1251 fprintf(stdout
, "sleeping for 120 seconds\n");
1254 dns_configuration_free(dns_config
);
1257 do_showDNSConfiguration(argc
, argv
);
1261 #endif // TEST_DNS_CONFIGURATION