]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/tests.c
configd-1061.0.2.tar.gz
[apple/configd.git] / scutil.tproj / tests.c
1 /*
2 * Copyright (c) 2000, 2001, 2003-2018 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 "dnsinfo_logging.h"
56
57 #include <network_information.h>
58 #include "network_state_information_logging.h"
59 #include "network_state_information_priv.h"
60
61 #include "SCNetworkReachabilityInternal.h"
62
63 #include <CommonCrypto/CommonDigest.h>
64
65
66 static Boolean resolver_bypass;
67
68
69 static CF_RETURNS_RETAINED CFMutableDictionaryRef
70 _setupReachabilityOptions(int argc, char **argv, const char *interface)
71 {
72 int i;
73 CFMutableDictionaryRef options;
74
75 options = CFDictionaryCreateMutable(NULL,
76 0,
77 &kCFTypeDictionaryKeyCallBacks,
78 &kCFTypeDictionaryValueCallBacks);
79
80 for (i = 0; i < argc; i++) {
81 if (strcasecmp(argv[i], "interface") == 0) {
82 if (++i >= argc) {
83 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
84 CFRelease(options);
85 exit(1);
86 }
87
88 interface = argv[i];
89 continue;
90 }
91
92
93 if (strcasecmp(argv[i], "server") == 0) {
94 CFDictionarySetValue(options,
95 kSCNetworkReachabilityOptionServerBypass,
96 kCFBooleanFalse);
97 continue;
98 } else if (strcasecmp(argv[i], "no-server") == 0) {
99 CFDictionarySetValue(options,
100 kSCNetworkReachabilityOptionServerBypass,
101 kCFBooleanTrue);
102 continue;
103 }
104
105 if (strcasecmp(argv[i], "no-connection-on-demand") == 0) {
106 CFDictionarySetValue(options,
107 kSCNetworkReachabilityOptionConnectionOnDemandBypass,
108 kCFBooleanTrue);
109 continue;
110 }
111
112 if (strcasecmp(argv[i], "no-resolve") == 0) {
113 CFDictionarySetValue(options,
114 kSCNetworkReachabilityOptionResolverBypass,
115 kCFBooleanTrue);
116 resolver_bypass = TRUE;
117 continue;
118 }
119
120 if (strcasecmp(argv[i], "ptr") == 0) {
121 CFDictionarySetValue(options,
122 kSCNetworkReachabilityOptionPTRAddress,
123 kCFBooleanTrue);
124 continue;
125 }
126
127 if (strlen(argv[i]) == 0) {
128 continue;
129 }
130
131 SCPrint(TRUE, stderr, CFSTR("Unrecognized option: %s\n"), argv[i]);
132 CFRelease(options);
133 exit(1);
134 }
135
136 if (interface != NULL) {
137 CFStringRef str;
138
139 if (if_nametoindex(interface) == 0) {
140 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface);
141 exit(1);
142 }
143
144 str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII);
145 CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
146 CFRelease(str);
147 }
148
149 if (CFDictionaryGetCount(options) == 0) {
150 CFRelease(options);
151 options = NULL;
152 }
153
154 return options;
155 }
156
157
158 static SCNetworkReachabilityRef
159 _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
160 {
161 const char *ip_address = argv[0];
162 char *ip_addressN = NULL;
163 const char *interface;
164 CFMutableDictionaryRef options = NULL;
165 const char *remote_address = NULL;
166 char *remote_addressN= NULL;
167 const char *remote_interface;
168 struct sockaddr_in sin;
169 struct sockaddr_in6 sin6;
170 SCNetworkReachabilityRef target = NULL;
171
172 memset(&sin, 0, sizeof(sin));
173 sin.sin_len = sizeof(sin);
174 sin.sin_family = AF_INET;
175
176 memset(&sin6, 0, sizeof(sin6));
177 sin6.sin6_len = sizeof(sin6);
178 sin6.sin6_family = AF_INET6;
179
180 interface = strchr(ip_address, '%');
181 if (interface != NULL) {
182 ip_addressN = strdup(ip_address);
183 ip_addressN[interface - ip_address] = '\0';
184 ip_address = ip_addressN;
185 interface++;
186 }
187
188 if ((argc > 1) && (strlen(argv[1]) > 0)) {
189 remote_address = argv[1];
190
191 remote_interface = strchr(remote_address, '%');
192 if (remote_interface != NULL) {
193 remote_addressN = strdup(remote_address);
194 remote_addressN[remote_interface - remote_address] = '\0';
195 remote_address = remote_addressN;
196 remote_interface++;
197 }
198 }
199
200 if (inet_aton(ip_address, &sin.sin_addr) == 1) {
201 struct sockaddr_in r_sin;
202
203 if (argc > 1) {
204 memset(&r_sin, 0, sizeof(r_sin));
205 r_sin.sin_len = sizeof(r_sin);
206 r_sin.sin_family = AF_INET;
207 }
208
209 if ((argc == 1)
210 || (remote_address == NULL)
211 || (inet_aton(remote_address, &r_sin.sin_addr) == 0)) {
212 if (argc > 2) {
213 options = _setupReachabilityOptions(argc - 2, argv + 2, interface);
214 }
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 if (remote_interface != NULL) {
242 if ((interface != NULL) && (strcmp(interface, remote_interface) != 0)) {
243 SCPrint(TRUE, stderr,
244 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
245 interface,
246 remote_interface);
247 exit(1);
248 }
249
250 interface = remote_interface;
251 }
252
253 options = _setupReachabilityOptions(argc - 2, argv + 2, interface);
254 if (options == NULL) {
255 target = SCNetworkReachabilityCreateWithAddressPair(NULL,
256 (struct sockaddr *)&sin,
257 (struct sockaddr *)&r_sin);
258 if (context != NULL) {
259 context->info = "by address pair";
260 }
261 } else {
262 CFDataRef data;
263
264 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
265 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
266 CFRelease(data);
267 data = CFDataCreate(NULL, (const UInt8 *)&r_sin, sizeof(r_sin));
268 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
269 CFRelease(data);
270
271 if (context != NULL) {
272 if (CFDictionaryContainsKey(options,
273 kSCNetworkReachabilityOptionInterface)) {
274 if (CFDictionaryGetCount(options) == 3) {
275 context->info = "by address pair w/scope";
276 } else {
277 context->info = "by address pair w/scope and options";
278 }
279 } else {
280 context->info = "by address pair w/options";
281 }
282 }
283 }
284 }
285 } else if (inet_pton(AF_INET6, ip_address, &sin6.sin6_addr) == 1) {
286 struct sockaddr_in6 r_sin6;
287
288 if (interface != NULL) {
289 sin6.sin6_scope_id = if_nametoindex(interface);
290 }
291
292 if (argc > 1) {
293 memset(&r_sin6, 0, sizeof(r_sin6));
294 r_sin6.sin6_len = sizeof(r_sin6);
295 r_sin6.sin6_family = AF_INET6;
296 }
297
298 if ((argc == 1)
299 || (remote_address == NULL)
300 || (inet_pton(AF_INET6, remote_address, &r_sin6.sin6_addr) == 0)) {
301 if (argc > 2) {
302 options = _setupReachabilityOptions(argc - 2, argv + 2, NULL);
303 }
304 if (options == NULL) {
305 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6);
306 if (context != NULL) {
307 context->info = "by (v6) address";
308 }
309 } else {
310 CFDataRef data;
311
312 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
313 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
314 CFRelease(data);
315
316 if (context != NULL) {
317 context->info = "by (v6) address w/options";
318 }
319 }
320 } else {
321 if (remote_interface != NULL) {
322 r_sin6.sin6_scope_id = if_nametoindex(remote_interface);
323
324 if ((interface != NULL) && (strcmp(interface, remote_interface) != 0)) {
325 SCPrint(TRUE, stderr,
326 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
327 interface,
328 remote_interface);
329 exit(1);
330 }
331 }
332
333 options = _setupReachabilityOptions(argc - 2, argv + 2, NULL);
334 if (options == NULL) {
335 target = SCNetworkReachabilityCreateWithAddressPair(NULL,
336 (struct sockaddr *)&sin6,
337 (struct sockaddr *)&r_sin6);
338 if (context != NULL) {
339 context->info = "by (v6) address pair";
340 }
341 } else {
342 CFDataRef data;
343
344 data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
345 CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
346 CFRelease(data);
347 data = CFDataCreate(NULL, (const UInt8 *)&r_sin6, sizeof(r_sin6));
348 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
349 CFRelease(data);
350
351 if (context != NULL) {
352 context->info = "by (v6) address pair w/options";
353 }
354 }
355 }
356 } else {
357 if (argc == 1) {
358 target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
359 if (context != NULL) {
360 context->info = "by name";
361 }
362 } else {
363 options = _setupReachabilityOptions(argc - 1, argv + 1, NULL);
364 if (options == NULL) {
365 target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
366 if (context != NULL) {
367 context->info = "by name";
368 }
369 } else {
370 CFStringRef str;
371
372 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
373 CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
374 CFRelease(str);
375
376 if (context != NULL) {
377 context->info = "by name w/options";
378 }
379 }
380 }
381 }
382
383 if (ip_addressN != NULL) {
384 free(ip_addressN);
385 }
386
387 if (remote_addressN != NULL) {
388 free(remote_addressN);
389 }
390
391 if ((target == NULL) && (options != NULL)) {
392 if (CFDictionaryContainsKey(options, kSCNetworkReachabilityOptionPTRAddress)) {
393 CFDataRef address;
394
395 address = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionRemoteAddress);
396 if (address == NULL) {
397 SCPrint(TRUE, stderr, CFSTR("No address\n"));
398 exit(1);
399 }
400 CFDictionarySetValue(options, kSCNetworkReachabilityOptionPTRAddress, address);
401 CFDictionaryRemoveValue(options, kSCNetworkReachabilityOptionRemoteAddress);
402
403 if (context != NULL) {
404 CFIndex n = CFDictionaryGetCount(options);
405
406 if (n == 1) {
407 context->info = "by PTR";
408 } else if (CFDictionaryContainsKey(options,
409 kSCNetworkReachabilityOptionInterface)) {
410 if (n == 2) {
411 context->info = "by PTR w/scope";
412 } else {
413 context->info = "by PTR w/scope and options";
414 }
415 } else {
416 context->info = "by PTR w/options";
417 }
418 }
419 }
420
421 target = SCNetworkReachabilityCreateWithOptions(NULL, options);
422 CFRelease(options);
423 }
424
425 return target;
426 }
427
428
429 static void
430 _printReachability(SCNetworkReachabilityRef target)
431 {
432 SCNetworkReachabilityFlags flags;
433 char flags_str[100];
434 Boolean ok;
435
436 ok = SCNetworkReachabilityGetFlags(target, &flags);
437 if (!ok) {
438 SCPrint(TRUE, stderr, CFSTR(" could not determine reachability, %s\n"), SCErrorString(SCError()));
439 return;
440 }
441
442 __SCNetworkReachability_flags_string(flags, _sc_debug, flags_str, sizeof(flags_str));
443 SCPrint(TRUE, stdout,
444 _sc_debug ? CFSTR("flags = %s\n") : CFSTR("%s\n"),
445 flags_str);
446
447 if (resolver_bypass && _sc_debug) {
448 int if_index;
449
450 if_index = SCNetworkReachabilityGetInterfaceIndex(target);
451 SCPrint(TRUE, stdout, CFSTR("interface index = %d\n"), if_index);
452 }
453
454 return;
455 }
456
457
458 __private_extern__
459 void
460 do_checkReachability(int argc, char **argv)
461 {
462 SCNetworkReachabilityRef target;
463
464 target = _setupReachability(argc, argv, NULL);
465 if (target == NULL) {
466 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
467 exit(1);
468 }
469
470 _printReachability(target);
471 CFRelease(target);
472 exit(0);
473 }
474
475
476 static void
477 do_printNWI(int argc, char **argv, nwi_state_t state)
478 {
479 if (state == NULL) {
480 SCPrint(TRUE, stdout, CFSTR("No network information\n"));
481 return;
482 }
483
484 if (argc > 0) {
485 nwi_ifstate_t ifstate;
486
487 ifstate = nwi_state_get_ifstate(state, argv[0]);
488 if (ifstate != NULL) {
489 nwi_ifstate_t alias;
490 int alias_af;
491
492 _nwi_ifstate_log(ifstate, _sc_debug, NULL);
493
494 alias_af = (ifstate->af == AF_INET) ? AF_INET6 : AF_INET;
495 alias = nwi_ifstate_get_alias(ifstate, alias_af);
496 if (alias != NULL) {
497 SCPrint(TRUE, stdout, CFSTR("\n"));
498 _nwi_ifstate_log(alias, _sc_debug, NULL);
499 }
500 } else {
501 SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]);
502 }
503 return;
504 }
505
506 _nwi_state_log(state, _sc_debug, NULL);
507 return;
508 }
509
510
511 __private_extern__
512 void
513 do_showNWI(int argc, char **argv)
514 {
515 nwi_state_t state;
516
517 state = nwi_state_copy();
518 do_printNWI(argc, argv, state);
519 if (state != NULL) {
520 nwi_state_release(state);
521 } else {
522 exit(1);
523 }
524
525 exit(0);
526 }
527
528
529 __private_extern__
530 void
531 do_watchNWI(int argc, char **argv)
532 {
533 nwi_state_t state;
534 int status;
535 int token;
536
537 state = nwi_state_copy();
538 do_printNWI(argc, argv, state);
539 if (state != NULL) {
540 nwi_state_release(state);
541 }
542
543 status = notify_register_dispatch(nwi_state_get_notify_key(),
544 &token,
545 dispatch_get_main_queue(),
546 ^(int token){
547 #pragma unused(token)
548 nwi_state_t state;
549 struct tm tm_now;
550 struct timeval tv_now;
551
552 (void)gettimeofday(&tv_now, NULL);
553 (void)localtime_r(&tv_now.tv_sec, &tm_now);
554 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
555 tm_now.tm_hour,
556 tm_now.tm_min,
557 tm_now.tm_sec,
558 tv_now.tv_usec / 1000);
559
560 state = nwi_state_copy();
561 do_printNWI(argc, argv, state);
562 if (state != NULL) {
563 nwi_state_release(state);
564 }
565 });
566 if (status != NOTIFY_STATUS_OK) {
567 SCPrint(TRUE, stderr, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), status);
568 exit(1);
569 }
570
571 CFRunLoopRun();
572 exit(0);
573 }
574
575
576 static void
577 callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
578 {
579 static int n = 3;
580 struct tm tm_now;
581 struct timeval tv_now;
582
583 (void)gettimeofday(&tv_now, NULL);
584 (void)localtime_r(&tv_now.tv_sec, &tm_now);
585
586 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
587 tm_now.tm_hour,
588 tm_now.tm_min,
589 tm_now.tm_sec,
590 tv_now.tv_usec / 1000);
591 SCPrint(TRUE, stdout, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n++, flags, (char *)info);
592 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
593 _printReachability(target);
594 SCPrint(TRUE, stdout, CFSTR("\n"));
595 return;
596 }
597
598
599 __private_extern__
600 void
601 do_watchReachability(int argc, char **argv)
602 {
603 SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
604 SCNetworkReachabilityRef target;
605 SCNetworkReachabilityRef target_async;
606
607 target = _setupReachability(argc, argv, NULL);
608 if (target == NULL) {
609 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
610 exit(1);
611 }
612
613 target_async = _setupReachability(argc, argv, &context);
614 if (target_async == NULL) {
615 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
616 exit(1);
617 }
618
619 // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags()
620 // until after the "target" has been scheduled on a run loop. Otherwise, we'll
621 // end up making a synchronous DNS request and that's not what we want.
622 //
623 // To test the case were an application first calls SCNetworkReachabilityGetFlags()
624 // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable.
625 if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL) {
626 CFRelease(target_async);
627 target_async = CFRetain(target);
628 }
629
630 // Direct check of reachability
631 SCPrint(TRUE, stdout, CFSTR(" 0: direct\n"));
632 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
633 _printReachability(target);
634 CFRelease(target);
635 SCPrint(TRUE, stdout, CFSTR("\n"));
636
637 // schedule the target
638 SCPrint(TRUE, stdout, CFSTR(" 1: start\n"));
639 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
640 // _printReachability(target_async);
641 SCPrint(TRUE, stdout, CFSTR("\n"));
642
643 if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) {
644 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
645 exit(1);
646 }
647
648 if (doDispatch) {
649 if (!SCNetworkReachabilitySetDispatchQueue(target_async, dispatch_get_main_queue())) {
650 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
651 exit(1);
652 }
653 } else {
654 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
655 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
656 exit(1);
657 }
658 }
659
660 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags()
661 // to get the current status. For "names", a DNS lookup has already been initiated.
662 SCPrint(TRUE, stdout, CFSTR(" 2: on %s\n"), doDispatch ? "dispatch queue" : "runloop");
663 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
664 _printReachability(target_async);
665 SCPrint(TRUE, stdout, CFSTR("\n"));
666
667 CFRunLoopRun();
668 exit(0);
669 }
670
671
672 static void
673 do_printDNSConfiguration(int argc, char **argv, dns_config_t *dns_config)
674 {
675 #pragma unused(argc)
676 #pragma unused(argv)
677 int _sc_log_save;
678
679 if (dns_config == NULL) {
680 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
681 return;
682 }
683
684 _sc_log_save = _sc_log;
685 _sc_log = FALSE;
686 _dns_configuration_log(dns_config, _sc_debug, NULL);
687 _sc_log = _sc_log_save;
688
689 if (_sc_debug) {
690 SCPrint(TRUE, stdout, CFSTR("\ngeneration = %llu\n"), dns_config->generation);
691 }
692
693 return;
694 }
695
696
697 __private_extern__
698 void
699 do_showDNSConfiguration(int argc, char **argv)
700 {
701 dns_config_t *dns_config;
702
703 dns_config = dns_configuration_copy();
704 do_printDNSConfiguration(argc, argv, dns_config);
705 if (dns_config != NULL) {
706 dns_configuration_free(dns_config);
707 } else {
708 exit(1);
709 }
710
711 exit(0);
712 }
713
714
715 __private_extern__
716 void
717 do_watchDNSConfiguration(int argc, char **argv)
718 {
719 dns_config_t *dns_config;
720 int status;
721 int token;
722
723 dns_config = dns_configuration_copy();
724 do_printDNSConfiguration(argc, argv, dns_config);
725 if (dns_config != NULL) {
726 dns_configuration_free(dns_config);
727 }
728
729 status = notify_register_dispatch(dns_configuration_notify_key(),
730 &token,
731 dispatch_get_main_queue(),
732 ^(int token){
733 #pragma unused(token)
734 dns_config_t *dns_config;
735 struct tm tm_now;
736 struct timeval tv_now;
737
738 (void)gettimeofday(&tv_now, NULL);
739 (void)localtime_r(&tv_now.tv_sec, &tm_now);
740 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
741 tm_now.tm_hour,
742 tm_now.tm_min,
743 tm_now.tm_sec,
744 tv_now.tv_usec / 1000);
745
746 dns_config = dns_configuration_copy();
747 do_printDNSConfiguration(argc, argv, dns_config);
748 if (dns_config != NULL) {
749 dns_configuration_free(dns_config);
750 }
751 });
752 if (status != NOTIFY_STATUS_OK) {
753 SCPrint(TRUE, stderr, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), status);
754 exit(1);
755 }
756
757 CFRunLoopRun();
758 exit(0);
759 }
760
761
762 static void
763 showProxy(CFDictionaryRef proxy)
764 {
765 CFMutableDictionaryRef cleaned = NULL;
766
767 if (!_sc_debug) {
768 cleaned = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
769 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesScoped);
770 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesServices);
771 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesSupplemental);
772 proxy = cleaned;
773 }
774
775 SCPrint(TRUE, stdout, CFSTR("%@\n"), proxy);
776 if (cleaned != NULL) CFRelease(cleaned);
777 return;
778 }
779
780
781 __private_extern__
782 void
783 do_showProxyConfiguration(int argc, char **argv)
784 {
785 CFDictionaryRef proxies;
786
787 if (getenv("BYPASS_GLOBAL_PROXY") != NULL) {
788 CFMutableDictionaryRef options ;
789
790 options = CFDictionaryCreateMutable(NULL, 0,
791 &kCFTypeDictionaryKeyCallBacks,
792 &kCFTypeDictionaryValueCallBacks);
793 CFDictionaryAddValue(options, kSCProxiesNoGlobal, kCFBooleanTrue);
794 proxies = SCDynamicStoreCopyProxiesWithOptions(NULL, options);
795 CFRelease(options);
796 } else {
797 proxies = SCDynamicStoreCopyProxies(NULL);
798 }
799
800 if (proxies != NULL) {
801 CFStringRef interface = NULL;
802 CFStringRef server = NULL;
803
804 while (argc > 0) {
805 if (strcasecmp(argv[0], "interface") == 0) {
806 argv++;
807 argc--;
808
809 if (argc < 1) {
810 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
811 exit(1);
812 }
813
814 if (if_nametoindex(argv[0]) == 0) {
815 SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[0]);
816 exit(1);
817 }
818
819 interface = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
820 argv++;
821 argc--;
822 } else {
823 if (server != NULL) {
824 CFRelease(server);
825 }
826
827 server = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
828 argv++;
829 argc--;
830 }
831 }
832
833 if ((server != NULL) || (interface != NULL)) {
834 CFArrayRef matching;
835
836 matching = SCNetworkProxiesCopyMatching(proxies, server, interface);
837 if (matching != NULL) {
838 CFIndex i;
839 CFIndex n;
840
841 if (server != NULL) {
842 if (interface != NULL) {
843 SCPrint(TRUE, stdout,
844 CFSTR("server = %@, interface = %@\n"),
845 server,
846 interface);
847 } else {
848 SCPrint(TRUE, stdout,
849 CFSTR("server = %@\n"),
850 server);
851 }
852 } else {
853 SCPrint(TRUE, stdout,
854 CFSTR("interface = %@\n"),
855 interface);
856 }
857
858 n = CFArrayGetCount(matching);
859 for (i = 0; i < n; i++) {
860 CFDictionaryRef proxy;
861
862 proxy = CFArrayGetValueAtIndex(matching, i);
863 SCPrint(TRUE, stdout, CFSTR("\nproxy #%ld\n"), i + 1);
864 showProxy(proxy);
865 }
866
867 CFRelease(matching);
868 } else {
869 SCPrint(TRUE, stdout, CFSTR("No matching proxy configurations\n"));
870 }
871 } else {
872 showProxy(proxies);
873 }
874
875 if (interface != NULL) CFRelease(interface);
876 if (server != NULL) CFRelease(server);
877 CFRelease(proxies);
878 } else {
879 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
880 }
881
882 exit(0);
883 }
884
885
886 __private_extern__
887 void
888 do_snapshot(int argc, char **argv)
889 {
890 #pragma unused(argc)
891 #pragma unused(argv)
892 if (argc == 1) {
893 CFDictionaryRef dict;
894 int fd;
895 CFMutableArrayRef patterns;
896
897 fd = open(argv[0], O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
898 if (fd == -1) {
899 SCPrint(TRUE, stdout, CFSTR("open() failed: %s\n"), strerror(errno));
900 return;
901 }
902
903 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
904 CFArrayAppendValue(patterns, CFSTR(".*"));
905 dict = SCDynamicStoreCopyMultiple(store, NULL, patterns);
906 CFRelease(patterns);
907 if (dict != NULL) {
908 CFDataRef xmlData;
909
910 xmlData = CFPropertyListCreateData(NULL, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL);
911 CFRelease(dict);
912 if (xmlData != NULL) {
913 (void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
914 CFRelease(xmlData);
915 } else {
916 SC_log(LOG_NOTICE, "CFPropertyListCreateData() failed");
917 }
918 } else {
919 if (SCError() == kSCStatusOK) {
920 SCPrint(TRUE, stdout, CFSTR("No SCDynamicStore content\n"));
921 } else {
922 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
923 }
924 }
925 (void) close(fd);
926 } else {
927 #if !TARGET_OS_SIMULATOR
928 if (geteuid() != 0) {
929 SCPrint(TRUE, stdout, CFSTR("Need to be \"root\" to capture snapshot\n"));
930 } else
931 #endif // !TARGET_OS_SIMULATOR
932 if (!SCDynamicStoreSnapshot(store)) {
933 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
934 }
935 }
936
937 return;
938 }
939
940
941 __private_extern__
942 void
943 do_renew(char *if_name)
944 {
945 CFArrayRef services;
946 Boolean ok = FALSE;
947
948 if ((if_name == NULL) || (strlen(if_name) == 0)) {
949 SCPrint(TRUE, stderr, CFSTR("No interface name\n"));
950 exit(1);
951 }
952
953 if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL) {
954 CFArrayRef interfaces;
955
956 interfaces = SCNetworkInterfaceCopyAll();
957 if (interfaces != NULL) {
958 CFIndex i;
959 CFStringRef match_name;
960 CFIndex n;
961
962 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
963 assert(match_name != NULL);
964
965 n = CFArrayGetCount(interfaces);
966 for (i = 0; i < n; i++) {
967 CFStringRef bsd_name;
968 SCNetworkInterfaceRef interface;
969
970 interface = CFArrayGetValueAtIndex(interfaces, i);
971 bsd_name = SCNetworkInterfaceGetBSDName(interface);
972 if (_SC_CFEqual(bsd_name, match_name)) {
973 // if match
974 ok = SCNetworkInterfaceForceConfigurationRefresh(interface);
975 if (!ok) {
976 int status;
977
978 status = SCError();
979 if (status != kSCStatusAccessError) {
980 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(status));
981 exit(1);
982 }
983
984 // ... and if can't write the SCDynamicStore, try w/prefs
985 }
986
987 break;
988 }
989 }
990
991 CFRelease(match_name);
992 CFRelease(interfaces);
993 }
994
995 if (ok) {
996 exit(0);
997 }
998 }
999
1000 do_prefs_init(); /* initialization */
1001 do_prefs_open(0, NULL); /* open default prefs */
1002
1003 services = SCNetworkServiceCopyAll(prefs);
1004 if (services != NULL) {
1005 CFIndex i;
1006 CFStringRef match_name;
1007 CFIndex n;
1008
1009 match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
1010 assert(match_name != NULL);
1011
1012 n = CFArrayGetCount(services);
1013 for (i = 0; i < n; i++) {
1014 CFStringRef bsd_name;
1015 SCNetworkInterfaceRef interface;
1016 SCNetworkServiceRef service;
1017
1018 service = CFArrayGetValueAtIndex(services, i);
1019 interface = SCNetworkServiceGetInterface(service);
1020 if (interface == NULL) {
1021 // if no interface
1022 continue;
1023 }
1024
1025 bsd_name = SCNetworkInterfaceGetBSDName(interface);
1026 if (_SC_CFEqual(bsd_name, match_name)) {
1027 // if match
1028 ok = SCNetworkInterfaceForceConfigurationRefresh(interface);
1029 if (!ok) {
1030 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(SCError()));
1031 exit(1);
1032 }
1033
1034 break;
1035 }
1036 }
1037
1038 CFRelease(match_name);
1039 CFRelease(services);
1040 }
1041
1042 if (!ok) {
1043 SCPrint(TRUE, stderr, CFSTR("No interface\n"));
1044 exit(1);
1045 }
1046
1047 _prefs_close();
1048 exit(0);
1049 }
1050
1051
1052 static void
1053 waitKeyFound()
1054 {
1055 exit(0);
1056 }
1057
1058
1059 static void
1060 waitTimeout(int sigraised)
1061 {
1062 #pragma unused(sigraised)
1063 exit(1);
1064 }
1065
1066
1067 __private_extern__
1068 void
1069 do_wait(char *waitKey, int timeout)
1070 {
1071 struct itimerval itv;
1072 CFStringRef key;
1073 CFMutableArrayRef keys;
1074 Boolean ok;
1075
1076 store = SCDynamicStoreCreate(NULL, CFSTR("scutil (wait)"), waitKeyFound, NULL);
1077 if (store == NULL) {
1078 SCPrint(TRUE, stderr,
1079 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1080 exit(1);
1081 }
1082
1083 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
1084
1085 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1086 CFArrayAppendValue(keys, key);
1087 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1088 CFRelease(keys);
1089 if (!ok) {
1090 SCPrint(TRUE, stderr,
1091 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1092 exit(1);
1093 }
1094
1095 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1096 if (!notifyRls) {
1097 SCPrint(TRUE, stderr,
1098 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1099 exit(1);
1100 }
1101
1102 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
1103
1104 value = SCDynamicStoreCopyValue(store, key);
1105 if (value) {
1106 /* if the key is already present */
1107 exit(0);
1108 }
1109 CFRelease(key);
1110
1111 if (timeout > 0) {
1112 signal(SIGALRM, waitTimeout);
1113 memset(&itv, 0, sizeof(itv));
1114 itv.it_value.tv_sec = timeout;
1115 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
1116 SCPrint(TRUE, stderr,
1117 CFSTR("setitimer() failed: %s\n"), strerror(errno));
1118 exit(1);
1119 }
1120 }
1121
1122 CFRunLoopRun();
1123 }
1124
1125 /**
1126 ** "scutil --advisory <ifname> [ set | -W ]"
1127 **/
1128 void
1129 timestamp_fprintf(FILE * f, const char * message, ...)
1130 {
1131 struct timeval tv;
1132 struct tm tm;
1133 time_t t;
1134 va_list ap;
1135
1136 (void)gettimeofday(&tv, NULL);
1137 t = tv.tv_sec;
1138 (void)localtime_r(&t, &tm);
1139
1140 va_start(ap, message);
1141 fprintf(f, "%04d/%02d/%02d %2d:%02d:%02d.%06d ",
1142 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
1143 tm.tm_hour, tm.tm_min, tm.tm_sec,
1144 tv.tv_usec);
1145 vfprintf(f, message, ap);
1146 va_end(ap);
1147 }
1148
1149 static void
1150 advisoryCheck(SCNetworkInterfaceRef interface, Boolean show_timestamp)
1151 {
1152 if (show_timestamp) {
1153 timestamp_fprintf(stdout, "");
1154 }
1155 printf("%sset\n",
1156 SCNetworkInterfaceAdvisoryIsSet(interface) ? "" : "not ");
1157 }
1158
1159 static void
1160 advisoryChanged(SCDynamicStoreRef session, CFArrayRef changes,
1161 void * info)
1162 {
1163 #pragma unused(session, changes)
1164 SCNetworkInterfaceRef interface = (SCNetworkInterfaceRef)info;
1165
1166 advisoryCheck(interface, TRUE);
1167 return;
1168 }
1169
1170 static void
1171 advisoryWatch(SCNetworkInterfaceRef interface)
1172 {
1173 SCDynamicStoreContext context = {
1174 .info = (void *)interface,
1175 };
1176 CFStringRef key;
1177 CFMutableArrayRef keys;
1178 Boolean ok;
1179
1180 store = SCDynamicStoreCreate(NULL, CFSTR("scutil (advisory)"), advisoryChanged, &context);
1181 if (store == NULL) {
1182 SCPrint(TRUE, stderr,
1183 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1184 exit(1);
1185 }
1186 key = SCNetworkInterfaceCopyAdvisoryNotificationKey(interface);
1187 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1188 CFArrayAppendValue(keys, key);
1189 CFRelease(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 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1198 if (!notifyRls) {
1199 SCPrint(TRUE, stderr,
1200 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1201 exit(1);
1202 }
1203 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
1204 }
1205
1206 __private_extern__
1207 void
1208 do_advisory(const char * ifname, Boolean watch, int argc, char **argv)
1209 {
1210 CFStringRef ifname_cf;
1211 SCNetworkInterfaceRef interface;
1212
1213 ifname_cf = CFStringCreateWithCString(NULL, ifname, kCFStringEncodingUTF8);
1214 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, ifname_cf, kIncludeAllVirtualInterfaces);
1215 CFRelease(ifname_cf);
1216 if (interface == NULL) {
1217 fprintf(stderr, "Failed to instantiate SCNetworkInterfaceRef\n");
1218 exit(1);
1219 }
1220 if (argc >= 1) {
1221 SCNetworkInterfaceAdvisory advisory = kSCNetworkInterfaceAdvisoryUplinkIssue;
1222
1223 if (strcasecmp(argv[0], "set") != 0) {
1224 fprintf(stderr,
1225 "usage: scutil --advisory <ifname> "
1226 "[ set [ linklayer | uplink ] | -W ]\n");
1227 exit(1);
1228 }
1229 if (argc >= 2) {
1230 if (strcasecmp(argv[1], "uplink") == 0) {
1231 advisory = kSCNetworkInterfaceAdvisoryUplinkIssue;
1232 } else if (strcasecmp(argv[1], "linklayer") == 0) {
1233 advisory = kSCNetworkInterfaceAdvisoryLinkLayerIssue;
1234 } else {
1235 fprintf(stderr,
1236 "Bad advisory '%s', must be either 'uplink' or 'linklayer'\n",
1237 argv[1]);
1238 exit(1);
1239 }
1240 }
1241 SCNetworkInterfaceSetAdvisory(interface, advisory, CFSTR("Because"));
1242 CFRunLoopRun();
1243 } else {
1244 advisoryCheck(interface, watch);
1245 if (watch) {
1246 advisoryWatch(interface);
1247 CFRunLoopRun();
1248 }
1249 }
1250 exit(0);
1251 }
1252
1253
1254 #ifdef TEST_DNS_CONFIGURATION
1255
1256 Boolean doDispatch = FALSE;
1257 CFRunLoopSourceRef notifyRls = NULL;
1258 SCDynamicStoreRef store = NULL;
1259 CFPropertyListRef value = NULL;
1260
1261 int
1262 main(int argc, char **argv)
1263 {
1264 dns_config_t *dns_config;
1265
1266 fprintf(stdout, "copy configuration\n");
1267 dns_config = dns_configuration_copy();
1268 if (dns_config != NULL) {
1269
1270 fprintf(stdout, "sleeping for 120 seconds\n");
1271 sleep(120);
1272
1273 fprintf(stdout, "sending ack\n");
1274 _dns_configuration_ack(dns_config, "TEST_DNS_CONFIGURATION");
1275
1276 fprintf(stdout, "sleeping for 120 seconds\n");
1277 sleep(120);
1278
1279 dns_configuration_free(dns_config);
1280 }
1281
1282 do_showDNSConfiguration(argc, argv);
1283 exit(0);
1284 }
1285
1286 #endif // TEST_DNS_CONFIGURATION