]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/tests.c
configd-453.16.tar.gz
[apple/configd.git] / scutil.tproj / tests.c
1 /*
2 * Copyright (c) 2000, 2001, 2003-2005, 2007-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * July 9, 2001 Allan Nathanson <ajn@apple.com>
28 * - added "-r" option for checking network reachability
29 * - added "-w" option to check/wait for the presence of a
30 * dynamic store key.
31 *
32 * June 1, 2001 Allan Nathanson <ajn@apple.com>
33 * - public API conversion
34 *
35 * November 9, 2000 Allan Nathanson <ajn@apple.com>
36 * - initial revision
37 */
38
39 #include "scutil.h"
40 #include "tests.h"
41
42 #include <netdb.h>
43 #include <netdb_async.h>
44 #include <sys/time.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48
49 #include <dnsinfo.h>
50 #include <network_information.h>
51 #include "SCNetworkReachabilityInternal.h"
52
53 static Boolean resolver_bypass;
54
55 static CF_RETURNS_RETAINED CFMutableDictionaryRef
56 _setupReachabilityOptions(int argc, char **argv, const char *interface)
57 {
58 CFMutableDictionaryRef options;
59
60 options = CFDictionaryCreateMutable(NULL,
61 0,
62 &kCFTypeDictionaryKeyCallBacks,
63 &kCFTypeDictionaryValueCallBacks);
64
65 if (argc > 2) {
66 struct addrinfo hints = { 0 };
67 int n_hints = 0;
68 int i;
69
70 for (i = 2; i < argc; i++) {
71 if (strcasecmp(argv[i], "interface") == 0) {
72 if (++i >= argc) {
73 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
74 CFRelease(options);
75 exit(1);
76 }
77
78 interface = argv[i];
79 continue;
80 }
81
82
83 if (strcasecmp(argv[i], "llq") == 0) {
84 CFDictionarySetValue(options,
85 kSCNetworkReachabilityOptionLongLivedQueryBypass,
86 kCFBooleanFalse);
87 continue;
88 } else if (strcasecmp(argv[i], "no-llq") == 0) {
89 CFDictionarySetValue(options,
90 kSCNetworkReachabilityOptionLongLivedQueryBypass,
91 kCFBooleanTrue);
92 continue;
93 }
94
95 if (strcasecmp(argv[i], "server") == 0) {
96 CFDictionarySetValue(options,
97 kSCNetworkReachabilityOptionServerBypass,
98 kCFBooleanFalse);
99 continue;
100 } else if (strcasecmp(argv[i], "no-server") == 0) {
101 CFDictionarySetValue(options,
102 kSCNetworkReachabilityOptionServerBypass,
103 kCFBooleanTrue);
104 continue;
105 }
106
107 if (strcasecmp(argv[i], "no-resolve") == 0) {
108 CFDictionarySetValue(options,
109 kSCNetworkReachabilityOptionResolverBypass,
110 kCFBooleanTrue);
111 resolver_bypass = TRUE;
112 continue;
113 }
114
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;
129 #ifdef AI_PARALLEL
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;
147 } else {
148 SCPrint(TRUE, stderr, CFSTR("Unrecognized hint: %s\n"), argv[i]);
149 CFRelease(options);
150 exit(1);
151 }
152 n_hints++;
153 }
154
155 if (n_hints > 0) {
156 CFDataRef data;
157
158 data = CFDataCreate(NULL, (const UInt8 *)&hints, sizeof(hints));
159 CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data);
160 CFRelease(data);
161 }
162 }
163
164 if (interface != NULL) {
165 CFStringRef str;
166
167 if (if_nametoindex(interface) == 0) {
168 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface);
169 exit(1);
170 }
171
172 str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII);
173 CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
174 CFRelease(str);
175 }
176
177 if (CFDictionaryGetCount(options) == 0) {
178 CFRelease(options);
179 options = NULL;
180 }
181
182 return options;
183 }
184
185
186 static SCNetworkReachabilityRef
187 _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
188 {
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;
195
196 bzero(&sin, sizeof(sin));
197 sin.sin_len = sizeof(sin);
198 sin.sin_family = AF_INET;
199
200 bzero(&sin6, sizeof(sin6));
201 sin6.sin6_len = sizeof(sin6);
202 sin6.sin6_family = AF_INET6;
203
204 interface = strchr(argv[0], '%');
205 if (interface != NULL) {
206 ip_address = strdup(argv[0]);
207 ip_address[interface - argv[0]] = '\0';
208 interface++;
209 }
210
211 if (inet_aton(ip_address, &sin.sin_addr) == 1) {
212 if ((argc == 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";
219 }
220 } else {
221 CFDataRef data;
222
223 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
224 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
225 CFRelease(data);
226
227 if (context != NULL) {
228 if (CFDictionaryContainsKey(options,
229 kSCNetworkReachabilityOptionInterface)) {
230 if (CFDictionaryGetCount(options) == 2) {
231 context->info = "by address w/scope";
232 } else {
233 context->info = "by address w/scope and options";
234 }
235 } else {
236 context->info = "by address w/options";
237 }
238 }
239 }
240 } else {
241 char *remote_address = argv[1];
242 const char *interface2;
243 struct sockaddr_in r_sin;
244
245 interface2 = strchr(argv[1], '%');
246 if (interface2 != NULL) {
247 remote_address = strdup(argv[1]);
248 remote_address[interface2 - argv[1]] = '\0';
249 interface2++;
250
251 if ((interface != NULL) && (strcmp(interface, interface2) != 0)) {
252 SCPrint(TRUE, stderr,
253 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
254 interface,
255 interface2);
256 exit(1);
257 }
258
259 interface = interface2;
260 }
261
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);
267 exit(1);
268 }
269
270 if (remote_address != argv[1]) {
271 free(remote_address);
272 }
273
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";
281 }
282 } else {
283 CFDataRef data;
284
285 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
286 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
287 CFRelease(data);
288 data = CFDataCreate(NULL, (const UInt8 *)&r_sin, sizeof(r_sin));
289 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
290 CFRelease(data);
291
292 if (context != NULL) {
293 if (CFDictionaryContainsKey(options,
294 kSCNetworkReachabilityOptionInterface)) {
295 if (CFDictionaryGetCount(options) == 3) {
296 context->info = "by address pair w/scope";
297 } else {
298 context->info = "by address pair w/scope and options";
299 }
300 } else {
301 context->info = "by address pair w/options";
302 }
303 }
304 }
305 }
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);
309 }
310
311 if ((argc == 1) ||
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";
318 }
319 } else {
320 CFDataRef data;
321
322 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
323 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
324 CFRelease(data);
325
326 if (context != NULL) {
327 context->info = "by (v6) address w/options";
328 }
329 }
330 } else {
331 struct sockaddr_in6 r_sin6;
332
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]);
338 exit(1);
339 }
340
341 interface = strchr(argv[1], '%');
342 if (interface != NULL) {
343 r_sin6.sin6_scope_id = if_nametoindex(interface);
344 }
345
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";
353 }
354 } else {
355 CFDataRef data;
356
357 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
358 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
359 CFRelease(data);
360 data = CFDataCreate(NULL, (const UInt8 *)&r_sin6, sizeof(r_sin6));
361 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
362 CFRelease(data);
363
364 if (context != NULL) {
365 context->info = "by (v6) address pair w/options";
366 }
367 }
368 }
369 } else {
370 CFStringRef str;
371
372 options = _setupReachabilityOptions(argc, argv, NULL);
373
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";
380 }
381 } else {
382 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
383 CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
384 CFRelease(str);
385
386 if (context != NULL) {
387 context->info = "by name w/options";
388 }
389 }
390 } else {
391 CFIndex n_options;
392
393 if (options == NULL) {
394 options = CFDictionaryCreateMutable(NULL,
395 0,
396 &kCFTypeDictionaryKeyCallBacks,
397 &kCFTypeDictionaryValueCallBacks);
398 }
399 n_options = CFDictionaryGetCount(options);
400
401 if (strlen(argv[0]) > 0) {
402 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
403 CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
404 CFRelease(str);
405 }
406 if (strlen(argv[1]) > 0) {
407 str = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8);
408 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServName, str);
409 CFRelease(str);
410 }
411
412 if (CFDictionaryGetCount(options) > n_options) {
413 if (context != NULL) {
414 if (n_options == 0) {
415 context->info = "by (node and/or serv) name";
416 } else {
417 context->info = "by (node and/or serv) name w/options";
418 }
419 }
420 } else {
421 SCPrint(TRUE, stderr, CFSTR("Must specify nodename or servname\n"));
422 CFRelease(options);
423 exit(1);
424 }
425 }
426 }
427
428 if (ip_address != argv[0]) {
429 free(ip_address);
430 }
431
432 if ((target == NULL) && (options != NULL)) {
433 target = SCNetworkReachabilityCreateWithOptions(NULL, options);
434 CFRelease(options);
435 }
436
437 return target;
438 }
439
440 static void
441 _printReachabilityFlags(SCNetworkReachabilityFlags flags)
442 {
443 if (flags != 0) {
444 if (flags & kSCNetworkReachabilityFlagsReachable) {
445 SCPrint(TRUE, stdout, CFSTR("Reachable"));
446 flags &= ~kSCNetworkReachabilityFlagsReachable;
447 SCPrint(flags != 0, stdout, CFSTR(","));
448 }
449 if (flags & kSCNetworkReachabilityFlagsTransientConnection) {
450 SCPrint(TRUE, stdout, CFSTR("Transient Connection"));
451 flags &= ~kSCNetworkReachabilityFlagsTransientConnection;
452 SCPrint(flags != 0, stdout, CFSTR(","));
453 }
454 if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
455 SCPrint(TRUE, stdout, CFSTR("Connection Required"));
456 flags &= ~kSCNetworkReachabilityFlagsConnectionRequired;
457 SCPrint(flags != 0, stdout, CFSTR(","));
458 }
459 if (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) {
460 SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Traffic"));
461 flags &= ~kSCNetworkReachabilityFlagsConnectionOnTraffic;
462 SCPrint(flags != 0, stdout, CFSTR(","));
463 }
464 if (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) {
465 SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Demand"));
466 flags &= ~kSCNetworkReachabilityFlagsConnectionOnDemand;
467 SCPrint(flags != 0, stdout, CFSTR(","));
468 }
469 if (flags & kSCNetworkReachabilityFlagsInterventionRequired) {
470 SCPrint(TRUE, stdout, CFSTR("Intervention Required"));
471 flags &= ~kSCNetworkReachabilityFlagsInterventionRequired;
472 SCPrint(flags != 0, stdout, CFSTR(","));
473 }
474 if (flags & kSCNetworkReachabilityFlagsIsLocalAddress) {
475 SCPrint(TRUE, stdout, CFSTR("Local Address"));
476 flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress;
477 SCPrint(flags != 0, stdout, CFSTR(","));
478 }
479 if (flags & kSCNetworkReachabilityFlagsIsDirect) {
480 SCPrint(TRUE, stdout, CFSTR("Directly Reachable Address"));
481 flags &= ~kSCNetworkReachabilityFlagsIsDirect;
482 SCPrint(flags != 0, stdout, CFSTR(","));
483 }
484 #if TARGET_OS_IPHONE
485 if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
486 SCPrint(TRUE, stdout, CFSTR("WWAN"));
487 flags &= ~kSCNetworkReachabilityFlagsIsWWAN;
488 SCPrint(flags != 0, stdout, CFSTR(","));
489 }
490 #endif // TARGET_OS_IPHONE
491 if (flags != 0) {
492 SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
493 }
494 } else {
495 SCPrint(TRUE, stdout, CFSTR("Not Reachable"));
496 }
497
498 return;
499 }
500
501 static void
502 _printReachability(SCNetworkReachabilityRef target)
503 {
504 SCNetworkReachabilityFlags flags;
505 Boolean ok;
506
507 ok = SCNetworkReachabilityGetFlags(target, &flags);
508 if (!ok) {
509 printf(" could not determine reachability, %s\n", SCErrorString(SCError()));
510 return;
511 }
512
513 SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x ("), flags);
514 _printReachabilityFlags(flags);
515 SCPrint(_sc_debug, stdout, CFSTR(")"));
516
517 if (resolver_bypass) {
518 int if_index =
519 SCNetworkReachabilityGetInterfaceIndex(target);
520 SCPrint(_sc_debug, stdout, CFSTR("interface index = %d"), if_index);
521 }
522
523 SCPrint(TRUE, stdout, CFSTR("\n"));
524
525 return;
526 }
527
528
529 __private_extern__
530 void
531 do_checkReachability(int argc, char **argv)
532 {
533 SCNetworkReachabilityRef target;
534
535 target = _setupReachability(argc, argv, NULL);
536 if (target == NULL) {
537 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
538 exit(1);
539 }
540
541 _printReachability(target);
542 CFRelease(target);
543 exit(0);
544 }
545
546
547 static void
548 _printNWIFlags(nwi_ifstate_flags flags)
549 {
550 if (flags == 0) {
551 return;
552 }
553
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(","));
559 }
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(","));
564 }
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(","));
569 }
570 if (flags != 0) {
571 SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
572 }
573 SCPrint(TRUE, stdout, CFSTR(")"));
574
575 return;
576 }
577
578
579 __private_extern__
580 void
581 do_nwi(int argc, char **argv)
582 {
583 nwi_ifstate_t ifstate;
584 nwi_state_t state = nwi_state_copy();
585
586 if (state == NULL) {
587 SCPrint(TRUE, stdout, CFSTR("No network information\n"));
588 exit(1);
589 }
590
591 if (argc > 0) {
592 ifstate = nwi_state_get_ifstate(state, argv[0]);
593 if (ifstate != NULL) {
594 nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate);
595
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),
600 flags);
601 _printNWIFlags(flags);
602 SCPrint(TRUE, stdout, CFSTR("\n"));
603 } else {
604 SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]);
605 }
606
607 goto done;
608 }
609
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);
613
614 if (ifstate == NULL) {
615 SCPrint(TRUE, stdout, CFSTR(" No IPv4 states found\n"));
616 }
617
618 while (ifstate != NULL) {
619 nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate);
620
621 SCPrint(TRUE, stdout,
622 CFSTR(" %7s : flags %p"),
623 nwi_ifstate_get_ifname(ifstate),
624 flags);
625 _printNWIFlags(flags);
626 SCPrint(TRUE, stdout, CFSTR("\n"));
627 ifstate = nwi_ifstate_get_next(ifstate, AF_INET);
628 }
629
630 SCPrint(TRUE, stdout, CFSTR("\nIPv6 network interface information\n"));
631 ifstate = nwi_state_get_first_ifstate(state, AF_INET6);
632
633 if (ifstate == NULL) {
634 SCPrint(TRUE, stdout, CFSTR(" No IPv6 states found\n"));
635 }
636
637 while (ifstate != NULL) {
638 nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate);
639
640 SCPrint(TRUE, stdout,
641 CFSTR(" %7s : flags %p"),
642 nwi_ifstate_get_ifname(ifstate),
643 flags);
644 _printNWIFlags(flags);
645 SCPrint(TRUE, stdout, CFSTR("\n"));
646 ifstate = nwi_ifstate_get_next(ifstate, AF_INET6);
647 }
648
649 done :
650
651 nwi_state_release(state);
652 exit(0);
653 }
654
655
656 static void
657 callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
658 {
659 static int n = 3;
660 struct tm tm_now;
661 struct timeval tv_now;
662
663 (void)gettimeofday(&tv_now, NULL);
664 (void)localtime_r(&tv_now.tv_sec, &tm_now);
665
666 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
667 tm_now.tm_hour,
668 tm_now.tm_min,
669 tm_now.tm_sec,
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"));
675 return;
676 }
677
678
679 __private_extern__
680 void
681 do_watchReachability(int argc, char **argv)
682 {
683 SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
684 SCNetworkReachabilityRef target;
685 SCNetworkReachabilityRef target_async;
686
687 target = _setupReachability(argc, argv, NULL);
688 if (target == NULL) {
689 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
690 exit(1);
691 }
692
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()));
696 exit(1);
697 }
698
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.
702 //
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);
708 }
709
710 // Direct check of reachability
711 SCPrint(TRUE, stdout, CFSTR(" 0: direct\n"));
712 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
713 _printReachability(target);
714 CFRelease(target);
715 SCPrint(TRUE, stdout, CFSTR("\n"));
716
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"));
722
723 if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) {
724 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
725 exit(1);
726 }
727
728 if (doDispatch) {
729 if (!SCNetworkReachabilitySetDispatchQueue(target_async, dispatch_get_current_queue())) {
730 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
731 exit(1);
732 }
733 } else {
734 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
735 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
736 exit(1);
737 }
738 }
739
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"));
746
747 CFRunLoopRun();
748 exit(0);
749 }
750
751
752 static void
753 showResolver(dns_resolver_t *resolver, int index)
754 {
755 int i;
756
757 SCPrint(TRUE, stdout, CFSTR("\nresolver #%d\n"), index);
758
759 if (resolver->domain != NULL) {
760 SCPrint(TRUE, stdout, CFSTR(" domain : %s\n"), resolver->domain);
761 }
762
763 for (i = 0; i < resolver->n_search; i++) {
764 SCPrint(TRUE, stdout, CFSTR(" search domain[%d] : %s\n"), i, resolver->search[i]);
765 }
766
767 for (i = 0; i < resolver->n_nameserver; i++) {
768 char buf[128];
769
770 _SC_sockaddr_to_string(resolver->nameserver[i], buf, sizeof(buf));
771 SCPrint(TRUE, stdout, CFSTR(" nameserver[%d] : %s\n"), i, buf);
772 }
773
774 for (i = 0; i < resolver->n_sortaddr; i++) {
775 char abuf[32];
776 char mbuf[32];
777
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);
781 }
782
783 if (resolver->options != NULL) {
784 SCPrint(TRUE, stdout, CFSTR(" options : %s\n"), resolver->options);
785 }
786
787 if (resolver->port != 0) {
788 SCPrint(TRUE, stdout, CFSTR(" port : %hd\n"), resolver->port);
789 }
790
791 if (resolver->timeout != 0) {
792 SCPrint(TRUE, stdout, CFSTR(" timeout : %d\n"), resolver->timeout);
793 }
794
795 if (resolver->if_index != 0) {
796 char buf[IFNAMSIZ];
797 char *if_name;
798
799 if_name = if_indextoname(resolver->if_index, buf);
800 SCPrint(TRUE, stdout, CFSTR(" if_index : %d (%s)\n"),
801 resolver->if_index,
802 (if_name != NULL) ? if_name : "?");
803 }
804
805 if (resolver->flags != 0) {
806 uint32_t flags = resolver->flags;
807
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(","));
814 }
815 if (flags != 0) {
816 SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
817 }
818 SCPrint(_sc_debug, stdout, CFSTR(")"));
819 SCPrint(TRUE, stdout, CFSTR("\n"));
820 }
821
822 if (resolver->reach_flags != 0) {
823 uint32_t flags = resolver->reach_flags;
824
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"));
830 }
831
832 if (resolver->search_order != 0) {
833 SCPrint(TRUE, stdout, CFSTR(" order : %d\n"), resolver->search_order);
834 }
835
836 return;
837 }
838
839
840 __private_extern__
841 void
842 do_showDNSConfiguration(int argc, char **argv)
843 {
844 dns_config_t *dns_config;
845 SCNetworkReachabilityRef target;
846
847 dns_config = dns_configuration_copy();
848
849 if (dns_config == NULL) {
850 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
851 exit(1);
852 }
853
854 if (argc > 1) {
855 int dns_config_index = -1;
856 SCNetworkReachabilityFlags flags = 0;
857 Boolean haveDNS = FALSE;
858 Boolean ok = FALSE;
859 dns_resolver_t *resolver;
860 uint32_t resolver_if_index;
861 SCNetworkReachabilityPrivateRef targetPrivate;
862
863 target = _setupReachability(argc, argv, NULL);
864
865 targetPrivate = (SCNetworkReachabilityPrivateRef)target;
866
867 if (targetPrivate->type != reachabilityTypeName) {
868 SCPrint(TRUE, stdout, CFSTR("\"%s\" is not a hostname.\n"), argv[0]);
869 exit(1);
870 }
871
872 ok = __SC_checkResolverReachabilityInternal(&store, &flags,
873 &haveDNS, targetPrivate->name, NULL,
874 &resolver_if_index, &dns_config_index);
875
876 if (!ok) {
877 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available.\n" ));
878 exit(1);
879 }
880
881 SCPrint(TRUE, stdout, CFSTR("DNS configuration for %s\n"),
882 targetPrivate->name);
883
884 if (targetPrivate->if_index == 0) {
885 resolver = dns_config->resolver[dns_config_index];
886 } else {
887 resolver = dns_config->scoped_resolver[dns_config_index];
888 }
889
890 showResolver(resolver, dns_config_index + 1);
891
892 if (target != NULL) CFRelease(target);
893 } else {
894 int i;
895
896 SCPrint(TRUE, stdout, CFSTR("DNS configuration\n"));
897
898 for (i = 0; i < dns_config->n_resolver; i++) {
899 dns_resolver_t *resolver = dns_config->resolver[i];
900
901 showResolver(resolver, i + 1);
902 }
903
904 if ((dns_config->n_scoped_resolver > 0) && (dns_config->scoped_resolver != NULL)) {
905 SCPrint(TRUE, stdout, CFSTR("\nDNS configuration (for scoped queries)\n"));
906
907 for (i = 0; i < dns_config->n_scoped_resolver; i++) {
908 dns_resolver_t *resolver = dns_config->scoped_resolver[i];
909
910 showResolver(resolver, i + 1);
911 }
912 }
913 }
914
915 dns_configuration_free(dns_config);
916 exit(0);
917 }
918
919
920 static void
921 showProxy(CFDictionaryRef proxy)
922 {
923 CFMutableDictionaryRef cleaned = NULL;
924
925 if (!_sc_debug) {
926 cleaned = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
927 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesSupplemental);
928 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesScoped);
929 proxy = cleaned;
930 }
931
932 SCPrint(TRUE, stdout, CFSTR("%@\n"), proxy);
933 if (cleaned != NULL) CFRelease(cleaned);
934 return;
935 }
936
937
938 __private_extern__
939 void
940 do_showProxyConfiguration(int argc, char **argv)
941 {
942 CFDictionaryRef proxies;
943
944 proxies = SCDynamicStoreCopyProxies(NULL);
945 if (proxies != NULL) {
946 CFStringRef interface = NULL;
947 CFStringRef server = NULL;
948
949 while (argc > 0) {
950 if (strcasecmp(argv[0], "interface") == 0) {
951 argv++;
952 argc--;
953
954 if (argc < 1) {
955 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
956 exit(1);
957 }
958
959 if (if_nametoindex(argv[0]) == 0) {
960 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[0]);
961 exit(1);
962 }
963
964 interface = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
965 argv++;
966 argc--;
967 } else {
968 if (server != NULL) {
969 CFRelease(server);
970 }
971
972 server = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
973 argv++;
974 argc--;
975 }
976 }
977
978 if ((server != NULL) || (interface != NULL)) {
979 CFArrayRef matching;
980
981 matching = SCNetworkProxiesCopyMatching(proxies, server, interface);
982 if (matching != NULL) {
983 CFIndex i;
984 CFIndex n;
985
986 if (server != NULL) {
987 if (interface != NULL) {
988 SCPrint(TRUE, stdout,
989 CFSTR("server = %@, interface = %@\n"),
990 server,
991 interface);
992 } else {
993 SCPrint(TRUE, stdout,
994 CFSTR("server = %@\n"),
995 server);
996 }
997 } else {
998 SCPrint(TRUE, stdout,
999 CFSTR("interface = %@\n"),
1000 interface);
1001 }
1002
1003 n = CFArrayGetCount(matching);
1004 for (i = 0; i < n; i++) {
1005 CFDictionaryRef proxy;
1006
1007 proxy = CFArrayGetValueAtIndex(matching, i);
1008 SCPrint(TRUE, stdout, CFSTR("\nproxy #%d\n"), i + 1);
1009 showProxy(proxy);
1010 }
1011
1012 CFRelease(matching);
1013 } else {
1014 SCPrint(TRUE, stdout, CFSTR("No matching proxy configurations\n"));
1015 }
1016 } else {
1017 showProxy(proxies);
1018 }
1019
1020 if (interface != NULL) CFRelease(interface);
1021 if (server != NULL) CFRelease(server);
1022 CFRelease(proxies);
1023 } else {
1024 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
1025 }
1026
1027 exit(0);
1028 }
1029
1030
1031 __private_extern__
1032 void
1033 do_snapshot(int argc, char **argv)
1034 {
1035 if (!SCDynamicStoreSnapshot(store)) {
1036 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
1037 }
1038
1039 #ifdef HAVE_REACHABILITY_SERVER
1040 (void) _SCNetworkReachabilityServer_snapshot();
1041 #endif // HAVE_REACHABILITY_SERVER
1042
1043 return;
1044 }
1045
1046
1047 static void
1048 waitKeyFound()
1049 {
1050 exit(0);
1051 }
1052
1053
1054 static void
1055 waitTimeout(int sigraised)
1056 {
1057 exit(1);
1058 }
1059
1060
1061 __private_extern__
1062 void
1063 do_wait(char *waitKey, int timeout)
1064 {
1065 struct itimerval itv;
1066 CFStringRef key;
1067 CFMutableArrayRef keys;
1068 Boolean ok;
1069
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()));
1074 exit(1);
1075 }
1076
1077 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
1078
1079 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1080 CFArrayAppendValue(keys, key);
1081 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1082 CFRelease(keys);
1083 if (!ok) {
1084 SCPrint(TRUE, stderr,
1085 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1086 exit(1);
1087 }
1088
1089 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1090 if (!notifyRls) {
1091 SCPrint(TRUE, stderr,
1092 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1093 exit(1);
1094 }
1095
1096 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
1097
1098 value = SCDynamicStoreCopyValue(store, key);
1099 if (value) {
1100 /* if the key is already present */
1101 exit(0);
1102 }
1103 CFRelease(key);
1104
1105 if (timeout > 0) {
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));
1112 exit(1);
1113 }
1114 }
1115
1116 CFRunLoopRun();
1117 }
1118
1119 #ifdef TEST_DNS_CONFIGURATION_COPY
1120
1121 CFRunLoopSourceRef notifyRls = NULL;
1122 SCDynamicStoreRef store = NULL;
1123 CFPropertyListRef value = NULL;
1124
1125 int
1126 main(int argc, char **argv)
1127 {
1128 do_showDNSConfiguration(argc, argv);
1129 exit(0);
1130 }
1131
1132 #endif // TEST_DNS_CONFIGURATION_COPY