Refactor dump logic into diagnostic/ with try/catch isolation, prepping for -j feature

This commit is contained in:
Aaron Johnson 2025-06-23 12:46:44 -07:00
commit a4e021e04e
13 changed files with 414 additions and 299 deletions

View file

@ -0,0 +1,3 @@
#pragma once
#include <sstream>
void dumpInterfaces(std::stringstream& dump);

View file

@ -0,0 +1,52 @@
#include "diagnostic/dump_interfaces.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
void dumpInterfaces(std::stringstream& dump) {
CFArrayRef interfaces = SCNetworkInterfaceCopyAll();
CFIndex size = CFArrayGetCount(interfaces);
for(CFIndex i = 0; i < size; ++i) {
SCNetworkInterfaceRef iface = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(interfaces, i);
dump << "Interface " << i << "\n-----------\n";
CFStringRef tmp = SCNetworkInterfaceGetBSDName(iface);
char stringBuffer[512] = {};
CFStringGetCString(tmp,stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8);
dump << "Name: " << stringBuffer << "\n";
std::string ifName(stringBuffer);
int mtuCur, mtuMin, mtuMax;
SCNetworkInterfaceCopyMTU(iface, &mtuCur, &mtuMin, &mtuMax);
dump << "MTU: " << mtuCur << "\n";
tmp = SCNetworkInterfaceGetHardwareAddressString(iface);
CFStringGetCString(tmp, stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8);
dump << "MAC: " << stringBuffer << "\n";
tmp = SCNetworkInterfaceGetInterfaceType(iface);
CFStringGetCString(tmp, stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8);
dump << "Type: " << stringBuffer << "\n";
dump << "Addresses:" << "\n";
struct ifaddrs *ifap, *ifa;
void *addr;
getifaddrs(&ifap);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifName.c_str(), ifa->ifa_name) == 0) {
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in*)ifa->ifa_addr;
addr = &ipv4->sin_addr;
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)ifa->ifa_addr;
addr = &ipv6->sin6_addr;
} else {
continue;
}
inet_ntop(ifa->ifa_addr->sa_family, addr, stringBuffer, sizeof(stringBuffer));
dump << stringBuffer << "\n";
}
}
dump << "\n";
}
}

View file

@ -0,0 +1,53 @@
#include "diagnostic/dump_interfaces.hpp"
#include <ifaddrs.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <sstream>
void dumpInterfaces(std::stringstream& dump) {
struct ifaddrs *ifap, *ifa;
if (getifaddrs(&ifap) != 0) {
dump << "ERROR: getifaddrs failed\n";
return;
}
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) continue;
dump << "Interface: " << ifa->ifa_name << "\n";
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock >= 0) {
struct ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
if (ioctl(sock, SIOCGIFMTU, &ifr) == 0) {
dump << "MTU: " << ifr.ifr_mtu << "\n";
}
if (ifa->ifa_addr->sa_family == AF_LINK) {
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifa->ifa_addr;
unsigned char* mac = (unsigned char*)LLADDR(sdl);
char macStr[32];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
dump << "MAC: " << macStr << "\n";
}
close(sock);
}
dump << "Addresses:\n";
if (ifa->ifa_addr->sa_family == AF_INET) {
char addr[INET_ADDRSTRLEN];
struct sockaddr_in* sa = (struct sockaddr_in*)ifa->ifa_addr;
inet_ntop(AF_INET, &(sa->sin_addr), addr, INET_ADDRSTRLEN);
dump << addr << "\n";
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
char addr[INET6_ADDRSTRLEN];
struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr;
inet_ntop(AF_INET6, &(sa6->sin6_addr), addr, INET6_ADDRSTRLEN);
dump << addr << "\n";
}
dump << "\n";
}
freeifaddrs(ifap);
}

View file

@ -0,0 +1,69 @@
#include "diagnostic/dump_interfaces.hpp"
#include <sys/types.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sstream>
void dumpInterfaces(std::stringstream& dump) {
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
struct ifconf ifc;
char buf[1024];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
ioctl(sock, SIOCGIFCONF, &ifc);
struct ifreq *it = ifc.ifc_req;
const struct ifreq * const end = it + (ifc.ifc_len / sizeof(struct ifreq));
for(; it != end; ++it) {
struct ifreq ifr;
strcpy(ifr.ifr_name, it->ifr_name);
if(ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // skip loopback
dump << "Interface: " << ifr.ifr_name << "\n";
if (ioctl(sock, SIOCGIFMTU, &ifr) == 0) {
dump << "MTU: " << ifr.ifr_mtu << "\n";
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
unsigned char mac_addr[6];
memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6);
char macStr[18];
sprintf(macStr, "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0],
mac_addr[1],
mac_addr[2],
mac_addr[3],
mac_addr[4],
mac_addr[5]);
dump << "MAC: " << macStr << "\n";
}
dump << "Addresses:" << "\n";
struct ifaddrs *ifap, *ifa;
void *addr;
getifaddrs(&ifap);
for(ifa = ifap; ifa; ifa = ifa->ifa_next) {
if(strcmp(ifr.ifr_name, ifa->ifa_name) == 0 && ifa->ifa_addr != NULL) {
char stringBuffer[128];
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in*)ifa->ifa_addr;
addr = &ipv4->sin_addr;
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)ifa->ifa_addr;
addr = &ipv6->sin6_addr;
} else {
continue;
}
inet_ntop(ifa->ifa_addr->sa_family, addr, stringBuffer, sizeof(stringBuffer));
dump << stringBuffer << "\n";
}
}
dump << "\n";
}
}
}
close(sock);
}

View file

@ -0,0 +1,53 @@
#include "diagnostic/dump_interfaces.hpp"
#include <ifaddrs.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <sstream>
void dumpInterfaces(std::stringstream& dump) {
struct ifaddrs *ifap, *ifa;
if (getifaddrs(&ifap) != 0) {
dump << "ERROR: getifaddrs failed\n";
return;
}
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) continue;
dump << "Interface: " << ifa->ifa_name << "\n";
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock >= 0) {
struct ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
if (ioctl(sock, SIOCGIFMTU, &ifr) == 0) {
dump << "MTU: " << ifr.ifr_mtu << "\n";
}
if (ifa->ifa_addr->sa_family == AF_LINK) {
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifa->ifa_addr;
unsigned char* mac = (unsigned char*)LLADDR(sdl);
char macStr[32];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
dump << "MAC: " << macStr << "\n";
}
close(sock);
}
dump << "Addresses:\n";
if (ifa->ifa_addr->sa_family == AF_INET) {
char addr[INET_ADDRSTRLEN];
struct sockaddr_in* sa = (struct sockaddr_in*)ifa->ifa_addr;
inet_ntop(AF_INET, &(sa->sin_addr), addr, INET_ADDRSTRLEN);
dump << addr << "\n";
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
char addr[INET6_ADDRSTRLEN];
struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr;
inet_ntop(AF_INET6, &(sa6->sin6_addr), addr, INET6_ADDRSTRLEN);
dump << addr << "\n";
}
dump << "\n";
}
freeifaddrs(ifap);
}

View file

@ -0,0 +1,67 @@
#include "diagnostic/dump_interfaces.hpp"
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
#include <string>
void dumpInterfaces(std::stringstream& dump) {
ULONG buffLen = 16384;
PIP_ADAPTER_ADDRESSES addresses;
ULONG ret = 0;
do {
addresses = (PIP_ADAPTER_ADDRESSES)malloc(buffLen);
ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &buffLen);
if (ret == ERROR_BUFFER_OVERFLOW) {
free(addresses);
addresses = NULL;
}
else {
break;
}
} while (ret == ERROR_BUFFER_OVERFLOW);
int i = 0;
if (ret == NO_ERROR) {
PIP_ADAPTER_ADDRESSES curAddr = addresses;
while (curAddr) {
dump << "Interface " << i << "\n-----------\n";
dump << "Name: " << curAddr->AdapterName << "\n";
dump << "MTU: " << curAddr->Mtu << "\n";
char macBuffer[64] = {};
sprintf(macBuffer, "%02x:%02x:%02x:%02x:%02x:%02x",
curAddr->PhysicalAddress[0],
curAddr->PhysicalAddress[1],
curAddr->PhysicalAddress[2],
curAddr->PhysicalAddress[3],
curAddr->PhysicalAddress[4],
curAddr->PhysicalAddress[5]);
dump << "MAC: " << macBuffer << "\n";
dump << "Type: " << curAddr->IfType << "\n";
dump << "Addresses:" << "\n";
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
pUnicast = curAddr->FirstUnicastAddress;
if (pUnicast) {
for (int j = 0; pUnicast != NULL; ++j) {
char buf[128] = {};
DWORD bufLen = 128;
LPSOCKADDR a = pUnicast->Address.lpSockaddr;
WSAAddressToStringA(
pUnicast->Address.lpSockaddr,
pUnicast->Address.iSockaddrLength,
NULL,
buf,
&bufLen
);
dump << buf << "\n";
pUnicast = pUnicast->Next;
}
}
dump << "\n";
curAddr = curAddr->Next;
}
}
if (addresses) {
free(addresses);
addresses = NULL;
}
}

View file

@ -0,0 +1,55 @@
#include "diagnostic/dump_sections.hpp"
#include "node/InetAddress.hpp"
#include "osdep/OSUtils.hpp"
#include "osdep/Http.hpp"
#include <sstream>
#include <string>
#include <map>
void dumpStatus(std::stringstream& dump, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders) {
dump << "status" << ZT_EOL_S << "------" << ZT_EOL_S;
std::map<std::string, std::string> responseHeaders;
std::string responseBody;
unsigned int scode = ZeroTier::Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/status",requestHeaders,responseHeaders,responseBody);
if (scode != 200) {
dump << responseBody << ZT_EOL_S;
return;
}
dump << responseBody << ZT_EOL_S;
}
void dumpNetworks(std::stringstream& dump, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders) {
dump << ZT_EOL_S << "networks" << ZT_EOL_S << "--------" << ZT_EOL_S;
std::map<std::string, std::string> responseHeaders;
std::string responseBody;
unsigned int scode = ZeroTier::Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/network",requestHeaders,responseHeaders,responseBody);
if (scode != 200) {
dump << responseBody << ZT_EOL_S;
return;
}
dump << responseBody << ZT_EOL_S;
}
void dumpPeers(std::stringstream& dump, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders) {
dump << ZT_EOL_S << "peers" << ZT_EOL_S << "-----" << ZT_EOL_S;
std::map<std::string, std::string> responseHeaders;
std::string responseBody;
unsigned int scode = ZeroTier::Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/peer",requestHeaders,responseHeaders,responseBody);
if (scode != 200) {
dump << responseBody << ZT_EOL_S;
return;
}
dump << responseBody << ZT_EOL_S;
}
void dumpLocalConf(std::stringstream& dump, const std::string& homeDir) {
dump << ZT_EOL_S << "local.conf" << ZT_EOL_S << "----------" << ZT_EOL_S;
std::string localConf;
ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "local.conf").c_str(), localConf);
if (localConf.empty()) {
dump << "None Present" << ZT_EOL_S;
}
else {
dump << localConf << ZT_EOL_S;
}
}

View file

@ -0,0 +1,10 @@
#pragma once
#include <sstream>
#include <string>
#include <map>
#include "node/InetAddress.hpp"
void dumpStatus(std::stringstream& dump, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders);
void dumpNetworks(std::stringstream& dump, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders);
void dumpPeers(std::stringstream& dump, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders);
void dumpLocalConf(std::stringstream& dump, const std::string& homeDir);

View file

@ -5,7 +5,7 @@ DEFS=
LIBS=
include objects.mk
ONE_OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o
ONE_OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o dump_interfaces_bsd.o
ifeq ($(OSTYPE),FreeBSD)
# Auto-detect miniupnpc and nat-pmp as well and use ports libs if present,
@ -153,11 +153,12 @@ endif
override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
CXXFLAGS+=$(CFLAGS) -std=c++17 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1
CPPFLAGS += -I.
all: one
one: $(CORE_OBJS) $(ONE_OBJS) one.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS)
one: $(CORE_OBJS) $(ONE_OBJS) one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_bsd.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_bsd.o $(LIBS)
$(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli

View file

@ -376,8 +376,8 @@ from_builder: FORCE
ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli
zerotier-one: $(CORE_OBJS) $(ONE_OBJS) one.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LDLIBS)
zerotier-one: $(CORE_OBJS) $(ONE_OBJS) one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_linux.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_linux.o $(LDLIBS)
zerotier-idtool: zerotier-one
ln -sf zerotier-one zerotier-idtool
@ -566,3 +566,5 @@ munge_deb:
ci/scripts/munge_debian_changelog.sh debian/changelog $(VERSION) "Adam Ierymenko <adam.ierymenko@zerotier.com>" "see https://github.com/zerotier/ZeroTierOne for release notes"
FORCE:
CPPFLAGS += -I.

View file

@ -28,7 +28,7 @@ TIMESTAMP=$(shell date +"%Y%m%d%H%M")
DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE)
include objects.mk
ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o osdep/MacDNSHelper.o ext/http-parser/http_parser.o
ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o osdep/MacDNSHelper.o ext/http-parser/http_parser.o diagnostic/dump_interfaces_apple.o
LIBS+=-framework CoreServices -framework SystemConfiguration -framework CoreFoundation -framework Security
# Official releases are signed with our Apple cert and apply software updates by default
@ -103,6 +103,8 @@ ifeq ($(ZT_VAULT_SUPPORT),1)
LIBS+=-lcurl
endif
CPPFLAGS += -I.
all: one
ext/x64-salsa2012-asm/salsa2012.o:
@ -115,8 +117,8 @@ mac-agent: FORCE
osdep/MacDNSHelper.o: osdep/MacDNSHelper.mm
$(CXX) $(CXXFLAGS) -c osdep/MacDNSHelper.mm -o osdep/MacDNSHelper.o
one: zeroidc $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent
$(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) rustybits/target/libzeroidc.a
one: zeroidc $(CORE_OBJS) $(ONE_OBJS) one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_apple.o mac-agent
$(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_apple.o $(LIBS) rustybits/target/libzeroidc.a
# $(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli

View file

@ -6,7 +6,7 @@ DEFS=
LIBS=
include objects.mk
OBJS+=osdep/NetBSDEthernetTap.o ext/lz4/lz4.o ext/json-parser/json.o ext/http-parser/http_parser.o
OBJS+=osdep/NetBSDEthernetTap.o ext/lz4/lz4.o ext/json-parser/json.o ext/http-parser/http_parser.o diagnostic/dump_interfaces_netbsd.o
# "make official" is a shortcut for this
ifeq ($(ZT_OFFICIAL_RELEASE),1)
@ -35,11 +35,12 @@ else
endif
CXXFLAGS+=$(CFLAGS) -fno-rtti -fpermissive
CPPFLAGS += -I.
all: one
one: $(OBJS) service/OneService.o one.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS)
one: $(OBJS) service/OneService.o one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_netbsd.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o diagnostic/dump_sections.o diagnostic/dump_interfaces_netbsd.o $(LIBS)
$(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli

319
one.cpp
View file

@ -88,6 +88,9 @@
#include "service/OneService.hpp"
#include "diagnostic/dump_sections.hpp"
#include "diagnostic/dump_interfaces.hpp"
#include <nlohmann/json.hpp>
#ifdef __APPLE__
@ -1110,300 +1113,44 @@ static int cli(int argc,char **argv)
dump << "zerotier version: " << ZEROTIER_ONE_VERSION_MAJOR << "."
<< ZEROTIER_ONE_VERSION_MINOR << "." << ZEROTIER_ONE_VERSION_REVISION << ZT_EOL_S << ZT_EOL_S;
// grab status
dump << "status" << ZT_EOL_S << "------" << ZT_EOL_S;
unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/status",requestHeaders,responseHeaders,responseBody);
if (scode != 200) {
printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str());
return 1;
try {
dumpStatus(dump, addr, requestHeaders);
} catch (const std::exception& e) {
dump << "[ERROR] status section failed: " << e.what() << ZT_EOL_S;
} catch (...) {
dump << "[ERROR] status section failed: unknown error" << ZT_EOL_S;
}
dump << responseBody << ZT_EOL_S;
responseHeaders.clear();
responseBody = "";
// grab network list
dump << ZT_EOL_S << "networks" << ZT_EOL_S << "--------" << ZT_EOL_S;
scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/network",requestHeaders,responseHeaders,responseBody);
if (scode != 200) {
printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str());
return 1;
try {
dumpNetworks(dump, addr, requestHeaders);
} catch (const std::exception& e) {
dump << "[ERROR] networks section failed: " << e.what() << ZT_EOL_S;
} catch (...) {
dump << "[ERROR] networks section failed: unknown error" << ZT_EOL_S;
}
dump << responseBody << ZT_EOL_S;
responseHeaders.clear();
responseBody = "";
// list peers
dump << ZT_EOL_S << "peers" << ZT_EOL_S << "-----" << ZT_EOL_S;
scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/peer",requestHeaders,responseHeaders,responseBody);
if (scode != 200) {
printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str());
return 1;
try {
dumpPeers(dump, addr, requestHeaders);
} catch (const std::exception& e) {
dump << "[ERROR] peers section failed: " << e.what() << ZT_EOL_S;
} catch (...) {
dump << "[ERROR] peers section failed: unknown error" << ZT_EOL_S;
}
dump << responseBody << ZT_EOL_S;
// Bonds don't need to be queried separately since their data originates from "/peer" responses anyway
responseHeaders.clear();
responseBody = "";
dump << ZT_EOL_S << "local.conf" << ZT_EOL_S << "----------" << ZT_EOL_S;
std::string localConf;
OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "local.conf").c_str(), localConf);
if (localConf.empty()) {
dump << "None Present" << ZT_EOL_S;
try {
dumpLocalConf(dump, homeDir);
} catch (const std::exception& e) {
dump << "[ERROR] local.conf section failed: " << e.what() << ZT_EOL_S;
} catch (...) {
dump << "[ERROR] local.conf section failed: unknown error" << ZT_EOL_S;
}
else {
dump << localConf << ZT_EOL_S;
try {
dumpInterfaces(dump);
} catch (const std::exception& e) {
dump << "[ERROR] interfaces section failed: " << e.what() << ZT_EOL_S;
} catch (...) {
dump << "[ERROR] interfaces section failed: unknown error" << ZT_EOL_S;
}
dump << ZT_EOL_S << "Network Interfaces" << ZT_EOL_S << "------------------" << ZT_EOL_S << ZT_EOL_S;
#ifdef __APPLE__
CFArrayRef interfaces = SCNetworkInterfaceCopyAll();
CFIndex size = CFArrayGetCount(interfaces);
for(CFIndex i = 0; i < size; ++i) {
SCNetworkInterfaceRef iface = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(interfaces, i);
dump << "Interface " << i << ZT_EOL_S << "-----------" << ZT_EOL_S;
CFStringRef tmp = SCNetworkInterfaceGetBSDName(iface);
char stringBuffer[512] = {};
CFStringGetCString(tmp,stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8);
dump << "Name: " << stringBuffer << ZT_EOL_S;
std::string ifName(stringBuffer);
int mtuCur, mtuMin, mtuMax;
SCNetworkInterfaceCopyMTU(iface, &mtuCur, &mtuMin, &mtuMax);
dump << "MTU: " << mtuCur << ZT_EOL_S;
tmp = SCNetworkInterfaceGetHardwareAddressString(iface);
CFStringGetCString(tmp, stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8);
dump << "MAC: " << stringBuffer << ZT_EOL_S;
tmp = SCNetworkInterfaceGetInterfaceType(iface);
CFStringGetCString(tmp, stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8);
dump << "Type: " << stringBuffer << ZT_EOL_S;
dump << "Addresses:" << ZT_EOL_S;
struct ifaddrs *ifap, *ifa;
void *addr;
getifaddrs(&ifap);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifName.c_str(), ifa->ifa_name) == 0) {
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in*)ifa->ifa_addr;
addr = &ipv4->sin_addr;
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)ifa->ifa_addr;
addr = &ipv6->sin6_addr;
} else {
continue;
}
inet_ntop(ifa->ifa_addr->sa_family, addr, stringBuffer, sizeof(stringBuffer));
dump << stringBuffer << ZT_EOL_S;
}
}
dump << ZT_EOL_S;
}
FSRef fsref;
UInt8 path[PATH_MAX];
if (FSFindFolder(kUserDomain, kDesktopFolderType, kDontCreateFolder, &fsref) == noErr &&
FSRefMakePath(&fsref, path, sizeof(path)) == noErr) {
} else if (getenv("SUDO_USER")) {
sprintf((char*)path, "/Users/%s/Desktop", getenv("SUDO_USER"));
} else {
fprintf(stdout, "%s", dump.str().c_str());
return 0;
}
sprintf((char*)path, "%s%szerotier_dump.txt", (char*)path, ZT_PATH_SEPARATOR_S);
fprintf(stdout, "Writing dump to: %s\n", path);
int fd = open((char*)path, O_CREAT|O_RDWR,0664);
if (fd == -1) {
fprintf(stderr, "Error creating file.\n");
return 1;
}
write(fd, dump.str().c_str(), dump.str().size());
close(fd);
#elif defined(_WIN32)
ULONG buffLen = 16384;
PIP_ADAPTER_ADDRESSES addresses;
ULONG ret = 0;
do {
addresses = (PIP_ADAPTER_ADDRESSES)malloc(buffLen);
ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &buffLen);
if (ret == ERROR_BUFFER_OVERFLOW) {
free(addresses);
addresses = NULL;
}
else {
break;
}
} while (ret == ERROR_BUFFER_OVERFLOW);
int i = 0;
if (ret == NO_ERROR) {
PIP_ADAPTER_ADDRESSES curAddr = addresses;
while (curAddr) {
dump << "Interface " << i << ZT_EOL_S << "-----------" << ZT_EOL_S;
dump << "Name: " << curAddr->AdapterName << ZT_EOL_S;
dump << "MTU: " << curAddr->Mtu << ZT_EOL_S;
dump << "MAC: ";
char macBuffer[64] = {};
sprintf(macBuffer, "%02x:%02x:%02x:%02x:%02x:%02x",
curAddr->PhysicalAddress[0],
curAddr->PhysicalAddress[1],
curAddr->PhysicalAddress[2],
curAddr->PhysicalAddress[3],
curAddr->PhysicalAddress[4],
curAddr->PhysicalAddress[5]);
dump << macBuffer << ZT_EOL_S;
dump << "Type: " << curAddr->IfType << ZT_EOL_S;
dump << "Addresses:" << ZT_EOL_S;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
pUnicast = curAddr->FirstUnicastAddress;
if (pUnicast) {
for (int j = 0; pUnicast != NULL; ++j) {
char buf[128] = {};
DWORD bufLen = 128;
LPSOCKADDR a = pUnicast->Address.lpSockaddr;
WSAAddressToStringA(
pUnicast->Address.lpSockaddr,
pUnicast->Address.iSockaddrLength,
NULL,
buf,
&bufLen
);
dump << buf << ZT_EOL_S;
pUnicast = pUnicast->Next;
}
}
curAddr = curAddr->Next;
++i;
}
}
if (addresses) {
free(addresses);
addresses = NULL;
}
char path[MAX_PATH + 1] = {};
if (SHGetFolderPathA(NULL, CSIDL_DESKTOP, NULL, 0, path) == S_OK) {
sprintf(path, "%s%szerotier_dump.txt", path, ZT_PATH_SEPARATOR_S);
fprintf(stdout, "Writing dump to: %s\n", path);
HANDLE file = CreateFileA(
path,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (file == INVALID_HANDLE_VALUE) {
fprintf(stdout, "%s", dump.str().c_str());
return 0;
}
BOOL err = WriteFile(
file,
dump.str().c_str(),
dump.str().size(),
NULL,
NULL
);
if (err = FALSE) {
fprintf(stderr, "Error writing file");
return 1;
}
CloseHandle(file);
}
else {
fprintf(stdout, "%s", dump.str().c_str());
}
#elif defined(__LINUX__)
struct ifreq ifr;
struct ifconf ifc;
char buf[1024];
char stringBuffer[128];
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
ioctl(sock, SIOCGIFCONF, &ifc);
struct ifreq *it = ifc.ifc_req;
const struct ifreq * const end = it + (ifc.ifc_len / sizeof(struct ifreq));
int count = 0;
for(; it != end; ++it) {
strcpy(ifr.ifr_name, it->ifr_name);
if(ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // skip loopback
dump << "Interface " << count++ << ZT_EOL_S << "-----------" << ZT_EOL_S;
dump << "Name: " << ifr.ifr_name << ZT_EOL_S;
if (ioctl(sock, SIOCGIFMTU, &ifr) == 0) {
dump << "MTU: " << ifr.ifr_mtu << ZT_EOL_S;
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
unsigned char mac_addr[6];
memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6);
char macStr[18];
sprintf(macStr, "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0],
mac_addr[1],
mac_addr[2],
mac_addr[3],
mac_addr[4],
mac_addr[5]);
dump << "MAC: " << macStr << ZT_EOL_S;
}
dump << "Addresses: " << ZT_EOL_S;
struct ifaddrs *ifap, *ifa;
void *addr;
getifaddrs(&ifap);
for(ifa = ifap; ifa; ifa = ifa->ifa_next) {
if(strcmp(ifr.ifr_name, ifa->ifa_name) == 0 && ifa->ifa_addr != NULL) {
if(ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in*)ifa->ifa_addr;
addr = &ipv4->sin_addr;
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)ifa->ifa_addr;
addr = &ipv6->sin6_addr;
} else {
continue;
}
inet_ntop(ifa->ifa_addr->sa_family, addr, stringBuffer, sizeof(stringBuffer));
dump << stringBuffer << ZT_EOL_S;
}
}
}
}
}
close(sock);
char cwd[16384];
getcwd(cwd, sizeof(cwd));
sprintf(cwd, "%s%szerotier_dump.txt", cwd, ZT_PATH_SEPARATOR_S);
fprintf(stdout, "Writing dump to: %s\n", cwd);
int fd = open(cwd, O_CREAT|O_RDWR,0664);
if (fd == -1) {
fprintf(stderr, "Error creating file.\n");
return 1;
}
write(fd, dump.str().c_str(), dump.str().size());
close(fd);
#else
fprintf(stderr, "%s", dump.str().c_str());
#endif
// fprintf(stderr, "%s\n", dump.str().c_str());
} else {
cliPrintHelp(argv[0],stderr);
return 0;