#include "scutil.h"
#include "tests.h"
#include <netdb.h>
#include <netdb_async.h>
#include <sys/time.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dnsinfo.h>
#include <network_information.h>
#include "SCNetworkReachabilityInternal.h"
static Boolean resolver_bypass;
static CF_RETURNS_RETAINED CFMutableDictionaryRef
_setupReachabilityOptions(int argc, char **argv, const char *interface)
{
CFMutableDictionaryRef options;
options = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (argc > 2) {
struct addrinfo hints = { 0 };
int n_hints = 0;
int i;
for (i = 2; i < argc; i++) {
if (strcasecmp(argv[i], "interface") == 0) {
if (++i >= argc) {
SCPrint(TRUE, stderr, CFSTR("No interface\n"));
CFRelease(options);
exit(1);
}
interface = argv[i];
continue;
}
if (strcasecmp(argv[i], "llq") == 0) {
CFDictionarySetValue(options,
kSCNetworkReachabilityOptionLongLivedQueryBypass,
kCFBooleanFalse);
continue;
} else if (strcasecmp(argv[i], "no-llq") == 0) {
CFDictionarySetValue(options,
kSCNetworkReachabilityOptionLongLivedQueryBypass,
kCFBooleanTrue);
continue;
}
if (strcasecmp(argv[i], "server") == 0) {
CFDictionarySetValue(options,
kSCNetworkReachabilityOptionServerBypass,
kCFBooleanFalse);
continue;
} else if (strcasecmp(argv[i], "no-server") == 0) {
CFDictionarySetValue(options,
kSCNetworkReachabilityOptionServerBypass,
kCFBooleanTrue);
continue;
}
if (strcasecmp(argv[i], "no-resolve") == 0) {
CFDictionarySetValue(options,
kSCNetworkReachabilityOptionResolverBypass,
kCFBooleanTrue);
resolver_bypass = TRUE;
continue;
}
if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
hints.ai_flags |= AI_ADDRCONFIG;
} else if (strcasecmp(argv[i], "AI_ALL") == 0) {
hints.ai_flags |= AI_ALL;
} else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
hints.ai_flags |= AI_V4MAPPED;
} else if (strcasecmp(argv[i], "AI_V4MAPPED_CFG") == 0) {
hints.ai_flags |= AI_V4MAPPED_CFG;
} else if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
hints.ai_flags |= AI_ADDRCONFIG;
} else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
hints.ai_flags |= AI_V4MAPPED;
} else if (strcasecmp(argv[i], "AI_DEFAULT") == 0) {
hints.ai_flags |= AI_DEFAULT;
#ifdef AI_PARALLEL
} else if (strcasecmp(argv[i], "AI_PARALLEL") == 0) {
hints.ai_flags |= AI_PARALLEL;
#endif // AI_PARALLEL
} else if (strcasecmp(argv[i], "PF_INET") == 0) {
hints.ai_family = PF_INET;
} else if (strcasecmp(argv[i], "PF_INET6") == 0) {
hints.ai_family = PF_INET6;
} else if (strcasecmp(argv[i], "SOCK_STREAM") == 0) {
hints.ai_socktype = SOCK_STREAM;
} else if (strcasecmp(argv[i], "SOCK_DGRAM") == 0) {
hints.ai_socktype = SOCK_DGRAM;
} else if (strcasecmp(argv[i], "SOCK_RAW") == 0) {
hints.ai_socktype = SOCK_RAW;
} else if (strcasecmp(argv[i], "IPPROTO_TCP") == 0) {
hints.ai_protocol = IPPROTO_TCP;
} else if (strcasecmp(argv[i], "IPPROTO_UDP") == 0) {
hints.ai_protocol = IPPROTO_UDP;
} else {
SCPrint(TRUE, stderr, CFSTR("Unrecognized hint: %s\n"), argv[i]);
CFRelease(options);
exit(1);
}
n_hints++;
}
if (n_hints > 0) {
CFDataRef data;
data = CFDataCreate(NULL, (const UInt8 *)&hints, sizeof(hints));
CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data);
CFRelease(data);
}
}
if (interface != NULL) {
CFStringRef str;
if (if_nametoindex(interface) == 0) {
SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface);
exit(1);
}
str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII);
CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
CFRelease(str);
}
if (CFDictionaryGetCount(options) == 0) {
CFRelease(options);
options = NULL;
}
return options;
}
static SCNetworkReachabilityRef
_setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
{
char *ip_address = argv[0];
const char *interface;
CFMutableDictionaryRef options = NULL;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
SCNetworkReachabilityRef target = NULL;
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
interface = strchr(argv[0], '%');
if (interface != NULL) {
ip_address = strdup(argv[0]);
ip_address[interface - argv[0]] = '\0';
interface++;
}
if (inet_aton(ip_address, &sin.sin_addr) == 1) {
if ((argc == 1) ||
((argc > 1) && (strlen(argv[1]) == 0))) {
options = _setupReachabilityOptions(argc, argv, interface);
if (options == NULL) {
target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
if (context != NULL) {
context->info = "by address";
}
} else {
CFDataRef data;
data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
CFRelease(data);
if (context != NULL) {
if (CFDictionaryContainsKey(options,
kSCNetworkReachabilityOptionInterface)) {
if (CFDictionaryGetCount(options) == 2) {
context->info = "by address w/scope";
} else {
context->info = "by address w/scope and options";
}
} else {
context->info = "by address w/options";
}
}
}
} else {
char *remote_address = argv[1];
const char *interface2;
struct sockaddr_in r_sin;
interface2 = strchr(argv[1], '%');
if (interface2 != NULL) {
remote_address = strdup(argv[1]);
remote_address[interface2 - argv[1]] = '\0';
interface2++;
if ((interface != NULL) && (strcmp(interface, interface2) != 0)) {
SCPrint(TRUE, stderr,
CFSTR("Interface mismatch \"%s\" != \"%s\"\n"),
interface,
interface2);
exit(1);
}
interface = interface2;
}
bzero(&r_sin, sizeof(r_sin));
r_sin.sin_len = sizeof(r_sin);
r_sin.sin_family = AF_INET;
if (inet_aton(remote_address, &r_sin.sin_addr) == 0) {
SCPrint(TRUE, stderr, CFSTR("Could not interpret address \"%s\"\n"), remote_address);
exit(1);
}
if (remote_address != argv[1]) {
free(remote_address);
}
options = _setupReachabilityOptions(argc, argv, interface);
if (options == NULL) {
target = SCNetworkReachabilityCreateWithAddressPair(NULL,
(struct sockaddr *)&sin,
(struct sockaddr *)&r_sin);
if (context != NULL) {
context->info = "by address pair";
}
} else {
CFDataRef data;
data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
CFRelease(data);
data = CFDataCreate(NULL, (const UInt8 *)&r_sin, sizeof(r_sin));
CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
CFRelease(data);
if (context != NULL) {
if (CFDictionaryContainsKey(options,
kSCNetworkReachabilityOptionInterface)) {
if (CFDictionaryGetCount(options) == 3) {
context->info = "by address pair w/scope";
} else {
context->info = "by address pair w/scope and options";
}
} else {
context->info = "by address pair w/options";
}
}
}
}
} else if (inet_pton(AF_INET6, argv[0], &sin6.sin6_addr) == 1) {
if (interface != NULL) {
sin6.sin6_scope_id = if_nametoindex(interface);
}
if ((argc == 1) ||
((argc > 1) && (strlen(argv[1]) == 0))) {
options = _setupReachabilityOptions(argc, argv, NULL);
if (options == NULL) {
target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6);
if (context != NULL) {
context->info = "by (v6) address";
}
} else {
CFDataRef data;
data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
CFRelease(data);
if (context != NULL) {
context->info = "by (v6) address w/options";
}
}
} else {
struct sockaddr_in6 r_sin6;
bzero(&r_sin6, sizeof(r_sin6));
r_sin6.sin6_len = sizeof(r_sin6);
r_sin6.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, argv[1], &r_sin6.sin6_addr) == 0) {
SCPrint(TRUE, stderr, CFSTR("Could not interpret address \"%s\"\n"), argv[1]);
exit(1);
}
interface = strchr(argv[1], '%');
if (interface != NULL) {
r_sin6.sin6_scope_id = if_nametoindex(interface);
}
options = _setupReachabilityOptions(argc, argv, NULL);
if (options == NULL) {
target = SCNetworkReachabilityCreateWithAddressPair(NULL,
(struct sockaddr *)&sin6,
(struct sockaddr *)&r_sin6);
if (context != NULL) {
context->info = "by (v6) address pair";
}
} else {
CFDataRef data;
data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
CFRelease(data);
data = CFDataCreate(NULL, (const UInt8 *)&r_sin6, sizeof(r_sin6));
CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
CFRelease(data);
if (context != NULL) {
context->info = "by (v6) address pair w/options";
}
}
}
} else {
CFStringRef str;
options = _setupReachabilityOptions(argc, argv, NULL);
if (((argc == 1) && (strlen(argv[0]) > 0)) ||
((argc > 1) && (strlen(argv[0]) > 0) && (strlen(argv[1]) == 0))) {
if (options == NULL) {
target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
if (context != NULL) {
context->info = "by name";
}
} else {
str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
CFRelease(str);
if (context != NULL) {
context->info = "by name w/options";
}
}
} else {
CFIndex n_options;
if (options == NULL) {
options = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
n_options = CFDictionaryGetCount(options);
if (strlen(argv[0]) > 0) {
str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
CFRelease(str);
}
if (strlen(argv[1]) > 0) {
str = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8);
CFDictionarySetValue(options, kSCNetworkReachabilityOptionServName, str);
CFRelease(str);
}
if (CFDictionaryGetCount(options) > n_options) {
if (context != NULL) {
if (n_options == 0) {
context->info = "by (node and/or serv) name";
} else {
context->info = "by (node and/or serv) name w/options";
}
}
} else {
SCPrint(TRUE, stderr, CFSTR("Must specify nodename or servname\n"));
CFRelease(options);
exit(1);
}
}
}
if (ip_address != argv[0]) {
free(ip_address);
}
if ((target == NULL) && (options != NULL)) {
target = SCNetworkReachabilityCreateWithOptions(NULL, options);
CFRelease(options);
}
return target;
}
static void
_printReachabilityFlags(SCNetworkReachabilityFlags flags)
{
if (flags != 0) {
if (flags & kSCNetworkReachabilityFlagsReachable) {
SCPrint(TRUE, stdout, CFSTR("Reachable"));
flags &= ~kSCNetworkReachabilityFlagsReachable;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & kSCNetworkReachabilityFlagsTransientConnection) {
SCPrint(TRUE, stdout, CFSTR("Transient Connection"));
flags &= ~kSCNetworkReachabilityFlagsTransientConnection;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
SCPrint(TRUE, stdout, CFSTR("Connection Required"));
flags &= ~kSCNetworkReachabilityFlagsConnectionRequired;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) {
SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Traffic"));
flags &= ~kSCNetworkReachabilityFlagsConnectionOnTraffic;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) {
SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Demand"));
flags &= ~kSCNetworkReachabilityFlagsConnectionOnDemand;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & kSCNetworkReachabilityFlagsInterventionRequired) {
SCPrint(TRUE, stdout, CFSTR("Intervention Required"));
flags &= ~kSCNetworkReachabilityFlagsInterventionRequired;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & kSCNetworkReachabilityFlagsIsLocalAddress) {
SCPrint(TRUE, stdout, CFSTR("Local Address"));
flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & kSCNetworkReachabilityFlagsIsDirect) {
SCPrint(TRUE, stdout, CFSTR("Directly Reachable Address"));
flags &= ~kSCNetworkReachabilityFlagsIsDirect;
SCPrint(flags != 0, stdout, CFSTR(","));
}
#if TARGET_OS_IPHONE
if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
SCPrint(TRUE, stdout, CFSTR("WWAN"));
flags &= ~kSCNetworkReachabilityFlagsIsWWAN;
SCPrint(flags != 0, stdout, CFSTR(","));
}
#endif // TARGET_OS_IPHONE
if (flags != 0) {
SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
}
} else {
SCPrint(TRUE, stdout, CFSTR("Not Reachable"));
}
return;
}
static void
_printReachability(SCNetworkReachabilityRef target)
{
SCNetworkReachabilityFlags flags;
Boolean ok;
ok = SCNetworkReachabilityGetFlags(target, &flags);
if (!ok) {
printf(" could not determine reachability, %s\n", SCErrorString(SCError()));
return;
}
SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x ("), flags);
_printReachabilityFlags(flags);
SCPrint(_sc_debug, stdout, CFSTR(")"));
if (resolver_bypass) {
int if_index =
SCNetworkReachabilityGetInterfaceIndex(target);
SCPrint(_sc_debug, stdout, CFSTR("interface index = %d"), if_index);
}
SCPrint(TRUE, stdout, CFSTR("\n"));
return;
}
__private_extern__
void
do_checkReachability(int argc, char **argv)
{
SCNetworkReachabilityRef target;
target = _setupReachability(argc, argv, NULL);
if (target == NULL) {
SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
exit(1);
}
_printReachability(target);
CFRelease(target);
exit(0);
}
static void
_printNWIFlags(nwi_ifstate_flags flags)
{
if (flags == 0) {
return;
}
SCPrint(TRUE, stdout, CFSTR(" ("));
if (flags & NWI_IFSTATE_FLAGS_HAS_IPV4) {
SCPrint(TRUE, stdout, CFSTR("IPv4"));
flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV4;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & NWI_IFSTATE_FLAGS_HAS_IPV6) {
SCPrint(TRUE, stdout, CFSTR("IPv6"));
flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV6;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags & NWI_IFSTATE_FLAGS_HAS_DNS) {
SCPrint(TRUE, stdout, CFSTR("DNS"));
flags &= ~NWI_IFSTATE_FLAGS_HAS_DNS;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags != 0) {
SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
}
SCPrint(TRUE, stdout, CFSTR(")"));
return;
}
__private_extern__
void
do_nwi(int argc, char **argv)
{
nwi_ifstate_t ifstate;
nwi_state_t state = nwi_state_copy();
if (state == NULL) {
SCPrint(TRUE, stdout, CFSTR("No network information\n"));
exit(1);
}
if (argc > 0) {
ifstate = nwi_state_get_ifstate(state, argv[0]);
if (ifstate != NULL) {
nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate);
SCPrint(TRUE, stdout, CFSTR("Network interface information\n"), argv[0]);
SCPrint(TRUE, stdout,
CFSTR(" %7s : flags %p"),
nwi_ifstate_get_ifname(ifstate),
flags);
_printNWIFlags(flags);
SCPrint(TRUE, stdout, CFSTR("\n"));
} else {
SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]);
}
goto done;
}
SCPrint(TRUE, stdout, CFSTR("Network information\n"));
SCPrint(TRUE, stdout, CFSTR("\nIPv4 network interface information\n"));
ifstate = nwi_state_get_first_ifstate(state, AF_INET);
if (ifstate == NULL) {
SCPrint(TRUE, stdout, CFSTR(" No IPv4 states found\n"));
}
while (ifstate != NULL) {
nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate);
SCPrint(TRUE, stdout,
CFSTR(" %7s : flags %p"),
nwi_ifstate_get_ifname(ifstate),
flags);
_printNWIFlags(flags);
SCPrint(TRUE, stdout, CFSTR("\n"));
ifstate = nwi_ifstate_get_next(ifstate, AF_INET);
}
SCPrint(TRUE, stdout, CFSTR("\nIPv6 network interface information\n"));
ifstate = nwi_state_get_first_ifstate(state, AF_INET6);
if (ifstate == NULL) {
SCPrint(TRUE, stdout, CFSTR(" No IPv6 states found\n"));
}
while (ifstate != NULL) {
nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate);
SCPrint(TRUE, stdout,
CFSTR(" %7s : flags %p"),
nwi_ifstate_get_ifname(ifstate),
flags);
_printNWIFlags(flags);
SCPrint(TRUE, stdout, CFSTR("\n"));
ifstate = nwi_ifstate_get_next(ifstate, AF_INET6);
}
done :
nwi_state_release(state);
exit(0);
}
static void
callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
{
static int n = 3;
struct tm tm_now;
struct timeval tv_now;
(void)gettimeofday(&tv_now, NULL);
(void)localtime_r(&tv_now.tv_sec, &tm_now);
SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
tm_now.tm_hour,
tm_now.tm_min,
tm_now.tm_sec,
tv_now.tv_usec / 1000);
SCPrint(TRUE, stdout, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n++, flags, (char *)info);
SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
_printReachability(target);
SCPrint(TRUE, stdout, CFSTR("\n"));
return;
}
__private_extern__
void
do_watchReachability(int argc, char **argv)
{
SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
SCNetworkReachabilityRef target;
SCNetworkReachabilityRef target_async;
target = _setupReachability(argc, argv, NULL);
if (target == NULL) {
SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
exit(1);
}
target_async = _setupReachability(argc, argv, &context);
if (target_async == NULL) {
SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
exit(1);
}
if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL) {
CFRelease(target_async);
target_async = CFRetain(target);
}
SCPrint(TRUE, stdout, CFSTR(" 0: direct\n"));
SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
_printReachability(target);
CFRelease(target);
SCPrint(TRUE, stdout, CFSTR("\n"));
SCPrint(TRUE, stdout, CFSTR(" 1: start\n"));
SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
SCPrint(TRUE, stdout, CFSTR("\n"));
if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) {
printf("SCNetworkReachabilitySetCallback() failed: %s\n", SCErrorString(SCError()));
exit(1);
}
if (doDispatch) {
if (!SCNetworkReachabilitySetDispatchQueue(target_async, dispatch_get_current_queue())) {
printf("SCNetworkReachabilitySetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
exit(1);
}
} else {
if (!SCNetworkReachabilityScheduleWithRunLoop(target_async, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
printf("SCNetworkReachabilityScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
exit(1);
}
}
SCPrint(TRUE, stdout, CFSTR(" 2: on %s\n"), doDispatch ? "dispatch queue" : "runloop");
SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async);
_printReachability(target_async);
SCPrint(TRUE, stdout, CFSTR("\n"));
CFRunLoopRun();
exit(0);
}
static void
showResolver(dns_resolver_t *resolver, int index)
{
int i;
SCPrint(TRUE, stdout, CFSTR("\nresolver #%d\n"), index);
if (resolver->domain != NULL) {
SCPrint(TRUE, stdout, CFSTR(" domain : %s\n"), resolver->domain);
}
for (i = 0; i < resolver->n_search; i++) {
SCPrint(TRUE, stdout, CFSTR(" search domain[%d] : %s\n"), i, resolver->search[i]);
}
for (i = 0; i < resolver->n_nameserver; i++) {
char buf[128];
_SC_sockaddr_to_string(resolver->nameserver[i], buf, sizeof(buf));
SCPrint(TRUE, stdout, CFSTR(" nameserver[%d] : %s\n"), i, buf);
}
for (i = 0; i < resolver->n_sortaddr; i++) {
char abuf[32];
char mbuf[32];
(void)inet_ntop(AF_INET, &resolver->sortaddr[i]->address, abuf, sizeof(abuf));
(void)inet_ntop(AF_INET, &resolver->sortaddr[i]->mask, mbuf, sizeof(mbuf));
SCPrint(TRUE, stdout, CFSTR(" sortaddr[%d] : %s/%s\n"), i, abuf, mbuf);
}
if (resolver->options != NULL) {
SCPrint(TRUE, stdout, CFSTR(" options : %s\n"), resolver->options);
}
if (resolver->port != 0) {
SCPrint(TRUE, stdout, CFSTR(" port : %hd\n"), resolver->port);
}
if (resolver->timeout != 0) {
SCPrint(TRUE, stdout, CFSTR(" timeout : %d\n"), resolver->timeout);
}
if (resolver->if_index != 0) {
char buf[IFNAMSIZ];
char *if_name;
if_name = if_indextoname(resolver->if_index, buf);
SCPrint(TRUE, stdout, CFSTR(" if_index : %d (%s)\n"),
resolver->if_index,
(if_name != NULL) ? if_name : "?");
}
if (resolver->flags != 0) {
uint32_t flags = resolver->flags;
SCPrint(TRUE, stdout, CFSTR(" flags : "));
SCPrint(_sc_debug, stdout, CFSTR("0x%08x ("), flags);
if (flags & DNS_RESOLVER_FLAGS_SCOPED) {
SCPrint(TRUE, stdout, CFSTR("Scoped"));
flags &= ~DNS_RESOLVER_FLAGS_SCOPED;
SCPrint(flags != 0, stdout, CFSTR(","));
}
if (flags != 0) {
SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
}
SCPrint(_sc_debug, stdout, CFSTR(")"));
SCPrint(TRUE, stdout, CFSTR("\n"));
}
if (resolver->reach_flags != 0) {
uint32_t flags = resolver->reach_flags;
SCPrint(TRUE, stdout, CFSTR(" reach : "));
SCPrint(_sc_debug, stdout, CFSTR("0x%08x ("), flags);
_printReachabilityFlags(flags);
SCPrint(_sc_debug, stdout, CFSTR(")"));
SCPrint(TRUE, stdout, CFSTR("\n"));
}
if (resolver->search_order != 0) {
SCPrint(TRUE, stdout, CFSTR(" order : %d\n"), resolver->search_order);
}
return;
}
__private_extern__
void
do_showDNSConfiguration(int argc, char **argv)
{
dns_config_t *dns_config;
SCNetworkReachabilityRef target;
dns_config = dns_configuration_copy();
if (dns_config == NULL) {
SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
exit(1);
}
if (argc > 1) {
int dns_config_index = -1;
SCNetworkReachabilityFlags flags = 0;
Boolean haveDNS = FALSE;
Boolean ok = FALSE;
dns_resolver_t *resolver;
uint32_t resolver_if_index;
SCNetworkReachabilityPrivateRef targetPrivate;
target = _setupReachability(argc, argv, NULL);
targetPrivate = (SCNetworkReachabilityPrivateRef)target;
if (targetPrivate->type != reachabilityTypeName) {
SCPrint(TRUE, stdout, CFSTR("\"%s\" is not a hostname.\n"), argv[0]);
exit(1);
}
ok = __SC_checkResolverReachabilityInternal(&store, &flags,
&haveDNS, targetPrivate->name, NULL,
&resolver_if_index, &dns_config_index);
if (!ok) {
SCPrint(TRUE, stdout, CFSTR("No DNS configuration available.\n" ));
exit(1);
}
SCPrint(TRUE, stdout, CFSTR("DNS configuration for %s\n"),
targetPrivate->name);
if (targetPrivate->if_index == 0) {
resolver = dns_config->resolver[dns_config_index];
} else {
resolver = dns_config->scoped_resolver[dns_config_index];
}
showResolver(resolver, dns_config_index + 1);
if (target != NULL) CFRelease(target);
} else {
int i;
SCPrint(TRUE, stdout, CFSTR("DNS configuration\n"));
for (i = 0; i < dns_config->n_resolver; i++) {
dns_resolver_t *resolver = dns_config->resolver[i];
showResolver(resolver, i + 1);
}
if ((dns_config->n_scoped_resolver > 0) && (dns_config->scoped_resolver != NULL)) {
SCPrint(TRUE, stdout, CFSTR("\nDNS configuration (for scoped queries)\n"));
for (i = 0; i < dns_config->n_scoped_resolver; i++) {
dns_resolver_t *resolver = dns_config->scoped_resolver[i];
showResolver(resolver, i + 1);
}
}
}
dns_configuration_free(dns_config);
exit(0);
}
static void
showProxy(CFDictionaryRef proxy)
{
CFMutableDictionaryRef cleaned = NULL;
if (!_sc_debug) {
cleaned = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesSupplemental);
CFDictionaryRemoveValue(cleaned, kSCPropNetProxiesScoped);
proxy = cleaned;
}
SCPrint(TRUE, stdout, CFSTR("%@\n"), proxy);
if (cleaned != NULL) CFRelease(cleaned);
return;
}
__private_extern__
void
do_showProxyConfiguration(int argc, char **argv)
{
CFDictionaryRef proxies;
proxies = SCDynamicStoreCopyProxies(NULL);
if (proxies != NULL) {
CFStringRef interface = NULL;
CFStringRef server = NULL;
while (argc > 0) {
if (strcasecmp(argv[0], "interface") == 0) {
argv++;
argc--;
if (argc < 1) {
SCPrint(TRUE, stderr, CFSTR("No interface\n"));
exit(1);
}
if (if_nametoindex(argv[0]) == 0) {
SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[0]);
exit(1);
}
interface = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
argv++;
argc--;
} else {
if (server != NULL) {
CFRelease(server);
}
server = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
argv++;
argc--;
}
}
if ((server != NULL) || (interface != NULL)) {
CFArrayRef matching;
matching = SCNetworkProxiesCopyMatching(proxies, server, interface);
if (matching != NULL) {
CFIndex i;
CFIndex n;
if (server != NULL) {
if (interface != NULL) {
SCPrint(TRUE, stdout,
CFSTR("server = %@, interface = %@\n"),
server,
interface);
} else {
SCPrint(TRUE, stdout,
CFSTR("server = %@\n"),
server);
}
} else {
SCPrint(TRUE, stdout,
CFSTR("interface = %@\n"),
interface);
}
n = CFArrayGetCount(matching);
for (i = 0; i < n; i++) {
CFDictionaryRef proxy;
proxy = CFArrayGetValueAtIndex(matching, i);
SCPrint(TRUE, stdout, CFSTR("\nproxy #%d\n"), i + 1);
showProxy(proxy);
}
CFRelease(matching);
} else {
SCPrint(TRUE, stdout, CFSTR("No matching proxy configurations\n"));
}
} else {
showProxy(proxies);
}
if (interface != NULL) CFRelease(interface);
if (server != NULL) CFRelease(server);
CFRelease(proxies);
} else {
SCPrint(TRUE, stdout, CFSTR("No proxy configuration available\n"));
}
exit(0);
}
__private_extern__
void
do_snapshot(int argc, char **argv)
{
if (!SCDynamicStoreSnapshot(store)) {
SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
}
#ifdef HAVE_REACHABILITY_SERVER
(void) _SCNetworkReachabilityServer_snapshot();
#endif // HAVE_REACHABILITY_SERVER
return;
}
static void
waitKeyFound()
{
exit(0);
}
static void
waitTimeout(int sigraised)
{
exit(1);
}
__private_extern__
void
do_wait(char *waitKey, int timeout)
{
struct itimerval itv;
CFStringRef key;
CFMutableArrayRef keys;
Boolean ok;
store = SCDynamicStoreCreate(NULL, CFSTR("scutil (wait)"), waitKeyFound, NULL);
if (store == NULL) {
SCPrint(TRUE, stderr,
CFSTR("SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
exit(1);
}
key = CFStringCreateWithCString(NULL, waitKey, kCFStringEncodingUTF8);
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(keys, key);
ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
CFRelease(keys);
if (!ok) {
SCPrint(TRUE, stderr,
CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
exit(1);
}
notifyRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
if (!notifyRls) {
SCPrint(TRUE, stderr,
CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s\n"), SCErrorString(SCError()));
exit(1);
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), notifyRls, kCFRunLoopDefaultMode);
value = SCDynamicStoreCopyValue(store, key);
if (value) {
exit(0);
}
CFRelease(key);
if (timeout > 0) {
signal(SIGALRM, waitTimeout);
bzero(&itv, sizeof(itv));
itv.it_value.tv_sec = timeout;
if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
SCPrint(TRUE, stderr,
CFSTR("setitimer() failed: %s\n"), strerror(errno));
exit(1);
}
}
CFRunLoopRun();
}
#ifdef TEST_DNS_CONFIGURATION_COPY
CFRunLoopSourceRef notifyRls = NULL;
SCDynamicStoreRef store = NULL;
CFPropertyListRef value = NULL;
int
main(int argc, char **argv)
{
do_showDNSConfiguration(argc, argv);
exit(0);
}
#endif // TEST_DNS_CONFIGURATION_COPY