]>
Commit | Line | Data |
---|---|---|
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 | |
61 | static Boolean resolver_bypass; | |
62 | ||
17d3ee29 A |
63 | |
64 | static 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 |
153 | static 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 | |
424 | static 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__ | |
453 | void | |
454 | do_checkReachability(int argc, char **argv) | |
455 | { | |
456 | SCNetworkReachabilityRef target; | |
457 | ||
458 | target = _setupReachability(argc, argv, NULL); | |
459 | if (target == NULL) { | |
460 | SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError())); | |
461 | exit(1); | |
462 | } | |
463 | ||
464 | _printReachability(target); | |
465 | CFRelease(target); | |
466 | exit(0); | |
467 | } | |
468 | ||
469 | ||
17d3ee29 A |
470 | static 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 |
518 | static 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 |
568 | static 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 | ||
584 | static void | |
585 | do_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__ | |
663 | void | |
664 | do_showNWI(int argc, char **argv) | |
665 | { | |
666 | nwi_state_t state; | |
667 | ||
668 | state = nwi_state_copy(); | |
669 | do_printNWI(argc, argv, state); | |
670 | if (state != NULL) { | |
671 | nwi_state_release(state); | |
672 | } else { | |
673 | exit(1); | |
674 | } | |
675 | ||
676 | exit(0); | |
677 | } | |
678 | ||
679 | ||
680 | __private_extern__ | |
681 | void | |
682 | do_watchNWI(int argc, char **argv) | |
683 | { | |
684 | nwi_state_t state; | |
685 | int status; | |
686 | int token; | |
687 | ||
688 | state = nwi_state_copy(); | |
689 | do_printNWI(argc, argv, state); | |
690 | if (state != NULL) { | |
691 | nwi_state_release(state); | |
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 |
726 | static void |
727 | callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) | |
728 | { | |
729 | static int n = 3; | |
730 | struct tm tm_now; | |
731 | struct timeval tv_now; | |
732 | ||
733 | (void)gettimeofday(&tv_now, NULL); | |
734 | (void)localtime_r(&tv_now.tv_sec, &tm_now); | |
735 | ||
736 | SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), | |
737 | tm_now.tm_hour, | |
738 | tm_now.tm_min, | |
739 | tm_now.tm_sec, | |
740 | tv_now.tv_usec / 1000); | |
741 | SCPrint(TRUE, stdout, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n++, flags, (char *)info); | |
742 | SCPrint(TRUE, stdout, CFSTR(" %@\n"), target); | |
743 | _printReachability(target); | |
744 | SCPrint(TRUE, stdout, CFSTR("\n")); | |
745 | return; | |
746 | } | |
747 | ||
748 | ||
749 | __private_extern__ | |
750 | void | |
751 | do_watchReachability(int argc, char **argv) | |
752 | { | |
753 | SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; | |
754 | SCNetworkReachabilityRef target; | |
755 | SCNetworkReachabilityRef target_async; | |
756 | ||
757 | target = _setupReachability(argc, argv, NULL); | |
758 | if (target == NULL) { | |
759 | SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError())); | |
760 | exit(1); | |
761 | } | |
762 | ||
763 | target_async = _setupReachability(argc, argv, &context); | |
764 | if (target_async == NULL) { | |
765 | SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError())); | |
766 | exit(1); | |
767 | } | |
768 | ||
769 | // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags() | |
770 | // until after the "target" has been scheduled on a run loop. Otherwise, we'll | |
771 | // end up making a synchronous DNS request and that's not what we want. | |
772 | // | |
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 |
822 | static void |
823 | do_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__ | |
846 | void | |
847 | do_showDNSConfiguration(int argc, char **argv) | |
848 | { | |
849 | dns_config_t *dns_config; | |
850 | ||
851 | dns_config = dns_configuration_copy(); | |
852 | do_printDNSConfiguration(argc, argv, dns_config); | |
853 | if (dns_config != NULL) { | |
854 | dns_configuration_free(dns_config); | |
855 | } else { | |
856 | exit(1); | |
857 | } | |
858 | ||
859 | exit(0); | |
860 | } | |
861 | ||
862 | ||
863 | __private_extern__ | |
864 | void | |
865 | do_watchDNSConfiguration(int argc, char **argv) | |
866 | { | |
867 | dns_config_t *dns_config; | |
868 | int status; | |
869 | int token; | |
870 | ||
871 | dns_config = dns_configuration_copy(); | |
872 | do_printDNSConfiguration(argc, argv, dns_config); | |
873 | if (dns_config != NULL) { | |
874 | dns_configuration_free(dns_config); | |
875 | } | |
876 | ||
877 | status = notify_register_dispatch(dns_configuration_notify_key(), | |
878 | &token, | |
879 | dispatch_get_main_queue(), | |
880 | ^(int token){ | |
881 | dns_config_t *dns_config; | |
882 | struct tm tm_now; | |
883 | struct timeval tv_now; | |
884 | ||
885 | (void)gettimeofday(&tv_now, NULL); | |
886 | (void)localtime_r(&tv_now.tv_sec, &tm_now); | |
887 | SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), | |
888 | tm_now.tm_hour, | |
889 | tm_now.tm_min, | |
890 | tm_now.tm_sec, | |
891 | tv_now.tv_usec / 1000); | |
892 | ||
893 | dns_config = dns_configuration_copy(); | |
894 | do_printDNSConfiguration(argc, argv, dns_config); | |
895 | if (dns_config != NULL) { | |
896 | dns_configuration_free(dns_config); | |
897 | } | |
898 | }); | |
899 | if (status != NOTIFY_STATUS_OK) { | |
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 |
909 | static void |
910 | showProxy(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__ |
929 | void | |
930 | do_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 |
1035 | void |
1036 | do_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__ |
1047 | void | |
1048 | do_renew(char *if_name) | |
1049 | { | |
1050 | CFArrayRef services; | |
1051 | Boolean ok = FALSE; | |
1052 | ||
1053 | if ((if_name == NULL) || (strlen(if_name) == 0)) { | |
1054 | SCPrint(TRUE, stderr, CFSTR("No interface name\n")); | |
1055 | exit(1); | |
1056 | } | |
1057 | ||
1058 | if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL) { | |
1059 | CFArrayRef interfaces; | |
1060 | ||
1061 | interfaces = SCNetworkInterfaceCopyAll(); | |
1062 | if (interfaces != NULL) { | |
1063 | CFIndex i; | |
1064 | CFStringRef match_name; | |
1065 | CFIndex n; | |
1066 | ||
1067 | match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII); | |
1068 | assert(match_name != NULL); | |
1069 | ||
1070 | n = CFArrayGetCount(interfaces); | |
1071 | for (i = 0; i < n; i++) { | |
1072 | CFStringRef bsd_name; | |
1073 | SCNetworkInterfaceRef interface; | |
1074 | ||
1075 | interface = CFArrayGetValueAtIndex(interfaces, i); | |
1076 | bsd_name = SCNetworkInterfaceGetBSDName(interface); | |
1077 | if (_SC_CFEqual(bsd_name, match_name)) { | |
1078 | // if match | |
1079 | ok = SCNetworkInterfaceForceConfigurationRefresh(interface); | |
1080 | if (!ok) { | |
1081 | int status; | |
1082 | ||
1083 | status = SCError(); | |
1084 | if (status != kSCStatusAccessError) { | |
1085 | SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(status)); | |
1086 | exit(1); | |
1087 | } | |
1088 | ||
1089 | // ... and if can't write the SCDynamicStore, try w/prefs | |
1090 | } | |
1091 | ||
1092 | break; | |
1093 | } | |
1094 | } | |
1095 | ||
1096 | CFRelease(match_name); | |
1097 | CFRelease(interfaces); | |
1098 | } | |
1099 | ||
1100 | if (ok) { | |
1101 | exit(0); | |
1102 | } | |
1103 | } | |
1104 | ||
1105 | do_prefs_init(); /* initialization */ | |
1106 | do_prefs_open(0, NULL); /* open default prefs */ | |
1107 | ||
1108 | services = SCNetworkServiceCopyAll(prefs); | |
1109 | if (services != NULL) { | |
1110 | CFIndex i; | |
1111 | CFStringRef match_name; | |
1112 | CFIndex n; | |
1113 | ||
1114 | match_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII); | |
1115 | assert(match_name != NULL); | |
1116 | ||
1117 | n = CFArrayGetCount(services); | |
1118 | for (i = 0; i < n; i++) { | |
1119 | CFStringRef bsd_name; | |
1120 | SCNetworkInterfaceRef interface; | |
1121 | SCNetworkServiceRef service; | |
1122 | ||
1123 | service = CFArrayGetValueAtIndex(services, i); | |
1124 | interface = SCNetworkServiceGetInterface(service); | |
1125 | if (interface == NULL) { | |
1126 | // if no interface | |
1127 | continue; | |
1128 | } | |
1129 | ||
1130 | bsd_name = SCNetworkInterfaceGetBSDName(interface); | |
1131 | if (_SC_CFEqual(bsd_name, match_name)) { | |
1132 | // if match | |
1133 | ok = SCNetworkInterfaceForceConfigurationRefresh(interface); | |
1134 | if (!ok) { | |
1135 | SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(SCError())); | |
1136 | exit(1); | |
1137 | } | |
1138 | ||
1139 | break; | |
1140 | } | |
1141 | } | |
1142 | ||
1143 | CFRelease(match_name); | |
1144 | CFRelease(services); | |
1145 | } | |
1146 | ||
1147 | if (!ok) { | |
1148 | SCPrint(TRUE, stderr, CFSTR("No interface\n")); | |
1149 | exit(1); | |
1150 | } | |
1151 | ||
1152 | _prefs_close(); | |
1153 | exit(0); | |
1154 | } | |
1155 | ||
1156 | ||
0fae82ee A |
1157 | static void |
1158 | waitKeyFound() | |
1159 | { | |
1160 | exit(0); | |
1161 | } | |
1162 | ||
1163 | ||
1164 | static void | |
1165 | waitTimeout(int sigraised) | |
1166 | { | |
1167 | exit(1); | |
1168 | } | |
1169 | ||
5958d7c0 | 1170 | |
dbf6a266 | 1171 | __private_extern__ |
5958d7c0 | 1172 | void |
0fae82ee | 1173 | do_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 | 1231 | Boolean doDispatch = FALSE; |
edebe297 A |
1232 | CFRunLoopSourceRef notifyRls = NULL; |
1233 | SCDynamicStoreRef store = NULL; | |
1234 | CFPropertyListRef value = NULL; | |
a40a14f8 | 1235 | |
edebe297 A |
1236 | int |
1237 | main(int argc, char **argv) | |
1238 | { | |
5e9ce69e A |
1239 | dns_config_t *dns_config; |
1240 | ||
1241 | fprintf(stdout, "copy configuration\n"); | |
1242 | dns_config = dns_configuration_copy(); | |
1243 | if (dns_config != NULL) { | |
1244 | ||
1245 | fprintf(stdout, "sleeping for 120 seconds\n"); | |
1246 | sleep(120); | |
1247 | ||
1248 | fprintf(stdout, "sending ack\n"); | |
1249 | _dns_configuration_ack(dns_config, "TEST_DNS_CONFIGURATION"); | |
1250 | ||
1251 | fprintf(stdout, "sleeping for 120 seconds\n"); | |
1252 | sleep(120); | |
1253 | ||
1254 | dns_configuration_free(dns_config); | |
1255 | } | |
1256 | ||
9de8ab86 | 1257 | do_showDNSConfiguration(argc, argv); |
edebe297 A |
1258 | exit(0); |
1259 | } | |
1260 | ||
5e9ce69e | 1261 | #endif // TEST_DNS_CONFIGURATION |