summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/EthernetTap.cpp160
-rw-r--r--version.h2
2 files changed, 119 insertions, 43 deletions
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp
index e6536223..38d37bd1 100644
--- a/node/EthernetTap.cpp
+++ b/node/EthernetTap.cpp
@@ -25,8 +25,10 @@
* LLC. Start here: http://www.zerotier.com/
*/
-#include <iostream>
#include <string>
+#include <map>
+
+#include "Constants.hpp"
#include "EthernetTap.hpp"
#include "Logger.hpp"
#include "RuntimeEnvironment.hpp"
@@ -59,31 +61,81 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
#include <net/if_arp.h>
#include <arpa/inet.h>
+// 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<int,std::string>::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<int,std::string> _paths;
+};
+static const _CommandFinder UNIX_COMMANDS;
+
+#ifdef __LINUX__
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
-
-#define ZT_ETHERTAP_IP_COMMAND "/sbin/ip"
-#define ZT_ETHERTAP_SYSCTL_COMMAND "/sbin/sysctl"
-
#endif // __LINUX__
#ifdef __APPLE__
-
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
-
-#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 59a2d535..c68ef0f4 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