]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/tests.c
b80f9a101bc6d1153a00324333ec28a7168a5c59
[apple/configd.git] / scutil.tproj / tests.c
1 /*
2 * Copyright (c) 2000, 2001, 2003-2016 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 "prefs.h"
41 #include "tests.h"
42
43 #include <netdb.h>
44 #include <netdb_async.h>
45 #include <notify.h>
46 #include <sys/time.h>
47 #include <net/if.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50
51 #define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
52
53 #include <dnsinfo.h>
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>
59
60
61 static Boolean resolver_bypass;
62
63
64 static CF_RETURNS_RETAINED CFMutableDictionaryRef
65 _setupReachabilityOptions(int argc, char **argv, const char *interface)
66 {
67 int i;
68 CFMutableDictionaryRef options;
69
70 options = CFDictionaryCreateMutable(NULL,
71 0,
72 &kCFTypeDictionaryKeyCallBacks,
73 &kCFTypeDictionaryValueCallBacks);
74
75 for (i = 0; i < argc; i++) {
76 if (strcasecmp(argv[i], "interface") == 0) {
77 if (++i >= argc) {
78 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
79 CFRelease(options);
80 exit(1);
81 }
82
83 interface = argv[i];
84 continue;
85 }
86
87
88 if (strcasecmp(argv[i], "server") == 0) {
89 CFDictionarySetValue(options,
90 kSCNetworkReachabilityOptionServerBypass,
91 kCFBooleanFalse);
92 continue;
93 } else if (strcasecmp(argv[i], "no-server") == 0) {
94 CFDictionarySetValue(options,
95 kSCNetworkReachabilityOptionServerBypass,
96 kCFBooleanTrue);
97 continue;
98 }
99
100 if (strcasecmp(argv[i], "no-connection-on-demand") == 0) {
101 CFDictionarySetValue(options,
102 kSCNetworkReachabilityOptionConnectionOnDemandBypass,
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], "ptr") == 0) {
116 CFDictionarySetValue(options,
117 kSCNetworkReachabilityOptionPTRAddress,
118 kCFBooleanTrue);
119 continue;
120 }
121
122 if (strlen(argv[i]) == 0) {
123 continue;
124 }
125
126 SCPrint(TRUE, stderr, CFSTR("Unrecognized option: %s\n"), argv[i]);
127 CFRelease(options);
128 exit(1);
129 }
130
131 if (interface != NULL) {
132 CFStringRef str;
133
134 if (if_nametoindex(interface) == 0) {
135 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface);
136 exit(1);
137 }
138
139 str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII);
140 CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
141 CFRelease(str);
142 }
143
144 if (CFDictionaryGetCount(options) == 0) {
145 CFRelease(options);
146 options = NULL;
147 }
148
149 return options;
150 }
151
152
153 static SCNetworkReachabilityRef
154 _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
155 {
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;
166
167 bzero(&sin, sizeof(sin));
168 sin.sin_len = sizeof(sin);
169 sin.sin_family = AF_INET;
170
171 bzero(&sin6, sizeof(sin6));
172 sin6.sin6_len = sizeof(sin6);
173 sin6.sin6_family = AF_INET6;
174
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;
180 interface++;
181 }
182
183 if ((argc > 1) && (strlen(argv[1]) > 0)) {
184 remote_address = argv[1];
185
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;
191 remote_interface++;
192 }
193 }
194
195 if (inet_aton(ip_address, &sin.sin_addr) == 1) {
196 struct sockaddr_in r_sin;
197
198 if (argc > 1) {
199 bzero(&r_sin, sizeof(r_sin));
200 r_sin.sin_len = sizeof(r_sin);
201 r_sin.sin_family = AF_INET;
202 }
203
204 if ((argc == 1)
205 || (remote_address == NULL)
206 || (inet_aton(remote_address, &r_sin.sin_addr) == 0)) {
207 if (argc > 2) {
208 options = _setupReachabilityOptions(argc - 2, argv + 2, interface);
209 }
210 if (options == NULL) {
211 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
212 if (context != NULL) {
213 context->info = "by address";
214 }
215 } else {
216 CFDataRef data;
217
218 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
219 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
220 CFRelease(data);
221
222 if (context != NULL) {
223 if (CFDictionaryContainsKey(options,
224 kSCNetworkReachabilityOptionInterface)) {
225 if (CFDictionaryGetCount(options) == 2) {
226 context->info = "by address w/scope";
227 } else {
228 context->info = "by address w/scope and options";
229 }
230 } else {
231 context->info = "by address w/options";
232 }
233 }
234 }
235 } else {
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"),
240 interface,
241 remote_interface);
242 exit(1);
243 }
244
245 interface = remote_interface;
246 }
247
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";
255 }
256 } else {
257 CFDataRef data;
258
259 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
260 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
261 CFRelease(data);
262 data = CFDataCreate(NULL, (const UInt8 *)&r_sin, sizeof(r_sin));
263 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
264 CFRelease(data);
265
266 if (context != NULL) {
267 if (CFDictionaryContainsKey(options,
268 kSCNetworkReachabilityOptionInterface)) {
269 if (CFDictionaryGetCount(options) == 3) {
270 context->info = "by address pair w/scope";
271 } else {
272 context->info = "by address pair w/scope and options";
273 }
274 } else {
275 context->info = "by address pair w/options";
276 }
277 }
278 }
279 }
280 } else if (inet_pton(AF_INET6, ip_address, &sin6.sin6_addr) == 1) {
281 struct sockaddr_in6 r_sin6;
282
283 if (interface != NULL) {
284 sin6.sin6_scope_id = if_nametoindex(interface);
285 }
286
287 if (argc > 1) {
288 bzero(&r_sin6, sizeof(r_sin6));
289 r_sin6.sin6_len = sizeof(r_sin6);
290 r_sin6.sin6_family = AF_INET6;
291 }
292
293 if ((argc == 1)
294 || (remote_address == NULL)
295 || (inet_pton(AF_INET6, remote_address, &r_sin6.sin6_addr) == 0)) {
296 if (argc > 2) {
297 options = _setupReachabilityOptions(argc - 2, argv + 2, NULL);
298 }
299 if (options == NULL) {
300 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6);
301 if (context != NULL) {
302 context->info = "by (v6) address";
303 }
304 } else {
305 CFDataRef data;
306
307 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
308 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
309 CFRelease(data);
310
311 if (context != NULL) {
312 context->info = "by (v6) address w/options";
313 }
314 }
315 } else {
316 if (remote_interface != NULL) {
317 r_sin6.sin6_scope_id = if_nametoindex(remote_interface);
318
319 if ((interface != NULL) && (strcmp(interface, remote_interface) != 0)) {
320 SCPrint(TRUE, stderr,
321 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
322 interface,
323 remote_interface);
324 exit(1);
325 }
326 }
327
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";
335 }
336 } else {
337 CFDataRef data;
338
339 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
340 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
341 CFRelease(data);
342 data = CFDataCreate(NULL, (const UInt8 *)&r_sin6, sizeof(r_sin6));
343 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
344 CFRelease(data);
345
346 if (context != NULL) {
347 context->info = "by (v6) address pair w/options";
348 }
349 }
350 }
351 } else {
352 if (argc == 1) {
353 target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
354 if (context != NULL) {
355 context->info = "by name";
356 }
357 } else {
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";
363 }
364 } else {
365 CFStringRef str;
366
367 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
368 CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
369 CFRelease(str);
370
371 if (context != NULL) {
372 context->info = "by name w/options";
373 }
374 }
375 }
376 }
377
378 if (ip_addressN != NULL) {
379 free(ip_addressN);
380 }
381
382 if (remote_addressN != NULL) {
383 free(remote_addressN);
384 }
385
386 if ((target == NULL) && (options != NULL)) {
387 if (CFDictionaryContainsKey(options, kSCNetworkReachabilityOptionPTRAddress)) {
388 CFDataRef address;
389
390 address = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionRemoteAddress);
391 if (address == NULL) {
392 SCPrint(TRUE, stderr, CFSTR("No address\n"));
393 exit(1);
394 }
395 CFDictionarySetValue(options, kSCNetworkReachabilityOptionPTRAddress, address);
396 CFDictionaryRemoveValue(options, kSCNetworkReachabilityOptionRemoteAddress);
397
398 if (context != NULL) {
399 CFIndex n = CFDictionaryGetCount(options);
400
401 if (n == 1) {
402 context->info = "by PTR";
403 } else if (CFDictionaryContainsKey(options,
404 kSCNetworkReachabilityOptionInterface)) {
405 if (n == 2) {
406 context->info = "by PTR w/scope";
407 } else {
408 context->info = "by PTR w/scope and options";
409 }
410 } else {
411 context->info = "by PTR w/options";
412 }
413 }
414 }
415
416 target = SCNetworkReachabilityCreateWithOptions(NULL, options);
417 CFRelease(options);
418 }
419
420 return target;
421 }
422
423
424 static void
425 _printReachability(SCNetworkReachabilityRef target)
426 {
427 SCNetworkReachabilityFlags flags;
428 Boolean ok;
429 CFStringRef str;
430
431 ok = SCNetworkReachabilityGetFlags(target, &flags);
432 if (!ok) {
433 SCPrint(TRUE, stderr, CFSTR(" could not determine reachability, %s\n"), SCErrorString(SCError()));
434 return;
435 }
436
437 str = __SCNetworkReachabilityCopyFlags(flags, CFSTR("flags = "), _sc_debug);
438 SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
439 CFRelease(str);
440
441 if (resolver_bypass && _sc_debug) {
442 int if_index;
443
444 if_index = SCNetworkReachabilityGetInterfaceIndex(target);
445 SCPrint(TRUE, stdout, CFSTR("interface index = %d\n"), if_index);
446 }
447
448 return;
449 }
450
451
452 __private_extern__
453 void
454 do_checkReachability(int argc, char **argv)
455 {
456 SCNetworkReachabilityRef target;
457
458 target = _setupReachability(argc, argv, NULL);
459 if (target == NULL) {
460 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
461 exit(1);
462 }
463
464 _printReachability(target);
465 CFRelease(target);
466 exit(0);
467 }
468
469
470 static void
471 _printNWIFlags(nwi_ifstate_flags flags)
472 {
473 flags &= NWI_IFSTATE_FLAGS_MASK;
474 if (flags == 0) {
475 return;
476 }
477
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(","));
483 }
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(","));
488 }
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(","));
493 }
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(","));
498 }
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(","));
503 }
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(","));
508 }
509 if (flags != 0) {
510 SCPrint(TRUE, stdout, CFSTR("%p"), (void *)flags);
511 }
512 SCPrint(TRUE, stdout, CFSTR(")"));
513
514 return;
515 }
516
517
518 static void
519 _printNWIInfo(nwi_ifstate_t ifstate)
520 {
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;
525 CFStringRef str;
526 const struct sockaddr *vpn_addr = nwi_ifstate_get_vpn_server(ifstate);
527
528 ifstate_flags = nwi_ifstate_get_flags(ifstate);
529 if (_sc_debug) {
530 ifstate_flags |= ifstate->flags;
531 }
532
533 SCPrint(TRUE, stdout,
534 CFSTR(" %7s : flags %p"),
535 nwi_ifstate_get_ifname(ifstate),
536 (void *)ifstate_flags);
537 _printNWIFlags(ifstate_flags);
538
539 str = __SCNetworkReachabilityCopyFlags(reach_flags, CFSTR(" reach "), TRUE);
540 SCPrint(TRUE, stdout, CFSTR("\n%@"), str);
541 CFRelease(str);
542
543 if (vpn_addr != NULL) {
544 char vpn_ntopbuf[INET6_ADDRSTRLEN];
545
546 _SC_sockaddr_to_string(vpn_addr, vpn_ntopbuf, sizeof(vpn_ntopbuf));
547 SCPrint(TRUE, stdout, CFSTR("\n VPN server: %s"), vpn_ntopbuf);
548 }
549
550 signature = nwi_ifstate_get_signature(ifstate, AF_UNSPEC, &signature_length);
551 if (signature != NULL) {
552 CFDataRef digest = NULL;
553
554 digest = CFDataCreate(NULL, signature, CC_SHA1_DIGEST_LENGTH);
555 SCPrint(TRUE, stdout, CFSTR("\n Signature Hash: %@"), digest);
556 CFRelease(digest);
557 } else {
558 SCPrint(TRUE, stdout, CFSTR("\n Signature Hash: <empty>"));
559 }
560
561 SCPrint(TRUE, stdout, CFSTR("\n generation %llu\n"),
562 nwi_ifstate_get_generation(ifstate));
563
564 return;
565 }
566
567
568 static void
569 _printNWIReachInfo(nwi_state_t state, int af)
570 {
571 uint32_t reach_flags;
572 CFStringRef str;
573
574 reach_flags = nwi_state_get_reachability_flags(state, af);
575
576 str = __SCNetworkReachabilityCopyFlags(reach_flags, CFSTR(" REACH : flags "), TRUE);
577 SCPrint(TRUE, stdout, CFSTR("\n%@\n"), str);
578 CFRelease(str);
579
580 return;
581 }
582
583
584 static void
585 do_printNWI(int argc, char **argv, nwi_state_t state)
586 {
587 unsigned int count;
588 nwi_ifstate_t ifstate;
589
590 if (state == NULL) {
591 SCPrint(TRUE, stdout, CFSTR("No network information\n"));
592 return;
593 }
594
595 if (argc > 0) {
596 ifstate = nwi_state_get_ifstate(state, argv[0]);
597 if (ifstate != NULL) {
598 nwi_ifstate_t alias;
599
600 _printNWIInfo(ifstate);
601
602 alias = nwi_ifstate_get_alias(ifstate,
603 ifstate->af == AF_INET ? AF_INET6 : AF_INET);
604 if (alias != NULL) {
605 SCPrint(TRUE, stdout, CFSTR("\n"));
606 _printNWIInfo(alias);
607 }
608 } else {
609 SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]);
610 }
611 return;
612 }
613
614 SCPrint(TRUE, stdout, CFSTR("Network information (generation %llu)"),
615 nwi_state_get_generation(state));
616
617 SCPrint(TRUE, stdout, CFSTR("\nIPv4 network interface information\n"));
618
619 ifstate = nwi_state_get_first_ifstate(state, AF_INET);
620 if (ifstate == NULL) {
621 SCPrint(TRUE, stdout, CFSTR(" No IPv4 states found\n"));
622 } else {
623 while (ifstate != NULL) {
624 _printNWIInfo(ifstate);
625 ifstate = nwi_ifstate_get_next(ifstate, AF_INET);
626 }
627 }
628 _printNWIReachInfo(state, AF_INET);
629
630 SCPrint(TRUE, stdout, CFSTR("\nIPv6 network interface information\n"));
631
632 ifstate = nwi_state_get_first_ifstate(state, AF_INET6);
633 if (ifstate == NULL) {
634 SCPrint(TRUE, stdout, CFSTR(" No IPv6 states found\n"));
635 } else {
636 while (ifstate != NULL) {
637 _printNWIInfo(ifstate);
638 ifstate = nwi_ifstate_get_next(ifstate, AF_INET6);
639 }
640 }
641 _printNWIReachInfo(state, AF_INET6);
642
643 count = nwi_state_get_interface_names(state, NULL, 0);
644 if (count > 0) {
645 const char * names[count];
646
647 count = nwi_state_get_interface_names(state, names, count);
648 if (count > 0) {
649 int i;
650
651 printf("\nNetwork interfaces:");
652 for (i = 0; i < count; i++) {
653 printf(" %s", names[i]);
654 }
655 printf("\n");
656 }
657 }
658 return;
659 }
660
661
662 __private_extern__
663 void
664 do_showNWI(int argc, char **argv)
665 {
666 nwi_state_t state;
667
668 state = nwi_state_copy();
669 do_printNWI(argc, argv, state);
670 if (state != NULL) {
671 nwi_state_release(state);
672 } else {
673 exit(1);
674 }
675
676 exit(0);
677 }
678
679
680 __private_extern__
681 void
682 do_watchNWI(int argc, char **argv)
683 {
684 nwi_state_t state;
685 int status;
686 int token;
687
688 state = nwi_state_copy();
689 do_printNWI(argc, argv, state);
690 if (state != NULL) {
691 nwi_state_release(state);
692 }
693
694 status = notify_register_dispatch(nwi_state_get_notify_key(),
695 &token,
696 dispatch_get_main_queue(),
697 ^(int token){
698 nwi_state_t state;
699 struct tm tm_now;
700 struct timeval tv_now;
701
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"),
705 tm_now.tm_hour,
706 tm_now.tm_min,
707 tm_now.tm_sec,
708 tv_now.tv_usec / 1000);
709
710 state = nwi_state_copy();
711 do_printNWI(argc, argv, state);
712 if (state != NULL) {
713 nwi_state_release(state);
714 }
715 });
716 if (status != NOTIFY_STATUS_OK) {
717 SCPrint(TRUE, stderr, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), status);
718 exit(1);
719 }
720
721 CFRunLoopRun();
722 exit(0);
723 }
724
725
726 static void
727 callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
728 {
729 static int n = 3;
730 struct tm tm_now;
731 struct timeval tv_now;
732
733 (void)gettimeofday(&tv_now, NULL);
734 (void)localtime_r(&tv_now.tv_sec, &tm_now);
735
736 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
737 tm_now.tm_hour,
738 tm_now.tm_min,
739 tm_now.tm_sec,
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"));
745 return;
746 }
747
748
749 __private_extern__
750 void
751 do_watchReachability(int argc, char **argv)
752 {
753 SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
754 SCNetworkReachabilityRef target;
755 SCNetworkReachabilityRef target_async;
756
757 target = _setupReachability(argc, argv, NULL);
758 if (target == NULL) {
759 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
760 exit(1);
761 }
762
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()));
766 exit(1);
767 }
768
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.
772 //
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);
778 }
779
780 // Direct check of reachability
781 SCPrint(TRUE, stdout, CFSTR(" 0: direct\n"));
782 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
783 _printReachability(target);
784 CFRelease(target);
785 SCPrint(TRUE, stdout, CFSTR("\n"));
786
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"));
792
793 if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) {
794 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
795 exit(1);
796 }
797
798 if (doDispatch) {
799 if (!SCNetworkReachabilitySetDispatchQueue(target_async, dispatch_get_main_queue())) {
800 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
801 exit(1);
802 }
803 } else {
804 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
805 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
806 exit(1);
807 }
808 }
809
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"));
816
817 CFRunLoopRun();
818 exit(0);
819 }
820
821
822 static void
823 do_printDNSConfiguration(int argc, char **argv, dns_config_t *dns_config)
824 {
825 int _sc_log_save;
826
827 if (dns_config == NULL) {
828 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
829 return;
830 }
831
832 _sc_log_save = _sc_log;
833 _sc_log = FALSE;
834 _dns_configuration_log(dns_config, _sc_debug);
835 _sc_log = _sc_log_save;
836
837 if (_sc_debug) {
838 SCPrint(TRUE, stdout, CFSTR("\ngeneration = %llu\n"), dns_config->generation);
839 }
840
841 return;
842 }
843
844
845 __private_extern__
846 void
847 do_showDNSConfiguration(int argc, char **argv)
848 {
849 dns_config_t *dns_config;
850
851 dns_config = dns_configuration_copy();
852 do_printDNSConfiguration(argc, argv, dns_config);
853 if (dns_config != NULL) {
854 dns_configuration_free(dns_config);
855 } else {
856 exit(1);
857 }
858
859 exit(0);
860 }
861
862
863 __private_extern__
864 void
865 do_watchDNSConfiguration(int argc, char **argv)
866 {
867 dns_config_t *dns_config;
868 int status;
869 int token;
870
871 dns_config = dns_configuration_copy();
872 do_printDNSConfiguration(argc, argv, dns_config);
873 if (dns_config != NULL) {
874 dns_configuration_free(dns_config);
875 }
876
877 status = notify_register_dispatch(dns_configuration_notify_key(),
878 &token,
879 dispatch_get_main_queue(),
880 ^(int token){
881 dns_config_t *dns_config;
882 struct tm tm_now;
883 struct timeval tv_now;
884
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"),
888 tm_now.tm_hour,
889 tm_now.tm_min,
890 tm_now.tm_sec,
891 tv_now.tv_usec / 1000);
892
893 dns_config = dns_configuration_copy();
894 do_printDNSConfiguration(argc, argv, dns_config);
895 if (dns_config != NULL) {
896 dns_configuration_free(dns_config);
897 }
898 });
899 if (status != NOTIFY_STATUS_OK) {
900 SCPrint(TRUE, stderr, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), status);
901 exit(1);
902 }
903
904 CFRunLoopRun();
905 exit(0);
906 }
907
908
909 static void
910 showProxy(CFDictionaryRef proxy)
911 {
912 CFMutableDictionaryRef cleaned = NULL;
913
914 if (!_sc_debug) {
915 cleaned = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
916 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesScoped);
917 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesServices);
918 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesSupplemental);
919 proxy = cleaned;
920 }
921
922 SCPrint(TRUE, stdout, CFSTR("%@\n"), proxy);
923 if (cleaned != NULL) CFRelease(cleaned);
924 return;
925 }
926
927
928 __private_extern__
929 void
930 do_showProxyConfiguration(int argc, char **argv)
931 {
932 CFDictionaryRef proxies;
933
934 if (getenv("BYPASS_GLOBAL_PROXY") != NULL) {
935 CFMutableDictionaryRef options ;
936
937 options = CFDictionaryCreateMutable(NULL, 0,
938 &kCFTypeDictionaryKeyCallBacks,
939 &kCFTypeDictionaryValueCallBacks);
940 CFDictionaryAddValue(options, kSCProxiesNoGlobal, kCFBooleanTrue);
941 proxies = SCDynamicStoreCopyProxiesWithOptions(NULL, options);
942 CFRelease(options);
943 } else {
944 proxies = SCDynamicStoreCopyProxies(NULL);
945 }
946
947 if (proxies != NULL) {
948 CFStringRef interface = NULL;
949 CFStringRef server = NULL;
950
951 while (argc > 0) {
952 if (strcasecmp(argv[0], "interface") == 0) {
953 argv++;
954 argc--;
955
956 if (argc < 1) {
957 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
958 exit(1);
959 }
960
961 if (if_nametoindex(argv[0]) == 0) {
962 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[0]);
963 exit(1);
964 }
965
966 interface = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
967 argv++;
968 argc--;
969 } else {
970 if (server != NULL) {
971 CFRelease(server);
972 }
973
974 server = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
975 argv++;
976 argc--;
977 }
978 }
979
980 if ((server != NULL) || (interface != NULL)) {
981 CFArrayRef matching;
982
983 matching = SCNetworkProxiesCopyMatching(proxies, server, interface);
984 if (matching != NULL) {
985 CFIndex i;
986 CFIndex n;
987
988 if (server != NULL) {
989 if (interface != NULL) {
990 SCPrint(TRUE, stdout,
991 CFSTR("server = %@, interface = %@\n"),
992 server,
993 interface);
994 } else {
995 SCPrint(TRUE, stdout,
996 CFSTR("server = %@\n"),
997 server);
998 }
999 } else {
1000 SCPrint(TRUE, stdout,
1001 CFSTR("interface = %@\n"),
1002 interface);
1003 }
1004
1005 n = CFArrayGetCount(matching);
1006 for (i = 0; i < n; i++) {
1007 CFDictionaryRef proxy;
1008
1009 proxy = CFArrayGetValueAtIndex(matching, i);
1010 SCPrint(TRUE, stdout, CFSTR("\nproxy #%ld\n"), i + 1);
1011 showProxy(proxy);
1012 }
1013
1014 CFRelease(matching);
1015 } else {
1016 SCPrint(TRUE, stdout, CFSTR("No matching proxy configurations\n"));
1017 }
1018 } else {
1019 showProxy(proxies);
1020 }
1021
1022 if (interface != NULL) CFRelease(interface);
1023 if (server != NULL) CFRelease(server);
1024 CFRelease(proxies);
1025 } else {
1026 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
1027 }
1028
1029 exit(0);
1030 }
1031
1032
1033 __private_extern__
1034 void
1035 do_snapshot(int argc, char **argv)
1036 {
1037 if (!SCDynamicStoreSnapshot(store)) {
1038 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
1039 }
1040
1041 return;
1042 }
1043
1044
1045 __private_extern__
1046 void
1047 do_renew(char *if_name)
1048 {
1049 CFArrayRef services;
1050 Boolean ok = FALSE;
1051
1052 if ((if_name == NULL) || (strlen(if_name) == 0)) {
1053 SCPrint(TRUE, stderr, CFSTR("No interface name\n"));
1054 exit(1);
1055 }
1056
1057 if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL) {
1058 CFArrayRef interfaces;
1059
1060 interfaces = SCNetworkInterfaceCopyAll();
1061 if (interfaces != NULL) {
1062 CFIndex i;
1063 CFStringRef match_name;
1064 CFIndex n;
1065
1066 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
1067 assert(match_name != NULL);
1068
1069 n = CFArrayGetCount(interfaces);
1070 for (i = 0; i < n; i++) {
1071 CFStringRef bsd_name;
1072 SCNetworkInterfaceRef interface;
1073
1074 interface = CFArrayGetValueAtIndex(interfaces, i);
1075 bsd_name = SCNetworkInterfaceGetBSDName(interface);
1076 if (_SC_CFEqual(bsd_name, match_name)) {
1077 // if match
1078 ok = SCNetworkInterfaceForceConfigurationRefresh(interface);
1079 if (!ok) {
1080 int status;
1081
1082 status = SCError();
1083 if (status != kSCStatusAccessError) {
1084 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(status));
1085 exit(1);
1086 }
1087
1088 // ... and if can't write the SCDynamicStore, try w/prefs
1089 }
1090
1091 break;
1092 }
1093 }
1094
1095 CFRelease(match_name);
1096 CFRelease(interfaces);
1097 }
1098
1099 if (ok) {
1100 exit(0);
1101 }
1102 }
1103
1104 do_prefs_init(); /* initialization */
1105 do_prefs_open(0, NULL); /* open default prefs */
1106
1107 services = SCNetworkServiceCopyAll(prefs);
1108 if (services != NULL) {
1109 CFIndex i;
1110 CFStringRef match_name;
1111 CFIndex n;
1112
1113 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
1114 assert(match_name != NULL);
1115
1116 n = CFArrayGetCount(services);
1117 for (i = 0; i < n; i++) {
1118 CFStringRef bsd_name;
1119 SCNetworkInterfaceRef interface;
1120 SCNetworkServiceRef service;
1121
1122 service = CFArrayGetValueAtIndex(services, i);
1123 interface = SCNetworkServiceGetInterface(service);
1124 if (interface == NULL) {
1125 // if no interface
1126 continue;
1127 }
1128
1129 bsd_name = SCNetworkInterfaceGetBSDName(interface);
1130 if (_SC_CFEqual(bsd_name, match_name)) {
1131 // if match
1132 ok = SCNetworkInterfaceForceConfigurationRefresh(interface);
1133 if (!ok) {
1134 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(SCError()));
1135 exit(1);
1136 }
1137
1138 break;
1139 }
1140 }
1141
1142 CFRelease(match_name);
1143 CFRelease(services);
1144 }
1145
1146 if (!ok) {
1147 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
1148 exit(1);
1149 }
1150
1151 _prefs_close();
1152 exit(0);
1153 }
1154
1155
1156 static void
1157 waitKeyFound()
1158 {
1159 exit(0);
1160 }
1161
1162
1163 static void
1164 waitTimeout(int sigraised)
1165 {
1166 exit(1);
1167 }
1168
1169
1170 __private_extern__
1171 void
1172 do_wait(char *waitKey, int timeout)
1173 {
1174 struct itimerval itv;
1175 CFStringRef key;
1176 CFMutableArrayRef keys;
1177 Boolean ok;
1178
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()));
1183 exit(1);
1184 }
1185
1186 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
1187
1188 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1189 CFArrayAppendValue(keys, key);
1190 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1191 CFRelease(keys);
1192 if (!ok) {
1193 SCPrint(TRUE, stderr,
1194 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1195 exit(1);
1196 }
1197
1198 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1199 if (!notifyRls) {
1200 SCPrint(TRUE, stderr,
1201 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1202 exit(1);
1203 }
1204
1205 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
1206
1207 value = SCDynamicStoreCopyValue(store, key);
1208 if (value) {
1209 /* if the key is already present */
1210 exit(0);
1211 }
1212 CFRelease(key);
1213
1214 if (timeout > 0) {
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));
1221 exit(1);
1222 }
1223 }
1224
1225 CFRunLoopRun();
1226 }
1227
1228 #ifdef TEST_DNS_CONFIGURATION
1229
1230 Boolean doDispatch = FALSE;
1231 CFRunLoopSourceRef notifyRls = NULL;
1232 SCDynamicStoreRef store = NULL;
1233 CFPropertyListRef value = NULL;
1234
1235 int
1236 main(int argc, char **argv)
1237 {
1238 dns_config_t *dns_config;
1239
1240 fprintf(stdout, "copy configuration\n");
1241 dns_config = dns_configuration_copy();
1242 if (dns_config != NULL) {
1243
1244 fprintf(stdout, "sleeping for 120 seconds\n");
1245 sleep(120);
1246
1247 fprintf(stdout, "sending ack\n");
1248 _dns_configuration_ack(dns_config, "TEST_DNS_CONFIGURATION");
1249
1250 fprintf(stdout, "sleeping for 120 seconds\n");
1251 sleep(120);
1252
1253 dns_configuration_free(dns_config);
1254 }
1255
1256 do_showDNSConfiguration(argc, argv);
1257 exit(0);
1258 }
1259
1260 #endif // TEST_DNS_CONFIGURATION