mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
LinuxEthernetTap refactor.
This commit is contained in:
parent
05031ff938
commit
1f5feb75fb
3 changed files with 30 additions and 91 deletions
|
@ -38,9 +38,8 @@ STRIP=strip --strip-all
|
||||||
|
|
||||||
CXXFLAGS=$(CFLAGS) -fno-rtti
|
CXXFLAGS=$(CFLAGS) -fno-rtti
|
||||||
|
|
||||||
OBJS+=osnet/LinuxRoutingTable.o osnet/LinuxEthernetTap.o osnet/LinuxEthernetTapFactory.o
|
|
||||||
|
|
||||||
include objects.mk
|
include objects.mk
|
||||||
|
OBJS+=osnet/LinuxRoutingTable.o osnet/LinuxEthernetTap.o osnet/LinuxEthernetTapFactory.o
|
||||||
|
|
||||||
all: one
|
all: one
|
||||||
|
|
||||||
|
@ -58,7 +57,7 @@ installer: one FORCE
|
||||||
./buildinstaller.sh
|
./buildinstaller.sh
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJS) *.o node/*.o zerotier-* build-* ZeroTierOneInstaller-*
|
rm -rf $(OBJS) zerotier-* build-* ZeroTierOneInstaller-*
|
||||||
|
|
||||||
official: FORCE
|
official: FORCE
|
||||||
make -j 4 ZT_OFFICIAL_RELEASE=1
|
make -j 4 ZT_OFFICIAL_RELEASE=1
|
||||||
|
|
|
@ -37,7 +37,6 @@ STRIP=strip
|
||||||
CXXFLAGS=$(CFLAGS) -fno-rtti
|
CXXFLAGS=$(CFLAGS) -fno-rtti
|
||||||
|
|
||||||
include objects.mk
|
include objects.mk
|
||||||
|
|
||||||
OBJS+=osnet/BSDRoutingTable.o osnet/OSXEthernetTap.o osnet/OSXEthernetTapFactory.o
|
OBJS+=osnet/BSDRoutingTable.o osnet/OSXEthernetTap.o osnet/OSXEthernetTapFactory.o
|
||||||
|
|
||||||
all: one
|
all: one
|
||||||
|
|
|
@ -60,67 +60,20 @@
|
||||||
// ff:ff:ff:ff:ff:ff with no ADI
|
// ff:ff:ff:ff:ff:ff with no ADI
|
||||||
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
|
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
|
||||||
|
|
||||||
// On startup, searches the path for required external utilities (which might vary by Linux distro)
|
|
||||||
#define ZT_UNIX_IP_COMMAND 1
|
|
||||||
class _CommandFinder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
_CommandFinder()
|
|
||||||
{
|
|
||||||
_findCmd(ZT_UNIX_IP_COMMAND,"ip");
|
|
||||||
}
|
|
||||||
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];
|
|
||||||
ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/sbin/%s",name);
|
|
||||||
if (ZeroTier::Utils::fileExists(tmp)) {
|
|
||||||
_paths[id] = tmp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/usr/sbin/%s",name);
|
|
||||||
if (ZeroTier::Utils::fileExists(tmp)) {
|
|
||||||
_paths[id] = tmp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/bin/%s",name);
|
|
||||||
if (ZeroTier::Utils::fileExists(tmp)) {
|
|
||||||
_paths[id] = tmp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ZeroTier::Utils::snprintf(tmp,sizeof(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;
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
// Only permit one tap to be opened concurrently across the entire process
|
|
||||||
static Mutex __tapCreateLock;
|
static Mutex __tapCreateLock;
|
||||||
|
|
||||||
LinuxEthernetTap::LinuxEthernetTap(
|
LinuxEthernetTap::LinuxEthernetTap(
|
||||||
const RuntimeEnvironment *renv,
|
|
||||||
const char *tryToGetDevice,
|
|
||||||
const MAC &mac,
|
const MAC &mac,
|
||||||
unsigned int mtu,
|
unsigned int mtu,
|
||||||
|
unsigned int metric,
|
||||||
|
uint64_t nwid,
|
||||||
|
const char *desiredDevice,
|
||||||
|
const char *friendlyName,
|
||||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||||
void *arg)
|
void *arg) :
|
||||||
throw(std::runtime_error) :
|
EthernetTap("LinuxEthernetTap",mac,mtu,metric),
|
||||||
EthernetTap("LinuxEthernetTap",mac,mtu),
|
|
||||||
_r(renv),
|
|
||||||
_handler(handler),
|
_handler(handler),
|
||||||
_arg(arg),
|
_arg(arg),
|
||||||
_fd(0),
|
_fd(0),
|
||||||
|
@ -128,10 +81,11 @@ LinuxEthernetTap::LinuxEthernetTap(
|
||||||
{
|
{
|
||||||
char procpath[128];
|
char procpath[128];
|
||||||
struct stat sbuf;
|
struct stat sbuf;
|
||||||
|
|
||||||
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
|
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
|
||||||
|
|
||||||
if (mtu > 4096)
|
if (mtu > 2800)
|
||||||
throw std::runtime_error("max tap MTU is 4096");
|
throw std::runtime_error("max tap MTU is 2800");
|
||||||
|
|
||||||
_fd = ::open("/dev/net/tun",O_RDWR);
|
_fd = ::open("/dev/net/tun",O_RDWR);
|
||||||
if (_fd <= 0)
|
if (_fd <= 0)
|
||||||
|
@ -142,8 +96,8 @@ LinuxEthernetTap::LinuxEthernetTap(
|
||||||
|
|
||||||
// Try to recall our last device name, or pick an unused one if that fails.
|
// Try to recall our last device name, or pick an unused one if that fails.
|
||||||
bool recalledDevice = false;
|
bool recalledDevice = false;
|
||||||
if ((tryToGetDevice)&&(tryToGetDevice[0])) {
|
if ((desiredDevice)&&(desiredDevice[0])) {
|
||||||
Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),tryToGetDevice);
|
Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),desiredDevice);
|
||||||
Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
|
Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
|
||||||
recalledDevice = (stat(procpath,&sbuf) != 0);
|
recalledDevice = (stat(procpath,&sbuf) != 0);
|
||||||
}
|
}
|
||||||
|
@ -163,7 +117,7 @@ LinuxEthernetTap::LinuxEthernetTap(
|
||||||
|
|
||||||
_dev = ifr.ifr_name;
|
_dev = ifr.ifr_name;
|
||||||
|
|
||||||
ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here
|
::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here
|
||||||
|
|
||||||
// Open an arbitrary socket to talk to netlink
|
// Open an arbitrary socket to talk to netlink
|
||||||
int sock = socket(AF_INET,SOCK_DGRAM,0);
|
int sock = socket(AF_INET,SOCK_DGRAM,0);
|
||||||
|
@ -211,7 +165,7 @@ LinuxEthernetTap::LinuxEthernetTap(
|
||||||
::close(sock);
|
::close(sock);
|
||||||
|
|
||||||
// Set close-on-exec so that devices cannot persist if we fork/exec for update
|
// Set close-on-exec so that devices cannot persist if we fork/exec for update
|
||||||
fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
|
::fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
|
||||||
|
|
||||||
::pipe(_shutdownSignalPipe);
|
::pipe(_shutdownSignalPipe);
|
||||||
|
|
||||||
|
@ -240,53 +194,42 @@ bool LinuxEthernetTap::enabled() const
|
||||||
|
|
||||||
static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
|
static bool ___removeIp(const std::string &_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(ipcmd,ipcmd,"addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
|
Utils::redirectUnixOutputs("/dev/null",(const char *)0);
|
||||||
_exit(-1);
|
::execl("/sbin/ip","/sbin/ip","addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
|
||||||
|
::execl("/usr/sbin/ip","/usr/sbin/ip","addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxEthernetTap::addIP(const InetAddress &ip)
|
bool LinuxEthernetTap::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.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ip)
|
if (!ip)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::set<InetAddress> allIps(ips());
|
std::set<InetAddress> allIps(ips());
|
||||||
if (allIps.count(ip) > 0)
|
if (allIps.count(ip) > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Remove and reconfigure if address is the same but netmask is different
|
// Remove and reconfigure if address is the same but netmask is different
|
||||||
for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
|
for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
|
||||||
if (i->ipsEqual(ip)) {
|
if (i->ipsEqual(ip))
|
||||||
if (___removeIp(_dev,*i)) {
|
___removeIp(_dev,*i);
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
LOG("WARNING: failed to remove old IP/netmask %s to replace with %s",i->toString().c_str(),ip.toString().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long cpid;
|
long cpid = (long)vfork();
|
||||||
if ((cpid = (long)vfork()) == 0) {
|
if (cpid == 0) {
|
||||||
execl(ipcmd,ipcmd,"addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
|
Utils::redirectUnixOutputs("/dev/null",(const char *)0);
|
||||||
_exit(-1);
|
::execl("/sbin/ip","/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
|
||||||
|
::execl("/usr/sbin/ip","/usr/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
|
||||||
|
::_exit(-1);
|
||||||
} else if (cpid > 0) {
|
} else if (cpid > 0) {
|
||||||
int exitcode = -1;
|
int exitcode = -1;
|
||||||
waitpid(cpid,&exitcode,0);
|
::waitpid(cpid,&exitcode,0);
|
||||||
return (exitcode == 0);
|
return (exitcode == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,10 +385,8 @@ void LinuxEthernetTap::threadMain()
|
||||||
if (FD_ISSET(_fd,&readfds)) {
|
if (FD_ISSET(_fd,&readfds)) {
|
||||||
n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
|
n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if ((errno != EINTR)&&(errno != ETIMEDOUT)) {
|
if ((errno != EINTR)&&(errno != ETIMEDOUT))
|
||||||
TRACE("unexpected error reading from tap: %s",strerror(errno));
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Some tap drivers like to send the ethernet frame and the
|
// Some tap drivers like to send the ethernet frame and the
|
||||||
// payload in two chunks, so handle that by accumulating
|
// payload in two chunks, so handle that by accumulating
|
||||||
|
|
Loading…
Add table
Reference in a new issue