]> git.saurik.com Git - apple/configd.git/blame - scutil.tproj/tests.c
configd-802.20.7.tar.gz
[apple/configd.git] / scutil.tproj / tests.c
CommitLineData
5958d7c0 1/*
9de8ab86 2 * Copyright (c) 2000, 2001, 2003-2015 Apple Inc. All rights reserved.
5958d7c0
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
78403150 5 *
009ee3c6
A
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.
78403150 12 *
009ee3c6
A
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
5958d7c0
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
009ee3c6
A
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.
78403150 20 *
5958d7c0
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
0fae82ee
A
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
5958d7c0 39#include "scutil.h"
5e9ce69e 40#include "prefs.h"
009ee3c6 41#include "tests.h"
0fae82ee 42
a40a14f8
A
43#include <netdb.h>
44#include <netdb_async.h>
78403150 45#include <notify.h>
0fae82ee 46#include <sys/time.h>
009ee3c6 47#include <net/if.h>
0fae82ee
A
48#include <netinet/in.h>
49#include <arpa/inet.h>
50
9de8ab86
A
51#define my_log(__level, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
52
dbf6a266 53#include <dnsinfo.h>
5e9ce69e 54#include "dnsinfo_internal.h"
17d3ee29 55#include <network_information.h>
9de8ab86 56#include "network_information_priv.h"
17d3ee29 57#include "SCNetworkReachabilityInternal.h"
5e9ce69e 58#include <CommonCrypto/CommonDigest.h>
17d3ee29 59
78403150
A
60
61static Boolean resolver_bypass;
62
17d3ee29
A
63
64static CF_RETURNS_RETAINED CFMutableDictionaryRef
65_setupReachabilityOptions(int argc, char **argv, const char *interface)
66{
5e9ce69e 67 int i;
17d3ee29
A
68 CFMutableDictionaryRef options;
69
70 options = CFDictionaryCreateMutable(NULL,
71 0,
72 &kCFTypeDictionaryKeyCallBacks,
73 &kCFTypeDictionaryValueCallBacks);
74
5e9ce69e
A
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);
17d3ee29
A
81 }
82
5e9ce69e
A
83 interface = argv[i];
84 continue;
85 }
17d3ee29 86
17d3ee29 87
5e9ce69e
A
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 }
17d3ee29 99
5e9ce69e
A
100 if (strcasecmp(argv[i], "no-connection-on-demand") == 0) {
101 CFDictionarySetValue(options,
102 kSCNetworkReachabilityOptionConnectionOnDemandBypass,
103 kCFBooleanTrue);
104 continue;
17d3ee29
A
105 }
106
5e9ce69e
A
107 if (strcasecmp(argv[i], "no-resolve") == 0) {
108 CFDictionarySetValue(options,
109 kSCNetworkReachabilityOptionResolverBypass,
110 kCFBooleanTrue);
111 resolver_bypass = TRUE;
112 continue;
113 }
17d3ee29 114
78403150
A
115 if (strcasecmp(argv[i], "ptr") == 0) {
116 CFDictionarySetValue(options,
117 kSCNetworkReachabilityOptionPTRAddress,
118 kCFBooleanTrue);
119 continue;
120 }
121
5e9ce69e
A
122 if (strlen(argv[i]) == 0) {
123 continue;
17d3ee29 124 }
5e9ce69e
A
125
126 SCPrint(TRUE, stderr, CFSTR("Unrecognized option: %s\n"), argv[i]);
127 CFRelease(options);
128 exit(1);
17d3ee29
A
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
5958d7c0 152
a40a14f8
A
153static SCNetworkReachabilityRef
154_setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
5958d7c0 155{
78403150
A
156 const char *ip_address = argv[0];
157 char *ip_addressN = NULL;
6bb65964 158 const char *interface;
17d3ee29 159 CFMutableDictionaryRef options = NULL;
78403150
A
160 const char *remote_address = NULL;
161 char *remote_addressN= NULL;
162 const char *remote_interface;
a40a14f8
A
163 struct sockaddr_in sin;
164 struct sockaddr_in6 sin6;
17d3ee29 165 SCNetworkReachabilityRef target = NULL;
0fae82ee 166
a40a14f8
A
167 bzero(&sin, sizeof(sin));
168 sin.sin_len = sizeof(sin);
169 sin.sin_family = AF_INET;
009ee3c6 170
a40a14f8
A
171 bzero(&sin6, sizeof(sin6));
172 sin6.sin6_len = sizeof(sin6);
173 sin6.sin6_family = AF_INET6;
009ee3c6 174
78403150 175 interface = strchr(ip_address, '%');
6bb65964 176 if (interface != NULL) {
78403150
A
177 ip_addressN = strdup(ip_address);
178 ip_addressN[interface - ip_address] = '\0';
179 ip_address = ip_addressN;
6bb65964
A
180 interface++;
181 }
182
78403150
A
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
6bb65964 195 if (inet_aton(ip_address, &sin.sin_addr) == 1) {
78403150
A
196 struct sockaddr_in r_sin;
197
5e9ce69e
A
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;
5e9ce69e
A
202 }
203
204 if ((argc == 1)
78403150
A
205 || (remote_address == NULL)
206 || (inet_aton(remote_address, &r_sin.sin_addr) == 0)) {
5e9ce69e
A
207 if (argc > 2) {
208 options = _setupReachabilityOptions(argc - 2, argv + 2, interface);
209 }
17d3ee29 210 if (options == NULL) {
6bb65964
A
211 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
212 if (context != NULL) {
213 context->info = "by address";
214 }
215 } else {
17d3ee29 216 CFDataRef data;
6bb65964 217
6bb65964
A
218 data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
219 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
220 CFRelease(data);
17d3ee29 221
6bb65964 222 if (context != NULL) {
17d3ee29
A
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 }
6bb65964 233 }
a40a14f8
A
234 }
235 } else {
78403150
A
236 if (remote_interface != NULL) {
237 if ((interface != NULL) && (strcmp(interface, remote_interface) != 0)) {
6bb65964
A
238 SCPrint(TRUE, stderr,
239 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
240 interface,
78403150 241 remote_interface);
6bb65964
A
242 exit(1);
243 }
244
78403150 245 interface = remote_interface;
6bb65964
A
246 }
247
5e9ce69e 248 options = _setupReachabilityOptions(argc - 2, argv + 2, interface);
17d3ee29 249 if (options == NULL) {
6bb65964
A
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 {
17d3ee29 257 CFDataRef data;
6bb65964 258
6bb65964
A
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);
17d3ee29 265
6bb65964 266 if (context != NULL) {
17d3ee29
A
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 }
6bb65964 277 }
009ee3c6 278 }
a40a14f8 279 }
78403150 280 } else if (inet_pton(AF_INET6, ip_address, &sin6.sin6_addr) == 1) {
5e9ce69e
A
281 struct sockaddr_in6 r_sin6;
282
6bb65964
A
283 if (interface != NULL) {
284 sin6.sin6_scope_id = if_nametoindex(interface);
a40a14f8 285 }
009ee3c6 286
78403150 287 if (argc > 1) {
5e9ce69e
A
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)
78403150
A
294 || (remote_address == NULL)
295 || (inet_pton(AF_INET6, remote_address, &r_sin6.sin6_addr) == 0)) {
5e9ce69e
A
296 if (argc > 2) {
297 options = _setupReachabilityOptions(argc - 2, argv + 2, NULL);
298 }
17d3ee29
A
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 }
a40a14f8 314 }
009ee3c6 315 } else {
78403150
A
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 }
a40a14f8 326 }
009ee3c6 327
5e9ce69e 328 options = _setupReachabilityOptions(argc - 2, argv + 2, NULL);
17d3ee29
A
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 }
a40a14f8
A
349 }
350 }
351 } else {
5e9ce69e
A
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);
17d3ee29
A
359 if (options == NULL) {
360 target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
361 if (context != NULL) {
362 context->info = "by name";
363 }
364 } else {
5e9ce69e 365 CFStringRef str;
a40a14f8 366
a40a14f8
A
367 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
368 CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
369 CFRelease(str);
6bb65964 370
17d3ee29 371 if (context != NULL) {
5e9ce69e 372 context->info = "by name w/options";
a40a14f8 373 }
a40a14f8 374 }
a40a14f8 375 }
009ee3c6
A
376 }
377
78403150
A
378 if (ip_addressN != NULL) {
379 free(ip_addressN);
380 }
381
382 if (remote_addressN != NULL) {
383 free(remote_addressN);
6bb65964
A
384 }
385
17d3ee29 386 if ((target == NULL) && (options != NULL)) {
78403150
A
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
17d3ee29
A
416 target = SCNetworkReachabilityCreateWithOptions(NULL, options);
417 CFRelease(options);
418 }
419
a40a14f8
A
420 return target;
421}
0fae82ee 422
17d3ee29
A
423
424static void
425_printReachability(SCNetworkReachabilityRef target)
426{
427 SCNetworkReachabilityFlags flags;
428 Boolean ok;
9de8ab86 429 CFStringRef str;
17d3ee29
A
430
431 ok = SCNetworkReachabilityGetFlags(target, &flags);
432 if (!ok) {
5e9ce69e 433 SCPrint(TRUE, stderr, CFSTR(" could not determine reachability, %s\n"), SCErrorString(SCError()));
17d3ee29
A
434 return;
435 }
436
9de8ab86
A
437 str = __SCNetworkReachabilityCopyFlags(flags, CFSTR("flags = "), _sc_debug);
438 SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
439 CFRelease(str);
17d3ee29 440
9de8ab86 441 if (resolver_bypass && _sc_debug) {
5e9ce69e 442 int if_index;
17d3ee29 443
5e9ce69e 444 if_index = SCNetworkReachabilityGetInterfaceIndex(target);
9de8ab86 445 SCPrint(TRUE, stdout, CFSTR("interface index = %d\n"), if_index);
5e9ce69e 446 }
a40a14f8
A
447
448 return;
449}
450
451
452__private_extern__
453void
454do_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
17d3ee29
A
470static void
471_printNWIFlags(nwi_ifstate_flags flags)
472{
9de8ab86 473 flags &= NWI_IFSTATE_FLAGS_MASK;
17d3ee29
A
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 }
9de8ab86
A
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 }
17d3ee29 509 if (flags != 0) {
78403150 510 SCPrint(TRUE, stdout, CFSTR("%p"), (void *)flags);
17d3ee29
A
511 }
512 SCPrint(TRUE, stdout, CFSTR(")"));
513
514 return;
515}
516
517
5e9ce69e
A
518static void
519_printNWIInfo(nwi_ifstate_t ifstate)
520{
9de8ab86 521 nwi_ifstate_flags ifstate_flags;
5e9ce69e
A
522 SCNetworkReachabilityFlags reach_flags = nwi_ifstate_get_reachability_flags(ifstate);
523 const uint8_t *signature;
524 int signature_length;
9de8ab86 525 CFStringRef str;
5e9ce69e
A
526 const struct sockaddr *vpn_addr = nwi_ifstate_get_vpn_server(ifstate);
527
9de8ab86
A
528 ifstate_flags = nwi_ifstate_get_flags(ifstate);
529 if (_sc_debug) {
530 ifstate_flags |= ifstate->flags;
531 }
532
5e9ce69e
A
533 SCPrint(TRUE, stdout,
534 CFSTR(" %7s : flags %p"),
535 nwi_ifstate_get_ifname(ifstate),
78403150 536 (void *)ifstate_flags);
5e9ce69e
A
537 _printNWIFlags(ifstate_flags);
538
9de8ab86
A
539 str = __SCNetworkReachabilityCopyFlags(reach_flags, CFSTR(" reach "), TRUE);
540 SCPrint(TRUE, stdout, CFSTR("\n%@"), str);
541 CFRelease(str);
5e9ce69e
A
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
78403150
A
568static void
569_printNWIReachInfo(nwi_state_t state, int af)
570{
571 uint32_t reach_flags;
9de8ab86 572 CFStringRef str;
78403150
A
573
574 reach_flags = nwi_state_get_reachability_flags(state, af);
9de8ab86
A
575
576 str = __SCNetworkReachabilityCopyFlags(reach_flags, CFSTR(" REACH : flags "), TRUE);
577 SCPrint(TRUE, stdout, CFSTR("\n%@\n"), str);
578 CFRelease(str);
78403150
A
579
580 return;
581}
582
583
584static void
585do_printNWI(int argc, char **argv, nwi_state_t state)
17d3ee29 586{
9de8ab86 587 unsigned int count;
17d3ee29 588 nwi_ifstate_t ifstate;
17d3ee29
A
589
590 if (state == NULL) {
591 SCPrint(TRUE, stdout, CFSTR("No network information\n"));
78403150 592 return;
17d3ee29
A
593 }
594
595 if (argc > 0) {
596 ifstate = nwi_state_get_ifstate(state, argv[0]);
597 if (ifstate != NULL) {
9de8ab86
A
598 nwi_ifstate_t alias;
599
5e9ce69e 600 _printNWIInfo(ifstate);
9de8ab86
A
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 }
17d3ee29
A
608 } else {
609 SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]);
610 }
78403150 611 return;
17d3ee29
A
612 }
613
5e9ce69e
A
614 SCPrint(TRUE, stdout, CFSTR("Network information (generation %llu)"),
615 nwi_state_get_generation(state));
616
17d3ee29 617 SCPrint(TRUE, stdout, CFSTR("\nIPv4 network interface information\n"));
17d3ee29 618
78403150 619 ifstate = nwi_state_get_first_ifstate(state, AF_INET);
17d3ee29 620 if (ifstate == NULL) {
78403150
A
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 }
17d3ee29 627 }
78403150 628 _printNWIReachInfo(state, AF_INET);
17d3ee29
A
629
630 SCPrint(TRUE, stdout, CFSTR("\nIPv6 network interface information\n"));
17d3ee29 631
78403150 632 ifstate = nwi_state_get_first_ifstate(state, AF_INET6);
17d3ee29 633 if (ifstate == NULL) {
78403150
A
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 }
17d3ee29 640 }
78403150 641 _printNWIReachInfo(state, AF_INET6);
17d3ee29 642
9de8ab86
A
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 }
78403150
A
658 return;
659}
660
661
662__private_extern__
663void
664do_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__
681void
682do_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);
17d3ee29
A
692 }
693
78403150
A
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) {
9de8ab86 717 SC_log(LOG_INFO, "notify_register_dispatch() failed for nwi changes, status=%u", status);
78403150
A
718 exit(1);
719 }
17d3ee29 720
78403150 721 CFRunLoopRun();
17d3ee29
A
722 exit(0);
723}
724
725
a40a14f8
A
726static void
727callout(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__
750void
751do_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 //
17d3ee29 773 // To test the case were an application first calls SCNetworkReachabilityGetFlags()
a40a14f8
A
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);
17d3ee29 790// _printReachability(target_async);
a40a14f8
A
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
d0784775 798 if (doDispatch) {
5e9ce69e 799 if (!SCNetworkReachabilitySetDispatchQueue(target_async, dispatch_get_main_queue())) {
d0784775
A
800 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
801 exit(1);
802 }
6bb65964 803 } else {
d0784775
A
804 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
805 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
806 exit(1);
807 }
a40a14f8
A
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.
d0784775 812 SCPrint(TRUE, stdout, CFSTR(" 2: on %s\n"), doDispatch ? "dispatch queue" : "runloop");
a40a14f8
A
813 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
814 _printReachability(target_async);
815 SCPrint(TRUE, stdout, CFSTR("\n"));
816
817 CFRunLoopRun();
0fae82ee
A
818 exit(0);
819}
5958d7c0 820
0fae82ee 821
78403150
A
822static void
823do_printDNSConfiguration(int argc, char **argv, dns_config_t *dns_config)
6bb65964 824{
9de8ab86 825 int _sc_log_save;
6bb65964 826
17d3ee29
A
827 if (dns_config == NULL) {
828 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
78403150 829 return;
17d3ee29
A
830 }
831
9de8ab86
A
832 _sc_log_save = _sc_log;
833 _sc_log = FALSE;
834 _dns_configuration_log(dns_config, _sc_debug);
835 _sc_log = _sc_log_save;
6bb65964 836
5e9ce69e 837 if (_sc_debug) {
78403150 838 SCPrint(TRUE, stdout, CFSTR("\ngeneration = %llu\n"), dns_config->generation);
dbf6a266
A
839 }
840
78403150
A
841 return;
842}
843
844
845__private_extern__
846void
847do_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__
864void
865do_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) {
9de8ab86 900 SC_log(LOG_INFO, "notify_register_dispatch() failed for DNS configuration changes, status=%u", status);
78403150
A
901 exit(1);
902 }
903
904 CFRunLoopRun();
dbf6a266
A
905 exit(0);
906}
907
908
6bb65964
A
909static void
910showProxy(CFDictionaryRef proxy)
911{
912 CFMutableDictionaryRef cleaned = NULL;
913
914 if (!_sc_debug) {
915 cleaned = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
6bb65964 916 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesScoped);
5e9ce69e
A
917 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesServices);
918 CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesSupplemental);
6bb65964
A
919 proxy = cleaned;
920 }
921
922 SCPrint(TRUE, stdout, CFSTR("%@\n"), proxy);
923 if (cleaned != NULL) CFRelease(cleaned);
924 return;
925}
926
927
dbf6a266
A
928__private_extern__
929void
930do_showProxyConfiguration(int argc, char **argv)
931{
5e9ce69e
A
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 }
dbf6a266 947
dbf6a266 948 if (proxies != NULL) {
6bb65964
A
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);
78403150 1011 SCPrint(TRUE, stdout, CFSTR("\nproxy #%ld\n"), i + 1);
6bb65964
A
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);
a40a14f8 1025 CFRelease(proxies);
dbf6a266
A
1026 } else {
1027 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
1028 }
1029
1030 exit(0);
1031}
1032
1033
1034__private_extern__
0fae82ee
A
1035void
1036do_snapshot(int argc, char **argv)
1037{
1038 if (!SCDynamicStoreSnapshot(store)) {
1039 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
5958d7c0 1040 }
17d3ee29 1041
5958d7c0
A
1042 return;
1043}
1044
1045
5e9ce69e
A
1046__private_extern__
1047void
1048do_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
0fae82ee
A
1157static void
1158waitKeyFound()
1159{
1160 exit(0);
1161}
1162
1163
1164static void
1165waitTimeout(int sigraised)
1166{
1167 exit(1);
1168}
1169
5958d7c0 1170
dbf6a266 1171__private_extern__
5958d7c0 1172void
0fae82ee 1173do_wait(char *waitKey, int timeout)
5958d7c0 1174{
0fae82ee
A
1175 struct itimerval itv;
1176 CFStringRef key;
1177 CFMutableArrayRef keys;
a40a14f8 1178 Boolean ok;
5958d7c0 1179
0fae82ee 1180 store = SCDynamicStoreCreate(NULL, CFSTR("scutil (wait)"), waitKeyFound, NULL);
dbf6a266 1181 if (store == NULL) {
0fae82ee
A
1182 SCPrint(TRUE, stderr,
1183 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1184 exit(1);
5958d7c0
A
1185 }
1186
dbf6a266 1187 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
5958d7c0 1188
a40a14f8
A
1189 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1190 CFArrayAppendValue(keys, key);
1191 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1192 CFRelease(keys);
1193 if (!ok) {
0fae82ee
A
1194 SCPrint(TRUE, stderr,
1195 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1196 exit(1);
1197 }
5958d7c0 1198
0fae82ee
A
1199 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1200 if (!notifyRls) {
1201 SCPrint(TRUE, stderr,
1202 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1203 exit(1);
5958d7c0
A
1204 }
1205
0fae82ee
A
1206 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
1207
1208 value = SCDynamicStoreCopyValue(store, key);
1209 if (value) {
1210 /* if the key is already present */
1211 exit(0);
5958d7c0 1212 }
0fae82ee
A
1213 CFRelease(key);
1214
dbf6a266 1215 if (timeout > 0) {
0fae82ee
A
1216 signal(SIGALRM, waitTimeout);
1217 bzero(&itv, sizeof(itv));
1218 itv.it_value.tv_sec = timeout;
edebe297 1219 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
0fae82ee
A
1220 SCPrint(TRUE, stderr,
1221 CFSTR("setitimer() failed: %s\n"), strerror(errno));
1222 exit(1);
5958d7c0
A
1223 }
1224 }
1225
0fae82ee 1226 CFRunLoopRun();
5958d7c0 1227}
edebe297 1228
5e9ce69e 1229#ifdef TEST_DNS_CONFIGURATION
edebe297 1230
5e9ce69e 1231Boolean doDispatch = FALSE;
edebe297
A
1232CFRunLoopSourceRef notifyRls = NULL;
1233SCDynamicStoreRef store = NULL;
1234CFPropertyListRef value = NULL;
a40a14f8 1235
edebe297
A
1236int
1237main(int argc, char **argv)
1238{
5e9ce69e
A
1239 dns_config_t *dns_config;
1240
1241fprintf(stdout, "copy configuration\n");
1242 dns_config = dns_configuration_copy();
1243 if (dns_config != NULL) {
1244
1245fprintf(stdout, "sleeping for 120 seconds\n");
1246sleep(120);
1247
1248fprintf(stdout, "sending ack\n");
1249 _dns_configuration_ack(dns_config, "TEST_DNS_CONFIGURATION");
1250
1251fprintf(stdout, "sleeping for 120 seconds\n");
1252sleep(120);
1253
1254 dns_configuration_free(dns_config);
1255 }
1256
9de8ab86 1257 do_showDNSConfiguration(argc, argv);
edebe297
A
1258 exit(0);
1259}
1260
5e9ce69e 1261#endif // TEST_DNS_CONFIGURATION