]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/tests.c
configd-801.1.1.tar.gz
[apple/configd.git] / scutil.tproj / tests.c
1 /*
2 * Copyright (c) 2000, 2001, 2003-2015 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, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
52
53 #include <dnsinfo.h>
54 #include "dnsinfo_internal.h"
55 #include <network_information.h>
56 #include "network_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 SC_log(LOG_INFO, "notify_register_dispatch() failed for nwi changes, status=%u", 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 SC_log(LOG_INFO, "notify_register_dispatch() failed for DNS configuration changes, status=%u", 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 CFMutableDictionaryRef options = NULL;
933 CFDictionaryRef proxies;
934
935 if (getenv("BYPASS_GLOBAL_PROXY") != NULL) {
936 options = CFDictionaryCreateMutable(NULL, 0,
937 &kCFTypeDictionaryKeyCallBacks,
938 &kCFTypeDictionaryValueCallBacks);
939 CFDictionaryAddValue(options, kSCProxiesNoGlobal, kCFBooleanTrue);
940 }
941
942 proxies = SCDynamicStoreCopyProxiesWithOptions(NULL, options);
943
944 if (options != NULL) {
945 CFRelease(options);
946 }
947
948 if (proxies != NULL) {
949 CFStringRef interface = NULL;
950 CFStringRef server = NULL;
951
952 while (argc > 0) {
953 if (strcasecmp(argv[0], "interface") == 0) {
954 argv++;
955 argc--;
956
957 if (argc < 1) {
958 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
959 exit(1);
960 }
961
962 if (if_nametoindex(argv[0]) == 0) {
963 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[0]);
964 exit(1);
965 }
966
967 interface = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
968 argv++;
969 argc--;
970 } else {
971 if (server != NULL) {
972 CFRelease(server);
973 }
974
975 server = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
976 argv++;
977 argc--;
978 }
979 }
980
981 if ((server != NULL) || (interface != NULL)) {
982 CFArrayRef matching;
983
984 matching = SCNetworkProxiesCopyMatching(proxies, server, interface);
985 if (matching != NULL) {
986 CFIndex i;
987 CFIndex n;
988
989 if (server != NULL) {
990 if (interface != NULL) {
991 SCPrint(TRUE, stdout,
992 CFSTR("server = %@, interface = %@\n"),
993 server,
994 interface);
995 } else {
996 SCPrint(TRUE, stdout,
997 CFSTR("server = %@\n"),
998 server);
999 }
1000 } else {
1001 SCPrint(TRUE, stdout,
1002 CFSTR("interface = %@\n"),
1003 interface);
1004 }
1005
1006 n = CFArrayGetCount(matching);
1007 for (i = 0; i < n; i++) {
1008 CFDictionaryRef proxy;
1009
1010 proxy = CFArrayGetValueAtIndex(matching, i);
1011 SCPrint(TRUE, stdout, CFSTR("\nproxy #%ld\n"), i + 1);
1012 showProxy(proxy);
1013 }
1014
1015 CFRelease(matching);
1016 } else {
1017 SCPrint(TRUE, stdout, CFSTR("No matching proxy configurations\n"));
1018 }
1019 } else {
1020 showProxy(proxies);
1021 }
1022
1023 if (interface != NULL) CFRelease(interface);
1024 if (server != NULL) CFRelease(server);
1025 CFRelease(proxies);
1026 } else {
1027 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
1028 }
1029
1030 exit(0);
1031 }
1032
1033
1034 __private_extern__
1035 void
1036 do_snapshot(int argc, char **argv)
1037 {
1038 if (!SCDynamicStoreSnapshot(store)) {
1039 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
1040 }
1041
1042 return;
1043 }
1044
1045
1046 __private_extern__
1047 void
1048 do_renew(char *if_name)
1049 {
1050 CFArrayRef services;
1051 Boolean ok = FALSE;
1052
1053 if ((if_name == NULL) || (strlen(if_name) == 0)) {
1054 SCPrint(TRUE, stderr, CFSTR("No interface name\n"));
1055 exit(1);
1056 }
1057
1058 if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL) {
1059 CFArrayRef interfaces;
1060
1061 interfaces = SCNetworkInterfaceCopyAll();
1062 if (interfaces != NULL) {
1063 CFIndex i;
1064 CFStringRef match_name;
1065 CFIndex n;
1066
1067 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
1068 assert(match_name != NULL);
1069
1070 n = CFArrayGetCount(interfaces);
1071 for (i = 0; i < n; i++) {
1072 CFStringRef bsd_name;
1073 SCNetworkInterfaceRef interface;
1074
1075 interface = CFArrayGetValueAtIndex(interfaces, i);
1076 bsd_name = SCNetworkInterfaceGetBSDName(interface);
1077 if (_SC_CFEqual(bsd_name, match_name)) {
1078 // if match
1079 ok = SCNetworkInterfaceForceConfigurationRefresh(interface);
1080 if (!ok) {
1081 int status;
1082
1083 status = SCError();
1084 if (status != kSCStatusAccessError) {
1085 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(status));
1086 exit(1);
1087 }
1088
1089 // ... and if can't write the SCDynamicStore, try w/prefs
1090 }
1091
1092 break;
1093 }
1094 }
1095
1096 CFRelease(match_name);
1097 CFRelease(interfaces);
1098 }
1099
1100 if (ok) {
1101 exit(0);
1102 }
1103 }
1104
1105 do_prefs_init(); /* initialization */
1106 do_prefs_open(0, NULL); /* open default prefs */
1107
1108 services = SCNetworkServiceCopyAll(prefs);
1109 if (services != NULL) {
1110 CFIndex i;
1111 CFStringRef match_name;
1112 CFIndex n;
1113
1114 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
1115 assert(match_name != NULL);
1116
1117 n = CFArrayGetCount(services);
1118 for (i = 0; i < n; i++) {
1119 CFStringRef bsd_name;
1120 SCNetworkInterfaceRef interface;
1121 SCNetworkServiceRef service;
1122
1123 service = CFArrayGetValueAtIndex(services, i);
1124 interface = SCNetworkServiceGetInterface(service);
1125 if (interface == NULL) {
1126 // if no interface
1127 continue;
1128 }
1129
1130 bsd_name = SCNetworkInterfaceGetBSDName(interface);
1131 if (_SC_CFEqual(bsd_name, match_name)) {
1132 // if match
1133 ok = SCNetworkInterfaceForceConfigurationRefresh(interface);
1134 if (!ok) {
1135 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(SCError()));
1136 exit(1);
1137 }
1138
1139 break;
1140 }
1141 }
1142
1143 CFRelease(match_name);
1144 CFRelease(services);
1145 }
1146
1147 if (!ok) {
1148 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
1149 exit(1);
1150 }
1151
1152 _prefs_close();
1153 exit(0);
1154 }
1155
1156
1157 static void
1158 waitKeyFound()
1159 {
1160 exit(0);
1161 }
1162
1163
1164 static void
1165 waitTimeout(int sigraised)
1166 {
1167 exit(1);
1168 }
1169
1170
1171 __private_extern__
1172 void
1173 do_wait(char *waitKey, int timeout)
1174 {
1175 struct itimerval itv;
1176 CFStringRef key;
1177 CFMutableArrayRef keys;
1178 Boolean ok;
1179
1180 store = SCDynamicStoreCreate(NULL, CFSTR("scutil (wait)"), waitKeyFound, NULL);
1181 if (store == NULL) {
1182 SCPrint(TRUE, stderr,
1183 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1184 exit(1);
1185 }
1186
1187 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
1188
1189 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1190 CFArrayAppendValue(keys, key);
1191 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1192 CFRelease(keys);
1193 if (!ok) {
1194 SCPrint(TRUE, stderr,
1195 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1196 exit(1);
1197 }
1198
1199 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1200 if (!notifyRls) {
1201 SCPrint(TRUE, stderr,
1202 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1203 exit(1);
1204 }
1205
1206 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
1207
1208 value = SCDynamicStoreCopyValue(store, key);
1209 if (value) {
1210 /* if the key is already present */
1211 exit(0);
1212 }
1213 CFRelease(key);
1214
1215 if (timeout > 0) {
1216 signal(SIGALRM, waitTimeout);
1217 bzero(&itv, sizeof(itv));
1218 itv.it_value.tv_sec = timeout;
1219 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
1220 SCPrint(TRUE, stderr,
1221 CFSTR("setitimer() failed: %s\n"), strerror(errno));
1222 exit(1);
1223 }
1224 }
1225
1226 CFRunLoopRun();
1227 }
1228
1229 #ifdef TEST_DNS_CONFIGURATION
1230
1231 Boolean doDispatch = FALSE;
1232 CFRunLoopSourceRef notifyRls = NULL;
1233 SCDynamicStoreRef store = NULL;
1234 CFPropertyListRef value = NULL;
1235
1236 int
1237 main(int argc, char **argv)
1238 {
1239 dns_config_t *dns_config;
1240
1241 fprintf(stdout, "copy configuration\n");
1242 dns_config = dns_configuration_copy();
1243 if (dns_config != NULL) {
1244
1245 fprintf(stdout, "sleeping for 120 seconds\n");
1246 sleep(120);
1247
1248 fprintf(stdout, "sending ack\n");
1249 _dns_configuration_ack(dns_config, "TEST_DNS_CONFIGURATION");
1250
1251 fprintf(stdout, "sleeping for 120 seconds\n");
1252 sleep(120);
1253
1254 dns_configuration_free(dns_config);
1255 }
1256
1257 do_showDNSConfiguration(argc, argv);
1258 exit(0);
1259 }
1260
1261 #endif // TEST_DNS_CONFIGURATION