]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/tests.c
configd-289.tar.gz
[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 (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
382 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
383 exit(1);
384 }
385
386 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags()
387 // to get the current status. For "names", a DNS lookup has already been initiated.
388 SCPrint(TRUE, stdout, CFSTR(" 2: on runloop\n"));
389 SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
390 _printReachability(target_async);
391 SCPrint(TRUE, stdout, CFSTR("\n"));
392
393 CFRunLoopRun();
394 exit(0);
395 }
396
397
398 __private_extern__
399 void
400 do_showDNSConfiguration(int argc, char **argv)
401 {
402 dns_config_t *dns_config;
403
404 dns_config = dns_configuration_copy();
405 if (dns_config) {
406 int n;
407
408 SCPrint(TRUE, stdout, CFSTR("DNS configuration\n"));
409
410 for (n = 0; n < dns_config->n_resolver; n++) {
411 int i;
412 dns_resolver_t *resolver = dns_config->resolver[n];
413
414 SCPrint(TRUE, stdout, CFSTR("\nresolver #%d\n"), n + 1);
415
416 if (resolver->domain != NULL) {
417 SCPrint(TRUE, stdout, CFSTR(" domain : %s\n"), resolver->domain);
418 }
419
420 for (i = 0; i < resolver->n_search; i++) {
421 SCPrint(TRUE, stdout, CFSTR(" search domain[%d] : %s\n"), i, resolver->search[i]);
422 }
423
424 for (i = 0; i < resolver->n_nameserver; i++) {
425 char buf[128];
426
427 _SC_sockaddr_to_string(resolver->nameserver[i], buf, sizeof(buf));
428 SCPrint(TRUE, stdout, CFSTR(" nameserver[%d] : %s\n"), i, buf);
429 }
430
431 for (i = 0; i < resolver->n_sortaddr; i++) {
432 char abuf[32];
433 char mbuf[32];
434
435 (void)inet_ntop(AF_INET, &resolver->sortaddr[i]->address, abuf, sizeof(abuf));
436 (void)inet_ntop(AF_INET, &resolver->sortaddr[i]->mask, mbuf, sizeof(mbuf));
437 SCPrint(TRUE, stdout, CFSTR(" sortaddr[%d] : %s/%s\n"), i, abuf, mbuf);
438 }
439
440 if (resolver->options != NULL) {
441 SCPrint(TRUE, stdout, CFSTR(" options : %s\n"), resolver->options);
442 }
443
444 if (resolver->port != 0) {
445 SCPrint(TRUE, stdout, CFSTR(" port : %hd\n"), resolver->port);
446 }
447
448 if (resolver->timeout != 0) {
449 SCPrint(TRUE, stdout, CFSTR(" timeout : %d\n"), resolver->timeout);
450 }
451
452 if (resolver->search_order != 0) {
453 SCPrint(TRUE, stdout, CFSTR(" order : %d\n"), resolver->search_order);
454 }
455 }
456
457 dns_configuration_free(dns_config);
458 } else {
459 SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
460 }
461
462 exit(0);
463 }
464
465
466 __private_extern__
467 void
468 do_showProxyConfiguration(int argc, char **argv)
469 {
470 CFDictionaryRef proxies;
471
472 proxies = SCDynamicStoreCopyProxies(NULL);
473 if (proxies != NULL) {
474 SCPrint(TRUE, stdout, CFSTR("%@\n"), proxies);
475 CFRelease(proxies);
476 } else {
477 SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
478 }
479
480 exit(0);
481 }
482
483
484 __private_extern__
485 void
486 do_snapshot(int argc, char **argv)
487 {
488 if (!SCDynamicStoreSnapshot(store)) {
489 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
490 }
491 return;
492 }
493
494
495 static void
496 waitKeyFound()
497 {
498 exit(0);
499 }
500
501
502 static void
503 waitTimeout(int sigraised)
504 {
505 exit(1);
506 }
507
508
509 __private_extern__
510 void
511 do_wait(char *waitKey, int timeout)
512 {
513 struct itimerval itv;
514 CFStringRef key;
515 CFMutableArrayRef keys;
516 Boolean ok;
517
518 store = SCDynamicStoreCreate(NULL, CFSTR("scutil (wait)"), waitKeyFound, NULL);
519 if (store == NULL) {
520 SCPrint(TRUE, stderr,
521 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
522 exit(1);
523 }
524
525 key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
526
527 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
528 CFArrayAppendValue(keys, key);
529 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
530 CFRelease(keys);
531 if (!ok) {
532 SCPrint(TRUE, stderr,
533 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
534 exit(1);
535 }
536
537 notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
538 if (!notifyRls) {
539 SCPrint(TRUE, stderr,
540 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
541 exit(1);
542 }
543
544 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
545
546 value = SCDynamicStoreCopyValue(store, key);
547 if (value) {
548 /* if the key is already present */
549 exit(0);
550 }
551 CFRelease(key);
552
553 if (timeout > 0) {
554 signal(SIGALRM, waitTimeout);
555 bzero(&itv, sizeof(itv));
556 itv.it_value.tv_sec = timeout;
557 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
558 SCPrint(TRUE, stderr,
559 CFSTR("setitimer() failed: %s\n"), strerror(errno));
560 exit(1);
561 }
562 }
563
564 CFRunLoopRun();
565 }
566
567 #ifdef TEST_DNS_CONFIGURATION_COPY
568
569 CFRunLoopSourceRef notifyRls = NULL;
570 SCDynamicStoreRef store = NULL;
571 CFPropertyListRef value = NULL;
572
573 int
574 main(int argc, char **argv)
575 {
576 do_showDNSConfiguration(argc, argv);
577 exit(0);
578 }
579
580 #endif // TEST_DNS_CONFIGURATION_COPY