2 * Copyright (c) 2000, 2001, 2003-2005, 2007-2009 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>
51 static SCNetworkReachabilityRef
52 _setupReachability(int argc
, char **argv
, SCNetworkReachabilityContext
*context
)
54 struct sockaddr_in sin
;
55 struct sockaddr_in6 sin6
;
56 SCNetworkReachabilityRef target
= NULL
;
58 bzero(&sin
, sizeof(sin
));
59 sin
.sin_len
= sizeof(sin
);
60 sin
.sin_family
= AF_INET
;
62 bzero(&sin6
, sizeof(sin6
));
63 sin6
.sin6_len
= sizeof(sin6
);
64 sin6
.sin6_family
= AF_INET6
;
66 if (inet_aton(argv
[0], &sin
.sin_addr
) == 1) {
68 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin
);
69 if (context
!= NULL
) {
70 context
->info
= "by address";
73 struct sockaddr_in r_sin
;
75 bzero(&r_sin
, sizeof(r_sin
));
76 r_sin
.sin_len
= sizeof(r_sin
);
77 r_sin
.sin_family
= AF_INET
;
78 if (inet_aton(argv
[1], &r_sin
.sin_addr
) == 0) {
79 SCPrint(TRUE
, stderr
, CFSTR("Could not interpret address \"%s\"\n"), argv
[1]);
83 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
84 (struct sockaddr
*)&sin
,
85 (struct sockaddr
*)&r_sin
);
86 if (context
!= NULL
) {
87 context
->info
= "by address pair";
90 } else if (inet_pton(AF_INET6
, argv
[0], &sin6
.sin6_addr
) == 1) {
93 p
= strchr(argv
[0], '%');
95 sin6
.sin6_scope_id
= if_nametoindex(p
+ 1);
99 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin6
);
100 if (context
!= NULL
) {
101 context
->info
= "by (v6) address";
104 struct sockaddr_in6 r_sin6
;
106 bzero(&r_sin6
, sizeof(r_sin6
));
107 r_sin6
.sin6_len
= sizeof(r_sin6
);
108 r_sin6
.sin6_family
= AF_INET6
;
109 if (inet_pton(AF_INET6
, argv
[1], &r_sin6
.sin6_addr
) == 0) {
110 SCPrint(TRUE
, stderr
, CFSTR("Could not interpret address \"%s\"\n"), argv
[1]);
114 p
= strchr(argv
[1], '%');
116 r_sin6
.sin6_scope_id
= if_nametoindex(p
+ 1);
119 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
120 (struct sockaddr
*)&sin6
,
121 (struct sockaddr
*)&r_sin6
);
122 if (context
!= NULL
) {
123 context
->info
= "by (v6) address pair";
128 target
= SCNetworkReachabilityCreateWithName(NULL
, argv
[0]);
129 if (context
!= NULL
) {
130 context
->info
= "by name";
134 CFMutableDictionaryRef options
;
136 options
= CFDictionaryCreateMutable(NULL
,
138 &kCFTypeDictionaryKeyCallBacks
,
139 &kCFTypeDictionaryValueCallBacks
);
140 if (strlen(argv
[0]) > 0) {
141 str
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
142 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionNodeName
, str
);
145 if (strlen(argv
[1]) > 0) {
146 str
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
147 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionServName
, str
);
152 struct addrinfo hints
= { 0 };
155 for (i
= 2; i
< argc
; i
++) {
156 if (strcasecmp(argv
[i
], "AI_ADDRCONFIG") == 0) {
157 hints
.ai_flags
|= AI_ADDRCONFIG
;
158 } else if (strcasecmp(argv
[i
], "AI_ALL") == 0) {
159 hints
.ai_flags
|= AI_ALL
;
160 } else if (strcasecmp(argv
[i
], "AI_V4MAPPED") == 0) {
161 hints
.ai_flags
|= AI_V4MAPPED
;
162 } else if (strcasecmp(argv
[i
], "AI_V4MAPPED_CFG") == 0) {
163 hints
.ai_flags
|= AI_V4MAPPED_CFG
;
164 } else if (strcasecmp(argv
[i
], "AI_ADDRCONFIG") == 0) {
165 hints
.ai_flags
|= AI_ADDRCONFIG
;
166 } else if (strcasecmp(argv
[i
], "AI_V4MAPPED") == 0) {
167 hints
.ai_flags
|= AI_V4MAPPED
;
168 } else if (strcasecmp(argv
[i
], "AI_DEFAULT") == 0) {
169 hints
.ai_flags
|= AI_DEFAULT
;
171 } else if (strcasecmp(argv
[i
], "AI_PARALLEL") == 0) {
172 hints
.ai_flags
|= AI_PARALLEL
;
173 #endif // AI_PARALLEL
174 } else if (strcasecmp(argv
[i
], "PF_INET") == 0) {
175 hints
.ai_family
= PF_INET
;
176 } else if (strcasecmp(argv
[i
], "PF_INET6") == 0) {
177 hints
.ai_family
= PF_INET6
;
178 } else if (strcasecmp(argv
[i
], "SOCK_STREAM") == 0) {
179 hints
.ai_socktype
= SOCK_STREAM
;
180 } else if (strcasecmp(argv
[i
], "SOCK_DGRAM") == 0) {
181 hints
.ai_socktype
= SOCK_DGRAM
;
182 } else if (strcasecmp(argv
[i
], "SOCK_RAW") == 0) {
183 hints
.ai_socktype
= SOCK_RAW
;
184 } else if (strcasecmp(argv
[i
], "IPPROTO_TCP") == 0) {
185 hints
.ai_protocol
= IPPROTO_TCP
;
186 } else if (strcasecmp(argv
[i
], "IPPROTO_UDP") == 0) {
187 hints
.ai_protocol
= IPPROTO_UDP
;
189 SCPrint(TRUE
, stderr
, CFSTR("Unrecognized hint: %s\n"), argv
[i
]);
194 data
= CFDataCreate(NULL
, (const UInt8
*)&hints
, sizeof(hints
));
195 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionHints
, data
);
198 if (CFDictionaryGetCount(options
) > 0) {
199 target
= SCNetworkReachabilityCreateWithOptions(NULL
, options
);
200 if (context
!= NULL
) {
201 context
->info
= "by (node and/or serv) name";
204 SCPrint(TRUE
, stderr
, CFSTR("Must specify nodename or servname\n"));
215 _printReachability(SCNetworkReachabilityRef target
)
217 SCNetworkReachabilityFlags flags
;
220 ok
= SCNetworkReachabilityGetFlags(target
, &flags
);
222 printf(" could not determine reachability, %s\n", SCErrorString(SCError()));
226 SCPrint(_sc_debug
, stdout
, CFSTR("flags = 0x%08x"), flags
);
228 SCPrint(_sc_debug
, stdout
, CFSTR(" ("));
229 if (flags
& kSCNetworkReachabilityFlagsReachable
) {
230 SCPrint(TRUE
, stdout
, CFSTR("Reachable"));
231 flags
&= ~kSCNetworkReachabilityFlagsReachable
;
232 SCPrint(flags
!= 0, stdout
, CFSTR(","));
234 if (flags
& kSCNetworkReachabilityFlagsTransientConnection
) {
235 SCPrint(TRUE
, stdout
, CFSTR("Transient Connection"));
236 flags
&= ~kSCNetworkReachabilityFlagsTransientConnection
;
237 SCPrint(flags
!= 0, stdout
, CFSTR(","));
239 if (flags
& kSCNetworkReachabilityFlagsConnectionRequired
) {
240 SCPrint(TRUE
, stdout
, CFSTR("Connection Required"));
241 flags
&= ~kSCNetworkReachabilityFlagsConnectionRequired
;
242 SCPrint(flags
!= 0, stdout
, CFSTR(","));
244 if (flags
& kSCNetworkReachabilityFlagsConnectionOnTraffic
) {
245 SCPrint(TRUE
, stdout
, CFSTR("Automatic Connection On Traffic"));
246 flags
&= ~kSCNetworkReachabilityFlagsConnectionOnTraffic
;
247 SCPrint(flags
!= 0, stdout
, CFSTR(","));
249 if (flags
& kSCNetworkReachabilityFlagsConnectionOnDemand
) {
250 SCPrint(TRUE
, stdout
, CFSTR("Automatic Connection On Demand"));
251 flags
&= ~kSCNetworkReachabilityFlagsConnectionOnDemand
;
252 SCPrint(flags
!= 0, stdout
, CFSTR(","));
254 if (flags
& kSCNetworkReachabilityFlagsInterventionRequired
) {
255 SCPrint(TRUE
, stdout
, CFSTR("Intervention Required"));
256 flags
&= ~kSCNetworkReachabilityFlagsInterventionRequired
;
257 SCPrint(flags
!= 0, stdout
, CFSTR(","));
259 if (flags
& kSCNetworkReachabilityFlagsIsLocalAddress
) {
260 SCPrint(TRUE
, stdout
, CFSTR("Local Address"));
261 flags
&= ~kSCNetworkReachabilityFlagsIsLocalAddress
;
262 SCPrint(flags
!= 0, stdout
, CFSTR(","));
264 if (flags
& kSCNetworkReachabilityFlagsIsDirect
) {
265 SCPrint(TRUE
, stdout
, CFSTR("Directly Reachable Address"));
266 flags
&= ~kSCNetworkReachabilityFlagsIsDirect
;
267 SCPrint(flags
!= 0, stdout
, CFSTR(","));
270 if (flags
& kSCNetworkReachabilityFlagsIsWWAN
) {
271 SCPrint(TRUE
, stdout
, CFSTR("WWAN"));
272 flags
&= ~kSCNetworkReachabilityFlagsIsWWAN
;
273 SCPrint(flags
!= 0, stdout
, CFSTR(","));
275 #endif // TARGET_OS_IPHONE
277 SCPrint(TRUE
, stdout
, CFSTR("0x%08x"), flags
);
279 SCPrint(_sc_debug
, stdout
, CFSTR(")"));
281 SCPrint(_sc_debug
, stdout
, CFSTR(" ("));
282 SCPrint(TRUE
, stdout
, CFSTR("Not Reachable"));
283 SCPrint(_sc_debug
, stdout
, CFSTR(")"));
285 SCPrint(TRUE
, stdout
, CFSTR("\n"));
293 do_checkReachability(int argc
, char **argv
)
295 SCNetworkReachabilityRef target
;
297 target
= _setupReachability(argc
, argv
, NULL
);
298 if (target
== NULL
) {
299 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
303 _printReachability(target
);
310 callout(SCNetworkReachabilityRef target
, SCNetworkReachabilityFlags flags
, void *info
)
314 struct timeval tv_now
;
316 (void)gettimeofday(&tv_now
, NULL
);
317 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
319 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
323 tv_now
.tv_usec
/ 1000);
324 SCPrint(TRUE
, stdout
, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n
++, flags
, (char *)info
);
325 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
326 _printReachability(target
);
327 SCPrint(TRUE
, stdout
, CFSTR("\n"));
334 do_watchReachability(int argc
, char **argv
)
336 SCNetworkReachabilityContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
337 SCNetworkReachabilityRef target
;
338 SCNetworkReachabilityRef target_async
;
340 target
= _setupReachability(argc
, argv
, NULL
);
341 if (target
== NULL
) {
342 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
346 target_async
= _setupReachability(argc
, argv
, &context
);
347 if (target_async
== NULL
) {
348 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
352 // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags()
353 // until after the "target" has been scheduled on a run loop. Otherwise, we'll
354 // end up making a synchronous DNS request and that's not what we want.
356 // But, to test the case were an application call SCNetworkReachabilityGetFlags()
357 // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable.
358 if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL
) {
359 CFRelease(target_async
);
360 target_async
= CFRetain(target
);
363 // Direct check of reachability
364 SCPrint(TRUE
, stdout
, CFSTR(" 0: direct\n"));
365 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
366 _printReachability(target
);
368 SCPrint(TRUE
, stdout
, CFSTR("\n"));
370 // schedule the target
371 SCPrint(TRUE
, stdout
, CFSTR(" 1: start\n"));
372 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
373 //_printReachability(target_async);
374 SCPrint(TRUE
, stdout
, CFSTR("\n"));
376 if (!SCNetworkReachabilitySetCallback(target_async
, callout
, &context
)) {
377 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
381 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
382 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
386 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags()
387 // to get the current status. For "names", a DNS lookup has already been initiated.
388 SCPrint(TRUE
, stdout
, CFSTR(" 2: on runloop\n"));
389 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
390 _printReachability(target_async
);
391 SCPrint(TRUE
, stdout
, CFSTR("\n"));
400 do_showDNSConfiguration(int argc
, char **argv
)
402 dns_config_t
*dns_config
;
404 dns_config
= dns_configuration_copy();
408 SCPrint(TRUE
, stdout
, CFSTR("DNS configuration\n"));
410 for (n
= 0; n
< dns_config
->n_resolver
; n
++) {
412 dns_resolver_t
*resolver
= dns_config
->resolver
[n
];
414 SCPrint(TRUE
, stdout
, CFSTR("\nresolver #%d\n"), n
+ 1);
416 if (resolver
->domain
!= NULL
) {
417 SCPrint(TRUE
, stdout
, CFSTR(" domain : %s\n"), resolver
->domain
);
420 for (i
= 0; i
< resolver
->n_search
; i
++) {
421 SCPrint(TRUE
, stdout
, CFSTR(" search domain[%d] : %s\n"), i
, resolver
->search
[i
]);
424 for (i
= 0; i
< resolver
->n_nameserver
; i
++) {
427 _SC_sockaddr_to_string(resolver
->nameserver
[i
], buf
, sizeof(buf
));
428 SCPrint(TRUE
, stdout
, CFSTR(" nameserver[%d] : %s\n"), i
, buf
);
431 for (i
= 0; i
< resolver
->n_sortaddr
; i
++) {
435 (void)inet_ntop(AF_INET
, &resolver
->sortaddr
[i
]->address
, abuf
, sizeof(abuf
));
436 (void)inet_ntop(AF_INET
, &resolver
->sortaddr
[i
]->mask
, mbuf
, sizeof(mbuf
));
437 SCPrint(TRUE
, stdout
, CFSTR(" sortaddr[%d] : %s/%s\n"), i
, abuf
, mbuf
);
440 if (resolver
->options
!= NULL
) {
441 SCPrint(TRUE
, stdout
, CFSTR(" options : %s\n"), resolver
->options
);
444 if (resolver
->port
!= 0) {
445 SCPrint(TRUE
, stdout
, CFSTR(" port : %hd\n"), resolver
->port
);
448 if (resolver
->timeout
!= 0) {
449 SCPrint(TRUE
, stdout
, CFSTR(" timeout : %d\n"), resolver
->timeout
);
452 if (resolver
->search_order
!= 0) {
453 SCPrint(TRUE
, stdout
, CFSTR(" order : %d\n"), resolver
->search_order
);
457 dns_configuration_free(dns_config
);
459 SCPrint(TRUE
, stdout
, CFSTR("No DNS configuration available\n"));
468 do_showProxyConfiguration(int argc
, char **argv
)
470 CFDictionaryRef proxies
;
472 proxies
= SCDynamicStoreCopyProxies(NULL
);
473 if (proxies
!= NULL
) {
474 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), proxies
);
477 SCPrint(TRUE
, stdout
, CFSTR("No proxy configuration available\n"));
486 do_snapshot(int argc
, char **argv
)
488 if (!SCDynamicStoreSnapshot(store
)) {
489 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
503 waitTimeout(int sigraised
)
511 do_wait(char *waitKey
, int timeout
)
513 struct itimerval itv
;
515 CFMutableArrayRef keys
;
518 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil (wait)"), waitKeyFound
, NULL
);
520 SCPrint(TRUE
, stderr
,
521 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
525 key
= CFStringCreateWithCString(NULL
, waitKey
, kCFStringEncodingUTF8
);
527 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
528 CFArrayAppendValue(keys
, key
);
529 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
532 SCPrint(TRUE
, stderr
,
533 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
537 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
539 SCPrint(TRUE
, stderr
,
540 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
544 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
546 value
= SCDynamicStoreCopyValue(store
, key
);
548 /* if the key is already present */
554 signal(SIGALRM
, waitTimeout
);
555 bzero(&itv
, sizeof(itv
));
556 itv
.it_value
.tv_sec
= timeout
;
557 if (setitimer(ITIMER_REAL
, &itv
, NULL
) == -1) {
558 SCPrint(TRUE
, stderr
,
559 CFSTR("setitimer() failed: %s\n"), strerror(errno
));
567 #ifdef TEST_DNS_CONFIGURATION_COPY
569 CFRunLoopSourceRef notifyRls
= NULL
;
570 SCDynamicStoreRef store
= NULL
;
571 CFPropertyListRef value
= NULL
;
574 main(int argc
, char **argv
)
576 do_showDNSConfiguration(argc
, argv
);
580 #endif // TEST_DNS_CONFIGURATION_COPY