]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/tests.c
cc9f95f7f7c0f2b39817c0555dec7853777406ba
[apple/configd.git] / scutil.tproj / tests.c
1 /*
2 * Copyright (c) 2000, 2001, 2003-2005, 2007-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * July 9, 2001 Allan Nathanson <ajn@apple.com>
28 * - added "-r" option for checking network reachability
29 * - added "-w" option to check/wait for the presence of a
30 * dynamic store key.
31 *
32 * June 1, 2001 Allan Nathanson <ajn@apple.com>
33 * - public API conversion
34 *
35 * November 9, 2000 Allan Nathanson <ajn@apple.com>
36 * - initial revision
37 */
38
39 #include "scutil.h"
40 #include "tests.h"
41
42 #include <netdb.h>
43 #include <netdb_async.h>
44 #include <sys/time.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48
49 #include <dnsinfo.h>
50
51 static SCNetworkReachabilityRef
52 _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
53 {
54 struct sockaddr_in sin;
55 struct sockaddr_in6 sin6;
56 SCNetworkReachabilityRef target = NULL;
57
58 bzero(&sin, sizeof(sin));
59 sin.sin_len = sizeof(sin);
60 sin.sin_family = AF_INET;
61
62 bzero(&sin6, sizeof(sin6));
63 sin6.sin6_len = sizeof(sin6);
64 sin6.sin6_family = AF_INET6;
65
66 if (inet_aton(argv[0], &sin.sin_addr) == 1) {
67 if (argc == 1) {
68 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
69 if (context != NULL) {
70 context->info = "by address";
71 }
72 } else {
73 struct sockaddr_in r_sin;
74
75 bzero(&r_sin, sizeof(r_sin));
76 r_sin.sin_len = sizeof(r_sin);
77 r_sin.sin_family = AF_INET;
78 if (inet_aton(argv[1], &r_sin.sin_addr) == 0) {
79 SCPrint(TRUE, stderr, CFSTR("Could not interpret address \"%s\"\n"), argv[1]);
80 exit(1);
81 }
82
83 target = SCNetworkReachabilityCreateWithAddressPair(NULL,
84 (struct sockaddr *)&sin,
85 (struct sockaddr *)&r_sin);
86 if (context != NULL) {
87 context->info = "by address pair";
88 }
89 }
90 } else if (inet_pton(AF_INET6, argv[0], &sin6.sin6_addr) == 1) {
91 char *p;
92
93 p = strchr(argv[0], '%');
94 if (p != NULL) {
95 sin6.sin6_scope_id = if_nametoindex(p + 1);
96 }
97
98 if (argc == 1) {
99 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6);
100 if (context != NULL) {
101 context->info = "by (v6) address";
102 }
103 } else {
104 struct sockaddr_in6 r_sin6;
105
106 bzero(&r_sin6, sizeof(r_sin6));
107 r_sin6.sin6_len = sizeof(r_sin6);
108 r_sin6.sin6_family = AF_INET6;
109 if (inet_pton(AF_INET6, argv[1], &r_sin6.sin6_addr) == 0) {
110 SCPrint(TRUE, stderr, CFSTR("Could not interpret address \"%s\"\n"), argv[1]);
111 exit(1);
112 }
113
114 p = strchr(argv[1], '%');
115 if (p != NULL) {
116 r_sin6.sin6_scope_id = if_nametoindex(p + 1);
117 }
118
119 target = SCNetworkReachabilityCreateWithAddressPair(NULL,
120 (struct sockaddr *)&sin6,
121 (struct sockaddr *)&r_sin6);
122 if (context != NULL) {
123 context->info = "by (v6) address pair";
124 }
125 }
126 } else {
127 if (argc == 1) {
128 target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
129 if (context != NULL) {
130 context->info = "by name";
131 }
132 } else {
133 CFStringRef str;
134 CFMutableDictionaryRef options;
135
136 options = CFDictionaryCreateMutable(NULL,
137 0,
138 &kCFTypeDictionaryKeyCallBacks,
139 &kCFTypeDictionaryValueCallBacks);
140 if (strlen(argv[0]) > 0) {
141 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
142 CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
143 CFRelease(str);
144 }
145 if (strlen(argv[1]) > 0) {
146 str = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8);
147 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServName, str);
148 CFRelease(str);
149 }
150 if (argc > 2) {
151 CFDataRef data;
152 struct addrinfo hints = { 0 };
153 int i;
154
155 for (i = 2; i < argc; i++) {
156 if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
157 hints.ai_flags |= AI_ADDRCONFIG;
158 } else if (strcasecmp(argv[i], "AI_ALL") == 0) {
159 hints.ai_flags |= AI_ALL;
160 } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
161 hints.ai_flags |= AI_V4MAPPED;
162 } else if (strcasecmp(argv[i], "AI_V4MAPPED_CFG") == 0) {
163 hints.ai_flags |= AI_V4MAPPED_CFG;
164 } else if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
165 hints.ai_flags |= AI_ADDRCONFIG;
166 } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
167 hints.ai_flags |= AI_V4MAPPED;
168 } else if (strcasecmp(argv[i], "AI_DEFAULT") == 0) {
169 hints.ai_flags |= AI_DEFAULT;
170 #ifdef AI_PARALLEL
171 } else if (strcasecmp(argv[i], "AI_PARALLEL") == 0) {
172 hints.ai_flags |= AI_PARALLEL;
173 #endif // AI_PARALLEL
174 } else if (strcasecmp(argv[i], "PF_INET") == 0) {
175 hints.ai_family = PF_INET;
176 } else if (strcasecmp(argv[i], "PF_INET6") == 0) {
177 hints.ai_family = PF_INET6;
178 } else if (strcasecmp(argv[i], "SOCK_STREAM") == 0) {
179 hints.ai_socktype = SOCK_STREAM;
180 } else if (strcasecmp(argv[i], "SOCK_DGRAM") == 0) {
181 hints.ai_socktype = SOCK_DGRAM;
182 } else if (strcasecmp(argv[i], "SOCK_RAW") == 0) {
183 hints.ai_socktype = SOCK_RAW;
184 } else if (strcasecmp(argv[i], "IPPROTO_TCP") == 0) {
185 hints.ai_protocol = IPPROTO_TCP;
186 } else if (strcasecmp(argv[i], "IPPROTO_UDP") == 0) {
187 hints.ai_protocol = IPPROTO_UDP;
188 } else {
189 SCPrint(TRUE, stderr, CFSTR("Unrecognized hint: %s\n"), argv[i]);
190 exit(1);
191 }
192 }
193
194 data = CFDataCreate(NULL, (const UInt8 *)&hints, sizeof(hints));
195 CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data);
196 CFRelease(data);
197 }
198 if (CFDictionaryGetCount(options) > 0) {
199 target = SCNetworkReachabilityCreateWithOptions(NULL, options);
200 if (context != NULL) {
201 context->info = "by (node and/or serv) name";
202 }
203 } else {
204 SCPrint(TRUE, stderr, CFSTR("Must specify nodename or servname\n"));
205 exit(1);
206 }
207 CFRelease(options);
208 }
209 }
210
211 return target;
212 }
213
214 static void
215 _printReachability(SCNetworkReachabilityRef target)
216 {
217 SCNetworkReachabilityFlags flags;
218 Boolean ok;
219
220 ok = SCNetworkReachabilityGetFlags(target, &flags);
221 if (!ok) {
222 printf(" could not determine reachability, %s\n", SCErrorString(SCError()));
223 return;
224 }
225
226 SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x"), flags);
227 if (flags != 0) {
228 SCPrint(_sc_debug, stdout, CFSTR(" ("));
229 if (flags & kSCNetworkReachabilityFlagsReachable) {
230 SCPrint(TRUE, stdout, CFSTR("Reachable"));
231 flags &= ~kSCNetworkReachabilityFlagsReachable;
232 SCPrint(flags != 0, stdout, CFSTR(","));
233 }
234 if (flags & kSCNetworkReachabilityFlagsTransientConnection) {
235 SCPrint(TRUE, stdout, CFSTR("Transient Connection"));
236 flags &= ~kSCNetworkReachabilityFlagsTransientConnection;
237 SCPrint(flags != 0, stdout, CFSTR(","));
238 }
239 if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
240 SCPrint(TRUE, stdout, CFSTR("Connection Required"));
241 flags &= ~kSCNetworkReachabilityFlagsConnectionRequired;
242 SCPrint(flags != 0, stdout, CFSTR(","));
243 }
244 if (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) {
245 SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Traffic"));
246 flags &= ~kSCNetworkReachabilityFlagsConnectionOnTraffic;
247 SCPrint(flags != 0, stdout, CFSTR(","));
248 }
249 if (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) {
250 SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Demand"));
251 flags &= ~kSCNetworkReachabilityFlagsConnectionOnDemand;
252 SCPrint(flags != 0, stdout, CFSTR(","));
253 }
254 if (flags & kSCNetworkReachabilityFlagsInterventionRequired) {
255 SCPrint(TRUE, stdout, CFSTR("Intervention Required"));
256 flags &= ~kSCNetworkReachabilityFlagsInterventionRequired;
257 SCPrint(flags != 0, stdout, CFSTR(","));
258 }
259 if (flags & kSCNetworkReachabilityFlagsIsLocalAddress) {
260 SCPrint(TRUE, stdout, CFSTR("Local Address"));
261 flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress;
262 SCPrint(flags != 0, stdout, CFSTR(","));
263 }
264 if (flags & kSCNetworkReachabilityFlagsIsDirect) {
265 SCPrint(TRUE, stdout, CFSTR("Directly Reachable Address"));
266 flags &= ~kSCNetworkReachabilityFlagsIsDirect;
267 SCPrint(flags != 0, stdout, CFSTR(","));
268 }
269 #if TARGET_OS_IPHONE
270 if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
271 SCPrint(TRUE, stdout, CFSTR("WWAN"));
272 flags &= ~kSCNetworkReachabilityFlagsIsWWAN;
273 SCPrint(flags != 0, stdout, CFSTR(","));
274 }
275 #endif // TARGET_OS_IPHONE
276 if (flags != 0) {
277 SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
278 }
279 SCPrint(_sc_debug, stdout, CFSTR(")"));
280 } else {
281 SCPrint(_sc_debug, stdout, CFSTR(" ("));
282 SCPrint(TRUE, stdout, CFSTR("Not Reachable"));
283 SCPrint(_sc_debug, stdout, CFSTR(")"));
284 }
285 SCPrint(TRUE, stdout, CFSTR("\n"));
286
287 return;
288 }
289
290
291 __private_extern__
292 void
293 do_checkReachability(int argc, char **argv)
294 {
295 SCNetworkReachabilityRef target;
296
297 target = _setupReachability(argc, argv, NULL);
298 if (target == NULL) {
299 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
300 exit(1);
301 }
302
303 _printReachability(target);
304 CFRelease(target);
305 exit(0);
306 }
307
308
309 static void
310 callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
311 {
312 static int n = 3;
313 struct tm tm_now;
314 struct timeval tv_now;
315
316 (void)gettimeofday(&tv_now, NULL);
317 (void)localtime_r(&tv_now.tv_sec, &tm_now);
318
319 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
320 tm_now.tm_hour,
321 tm_now.tm_min,
322 tm_now.tm_sec,
323 tv_now.tv_usec / 1000);
324 SCPrint(TRUE, stdout, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n++, flags, (char *)info);
325 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
326 _printReachability(target);
327 SCPrint(TRUE, stdout, CFSTR("\n"));
328 return;
329 }
330
331
332 __private_extern__
333 void
334 do_watchReachability(int argc, char **argv)
335 {
336 SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
337 SCNetworkReachabilityRef target;
338 SCNetworkReachabilityRef target_async;
339
340 target = _setupReachability(argc, argv, NULL);
341 if (target == NULL) {
342 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
343 exit(1);
344 }
345
346 target_async = _setupReachability(argc, argv, &context);
347 if (target_async == NULL) {
348 SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
349 exit(1);
350 }
351
352 // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags()
353 // until after the "target" has been scheduled on a run loop. Otherwise, we'll
354 // end up making a synchronous DNS request and that's not what we want.
355 //
356 // But, to test the case were an application call SCNetworkReachabilityGetFlags()
357 // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable.
358 if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL) {
359 CFRelease(target_async);
360 target_async = CFRetain(target);
361 }
362
363 // Direct check of reachability
364 SCPrint(TRUE, stdout, CFSTR(" 0: direct\n"));
365 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
366 _printReachability(target);
367 CFRelease(target);
368 SCPrint(TRUE, stdout, CFSTR("\n"));
369
370 // schedule the target
371 SCPrint(TRUE, stdout, CFSTR(" 1: start\n"));
372 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
373 //_printReachability(target_async);
374 SCPrint(TRUE, stdout, CFSTR("\n"));
375
376 if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) {
377 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
378 exit(1);
379 }
380
381 #if !TARGET_OS_IPHONE
382 if (doDispatch) {
383 if (!SCNetworkReachabilitySetDispatchQueue(target_async, dispatch_get_current_queue())) {
384 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
385 exit(1);
386 }
387 } else
388 #endif // !TARGET_OS_IPHONE
389 {
390 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
391 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
392 exit(1);
393 }
394 }
395
396 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags()
397 // to get the current status. For "names", a DNS lookup has already been initiated.
398 SCPrint(TRUE, stdout, CFSTR(" 2: on %s\n"), doDispatch ? "dispatch queue" : "runloop");
399 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
400 _printReachability(target_async);
401 SCPrint(TRUE, stdout, CFSTR("\n"));
402
403 CFRunLoopRun();
404 exit(0);
405 }
406
407
408 __private_extern__
409 void
410 do_showDNSConfiguration(int argc, char **argv)
411 {
412 dns_config_t *dns_config;
413
414 dns_config = dns_configuration_copy();
415 if (dns_config) {
416 int n;
417
418 SCPrint(TRUE, stdout, CFSTR("DNS configuration\n"));
419
420 for (n = 0; n < dns_config->n_resolver; n++) {
421 int i;
422 dns_resolver_t *resolver = dns_config->resolver[n];
423
424 SCPrint(TRUE, stdout, CFSTR("\nresolver #%d\n"), n + 1);
425
426 if (resolver->domain != NULL) {
427 SCPrint(TRUE, stdout, CFSTR(" domain : %s\n"), resolver->domain);
428 }
429
430 for (i = 0; i < resolver->n_search; i++) {
431 SCPrint(TRUE, stdout, CFSTR(" search domain[%d] : %s\n"), i, resolver->search[i]);
432 }
433
434 for (i = 0; i < resolver->n_nameserver; i++) {
435 char buf[128];
436
437 _SC_sockaddr_to_string(resolver->nameserver[i], buf, sizeof(buf));
438 SCPrint(TRUE, stdout, CFSTR(" nameserver[%d] : %s\n"), i, buf);
439 }
440
441 for (i = 0; i < resolver->n_sortaddr; i++) {
442 char abuf[32];
443 char mbuf[32];
444
445 (void)inet_ntop(AF_INET, &resolver->sortaddr[i]->address, abuf, sizeof(abuf));
446 (void)inet_ntop(AF_INET, &resolver->sortaddr[i]->mask, mbuf, sizeof(mbuf));
447 SCPrint(TRUE, stdout, CFSTR(" sortaddr[%d] : %s/%s\n"), i, abuf, mbuf);
448 }
449
450 if (resolver->options != NULL) {
451 SCPrint(TRUE, stdout, CFSTR(" options : %s\n"), resolver->options);
452 }
453
454 if (resolver->port != 0) {
455 SCPrint(TRUE, stdout, CFSTR(" port : %hd\n"), resolver->port);
456 }
457
458 if (resolver->timeout != 0) {
459 SCPrint(TRUE, stdout, CFSTR(" timeout : %d\n"), resolver->timeout);
460 }
461
462 if (resolver->search_order != 0) {
463 SCPrint(TRUE, stdout, CFSTR(" order : %d\n"), resolver->search_order);
464 }
465 }
466
467 dns_configuration_free(dns_config);
468 } else {
469 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
470 }
471
472 exit(0);
473 }
474
475
476 __private_extern__
477 void
478 do_showProxyConfiguration(int argc, char **argv)
479 {
480 CFDictionaryRef proxies;
481
482 proxies = SCDynamicStoreCopyProxies(NULL);
483 if (proxies != NULL) {
484 SCPrint(TRUE, stdout, CFSTR("%@\n"), proxies);
485 CFRelease(proxies);
486 } else {
487 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
488 }
489
490 exit(0);
491 }
492
493
494 __private_extern__
495 void
496 do_snapshot(int argc, char **argv)
497 {
498 if (!SCDynamicStoreSnapshot(store)) {
499 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
500 }
501 return;
502 }
503
504
505 static void
506 waitKeyFound()
507 {
508 exit(0);
509 }
510
511
512 static void
513 waitTimeout(int sigraised)
514 {
515 exit(1);
516 }
517
518
519 __private_extern__
520 void
521 do_wait(char *waitKey, int timeout)
522 {
523 struct itimerval itv;
524 CFStringRef key;
525 CFMutableArrayRef keys;
526 Boolean ok;
527
528 store = SCDynamicStoreCreate(NULL, CFSTR("scutil (wait)"), waitKeyFound, NULL);
529 if (store == NULL) {
530 SCPrint(TRUE, stderr,
531 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
532 exit(1);
533 }
534
535 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
536
537 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
538 CFArrayAppendValue(keys, key);
539 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
540 CFRelease(keys);
541 if (!ok) {
542 SCPrint(TRUE, stderr,
543 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
544 exit(1);
545 }
546
547 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
548 if (!notifyRls) {
549 SCPrint(TRUE, stderr,
550 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
551 exit(1);
552 }
553
554 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
555
556 value = SCDynamicStoreCopyValue(store, key);
557 if (value) {
558 /* if the key is already present */
559 exit(0);
560 }
561 CFRelease(key);
562
563 if (timeout > 0) {
564 signal(SIGALRM, waitTimeout);
565 bzero(&itv, sizeof(itv));
566 itv.it_value.tv_sec = timeout;
567 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
568 SCPrint(TRUE, stderr,
569 CFSTR("setitimer() failed: %s\n"), strerror(errno));
570 exit(1);
571 }
572 }
573
574 CFRunLoopRun();
575 }
576
577 #ifdef TEST_DNS_CONFIGURATION_COPY
578
579 CFRunLoopSourceRef notifyRls = NULL;
580 SCDynamicStoreRef store = NULL;
581 CFPropertyListRef value = NULL;
582
583 int
584 main(int argc, char **argv)
585 {
586 do_showDNSConfiguration(argc, argv);
587 exit(0);
588 }
589
590 #endif // TEST_DNS_CONFIGURATION_COPY