2 * Copyright (c) 2000, 2001, 2003-2016 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, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
54 #include "dnsinfo_internal.h"
55 #include <network_information.h>
56 #include "network_state_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 SCPrint(TRUE
, stderr
, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), 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 SCPrint(TRUE
, stderr
, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), 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 CFDictionaryRef proxies
;
934 if (getenv("BYPASS_GLOBAL_PROXY") != NULL
) {
935 CFMutableDictionaryRef options
;
937 options
= CFDictionaryCreateMutable(NULL
, 0,
938 &kCFTypeDictionaryKeyCallBacks
,
939 &kCFTypeDictionaryValueCallBacks
);
940 CFDictionaryAddValue(options
, kSCProxiesNoGlobal
, kCFBooleanTrue
);
941 proxies
= SCDynamicStoreCopyProxiesWithOptions(NULL
, options
);
944 proxies
= SCDynamicStoreCopyProxies(NULL
);
947 if (proxies
!= NULL
) {
948 CFStringRef interface
= NULL
;
949 CFStringRef server
= NULL
;
952 if (strcasecmp(argv
[0], "interface") == 0) {
957 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
961 if (if_nametoindex(argv
[0]) == 0) {
962 SCPrint(TRUE
, stderr
, CFSTR("No interface: %s\n"), argv
[0]);
966 interface
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
970 if (server
!= NULL
) {
974 server
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
980 if ((server
!= NULL
) || (interface
!= NULL
)) {
983 matching
= SCNetworkProxiesCopyMatching(proxies
, server
, interface
);
984 if (matching
!= NULL
) {
988 if (server
!= NULL
) {
989 if (interface
!= NULL
) {
990 SCPrint(TRUE
, stdout
,
991 CFSTR("server = %@, interface = %@\n"),
995 SCPrint(TRUE
, stdout
,
996 CFSTR("server = %@\n"),
1000 SCPrint(TRUE
, stdout
,
1001 CFSTR("interface = %@\n"),
1005 n
= CFArrayGetCount(matching
);
1006 for (i
= 0; i
< n
; i
++) {
1007 CFDictionaryRef proxy
;
1009 proxy
= CFArrayGetValueAtIndex(matching
, i
);
1010 SCPrint(TRUE
, stdout
, CFSTR("\nproxy #%ld\n"), i
+ 1);
1014 CFRelease(matching
);
1016 SCPrint(TRUE
, stdout
, CFSTR("No matching proxy configurations\n"));
1022 if (interface
!= NULL
) CFRelease(interface
);
1023 if (server
!= NULL
) CFRelease(server
);
1026 SCPrint(TRUE
, stdout
, CFSTR("No proxy configuration available\n"));
1035 do_snapshot(int argc
, char **argv
)
1037 if (!SCDynamicStoreSnapshot(store
)) {
1038 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
1047 do_renew(char *if_name
)
1049 CFArrayRef services
;
1052 if ((if_name
== NULL
) || (strlen(if_name
) == 0)) {
1053 SCPrint(TRUE
, stderr
, CFSTR("No interface name\n"));
1057 if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL
) {
1058 CFArrayRef interfaces
;
1060 interfaces
= SCNetworkInterfaceCopyAll();
1061 if (interfaces
!= NULL
) {
1063 CFStringRef match_name
;
1066 match_name
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
1067 assert(match_name
!= NULL
);
1069 n
= CFArrayGetCount(interfaces
);
1070 for (i
= 0; i
< n
; i
++) {
1071 CFStringRef bsd_name
;
1072 SCNetworkInterfaceRef interface
;
1074 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
1075 bsd_name
= SCNetworkInterfaceGetBSDName(interface
);
1076 if (_SC_CFEqual(bsd_name
, match_name
)) {
1078 ok
= SCNetworkInterfaceForceConfigurationRefresh(interface
);
1083 if (status
!= kSCStatusAccessError
) {
1084 SCPrint(TRUE
, stderr
, CFSTR("%s\n"), SCErrorString(status
));
1088 // ... and if can't write the SCDynamicStore, try w/prefs
1095 CFRelease(match_name
);
1096 CFRelease(interfaces
);
1104 do_prefs_init(); /* initialization */
1105 do_prefs_open(0, NULL
); /* open default prefs */
1107 services
= SCNetworkServiceCopyAll(prefs
);
1108 if (services
!= NULL
) {
1110 CFStringRef match_name
;
1113 match_name
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
1114 assert(match_name
!= NULL
);
1116 n
= CFArrayGetCount(services
);
1117 for (i
= 0; i
< n
; i
++) {
1118 CFStringRef bsd_name
;
1119 SCNetworkInterfaceRef interface
;
1120 SCNetworkServiceRef service
;
1122 service
= CFArrayGetValueAtIndex(services
, i
);
1123 interface
= SCNetworkServiceGetInterface(service
);
1124 if (interface
== NULL
) {
1129 bsd_name
= SCNetworkInterfaceGetBSDName(interface
);
1130 if (_SC_CFEqual(bsd_name
, match_name
)) {
1132 ok
= SCNetworkInterfaceForceConfigurationRefresh(interface
);
1134 SCPrint(TRUE
, stderr
, CFSTR("%s\n"), SCErrorString(SCError()));
1142 CFRelease(match_name
);
1143 CFRelease(services
);
1147 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
1164 waitTimeout(int sigraised
)
1172 do_wait(char *waitKey
, int timeout
)
1174 struct itimerval itv
;
1176 CFMutableArrayRef keys
;
1179 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil (wait)"), waitKeyFound
, NULL
);
1180 if (store
== NULL
) {
1181 SCPrint(TRUE
, stderr
,
1182 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1186 key
= CFStringCreateWithCString(NULL
, waitKey
, kCFStringEncodingUTF8
);
1188 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1189 CFArrayAppendValue(keys
, key
);
1190 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
1193 SCPrint(TRUE
, stderr
,
1194 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1198 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1200 SCPrint(TRUE
, stderr
,
1201 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1205 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
1207 value
= SCDynamicStoreCopyValue(store
, key
);
1209 /* if the key is already present */
1215 signal(SIGALRM
, waitTimeout
);
1216 bzero(&itv
, sizeof(itv
));
1217 itv
.it_value
.tv_sec
= timeout
;
1218 if (setitimer(ITIMER_REAL
, &itv
, NULL
) == -1) {
1219 SCPrint(TRUE
, stderr
,
1220 CFSTR("setitimer() failed: %s\n"), strerror(errno
));
1228 #ifdef TEST_DNS_CONFIGURATION
1230 Boolean doDispatch
= FALSE
;
1231 CFRunLoopSourceRef notifyRls
= NULL
;
1232 SCDynamicStoreRef store
= NULL
;
1233 CFPropertyListRef value
= NULL
;
1236 main(int argc
, char **argv
)
1238 dns_config_t
*dns_config
;
1240 fprintf(stdout
, "copy configuration\n");
1241 dns_config
= dns_configuration_copy();
1242 if (dns_config
!= NULL
) {
1244 fprintf(stdout
, "sleeping for 120 seconds\n");
1247 fprintf(stdout
, "sending ack\n");
1248 _dns_configuration_ack(dns_config
, "TEST_DNS_CONFIGURATION");
1250 fprintf(stdout
, "sleeping for 120 seconds\n");
1253 dns_configuration_free(dns_config
);
1256 do_showDNSConfiguration(argc
, argv
);
1260 #endif // TEST_DNS_CONFIGURATION