summaryrefslogtreecommitdiff
path: root/osnet
diff options
context:
space:
mode:
Diffstat (limited to 'osnet')
-rw-r--r--osnet/BSDEthernetTap.cpp429
-rw-r--r--osnet/BSDEthernetTap.hpp84
-rw-r--r--osnet/BSDEthernetTapFactory.cpp78
-rw-r--r--osnet/BSDEthernetTapFactory.hpp63
-rw-r--r--osnet/LinuxEthernetTap.cpp424
-rw-r--r--osnet/LinuxEthernetTap.hpp85
-rw-r--r--osnet/LinuxEthernetTapFactory.cpp74
-rw-r--r--osnet/LinuxEthernetTapFactory.hpp63
-rw-r--r--osnet/NativeSocketManager.cpp989
-rw-r--r--osnet/NativeSocketManager.hpp117
-rw-r--r--osnet/OSXEthernetTap.cpp639
-rw-r--r--osnet/OSXEthernetTap.hpp91
-rw-r--r--osnet/OSXEthernetTapFactory.cpp122
-rw-r--r--osnet/OSXEthernetTapFactory.hpp76
-rw-r--r--osnet/Phy.hpp817
-rw-r--r--osnet/README.md6
-rw-r--r--osnet/WindowsEthernetTap.cpp867
-rw-r--r--osnet/WindowsEthernetTap.hpp115
-rw-r--r--osnet/WindowsEthernetTapFactory.cpp162
-rw-r--r--osnet/WindowsEthernetTapFactory.hpp90
20 files changed, 0 insertions, 5391 deletions
diff --git a/osnet/BSDEthernetTap.cpp b/osnet/BSDEthernetTap.cpp
deleted file mode 100644
index e9899bc4..00000000
--- a/osnet/BSDEthernetTap.cpp
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <unistd.h>
-#include <signal.h>
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <sys/select.h>
-#include <sys/cdefs.h>
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <ifaddrs.h>
-#include <net/if_arp.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-#include <net/route.h>
-
-#include <string>
-#include <map>
-#include <set>
-#include <algorithm>
-
-#include "../node/Constants.hpp"
-#include "../node/Utils.hpp"
-#include "../node/Mutex.hpp"
-#include "BSDEthernetTap.hpp"
-
-#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv"
-
-// ff:ff:ff:ff:ff:ff with no ADI
-static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
-
-namespace ZeroTier {
-
-BSDEthernetTap::BSDEthernetTap(
- const MAC &mac,
- 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 *arg) :
- EthernetTap("BSDEthernetTap",mac,mtu,metric),
- _handler(handler),
- _arg(arg),
- _mtu(mtu),
- _metric(metric),
- _fd(0),
- _enabled(true)
-{
- static Mutex globalTapCreateLock;
- char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32];
- struct stat stattmp;
-
- // On FreeBSD at least we can rename, so use nwid to generate a deterministic unique zt#### name using base32
- // As a result we don't use desiredDevice
- _dev = "zt";
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 60) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 55) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 50) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 45) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 40) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 35) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 30) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 25) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 20) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 15) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 10) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 5) & 0x1f)]);
- _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]);
-
- Mutex::Lock _gl(globalTapCreateLock);
-
- if (mtu > 2800)
- throw std::runtime_error("max tap MTU is 2800");
-
- // On BSD we create taps and they can have high numbers, so use ones starting
- // at 9993 to not conflict with other stuff. Then we rename it to zt<base32 of nwid>
- std::map<std::string,bool> devFiles(Utils::listDirectory("/dev"));
- for(int i=9993;i<(9993+128);++i) {
- Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
- Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
- if (devFiles.count(std::string(tmpdevname)) == 0) {
- long cpid = (long)vfork();
- if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0);
- ::_exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- } else throw std::runtime_error("fork() failed");
-
- if (!stat(devpath,&stattmp)) {
- cpid = (long)vfork();
- if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0);
- ::_exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- if (exitcode)
- throw std::runtime_error("ifconfig rename operation failed");
- } else throw std::runtime_error("fork() failed");
-
- _fd = ::open(devpath,O_RDWR);
- if (_fd > 0)
- break;
- else throw std::runtime_error("unable to open created tap device");
- } else {
- throw std::runtime_error("cannot find /dev node for newly created tap device");
- }
- }
- }
-
- if (_fd <= 0)
- throw std::runtime_error("unable to open TAP device or no more devices available");
-
- if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
- ::close(_fd);
- throw std::runtime_error("unable to set flags on file descriptor for TAP device");
- }
-
- // Configure MAC address and MTU, bring interface up
- Utils::snprintf(ethaddr,sizeof(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]);
- Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu);
- Utils::snprintf(metstr,sizeof(metstr),"%u",_metric);
- long cpid = (long)vfork();
- if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
- ::_exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- if (exitcode) {
- ::close(_fd);
- throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
- }
- }
-
- // 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);
-
- ::pipe(_shutdownSignalPipe);
-
- _thread = Thread::start(this);
-}
-
-BSDEthernetTap::~BSDEthernetTap()
-{
- ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
- Thread::join(_thread);
- ::close(_fd);
- ::close(_shutdownSignalPipe[0]);
- ::close(_shutdownSignalPipe[1]);
-
- long cpid = (long)vfork();
- if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0);
- ::_exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- }
-}
-
-void BSDEthernetTap::setEnabled(bool en)
-{
- _enabled = en;
- // TODO: interface status change
-}
-
-bool BSDEthernetTap::enabled() const
-{
- return _enabled;
-}
-
-static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
-{
- long cpid = (long)vfork();
- if (cpid == 0) {
- execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0);
- _exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- waitpid(cpid,&exitcode,0);
- return (exitcode == 0);
- }
- return false; // never reached, make compiler shut up about return value
-}
-
-bool BSDEthernetTap::addIP(const InetAddress &ip)
-{
- if (!ip)
- return false;
-
- std::set<InetAddress> allIps(ips());
- if (allIps.count(ip) > 0)
- return true; // IP/netmask already assigned
-
- // Remove and reconfigure if address is the same but netmask is different
- for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
- if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
- if (___removeIp(_dev,*i))
- break;
- }
- }
-
- long cpid = (long)vfork();
- if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0);
- ::_exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- return (exitcode == 0);
- }
- return false;
-}
-
-bool BSDEthernetTap::removeIP(const InetAddress &ip)
-{
- if (ips().count(ip) > 0) {
- if (___removeIp(_dev,ip))
- return true;
- }
- return false;
-}
-
-std::set<InetAddress> BSDEthernetTap::ips() const
-{
- struct ifaddrs *ifa = (struct ifaddrs *)0;
- if (getifaddrs(&ifa))
- return std::set<InetAddress>();
-
- std::set<InetAddress> r;
-
- struct ifaddrs *p = ifa;
- while (p) {
- if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
- switch(p->ifa_addr->sa_family) {
- case AF_INET: {
- struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
- struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
- r.insert(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
- } break;
- case AF_INET6: {
- struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
- struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
- uint32_t b[4];
- memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
- r.insert(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
- } break;
- }
- }
- p = p->ifa_next;
- }
-
- if (ifa)
- freeifaddrs(ifa);
-
- return r;
-}
-
-void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- char putBuf[4096];
- if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
- to.copyTo(putBuf,6);
- from.copyTo(putBuf + 6,6);
- *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
- memcpy(putBuf + 14,data,len);
- len += 14;
- ::write(_fd,putBuf,len);
- }
-}
-
-std::string BSDEthernetTap::deviceName() const
-{
- return _dev;
-}
-
-void BSDEthernetTap::setFriendlyName(const char *friendlyName)
-{
-}
-
-bool BSDEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
-{
- std::set<MulticastGroup> newGroups;
- struct ifmaddrs *ifmap = (struct ifmaddrs *)0;
- if (!getifmaddrs(&ifmap)) {
- struct ifmaddrs *p = ifmap;
- while (p) {
- if (p->ifma_addr->sa_family == AF_LINK) {
- struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
- struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
- if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
- newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
- }
- p = p->ifma_next;
- }
- freeifmaddrs(ifmap);
- }
-
- {
- std::set<InetAddress> allIps(ips());
- for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i)
- newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
- }
-
- bool changed = false;
-
- for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) {
- if (!groups.count(*mg)) {
- groups.insert(*mg);
- changed = true;
- }
- }
- for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
- if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
- groups.erase(mg++);
- changed = true;
- } else ++mg;
- }
-
- return changed;
-}
-
-bool BSDEthernetTap::injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- return false;
-}
-
-void BSDEthernetTap::threadMain()
- throw()
-{
- fd_set readfds,nullfds;
- MAC to,from;
- int n,nfds,r;
- char getBuf[8194];
- Buffer<4096> data;
-
- // Wait for a moment after startup -- wait for Network to finish
- // constructing itself.
- Thread::sleep(500);
-
- FD_ZERO(&readfds);
- FD_ZERO(&nullfds);
- nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
-
- r = 0;
- for(;;) {
- FD_SET(_shutdownSignalPipe[0],&readfds);
- FD_SET(_fd,&readfds);
- select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
-
- if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
- break;
-
- if (FD_ISSET(_fd,&readfds)) {
- n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
- if (n < 0) {
- if ((errno != EINTR)&&(errno != ETIMEDOUT))
- break;
- } else {
- // Some tap drivers like to send the ethernet frame and the
- // payload in two chunks, so handle that by accumulating
- // data until we have at least a frame.
- r += n;
- if (r > 14) {
- if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
- r = _mtu + 14;
-
- if (_enabled) {
- to.setTo(getBuf,6);
- from.setTo(getBuf + 6,6);
- unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
- data.copyFrom(getBuf + 14,(unsigned int)r - 14);
- _handler(_arg,from,to,etherType,data);
- }
-
- r = 0;
- }
- }
- }
- }
-}
-
-} // namespace ZeroTier
diff --git a/osnet/BSDEthernetTap.hpp b/osnet/BSDEthernetTap.hpp
deleted file mode 100644
index 582292a1..00000000
--- a/osnet/BSDEthernetTap.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_BSDETHERNETTAP_HPP
-#define ZT_BSDETHERNETTAP_HPP
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <stdexcept>
-
-#include "../node/EthernetTap.hpp"
-#include "../node/Thread.hpp"
-
-namespace ZeroTier {
-
-class BSDEthernetTap : public EthernetTap
-{
-public:
- BSDEthernetTap(
- const MAC &mac,
- 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 *arg);
-
- virtual ~BSDEthernetTap();
-
- virtual void setEnabled(bool en);
- virtual bool enabled() const;
- virtual bool addIP(const InetAddress &ip);
- virtual bool removeIP(const InetAddress &ip);
- virtual std::set<InetAddress> ips() const;
- virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
- virtual std::string deviceName() const;
- virtual void setFriendlyName(const char *friendlyName);
- virtual bool updateMulticastGroups(std::set<MulticastGroup> &groups);
- virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
-
- void threadMain()
- throw();
-
-private:
- void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
- void *_arg;
- Thread _thread;
- std::string _dev;
- unsigned int _mtu;
- unsigned int _metric;
- int _fd;
- int _shutdownSignalPipe[2];
- volatile bool _enabled;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/BSDEthernetTapFactory.cpp b/osnet/BSDEthernetTapFactory.cpp
deleted file mode 100644
index 79ae73f7..00000000
--- a/osnet/BSDEthernetTapFactory.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "BSDEthernetTapFactory.hpp"
-#include "BSDEthernetTap.hpp"
-
-namespace ZeroTier {
-
-BSDEthernetTapFactory::BSDEthernetTapFactory()
-{
-}
-
-BSDEthernetTapFactory::~BSDEthernetTapFactory()
-{
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
- delete *d;
-}
-
-EthernetTap *BSDEthernetTapFactory::open(
- const MAC &mac,
- 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 *arg)
-{
- Mutex::Lock _l(_devices_m);
- EthernetTap *t = new BSDEthernetTap(mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
- _devices.push_back(t);
- return t;
-}
-
-void BSDEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
-{
- {
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
- if (*d == tap) {
- _devices.erase(d);
- break;
- }
- }
- }
- delete tap;
-}
-
-} // namespace ZeroTier
diff --git a/osnet/BSDEthernetTapFactory.hpp b/osnet/BSDEthernetTapFactory.hpp
deleted file mode 100644
index 63e77339..00000000
--- a/osnet/BSDEthernetTapFactory.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_BSDETHERNETTAPFACTORY_HPP
-#define ZT_BSDETHERNETTAPFACTORY_HPP
-
-#include <vector>
-#include <string>
-
-#include "../node/EthernetTapFactory.hpp"
-#include "../node/Mutex.hpp"
-
-namespace ZeroTier {
-
-class BSDEthernetTapFactory : public EthernetTapFactory
-{
-public:
- BSDEthernetTapFactory();
- virtual ~BSDEthernetTapFactory();
-
- virtual EthernetTap *open(
- const MAC &mac,
- 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 *arg);
- virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
-
-private:
- std::vector<EthernetTap *> _devices;
- Mutex _devices_m;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/LinuxEthernetTap.cpp b/osnet/LinuxEthernetTap.cpp
deleted file mode 100644
index ee89159e..00000000
--- a/osnet/LinuxEthernetTap.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <sys/select.h>
-#include <netinet/in.h>
-#include <net/if_arp.h>
-#include <arpa/inet.h>
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#include <linux/if_addr.h>
-#include <linux/if_ether.h>
-#include <ifaddrs.h>
-
-#include <string>
-#include <map>
-#include <set>
-#include <algorithm>
-
-#include "../node/Constants.hpp"
-#include "../node/Utils.hpp"
-#include "../node/Mutex.hpp"
-#include "LinuxEthernetTap.hpp"
-
-// ff:ff:ff:ff:ff:ff with no ADI
-static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
-
-namespace ZeroTier {
-
-static Mutex __tapCreateLock;
-
-LinuxEthernetTap::LinuxEthernetTap(
- const MAC &mac,
- 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 *arg) :
- EthernetTap("LinuxEthernetTap",mac,mtu,metric),
- _handler(handler),
- _arg(arg),
- _fd(0),
- _enabled(true)
-{
- char procpath[128];
- struct stat sbuf;
-
- Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
-
- if (mtu > 2800)
- throw std::runtime_error("max tap MTU is 2800");
-
- _fd = ::open("/dev/net/tun",O_RDWR);
- if (_fd <= 0)
- throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno));
-
- struct ifreq ifr;
- memset(&ifr,0,sizeof(ifr));
-
- // Try to recall our last device name, or pick an unused one if that fails.
- bool recalledDevice = false;
- if ((desiredDevice)&&(desiredDevice[0])) {
- Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),desiredDevice);
- Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
- recalledDevice = (stat(procpath,&sbuf) != 0);
- }
- if (!recalledDevice) {
- int devno = 0;
- do {
- Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++);
- Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
- } while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist
- }
-
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) {
- ::close(_fd);
- throw std::runtime_error("unable to configure TUN/TAP device for TAP operation");
- }
-
- _dev = ifr.ifr_name;
-
- ::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here
-
- // Open an arbitrary socket to talk to netlink
- int sock = socket(AF_INET,SOCK_DGRAM,0);
- if (sock <= 0) {
- ::close(_fd);
- throw std::runtime_error("unable to open netlink socket");
- }
-
- // Set MAC address
- ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER;
- mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6);
- if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) {
- ::close(_fd);
- ::close(sock);
- throw std::runtime_error("unable to configure TAP hardware (MAC) address");
- return;
- }
-
- // Set MTU
- ifr.ifr_ifru.ifru_mtu = (int)mtu;
- if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) {
- ::close(_fd);
- ::close(sock);
- throw std::runtime_error("unable to configure TAP MTU");
- }
-
- if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
- ::close(_fd);
- throw std::runtime_error("unable to set flags on file descriptor for TAP device");
- }
-
- /* Bring interface up */
- if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) {
- ::close(_fd);
- ::close(sock);
- throw std::runtime_error("unable to get TAP interface flags");
- }
- ifr.ifr_flags |= IFF_UP;
- if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) {
- ::close(_fd);
- ::close(sock);
- throw std::runtime_error("unable to set TAP interface flags");
- }
-
- ::close(sock);
-
- // 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);
-
- ::pipe(_shutdownSignalPipe);
-
- _thread = Thread::start(this);
-}
-
-LinuxEthernetTap::~LinuxEthernetTap()
-{
- ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
- Thread::join(_thread);
- ::close(_fd);
- ::close(_shutdownSignalPipe[0]);
- ::close(_shutdownSignalPipe[1]);
-}
-
-void LinuxEthernetTap::setEnabled(bool en)
-{
- _enabled = en;
- // TODO: interface status change
-}
-
-bool LinuxEthernetTap::enabled() const
-{
- return _enabled;
-}
-
-static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
-{
- long cpid = (long)vfork();
- if (cpid == 0) {
- Utils::redirectUnixOutputs("/dev/null",(const char *)0);
- ::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 {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- return (exitcode == 0);
- }
-}
-
-bool LinuxEthernetTap::addIP(const InetAddress &ip)
-{
- if (!ip)
- return false;
- std::set<InetAddress> allIps(ips());
- if (allIps.count(ip) > 0)
- return true;
-
- // Remove and reconfigure if address is the same but netmask is different
- for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
- if (i->ipsEqual(ip))
- ___removeIp(_dev,*i);
- }
-
- long cpid = (long)vfork();
- if (cpid == 0) {
- Utils::redirectUnixOutputs("/dev/null",(const char *)0);
- if (ip.isV4()) {
- ::execl("/sbin/ip","/sbin/ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
- ::execl("/usr/sbin/ip","/usr/sbin/ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
- } else {
- ::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) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- return (exitcode == 0);
- }
-
- return false;
-}
-
-bool LinuxEthernetTap::removeIP(const InetAddress &ip)
-{
- if (ips().count(ip) > 0) {
- if (___removeIp(_dev,ip))
- return true;
- }
- return false;
-}
-
-std::set<InetAddress> LinuxEthernetTap::ips() const
-{
- struct ifaddrs *ifa = (struct ifaddrs *)0;
- if (getifaddrs(&ifa))
- return std::set<InetAddress>();
-
- std::set<InetAddress> r;
-
- struct ifaddrs *p = ifa;
- while (p) {
- if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
- switch(p->ifa_addr->sa_family) {
- case AF_INET: {
- struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
- struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
- r.insert(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
- } break;
- case AF_INET6: {
- struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
- struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
- uint32_t b[4];
- memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
- r.insert(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
- } break;
- }
- }
- p = p->ifa_next;
- }
-
- if (ifa)
- freeifaddrs(ifa);
-
- return r;
-}
-
-void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- char putBuf[8194];
- if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
- to.copyTo(putBuf,6);
- from.copyTo(putBuf + 6,6);
- *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
- memcpy(putBuf + 14,data,len);
- len += 14;
- ::write(_fd,putBuf,len);
- }
-}
-
-std::string LinuxEthernetTap::deviceName() const
-{
- return _dev;
-}
-
-void LinuxEthernetTap::setFriendlyName(const char *friendlyName)
-{
-}
-
-bool LinuxEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
-{
- char *ptr,*ptr2;
- unsigned char mac[6];
- std::set<MulticastGroup> newGroups;
-
- int fd = ::open("/proc/net/dev_mcast",O_RDONLY);
- if (fd > 0) {
- char buf[131072];
- int n = (int)::read(fd,buf,sizeof(buf));
- if ((n > 0)&&(n < (int)sizeof(buf))) {
- buf[n] = (char)0;
- for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) {
- int fno = 0;
- char *devname = (char *)0;
- char *mcastmac = (char *)0;
- for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) {
- if (fno == 1)
- devname = f;
- else if (fno == 4)
- mcastmac = f;
- ++fno;
- }
- if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6))
- newGroups.insert(MulticastGroup(MAC(mac,6),0));
- }
- }
- ::close(fd);
- }
-
- {
- std::set<InetAddress> allIps(ips());
- for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i)
- newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
- }
-
- bool changed = false;
-
- for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) {
- if (!groups.count(*mg)) {
- groups.insert(*mg);
- changed = true;
- }
- }
- for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
- if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
- groups.erase(mg++);
- changed = true;
- } else ++mg;
- }
-
- return changed;
-}
-
-bool LinuxEthernetTap::injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- return false;
-}
-
-void LinuxEthernetTap::threadMain()
- throw()
-{
- fd_set readfds,nullfds;
- MAC to,from;
- int n,nfds,r;
- char getBuf[8194];
- Buffer<4096> data;
-
- // Wait for a moment after startup -- wait for Network to finish
- // constructing itself.
- Thread::sleep(500);
-
- FD_ZERO(&readfds);
- FD_ZERO(&nullfds);
- nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
-
- r = 0;
- for(;;) {
- FD_SET(_shutdownSignalPipe[0],&readfds);
- FD_SET(_fd,&readfds);
- select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
-
- if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
- break;
-
- if (FD_ISSET(_fd,&readfds)) {
- n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
- if (n < 0) {
- if ((errno != EINTR)&&(errno != ETIMEDOUT))
- break;
- } else {
- // Some tap drivers like to send the ethernet frame and the
- // payload in two chunks, so handle that by accumulating
- // data until we have at least a frame.
- r += n;
- if (r > 14) {
- if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
- r = _mtu + 14;
-
- if (_enabled) {
- to.setTo(getBuf,6);
- from.setTo(getBuf + 6,6);
- unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
- data.copyFrom(getBuf + 14,(unsigned int)r - 14);
- _handler(_arg,from,to,etherType,data);
- }
-
- r = 0;
- }
- }
- }
- }
-}
-
-} // namespace ZeroTier
diff --git a/osnet/LinuxEthernetTap.hpp b/osnet/LinuxEthernetTap.hpp
deleted file mode 100644
index 31980ea0..00000000
--- a/osnet/LinuxEthernetTap.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_LINUXETHERNETTAP_HPP
-#define ZT_LINUXETHERNETTAP_HPP
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <stdexcept>
-
-#include "../node/EthernetTap.hpp"
-#include "../node/Thread.hpp"
-
-namespace ZeroTier {
-
-/**
- * Linux Ethernet tap using kernel tun/tap driver
- */
-class LinuxEthernetTap : public EthernetTap
-{
-public:
- LinuxEthernetTap(
- const MAC &mac,
- 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 *arg);
-
- virtual ~LinuxEthernetTap();
-
- virtual void setEnabled(bool en);
- virtual bool enabled() const;
- virtual bool addIP(const InetAddress &ip);
- virtual bool removeIP(const InetAddress &ip);
- virtual std::set<InetAddress> ips() const;
- virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
- virtual std::string deviceName() const;
- virtual void setFriendlyName(const char *friendlyName);
- virtual bool updateMulticastGroups(std::set<MulticastGroup> &groups);
- virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
-
- void threadMain()
- throw();
-
-private:
- void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
- void *_arg;
- Thread _thread;
- std::string _dev;
- int _fd;
- int _shutdownSignalPipe[2];
- volatile bool _enabled;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/LinuxEthernetTapFactory.cpp b/osnet/LinuxEthernetTapFactory.cpp
deleted file mode 100644
index 014c6514..00000000
--- a/osnet/LinuxEthernetTapFactory.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include "LinuxEthernetTapFactory.hpp"
-#include "LinuxEthernetTap.hpp"
-
-namespace ZeroTier {
-
-LinuxEthernetTapFactory::LinuxEthernetTapFactory()
-{
-}
-
-LinuxEthernetTapFactory::~LinuxEthernetTapFactory()
-{
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
- delete *d;
-}
-
-EthernetTap *LinuxEthernetTapFactory::open(
- const MAC &mac,
- 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 *arg)
-{
- Mutex::Lock _l(_devices_m);
- EthernetTap *t = new LinuxEthernetTap(mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
- _devices.push_back(t);
- return t;
-}
-
-void LinuxEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
-{
- {
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
- if (*d == tap) {
- _devices.erase(d);
- break;
- }
- }
- }
- delete tap;
-}
-
-} // namespace ZeroTier
diff --git a/osnet/LinuxEthernetTapFactory.hpp b/osnet/LinuxEthernetTapFactory.hpp
deleted file mode 100644
index e61863ed..00000000
--- a/osnet/LinuxEthernetTapFactory.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_LINUXETHERNETTAPFACTORY_HPP
-#define ZT_LINUXETHERNETTAPFACTORY_HPP
-
-#include <vector>
-#include <string>
-
-#include "../node/EthernetTapFactory.hpp"
-#include "../node/Mutex.hpp"
-
-namespace ZeroTier {
-
-class LinuxEthernetTapFactory : public EthernetTapFactory
-{
-public:
- LinuxEthernetTapFactory();
- virtual ~LinuxEthernetTapFactory();
-
- virtual EthernetTap *open(
- const MAC &mac,
- 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 *arg);
- virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
-
-private:
- std::vector<EthernetTap *> _devices;
- Mutex _devices_m;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/NativeSocketManager.cpp b/osnet/NativeSocketManager.cpp
deleted file mode 100644
index 797764ef..00000000
--- a/osnet/NativeSocketManager.cpp
+++ /dev/null
@@ -1,989 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-/* Native SocketManager for Windows and Unix */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/types.h>
-
-#include <algorithm>
-
-#include "../node/Constants.hpp"
-#include "NativeSocketManager.hpp"
-
-#ifndef __WINDOWS__
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <signal.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#endif // !__WINDOWS__
-
-// Uncomment to turn off TCP Nagle
-//#define ZT_TCP_NODELAY
-
-// Allow us to use the same value on Windows and *nix
-#ifndef INVALID_SOCKET
-#define INVALID_SOCKET (-1)
-#endif
-
-#ifdef __WINDOWS__
-#define CLOSE_SOCKET(s) ::closesocket(s)
-#else
-#define CLOSE_SOCKET(s) ::close(s)
-#endif
-
-namespace ZeroTier {
-
-//////////////////////////////////////////////////////////////////////////////
-// Socket implementations
-//////////////////////////////////////////////////////////////////////////////
-
-class NativeSocket : public Socket
-{
-public:
-#ifdef __WINDOWS__
- NativeSocket(const Type &t,SOCKET s) : Socket(t),_sock(s) {}
- SOCKET _sock;
-#else
- NativeSocket(const Type &t,int s) : Socket(t),_sock(s) {}
- int _sock;
-#endif
-};
-
-/**
- * Native UDP socket
- */
-class NativeUdpSocket : public NativeSocket
-{
-public:
-#ifdef __WINDOWS__
- NativeUdpSocket(Type t,SOCKET s) : NativeSocket(t,s) {}
-#else
- NativeUdpSocket(Type t,int s) : NativeSocket(t,s) {}
-#endif
-
- virtual ~NativeUdpSocket()
- {
-#ifdef __WINDOWS__
- ::closesocket(_sock);
-#else
- ::close(_sock);
-#endif
- }
-
- virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen)
- {
- if (to.isV6()) {
-#ifdef __WINDOWS__
- return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
-#else
- return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
-#endif
- } else {
-#ifdef __WINDOWS__
- return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
-#else
- return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
-#endif
- }
- }
-
- inline bool notifyAvailableForRead(const SharedPtr<Socket> &self,NativeSocketManager *sm,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg)
- {
- Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> buf;
- InetAddress from;
- socklen_t salen = from.saddrSpaceLen();
- int n = (int)recvfrom(_sock,(char *)(buf.data()),ZT_SOCKET_MAX_MESSAGE_LEN,0,from.saddr(),&salen);
- if (n > 0) {
- buf.setSize((unsigned int)n);
- try {
- handler(self,arg,from,buf);
- } catch ( ... ) {} // handlers should not throw
- }
- return true;
- }
-
- inline bool notifyAvailableForWrite(const SharedPtr<Socket> &self,NativeSocketManager *sm)
- {
- return true;
- }
-};
-
-/**
- * A TCP socket encapsulating ZeroTier packets over a TCP stream connection
- *
- * This implements a simple packet encapsulation that is designed to look like
- * a TLS connection. It's not a TLS connection, but it sends TLS format record
- * headers. It could be extended in the future to implement a fake TLS
- * handshake.
- *
- * At the moment, each packet is just made to look like TLS application data:
- * <[1] TLS content type> - currently 0x17 for "application data"
- * <[1] TLS major version> - currently 0x03 for TLS 1.2
- * <[1] TLS minor version> - currently 0x03 for TLS 1.2
- * <[2] payload length> - 16-bit length of payload in bytes
- * <[...] payload> - Message payload
- *
- * The primary purpose of TCP sockets is to work over ports like HTTPS(443),
- * allowing users behind particularly fascist firewalls to at least reach
- * ZeroTier's supernodes. UDP is the preferred method of communication as
- * encapsulating L2 and L3 protocols over TCP is inherently inefficient
- * due to double-ACKs. So TCP is only used as a fallback.
- */
-class NativeTcpSocket : public NativeSocket
-{
-public:
-#ifdef __WINDOWS__
- NativeTcpSocket(NativeSocketManager *sm,SOCKET s,Socket::Type t,bool c,const InetAddress &r) :
-#else
- NativeTcpSocket(NativeSocketManager *sm,int s,Socket::Type t,bool c,const InetAddress &r) :
-#endif
- NativeSocket(t,s),
- _lastActivity(Utils::now()),
- _sm(sm),
- _inptr(0),
- _outptr(0),
- _connecting(c),
- _remote(r) {}
-
- virtual ~NativeTcpSocket()
- {
-#ifdef __WINDOWS__
- ::closesocket(_sock);
-#else
- ::close(_sock);
-#endif
- }
-
- virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen)
- {
- if (msglen > ZT_SOCKET_MAX_MESSAGE_LEN)
- return false; // message too big
- if (!msglen)
- return true; // sanity check
-
- Mutex::Lock _l(_writeLock);
-
- bool writeInProgress = ((_outptr != 0)||(_connecting));
-
- if ((_outptr + 5 + msglen) > (unsigned int)sizeof(_outbuf))
- return false;
-
- _outbuf[_outptr++] = 0x17; // look like TLS data
- _outbuf[_outptr++] = 0x03;
- _outbuf[_outptr++] = 0x03; // look like TLS 1.2
- _outbuf[_outptr++] = (unsigned char)((msglen >> 8) & 0xff);
- _outbuf[_outptr++] = (unsigned char)(msglen & 0xff);
- for(unsigned int i=0;i<msglen;++i)
- _outbuf[_outptr++] = ((const unsigned char *)msg)[i];
-
- if (!writeInProgress) {
- // If no output was enqueued before this, try to send() it and then
- // start a queued write if any remains after that.
-
- int n = (int)::send(_sock,(const char *)_outbuf,_outptr,0);
- if (n > 0)
- memmove(_outbuf,_outbuf + (unsigned int)n,_outptr -= (unsigned int)n);
-
- if (_outptr) {
- _sm->_startNotifyWrite(this);
- _sm->whack();
- }
- } // else just leave in _outbuf[] to get written when stream is available for write
-
- return true;
- }
-
- inline bool notifyAvailableForRead(const SharedPtr<Socket> &self,NativeSocketManager *sm,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg)
- {
- unsigned char buf[65536];
-
- int n = (int)::recv(_sock,(char *)buf,sizeof(buf),0);
- if (n <= 0)
- return false; // read error, stream probably closed
-
- unsigned int p = _inptr,pl = 0;
- for(int k=0;k<n;++k) {
- _inbuf[p++] = buf[k];
- if (p >= (int)sizeof(_inbuf))
- return false; // read overrun, packet too large or invalid
-
- if ((!pl)&&(p >= 5)) {
- if (_inbuf[0] == 0x17) {
- // fake TLS data frame, next two bytes are TLS version and are ignored
- pl = (((unsigned int)_inbuf[3] << 8) | (unsigned int)_inbuf[4]) + 5;
- } else return false; // in the future we may support fake TLS handshakes
- }
-
- if ((pl)&&(p >= pl)) {
- Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> data(_inbuf + 5,pl - 5);
- memmove(_inbuf,_inbuf + pl,p -= pl);
- try {
- handler(self,arg,_remote,data);
- } catch ( ... ) {} // handlers should not throw
- pl = 0;
- }
- }
- _inptr = p;
-
- return true;
- }
-
- inline bool notifyAvailableForWrite(const SharedPtr<Socket> &self,NativeSocketManager *sm)
- {
- Mutex::Lock _l(_writeLock);
-
- if (_connecting)
- _connecting = false;
-
- if (_outptr) {
- int n = (int)::send(_sock,(const char *)_outbuf,_outptr,0);
-#ifdef __WINDOWS__
- if (n == SOCKET_ERROR) {
- switch(WSAGetLastError()) {
- case WSAEINTR:
- case WSAEWOULDBLOCK:
- break;
- default:
- return false;
- }
-#else
- if (n <= 0) {
- switch(errno) {
-#ifdef EAGAIN
- case EAGAIN:
-#endif
-#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) )
- case EWOULDBLOCK:
-#endif
-#ifdef EINTR
- case EINTR:
-#endif
- break;
- default:
- return false;
- }
-#endif
- } else memmove(_outbuf,_outbuf + (unsigned int)n,_outptr -= (unsigned int)n);
- }
-
- if (!_outptr)
- sm->_stopNotifyWrite(this);
-
- return true;
- }
-
- unsigned char _inbuf[ZT_SOCKET_MAX_MESSAGE_LEN];
- unsigned char _outbuf[ZT_SOCKET_MAX_MESSAGE_LEN * 4];
- uint64_t _lastActivity; // updated whenever data is received, checked directly by SocketManager for stale TCP cleanup
- NativeSocketManager *_sm;
- unsigned int _inptr;
- unsigned int _outptr;
- bool _connecting; // manipulated directly by SocketManager, true if connect() is in progress
- InetAddress _remote;
- Mutex _writeLock;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-#ifdef __WINDOWS__
-// hack copied from StackOverflow, behaves a bit like pipe() on *nix systems
-static inline void winPipeHack(SOCKET fds[2])
-{
- struct sockaddr_in inaddr;
- struct sockaddr addr;
- SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
- memset(&inaddr, 0, sizeof(inaddr));
- memset(&addr, 0, sizeof(addr));
- inaddr.sin_family = AF_INET;
- inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- inaddr.sin_port = 0;
- int yes=1;
- setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes));
- bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr));
- listen(lst,1);
- int len=sizeof(inaddr);
- getsockname(lst, &addr,&len);
- fds[0]=::socket(AF_INET, SOCK_STREAM,0);
- connect(fds[0],&addr,len);
- fds[1]=accept(lst,0,0);
- closesocket(lst);
-}
-#endif
-
-NativeSocketManager::NativeSocketManager(int localUdpPort,int localTcpPort) :
- SocketManager(),
- _whackSendPipe(INVALID_SOCKET),
- _whackReceivePipe(INVALID_SOCKET),
- _tcpV4ListenSocket(INVALID_SOCKET),
- _tcpV6ListenSocket(INVALID_SOCKET),
- _nfds(0)
-{
- FD_ZERO(&_readfds);
- FD_ZERO(&_writefds);
-
- // Create a pipe or socket pair that can be used to interrupt select()
-#ifdef __WINDOWS__
- {
- SOCKET tmps[2] = { INVALID_SOCKET,INVALID_SOCKET };
- winPipeHack(tmps);
- _whackSendPipe = tmps[0];
- _whackReceivePipe = tmps[1];
- u_long iMode=1;
- ioctlsocket(tmps[1],FIONBIO,&iMode);
- }
-#else
- {
- int tmpfds[2];
- if (::pipe(tmpfds))
- throw std::runtime_error("pipe() failed");
- _whackSendPipe = tmpfds[1];
- _whackReceivePipe = tmpfds[0];
- fcntl(_whackReceivePipe,F_SETFL,O_NONBLOCK);
- }
-#endif
- FD_SET(_whackReceivePipe,&_readfds);
-
- if (localTcpPort > 0) {
- if (localTcpPort > 0xffff) {
- _closeSockets();
- throw std::runtime_error("invalid local TCP port number");
- }
-
- { // bind TCP IPv6
- _tcpV6ListenSocket = ::socket(AF_INET6,SOCK_STREAM,0);
-#ifdef __WINDOWS__
- if (_tcpV6ListenSocket != INVALID_SOCKET) {
- {
- BOOL f;
- f = TRUE; ::setsockopt(_tcpV6ListenSocket,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f));
- f = TRUE; ::setsockopt(_tcpV6ListenSocket,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
- u_long iMode=1;
- ioctlsocket(_tcpV6ListenSocket,FIONBIO,&iMode);
- }
-#else
- if (_tcpV6ListenSocket > 0) {
- {
- int f;
- f = 1; ::setsockopt(_tcpV6ListenSocket,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
- f = 1; ::setsockopt(_tcpV6ListenSocket,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
- fcntl(_tcpV6ListenSocket,F_SETFL,O_NONBLOCK);
- }
-#endif // __WINDOWS__ / not __WINDOWS__
-
- struct sockaddr_in6 sin6;
- memset(&sin6,0,sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(localTcpPort);
- memcpy(&(sin6.sin6_addr),&in6addr_any,sizeof(struct in6_addr));
- if (::bind(_tcpV6ListenSocket,(const struct sockaddr *)&sin6,sizeof(sin6))) {
- _closeSockets();
- throw std::runtime_error("unable to bind to local TCP port");
- }
-
- if (::listen(_tcpV6ListenSocket,1024)) {
- _closeSockets();
- throw std::runtime_error("listen() failed");
- }
-
- FD_SET(_tcpV6ListenSocket,&_readfds);
- }
- }
-
- { // bind TCP IPv4
- _tcpV4ListenSocket = ::socket(AF_INET,SOCK_STREAM,0);
-#ifdef __WINDOWS__
- if (_tcpV4ListenSocket == INVALID_SOCKET) {
-#else
- if (_tcpV4ListenSocket <= 0) {
-#endif
- _closeSockets();
- throw std::runtime_error("unable to create IPv4 SOCK_STREAM socket");
- }
-
-#ifdef __WINDOWS__
- {
- BOOL f = TRUE; ::setsockopt(_tcpV4ListenSocket,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
- u_long iMode=1;
- ioctlsocket(_tcpV4ListenSocket,FIONBIO,&iMode);
- }
-#else
- {
- int f = 1; ::setsockopt(_tcpV4ListenSocket,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
- fcntl(_tcpV4ListenSocket,F_SETFL,O_NONBLOCK);
- }
-#endif
-
- struct sockaddr_in sin4;
- memset(&sin4,0,sizeof(sin4));
- sin4.sin_family = AF_INET;
- sin4.sin_port = htons(localTcpPort);
- sin4.sin_addr.s_addr = INADDR_ANY;
- if (::bind(_tcpV4ListenSocket,(const struct sockaddr *)&sin4,sizeof(sin4))) {
- _closeSockets();
- throw std::runtime_error("unable to bind to local TCP port");
- }
-
- if (::listen(_tcpV4ListenSocket,1024)) {
- _closeSockets();
- throw std::runtime_error("listen() failed");
- }
-
- FD_SET(_tcpV4ListenSocket,&_readfds);
- }
- }
-
- if (localUdpPort > 0) {
- if (localUdpPort > 0xffff) {
- _closeSockets();
- throw std::runtime_error("invalid local UDP port number");
- }
-
- { // bind UDP IPv6
-#ifdef __WINDOWS__
- SOCKET s = ::socket(AF_INET6,SOCK_DGRAM,0);
- if (s != INVALID_SOCKET) {
-#else
- int s = ::socket(AF_INET6,SOCK_DGRAM,0);
- if (s > 0) {
-#endif
-
- {
- int bs = 1048576;
- while (bs >= 65536) {
- int tmpbs = bs;
- if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
- break;
- bs -= 16384;
- }
- bs = 1048576;
- while (bs >= 65536) {
- int tmpbs = bs;
- if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
- break;
- bs -= 16384;
- }
-#ifdef __WINDOWS__
- BOOL f;
- f = TRUE; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f));
- f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
- f = FALSE; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,(const char *)&f,sizeof(f));
- f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f));
-#else
- int f;
- f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
- f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
- f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
-#ifdef IP_DONTFRAG
- f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f));
-#endif
-#ifdef IP_MTU_DISCOVER
- f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
-#endif
-#ifdef IPV6_MTU_DISCOVER
- f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f));
-#endif
-#endif
- }
-
- struct sockaddr_in6 sin6;
- memset(&sin6,0,sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(localUdpPort);
- memcpy(&(sin6.sin6_addr),&in6addr_any,sizeof(struct in6_addr));
- if (::bind(s,(const struct sockaddr *)&sin6,sizeof(sin6))) {
- CLOSE_SOCKET(s);
- _closeSockets();
- throw std::runtime_error("unable to bind to port");
- }
-
- _udpV6Socket = SharedPtr<Socket>(new NativeUdpSocket(Socket::ZT_SOCKET_TYPE_UDP_V6,s));
-#ifdef __WINDOWS__
- u_long iMode=1;
- ioctlsocket(s,FIONBIO,&iMode);
-#else
- fcntl(s,F_SETFL,O_NONBLOCK);
-#endif
- FD_SET(s,&_readfds);
- }
- }
-
- { // bind UDP IPv4
-#ifdef __WINDOWS__
- SOCKET s = ::socket(AF_INET,SOCK_DGRAM,0);
- if (s == INVALID_SOCKET) {
- _closeSockets();
- throw std::runtime_error("unable to create IPv4 SOCK_DGRAM socket");
- }
-#else
- int s = ::socket(AF_INET,SOCK_DGRAM,0);
- if (s <= 0) {
- _closeSockets();
- throw std::runtime_error("unable to create IPv4 SOCK_DGRAM socket");
- }
-#endif
-
- {
- int bs = 1048576;
- while (bs >= 65536) {
- int tmpbs = bs;
- if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
- break;
- bs -= 16384;
- }
- bs = 1048576;
- while (bs >= 65536) {
- int tmpbs = bs;
- if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
- break;
- bs -= 16384;
- }
-#ifdef __WINDOWS__
- BOOL f;
- f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
- f = FALSE; setsockopt(s,IPPROTO_IP,IP_DONTFRAGMENT,(const char *)&f,sizeof(f));
- f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f));
-#else
- int f;
- f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
- f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
-#ifdef IP_DONTFRAG
- f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f));
-#endif
-#ifdef IP_MTU_DISCOVER
- f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
-#endif
-#endif
- }
-
- struct sockaddr_in sin4;
- memset(&sin4,0,sizeof(sin4));
- sin4.sin_family = AF_INET;
- sin4.sin_port = htons(localUdpPort);
- sin4.sin_addr.s_addr = INADDR_ANY;
- if (::bind(s,(const struct sockaddr *)&sin4,sizeof(sin4))) {
- CLOSE_SOCKET(s);
- _closeSockets();
- throw std::runtime_error("unable to bind to port");
- }
-
- _udpV4Socket = SharedPtr<Socket>(new NativeUdpSocket(Socket::ZT_SOCKET_TYPE_UDP_V4,s));
-#ifdef __WINDOWS__
- u_long iMode=1;
- ioctlsocket(s,FIONBIO,&iMode);
-#else
- fcntl(s,F_SETFL,O_NONBLOCK);
-#endif
- FD_SET(s,&_readfds);
- }
- }
-
- _updateNfds();
-}
-
-NativeSocketManager::~NativeSocketManager()
-{
- Mutex::Lock _l(_pollLock);
- _closeSockets();
-}
-
-bool NativeSocketManager::send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen)
-{
- if (tcp) {
- SharedPtr<Socket> ts;
- {
- Mutex::Lock _l(_tcpSockets_m);
- std::map< InetAddress,SharedPtr<Socket> >::iterator opents(_tcpSockets.find(to));
- if (opents != _tcpSockets.end())
- ts = opents->second;
- }
- if (ts)
- return ts->send(to,msg,msglen);
-
- if (!autoConnectTcp)
- return false;
-
-#ifdef __WINDOWS__
- SOCKET s = ::socket(to.isV4() ? AF_INET : AF_INET6,SOCK_STREAM,0);
- if (s == INVALID_SOCKET)
- return false;
- { u_long iMode=1; ioctlsocket(s,FIONBIO,&iMode); }
-#ifdef ZT_TCP_NODELAY
- { BOOL f = TRUE; setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
-#endif
-#else
- int s = ::socket(to.isV4() ? AF_INET : AF_INET6,SOCK_STREAM,0);
- if (s <= 0)
- return false;
- if (s >= FD_SETSIZE) {
- ::close(s);
- return false;
- }
- fcntl(s,F_SETFL,O_NONBLOCK);
-#ifdef ZT_TCP_NODELAY
- { int f = 1; setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
-#endif
-#endif
-
- bool connecting = false;
- if (::connect(s,to.saddr(),to.saddrLen())) {
-#ifdef __WINDOWS__
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
-#else
- if (errno != EINPROGRESS) {
-#endif
- CLOSE_SOCKET(s);
- return false;
- } else connecting = true;
- }
-
- ts = SharedPtr<Socket>(new NativeTcpSocket(this,s,Socket::ZT_SOCKET_TYPE_TCP_OUT,connecting,to));
- if (!ts->send(to,msg,msglen)) {
- _fdSetLock.lock();
- FD_CLR(s,&_readfds);
- FD_CLR(s,&_writefds);
- _fdSetLock.unlock();
- return false;
- }
-
- {
- Mutex::Lock _l(_tcpSockets_m);
- _tcpSockets[to] = ts;
- }
-
- _fdSetLock.lock();
- FD_SET(s,&_readfds);
- if (connecting)
- FD_SET(s,&_writefds);
- _fdSetLock.unlock();
-
- _updateNfds();
- whack();
-
- return true;
- } else if (to.isV4()) {
- if (_udpV4Socket)
- return _udpV4Socket->send(to,msg,msglen);
- } else if (to.isV6()) {
- if (_udpV6Socket)
- return _udpV6Socket->send(to,msg,msglen);
- }
- return false;
-}
-
-void NativeSocketManager::poll(unsigned long timeout,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg)
-{
- fd_set rfds,wfds,efds;
- struct timeval tv;
- std::vector< SharedPtr<Socket> > ts;
-#ifdef __WINDOWS__
- SOCKET sockfd;
-#else
- int sockfd;
-#endif
-
- Mutex::Lock _l(_pollLock);
-
- _fdSetLock.lock();
- memcpy(&rfds,&_readfds,sizeof(rfds));
- memcpy(&wfds,&_writefds,sizeof(wfds));
- _fdSetLock.unlock();
- FD_ZERO(&efds);
-
-#ifdef __WINDOWS__
- // Windows signals failed connects in exceptfds
- {
- Mutex::Lock _l2(_tcpSockets_m);
- for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();++s) {
- if (((NativeTcpSocket *)s->second.ptr())->_connecting)
- FD_SET(((NativeTcpSocket *)s->second.ptr())->_sock,&efds);
- }
- }
-#endif
-
- tv.tv_sec = (long)(timeout / 1000);
- tv.tv_usec = (long)((timeout % 1000) * 1000);
- select(_nfds + 1,&rfds,&wfds,&efds,(timeout > 0) ? &tv : (struct timeval *)0);
-
- if (FD_ISSET(_whackReceivePipe,&rfds)) {
- char tmp[16];
-#ifdef __WINDOWS__
- ::recv(_whackReceivePipe,tmp,16,0);
-#else
- ::read(_whackReceivePipe,tmp,16);
-#endif
- }
-
- if ((_tcpV4ListenSocket != INVALID_SOCKET)&&(FD_ISSET(_tcpV4ListenSocket,&rfds))) {
- struct sockaddr_in from;
- socklen_t fromlen = sizeof(from);
- sockfd = accept(_tcpV4ListenSocket,(struct sockaddr *)&from,&fromlen);
-#ifdef __WINDOWS__
- if (sockfd != INVALID_SOCKET) {
-#else
- if (sockfd > 0) {
- if (sockfd < FD_SETSIZE) {
-#endif
- InetAddress fromia((const struct sockaddr *)&from);
- Mutex::Lock _l2(_tcpSockets_m);
- try {
- _tcpSockets[fromia] = SharedPtr<Socket>(new NativeTcpSocket(this,sockfd,Socket::ZT_SOCKET_TYPE_TCP_IN,false,fromia));
-#ifdef __WINDOWS__
- { u_long iMode=1; ioctlsocket(sockfd,FIONBIO,&iMode); }
-#ifdef ZT_TCP_NODELAY
- { BOOL f = TRUE; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
-#endif
-#else
- fcntl(sockfd,F_SETFL,O_NONBLOCK);
-#ifdef ZT_TCP_NODELAY
- { int f = 1; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
-#endif
-#endif
- _fdSetLock.lock();
- FD_SET(sockfd,&_readfds);
- _fdSetLock.unlock();
- if ((int)sockfd > (int)_nfds)
- _nfds = (int)sockfd;
- } catch ( ... ) {
- CLOSE_SOCKET(sockfd);
- }
-#ifndef __WINDOWS__
- } else {
- CLOSE_SOCKET(sockfd);
- }
-#endif
- }
- }
- if ((_tcpV6ListenSocket != INVALID_SOCKET)&&(FD_ISSET(_tcpV6ListenSocket,&rfds))) {
- struct sockaddr_in6 from;
- socklen_t fromlen = sizeof(from);
- sockfd = accept(_tcpV6ListenSocket,(struct sockaddr *)&from,&fromlen);
-#ifdef __WINDOWS__
- if (sockfd != INVALID_SOCKET) {
-#else
- if (sockfd > 0) {
- if (sockfd < FD_SETSIZE) {
-#endif
- InetAddress fromia((const struct sockaddr *)&from);
- Mutex::Lock _l2(_tcpSockets_m);
- try {
- _tcpSockets[fromia] = SharedPtr<Socket>(new NativeTcpSocket(this,sockfd,Socket::ZT_SOCKET_TYPE_TCP_IN,false,fromia));
-#ifdef __WINDOWS__
- { u_long iMode=1; ioctlsocket(sockfd,FIONBIO,&iMode); }
-#ifdef ZT_TCP_NODELAY
- { BOOL f = TRUE; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
-#endif
-#else
- fcntl(sockfd,F_SETFL,O_NONBLOCK);
-#ifdef ZT_TCP_NODELAY
- { int f = 1; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
-#endif
-#endif
- _fdSetLock.lock();
- FD_SET(sockfd,&_readfds);
- _fdSetLock.unlock();
- if ((int)sockfd > (int)_nfds)
- _nfds = (int)sockfd;
- } catch ( ... ) {
- CLOSE_SOCKET(sockfd);
- }
-#ifndef __WINDOWS__
- } else {
- CLOSE_SOCKET(sockfd);
- }
-#endif
- }
- }
-
- {
- NativeUdpSocket *usock = (NativeUdpSocket *)_udpV4Socket.ptr();
- if ((usock)&&(FD_ISSET(usock->_sock,&rfds))) {
- usock->notifyAvailableForRead(_udpV4Socket,this,handler,arg);
- }
- usock = (NativeUdpSocket *)_udpV6Socket.ptr();
- if ((usock)&&(FD_ISSET(usock->_sock,&rfds))) {
- usock->notifyAvailableForRead(_udpV6Socket,this,handler,arg);
- }
- }
-
- bool closedSockets = false;
- { // grab copy of TCP sockets list because _tcpSockets[] might be changed in a handler
- Mutex::Lock _l2(_tcpSockets_m);
- if (!_tcpSockets.empty()) {
- ts.reserve(_tcpSockets.size());
- uint64_t now = Utils::now();
- for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();) {
- NativeTcpSocket *tsock = (NativeTcpSocket *)s->second.ptr();
-#ifdef __WINDOWS__
- if ( ((now - tsock->_lastActivity) < ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT) && (! ((tsock->_connecting)&&(FD_ISSET(tsock->_sock,&efds))) ) ) {
-#else
- if ((now - tsock->_lastActivity) < ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT) {
-#endif
- ts.push_back(s->second);
- ++s;
- } else {
- _fdSetLock.lock();
- FD_CLR(tsock->_sock,&_readfds);
- FD_CLR(tsock->_sock,&_writefds);
- _fdSetLock.unlock();
- _tcpSockets.erase(s++);
- closedSockets = true;
- }
- }
- }
- }
- for(std::vector< SharedPtr<Socket> >::iterator s(ts.begin());s!=ts.end();++s) {
- NativeTcpSocket *tsock = (NativeTcpSocket *)s->ptr();
- if (FD_ISSET(tsock->_sock,&wfds)) {
- if (!tsock->notifyAvailableForWrite(*s,this)) {
- {
- Mutex::Lock _l2(_tcpSockets_m);
- _tcpSockets.erase(tsock->_remote);
- }
- _fdSetLock.lock();
- FD_CLR(tsock->_sock,&_readfds);
- FD_CLR(tsock->_sock,&_writefds);
- _fdSetLock.unlock();
- closedSockets = true;
- continue;
- }
- }
- if (FD_ISSET(tsock->_sock,&rfds)) {
- if (!tsock->notifyAvailableForRead(*s,this,handler,arg)) {
- {
- Mutex::Lock _l2(_tcpSockets_m);
- _tcpSockets.erase(tsock->_remote);
- }
- _fdSetLock.lock();
- FD_CLR(tsock->_sock,&_readfds);
- FD_CLR(tsock->_sock,&_writefds);
- _fdSetLock.unlock();
- closedSockets = true;
- continue;
- }
- }
- }
- if (closedSockets)
- _updateNfds();
-}
-
-void NativeSocketManager::whack()
-{
- _whackSendPipe_m.lock();
-#ifdef __WINDOWS__
- ::send(_whackSendPipe,(const char *)this,1,0);
-#else
- ::write(_whackSendPipe,(const void *)this,1); // data is arbitrary, just send a byte
-#endif
- _whackSendPipe_m.unlock();
-}
-
-void NativeSocketManager::closeTcpSockets()
-{
- {
- Mutex::Lock _l2(_tcpSockets_m);
- _fdSetLock.lock();
- for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();++s) {
- FD_CLR(((NativeTcpSocket *)s->second.ptr())->_sock,&_readfds);
- FD_CLR(((NativeTcpSocket *)s->second.ptr())->_sock,&_writefds);
- }
- _fdSetLock.unlock();
- _tcpSockets.clear();
- }
- _updateNfds();
-}
-
-void NativeSocketManager::_startNotifyWrite(const NativeSocket *sock)
-{
- _fdSetLock.lock();
- FD_SET(sock->_sock,&_writefds);
- _fdSetLock.unlock();
-}
-
-void NativeSocketManager::_stopNotifyWrite(const NativeSocket *sock)
-{
- _fdSetLock.lock();
- FD_CLR(sock->_sock,&_writefds);
- _fdSetLock.unlock();
-}
-
-void NativeSocketManager::_closeSockets()
-{
-#ifdef __WINDOWS__
- if (_whackSendPipe != INVALID_SOCKET)
- ::closesocket(_whackSendPipe);
- if (_whackReceivePipe != INVALID_SOCKET)
- ::closesocket(_whackReceivePipe);
- if (_tcpV4ListenSocket != INVALID_SOCKET)
- ::closesocket(_tcpV4ListenSocket);
- if (_tcpV6ListenSocket != INVALID_SOCKET)
- ::closesocket(_tcpV6ListenSocket);
-#else
- if (_whackSendPipe > 0)
- ::close(_whackSendPipe);
- if (_whackReceivePipe > 0)
- ::close(_whackReceivePipe);
- if (_tcpV4ListenSocket > 0)
- ::close(_tcpV4ListenSocket);
- if (_tcpV4ListenSocket > 0)
- ::close(_tcpV6ListenSocket);
-#endif
-}
-
-void NativeSocketManager::_updateNfds()
-{
-#ifdef __WINDOWS__
- SOCKET nfds = _whackSendPipe;
-#else
- int nfds = _whackSendPipe;
-#endif
- if (_whackReceivePipe > nfds)
- nfds = _whackReceivePipe;
- if (_tcpV4ListenSocket > nfds)
- nfds = _tcpV4ListenSocket;
- if (_tcpV6ListenSocket > nfds)
- nfds = _tcpV6ListenSocket;
- if ((_udpV4Socket)&&(((NativeUdpSocket *)_udpV4Socket.ptr())->_sock > nfds))
- nfds = ((NativeUdpSocket *)_udpV4Socket.ptr())->_sock;
- if ((_udpV6Socket)&&(((NativeUdpSocket *)_udpV6Socket.ptr())->_sock > nfds))
- nfds = ((NativeUdpSocket *)_udpV6Socket.ptr())->_sock;
- Mutex::Lock _l(_tcpSockets_m);
- for(std::map< InetAddress,SharedPtr<Socket> >::const_iterator s(_tcpSockets.begin());s!=_tcpSockets.end();++s) {
- if (((NativeTcpSocket *)s->second.ptr())->_sock > nfds)
- nfds = ((NativeTcpSocket *)s->second.ptr())->_sock;
- }
- _nfds = (int)nfds;
-}
-
-} // namespace ZeroTier
diff --git a/osnet/NativeSocketManager.hpp b/osnet/NativeSocketManager.hpp
deleted file mode 100644
index 5db06d6a..00000000
--- a/osnet/NativeSocketManager.hpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_NATIVESOCKETMANAGER_HPP
-#define ZT_NATIVESOCKETMANAGER_HPP
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <map>
-#include <stdexcept>
-
-#include "../node/Constants.hpp"
-#include "../node/SharedPtr.hpp"
-#include "../node/Mutex.hpp"
-#include "../node/SocketManager.hpp"
-#include "../node/Socket.hpp"
-
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#include <WS2tcpip.h>
-#include <Windows.h>
-#else
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/select.h>
-#endif
-
-namespace ZeroTier {
-
-class NativeSocket;
-class NativeUdpSocket;
-class NativeTcpSocket;
-
-/**
- * Native socket manager for Unix and Windows
- */
-class NativeSocketManager : public SocketManager
-{
- friend class NativeUdpSocket;
- friend class NativeTcpSocket;
-
-public:
- NativeSocketManager(int localUdpPort,int localTcpPort);
- virtual ~NativeSocketManager();
-
- virtual bool send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen);
- virtual void poll(unsigned long timeout,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg);
- virtual void whack();
- virtual void closeTcpSockets();
-
-private:
- // Used by TcpSocket to register/unregister for write availability notification
- void _startNotifyWrite(const NativeSocket *sock);
- void _stopNotifyWrite(const NativeSocket *sock);
-
- // Called in SocketManager destructor or in constructor cleanup before exception throwing
- void _closeSockets();
-
- // Called in SocketManager to recompute _nfds for select() based implementation
- void _updateNfds();
-
-#ifdef __WINDOWS__
- SOCKET _whackSendPipe;
- SOCKET _whackReceivePipe;
- SOCKET _tcpV4ListenSocket;
- SOCKET _tcpV6ListenSocket;
-#else
- int _whackSendPipe;
- int _whackReceivePipe;
- int _tcpV4ListenSocket;
- int _tcpV6ListenSocket;
-#endif
- Mutex _whackSendPipe_m;
-
- SharedPtr<Socket> _udpV4Socket;
- SharedPtr<Socket> _udpV6Socket;
-
- fd_set _readfds;
- fd_set _writefds;
- volatile int _nfds;
- Mutex _fdSetLock;
-
- std::map< InetAddress,SharedPtr<Socket> > _tcpSockets;
- Mutex _tcpSockets_m;
-
- Mutex _pollLock;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/OSXEthernetTap.cpp b/osnet/OSXEthernetTap.cpp
deleted file mode 100644
index 396605c5..00000000
--- a/osnet/OSXEthernetTap.cpp
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <unistd.h>
-#include <signal.h>
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <sys/select.h>
-#include <sys/cdefs.h>
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/route.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-#include <netinet6/in6_var.h>
-#include <netinet/in_var.h>
-#include <netinet/icmp6.h>
-
-// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!?
-struct prf_ra {
- u_char onlink : 1;
- u_char autonomous : 1;
- u_char reserved : 6;
-} prf_ra;
-
-#include <netinet6/nd6.h>
-#include <ifaddrs.h>
-
-// These are KERNEL_PRIVATE... why?
-#ifndef SIOCAUTOCONF_START
-#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
-#endif
-#ifndef SIOCAUTOCONF_STOP
-#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
-#endif
-
-// --------------------------------------------------------------------------
-// --------------------------------------------------------------------------
-// This source is from:
-// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt
-// It's here because OSX 10.6 does not have this convenience function.
-
-#define SALIGN (sizeof(uint32_t) - 1)
-#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
-(SALIGN + 1))
-#define MAX_SYSCTL_TRY 5
-#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
-
-/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */
-/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */
-//#define DARWIN_COMPAT
-
-//#ifdef DARWIN_COMPAT
-#define GIM_SYSCTL_MIB NET_RT_IFLIST2
-#define GIM_RTM_ADDR RTM_NEWMADDR2
-//#else
-//#define GIM_SYSCTL_MIB NET_RT_IFMALIST
-//#define GIM_RTM_ADDR RTM_NEWMADDR
-//#endif
-
-// Not in 10.6 includes so use our own
-struct _intl_ifmaddrs {
- struct _intl_ifmaddrs *ifma_next;
- struct sockaddr *ifma_name;
- struct sockaddr *ifma_addr;
- struct sockaddr *ifma_lladdr;
-};
-
-static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
-{
- int icnt = 1;
- int dcnt = 0;
- int ntry = 0;
- size_t len;
- size_t needed;
- int mib[6];
- int i;
- char *buf;
- char *data;
- char *next;
- char *p;
- struct ifma_msghdr2 *ifmam;
- struct _intl_ifmaddrs *ifa, *ift;
- struct rt_msghdr *rtm;
- struct sockaddr *sa;
-
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE;
- mib[2] = 0; /* protocol */
- mib[3] = 0; /* wildcard address family */
- mib[4] = GIM_SYSCTL_MIB;
- mib[5] = 0; /* no flags */
- do {
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
- return (-1);
- if ((buf = (char *)malloc(needed)) == NULL)
- return (-1);
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
- if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
- free(buf);
- return (-1);
- }
- free(buf);
- buf = NULL;
- }
- } while (buf == NULL);
-
- for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)(void *)next;
- if (rtm->rtm_version != RTM_VERSION)
- continue;
- switch (rtm->rtm_type) {
- case GIM_RTM_ADDR:
- ifmam = (struct ifma_msghdr2 *)(void *)rtm;
- if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
- break;
- icnt++;
- p = (char *)(ifmam + 1);
- for (i = 0; i < RTAX_MAX; i++) {
- if ((RTA_MASKS & ifmam->ifmam_addrs &
- (1 << i)) == 0)
- continue;
- sa = (struct sockaddr *)(void *)p;
- len = SA_RLEN(sa);
- dcnt += len;
- p += len;
- }
- break;
- }
- }
-
- data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
- if (data == NULL) {
- free(buf);
- return (-1);
- }
-
- ifa = (struct _intl_ifmaddrs *)(void *)data;
- data += sizeof(struct _intl_ifmaddrs) * icnt;
-
- memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt);
- ift = ifa;
-
- for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)(void *)next;
- if (rtm->rtm_version != RTM_VERSION)
- continue;
-
- switch (rtm->rtm_type) {
- case GIM_RTM_ADDR:
- ifmam = (struct ifma_msghdr2 *)(void *)rtm;
- if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
- break;
-
- p = (char *)(ifmam + 1);
- for (i = 0; i < RTAX_MAX; i++) {
- if ((RTA_MASKS & ifmam->ifmam_addrs &
- (1 << i)) == 0)
- continue;
- sa = (struct sockaddr *)(void *)p;
- len = SA_RLEN(sa);
- switch (i) {
- case RTAX_GATEWAY:
- ift->ifma_lladdr =
- (struct sockaddr *)(void *)data;
- memcpy(data, p, len);
- data += len;
- break;
-
- case RTAX_IFP:
- ift->ifma_name =
- (struct sockaddr *)(void *)data;
- memcpy(data, p, len);
- data += len;
- break;
-
- case RTAX_IFA:
- ift->ifma_addr =
- (struct sockaddr *)(void *)data;
- memcpy(data, p, len);
- data += len;
- break;
-
- default:
- data += len;
- break;
- }
- p += len;
- }
- ift->ifma_next = ift + 1;
- ift = ift->ifma_next;
- break;
- }
- }
-
- free(buf);
-
- if (ift > ifa) {
- ift--;
- ift->ifma_next = NULL;
- *pif = ifa;
- } else {
- *pif = NULL;
- free(ifa);
- }
- return (0);
-}
-
-static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
-{
- free(ifmp);
-}
-
-// --------------------------------------------------------------------------
-// --------------------------------------------------------------------------
-
-#include <string>
-#include <map>
-#include <set>
-#include <algorithm>
-
-#include "../node/Constants.hpp"
-#include "../node/Utils.hpp"
-#include "../node/Mutex.hpp"
-#include "OSXEthernetTap.hpp"
-
-// ff:ff:ff:ff:ff:ff with no ADI
-static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
-
-static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts)
-{
- struct in6_ndireq nd;
- struct in6_ifreq ifr;
-
- int s = socket(AF_INET6,SOCK_DGRAM,0);
- if (s <= 0)
- return false;
-
- memset(&nd,0,sizeof(nd));
- strncpy(nd.ifname,ifname,sizeof(nd.ifname));
-
- if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
- close(s);
- return false;
- }
-
- unsigned long oldFlags = (unsigned long)nd.ndi.flags;
-
- if (performNUD)
- nd.ndi.flags |= ND6_IFF_PERFORMNUD;
- else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
-
- if (oldFlags != (unsigned long)nd.ndi.flags) {
- if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) {
- close(s);
- return false;
- }
- }
-
- memset(&ifr,0,sizeof(ifr));
- strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
- if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) {
- close(s);
- return false;
- }
-
- close(s);
- return true;
-}
-
-namespace ZeroTier {
-
-OSXEthernetTap::OSXEthernetTap(
- const MAC &mac,
- 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 *arg) :
- EthernetTap("OSXEthernetTap",mac,mtu,metric),
- _handler(handler),
- _arg(arg),
- _mtu(mtu),
- _metric(metric),
- _fd(0),
- _enabled(true)
-{
- static Mutex globalTapCreateLock;
- char devpath[64],ethaddr[64],mtustr[32],metstr[32];
- struct stat stattmp;
-
- Mutex::Lock _gl(globalTapCreateLock);
-
- if (mtu > 2800)
- throw std::runtime_error("max tap MTU is 2800");
- if (stat("/dev/zt0",&stattmp))
- throw std::runtime_error("/dev/zt# tap devices do not exist");
-
- // Try to reopen the last device we had, if we had one and it's still unused.
- bool recalledDevice = false;
- if ((desiredDevice)&&(desiredDevice[0] == 'z')&&(desiredDevice[1] == 't')) {
- if ((strchr(desiredDevice,'/'))||(strchr(desiredDevice,'.'))) // security sanity check
- throw std::runtime_error("invalid desiredDevice parameter");
- Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",desiredDevice);
- if (stat(devpath,&stattmp) == 0) {
- _fd = ::open(devpath,O_RDWR);
- if (_fd > 0) {
- _dev = desiredDevice;
- recalledDevice = true;
- }
- }
- }
-
- // Open the first unused tap device if we didn't recall a previous one.
- if (!recalledDevice) {
- for(int i=0;i<64;++i) {
- Utils::snprintf(devpath,sizeof(devpath),"/dev/zt%d",i);
- if (stat(devpath,&stattmp))
- throw std::runtime_error("no more TAP devices available");
- _fd = ::open(devpath,O_RDWR);
- if (_fd > 0) {
- char foo[16];
- Utils::snprintf(foo,sizeof(foo),"zt%d",i);
- _dev = foo;
- break;
- }
- }
- }
-
- if (_fd <= 0)
- throw std::runtime_error("unable to open TAP device or no more devices available");
-
- if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
- ::close(_fd);
- throw std::runtime_error("unable to set flags on file descriptor for TAP device");
- }
-
- // Configure MAC address and MTU, bring interface up
- Utils::snprintf(ethaddr,sizeof(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]);
- Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu);
- Utils::snprintf(metstr,sizeof(metstr),"%u",_metric);
- long cpid = (long)vfork();
- if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
- ::_exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- if (exitcode) {
- ::close(_fd);
- throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
- }
- }
-
- _setIpv6Stuff(_dev.c_str(),true,false);
-
- // 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);
-
- ::pipe(_shutdownSignalPipe);
-
- _thread = Thread::start(this);
-}
-
-OSXEthernetTap::~OSXEthernetTap()
-{
- ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
- Thread::join(_thread);
- ::close(_fd);
- ::close(_shutdownSignalPipe[0]);
- ::close(_shutdownSignalPipe[1]);
-}
-
-void OSXEthernetTap::setEnabled(bool en)
-{
- _enabled = en;
- // TODO: interface status change
-}
-
-bool OSXEthernetTap::enabled() const
-{
- return _enabled;
-}
-
-static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
-{
- long cpid = (long)vfork();
- if (cpid == 0) {
- execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0);
- _exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- waitpid(cpid,&exitcode,0);
- return (exitcode == 0);
- }
- return false; // never reached, make compiler shut up about return value
-}
-
-bool OSXEthernetTap::addIP(const InetAddress &ip)
-{
- if (!ip)
- return false;
-
- std::set<InetAddress> allIps(ips());
- if (allIps.count(ip) > 0)
- return true; // IP/netmask already assigned
-
- // Remove and reconfigure if address is the same but netmask is different
- for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
- if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
- if (___removeIp(_dev,*i))
- break;
- }
- }
-
- long cpid = (long)vfork();
- if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0);
- ::_exit(-1);
- } else if (cpid > 0) {
- int exitcode = -1;
- ::waitpid(cpid,&exitcode,0);
- return (exitcode == 0);
- }
- return false;
-}
-
-bool OSXEthernetTap::removeIP(const InetAddress &ip)
-{
- if (ips().count(ip) > 0) {
- if (___removeIp(_dev,ip))
- return true;
- }
- return false;
-}
-
-std::set<InetAddress> OSXEthernetTap::ips() const
-{
- struct ifaddrs *ifa = (struct ifaddrs *)0;
- if (getifaddrs(&ifa))
- return std::set<InetAddress>();
-
- std::set<InetAddress> r;
-
- struct ifaddrs *p = ifa;
- while (p) {
- if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
- switch(p->ifa_addr->sa_family) {
- case AF_INET: {
- struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
- struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
- r.insert(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
- } break;
- case AF_INET6: {
- struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
- struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
- uint32_t b[4];
- memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
- r.insert(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
- } break;
- }
- }
- p = p->ifa_next;
- }
-
- if (ifa)
- freeifaddrs(ifa);
-
- return r;
-}
-
-void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- char putBuf[4096];
- if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
- to.copyTo(putBuf,6);
- from.copyTo(putBuf + 6,6);
- *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
- memcpy(putBuf + 14,data,len);
- len += 14;
- ::write(_fd,putBuf,len);
- }
-}
-
-std::string OSXEthernetTap::deviceName() const
-{
- return _dev;
-}
-
-void OSXEthernetTap::setFriendlyName(const char *friendlyName)
-{
-}
-
-bool OSXEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
-{
- std::set<MulticastGroup> newGroups;
- struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0;
- if (!_intl_getifmaddrs(&ifmap)) {
- struct _intl_ifmaddrs *p = ifmap;
- while (p) {
- if (p->ifma_addr->sa_family == AF_LINK) {
- struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
- struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
- if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
- newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
- }
- p = p->ifma_next;
- }
- _intl_freeifmaddrs(ifmap);
- }
-
- {
- std::set<InetAddress> allIps(ips());
- for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i)
- newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
- }
-
- bool changed = false;
-
- for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) {
- if (!groups.count(*mg)) {
- groups.insert(*mg);
- changed = true;
- }
- }
- for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
- if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
- groups.erase(mg++);
- changed = true;
- } else ++mg;
- }
-
- return changed;
-}
-
-bool OSXEthernetTap::injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- return false;
-}
-
-void OSXEthernetTap::threadMain()
- throw()
-{
- fd_set readfds,nullfds;
- MAC to,from;
- int n,nfds,r;
- char getBuf[8194];
- Buffer<4096> data;
-
- // Wait for a moment after startup -- wait for Network to finish
- // constructing itself.
- Thread::sleep(500);
-
- FD_ZERO(&readfds);
- FD_ZERO(&nullfds);
- nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
-
- r = 0;
- for(;;) {
- FD_SET(_shutdownSignalPipe[0],&readfds);
- FD_SET(_fd,&readfds);
- select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
-
- if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
- break;
-
- if (FD_ISSET(_fd,&readfds)) {
- n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
- if (n < 0) {
- if ((errno != EINTR)&&(errno != ETIMEDOUT))
- break;
- } else {
- // Some tap drivers like to send the ethernet frame and the
- // payload in two chunks, so handle that by accumulating
- // data until we have at least a frame.
- r += n;
- if (r > 14) {
- if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
- r = _mtu + 14;
-
- if (_enabled) {
- to.setTo(getBuf,6);
- from.setTo(getBuf + 6,6);
- unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
- data.copyFrom(getBuf + 14,(unsigned int)r - 14);
- _handler(_arg,from,to,etherType,data);
- }
-
- r = 0;
- }
- }
- }
- }
-}
-
-} // namespace ZeroTier
diff --git a/osnet/OSXEthernetTap.hpp b/osnet/OSXEthernetTap.hpp
deleted file mode 100644
index efcb550f..00000000
--- a/osnet/OSXEthernetTap.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_OSXETHERNETTAP_HPP
-#define ZT_OSXETHERNETTAP_HPP
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <stdexcept>
-
-#include "../node/EthernetTap.hpp"
-#include "../node/Thread.hpp"
-
-namespace ZeroTier {
-
-/**
- * OSX Ethernet tap using ZeroTier kernel extension zt# devices
- *
- * This also installs a friendly-named network device in the system network
- * configuration, permitting network devices to be seen and configured in
- * the OSX system preferences app.
- */
-class OSXEthernetTap : public EthernetTap
-{
-public:
- OSXEthernetTap(
- const MAC &mac,
- 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 *arg);
-
- virtual ~OSXEthernetTap();
-
- virtual void setEnabled(bool en);
- virtual bool enabled() const;
- virtual bool addIP(const InetAddress &ip);
- virtual bool removeIP(const InetAddress &ip);
- virtual std::set<InetAddress> ips() const;
- virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
- virtual std::string deviceName() const;
- virtual void setFriendlyName(const char *friendlyName);
- virtual bool updateMulticastGroups(std::set<MulticastGroup> &groups);
- virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
-
- void threadMain()
- throw();
-
-private:
- void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
- void *_arg;
- Thread _thread;
- std::string _dev;
- unsigned int _mtu;
- unsigned int _metric;
- int _fd;
- int _shutdownSignalPipe[2];
- volatile bool _enabled;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/OSXEthernetTapFactory.cpp b/osnet/OSXEthernetTapFactory.cpp
deleted file mode 100644
index 4cad8daa..00000000
--- a/osnet/OSXEthernetTapFactory.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "OSXEthernetTapFactory.hpp"
-#include "OSXEthernetTap.hpp"
-
-#include "../node/Utils.hpp"
-
-namespace ZeroTier {
-
-OSXEthernetTapFactory::OSXEthernetTapFactory(const char *pathToTapKext,const char *tapKextName) :
- _pathToTapKext((pathToTapKext) ? pathToTapKext : ""),
- _tapKextName((tapKextName) ? tapKextName : "")
-{
- struct stat stattmp;
-
- if ((_pathToTapKext.length())&&(_tapKextName.length())) {
- if (stat("/dev/zt0",&stattmp)) {
- long kextpid = (long)vfork();
- if (kextpid == 0) {
- ::chdir(_pathToTapKext.c_str());
- Utils::redirectUnixOutputs("/dev/null",(const char *)0);
- ::execl("/sbin/kextload","/sbin/kextload","-q","-repository",_pathToTapKext.c_str(),_tapKextName.c_str(),(const char *)0);
- ::_exit(-1);
- } else if (kextpid > 0) {
- int exitcode = -1;
- ::waitpid(kextpid,&exitcode,0);
- } else throw std::runtime_error("unable to create subprocess with fork()");
- }
- }
-
- if (stat("/dev/zt0",&stattmp)) {
- ::usleep(500); // give tap device driver time to start up and try again
- if (stat("/dev/zt0",&stattmp))
- throw std::runtime_error("/dev/zt# tap devices do not exist and unable to load kernel extension");
- }
-}
-
-OSXEthernetTapFactory::~OSXEthernetTapFactory()
-{
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
- delete *d;
-
- if ((_pathToTapKext.length())&&(_tapKextName.length())) {
- // Attempt to unload kext. If anything else is using a /dev/zt# node, this
- // fails and the kext stays in the kernel.
- char tmp[16384];
- sprintf(tmp,"%s/%s",_pathToTapKext.c_str(),_tapKextName.c_str());
- long kextpid = (long)vfork();
- if (kextpid == 0) {
- Utils::redirectUnixOutputs("/dev/null",(const char *)0);
- ::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0);
- ::_exit(-1);
- } else if (kextpid > 0) {
- int exitcode = -1;
- ::waitpid(kextpid,&exitcode,0);
- }
- }
-}
-
-EthernetTap *OSXEthernetTapFactory::open(
- const MAC &mac,
- 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 *arg)
-{
- Mutex::Lock _l(_devices_m);
- EthernetTap *t = new OSXEthernetTap(mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
- _devices.push_back(t);
- return t;
-}
-
-void OSXEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
-{
- {
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
- if (*d == tap) {
- _devices.erase(d);
- break;
- }
- }
- }
- delete tap;
-}
-
-} // namespace ZeroTier
diff --git a/osnet/OSXEthernetTapFactory.hpp b/osnet/OSXEthernetTapFactory.hpp
deleted file mode 100644
index 2f2ee527..00000000
--- a/osnet/OSXEthernetTapFactory.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_OSXETHERNETTAPFACTORY_HPP
-#define ZT_OSXETHERNETTAPFACTORY_HPP
-
-#include <vector>
-#include <string>
-
-#include "../node/EthernetTapFactory.hpp"
-#include "../node/Mutex.hpp"
-
-namespace ZeroTier {
-
-class OSXEthernetTapFactory : public EthernetTapFactory
-{
-public:
- /**
- * Create OSX ethernet tap factory
- *
- * If kext paths are specified, an attempt will be made to load the kext
- * on launch if not present and unload it on shutdown.
- *
- * @param pathToTapKext Full path to the location of the tap kext
- * @param tapKextName Name of tap kext as found within tap kext path (usually "tap.kext")
- * @throws std::runtime_error Tap not available and unable to load kext
- */
- OSXEthernetTapFactory(const char *pathToTapKext,const char *tapKextName);
-
- virtual ~OSXEthernetTapFactory();
-
- virtual EthernetTap *open(
- const MAC &mac,
- 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 *arg);
- virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
-
-private:
- std::vector<EthernetTap *> _devices;
- Mutex _devices_m;
- std::string _pathToTapKext;
- std::string _tapKextName;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/Phy.hpp b/osnet/Phy.hpp
deleted file mode 100644
index 6abdf8ad..00000000
--- a/osnet/Phy.hpp
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_PHY_HPP
-#define ZT_PHY_HPP
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <list>
-
-#if defined(_WIN32) || defined(_WIN64)
-
-#include <WinSock2.h>
-#include <WS2tcpip.h>
-#include <Windows.h>
-
-#define ZT_PHY_SOCKFD_TYPE SOCKET
-#define ZT_PHY_SOCKFD_NULL (INVALID_SOCKET)
-#define ZT_PHY_SOCKFD_VALID(s) ((s) != INVALID_SOCKET)
-#define ZT_PHY_CLOSE_SOCKET(s) ::closesocket(s)
-#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE)
-#define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage
-
-#else // not Windows
-
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#define ZT_PHY_SOCKFD_TYPE int
-#define ZT_PHY_SOCKFD_NULL (-1)
-#define ZT_PHY_SOCKFD_VALID(s) ((s) > -1)
-#define ZT_PHY_CLOSE_SOCKET(s) ::close(s)
-#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE)
-#define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage
-
-#endif // Windows or not
-
-namespace ZeroTier {
-
-/**
- * Opaque socket type
- */
-typedef void PhySocket;
-
-/**
- * Simple templated non-blocking sockets implementation
- *
- * Yes there is boost::asio and libuv, but I like small binaries and I hate
- * build dependencies. Both drag in a whole bunch of pasta with them.
- *
- * This implementation takes four functions or function objects as template
- * paramters:
- *
- * ON_DATAGRAM_FUNCTION(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
- * ON_TCP_CONNECT_FUNCTION(PhySocket *sock,void **uptr,bool success)
- * ON_TCP_ACCEPT_FUNCTION(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
- * ON_TCP_CLOSE_FUNCTION(PhySocket *sock,void **uptr)
- * ON_TCP_DATA_FUNCTION(PhySocket *sock,void **uptr,void *data,unsigned long len)
- * ON_TCP_WRITABLE_FUNCTION(PhySocket *sock,void **uptr)
- *
- * These templates typically refer to function objects. Templates are used to
- * avoid the call overhead of indirection, which is surprisingly high for high
- * bandwidth applications pushing a lot of packets.
- *
- * The 'sock' pointer above is an opaque pointer to a socket. Each socket
- * has a 'uptr' user-settable/modifiable pointer associated with it, which
- * can be set on bind/connect calls and is passed as a void ** to permit
- * resetting at any time. The ACCEPT handler takes two sets of sock and
- * uptr: sockL and uptrL for the listen socket, and sockN and uptrN for
- * the new TCP connection socket that has just been created.
- *
- * Handlers are always called. On outgoing TCP connection, CONNECT is always
- * called on either success or failure followed by DATA and/or WRITABLE as
- * indicated. On socket close, handlers are called unless close() is told
- * explicitly not to call handlers. It is safe to close a socket within a
- * handler, and in that case close() can be told not to call handlers to
- * prevent recursion.
- *
- * This isn't thread-safe with the exception of whack(), which is safe to
- * call from another thread to abort poll().
- */
-template <
- typename ON_DATAGRAM_FUNCTION,
- typename ON_TCP_CONNECT_FUNCTION,
- typename ON_TCP_ACCEPT_FUNCTION,
- typename ON_TCP_CLOSE_FUNCTION,
- typename ON_TCP_DATA_FUNCTION,
- typename ON_TCP_WRITABLE_FUNCTION >
-class Phy
-{
-private:
- ON_DATAGRAM_FUNCTION _datagramHandler;
- ON_TCP_CONNECT_FUNCTION _tcpConnectHandler;
- ON_TCP_ACCEPT_FUNCTION _tcpAcceptHandler;
- ON_TCP_CLOSE_FUNCTION _tcpCloseHandler;
- ON_TCP_DATA_FUNCTION _tcpDataHandler;
- ON_TCP_WRITABLE_FUNCTION _tcpWritableHandler;
-
- enum PhySocketType
- {
- ZT_PHY_SOCKET_TCP_OUT_PENDING = 0x00,
- ZT_PHY_SOCKET_TCP_OUT_CONNECTED = 0x01,
- ZT_PHY_SOCKET_TCP_IN = 0x02,
- ZT_PHY_SOCKET_TCP_LISTEN = 0x03,
- ZT_PHY_SOCKET_RAW = 0x04,
- ZT_PHY_SOCKET_UDP = 0x05
- };
-
- struct PhySocketImpl
- {
- PhySocketType type;
- ZT_PHY_SOCKFD_TYPE sock;
- void *uptr; // user-settable pointer
- ZT_PHY_SOCKADDR_STORAGE_TYPE saddr; // remote for TCP_OUT and TCP_IN, local for TCP_LISTEN, RAW, and UDP
- };
-
- std::list<PhySocketImpl> _socks;
- fd_set _readfds;
- fd_set _writefds;
-#if defined(_WIN32) || defined(_WIN64)
- fd_set _exceptfds;
-#endif
- long _nfds;
-
- ZT_PHY_SOCKFD_TYPE _whackReceiveSocket;
- ZT_PHY_SOCKFD_TYPE _whackSendSocket;
-
- bool _noDelay;
-
-public:
- /**
- * @param datagramHandler Function or function object to handle UDP or RAW datagrams
- * @param tcpConnectHandler Handler for outgoing TCP connection attempts (success or failure)
- * @param tcpAcceptHandler Handler for incoming TCP connections
- * @param tcpDataHandler Handler for incoming TCP data
- * @param tcpWritableHandler Handler to be called when TCP sockets are writable (if notification is on)
- * @param noDelay If true, disable Nagle algorithm on new TCP sockets
- */
- Phy(
- ON_DATAGRAM_FUNCTION datagramHandler,
- ON_TCP_CONNECT_FUNCTION tcpConnectHandler,
- ON_TCP_ACCEPT_FUNCTION tcpAcceptHandler,
- ON_TCP_CLOSE_FUNCTION tcpCloseHandler,
- ON_TCP_DATA_FUNCTION tcpDataHandler,
- ON_TCP_WRITABLE_FUNCTION tcpWritableHandler,
- bool noDelay
- ) :
- _datagramHandler(datagramHandler),
- _tcpConnectHandler(tcpConnectHandler),
- _tcpAcceptHandler(tcpAcceptHandler),
- _tcpCloseHandler(tcpCloseHandler),
- _tcpDataHandler(tcpDataHandler),
- _tcpWritableHandler(tcpWritableHandler)
- {
- FD_ZERO(&_readfds);
- FD_ZERO(&_writefds);
-
-#if defined(_WIN32) || defined(_WIN64)
- FD_ZERO(&_exceptfds);
-
- SOCKET pipes[2];
- { // hack copied from StackOverflow, behaves a bit like pipe() on *nix systems
- struct sockaddr_in inaddr;
- struct sockaddr addr;
- SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
- if (lst == INVALID_SOCKET)
- throw std::runtime_error("unable to create pipes for select() abort");
- memset(&inaddr, 0, sizeof(inaddr));
- memset(&addr, 0, sizeof(addr));
- inaddr.sin_family = AF_INET;
- inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- inaddr.sin_port = 0;
- int yes=1;
- setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes));
- bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr));
- listen(lst,1);
- int len=sizeof(inaddr);
- getsockname(lst, &addr,&len);
- pipes[0]=::socket(AF_INET, SOCK_STREAM,0);
- if (pipes[0] == INVALID_SOCKET)
- throw std::runtime_error("unable to create pipes for select() abort");
- connect(pipes[0],&addr,len);
- pipes[1]=accept(lst,0,0);
- closesocket(lst);
- }
-#else // not Windows
- int pipes[2];
- if (::pipe(pipes))
- throw std::runtime_error("unable to create pipes for select() abort");
-#endif // Windows or not
-
- _nfds = (pipes[0] > pipes[1]) ? (long)pipes[0] : (long)pipes[1];
- _whackReceiveSocket = pipes[0];
- _whackSendSocket = pipes[1];
- _noDelay = noDelay;
- }
-
- ~Phy()
- {
- while (!_socks.empty())
- this->close((PhySocket *)&(_socks.front()),true);
- ZT_PHY_CLOSE_SOCKET(_whackReceiveSocket);
- ZT_PHY_CLOSE_SOCKET(_whackSendSocket);
- }
-
- /**
- * Cause poll() to stop waiting immediately
- */
- inline void whack()
- {
-#if defined(_WIN32) || defined(_WIN64)
- ::send(_whackSendSocket,(const char *)this,1,0);
-#else
- ::write(_whackSendSocket,(PhySocket *)this,1);
-#endif
- }
-
- /**
- * @return Number of open sockets
- */
- inline unsigned long count() const throw() { return _socks.size(); }
-
- /**
- * @return Maximum number of sockets allowed
- */
- inline unsigned long maxCount() const throw() { return ZT_PHY_MAX_SOCKETS; }
-
- /**
- * Bind a UDP socket
- *
- * @param localAddress Local endpoint address and port
- * @param uptr Initial value of user pointer associated with this socket (default: NULL)
- * @param bufferSize Desired socket receive/send buffer size -- will set as close to this as possible (default: 0, leave alone)
- * @return Socket or NULL on failure to bind
- */
- inline PhySocket *udpBind(const struct sockaddr *localAddress,void *uptr = (void *)0,int bufferSize = 0)
- {
- if (_socks.size() >= ZT_PHY_MAX_SOCKETS)
- return (PhySocket *)0;
-
- ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family,SOCK_DGRAM,0);
- if (!ZT_PHY_SOCKFD_VALID(s))
- return (PhySocket *)0;
-
- if (bufferSize > 0) {
- int bs = bufferSize;
- while (bs >= 65536) {
- int tmpbs = bs;
- if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
- break;
- bs -= 16384;
- }
- bs = bufferSize;
- while (bs >= 65536) {
- int tmpbs = bs;
- if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
- break;
- bs -= 16384;
- }
- }
-
-#if defined(_WIN32) || defined(_WIN64)
- {
- BOOL f;
- if (localAddress->sa_family == AF_INET6) {
- f = TRUE; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f));
- f = FALSE; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,(const char *)&f,sizeof(f));
- }
- f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
- f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f));
- }
-#else // not Windows
- {
- int f;
- if (localAddress->sa_family == AF_INET6) {
- f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
-#ifdef IPV6_MTU_DISCOVER
- f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f));
-#endif
- }
- f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
- f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
-#ifdef IP_DONTFRAG
- f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f));
-#endif
-#ifdef IP_MTU_DISCOVER
- f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
-#endif
- }
-#endif // Windows or not
-
- if (::bind(s,localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
- ZT_PHY_CLOSE_SOCKET(s);
- return (PhySocket *)0;
- }
-
-#if defined(_WIN32) || defined(_WIN64)
- { u_long iMode=1; ioctlsocket(s,FIONBIO,&iMode); }
-#else
- fcntl(s,F_SETFL,O_NONBLOCK);
-#endif
-
- try {
- _socks.push_back(PhySocketImpl());
- } catch ( ... ) {
- ZT_PHY_CLOSE_SOCKET(s);
- return (PhySocket *)0;
- }
- PhySocketImpl &sws = _socks.back();
-
- if ((long)s > _nfds)
- _nfds = (long)s;
- FD_SET(s,&_readfds);
- sws.type = ZT_PHY_SOCKET_UDP;
- sws.sock = s;
- sws.uptr = uptr;
- memset(&(sws.saddr),0,sizeof(struct sockaddr_storage));
- memcpy(&(sws.saddr),localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
-
- return (PhySocket *)&sws;
- }
-
- /**
- * Send a UDP packet
- *
- * @param sock UDP socket
- * @param remoteAddress Destination address (must be correct type for socket)
- * @param data Data to send
- * @param len Length of packet
- * @return True if packet appears to have been sent successfully
- */
- inline bool udpSend(PhySocket *sock,const struct sockaddr *remoteAddress,const void *data,unsigned long len)
- {
- PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
- return ((long)::sendto(sws.sock,data,len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len);
- }
-
- /**
- * Bind a local listen socket to listen for new TCP connections
- *
- * @param localAddress Local address and port
- * @param uptr Initial value of uptr for new socket (default: NULL)
- * @return Socket or NULL on failure to bind
- */
- inline PhySocket *tcpListen(const struct sockaddr *localAddress,void *uptr = (void *)0)
- {
- if (_socks.size() >= ZT_PHY_MAX_SOCKETS)
- return (PhySocket *)0;
-
- ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family,SOCK_STREAM,0);
- if (!ZT_PHY_SOCKFD_VALID(s))
- return (PhySocket *)0;
-
-#if defined(_WIN32) || defined(_WIN64)
- {
- BOOL f;
- f = TRUE; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f));
- f = TRUE; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
- f = (_noDelay ? TRUE : FALSE); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f));
- u_long iMode=1;
- ioctlsocket(s,FIONBIO,&iMode);
- }
-#else
- {
- int f;
- f = 1; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
- f = 1; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
- f = (_noDelay ? 1 : 0); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f));
- fcntl(s,F_SETFL,O_NONBLOCK);
- }
-#endif
-
- if (::bind(s,localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
- ZT_PHY_CLOSE_SOCKET(s);
- return (PhySocket *)0;
- }
-
- if (::listen(s,1024)) {
- ZT_PHY_CLOSE_SOCKET(s);
- return (PhySocket *)0;
- }
-
- try {
- _socks.push_back(PhySocketImpl());
- } catch ( ... ) {
- ZT_PHY_CLOSE_SOCKET(s);
- return (PhySocket *)0;
- }
- PhySocketImpl &sws = _socks.back();
-
- if ((long)s > _nfds)
- _nfds = (long)s;
- FD_SET(s,&_readfds);
- sws.type = ZT_PHY_SOCKET_TCP_LISTEN;
- sws.sock = s;
- sws.uptr = uptr;
- memset(&(sws.saddr),0,sizeof(struct sockaddr_storage));
- memcpy(&(sws.saddr),localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
-
- return (PhySocket *)&sws;
- }
-
- /**
- * Start a non-blocking connect; CONNECT handler is called on success or failure
- *
- * A return value of NULL indicates a synchronous failure such as a
- * failure to open a socket. The TCP connection handler is not called
- * in this case.
- *
- * It is possible on some platforms for an "instant connect" to occur,
- * such as when connecting to a loopback address. In this case, the
- * 'connected' result parameter will be set to 'true' and if the
- * 'callConnectHandler' flag is true (the default) the TCP connect
- * handler will be called before the function returns.
- *
- * These semantics can be a bit confusing, but they're less so than
- * the underlying semantics of asynchronous TCP connect.
- *
- * @param remoteAddress Remote address
- * @param connected Result parameter: set to whether an "instant connect" has occurred (true if yes)
- * @param uptr Initial value of uptr for new socket (default: NULL)
- * @param callConnectHandler If true, call TCP connect handler even if result is known before function exit (default: true)
- * @return New socket or NULL on failure
- */
- inline PhySocket *tcpConnect(const struct sockaddr *remoteAddress,bool &connected,void *uptr = (void *)0,bool callConnectHandler = true)
- {
- if (_socks.size() >= ZT_PHY_MAX_SOCKETS)
- return (PhySocket *)0;
-
- ZT_PHY_SOCKFD_TYPE s = ::socket(remoteAddress->sa_family,SOCK_STREAM,0);
- if (!ZT_PHY_SOCKFD_VALID(s)) {
- connected = false;
- return (PhySocket *)0;
- }
-
-#if defined(_WIN32) || defined(_WIN64)
- {
- BOOL f;
- f = TRUE; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f));
- f = TRUE; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
- f = (_noDelay ? TRUE : FALSE); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f));
- u_long iMode=1;
- ioctlsocket(s,FIONBIO,&iMode);
- }
-#else
- {
- int f;
- f = 1; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
- f = 1; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
- f = (_noDelay ? 1 : 0); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f));
- fcntl(s,F_SETFL,O_NONBLOCK);
- }
-#endif
-
- connected = true;
- if (::connect(s,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
- connected = false;
-#if defined(_WIN32) || defined(_WIN64)
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
-#else
- if (errno != EINPROGRESS) {
-#endif
- ZT_PHY_CLOSE_SOCKET(s);
- return (PhySocket *)0;
- } // else connection is proceeding asynchronously...
- }
-
- try {
- _socks.push_back(PhySocketImpl());
- } catch ( ... ) {
- ZT_PHY_CLOSE_SOCKET(s);
- return (PhySocket *)0;
- }
- PhySocketImpl &sws = _socks.back();
-
- if ((long)s > _nfds)
- _nfds = (long)s;
- if (connected) {
- FD_SET(s,&_readfds);
- sws.type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED;
- } else {
- FD_SET(s,&_writefds);
-#if defined(_WIN32) || defined(_WIN64)
- FD_SET(s,&_exceptfds);
-#endif
- sws.type = ZT_PHY_SOCKET_TCP_OUT_PENDING;
- }
- sws.sock = s;
- sws.uptr = uptr;
- memset(&(sws.saddr),0,sizeof(struct sockaddr_storage));
- memcpy(&(sws.saddr),remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
-
- if ((callConnectHandler)&&(connected)) {
- try {
- _tcpConnectHandler((PhySocket *)&sws,&(sws.uptr),true);
- } catch ( ... ) {}
- }
-
- return (PhySocket *)&sws;
- }
-
- /**
- * Attempt to send data to a TCP connection (non-blocking)
- *
- * If -1 is returned, the socket should no longer be used as it is now
- * destroyed. If callCloseHandler is true, the close handler will be
- * called before the function returns.
- *
- * @param sock An open TCP socket (other socket types will fail)
- * @param data Data to send
- * @param len Length of data
- * @param callCloseHandler If true, call close handler on socket closing failure condition
- * @return Number of bytes actually sent or -1 on fatal error (socket closure)
- */
- inline long tcpSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler)
- {
- PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
- long n = (long)::send(sws.sock,data,len,0);
-#if defined(_WIN32) || defined(_WIN64)
- if (n == SOCKET_ERROR) {
- switch(WSAGetLastError()) {
- case WSAEINTR:
- case WSAEWOULDBLOCK:
- return 0;
- default:
- this->close(sock,callCloseHandler);
- return -1;
- }
- }
-#else // not Windows
- if (n < 0) {
- switch(errno) {
-#ifdef EAGAIN
- case EAGAIN:
-#endif
-#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) )
- case EWOULDBLOCK:
-#endif
-#ifdef EINTR
- case EINTR:
-#endif
- return 0;
- default:
- this->close(sock,callCloseHandler);
- return -1;
- }
- }
-#endif // Windows or not
- return n;
- }
-
- /**
- * Set whether we want to be notified via the TCP writability handler when a socket is writable
- *
- * Call whack() if this is being done from another thread and you want
- * it to take effect immediately. Otherwise it is only guaranteed to
- * take effect on the next poll().
- *
- * @param sock TCP connection socket (other types are not valid)
- * @param notifyWritable Want writable notifications?
- */
- inline const void tcpSetNotifyWritable(PhySocket *sock,bool notifyWritable)
- {
- PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
- if (notifyWritable) {
- FD_SET(sws.sock,&_writefds);
- } else {
- FD_CLR(sws.sock,&_writefds);
- }
- }
-
- /**
- * Wait for activity and handle one or more events
- *
- * Note that this is not guaranteed to wait up to 'timeout' even
- * if nothing happens, as whack() or other events such as signals
- * may cause premature termination.
- *
- * @param timeout Timeout in milliseconds or 0 for none (forever)
- */
- inline void poll(unsigned long timeout)
- {
- char buf[131072];
- struct sockaddr_storage ss;
- struct timeval tv;
- fd_set rfds,wfds,efds;
-
- memcpy(&rfds,&_readfds,sizeof(rfds));
- memcpy(&wfds,&_writefds,sizeof(wfds));
-#if defined(_WIN32) || defined(_WIN64)
- memcpy(&efds,&_exceptfds,sizeof(efds));
-#else
- FD_ZERO(&efds);
-#endif
-
- tv.tv_sec = (long)(timeout / 1000);
- tv.tv_usec = (long)((timeout % 1000) * 1000);
- if (::select((int)_nfds + 1,&rfds,&wfds,&efds,(timeout > 0) ? &tv : (struct timeval *)0) <= 0)
- return;
-
- if (FD_ISSET(_whackReceiveSocket,&rfds)) {
- char tmp[16];
-#if defined(_WIN32) || defined(_WIN64)
- ::recv(_whackReceiveSocket,tmp,16,0);
-#else
- ::read(_whackReceiveSocket,tmp,16);
-#endif
- }
-
- for(typename std::list<PhySocketImpl>::iterator s(_socks.begin()),nexts;s!=_socks.end();s=nexts) {
- nexts = s; ++nexts; // we can delete the linked list item, so traverse now
-
- switch (s->type) {
-
- case ZT_PHY_SOCKET_TCP_OUT_PENDING:
-#if defined(_WIN32) || defined(_WIN64)
- if (FD_ISSET(s->sock,&efds))
- this->close((PhySocket *)&(*s),true);
- else // ... if
-#endif
- if (FD_ISSET(s->sock,&wfds)) {
- socklen_t slen = sizeof(ss);
- if (::getpeername(s->sock,(struct sockaddr *)&ss,&slen) != 0) {
- this->close((PhySocket *)&(*s),true);
- } else {
- s->type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED;
- FD_SET(s->sock,&_readfds);
- FD_CLR(s->sock,&_writefds);
-#if defined(_WIN32) || defined(_WIN64)
- FD_CLR(s->sock,&_exceptfds);
-#endif
- try {
- _tcpConnectHandler((PhySocket *)&(*s),&(s->uptr),true);
- } catch ( ... ) {}
- }
- }
- break;
-
- case ZT_PHY_SOCKET_TCP_OUT_CONNECTED:
- case ZT_PHY_SOCKET_TCP_IN:
- if (FD_ISSET(s->sock,&rfds)) {
- long n = (long)::recv(s->sock,buf,sizeof(buf),0);
- if (n <= 0) {
- this->close((PhySocket *)&(*s),true);
- } else {
- try {
- _tcpDataHandler((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n);
- } catch ( ... ) {}
- }
- }
- if ((FD_ISSET(s->sock,&wfds))&&(FD_ISSET(s->sock,&_writefds))) {
- try {
- _tcpWritableHandler((PhySocket *)&(*s),&(s->uptr));
- } catch ( ... ) {}
- }
- break;
-
- case ZT_PHY_SOCKET_TCP_LISTEN:
- if (FD_ISSET(s->sock,&rfds)) {
- memset(&ss,0,sizeof(ss));
- socklen_t slen = sizeof(ss);
- ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock,(struct sockaddr *)&ss,&slen);
- if (ZT_PHY_SOCKFD_VALID(newSock)) {
- if (_socks.size() >= ZT_PHY_MAX_SOCKETS) {
- ZT_PHY_CLOSE_SOCKET(newSock);
- } else {
-#if defined(_WIN32) || defined(_WIN64)
- { BOOL f = (_noDelay ? TRUE : FALSE); setsockopt(newSock,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
- { u_long iMode=1; ioctlsocket(newSock,FIONBIO,&iMode); }
-#else
- { int f = (_noDelay ? 1 : 0); setsockopt(newSock,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
- fcntl(newSock,F_SETFL,O_NONBLOCK);
-#endif
- _socks.push_back(PhySocketImpl());
- PhySocketImpl &sws = _socks.back();
- FD_SET(newSock,&_readfds);
- if ((long)newSock > _nfds)
- _nfds = (long)newSock;
- sws.type = ZT_PHY_SOCKET_TCP_IN;
- sws.sock = newSock;
- sws.uptr = (void *)0;
- memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage));
- try {
- _tcpAcceptHandler((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr),(const struct sockaddr *)&(sws.saddr));
- } catch ( ... ) {}
- }
- }
- }
- break;
-
- case ZT_PHY_SOCKET_UDP:
- if (FD_ISSET(s->sock,&rfds)) {
- memset(&ss,0,sizeof(ss));
- socklen_t slen = sizeof(ss);
- long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen);
- if (n > 0) {
- try {
- _datagramHandler((PhySocket *)&(*s),&(s->uptr),(const struct sockaddr *)&ss,(void *)buf,(unsigned long)n);
- } catch ( ... ) {}
- }
- }
- break;
-
- default:
- break;
-
- }
- }
- }
-
- inline void close(PhySocket *sock,bool callHandlers)
- {
- if (!sock)
- return;
- PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
-
- FD_CLR(sws.sock,&_readfds);
- FD_CLR(sws.sock,&_writefds);
-#if defined(_WIN32) || defined(_WIN64)
- FD_CLR(sws.sock,&_exceptfds);
-#endif
-
- ZT_PHY_CLOSE_SOCKET(sws.sock);
-
- switch(sws.type) {
- case ZT_PHY_SOCKET_TCP_OUT_PENDING:
- if (callHandlers) {
- try {
- _tcpConnectHandler(sock,&(sws.uptr),false);
- } catch ( ... ) {}
- }
- break;
- case ZT_PHY_SOCKET_TCP_OUT_CONNECTED:
- case ZT_PHY_SOCKET_TCP_IN:
- if (callHandlers) {
- try {
- _tcpCloseHandler(sock,&(sws.uptr));
- } catch ( ... ) {}
- }
- break;
- default:
- break;
- }
-
- long oldSock = (long)sws.sock;
-
- for(typename std::list<PhySocketImpl>::iterator s(_socks.begin());s!=_socks.end();++s) {
- if (reinterpret_cast<PhySocket *>(&(*s)) == sock) {
- _socks.erase(s);
- break;
- }
- }
-
- if (oldSock >= _nfds) {
- long nfds = (long)_whackSendSocket;
- if ((long)_whackReceiveSocket > nfds)
- nfds = (long)_whackReceiveSocket;
- for(typename std::list<PhySocketImpl>::iterator s(_socks.begin());s!=_socks.end();++s) {
- if ((long)s->sock > nfds)
- nfds = (long)s->sock;
- }
- _nfds = nfds;
- }
- }
-};
-
-// Typedefs for using regular naked functions as template parameters to Phy<>
-typedef void (*Phy_OnDatagramFunctionPtr)(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len);
-typedef void (*Phy_OnTcpConnectFunction)(PhySocket *sock,void **uptr,bool success);
-typedef void (*Phy_OnTcpAcceptFunction)(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from);
-typedef void (*Phy_OnTcpCloseFunction)(PhySocket *sock,void **uptr);
-typedef void (*Phy_OnTcpDataFunction)(PhySocket *sock,void **uptr,void *data,unsigned long len);
-typedef void (*Phy_OnTcpWritableFunction)(PhySocket *sock,void **uptr);
-
-/**
- * Phy<> typedef'd to use simple naked function pointers
- */
-typedef Phy<Phy_OnDatagramFunctionPtr,Phy_OnTcpConnectFunction,Phy_OnTcpAcceptFunction,Phy_OnTcpCloseFunction,Phy_OnTcpDataFunction,Phy_OnTcpWritableFunction> SimpleFunctionPhy;
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/README.md b/osnet/README.md
deleted file mode 100644
index 114e26f2..00000000
--- a/osnet/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Network and Virtual Network Port Interfaces for Real OSes
-======
-
-This folder contains implementations of EthernetTap, EthernetTapFactory, and RoutingTable that bind to operating system level interfaces and drivers on Linux, Mac, Windows, and other platforms.
-
-It also contains NativeSocketManager which implements SocketManager using standard sockets (or WinSock2) and select() for multiplexing.
diff --git a/osnet/WindowsEthernetTap.cpp b/osnet/WindowsEthernetTap.cpp
deleted file mode 100644
index 5d445380..00000000
--- a/osnet/WindowsEthernetTap.cpp
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <WinSock2.h>
-#include <Windows.h>
-#include <tchar.h>
-#include <winreg.h>
-#include <wchar.h>
-#include <ws2ipdef.h>
-#include <WS2tcpip.h>
-#include <IPHlpApi.h>
-#include <nldef.h>
-#include <netioapi.h>
-#include <atlbase.h>
-#include <netlistmgr.h>
-#include <nldef.h>
-
-#include <iostream>
-
-#include "../node/Constants.hpp"
-
-#include "WindowsEthernetTap.hpp"
-#include "WindowsEthernetTapFactory.hpp"
-#include "../node/Utils.hpp"
-#include "../node/Mutex.hpp"
-
-#include "..\windows\TapDriver\tap-windows.h"
-
-// ff:ff:ff:ff:ff:ff with no ADI
-static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
-
-#define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE
-
-namespace ZeroTier {
-
-// Only create or delete devices one at a time
-static Mutex _systemTapInitLock;
-
-WindowsEthernetTap::WindowsEthernetTap(
- const char *pathToHelpers,
- const MAC &mac,
- 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 *arg) :
- EthernetTap("WindowsEthernetTap",mac,mtu,metric),
- _handler(handler),
- _arg(arg),
- _nwid(nwid),
- _tap(INVALID_HANDLE_VALUE),
- _injectSemaphore(INVALID_HANDLE_VALUE),
- _pathToHelpers(pathToHelpers),
- _run(true),
- _initialized(false),
- _enabled(true)
-{
- char subkeyName[4096];
- char subkeyClass[4096];
- char data[4096];
- char tag[24];
-
- if (mtu > 2800)
- throw std::runtime_error("MTU too large for Windows tap");
-
- Mutex::Lock _l(_systemTapInitLock);
-
- HKEY nwAdapters;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS)
- throw std::runtime_error("unable to open registry key for network adapter enumeration");
-
- std::set<std::string> existingDeviceInstances;
- std::string mySubkeyName;
-
- // We "tag" registry entries with the network ID to identify persistent devices
- Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid);
-
- // Look for the tap instance that corresponds with this network
- for(DWORD subkeyIndex=0;;++subkeyIndex) {
- DWORD type;
- DWORD dataLen;
- DWORD subkeyNameLen = sizeof(subkeyName);
- DWORD subkeyClassLen = sizeof(subkeyClass);
- FILETIME lastWriteTime;
- if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) {
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
- data[dataLen] = '\0';
- if (!strnicmp(data,"zttap",5)) {
- std::string instanceId;
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
- instanceId.assign(data,dataLen);
- existingDeviceInstances.insert(instanceId);
- }
-
- std::string instanceIdPath;
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
- instanceIdPath.assign(data,dataLen);
-
- if ((_netCfgInstanceId.length() == 0)&&(instanceId.length() != 0)&&(instanceIdPath.length() != 0)) {
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
- data[dataLen] = '\0';
- if (!strcmp(data,tag)) {
- _netCfgInstanceId = instanceId;
- _deviceInstanceId = instanceIdPath;
-
- mySubkeyName = subkeyName;
- break; // found it!
- }
- }
- }
- }
- }
- } else break; // no more subkeys or error occurred enumerating them
- }
-
- // If there is no device, try to create one
- bool creatingNewDevice = (_netCfgInstanceId.length() == 0);
- if (creatingNewDevice) {
- // Log devcon output to a file
- HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
- if (devconLog != INVALID_HANDLE_VALUE)
- SetFilePointer(devconLog,0,0,FILE_END);
-
- // Execute devcon to install an instance of the Microsoft Loopback Adapter
- STARTUPINFOA startupInfo;
- startupInfo.cb = sizeof(startupInfo);
- if (devconLog != INVALID_HANDLE_VALUE) {
- SetFilePointer(devconLog,0,0,FILE_END);
- startupInfo.hStdOutput = devconLog;
- startupInfo.hStdError = devconLog;
- }
- PROCESS_INFORMATION processInfo;
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" install \"" + _pathToHelpers + WindowsEthernetTapFactory::WINENV.tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- RegCloseKey(nwAdapters);
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
- throw std::runtime_error(std::string("unable to find or execute devcon at ") + WindowsEthernetTapFactory::WINENV.devcon);
- }
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
-
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
-
- // Scan for the new instance by simply looking for taps that weren't originally there...
- for(DWORD subkeyIndex=0;;++subkeyIndex) {
- DWORD type;
- DWORD dataLen;
- DWORD subkeyNameLen = sizeof(subkeyName);
- DWORD subkeyClassLen = sizeof(subkeyClass);
- FILETIME lastWriteTime;
- if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) {
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
- data[dataLen] = '\0';
- if (!strnicmp(data,"zttap",5)) {
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
- if (existingDeviceInstances.count(std::string(data,dataLen)) == 0) {
- RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1));
- _netCfgInstanceId.assign(data,dataLen);
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
- _deviceInstanceId.assign(data,dataLen);
- mySubkeyName = subkeyName;
-
- // Disable DHCP by default on newly created devices
- HKEY tcpIpInterfaces;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
- DWORD enable = 0;
- RegSetKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable));
- RegCloseKey(tcpIpInterfaces);
- }
-
- break; // found it!
- }
- }
- }
- }
- } else break; // no more keys or error occurred
- }
- }
-
- if (_netCfgInstanceId.length() > 0) {
- char tmps[64];
- unsigned int tmpsl = Utils::snprintf(tmps,sizeof(tmps),"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",(unsigned int)mac[0],(unsigned int)mac[1],(unsigned int)mac[2],(unsigned int)mac[3],(unsigned int)mac[4],(unsigned int)mac[5]) + 1;
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,tmpsl);
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MAC",REG_SZ,tmps,tmpsl);
- DWORD tmp = mtu;
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MTU",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
-
- tmp = 0;
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*NdisDeviceType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
- tmp = IF_TYPE_ETHERNET_CSMACD;
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
-
- if (creatingNewDevice) {
- tmp = 0;
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
- }
- RegCloseKey(nwAdapters);
- } else {
- RegCloseKey(nwAdapters);
- throw std::runtime_error("unable to find or create tap adapter");
- }
-
- // Convert device GUID junk... blech... is there an easier way to do this?
- {
- char nobraces[128];
- const char *nbtmp1 = _netCfgInstanceId.c_str();
- char *nbtmp2 = nobraces;
- while (*nbtmp1) {
- if ((*nbtmp1 != '{')&&(*nbtmp1 != '}'))
- *nbtmp2++ = *nbtmp1;
- ++nbtmp1;
- }
- *nbtmp2 = (char)0;
- if (UuidFromStringA((RPC_CSTR)nobraces,&_deviceGuid) != RPC_S_OK)
- throw std::runtime_error("unable to convert instance ID GUID to native GUID (invalid NetCfgInstanceId in registry?)");
- }
-
- // Look up interface LUID... why are there (at least) four fucking ways to refer to a network device in Windows?
- if (ConvertInterfaceGuidToLuid(&_deviceGuid,&_deviceLuid) != NO_ERROR)
- throw std::runtime_error("unable to convert device interface GUID to LUID");
-
- if (friendlyName)
- setFriendlyName(friendlyName);
-
- // Start background thread that actually performs I/O
- _injectSemaphore = CreateSemaphore(NULL,0,1,NULL);
- _thread = Thread::start(this);
-
- // Certain functions can now work (e.g. ips())
- _initialized = true;
-}
-
-WindowsEthernetTap::~WindowsEthernetTap()
-{
- _run = false;
- ReleaseSemaphore(_injectSemaphore,1,NULL);
- Thread::join(_thread);
- CloseHandle(_injectSemaphore);
- _disableTapDevice();
-}
-
-void WindowsEthernetTap::setEnabled(bool en)
-{
- _enabled = en;
-}
-
-bool WindowsEthernetTap::enabled() const
-{
- return _enabled;
-}
-
-bool WindowsEthernetTap::addIP(const InetAddress &ip)
-{
- if (!_initialized)
- return false;
- if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT?
- return false;
-
- std::set<InetAddress> haveIps(ips());
-
- try {
- // Add IP to interface at the netlink level if not already assigned.
- if (!haveIps.count(ip)) {
- MIB_UNICASTIPADDRESS_ROW ipr;
-
- InitializeUnicastIpAddressEntry(&ipr);
- if (ip.isV4()) {
- ipr.Address.Ipv4.sin_family = AF_INET;
- ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)ip.rawIpData());
- ipr.OnLinkPrefixLength = ip.port();
- if (ipr.OnLinkPrefixLength >= 32)
- return false;
- } else if (ip.isV6()) {
- ipr.Address.Ipv6.sin6_family = AF_INET6;
- memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,ip.rawIpData(),16);
- ipr.OnLinkPrefixLength = ip.port();
- if (ipr.OnLinkPrefixLength >= 128)
- return false;
- } else return false;
-
- ipr.PrefixOrigin = IpPrefixOriginManual;
- ipr.SuffixOrigin = IpSuffixOriginManual;
- ipr.ValidLifetime = 0xffffffff;
- ipr.PreferredLifetime = 0xffffffff;
-
- ipr.InterfaceLuid = _deviceLuid;
- ipr.InterfaceIndex = _getDeviceIndex();
-
- if (CreateUnicastIpAddressEntry(&ipr) == NO_ERROR) {
- haveIps.insert(ip);
- } else {
- return false;
- }
- }
-
- std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress"));
- if (std::find(regIps.begin(),regIps.end(),ip.toIpString()) == regIps.end()) {
- std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask"));
- regIps.push_back(ip.toIpString());
- regSubnetMasks.push_back(ip.netmask().toIpString());
- _setRegistryIPv4Value("IPAddress",regIps);
- _setRegistryIPv4Value("SubnetMask",regSubnetMasks);
- }
- //_syncIpsWithRegistry(haveIps,_netCfgInstanceId);
- } catch ( ... ) {
- return false;
- }
- return true;
-}
-
-bool WindowsEthernetTap::removeIP(const InetAddress &ip)
-{
- if (!_initialized)
- return false;
- try {
- MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0;
- if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) {
- for(DWORD i=0;i<ipt->NumEntries;++i) {
- if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) {
- InetAddress addr;
- switch(ipt->Table[i].Address.si_family) {
- case AF_INET:
- addr.set(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength);
- break;
- case AF_INET6:
- addr.set(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength);
- if (addr.isLinkLocal())
- continue; // can't remove link-local IPv6 addresses
- break;
- }
- if (addr == ip) {
- DeleteUnicastIpAddressEntry(&(ipt->Table[i]));
- FreeMibTable(ipt);
-
- std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress"));
- std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask"));
- std::string ipstr(ip.toIpString());
- for(std::vector<std::string>::iterator rip(regIps.begin()),rm(regSubnetMasks.begin());((rip!=regIps.end())&&(rm!=regSubnetMasks.end()));++rip,++rm) {
- if (*rip == ipstr) {
- regIps.erase(rip);
- regSubnetMasks.erase(rm);
- _setRegistryIPv4Value("IPAddress",regIps);
- _setRegistryIPv4Value("SubnetMask",regSubnetMasks);
- break;
- }
- }
-
- return true;
- }
- }
- }
- FreeMibTable((PVOID)ipt);
- }
- } catch ( ... ) {}
- return false;
-}
-
-std::set<InetAddress> WindowsEthernetTap::ips() const
-{
- static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it?
- std::set<InetAddress> addrs;
-
- if (!_initialized)
- return addrs;
-
- try {
- MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0;
- if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) {
- for(DWORD i=0;i<ipt->NumEntries;++i) {
- if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) {
- switch(ipt->Table[i].Address.si_family) {
- case AF_INET: {
- InetAddress ip(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength);
- if (ip != InetAddress::LO4)
- addrs.insert(ip);
- } break;
- case AF_INET6: {
- InetAddress ip(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength);
- if ((ip != linkLocalLoopback)&&(ip != InetAddress::LO6))
- addrs.insert(ip);
- } break;
- }
- }
- }
- FreeMibTable(ipt);
- }
- } catch ( ... ) {} // sanity check, shouldn't happen unless out of memory
-
- return addrs;
-}
-
-void WindowsEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- if ((!_initialized)||(!_enabled)||(_tap == INVALID_HANDLE_VALUE)||(len > (ZT_IF_MTU)))
- return;
-
- Mutex::Lock _l(_injectPending_m);
- _injectPending.push( std::pair<Array<char,ZT_IF_MTU + 32>,unsigned int>(Array<char,ZT_IF_MTU + 32>(),len + 14) );
- char *d = _injectPending.back().first.data;
- to.copyTo(d,6);
- from.copyTo(d + 6,6);
- d[12] = (char)((etherType >> 8) & 0xff);
- d[13] = (char)(etherType & 0xff);
- memcpy(d + 14,data,len);
-
- ReleaseSemaphore(_injectSemaphore,1,NULL);
-}
-
-std::string WindowsEthernetTap::deviceName() const
-{
- char tmp[1024];
- if (ConvertInterfaceLuidToNameA(&_deviceLuid,tmp,sizeof(tmp)) != NO_ERROR)
- return std::string("[ConvertInterfaceLuidToName() failed]");
- return std::string(tmp);
-}
-
-void WindowsEthernetTap::setFriendlyName(const char *dn)
-{
- if (!_initialized)
- return;
- HKEY ifp;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,(std::string("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\") + _netCfgInstanceId).c_str(),0,KEY_READ|KEY_WRITE,&ifp) == ERROR_SUCCESS) {
- RegSetKeyValueA(ifp,"Connection","Name",REG_SZ,(LPCVOID)dn,(DWORD)(strlen(dn)+1));
- RegCloseKey(ifp);
- }
-}
-
-bool WindowsEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
-{
- if (!_initialized)
- return false;
- HANDLE t = _tap;
- if (t == INVALID_HANDLE_VALUE)
- return false;
-
- std::set<MulticastGroup> newGroups;
-
- // Ensure that groups are added for each IP... this handles the MAC:ADI
- // groups that are created from IPv4 addresses. Some of these may end
- // up being duplicates of what the IOCTL returns but that's okay since
- // the set<> will filter that.
- std::set<InetAddress> ipaddrs(ips());
- for(std::set<InetAddress>::const_iterator i(ipaddrs.begin());i!=ipaddrs.end();++i)
- newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
-
- // The ZT1 tap driver supports an IOCTL to get multicast memberships at the L2
- // level... something Windows does not seem to expose ordinarily. This lets
- // pretty much anything work... IPv4, IPv6, IPX, oldskool Netbios, who knows...
- unsigned char mcastbuf[TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE];
- DWORD bytesReturned = 0;
- if (DeviceIoControl(t,TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS,(LPVOID)0,0,(LPVOID)mcastbuf,sizeof(mcastbuf),&bytesReturned,NULL)) {
- MAC mac;
- DWORD i = 0;
- while ((i + 6) <= bytesReturned) {
- mac.setTo(mcastbuf + i,6);
- i += 6;
- if ((mac.isMulticast())&&(!mac.isBroadcast())) {
- // exclude the nulls that may be returned or any other junk Windows puts in there
- newGroups.insert(MulticastGroup(mac,0));
- }
- }
- }
-
- bool changed = false;
-
- for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) {
- if (!groups.count(*mg)) {
- groups.insert(*mg);
- changed = true;
- }
- }
- for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
- if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
- groups.erase(mg++);
- changed = true;
- } else ++mg;
- }
-
- return changed;
-}
-
-bool WindowsEthernetTap::injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- return false;
-}
-
-void WindowsEthernetTap::threadMain()
- throw()
-{
- char tapPath[256];
- OVERLAPPED tapOvlRead,tapOvlWrite;
- HANDLE wait4[3];
- char *tapReadBuf = (char *)0;
-
- // Shouldn't be needed, but Windows does not overcommit. This Windows
- // tap code is defensive to schizoid paranoia degrees.
- while (!tapReadBuf) {
- tapReadBuf = (char *)::malloc(ZT_IF_MTU + 32);
- if (!tapReadBuf)
- Sleep(1000);
- }
-
- // Tap is in this weird Windows global pseudo file space
- Utils::snprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str());
-
- /* More insanity: repetatively try to enable/disable tap device. The first
- * time we succeed, close it and do it again. This is to fix a driver init
- * bug that seems to be extremely non-deterministic and to only occur after
- * headless MSI upgrade. It cannot be reproduced in any other circumstance.
- *
- * Eventually when ZeroTier has actual money we will have someone create an
- * NDIS6 tap driver. Yes, we'll likely be cool and open source it. */
- bool throwOneAway = true;
- while (_run) {
- _disableTapDevice();
- Sleep(250);
- if (!_enableTapDevice()) {
- ::free(tapReadBuf);
- _enabled = false;
- return; // only happens if devcon is missing or totally fails
- }
- Sleep(250);
-
- _tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL);
- if (_tap == INVALID_HANDLE_VALUE) {
- Sleep(500);
- continue;
- }
-
- {
- uint32_t tmpi = 1;
- DWORD bytesReturned = 0;
- DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL);
- bytesReturned = 0;
- DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL);
- }
-
- {
-#ifdef ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE
- /* This inserts a fake default route and a fake ARP entry, forcing
- * Windows to detect this as a "real" network and apply proper
- * firewall rules.
- *
- * This hack is completely stupid, but Windows made me do it
- * by being broken and insane.
- *
- * Background: Windows tries to detect its network location by
- * matching it to the ARP address of the default route. Networks
- * without default routes are "unidentified networks" and cannot
- * have their firewall classification changed by the user (easily).
- *
- * Yes, you read that right.
- *
- * The common workaround is to set *NdisDeviceType to 1, which
- * totally disables all Windows firewall functionality. This is
- * the answer you'll find on most forums for things like OpenVPN.
- *
- * Yes, you read that right.
- *
- * The default route workaround is also known, but for this to
- * work there must be a known default IP that resolves to a known
- * ARP address. This works for an OpenVPN tunnel, but not here
- * because this isn't a tunnel. It's a mesh. There is no "other
- * end," or any other known always on IP.
- *
- * So let's make a fake one and shove it in there along with its
- * fake static ARP entry. Also makes it instant-on and static.
- *
- * We'll have to see what DHCP does with this. In the future we
- * probably will not want to do this on DHCP-enabled networks, so
- * when we enable DHCP we will go in and yank this wacko hacko from
- * the routing table before doing so.
- *
- * Like Jesse Pinkman would say: "YEEEEAAH BITCH!" */
- const uint32_t fakeIp = htonl(0x19fffffe); // 25.255.255.254 -- unrouted IPv4 block
- for(int i=0;i<8;++i) {
- MIB_IPNET_ROW2 ipnr;
- memset(&ipnr,0,sizeof(ipnr));
- ipnr.Address.si_family = AF_INET;
- ipnr.Address.Ipv4.sin_addr.s_addr = fakeIp;
- ipnr.InterfaceLuid.Value = _deviceLuid.Value;
- ipnr.PhysicalAddress[0] = _mac[0] ^ 0x10; // just make something up that's consistent and not part of this net
- ipnr.PhysicalAddress[1] = 0x00;
- ipnr.PhysicalAddress[2] = (UCHAR)((_deviceGuid.Data1 >> 24) & 0xff);
- ipnr.PhysicalAddress[3] = (UCHAR)((_deviceGuid.Data1 >> 16) & 0xff);
- ipnr.PhysicalAddress[4] = (UCHAR)((_deviceGuid.Data1 >> 8) & 0xff);
- ipnr.PhysicalAddress[5] = (UCHAR)(_deviceGuid.Data1 & 0xff);
- ipnr.PhysicalAddressLength = 6;
- ipnr.State = NlnsPermanent;
- ipnr.IsRouter = 1;
- ipnr.IsUnreachable = 0;
- ipnr.ReachabilityTime.LastReachable = 0x0fffffff;
- ipnr.ReachabilityTime.LastUnreachable = 1;
- DWORD result = CreateIpNetEntry2(&ipnr);
- if (result != NO_ERROR)
- Sleep(500);
- else break;
- }
- for(int i=0;i<8;++i) {
- MIB_IPFORWARD_ROW2 nr;
- memset(&nr,0,sizeof(nr));
- InitializeIpForwardEntry(&nr);
- nr.InterfaceLuid.Value = _deviceLuid.Value;
- nr.DestinationPrefix.Prefix.si_family = AF_INET; // rest is left as 0.0.0.0/0
- nr.NextHop.si_family = AF_INET;
- nr.NextHop.Ipv4.sin_addr.s_addr = fakeIp;
- nr.Metric = 9999; // do not use as real default route
- nr.Protocol = MIB_IPPROTO_NETMGMT;
- DWORD result = CreateIpForwardEntry2(&nr);
- if (result != NO_ERROR)
- Sleep(500);
- else break;
- }
-#endif
- }
-
- if (throwOneAway) {
- throwOneAway = false;
- CloseHandle(_tap);
- _tap = INVALID_HANDLE_VALUE;
- Sleep(1000);
- continue;
- } else break;
- }
-
- memset(&tapOvlRead,0,sizeof(tapOvlRead));
- tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
- memset(&tapOvlWrite,0,sizeof(tapOvlWrite));
- tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
-
- wait4[0] = _injectSemaphore;
- wait4[1] = tapOvlRead.hEvent;
- wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true
-
- // Start overlapped read, which is always active
- ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead);
- bool writeInProgress = false;
-
- for(;;) {
- if (!_run) break;
- DWORD r = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,5000,TRUE);
- if (!_run) break;
-
- if ((r == WAIT_TIMEOUT)||(r == WAIT_FAILED))
- continue;
-
- if (HasOverlappedIoCompleted(&tapOvlRead)) {
- DWORD bytesRead = 0;
- if (GetOverlappedResult(_tap,&tapOvlRead,&bytesRead,FALSE)) {
- if ((bytesRead > 14)&&(_enabled)) {
- MAC to(tapReadBuf,6);
- MAC from(tapReadBuf + 6,6);
- unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff);
- try {
- Buffer<4096> tmp(tapReadBuf + 14,bytesRead - 14);
- _handler(_arg,from,to,etherType,tmp);
- } catch ( ... ) {} // handlers should not throw
- }
- }
- ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead);
- }
-
- if (writeInProgress) {
- if (HasOverlappedIoCompleted(&tapOvlWrite)) {
- writeInProgress = false;
- _injectPending_m.lock();
- _injectPending.pop();
- } else continue; // still writing, so skip code below and wait
- } else _injectPending_m.lock();
-
- if (!_injectPending.empty()) {
- WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&tapOvlWrite);
- writeInProgress = true;
- }
-
- _injectPending_m.unlock();
- }
-
- CancelIo(_tap);
-
- CloseHandle(tapOvlRead.hEvent);
- CloseHandle(tapOvlWrite.hEvent);
- CloseHandle(_tap);
- _tap = INVALID_HANDLE_VALUE;
-
- ::free(tapReadBuf);
-}
-
-bool WindowsEthernetTap::_disableTapDevice()
-{
- HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
- if (devconLog != INVALID_HANDLE_VALUE)
- SetFilePointer(devconLog,0,0,FILE_END);
-
- STARTUPINFOA startupInfo;
- startupInfo.cb = sizeof(startupInfo);
- if (devconLog != INVALID_HANDLE_VALUE) {
- startupInfo.hStdOutput = devconLog;
- startupInfo.hStdError = devconLog;
- }
- PROCESS_INFORMATION processInfo;
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" disable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
- return false;
- }
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
-
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
-
- return true;
-}
-
-bool WindowsEthernetTap::_enableTapDevice()
-{
- HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
- if (devconLog != INVALID_HANDLE_VALUE)
- SetFilePointer(devconLog,0,0,FILE_END);
-
- STARTUPINFOA startupInfo;
- startupInfo.cb = sizeof(startupInfo);
- if (devconLog != INVALID_HANDLE_VALUE) {
- startupInfo.hStdOutput = devconLog;
- startupInfo.hStdError = devconLog;
- }
- PROCESS_INFORMATION processInfo;
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" enable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
- return false;
- }
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
-
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
-
- return true;
-}
-
-NET_IFINDEX WindowsEthernetTap::_getDeviceIndex()
-{
- MIB_IF_TABLE2 *ift = (MIB_IF_TABLE2 *)0;
-
- if (GetIfTable2Ex(MibIfTableRaw,&ift) != NO_ERROR)
- throw std::runtime_error("GetIfTable2Ex() failed");
-
- for(ULONG i=0;i<ift->NumEntries;++i) {
- if (ift->Table[i].InterfaceLuid.Value == _deviceLuid.Value) {
- NET_IFINDEX idx = ift->Table[i].InterfaceIndex;
- FreeMibTable(ift);
- return idx;
- }
- }
-
- FreeMibTable(&ift);
-
- throw std::runtime_error("interface not found");
-}
-
-std::vector<std::string> WindowsEthernetTap::_getRegistryIPv4Value(const char *regKey)
-{
- std::vector<std::string> value;
- HKEY tcpIpInterfaces;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
- char buf[16384];
- DWORD len = sizeof(buf);
- DWORD kt = REG_MULTI_SZ;
- if (RegGetValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey,0,&kt,&buf,&len) == ERROR_SUCCESS) {
- switch(kt) {
- case REG_SZ:
- if (len > 0)
- value.push_back(std::string(buf));
- break;
- case REG_MULTI_SZ: {
- for(DWORD k=0,s=0;k<len;++k) {
- if (!buf[k]) {
- if (s < k) {
- value.push_back(std::string(buf + s));
- s = k + 1;
- } else break;
- }
- }
- } break;
- }
- }
- RegCloseKey(tcpIpInterfaces);
- }
- return value;
-}
-
-void WindowsEthernetTap::_setRegistryIPv4Value(const char *regKey,const std::vector<std::string> &value)
-{
- std::string regMulti;
- for(std::vector<std::string>::const_iterator s(value.begin());s!=value.end();++s) {
- regMulti.append(*s);
- regMulti.push_back((char)0);
- }
- HKEY tcpIpInterfaces;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
- if (regMulti.length() > 0) {
- regMulti.push_back((char)0);
- RegSetKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey,REG_MULTI_SZ,regMulti.data(),(DWORD)regMulti.length());
- } else {
- RegDeleteKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey);
- }
- RegCloseKey(tcpIpInterfaces);
- }
-}
-
-} // namespace ZeroTier
diff --git a/osnet/WindowsEthernetTap.hpp b/osnet/WindowsEthernetTap.hpp
deleted file mode 100644
index 08dc8d17..00000000
--- a/osnet/WindowsEthernetTap.hpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_WINDOWSETHERNETTAP_HPP
-#define ZT_WINDOWSETHERNETTAP_HPP
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <ifdef.h>
-
-#include <string>
-#include <queue>
-#include <stdexcept>
-
-#include "../node/Constants.hpp"
-#include "../node/EthernetTap.hpp"
-#include "../node/Mutex.hpp"
-#include "../node/Thread.hpp"
-#include "../node/Array.hpp"
-#include "../node/MulticastGroup.hpp"
-
-namespace ZeroTier {
-
-class WindowsEthernetTap : public EthernetTap
-{
-public:
- WindowsEthernetTap(
- const char *pathToHelpers,
- const MAC &mac,
- 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 *arg);
-
- virtual ~WindowsEthernetTap();
-
- virtual void setEnabled(bool en);
- virtual bool enabled() const;
- virtual bool addIP(const InetAddress &ip);
- virtual bool removeIP(const InetAddress &ip);
- virtual std::set<InetAddress> ips() const;
- virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
- virtual std::string deviceName() const;
- virtual void setFriendlyName(const char *friendlyName);
- virtual bool updateMulticastGroups(std::set<MulticastGroup> &groups);
- virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
-
- inline const NET_LUID &luid() const { return _deviceLuid; }
- inline const GUID &guid() const { return _deviceGuid; }
- inline const std::string &instanceId() const { return _deviceInstanceId; }
-
- void threadMain()
- throw();
-
-private:
- bool _disableTapDevice();
- bool _enableTapDevice();
- NET_IFINDEX _getDeviceIndex(); // throws on failure
- std::vector<std::string> _getRegistryIPv4Value(const char *regKey);
- void _setRegistryIPv4Value(const char *regKey,const std::vector<std::string> &value);
-
- void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
- void *_arg;
- uint64_t _nwid;
- Thread _thread;
-
- volatile HANDLE _tap;
- HANDLE _injectSemaphore;
-
- GUID _deviceGuid;
- NET_LUID _deviceLuid;
- std::string _netCfgInstanceId; // NetCfgInstanceId, a GUID
- std::string _deviceInstanceId; // DeviceInstanceID, another kind of "instance ID"
-
- std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending;
- Mutex _injectPending_m;
-
- std::string _pathToHelpers;
-
- volatile bool _run;
- volatile bool _initialized;
- volatile bool _enabled;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/osnet/WindowsEthernetTapFactory.cpp b/osnet/WindowsEthernetTapFactory.cpp
deleted file mode 100644
index 996460a1..00000000
--- a/osnet/WindowsEthernetTapFactory.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include "WindowsEthernetTapFactory.hpp"
-#include "WindowsEthernetTap.hpp"
-
-namespace ZeroTier {
-
-WindowsEthernetTapFactory::Env::Env()
-{
-#ifdef _WIN64
- is64Bit = TRUE;
- devcon = "\\devcon_x64.exe";
- tapDriver = "\\tap-windows\\x64\\zttap200.inf";
-#else
- is64Bit = FALSE;
- IsWow64Process(GetCurrentProcess(),&is64Bit);
- devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe");
- tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf");
-#endif
-}
-const WindowsEthernetTapFactory::Env WindowsEthernetTapFactory::WINENV;
-
-WindowsEthernetTapFactory::WindowsEthernetTapFactory(const char *pathToHelpers) :
- _pathToHelpers(pathToHelpers)
-{
-}
-
-WindowsEthernetTapFactory::~WindowsEthernetTapFactory()
-{
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
- delete *d;
-}
-
-EthernetTap *WindowsEthernetTapFactory::open(
- const MAC &mac,
- 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 *arg)
-{
- Mutex::Lock _l(_devices_m);
- EthernetTap *t = new WindowsEthernetTap(_pathToHelpers.c_str(),mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
- _devices.push_back(t);
- return t;
-}
-
-void WindowsEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
-{
- if (!tap)
- return;
-
- std::string instanceId(((WindowsEthernetTap *)tap)->instanceId());
- Mutex::Lock _l(_devices_m);
-
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
- if (*d == tap) {
- _devices.erase(d);
- break;
- }
- }
-
- delete tap;
-
- if (destroyPersistentDevices)
- _deletePersistentTapDevice(_pathToHelpers.c_str(),instanceId.c_str());
-}
-
-void WindowsEthernetTapFactory::destroyAllPersistentTapDevices(const char *pathToHelpers)
-{
- char subkeyName[4096];
- char subkeyClass[4096];
- char data[4096];
-
- std::set<std::string> instanceIdPathsToRemove;
- {
- HKEY nwAdapters;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS)
- return;
-
- for(DWORD subkeyIndex=0;;++subkeyIndex) {
- DWORD type;
- DWORD dataLen;
- DWORD subkeyNameLen = sizeof(subkeyName);
- DWORD subkeyClassLen = sizeof(subkeyClass);
- FILETIME lastWriteTime;
- if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) {
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
- data[dataLen] = '\0';
- if (!strnicmp(data,"zttap",5)) {
- std::string instanceIdPath;
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
- instanceIdPath.assign(data,dataLen);
- if (instanceIdPath.length() != 0)
- instanceIdPathsToRemove.insert(instanceIdPath);
- }
- }
- } else break; // end of list or failure
- }
-
- RegCloseKey(nwAdapters);
- }
-
- for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp)
- _deletePersistentTapDevice(pathToHelpers,iidp->c_str());
-}
-
-void WindowsEthernetTapFactory::_deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId)
-{
- HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
- STARTUPINFOA startupInfo;
- startupInfo.cb = sizeof(startupInfo);
- if (devconLog != INVALID_HANDLE_VALUE) {
- SetFilePointer(devconLog,0,0,FILE_END);
- startupInfo.hStdOutput = devconLog;
- startupInfo.hStdError = devconLog;
- }
- PROCESS_INFORMATION processInfo;
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
- }
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
-}
-
-} // namespace ZeroTier
diff --git a/osnet/WindowsEthernetTapFactory.hpp b/osnet/WindowsEthernetTapFactory.hpp
deleted file mode 100644
index 47e146e3..00000000
--- a/osnet/WindowsEthernetTapFactory.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_WINDOWSETHERNETTAPFACTORY_HPP
-#define ZT_WINDOWSETHERNETTAPFACTORY_HPP
-
-#include <vector>
-#include <string>
-
-#include "../node/EthernetTapFactory.hpp"
-#include "../node/Mutex.hpp"
-
-namespace ZeroTier {
-
-class WindowsEthernetTapFactory : public EthernetTapFactory
-{
-public:
- class Env
- {
- public:
- Env();
- BOOL is64Bit; // true if WIN64 or WoW64 (32-bit binary on 64-bit architecture)
- const char *devcon; // name of devcon binary in pathToHelpers to use
- const char *tapDriver; // relative path to driver under pathToHelpers to use
- };
-
- /**
- * Constants related to Windows environment, computed on program start
- */
- static const Env WINENV;
-
- /**
- * @param pathToHelpers Path to devcon32.exe, devcon64.exe, and other required helper binaries (ZeroTier running directory)
- */
- WindowsEthernetTapFactory(const char *pathToHelpers);
- virtual ~WindowsEthernetTapFactory();
-
- virtual EthernetTap *open(
- const MAC &mac,
- 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 *arg);
- virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
-
- /**
- * Uninstalls all persistent tap devices in the system belonging to ZeroTier
- *
- * This is for uninstallation. Do not call this while tap devices are active.
- */
- static void destroyAllPersistentTapDevices(const char *pathToHelpers);
-
-private:
- static void _deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId);
-
- std::string _pathToHelpers;
- std::vector<EthernetTap *> _devices;
- Mutex _devices_m;
-};
-
-} // namespace ZeroTier
-
-#endif