|
@@ -25,8 +25,10 @@
|
|
* LLC. Start here: http://www.zerotier.com/
|
|
* LLC. Start here: http://www.zerotier.com/
|
|
*/
|
|
*/
|
|
|
|
|
|
-#include <iostream>
|
|
|
|
#include <string>
|
|
#include <string>
|
|
|
|
+#include <map>
|
|
|
|
+
|
|
|
|
+#include "Constants.hpp"
|
|
#include "EthernetTap.hpp"
|
|
#include "EthernetTap.hpp"
|
|
#include "Logger.hpp"
|
|
#include "Logger.hpp"
|
|
#include "RuntimeEnvironment.hpp"
|
|
#include "RuntimeEnvironment.hpp"
|
|
@@ -59,31 +61,81 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
|
|
#include <net/if_arp.h>
|
|
#include <net/if_arp.h>
|
|
#include <arpa/inet.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__
|
|
#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.h>
|
|
#include <linux/if_tun.h>
|
|
#include <linux/if_tun.h>
|
|
#include <linux/if_addr.h>
|
|
#include <linux/if_addr.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/if_ether.h>
|
|
-
|
|
|
|
-#define ZT_ETHERTAP_IP_COMMAND "/sbin/ip"
|
|
|
|
-#define ZT_ETHERTAP_SYSCTL_COMMAND "/sbin/sysctl"
|
|
|
|
-
|
|
|
|
#endif // __LINUX__
|
|
#endif // __LINUX__
|
|
|
|
|
|
#ifdef __APPLE__
|
|
#ifdef __APPLE__
|
|
-
|
|
|
|
#include <sys/uio.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/param.h>
|
|
#include <sys/param.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/sysctl.h>
|
|
#include <net/route.h>
|
|
#include <net/route.h>
|
|
#include <net/if_dl.h>
|
|
#include <net/if_dl.h>
|
|
#include <ifaddrs.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__
|
|
#endif // __APPLE__
|
|
|
|
|
|
namespace ZeroTier {
|
|
namespace ZeroTier {
|
|
@@ -214,14 +266,15 @@ EthernetTap::EthernetTap(
|
|
throw std::runtime_error("max tap MTU is 4096");
|
|
throw std::runtime_error("max tap MTU is 4096");
|
|
|
|
|
|
// Check for existence of ZT tap devices, try to load module if not there
|
|
// 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];
|
|
char tmp[4096];
|
|
strcpy(tmp,_r->homePath.c_str());
|
|
strcpy(tmp,_r->homePath.c_str());
|
|
- if ((kextpid = (int)vfork()) == 0) {
|
|
|
|
|
|
+ if ((kextpid = (long)vfork()) == 0) {
|
|
chdir(tmp);
|
|
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 {
|
|
} else {
|
|
int exitcode = -1;
|
|
int exitcode = -1;
|
|
waitpid(kextpid,&exitcode,0);
|
|
waitpid(kextpid,&exitcode,0);
|
|
@@ -250,14 +303,19 @@ EthernetTap::EthernetTap(
|
|
throw std::runtime_error("unable to set flags on file descriptor for TAP device");
|
|
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
|
|
// 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;
|
|
long cpid;
|
|
if ((cpid = (long)vfork()) == 0) {
|
|
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 {
|
|
} else {
|
|
int exitcode = -1;
|
|
int exitcode = -1;
|
|
waitpid(cpid,&exitcode,0);
|
|
waitpid(cpid,&exitcode,0);
|
|
@@ -285,15 +343,15 @@ EthernetTap::~EthernetTap()
|
|
#ifdef __APPLE__
|
|
#ifdef __APPLE__
|
|
void EthernetTap::whack()
|
|
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__
|
|
#ifdef __LINUX__
|
|
static bool ___removeIp(const char *_dev,const InetAddress &ip)
|
|
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();
|
|
long cpid = (long)vfork();
|
|
if (cpid == 0) {
|
|
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 {
|
|
} else {
|
|
- int exitcode = 1;
|
|
|
|
|
|
+ int exitcode = -1;
|
|
waitpid(cpid,&exitcode,0);
|
|
waitpid(cpid,&exitcode,0);
|
|
return (exitcode == 0);
|
|
return (exitcode == 0);
|
|
}
|
|
}
|
|
@@ -317,6 +378,12 @@ static bool ___removeIp(const char *_dev,const InetAddress &ip)
|
|
|
|
|
|
bool EthernetTap::addIP(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);
|
|
Mutex::Lock _l(_ips_m);
|
|
|
|
|
|
if (!ip)
|
|
if (!ip)
|
|
@@ -338,8 +405,8 @@ bool EthernetTap::addIP(const InetAddress &ip)
|
|
|
|
|
|
long cpid;
|
|
long cpid;
|
|
if ((cpid = (long)vfork()) == 0) {
|
|
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 {
|
|
} else {
|
|
int exitcode = -1;
|
|
int exitcode = -1;
|
|
waitpid(cpid,&exitcode,0);
|
|
waitpid(cpid,&exitcode,0);
|
|
@@ -356,10 +423,13 @@ bool EthernetTap::addIP(const InetAddress &ip)
|
|
#ifdef __APPLE__
|
|
#ifdef __APPLE__
|
|
static bool ___removeIp(const char *_dev,const InetAddress &ip)
|
|
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 {
|
|
} else {
|
|
int exitcode = -1;
|
|
int exitcode = -1;
|
|
waitpid(cpid,&exitcode,0);
|
|
waitpid(cpid,&exitcode,0);
|
|
@@ -370,6 +440,12 @@ static bool ___removeIp(const char *_dev,const InetAddress &ip)
|
|
|
|
|
|
bool EthernetTap::addIP(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);
|
|
Mutex::Lock _l(_ips_m);
|
|
|
|
|
|
if (!ip)
|
|
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 {
|
|
} else {
|
|
int exitcode = -1;
|
|
int exitcode = -1;
|
|
waitpid(cpid,&exitcode,0);
|
|
waitpid(cpid,&exitcode,0);
|