2 * Copyright (c) 2000, 2001, 2003-2018, 2020 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
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
32 * June 1, 2001 Allan Nathanson <ajn@apple.com>
33 * - public API conversion
35 * November 9, 2000 Allan Nathanson <ajn@apple.com>
44 #include <netdb_async.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
51 #define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
54 #include "dnsinfo_internal.h"
55 #include "dnsinfo_logging.h"
57 #include <network_information.h>
58 #include "network_state_information_logging.h"
59 #include "network_state_information_priv.h"
61 #include "SCNetworkReachabilityInternal.h"
63 #include <CommonCrypto/CommonDigest.h>
66 static Boolean resolver_bypass
;
69 static CF_RETURNS_RETAINED CFMutableDictionaryRef
70 _setupReachabilityOptions(int argc
, char **argv
, const char *interface
)
73 CFMutableDictionaryRef options
;
75 options
= CFDictionaryCreateMutable(NULL
,
77 &kCFTypeDictionaryKeyCallBacks
,
78 &kCFTypeDictionaryValueCallBacks
);
80 for (i
= 0; i
< argc
; i
++) {
81 if (strcasecmp(argv
[i
], "interface") == 0) {
83 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
93 if (strcasecmp(argv
[i
], "server") == 0) {
94 CFDictionarySetValue(options
,
95 kSCNetworkReachabilityOptionServerBypass
,
98 } else if (strcasecmp(argv
[i
], "no-server") == 0) {
99 CFDictionarySetValue(options
,
100 kSCNetworkReachabilityOptionServerBypass
,
105 if (strcasecmp(argv
[i
], "no-connection-on-demand") == 0) {
106 CFDictionarySetValue(options
,
107 kSCNetworkReachabilityOptionConnectionOnDemandBypass
,
112 if (strcasecmp(argv
[i
], "no-resolve") == 0) {
113 CFDictionarySetValue(options
,
114 kSCNetworkReachabilityOptionResolverBypass
,
116 resolver_bypass
= TRUE
;
120 if (strcasecmp(argv
[i
], "ptr") == 0) {
121 CFDictionarySetValue(options
,
122 kSCNetworkReachabilityOptionPTRAddress
,
127 if (strlen(argv
[i
]) == 0) {
131 SCPrint(TRUE
, stderr
, CFSTR("Unrecognized option: %s\n"), argv
[i
]);
136 if (interface
!= NULL
) {
139 if (if_nametoindex(interface
) == 0) {
140 SCPrint(TRUE
, stderr
, CFSTR("No interface: %s\n"), interface
);
144 str
= CFStringCreateWithCString(NULL
, interface
, kCFStringEncodingASCII
);
145 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionInterface
, str
);
149 if (CFDictionaryGetCount(options
) == 0) {
158 static SCNetworkReachabilityRef
159 _setupReachability(int argc
, char **argv
, SCNetworkReachabilityContext
*context
)
161 const char *ip_address
= argv
[0];
162 char *ip_addressN
= NULL
;
163 const char *interface
;
164 CFMutableDictionaryRef options
= NULL
;
165 const char *remote_address
= NULL
;
166 char *remote_addressN
= NULL
;
167 const char *remote_interface
;
168 struct sockaddr_in sin
;
169 struct sockaddr_in6 sin6
;
170 SCNetworkReachabilityRef target
= NULL
;
172 memset(&sin
, 0, sizeof(sin
));
173 sin
.sin_len
= sizeof(sin
);
174 sin
.sin_family
= AF_INET
;
176 memset(&sin6
, 0, sizeof(sin6
));
177 sin6
.sin6_len
= sizeof(sin6
);
178 sin6
.sin6_family
= AF_INET6
;
180 interface
= strchr(ip_address
, '%');
181 if (interface
!= NULL
) {
182 ip_addressN
= strdup(ip_address
);
183 ip_addressN
[interface
- ip_address
] = '\0';
184 ip_address
= ip_addressN
;
188 if ((argc
> 1) && (strlen(argv
[1]) > 0)) {
189 remote_address
= argv
[1];
191 remote_interface
= strchr(remote_address
, '%');
192 if (remote_interface
!= NULL
) {
193 remote_addressN
= strdup(remote_address
);
194 remote_addressN
[remote_interface
- remote_address
] = '\0';
195 remote_address
= remote_addressN
;
200 if (inet_aton(ip_address
, &sin
.sin_addr
) == 1) {
201 struct sockaddr_in r_sin
;
204 memset(&r_sin
, 0, sizeof(r_sin
));
205 r_sin
.sin_len
= sizeof(r_sin
);
206 r_sin
.sin_family
= AF_INET
;
210 || (remote_address
== NULL
)
211 || (inet_aton(remote_address
, &r_sin
.sin_addr
) == 0)) {
213 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, interface
);
215 if (options
== NULL
) {
216 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin
);
217 if (context
!= NULL
) {
218 context
->info
= "by address";
223 data
= CFDataCreate(NULL
, (const UInt8
*)&sin
, sizeof(sin
));
224 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
227 if (context
!= NULL
) {
228 if (CFDictionaryContainsKey(options
,
229 kSCNetworkReachabilityOptionInterface
)) {
230 if (CFDictionaryGetCount(options
) == 2) {
231 context
->info
= "by address w/scope";
233 context
->info
= "by address w/scope and options";
236 context
->info
= "by address w/options";
241 if (remote_interface
!= NULL
) {
242 if ((interface
!= NULL
) && (strcmp(interface
, remote_interface
) != 0)) {
243 SCPrint(TRUE
, stderr
,
244 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
250 interface
= remote_interface
;
253 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, interface
);
254 if (options
== NULL
) {
255 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
256 (struct sockaddr
*)&sin
,
257 (struct sockaddr
*)&r_sin
);
258 if (context
!= NULL
) {
259 context
->info
= "by address pair";
264 data
= CFDataCreate(NULL
, (const UInt8
*)&sin
, sizeof(sin
));
265 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionLocalAddress
, data
);
267 data
= CFDataCreate(NULL
, (const UInt8
*)&r_sin
, sizeof(r_sin
));
268 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
271 if (context
!= NULL
) {
272 if (CFDictionaryContainsKey(options
,
273 kSCNetworkReachabilityOptionInterface
)) {
274 if (CFDictionaryGetCount(options
) == 3) {
275 context
->info
= "by address pair w/scope";
277 context
->info
= "by address pair w/scope and options";
280 context
->info
= "by address pair w/options";
285 } else if (inet_pton(AF_INET6
, ip_address
, &sin6
.sin6_addr
) == 1) {
286 struct sockaddr_in6 r_sin6
;
288 if (interface
!= NULL
) {
289 sin6
.sin6_scope_id
= if_nametoindex(interface
);
293 memset(&r_sin6
, 0, sizeof(r_sin6
));
294 r_sin6
.sin6_len
= sizeof(r_sin6
);
295 r_sin6
.sin6_family
= AF_INET6
;
299 || (remote_address
== NULL
)
300 || (inet_pton(AF_INET6
, remote_address
, &r_sin6
.sin6_addr
) == 0)) {
302 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, NULL
);
304 if (options
== NULL
) {
305 target
= SCNetworkReachabilityCreateWithAddress(NULL
, (struct sockaddr
*)&sin6
);
306 if (context
!= NULL
) {
307 context
->info
= "by (v6) address";
312 data
= CFDataCreate(NULL
, (const UInt8
*)&sin6
, sizeof(sin6
));
313 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
316 if (context
!= NULL
) {
317 context
->info
= "by (v6) address w/options";
321 if (remote_interface
!= NULL
) {
322 r_sin6
.sin6_scope_id
= if_nametoindex(remote_interface
);
324 if ((interface
!= NULL
) && (strcmp(interface
, remote_interface
) != 0)) {
325 SCPrint(TRUE
, stderr
,
326 CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
333 options
= _setupReachabilityOptions(argc
- 2, argv
+ 2, NULL
);
334 if (options
== NULL
) {
335 target
= SCNetworkReachabilityCreateWithAddressPair(NULL
,
336 (struct sockaddr
*)&sin6
,
337 (struct sockaddr
*)&r_sin6
);
338 if (context
!= NULL
) {
339 context
->info
= "by (v6) address pair";
344 data
= CFDataCreate(NULL
, (const UInt8
*)&sin6
, sizeof(sin6
));
345 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionLocalAddress
, data
);
347 data
= CFDataCreate(NULL
, (const UInt8
*)&r_sin6
, sizeof(r_sin6
));
348 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
, data
);
351 if (context
!= NULL
) {
352 context
->info
= "by (v6) address pair w/options";
358 target
= SCNetworkReachabilityCreateWithName(NULL
, argv
[0]);
359 if (context
!= NULL
) {
360 context
->info
= "by name";
363 options
= _setupReachabilityOptions(argc
- 1, argv
+ 1, NULL
);
364 if (options
== NULL
) {
365 target
= SCNetworkReachabilityCreateWithName(NULL
, argv
[0]);
366 if (context
!= NULL
) {
367 context
->info
= "by name";
372 str
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
373 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionNodeName
, str
);
376 if (context
!= NULL
) {
377 context
->info
= "by name w/options";
383 if (ip_addressN
!= NULL
) {
387 if (remote_addressN
!= NULL
) {
388 free(remote_addressN
);
391 if ((target
== NULL
) && (options
!= NULL
)) {
392 if (CFDictionaryContainsKey(options
, kSCNetworkReachabilityOptionPTRAddress
)) {
395 address
= CFDictionaryGetValue(options
, kSCNetworkReachabilityOptionRemoteAddress
);
396 if (address
== NULL
) {
397 SCPrint(TRUE
, stderr
, CFSTR("No address\n"));
400 CFDictionarySetValue(options
, kSCNetworkReachabilityOptionPTRAddress
, address
);
401 CFDictionaryRemoveValue(options
, kSCNetworkReachabilityOptionRemoteAddress
);
403 if (context
!= NULL
) {
404 CFIndex n
= CFDictionaryGetCount(options
);
407 context
->info
= "by PTR";
408 } else if (CFDictionaryContainsKey(options
,
409 kSCNetworkReachabilityOptionInterface
)) {
411 context
->info
= "by PTR w/scope";
413 context
->info
= "by PTR w/scope and options";
416 context
->info
= "by PTR w/options";
421 target
= SCNetworkReachabilityCreateWithOptions(NULL
, options
);
430 _printReachability(SCNetworkReachabilityRef target
)
432 SCNetworkReachabilityFlags flags
;
436 ok
= SCNetworkReachabilityGetFlags(target
, &flags
);
438 SCPrint(TRUE
, stderr
, CFSTR(" could not determine reachability, %s\n"), SCErrorString(SCError()));
442 __SCNetworkReachability_flags_string(flags
, _sc_debug
, flags_str
, sizeof(flags_str
));
443 SCPrint(TRUE
, stdout
,
444 _sc_debug
? CFSTR("flags = %s\n") : CFSTR("%s\n"),
447 if (resolver_bypass
&& _sc_debug
) {
450 if_index
= SCNetworkReachabilityGetInterfaceIndex(target
);
451 SCPrint(TRUE
, stdout
, CFSTR("interface index = %d\n"), if_index
);
460 do_checkReachability(int argc
, char **argv
)
462 SCNetworkReachabilityRef target
;
464 target
= _setupReachability(argc
, argv
, NULL
);
465 if (target
== NULL
) {
466 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
470 _printReachability(target
);
477 do_printNWI(int argc
, char **argv
, nwi_state_t state
)
480 SCPrint(TRUE
, stdout
, CFSTR("No network information\n"));
485 nwi_ifstate_t ifstate
;
487 ifstate
= nwi_state_get_ifstate(state
, argv
[0]);
488 if (ifstate
!= NULL
) {
492 _nwi_ifstate_log(ifstate
, _sc_debug
, NULL
);
494 alias_af
= (ifstate
->af
== AF_INET
) ? AF_INET6
: AF_INET
;
495 alias
= nwi_ifstate_get_alias(ifstate
, alias_af
);
497 SCPrint(TRUE
, stdout
, CFSTR("\n"));
498 _nwi_ifstate_log(alias
, _sc_debug
, NULL
);
501 SCPrint(TRUE
, stdout
, CFSTR("No network information (for %s)\n"), argv
[0]);
506 _nwi_state_log(state
, _sc_debug
, NULL
);
513 do_showNWI(int argc
, char **argv
)
517 state
= nwi_state_copy();
518 do_printNWI(argc
, argv
, state
);
520 nwi_state_release(state
);
531 do_watchNWI(int argc
, char **argv
)
537 state
= nwi_state_copy();
538 do_printNWI(argc
, argv
, state
);
540 nwi_state_release(state
);
543 status
= notify_register_dispatch(nwi_state_get_notify_key(),
545 dispatch_get_main_queue(),
547 #pragma unused(token)
550 struct timeval tv_now
;
552 (void)gettimeofday(&tv_now
, NULL
);
553 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
554 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
558 tv_now
.tv_usec
/ 1000);
560 state
= nwi_state_copy();
561 do_printNWI(argc
, argv
, state
);
563 nwi_state_release(state
);
566 if (status
!= NOTIFY_STATUS_OK
) {
567 SCPrint(TRUE
, stderr
, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), status
);
577 callout(SCNetworkReachabilityRef target
, SCNetworkReachabilityFlags flags
, void *info
)
581 struct timeval tv_now
;
583 (void)gettimeofday(&tv_now
, NULL
);
584 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
586 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
590 tv_now
.tv_usec
/ 1000);
591 SCPrint(TRUE
, stdout
, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n
++, flags
, (char *)info
);
592 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
593 _printReachability(target
);
594 SCPrint(TRUE
, stdout
, CFSTR("\n"));
601 do_watchReachability(int argc
, char **argv
)
603 SCNetworkReachabilityContext context
= { 0, NULL
, NULL
, NULL
, NULL
};
604 SCNetworkReachabilityRef target
;
605 SCNetworkReachabilityRef target_async
;
607 target
= _setupReachability(argc
, argv
, NULL
);
608 if (target
== NULL
) {
609 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
613 target_async
= _setupReachability(argc
, argv
, &context
);
614 if (target_async
== NULL
) {
615 SCPrint(TRUE
, stderr
, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
619 // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags()
620 // until after the "target" has been scheduled on a run loop. Otherwise, we'll
621 // end up making a synchronous DNS request and that's not what we want.
623 // To test the case were an application first calls SCNetworkReachabilityGetFlags()
624 // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable.
625 if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL
) {
626 CFRelease(target_async
);
627 target_async
= CFRetain(target
);
630 // Direct check of reachability
631 SCPrint(TRUE
, stdout
, CFSTR(" 0: direct\n"));
632 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target
);
633 _printReachability(target
);
635 SCPrint(TRUE
, stdout
, CFSTR("\n"));
637 // schedule the target
638 SCPrint(TRUE
, stdout
, CFSTR(" 1: start\n"));
639 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
640 // _printReachability(target_async);
641 SCPrint(TRUE
, stdout
, CFSTR("\n"));
643 if (!SCNetworkReachabilitySetCallback(target_async
, callout
, &context
)) {
644 printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
649 if (!SCNetworkReachabilitySetDispatchQueue(target_async
, dispatch_get_main_queue())) {
650 printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
654 if (!SCNetworkReachabilityScheduleWithRunLoop(target_async
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
655 printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
660 // Note: now that we are scheduled on a run loop we can call SCNetworkReachabilityGetFlags()
661 // to get the current status. For "names", a DNS lookup has already been initiated.
662 SCPrint(TRUE
, stdout
, CFSTR(" 2: on %s\n"), doDispatch
? "dispatch queue" : "runloop");
663 SCPrint(TRUE
, stdout
, CFSTR(" %@\n"), target_async
);
664 _printReachability(target_async
);
665 SCPrint(TRUE
, stdout
, CFSTR("\n"));
673 do_printDNSConfiguration(int argc
, char **argv
, dns_config_t
*dns_config
)
679 if (dns_config
== NULL
) {
680 SCPrint(TRUE
, stdout
, CFSTR("No DNS configuration available\n"));
684 _sc_log_save
= _sc_log
;
685 _sc_log
= kSCLogDestinationFile
;
686 _dns_configuration_log(dns_config
, _sc_debug
, NULL
);
687 _sc_log
= _sc_log_save
;
690 SCPrint(TRUE
, stdout
, CFSTR("\ngeneration = %llu\n"), dns_config
->generation
);
699 do_showDNSConfiguration(int argc
, char **argv
)
701 dns_config_t
*dns_config
;
703 dns_config
= dns_configuration_copy();
704 do_printDNSConfiguration(argc
, argv
, dns_config
);
705 if (dns_config
!= NULL
) {
706 dns_configuration_free(dns_config
);
717 do_watchDNSConfiguration(int argc
, char **argv
)
719 dns_config_t
*dns_config
;
723 dns_config
= dns_configuration_copy();
724 do_printDNSConfiguration(argc
, argv
, dns_config
);
725 if (dns_config
!= NULL
) {
726 dns_configuration_free(dns_config
);
729 status
= notify_register_dispatch(dns_configuration_notify_key(),
731 dispatch_get_main_queue(),
733 #pragma unused(token)
734 dns_config_t
*dns_config
;
736 struct timeval tv_now
;
738 (void)gettimeofday(&tv_now
, NULL
);
739 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
740 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
744 tv_now
.tv_usec
/ 1000);
746 dns_config
= dns_configuration_copy();
747 do_printDNSConfiguration(argc
, argv
, dns_config
);
748 if (dns_config
!= NULL
) {
749 dns_configuration_free(dns_config
);
752 if (status
!= NOTIFY_STATUS_OK
) {
753 SCPrint(TRUE
, stderr
, CFSTR("notify_register_dispatch() failed for nwi changes, status=%u\n"), status
);
763 showProxy(CFDictionaryRef proxy
)
765 CFMutableDictionaryRef cleaned
= NULL
;
768 cleaned
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
769 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesScoped
);
770 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesServices
);
771 CFDictionaryRemoveValue(cleaned
, kSCPropNetProxiesSupplemental
);
775 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), proxy
);
776 if (cleaned
!= NULL
) CFRelease(cleaned
);
783 do_showProxyConfiguration(int argc
, char **argv
)
785 CFDictionaryRef proxies
;
787 if (getenv("BYPASS_GLOBAL_PROXY") != NULL
) {
788 CFMutableDictionaryRef options
;
790 options
= CFDictionaryCreateMutable(NULL
, 0,
791 &kCFTypeDictionaryKeyCallBacks
,
792 &kCFTypeDictionaryValueCallBacks
);
793 CFDictionaryAddValue(options
, kSCProxiesNoGlobal
, kCFBooleanTrue
);
794 proxies
= SCDynamicStoreCopyProxiesWithOptions(NULL
, options
);
797 proxies
= SCDynamicStoreCopyProxies(NULL
);
800 if (proxies
!= NULL
) {
801 CFStringRef interface
= NULL
;
802 CFStringRef server
= NULL
;
805 if (strcasecmp(argv
[0], "interface") == 0) {
810 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
814 if (if_nametoindex(argv
[0]) == 0) {
815 SCPrint(TRUE
, stderr
, CFSTR("No interface: %s\n"), argv
[0]);
819 interface
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
823 if (server
!= NULL
) {
827 server
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
833 if ((server
!= NULL
) || (interface
!= NULL
)) {
836 matching
= SCNetworkProxiesCopyMatching(proxies
, server
, interface
);
837 if (matching
!= NULL
) {
841 if (server
!= NULL
) {
842 if (interface
!= NULL
) {
843 SCPrint(TRUE
, stdout
,
844 CFSTR("server = %@, interface = %@\n"),
848 SCPrint(TRUE
, stdout
,
849 CFSTR("server = %@\n"),
853 SCPrint(TRUE
, stdout
,
854 CFSTR("interface = %@\n"),
858 n
= CFArrayGetCount(matching
);
859 for (i
= 0; i
< n
; i
++) {
860 CFDictionaryRef proxy
;
862 proxy
= CFArrayGetValueAtIndex(matching
, i
);
863 SCPrint(TRUE
, stdout
, CFSTR("\nproxy #%ld\n"), i
+ 1);
869 SCPrint(TRUE
, stdout
, CFSTR("No matching proxy configurations\n"));
875 if (interface
!= NULL
) CFRelease(interface
);
876 if (server
!= NULL
) CFRelease(server
);
879 SCPrint(TRUE
, stdout
, CFSTR("No proxy configuration available\n"));
888 do_snapshot(int argc
, char **argv
)
893 CFDictionaryRef dict
;
895 CFMutableArrayRef patterns
;
897 fd
= open(argv
[0], O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
, 0644);
899 SCPrint(TRUE
, stdout
, CFSTR("open() failed: %s\n"), strerror(errno
));
903 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
904 CFArrayAppendValue(patterns
, CFSTR(".*"));
905 dict
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
910 xmlData
= CFPropertyListCreateData(NULL
, dict
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
912 if (xmlData
!= NULL
) {
913 (void) write(fd
, CFDataGetBytePtr(xmlData
), CFDataGetLength(xmlData
));
916 SC_log(LOG_NOTICE
, "CFPropertyListCreateData() failed");
919 if (SCError() == kSCStatusOK
) {
920 SCPrint(TRUE
, stdout
, CFSTR("No SCDynamicStore content\n"));
922 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
927 #if !TARGET_OS_SIMULATOR
928 if (geteuid() != 0) {
929 SCPrint(TRUE
, stdout
, CFSTR("Need to be \"root\" to capture snapshot\n"));
931 #endif // !TARGET_OS_SIMULATOR
932 if (!SCDynamicStoreSnapshot(store
)) {
933 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
943 do_renew(char *if_name
)
948 if ((if_name
== NULL
) || (strlen(if_name
) == 0)) {
949 SCPrint(TRUE
, stderr
, CFSTR("No interface name\n"));
953 if (getenv("ATTEMPT_DHCP_RENEW_WITH_SCDYNAMICSTORE") != NULL
) {
954 CFArrayRef interfaces
;
956 interfaces
= SCNetworkInterfaceCopyAll();
957 if (interfaces
!= NULL
) {
959 CFStringRef match_name
;
962 match_name
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
963 assert(match_name
!= NULL
);
965 n
= CFArrayGetCount(interfaces
);
966 for (i
= 0; i
< n
; i
++) {
967 CFStringRef bsd_name
;
968 SCNetworkInterfaceRef interface
;
970 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
971 bsd_name
= SCNetworkInterfaceGetBSDName(interface
);
972 if (_SC_CFEqual(bsd_name
, match_name
)) {
974 ok
= SCNetworkInterfaceForceConfigurationRefresh(interface
);
979 if (status
!= kSCStatusAccessError
) {
980 SCPrint(TRUE
, stderr
, CFSTR("%s\n"), SCErrorString(status
));
984 // ... and if can't write the SCDynamicStore, try w/prefs
991 CFRelease(match_name
);
992 CFRelease(interfaces
);
1000 do_prefs_init(); /* initialization */
1001 do_prefs_open(0, NULL
); /* open default prefs */
1003 services
= SCNetworkServiceCopyAll(prefs
);
1004 if (services
!= NULL
) {
1006 CFStringRef match_name
;
1009 match_name
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
1010 assert(match_name
!= NULL
);
1012 n
= CFArrayGetCount(services
);
1013 for (i
= 0; i
< n
; i
++) {
1014 CFStringRef bsd_name
;
1015 SCNetworkInterfaceRef interface
;
1016 SCNetworkServiceRef service
;
1018 service
= CFArrayGetValueAtIndex(services
, i
);
1019 interface
= SCNetworkServiceGetInterface(service
);
1020 if (interface
== NULL
) {
1025 bsd_name
= SCNetworkInterfaceGetBSDName(interface
);
1026 if (_SC_CFEqual(bsd_name
, match_name
)) {
1028 ok
= SCNetworkInterfaceForceConfigurationRefresh(interface
);
1030 SCPrint(TRUE
, stderr
, CFSTR("%s\n"), SCErrorString(SCError()));
1038 CFRelease(match_name
);
1039 CFRelease(services
);
1043 SCPrint(TRUE
, stderr
, CFSTR("No interface\n"));
1060 waitTimeout(int sigraised
)
1062 #pragma unused(sigraised)
1069 do_wait(char *waitKey
, int timeout
)
1071 struct itimerval itv
;
1073 CFMutableArrayRef keys
;
1076 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil (wait)"), waitKeyFound
, NULL
);
1077 if (store
== NULL
) {
1078 SCPrint(TRUE
, stderr
,
1079 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1083 key
= CFStringCreateWithCString(NULL
, waitKey
, kCFStringEncodingUTF8
);
1085 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1086 CFArrayAppendValue(keys
, key
);
1087 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
1090 SCPrint(TRUE
, stderr
,
1091 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1095 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1097 SCPrint(TRUE
, stderr
,
1098 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1102 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
1104 value
= SCDynamicStoreCopyValue(store
, key
);
1106 /* if the key is already present */
1112 signal(SIGALRM
, waitTimeout
);
1113 memset(&itv
, 0, sizeof(itv
));
1114 itv
.it_value
.tv_sec
= timeout
;
1115 if (setitimer(ITIMER_REAL
, &itv
, NULL
) == -1) {
1116 SCPrint(TRUE
, stderr
,
1117 CFSTR("setitimer() failed: %s\n"), strerror(errno
));
1126 ** "scutil --advisory <ifname> [ set | -W ]"
1129 timestamp_fprintf(FILE * f
, const char * message
, ...)
1136 (void)gettimeofday(&tv
, NULL
);
1138 (void)localtime_r(&t
, &tm
);
1140 va_start(ap
, message
);
1141 fprintf(f
, "%04d/%02d/%02d %2d:%02d:%02d.%06d ",
1142 tm
.tm_year
+ 1900, tm
.tm_mon
+ 1, tm
.tm_mday
,
1143 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
,
1145 vfprintf(f
, message
, ap
);
1150 advisoryCheck(SCNetworkInterfaceRef interface
, Boolean show_timestamp
)
1152 if (show_timestamp
) {
1153 timestamp_fprintf(stdout
, "");
1156 SCNetworkInterfaceAdvisoryIsSet(interface
) ? "" : "not ");
1160 advisoryChanged(SCDynamicStoreRef session
, CFArrayRef changes
,
1163 #pragma unused(session, changes)
1164 SCNetworkInterfaceRef interface
= (SCNetworkInterfaceRef
)info
;
1166 advisoryCheck(interface
, TRUE
);
1171 advisoryWatch(SCNetworkInterfaceRef interface
)
1173 SCDynamicStoreContext context
= {
1174 .info
= (void *)interface
,
1177 CFMutableArrayRef keys
;
1180 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil (advisory)"), advisoryChanged
, &context
);
1181 if (store
== NULL
) {
1182 SCPrint(TRUE
, stderr
,
1183 CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
1186 key
= SCNetworkInterfaceCopyAdvisoryNotificationKey(interface
);
1187 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1188 CFArrayAppendValue(keys
, key
);
1190 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
1193 SCPrint(TRUE
, stderr
,
1194 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
1197 notifyRls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1199 SCPrint(TRUE
, stderr
,
1200 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
1203 CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls
, kCFRunLoopDefaultMode
);
1208 do_advisory(const char * ifname
, Boolean watch
, int argc
, char **argv
)
1210 CFStringRef ifname_cf
;
1211 SCNetworkInterfaceRef interface
;
1213 ifname_cf
= CFStringCreateWithCString(NULL
, ifname
, kCFStringEncodingUTF8
);
1214 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, ifname_cf
, kIncludeAllVirtualInterfaces
);
1215 CFRelease(ifname_cf
);
1216 if (interface
== NULL
) {
1217 fprintf(stderr
, "Failed to instantiate SCNetworkInterfaceRef\n");
1221 SCNetworkInterfaceAdvisory advisory
= kSCNetworkInterfaceAdvisoryUplinkIssue
;
1223 if (strcasecmp(argv
[0], "set") != 0) {
1225 "usage: scutil --advisory <ifname> "
1226 "[ set [ linklayer | uplink ] | -W ]\n");
1230 if (strcasecmp(argv
[1], "uplink") == 0) {
1231 advisory
= kSCNetworkInterfaceAdvisoryUplinkIssue
;
1232 } else if (strcasecmp(argv
[1], "linklayer") == 0) {
1233 advisory
= kSCNetworkInterfaceAdvisoryLinkLayerIssue
;
1236 "Bad advisory '%s', must be either 'uplink' or 'linklayer'\n",
1241 SCNetworkInterfaceSetAdvisory(interface
, advisory
, CFSTR("Because"));
1244 advisoryCheck(interface
, watch
);
1246 advisoryWatch(interface
);
1254 #ifdef TEST_DNS_CONFIGURATION
1256 Boolean doDispatch
= FALSE
;
1257 CFRunLoopSourceRef notifyRls
= NULL
;
1258 SCDynamicStoreRef store
= NULL
;
1259 CFPropertyListRef value
= NULL
;
1262 main(int argc
, char **argv
)
1264 dns_config_t
*dns_config
;
1266 fprintf(stdout
, "copy configuration\n");
1267 dns_config
= dns_configuration_copy();
1268 if (dns_config
!= NULL
) {
1270 fprintf(stdout
, "sleeping for 120 seconds\n");
1273 fprintf(stdout
, "sending ack\n");
1274 _dns_configuration_ack(dns_config
, "TEST_DNS_CONFIGURATION");
1276 fprintf(stdout
, "sleeping for 120 seconds\n");
1279 dns_configuration_free(dns_config
);
1282 do_showDNSConfiguration(argc
, argv
);
1286 #endif // TEST_DNS_CONFIGURATION