2 * Copyright (c) 2000, 2001, 2003-2005, 2007-2012 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>
43 #include <netdb_async.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
50 #include <network_information.h>
51 #include "SCNetworkReachabilityInternal.h"
53 static Boolean resolver_bypass
;
55 static CF_RETURNS_RETAINED CFMutableDictionaryRef
56 _setupReachabilityOptions(int argc
, char **argv
, const char *interface
)
58 CFMutableDictionaryRef options
;
60 options
= CFDictionaryCreateMutable(NULL
,
62 &kCFTypeDictionaryKeyCallBacks
,
63 &kCFTypeDictionaryValueCallBacks
);
66 struct addrinfo hints
= { 0 };
70 for (i
= 2; i
< argc
; i
++) {
71 if (strcasecmp(argv
[i
], "interface") == 0) {
73 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
83 if (strcasecmp(argv
[i
], "llq") == 0) {
84 CFDictionarySetValue(options
,
85 kSCNetworkReachabilityOptionLongLivedQueryBypass
,
88 } else if (strcasecmp(argv
[i
], "no-llq") == 0) {
89 CFDictionarySetValue(options
,
90 kSCNetworkReachabilityOptionLongLivedQueryBypass
,
95 if (strcasecmp(argv
[i
], "server") == 0) {
96 CFDictionarySetValue(options
,
97 kSCNetworkReachabilityOptionServerBypass
,
100 } else if (strcasecmp(argv
[i
], "no-server") == 0) {
101 CFDictionarySetValue(options
,
102 kSCNetworkReachabilityOptionServerBypass
,
107 if (strcasecmp(argv
[i
], "no-resolve") == 0) {
108 CFDictionarySetValue(options
,
109 kSCNetworkReachabilityOptionResolverBypass
,
111 resolver_bypass
= TRUE
;
115 if (strcasecmp(argv
[i
], "AI_ADDRCONFIG") == 0) {
116 hints
.ai_flags
|= AI_ADDRCONFIG
;
117 } else if (strcasecmp(argv
[i
], "AI_ALL") == 0) {
118 hints
.ai_flags
|= AI_ALL
;
119 } else if (strcasecmp(argv
[i
], "AI_V4MAPPED") == 0) {
120 hints
.ai_flags
|= AI_V4MAPPED
;
121 } else if (strcasecmp(argv
[i
], "AI_V4MAPPED_CFG") == 0) {
122 hints
.ai_flags
|= AI_V4MAPPED_CFG
;
123 } else if (strcasecmp(argv
[i
], "AI_ADDRCONFIG") == 0) {
124 hints
.ai_flags
|= AI_ADDRCONFIG
;
125 } else if (strcasecmp(argv
[i
], "AI_V4MAPPED") == 0) {
126 hints
.ai_flags
|= AI_V4MAPPED
;
127 } else if (strcasecmp(argv
[i
], "AI_DEFAULT") == 0) {
128 hints
.ai_flags
|= AI_DEFAULT
;
130 } else if (strcasecmp(argv
[i
], "AI_PARALLEL") == 0) {
131 hints
.ai_flags
|= AI_PARALLEL
;
132 #endif // AI_PARALLEL
133 } else if (strcasecmp(argv
[i
], "PF_INET") == 0) {
134 hints
.ai_family
= PF_INET
;
135 } else if (strcasecmp(argv
[i
], "PF_INET6") == 0) {
136 hints
.ai_family
= PF_INET6
;
137 } else if (strcasecmp(argv
[i
], "SOCK_STREAM") == 0) {
138 hints
.ai_socktype
= SOCK_STREAM
;
139 } else if (strcasecmp(argv
[i
], "SOCK_DGRAM") == 0) {
140 hints
.ai_socktype
= SOCK_DGRAM
;
141 } else if (strcasecmp(argv
[i
], "SOCK_RAW") == 0) {
142 hints
.ai_socktype
= SOCK_RAW
;
143 } else if (strcasecmp(argv
[i
], "IPPROTO_TCP") == 0) {
144 hints
.ai_protocol
= IPPROTO_TCP
;
145 } else if (strcasecmp(argv
[i
], "IPPROTO_UDP") == 0) {
146 hints
.ai_protocol
= IPPROTO_UDP
;
148 SCPrint(TRUE
, stderr
, CFSTR("Unrecognized hint: %s\n"), argv
[i
]);
158 data
= CFDataCreate(NULL
, (const UInt8
*)&hints
, sizeof(hints
));
159 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionHints
, data
);
164 if (interface
!= NULL
) {
167 if (if_nametoindex(interface
) == 0) {
168 SCPrint(TRUE
, stderr
, CFSTR("No interface: %s\n"), interface
);
172 str
= CFStringCreateWithCString(NULL
, interface
, kCFStringEncodingASCII
);
173 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionInterface
, str
);
177 if (CFDictionaryGetCount(options
) == 0) {
186 static SCNetworkReachabilityRef
187 _setupReachability(int argc
, char **argv
, SCNetworkReachabilityContext
*context
)
189 char *ip_address
= argv
[0];
190 const char *interface
;
191 CFMutableDictionaryRef options
= NULL
;
192 struct sockaddr_in sin
;
193 struct sockaddr_in6 sin6
;
194 SCNetworkReachabilityRef target
= NULL
;
196 bzero(&sin
, sizeof(sin
));
197 sin
.sin_len
= sizeof(sin
);
198 sin
.sin_family
= AF_INET
;
200 bzero(&sin6
, sizeof(sin6
));
201 sin6
.sin6_len
= sizeof(sin6
);
202 sin6
.sin6_family
= AF_INET6
;
204 interface
= strchr(argv
[0], '%');
205 if (interface
!= NULL
) {
206 ip_address
= strdup(argv
[0]);
207 ip_address
[interface
- argv
[0]] = '\0';
211 if (inet_aton(ip_address
, &sin
.sin_addr
) == 1) {
213 ((argc
> 1) && (strlen(argv
[1]) == 0))) {
214 options
= _setupReachabilityOptions(argc
, argv
, interface
);
215 if (options
== NULL
) {
216 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin
);
217 if (context
!= NULL
) {
218 context
->info
= "by address";
223 data
= CFDataCreate(NULL
, (const UInt8
*)&sin
, sizeof(sin
));
224 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
227 if (context
!= NULL
) {
228 if (CFDictionaryContainsKey(options
,
229 kSCNetworkReachabilityOptionInterface
)) {
230 if (CFDictionaryGetCount(options
) == 2) {
231 context
->info
= "by address w/scope";
233 context
->info
= "by address w/scope and options";
236 context
->info
= "by address w/options";
241 char *remote_address
= argv
[1];
242 const char *interface2
;
243 struct sockaddr_in r_sin
;
245 interface2
= strchr(argv
[1], '%');
246 if (interface2
!= NULL
) {
247 remote_address
= strdup(argv
[1]);
248 remote_address
[interface2
- argv
[1]] = '\0';
251 if ((interface
!= NULL
) && (strcmp(interface
, interface2
) != 0)) {
252 SCPrint(TRUE
, stderr
,
253 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
259 interface
= interface2
;
262 bzero(&r_sin
, sizeof(r_sin
));
263 r_sin
.sin_len
= sizeof(r_sin
);
264 r_sin
.sin_family
= AF_INET
;
265 if (inet_aton(remote_address
, &r_sin
.sin_addr
) == 0) {
266 SCPrint(TRUE
, stderr
, CFSTR("Could not interpret address \"%s\"\n"), remote_address
);
270 if (remote_address
!= argv
[1]) {
271 free(remote_address
);
274 options
= _setupReachabilityOptions(argc
, argv
, interface
);
275 if (options
== NULL
) {
276 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
277 (struct sockaddr
*)&sin
,
278 (struct sockaddr
*)&r_sin
);
279 if (context
!= NULL
) {
280 context
->info
= "by address pair";
285 data
= CFDataCreate(NULL
, (const UInt8
*)&sin
, sizeof(sin
));
286 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionLocalAddress
, data
);
288 data
= CFDataCreate(NULL
, (const UInt8
*)&r_sin
, sizeof(r_sin
));
289 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
292 if (context
!= NULL
) {
293 if (CFDictionaryContainsKey(options
,
294 kSCNetworkReachabilityOptionInterface
)) {
295 if (CFDictionaryGetCount(options
) == 3) {
296 context
->info
= "by address pair w/scope";
298 context
->info
= "by address pair w/scope and options";
301 context
->info
= "by address pair w/options";
306 } else if (inet_pton(AF_INET6
, argv
[0], &sin6
.sin6_addr
) == 1) {
307 if (interface
!= NULL
) {
308 sin6
.sin6_scope_id
= if_nametoindex(interface
);
312 ((argc
> 1) && (strlen(argv
[1]) == 0))) {
313 options
= _setupReachabilityOptions(argc
, argv
, NULL
);
314 if (options
== NULL
) {
315 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin6
);
316 if (context
!= NULL
) {
317 context
->info
= "by (v6) address";
322 data
= CFDataCreate(NULL
, (const UInt8
*)&sin6
, sizeof(sin6
));
323 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
326 if (context
!= NULL
) {
327 context
->info
= "by (v6) address w/options";
331 struct sockaddr_in6 r_sin6
;
333 bzero(&r_sin6
, sizeof(r_sin6
));
334 r_sin6
.sin6_len
= sizeof(r_sin6
);
335 r_sin6
.sin6_family
= AF_INET6
;
336 if (inet_pton(AF_INET6
, argv
[1], &r_sin6
.sin6_addr
) == 0) {
337 SCPrint(TRUE
, stderr
, CFSTR("Could not interpret address \"%s\"\n"), argv
[1]);
341 interface
= strchr(argv
[1], '%');
342 if (interface
!= NULL
) {
343 r_sin6
.sin6_scope_id
= if_nametoindex(interface
);
346 options
= _setupReachabilityOptions(argc
, argv
, NULL
);
347 if (options
== NULL
) {
348 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
349 (struct sockaddr
*)&sin6
,
350 (struct sockaddr
*)&r_sin6
);
351 if (context
!= NULL
) {
352 context
->info
= "by (v6) address pair";
357 data
= CFDataCreate(NULL
, (const UInt8
*)&sin6
, sizeof(sin6
));
358 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionLocalAddress
, data
);
360 data
= CFDataCreate(NULL
, (const UInt8
*)&r_sin6
, sizeof(r_sin6
));
361 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
364 if (context
!= NULL
) {
365 context
->info
= "by (v6) address pair w/options";
372 options
= _setupReachabilityOptions(argc
, argv
, NULL
);
374 if (((argc
== 1) && (strlen(argv
[0]) > 0)) ||
375 ((argc
> 1) && (strlen(argv
[0]) > 0) && (strlen(argv
[1]) == 0))) {
376 if (options
== NULL
) {
377 target
= SCNetworkReachabilityCreateWithName(NULL
, argv
[0]);
378 if (context
!= NULL
) {
379 context
->info
= "by name";
382 str
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
383 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionNodeName
, str
);
386 if (context
!= NULL
) {
387 context
->info
= "by name w/options";
393 if (options
== NULL
) {
394 options
= CFDictionaryCreateMutable(NULL
,
396 &kCFTypeDictionaryKeyCallBacks
,
397 &kCFTypeDictionaryValueCallBacks
);
399 n_options
= CFDictionaryGetCount(options
);
401 if (strlen(argv
[0]) > 0) {
402 str
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
403 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionNodeName
, str
);
406 if (strlen(argv
[1]) > 0) {
407 str
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
408 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionServName
, str
);
412 if (CFDictionaryGetCount(options
) > n_options
) {
413 if (context
!= NULL
) {
414 if (n_options
== 0) {
415 context
->info
= "by (node and/or serv) name";
417 context
->info
= "by (node and/or serv) name w/options";
421 SCPrint(TRUE
, stderr
, CFSTR("Must specify nodename or servname\n"));
428 if (ip_address
!= argv
[0]) {
432 if ((target
== NULL
) && (options
!= NULL
)) {
433 target
= SCNetworkReachabilityCreateWithOptions(NULL
, options
);
441 _printReachabilityFlags(SCNetworkReachabilityFlags flags
)
444 if (flags
& kSCNetworkReachabilityFlagsReachable
) {
445 SCPrint(TRUE
, stdout
, CFSTR("Reachable"));
446 flags
&= ~kSCNetworkReachabilityFlagsReachable
;
447 SCPrint(flags
!= 0, stdout
, CFSTR(","));
449 if (flags
& kSCNetworkReachabilityFlagsTransientConnection
) {
450 SCPrint(TRUE
, stdout
, CFSTR("Transient Connection"));
451 flags
&= ~kSCNetworkReachabilityFlagsTransientConnection
;
452 SCPrint(flags
!= 0, stdout
, CFSTR(","));
454 if (flags
& kSCNetworkReachabilityFlagsConnectionRequired
) {
455 SCPrint(TRUE
, stdout
, CFSTR("Connection Required"));
456 flags
&= ~kSCNetworkReachabilityFlagsConnectionRequired
;
457 SCPrint(flags
!= 0, stdout
, CFSTR(","));
459 if (flags
& kSCNetworkReachabilityFlagsConnectionOnTraffic
) {
460 SCPrint(TRUE
, stdout
, CFSTR("Automatic Connection On Traffic"));
461 flags
&= ~kSCNetworkReachabilityFlagsConnectionOnTraffic
;
462 SCPrint(flags
!= 0, stdout
, CFSTR(","));
464 if (flags
& kSCNetworkReachabilityFlagsConnectionOnDemand
) {
465 SCPrint(TRUE
, stdout
, CFSTR("Automatic Connection On Demand"));
466 flags
&= ~kSCNetworkReachabilityFlagsConnectionOnDemand
;
467 SCPrint(flags
!= 0, stdout
, CFSTR(","));
469 if (flags
& kSCNetworkReachabilityFlagsInterventionRequired
) {
470 SCPrint(TRUE
, stdout
, CFSTR("Intervention Required"));
471 flags
&= ~kSCNetworkReachabilityFlagsInterventionRequired
;
472 SCPrint(flags
!= 0, stdout
, CFSTR(","));
474 if (flags
& kSCNetworkReachabilityFlagsIsLocalAddress
) {
475 SCPrint(TRUE
, stdout
, CFSTR("Local Address"));
476 flags
&= ~kSCNetworkReachabilityFlagsIsLocalAddress
;
477 SCPrint(flags
!= 0, stdout
, CFSTR(","));
479 if (flags
& kSCNetworkReachabilityFlagsIsDirect
) {
480 SCPrint(TRUE
, stdout
, CFSTR("Directly Reachable Address"));
481 flags
&= ~kSCNetworkReachabilityFlagsIsDirect
;
482 SCPrint(flags
!= 0, stdout
, CFSTR(","));
485 if (flags
& kSCNetworkReachabilityFlagsIsWWAN
) {
486 SCPrint(TRUE
, stdout
, CFSTR("WWAN"));
487 flags
&= ~kSCNetworkReachabilityFlagsIsWWAN
;
488 SCPrint(flags
!= 0, stdout
, CFSTR(","));
490 #endif // TARGET_OS_IPHONE
492 SCPrint(TRUE
, stdout
, CFSTR("0x%08x"), flags
);
495 SCPrint(TRUE
, stdout
, CFSTR("Not Reachable"));
502 _printReachability(SCNetworkReachabilityRef target
)
504 SCNetworkReachabilityFlags flags
;
507 ok
= SCNetworkReachabilityGetFlags(target
, &flags
);
509 printf(" could not determine reachability, %s\n", SCErrorString(SCError()));
513 SCPrint(_sc_debug
, stdout
, CFSTR("flags = 0x%08x ("), flags
);
514 _printReachabilityFlags(flags
);
515 SCPrint(_sc_debug
, stdout
, CFSTR(")"));
517 if (resolver_bypass
) {
519 SCNetworkReachabilityGetInterfaceIndex(target
);
520 SCPrint(_sc_debug
, stdout
, CFSTR("interface index = %d"), if_index
);
523 SCPrint(TRUE
, stdout
, CFSTR("\n"));
531 do_checkReachability(int argc
, char **argv
)
533 SCNetworkReachabilityRef target
;
535 target
= _setupReachability(argc
, argv
, NULL
);
536 if (target
== NULL
) {
537 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
541 _printReachability(target
);
548 _printNWIFlags(nwi_ifstate_flags flags
)
554 SCPrint(TRUE
, stdout
, CFSTR(" ("));
555 if (flags
& NWI_IFSTATE_FLAGS_HAS_IPV4
) {
556 SCPrint(TRUE
, stdout
, CFSTR("IPv4"));
557 flags
&= ~NWI_IFSTATE_FLAGS_HAS_IPV4
;
558 SCPrint(flags
!= 0, stdout
, CFSTR(","));
560 if (flags
& NWI_IFSTATE_FLAGS_HAS_IPV6
) {
561 SCPrint(TRUE
, stdout
, CFSTR("IPv6"));
562 flags
&= ~NWI_IFSTATE_FLAGS_HAS_IPV6
;
563 SCPrint(flags
!= 0, stdout
, CFSTR(","));
565 if (flags
& NWI_IFSTATE_FLAGS_HAS_DNS
) {
566 SCPrint(TRUE
, stdout
, CFSTR("DNS"));
567 flags
&= ~NWI_IFSTATE_FLAGS_HAS_DNS
;
568 SCPrint(flags
!= 0, stdout
, CFSTR(","));
571 SCPrint(TRUE
, stdout
, CFSTR("0x%08x"), flags
);
573 SCPrint(TRUE
, stdout
, CFSTR(")"));
581 do_nwi(int argc
, char **argv
)
583 nwi_ifstate_t ifstate
;
584 nwi_state_t state
= nwi_state_copy();
587 SCPrint(TRUE
, stdout
, CFSTR("No network information\n"));
592 ifstate
= nwi_state_get_ifstate(state
, argv
[0]);
593 if (ifstate
!= NULL
) {
594 nwi_ifstate_flags flags
= nwi_ifstate_get_flags(ifstate
);
596 SCPrint(TRUE
, stdout
, CFSTR("Network interface information\n"), argv
[0]);
597 SCPrint(TRUE
, stdout
,
598 CFSTR(" %7s : flags %p"),
599 nwi_ifstate_get_ifname(ifstate
),
601 _printNWIFlags(flags
);
602 SCPrint(TRUE
, stdout
, CFSTR("\n"));
604 SCPrint(TRUE
, stdout
, CFSTR("No network information (for %s)\n"), argv
[0]);
610 SCPrint(TRUE
, stdout
, CFSTR("Network information\n"));
611 SCPrint(TRUE
, stdout
, CFSTR("\nIPv4 network interface information\n"));
612 ifstate
= nwi_state_get_first_ifstate(state
, AF_INET
);
614 if (ifstate
== NULL
) {
615 SCPrint(TRUE
, stdout
, CFSTR(" No IPv4 states found\n"));
618 while (ifstate
!= NULL
) {
619 nwi_ifstate_flags flags
= nwi_ifstate_get_flags(ifstate
);
621 SCPrint(TRUE
, stdout
,
622 CFSTR(" %7s : flags %p"),
623 nwi_ifstate_get_ifname(ifstate
),
625 _printNWIFlags(flags
);
626 SCPrint(TRUE
, stdout
, CFSTR("\n"));
627 ifstate
= nwi_ifstate_get_next(ifstate
, AF_INET
);
630 SCPrint(TRUE
, stdout
, CFSTR("\nIPv6 network interface information\n"));
631 ifstate
= nwi_state_get_first_ifstate(state
, AF_INET6
);
633 if (ifstate
== NULL
) {
634 SCPrint(TRUE
, stdout
, CFSTR(" No IPv6 states found\n"));
637 while (ifstate
!= NULL
) {
638 nwi_ifstate_flags flags
= nwi_ifstate_get_flags(ifstate
);
640 SCPrint(TRUE
, stdout
,
641 CFSTR(" %7s : flags %p"),
642 nwi_ifstate_get_ifname(ifstate
),
644 _printNWIFlags(flags
);
645 SCPrint(TRUE
, stdout
, CFSTR("\n"));
646 ifstate
= nwi_ifstate_get_next(ifstate
, AF_INET6
);
651 nwi_state_release(state
);
657 callout(SCNetworkReachabilityRef target
, SCNetworkReachabilityFlags flags
, void *info
)
661 struct timeval tv_now
;
663 (void)gettimeofday(&tv_now
, NULL
);
664 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
666 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
670 tv_now
.tv_usec
/ 1000);
671 SCPrint(TRUE
, stdout
, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n
++, flags
, (char *)info
);
672 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
673 _printReachability(target
);
674 SCPrint(TRUE
, stdout
, CFSTR("\n"));
681 do_watchReachability(int argc
, char **argv
)
683 SCNetworkReachabilityContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
684 SCNetworkReachabilityRef target
;
685 SCNetworkReachabilityRef target_async
;
687 target
= _setupReachability(argc
, argv
, NULL
);
688 if (target
== NULL
) {
689 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
693 target_async
= _setupReachability(argc
, argv
, &context
);
694 if (target_async
== NULL
) {
695 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
699 // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags()
700 // until after the "target" has been scheduled on a run loop. Otherwise, we'll
701 // end up making a synchronous DNS request and that's not what we want.
703 // To test the case were an application first calls SCNetworkReachabilityGetFlags()
704 // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable.
705 if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL
) {
706 CFRelease(target_async
);
707 target_async
= CFRetain(target
);
710 // Direct check of reachability
711 SCPrint(TRUE
, stdout
, CFSTR(" 0: direct\n"));
712 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
713 _printReachability(target
);
715 SCPrint(TRUE
, stdout
, CFSTR("\n"));
717 // schedule the target
718 SCPrint(TRUE
, stdout
, CFSTR(" 1: start\n"));
719 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
720 // _printReachability(target_async);
721 SCPrint(TRUE
, stdout
, CFSTR("\n"));
723 if (!SCNetworkReachabilitySetCallback(target_async
, callout
, &context
)) {
724 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
729 if (!SCNetworkReachabilitySetDispatchQueue(target_async
, dispatch_get_current_queue())) {
730 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
734 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
735 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
740 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags()
741 // to get the current status. For "names", a DNS lookup has already been initiated.
742 SCPrint(TRUE
, stdout
, CFSTR(" 2: on %s\n"), doDispatch
? "dispatch queue" : "runloop");
743 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
744 _printReachability(target_async
);
745 SCPrint(TRUE
, stdout
, CFSTR("\n"));
753 showResolver(dns_resolver_t
*resolver
, int index
)
757 SCPrint(TRUE
, stdout
, CFSTR("\nresolver #%d\n"), index
);
759 if (resolver
->domain
!= NULL
) {
760 SCPrint(TRUE
, stdout
, CFSTR(" domain : %s\n"), resolver
->domain
);
763 for (i
= 0; i
< resolver
->n_search
; i
++) {
764 SCPrint(TRUE
, stdout
, CFSTR(" search domain[%d] : %s\n"), i
, resolver
->search
[i
]);
767 for (i
= 0; i
< resolver
->n_nameserver
; i
++) {
770 _SC_sockaddr_to_string(resolver
->nameserver
[i
], buf
, sizeof(buf
));
771 SCPrint(TRUE
, stdout
, CFSTR(" nameserver[%d] : %s\n"), i
, buf
);
774 for (i
= 0; i
< resolver
->n_sortaddr
; i
++) {
778 (void)inet_ntop(AF_INET
, &resolver
->sortaddr
[i
]->address
, abuf
, sizeof(abuf
));
779 (void)inet_ntop(AF_INET
, &resolver
->sortaddr
[i
]->mask
, mbuf
, sizeof(mbuf
));
780 SCPrint(TRUE
, stdout
, CFSTR(" sortaddr[%d] : %s/%s\n"), i
, abuf
, mbuf
);
783 if (resolver
->options
!= NULL
) {
784 SCPrint(TRUE
, stdout
, CFSTR(" options : %s\n"), resolver
->options
);
787 if (resolver
->port
!= 0) {
788 SCPrint(TRUE
, stdout
, CFSTR(" port : %hd\n"), resolver
->port
);
791 if (resolver
->timeout
!= 0) {
792 SCPrint(TRUE
, stdout
, CFSTR(" timeout : %d\n"), resolver
->timeout
);
795 if (resolver
->if_index
!= 0) {
799 if_name
= if_indextoname(resolver
->if_index
, buf
);
800 SCPrint(TRUE
, stdout
, CFSTR(" if_index : %d (%s)\n"),
802 (if_name
!= NULL
) ? if_name
: "?");
805 if (resolver
->flags
!= 0) {
806 uint32_t flags
= resolver
->flags
;
808 SCPrint(TRUE
, stdout
, CFSTR(" flags : "));
809 SCPrint(_sc_debug
, stdout
, CFSTR("0x%08x ("), flags
);
810 if (flags
& DNS_RESOLVER_FLAGS_SCOPED
) {
811 SCPrint(TRUE
, stdout
, CFSTR("Scoped"));
812 flags
&= ~DNS_RESOLVER_FLAGS_SCOPED
;
813 SCPrint(flags
!= 0, stdout
, CFSTR(","));
816 SCPrint(TRUE
, stdout
, CFSTR("0x%08x"), flags
);
818 SCPrint(_sc_debug
, stdout
, CFSTR(")"));
819 SCPrint(TRUE
, stdout
, CFSTR("\n"));
822 if (resolver
->reach_flags
!= 0) {
823 uint32_t flags
= resolver
->reach_flags
;
825 SCPrint(TRUE
, stdout
, CFSTR(" reach : "));
826 SCPrint(_sc_debug
, stdout
, CFSTR("0x%08x ("), flags
);
827 _printReachabilityFlags(flags
);
828 SCPrint(_sc_debug
, stdout
, CFSTR(")"));
829 SCPrint(TRUE
, stdout
, CFSTR("\n"));
832 if (resolver
->search_order
!= 0) {
833 SCPrint(TRUE
, stdout
, CFSTR(" order : %d\n"), resolver
->search_order
);
842 do_showDNSConfiguration(int argc
, char **argv
)
844 dns_config_t
*dns_config
;
845 SCNetworkReachabilityRef target
;
847 dns_config
= dns_configuration_copy();
849 if (dns_config
== NULL
) {
850 SCPrint(TRUE
, stdout
, CFSTR("No DNS configuration available\n"));
855 int dns_config_index
= -1;
856 SCNetworkReachabilityFlags flags
= 0;
857 Boolean haveDNS
= FALSE
;
859 dns_resolver_t
*resolver
;
860 uint32_t resolver_if_index
;
861 SCNetworkReachabilityPrivateRef targetPrivate
;
863 target
= _setupReachability(argc
, argv
, NULL
);
865 targetPrivate
= (SCNetworkReachabilityPrivateRef
)target
;
867 if (targetPrivate
->type
!= reachabilityTypeName
) {
868 SCPrint(TRUE
, stdout
, CFSTR("\"%s\" is not a hostname.\n"), argv
[0]);
872 ok
= __SC_checkResolverReachabilityInternal(&store
, &flags
,
873 &haveDNS
, targetPrivate
->name
, NULL
,
874 &resolver_if_index
, &dns_config_index
);
877 SCPrint(TRUE
, stdout
, CFSTR("No DNS configuration available.\n" ));
881 SCPrint(TRUE
, stdout
, CFSTR("DNS configuration for %s\n"),
882 targetPrivate
->name
);
884 if (targetPrivate
->if_index
== 0) {
885 resolver
= dns_config
->resolver
[dns_config_index
];
887 resolver
= dns_config
->scoped_resolver
[dns_config_index
];
890 showResolver(resolver
, dns_config_index
+ 1);
892 if (target
!= NULL
) CFRelease(target
);
896 SCPrint(TRUE
, stdout
, CFSTR("DNS configuration\n"));
898 for (i
= 0; i
< dns_config
->n_resolver
; i
++) {
899 dns_resolver_t
*resolver
= dns_config
->resolver
[i
];
901 showResolver(resolver
, i
+ 1);
904 if ((dns_config
->n_scoped_resolver
> 0) && (dns_config
->scoped_resolver
!= NULL
)) {
905 SCPrint(TRUE
, stdout
, CFSTR("\nDNS configuration (for scoped queries)\n"));
907 for (i
= 0; i
< dns_config
->n_scoped_resolver
; i
++) {
908 dns_resolver_t
*resolver
= dns_config
->scoped_resolver
[i
];
910 showResolver(resolver
, i
+ 1);
915 dns_configuration_free(dns_config
);
921 showProxy(CFDictionaryRef proxy
)
923 CFMutableDictionaryRef cleaned
= NULL
;
926 cleaned
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
927 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesSupplemental
);
928 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesScoped
);
932 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), proxy
);
933 if (cleaned
!= NULL
) CFRelease(cleaned
);
940 do_showProxyConfiguration(int argc
, char **argv
)
942 CFDictionaryRef proxies
;
944 proxies
= SCDynamicStoreCopyProxies(NULL
);
945 if (proxies
!= NULL
) {
946 CFStringRef interface
= NULL
;
947 CFStringRef server
= NULL
;
950 if (strcasecmp(argv
[0], "interface") == 0) {
955 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
959 if (if_nametoindex(argv
[0]) == 0) {
960 SCPrint(TRUE
, stderr
, CFSTR("No interface: %s\n"), argv
[0]);
964 interface
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
968 if (server
!= NULL
) {
972 server
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
978 if ((server
!= NULL
) || (interface
!= NULL
)) {
981 matching
= SCNetworkProxiesCopyMatching(proxies
, server
, interface
);
982 if (matching
!= NULL
) {
986 if (server
!= NULL
) {
987 if (interface
!= NULL
) {
988 SCPrint(TRUE
, stdout
,
989 CFSTR("server = %@, interface = %@\n"),
993 SCPrint(TRUE
, stdout
,
994 CFSTR("server = %@\n"),
998 SCPrint(TRUE
, stdout
,
999 CFSTR("interface = %@\n"),
1003 n
= CFArrayGetCount(matching
);
1004 for (i
= 0; i
< n
; i
++) {
1005 CFDictionaryRef proxy
;
1007 proxy
= CFArrayGetValueAtIndex(matching
, i
);
1008 SCPrint(TRUE
, stdout
, CFSTR("\nproxy #%d\n"), i
+ 1);
1012 CFRelease(matching
);
1014 SCPrint(TRUE
, stdout
, CFSTR("No matching proxy configurations\n"));
1020 if (interface
!= NULL
) CFRelease(interface
);
1021 if (server
!= NULL
) CFRelease(server
);
1024 SCPrint(TRUE
, stdout
, CFSTR("No proxy configuration available\n"));
1033 do_snapshot(int argc
, char **argv
)
1035 if (!SCDynamicStoreSnapshot(store
)) {
1036 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
1039 #ifdef HAVE_REACHABILITY_SERVER
1040 (void) _SCNetworkReachabilityServer_snapshot();
1041 #endif // HAVE_REACHABILITY_SERVER
1055 waitTimeout(int sigraised
)
1063 do_wait(char *waitKey
, int timeout
)
1065 struct itimerval itv
;
1067 CFMutableArrayRef keys
;
1070 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil (wait)"), waitKeyFound
, NULL
);
1071 if (store
== NULL
) {
1072 SCPrint(TRUE
, stderr
,
1073 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1077 key
= CFStringCreateWithCString(NULL
, waitKey
, kCFStringEncodingUTF8
);
1079 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1080 CFArrayAppendValue(keys
, key
);
1081 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
1084 SCPrint(TRUE
, stderr
,
1085 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1089 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1091 SCPrint(TRUE
, stderr
,
1092 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1096 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
1098 value
= SCDynamicStoreCopyValue(store
, key
);
1100 /* if the key is already present */
1106 signal(SIGALRM
, waitTimeout
);
1107 bzero(&itv
, sizeof(itv
));
1108 itv
.it_value
.tv_sec
= timeout
;
1109 if (setitimer(ITIMER_REAL
, &itv
, NULL
) == -1) {
1110 SCPrint(TRUE
, stderr
,
1111 CFSTR("setitimer() failed: %s\n"), strerror(errno
));
1119 #ifdef TEST_DNS_CONFIGURATION_COPY
1121 CFRunLoopSourceRef notifyRls
= NULL
;
1122 SCDynamicStoreRef store
= NULL
;
1123 CFPropertyListRef value
= NULL
;
1126 main(int argc
, char **argv
)
1128 do_showDNSConfiguration(argc
, argv
);
1132 #endif // TEST_DNS_CONFIGURATION_COPY