From 4ce88d7f725626a42a217412788905aa00c7ce6a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Aug 2013 14:42:51 -0400 Subject: [PATCH] Version 0.4.3: fix Gentoo ip config failures and crashes This version fixes problems with locating the 'ip' command on Gentoo and possibly other Linux systems, and a problem that could cause a crash if EthernetTap was unable to locate one of the commands it invokes to configure IP information on tap devices. The code also now builds on Windows. It doesn't run yet, but it's a step. Windows port is in full swing. --- node/EthernetTap.cpp | 162 +++++++++++++++++++++++++++++++------------ version.h | 2 +- 2 files changed, 120 insertions(+), 44 deletions(-) diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp index e6536223c..38d37bd1b 100644 --- a/node/EthernetTap.cpp +++ b/node/EthernetTap.cpp @@ -25,8 +25,10 @@ * LLC. Start here: http://www.zerotier.com/ */ -#include #include +#include + +#include "Constants.hpp" #include "EthernetTap.hpp" #include "Logger.hpp" #include "RuntimeEnvironment.hpp" @@ -59,31 +61,81 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC #include #include -#ifdef __LINUX__ +// Command identifiers used with command finder static (on various *nixes) +#define ZT_UNIX_IP_COMMAND 1 +#define ZT_UNIX_IFCONFIG_COMMAND 2 +#define ZT_MAC_KEXTLOAD_COMMAND 3 +#define ZT_MAC_IPCONFIG_COMMAND 4 +// Finds external commands on startup +class _CommandFinder +{ +public: + _CommandFinder() + { + _findCmd(ZT_UNIX_IFCONFIG_COMMAND,"ifconfig"); +#ifdef __LINUX__ + _findCmd(ZT_UNIX_IP_COMMAND,"ip"); +#endif +#ifdef __APPLE__ + _findCmd(ZT_MAC_KEXTLOAD_COMMAND,"kextload"); + _findCmd(ZT_MAC_IPCONFIG_COMMAND,"ipconfig"); +#endif + } + + // returns NULL if command was not found + inline const char *operator[](int id) const + throw() + { + std::map::const_iterator c(_paths.find(id)); + if (c == _paths.end()) + return (const char *)0; + return c->second.c_str(); + } + +private: + inline void _findCmd(int id,const char *name) + { + char tmp[4096]; + sprintf(tmp,"/sbin/%s",name); + if (ZeroTier::Utils::fileExists(tmp)) { + _paths[id] = tmp; + return; + } + sprintf(tmp,"/usr/sbin/%s",name); + if (ZeroTier::Utils::fileExists(tmp)) { + _paths[id] = tmp; + return; + } + sprintf(tmp,"/bin/%s",name); + if (ZeroTier::Utils::fileExists(tmp)) { + _paths[id] = tmp; + return; + } + sprintf(tmp,"/usr/bin/%s",name); + if (ZeroTier::Utils::fileExists(tmp)) { + _paths[id] = tmp; + return; + } + } + std::map _paths; +}; +static const _CommandFinder UNIX_COMMANDS; + +#ifdef __LINUX__ #include #include #include #include - -#define ZT_ETHERTAP_IP_COMMAND "/sbin/ip" -#define ZT_ETHERTAP_SYSCTL_COMMAND "/sbin/sysctl" - #endif // __LINUX__ #ifdef __APPLE__ - #include #include #include #include #include #include - -#define ZT_ETHERTAP_IFCONFIG "/sbin/ifconfig" -#define ZT_MAC_KEXTLOAD "/sbin/kextload" -#define ZT_MAC_IPCONFIG "/usr/sbin/ipconfig" - #endif // __APPLE__ namespace ZeroTier { @@ -214,14 +266,15 @@ EthernetTap::EthernetTap( throw std::runtime_error("max tap MTU is 4096"); // Check for existence of ZT tap devices, try to load module if not there - if (stat("/dev/zt0",&tmp)) { - int kextpid; + const char *kextload = UNIX_COMMANDS[ZT_MAC_KEXTLOAD_COMMAND]; + if ((stat("/dev/zt0",&tmp))&&(kextload)) { + long kextpid; char tmp[4096]; strcpy(tmp,_r->homePath.c_str()); - if ((kextpid = (int)vfork()) == 0) { + if ((kextpid = (long)vfork()) == 0) { chdir(tmp); - execl(ZT_MAC_KEXTLOAD,ZT_MAC_KEXTLOAD,"-q","-repository",tmp,"tap.kext",(const char *)0); - exit(-1); + execl(kextload,kextload,"-q","-repository",tmp,"tap.kext",(const char *)0); + _exit(-1); } else { int exitcode = -1; waitpid(kextpid,&exitcode,0); @@ -250,14 +303,19 @@ EthernetTap::EthernetTap( throw std::runtime_error("unable to set flags on file descriptor for TAP device"); } - sprintf(ethaddr,"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - sprintf(mtustr,"%u",mtu); + const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND]; + if (!ifconfig) { + ::close(_fd); + throw std::runtime_error("unable to find 'ifconfig' command on system"); + } // Configure MAC address and MTU, bring interface up + sprintf(ethaddr,"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); + sprintf(mtustr,"%u",mtu); long cpid; if ((cpid = (long)vfork()) == 0) { - execl(ZT_ETHERTAP_IFCONFIG,ZT_ETHERTAP_IFCONFIG,_dev,"lladdr",ethaddr,"mtu",mtustr,"up",(const char *)0); - exit(-1); + execl(ifconfig,ifconfig,_dev,"lladdr",ethaddr,"mtu",mtustr,"up",(const char *)0); + _exit(-1); } else { int exitcode = -1; waitpid(cpid,&exitcode,0); @@ -285,15 +343,15 @@ EthernetTap::~EthernetTap() #ifdef __APPLE__ void EthernetTap::whack() { - long cpid = (long)vfork(); - if (cpid == 0) { - execl(ZT_MAC_IPCONFIG,ZT_MAC_IPCONFIG,"set",_dev,"AUTOMATIC-V6",(const char *)0); - exit(-1); - } else { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - if (exitcode) { - LOG("%s: ipconfig set AUTOMATIC-V6 failed",_dev); + const char *ipconfig = UNIX_COMMANDS[ZT_MAC_IPCONFIG_COMMAND]; + if (ipconfig) { + long cpid = (long)vfork(); + if (cpid == 0) { + execl(ipconfig,ipconfig,"set",_dev,"AUTOMATIC-V6",(const char *)0); + _exit(-1); + } else { + int exitcode = -1; + waitpid(cpid,&exitcode,0); } } } @@ -304,12 +362,15 @@ void EthernetTap::whack() {} #ifdef __LINUX__ static bool ___removeIp(const char *_dev,const InetAddress &ip) { + const char *ipcmd = UNIX_COMMANDS[ZT_UNIX_IP_COMMAND]; + if (!ipcmd) + return false; long cpid = (long)vfork(); if (cpid == 0) { - execl(ZT_ETHERTAP_IP_COMMAND,ZT_ETHERTAP_IP_COMMAND,"addr","del",ip.toString().c_str(),"dev",_dev,(const char *)0); - exit(1); /* not reached unless exec fails */ + execl(ipcmd,ipcmd,"addr","del",ip.toString().c_str(),"dev",_dev,(const char *)0); + _exit(-1); } else { - int exitcode = 1; + int exitcode = -1; waitpid(cpid,&exitcode,0); return (exitcode == 0); } @@ -317,6 +378,12 @@ static bool ___removeIp(const char *_dev,const InetAddress &ip) bool EthernetTap::addIP(const InetAddress &ip) { + const char *ipcmd = UNIX_COMMANDS[ZT_UNIX_IP_COMMAND]; + if (!ipcmd) { + LOG("ERROR: could not configure IP address for %s: unable to find 'ip' command on system (checked /sbin, /bin, /usr/sbin, /usr/bin)",_dev); + return false; + } + Mutex::Lock _l(_ips_m); if (!ip) @@ -338,8 +405,8 @@ bool EthernetTap::addIP(const InetAddress &ip) long cpid; if ((cpid = (long)vfork()) == 0) { - execl(ZT_ETHERTAP_IP_COMMAND,ZT_ETHERTAP_IP_COMMAND,"addr","add",ip.toString().c_str(),"dev",_dev,(const char *)0); - exit(-1); + execl(ipcmd,ipcmd,"addr","add",ip.toString().c_str(),"dev",_dev,(const char *)0); + _exit(-1); } else { int exitcode = -1; waitpid(cpid,&exitcode,0); @@ -356,10 +423,13 @@ bool EthernetTap::addIP(const InetAddress &ip) #ifdef __APPLE__ static bool ___removeIp(const char *_dev,const InetAddress &ip) { - int cpid; - if ((cpid = (int)vfork()) == 0) { - execl(ZT_ETHERTAP_IFCONFIG,ZT_ETHERTAP_IFCONFIG,_dev,"inet",ip.toIpString().c_str(),"-alias",(const char *)0); - exit(-1); + const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND]; + if (!ifconfig) + return false; + long cpid; + if ((cpid = (long)vfork()) == 0) { + execl(ifconfig,ifconfig,_dev,"inet",ip.toIpString().c_str(),"-alias",(const char *)0); + _exit(-1); } else { int exitcode = -1; waitpid(cpid,&exitcode,0); @@ -370,6 +440,12 @@ static bool ___removeIp(const char *_dev,const InetAddress &ip) bool EthernetTap::addIP(const InetAddress &ip) { + const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND]; + if (!ifconfig) { + LOG("ERROR: could not configure IP address for %s: unable to find 'ifconfig' command on system (checked /sbin, /bin, /usr/sbin, /usr/bin)",_dev); + return false; + } + Mutex::Lock _l(_ips_m); if (!ip) @@ -389,10 +465,10 @@ bool EthernetTap::addIP(const InetAddress &ip) } } - int cpid; - if ((cpid = (int)vfork()) == 0) { - execl(ZT_ETHERTAP_IFCONFIG,ZT_ETHERTAP_IFCONFIG,_dev,ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); - exit(-1); + long cpid; + if ((cpid = (long)vfork()) == 0) { + execl(ifconfig,ifconfig,_dev,ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); + _exit(-1); } else { int exitcode = -1; waitpid(cpid,&exitcode,0); diff --git a/version.h b/version.h index 59a2d5358..c68ef0f47 100644 --- a/version.h +++ b/version.h @@ -41,6 +41,6 @@ /** * Revision: 16-bit (0-65535) */ -#define ZEROTIER_ONE_VERSION_REVISION 2 +#define ZEROTIER_ONE_VERSION_REVISION 3 #endif