summaryrefslogtreecommitdiff
path: root/osdep
diff options
context:
space:
mode:
Diffstat (limited to 'osdep')
-rw-r--r--osdep/Arp.cpp10
-rw-r--r--osdep/Arp.hpp10
-rw-r--r--osdep/BSDEthernetTap.cpp88
-rw-r--r--osdep/BSDEthernetTap.hpp11
-rw-r--r--osdep/Binder.hpp544
-rw-r--r--osdep/BlockingQueue.hpp57
-rw-r--r--osdep/Http.cpp45
-rw-r--r--osdep/Http.hpp10
-rw-r--r--osdep/LinuxEthernetTap.cpp109
-rw-r--r--osdep/LinuxEthernetTap.hpp11
-rw-r--r--osdep/ManagedRoute.cpp30
-rw-r--r--osdep/ManagedRoute.hpp32
-rw-r--r--osdep/NeighborDiscovery.cpp14
-rw-r--r--osdep/NeighborDiscovery.hpp10
-rw-r--r--osdep/OSUtils.cpp81
-rw-r--r--osdep/OSUtils.hpp81
-rw-r--r--osdep/OSXEthernetTap.cpp52
-rw-r--r--osdep/OSXEthernetTap.hpp11
-rw-r--r--osdep/Phy.hpp39
-rw-r--r--osdep/PortMapper.cpp64
-rw-r--r--osdep/PortMapper.hpp10
-rw-r--r--osdep/TestEthernetTap.hpp161
-rw-r--r--osdep/Thread.hpp54
-rw-r--r--osdep/WindowsEthernetTap.cpp137
-rw-r--r--osdep/WindowsEthernetTap.hpp23
25 files changed, 1126 insertions, 568 deletions
diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp
index fcc122f0..cc4e920a 100644
--- a/osdep/Arp.cpp
+++ b/osdep/Arp.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include <stdio.h>
diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp
index 5f0d199a..27e92fdb 100644
--- a/osdep/Arp.hpp
+++ b/osdep/Arp.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_ARP_HPP
diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp
index 62fabc48..053df21d 100644
--- a/osdep/BSDEthernetTap.cpp
+++ b/osdep/BSDEthernetTap.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include <stdint.h>
@@ -86,9 +94,6 @@ BSDEthernetTap::BSDEthernetTap(
Mutex::Lock _gl(globalTapCreateLock);
- if (mtu > 2800)
- throw std::runtime_error("max tap MTU is 2800");
-
#ifdef __FreeBSD__
/* FreeBSD allows long interface names and interface renaming */
@@ -109,8 +114,8 @@ BSDEthernetTap::BSDEthernetTap(
std::vector<std::string> devFiles(OSUtils::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);
+ OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
+ OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) {
long cpid = (long)vfork();
if (cpid == 0) {
@@ -147,8 +152,8 @@ BSDEthernetTap::BSDEthernetTap(
/* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */
for(int i=0;i<64;++i) {
- Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
- Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
+ OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
+ OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
_fd = ::open(devpath,O_RDWR);
if (_fd > 0) {
_dev = tmpdevname;
@@ -166,9 +171,9 @@ BSDEthernetTap::BSDEthernetTap(
}
// 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);
+ OSUtils::ztsnprintf(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]);
+ OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu);
+ OSUtils::ztsnprintf(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);
@@ -222,7 +227,8 @@ 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);
+ char ipbuf[64];
+ execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString(ipbuf),"-alias",(const char *)0);
_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
@@ -251,7 +257,8 @@ bool BSDEthernetTap::addIp(const InetAddress &ip)
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);
+ char tmp[128];
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString(tmp),"alias",(const char *)0);
::_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
@@ -313,7 +320,7 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
- char putBuf[4096];
+ char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6);
@@ -373,49 +380,22 @@ void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std:
_multicastGroups.swap(newGroups);
}
-/*
-bool BSDEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
+void BSDEthernetTap::setMtu(unsigned int mtu)
{
- 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;
+ if (mtu != _mtu) {
+ _mtu = mtu;
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ char tmp[64];
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu);
+ execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0);
+ _exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ waitpid(cpid,&exitcode,0);
}
- 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;
}
-*/
void BSDEthernetTap::threadMain()
throw()
@@ -423,7 +403,7 @@ void BSDEthernetTap::threadMain()
fd_set readfds,nullfds;
MAC to,from;
int n,nfds,r;
- char getBuf[8194];
+ char getBuf[ZT_MAX_MTU + 64];
// Wait for a moment after startup -- wait for Network to finish
// constructing itself.
diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp
index 8c6314db..3d91dbbb 100644
--- a/osdep/BSDEthernetTap.hpp
+++ b/osdep/BSDEthernetTap.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_BSDETHERNETTAP_HPP
@@ -57,6 +65,7 @@ public:
std::string deviceName() const;
void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
+ void setMtu(unsigned int mtu);
void threadMain()
throw();
diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp
index 9829f170..93fad9f1 100644
--- a/osdep/Binder.hpp
+++ b/osdep/Binder.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_BINDER_HPP
@@ -49,8 +57,9 @@
#include <algorithm>
#include <utility>
#include <map>
+#include <set>
+#include <atomic>
-#include "../node/NonCopyable.hpp"
#include "../node/InetAddress.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
@@ -58,13 +67,12 @@
#include "Phy.hpp"
#include "OSUtils.hpp"
-/**
- * Period between binder rescans/refreshes
- *
- * OneService also does this on detected restarts.
- */
+// Period between refreshes of bindings
#define ZT_BINDER_REFRESH_PERIOD 30000
+// Max number of bindings
+#define ZT_BINDER_MAX_BINDINGS 256
+
namespace ZeroTier {
/**
@@ -78,29 +86,22 @@ namespace ZeroTier {
* On OSes that do not support local port enumeration or where this is not
* meaningful, this degrades to binding to wildcard.
*/
-class Binder : NonCopyable
+class Binder
{
private:
struct _Binding
{
- _Binding() :
- udpSock((PhySocket *)0),
- tcpListenSock((PhySocket *)0),
- address() {}
-
+ _Binding() : udpSock((PhySocket *)0),tcpListenSock((PhySocket *)0) {}
PhySocket *udpSock;
PhySocket *tcpListenSock;
InetAddress address;
};
public:
- Binder() {}
+ Binder() : _bindingCount(0) {}
/**
- * Close all bound ports
- *
- * This should be called on shutdown. It closes listen sockets and UDP ports
- * but not TCP connections from any TCP listen sockets.
+ * Close all bound ports, should be called on shutdown
*
* @param phy Physical interface
*/
@@ -108,10 +109,11 @@ public:
void closeAll(Phy<PHY_HANDLER_TYPE> &phy)
{
Mutex::Lock _l(_lock);
- for(typename std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i) {
- phy.close(i->udpSock,false);
- phy.close(i->tcpListenSock,false);
+ for(unsigned int b=0,c=_bindingCount;b<c;++b) {
+ phy.close(_bindings[b].udpSock,false);
+ phy.close(_bindings[b].tcpListenSock,false);
}
+ _bindingCount = 0;
}
/**
@@ -121,325 +123,341 @@ public:
* changes, on startup, or periodically (e.g. every 30-60s).
*
* @param phy Physical interface
- * @param port Port to bind to on all interfaces (TCP and UDP)
- * @param ignoreInterfacesByName Ignore these interfaces by name
- * @param ignoreInterfacesByNamePrefix Ignore these interfaces by name-prefix (starts-with, e.g. zt ignores zt*)
- * @param ignoreInterfacesByAddress Ignore these interfaces by address
+ * @param ports Ports to bind on all interfaces
+ * @param portCount Number of ports
+ * @param explicitBind If present, override interface IP detection and bind to these (if possible)
+ * @param ifChecker Interface checker function to see if an interface should be used
* @tparam PHY_HANDLER_TYPE Type for Phy<> template
* @tparam INTERFACE_CHECKER Type for class containing shouldBindInterface() method
*/
template<typename PHY_HANDLER_TYPE,typename INTERFACE_CHECKER>
- void refresh(Phy<PHY_HANDLER_TYPE> &phy,unsigned int port,INTERFACE_CHECKER &ifChecker)
+ void refresh(Phy<PHY_HANDLER_TYPE> &phy,unsigned int *ports,unsigned int portCount,const std::vector<InetAddress> explicitBind,INTERFACE_CHECKER &ifChecker)
{
std::map<InetAddress,std::string> localIfAddrs;
- PhySocket *udps;
- //PhySocket *tcps;
+ PhySocket *udps,*tcps;
Mutex::Lock _l(_lock);
+ bool interfacesEnumerated = true;
+ if (explicitBind.empty()) {
#ifdef __WINDOWS__
- char aabuf[32768];
- ULONG aalen = sizeof(aabuf);
- if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf),&aalen) == NO_ERROR) {
- PIP_ADAPTER_ADDRESSES a = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf);
- while (a) {
- PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress;
- while (ua) {
- InetAddress ip(ua->Address.lpSockaddr);
- if (ifChecker.shouldBindInterface("",ip)) {
- switch(ip.ipScope()) {
- default: break;
- case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
- case InetAddress::IP_SCOPE_GLOBAL:
- case InetAddress::IP_SCOPE_SHARED:
- case InetAddress::IP_SCOPE_PRIVATE:
- ip.setPort(port);
- localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string()));
- break;
+ char aabuf[32768];
+ ULONG aalen = sizeof(aabuf);
+ if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf),&aalen) == NO_ERROR) {
+ PIP_ADAPTER_ADDRESSES a = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf);
+ while (a) {
+ PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress;
+ while (ua) {
+ InetAddress ip(ua->Address.lpSockaddr);
+ if (ifChecker.shouldBindInterface("",ip)) {
+ switch(ip.ipScope()) {
+ default: break;
+ case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+ case InetAddress::IP_SCOPE_GLOBAL:
+ case InetAddress::IP_SCOPE_SHARED:
+ case InetAddress::IP_SCOPE_PRIVATE:
+ for(int x=0;x<(int)portCount;++x) {
+ ip.setPort(ports[x]);
+ localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string()));
+ }
+ break;
+ }
}
+ ua = ua->Next;
}
- ua = ua->Next;
+ a = a->Next;
}
- a = a->Next;
}
- }
+ else {
+ interfacesEnumerated = false;
+ }
#else // not __WINDOWS__
- /* On Linux we use an alternative method if available since getifaddrs()
- * gets very slow when there are lots of network namespaces. This won't
- * work unless /proc/PID/net/if_inet6 exists and it may not on some
- * embedded systems, so revert to getifaddrs() there. */
+ /* On Linux we use an alternative method if available since getifaddrs()
+ * gets very slow when there are lots of network namespaces. This won't
+ * work unless /proc/PID/net/if_inet6 exists and it may not on some
+ * embedded systems, so revert to getifaddrs() there. */
#ifdef __LINUX__
- char fn[256],tmp[256];
- std::set<std::string> ifnames;
- const unsigned long pid = (unsigned long)getpid();
-
- // Get all device names
- Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid);
- FILE *procf = fopen(fn,"r");
- if (procf) {
- while (fgets(tmp,sizeof(tmp),procf)) {
- tmp[255] = 0;
- char *saveptr = (char *)0;
- for(char *f=Utils::stok(tmp," \t\r\n:|",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n:|",&saveptr)) {
- if ((strcmp(f,"Inter-") != 0)&&(strcmp(f,"face") != 0)&&(f[0] != 0))
- ifnames.insert(f);
- break; // we only want the first field
+ char fn[256],tmp[256];
+ std::set<std::string> ifnames;
+ const unsigned long pid = (unsigned long)getpid();
+
+ // Get all device names
+ OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid);
+ FILE *procf = fopen(fn,"r");
+ if (procf) {
+ while (fgets(tmp,sizeof(tmp),procf)) {
+ tmp[255] = 0;
+ char *saveptr = (char *)0;
+ for(char *f=Utils::stok(tmp," \t\r\n:|",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n:|",&saveptr)) {
+ if ((strcmp(f,"Inter-") != 0)&&(strcmp(f,"face") != 0)&&(f[0] != 0))
+ ifnames.insert(f);
+ break; // we only want the first field
+ }
}
+ fclose(procf);
+ }
+ else {
+ interfacesEnumerated = false;
}
- fclose(procf);
- }
- // Get IPv6 addresses (and any device names we don't already know)
- Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid);
- procf = fopen(fn,"r");
- if (procf) {
- while (fgets(tmp,sizeof(tmp),procf)) {
- tmp[255] = 0;
- char *saveptr = (char *)0;
- unsigned char ipbits[16];
- memset(ipbits,0,sizeof(ipbits));
- char *devname = (char *)0;
- int n = 0;
- for(char *f=Utils::stok(tmp," \t\r\n",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n",&saveptr)) {
- switch(n++) {
- case 0: // IP in hex
- Utils::unhex(f,32,ipbits,16);
- break;
- case 5: // device name
- devname = f;
- break;
- }
- }
- if (devname) {
- ifnames.insert(devname);
- InetAddress ip(ipbits,16,0);
- if (ifChecker.shouldBindInterface(devname,ip)) {
- switch(ip.ipScope()) {
- default: break;
- case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
- case InetAddress::IP_SCOPE_GLOBAL:
- case InetAddress::IP_SCOPE_SHARED:
- case InetAddress::IP_SCOPE_PRIVATE:
- ip.setPort(port);
- localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(devname)));
+ // Get IPv6 addresses (and any device names we don't already know)
+ OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid);
+ procf = fopen(fn,"r");
+ if (procf) {
+ while (fgets(tmp,sizeof(tmp),procf)) {
+ tmp[255] = 0;
+ char *saveptr = (char *)0;
+ unsigned char ipbits[16];
+ memset(ipbits,0,sizeof(ipbits));
+ char *devname = (char *)0;
+ int n = 0;
+ for(char *f=Utils::stok(tmp," \t\r\n",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n",&saveptr)) {
+ switch(n++) {
+ case 0: // IP in hex
+ Utils::unhex(f,32,ipbits,16);
break;
+ case 5: // device name
+ devname = f;
+ break;
+ }
+ }
+ if (devname) {
+ ifnames.insert(devname);
+ InetAddress ip(ipbits,16,0);
+ if (ifChecker.shouldBindInterface(devname,ip)) {
+ switch(ip.ipScope()) {
+ default: break;
+ case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+ case InetAddress::IP_SCOPE_GLOBAL:
+ case InetAddress::IP_SCOPE_SHARED:
+ case InetAddress::IP_SCOPE_PRIVATE:
+ for(int x=0;x<(int)portCount;++x) {
+ ip.setPort(ports[x]);
+ localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(devname)));
+ }
+ break;
+ }
}
}
}
+ fclose(procf);
}
- fclose(procf);
- }
-
- // Get IPv4 addresses for each device
- if (ifnames.size() > 0) {
- const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0);
- struct ifconf configuration;
- configuration.ifc_len = 0;
- configuration.ifc_buf = nullptr;
-
- if (controlfd < 0) goto ip4_address_error;
-
- if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
- configuration.ifc_buf = (char*)malloc(configuration.ifc_len);
-
- if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
-
- for (int i=0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i ++) {
- struct ifreq& request = configuration.ifc_req[i];
- struct sockaddr* addr = &request.ifr_ifru.ifru_addr;
- if (addr->sa_family != AF_INET) continue;
- std::string ifname = request.ifr_ifrn.ifrn_name;
- // name can either be just interface name or interface name followed by ':' and arbitrary label
- if (ifname.find(':') != std::string::npos) {
- ifname = ifname.substr(0, ifname.find(':'));
- }
-
- InetAddress ip(&(((struct sockaddr_in *)addr)->sin_addr),4,0);
- if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) {
- switch(ip.ipScope()) {
- default: break;
- case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
- case InetAddress::IP_SCOPE_GLOBAL:
- case InetAddress::IP_SCOPE_SHARED:
- case InetAddress::IP_SCOPE_PRIVATE:
- ip.setPort(port);
- localIfAddrs.insert(std::pair<InetAddress,std::string>(ip, ifname));
- break;
+ // Get IPv4 addresses for each device
+ if (ifnames.size() > 0) {
+ const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0);
+ struct ifconf configuration;
+ configuration.ifc_len = 0;
+ configuration.ifc_buf = nullptr;
+
+ if (controlfd < 0) goto ip4_address_error;
+ if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
+ configuration.ifc_buf = (char*)malloc(configuration.ifc_len);
+ if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
+
+ for (int i=0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i ++) {
+ struct ifreq& request = configuration.ifc_req[i];
+ struct sockaddr* addr = &request.ifr_ifru.ifru_addr;
+ if (addr->sa_family != AF_INET) continue;
+ std::string ifname = request.ifr_ifrn.ifrn_name;
+ // name can either be just interface name or interface name followed by ':' and arbitrary label
+ if (ifname.find(':') != std::string::npos)
+ ifname = ifname.substr(0, ifname.find(':'));
+
+ InetAddress ip(&(((struct sockaddr_in *)addr)->sin_addr),4,0);
+ if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) {
+ switch(ip.ipScope()) {
+ default: break;
+ case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+ case InetAddress::IP_SCOPE_GLOBAL:
+ case InetAddress::IP_SCOPE_SHARED:
+ case InetAddress::IP_SCOPE_PRIVATE:
+ for(int x=0;x<(int)portCount;++x) {
+ ip.setPort(ports[x]);
+ localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,ifname));
+ }
+ break;
+ }
}
}
- }
- ip4_address_error:
- free(configuration.ifc_buf);
- if (controlfd > 0) close(controlfd);
- }
+ ip4_address_error:
+ free(configuration.ifc_buf);
+ if (controlfd > 0) close(controlfd);
+ }
- const bool gotViaProc = (localIfAddrs.size() > 0);
+ const bool gotViaProc = (localIfAddrs.size() > 0);
#else
- const bool gotViaProc = false;
+ const bool gotViaProc = false;
#endif
- if (!gotViaProc) {
- struct ifaddrs *ifatbl = (struct ifaddrs *)0;
- struct ifaddrs *ifa;
- if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) {
- ifa = ifatbl;
- while (ifa) {
- if ((ifa->ifa_name)&&(ifa->ifa_addr)) {
- InetAddress ip = *(ifa->ifa_addr);
- if (ifChecker.shouldBindInterface(ifa->ifa_name,ip)) {
- switch(ip.ipScope()) {
- default: break;
- case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
- case InetAddress::IP_SCOPE_GLOBAL:
- case InetAddress::IP_SCOPE_SHARED:
- case InetAddress::IP_SCOPE_PRIVATE:
- ip.setPort(port);
- localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(ifa->ifa_name)));
- break;
+ if (!gotViaProc) {
+ struct ifaddrs *ifatbl = (struct ifaddrs *)0;
+ struct ifaddrs *ifa;
+ if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) {
+ ifa = ifatbl;
+ while (ifa) {
+ if ((ifa->ifa_name)&&(ifa->ifa_addr)) {
+ InetAddress ip = *(ifa->ifa_addr);
+ if (ifChecker.shouldBindInterface(ifa->ifa_name,ip)) {
+ switch(ip.ipScope()) {
+ default: break;
+ case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+ case InetAddress::IP_SCOPE_GLOBAL:
+ case InetAddress::IP_SCOPE_SHARED:
+ case InetAddress::IP_SCOPE_PRIVATE:
+ for(int x=0;x<(int)portCount;++x) {
+ ip.setPort(ports[x]);
+ localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(ifa->ifa_name)));
+ }
+ break;
+ }
}
}
+ ifa = ifa->ifa_next;
}
- ifa = ifa->ifa_next;
+ freeifaddrs(ifatbl);
+ }
+ else {
+ interfacesEnumerated = false;
}
- freeifaddrs(ifatbl);
}
- }
#endif
+ } else {
+ for(std::vector<InetAddress>::const_iterator i(explicitBind.begin());i!=explicitBind.end();++i)
+ localIfAddrs.insert(std::pair<InetAddress,std::string>(*i,std::string()));
+ }
// Default to binding to wildcard if we can't enumerate addresses
- if (localIfAddrs.empty()) {
- localIfAddrs.insert(std::pair<InetAddress,std::string>(InetAddress((uint32_t)0,port),std::string()));
- localIfAddrs.insert(std::pair<InetAddress,std::string>(InetAddress((const void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,port),std::string()));
+ if (!interfacesEnumerated && localIfAddrs.empty()) {
+ for(int x=0;x<(int)portCount;++x) {
+ localIfAddrs.insert(std::pair<InetAddress,std::string>(InetAddress((uint32_t)0,ports[x]),std::string()));
+ localIfAddrs.insert(std::pair<InetAddress,std::string>(InetAddress((const void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,ports[x]),std::string()));
+ }
}
- // Close any old bindings to anything that doesn't exist anymore
- for(typename std::vector<_Binding>::const_iterator bi(_bindings.begin());bi!=_bindings.end();++bi) {
- if (localIfAddrs.find(bi->address) == localIfAddrs.end()) {
- phy.close(bi->udpSock,false);
- phy.close(bi->tcpListenSock,false);
+ const unsigned int oldBindingCount = _bindingCount;
+ _bindingCount = 0;
+
+ // Save bindings that are still valid, close those that are not
+ for(unsigned int b=0;b<oldBindingCount;++b) {
+ if (localIfAddrs.find(_bindings[b].address) != localIfAddrs.end()) {
+ if (_bindingCount != b)
+ _bindings[(unsigned int)_bindingCount] = _bindings[b];
+ ++_bindingCount;
+ } else {
+ PhySocket *const udps = _bindings[b].udpSock;
+ PhySocket *const tcps = _bindings[b].tcpListenSock;
+ _bindings[b].udpSock = (PhySocket *)0;
+ _bindings[b].tcpListenSock = (PhySocket *)0;
+ phy.close(udps,false);
+ phy.close(tcps,false);
}
}
- std::vector<_Binding> newBindings;
+ // Create new bindings for those not already bound
for(std::map<InetAddress,std::string>::const_iterator ii(localIfAddrs.begin());ii!=localIfAddrs.end();++ii) {
- typename std::vector<_Binding>::const_iterator bi(_bindings.begin());
- while (bi != _bindings.end()) {
- if (bi->address == ii->first) {
- newBindings.push_back(*bi);
+ unsigned int bi = 0;
+ while (bi != _bindingCount) {
+ if (_bindings[bi].address == ii->first)
break;
- }
++bi;
}
-
- if (bi == _bindings.end()) {
+ if (bi == _bindingCount) {
udps = phy.udpBind(reinterpret_cast<const struct sockaddr *>(&(ii->first)),(void *)0,ZT_UDP_DESIRED_BUF_SIZE);
- if (udps) {
- //tcps = phy.tcpListen(reinterpret_cast<const struct sockaddr *>(&ii),(void *)0);
- //if (tcps) {
+ tcps = phy.tcpListen(reinterpret_cast<const struct sockaddr *>(&(ii->first)),(void *)0);
+ if ((udps)&&(tcps)) {
#ifdef __LINUX__
- // Bind Linux sockets to their device so routes tha we manage do not override physical routes (wish all platforms had this!)
- if (ii->second.length() > 0) {
- int fd = (int)Phy<PHY_HANDLER_TYPE>::getDescriptor(udps);
- char tmp[256];
- Utils::scopy(tmp,sizeof(tmp),ii->second.c_str());
- if (fd >= 0) {
- if (setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp)) != 0) {
- fprintf(stderr,"WARNING: unable to set SO_BINDTODEVICE to bind %s to %s\n",ii->first.toIpString().c_str(),ii->second.c_str());
- }
- }
- }
+ // Bind Linux sockets to their device so routes tha we manage do not override physical routes (wish all platforms had this!)
+ if (ii->second.length() > 0) {
+ char tmp[256];
+ Utils::scopy(tmp,sizeof(tmp),ii->second.c_str());
+ int fd = (int)Phy<PHY_HANDLER_TYPE>::getDescriptor(udps);
+ if (fd >= 0)
+ setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp));
+ fd = (int)Phy<PHY_HANDLER_TYPE>::getDescriptor(tcps);
+ if (fd >= 0)
+ setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp));
+ }
#endif // __LINUX__
- newBindings.push_back(_Binding());
- newBindings.back().udpSock = udps;
- //newBindings.back().tcpListenSock = tcps;
- newBindings.back().address = ii->first;
- //} else {
- // phy.close(udps,false);
- //}
+ if (_bindingCount < ZT_BINDER_MAX_BINDINGS) {
+ _bindings[_bindingCount].udpSock = udps;
+ _bindings[_bindingCount].tcpListenSock = tcps;
+ _bindings[_bindingCount].address = ii->first;
+ ++_bindingCount;
+ }
+ } else {
+ phy.close(udps,false);
+ phy.close(tcps,false);
}
}
}
+ }
- // Swapping pointers and then letting the old one fall out of scope is faster than copying again
- _bindings.swap(newBindings);
+ /**
+ * @return All currently bound local interface addresses
+ */
+ inline std::vector<InetAddress> allBoundLocalInterfaceAddresses() const
+ {
+ std::vector<InetAddress> aa;
+ Mutex::Lock _l(_lock);
+ for(unsigned int b=0,c=_bindingCount;b<c;++b)
+ aa.push_back(_bindings[b].address);
+ return aa;
}
/**
- * Send a UDP packet from the specified local interface, or all
- *
- * Unfortunately even by examining the routing table there is no ultimately
- * robust way to tell where we might reach another host that works in all
- * environments. As a result, we send packets with null (wildcard) local
- * addresses from *every* bound interface.
- *
- * These are typically initial HELLOs, path probes, etc., since normal
- * conversations will have a local endpoint address. So the cost is low and
- * if the peer is not reachable via that route then the packet will go
- * nowhere and nothing will happen.
- *
- * It will of course only send via interface bindings of the same socket
- * family. No point in sending V4 via V6 or vice versa.
- *
- * In any case on most hosts there's only one or two interfaces that we
- * will use, so none of this is particularly costly.
- *
- * @param local Local interface address or null address for 'all'
- * @param remote Remote address
- * @param data Data to send
- * @param len Length of data
- * @param v4ttl If non-zero, send this packet with the specified IP TTL (IPv4 only)
+ * Send from all bound UDP sockets
*/
template<typename PHY_HANDLER_TYPE>
- inline bool udpSend(Phy<PHY_HANDLER_TYPE> &phy,const InetAddress &local,const InetAddress &remote,const void *data,unsigned int len,unsigned int v4ttl = 0) const
+ inline bool udpSendAll(Phy<PHY_HANDLER_TYPE> &phy,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
{
+ bool r = false;
Mutex::Lock _l(_lock);
- if (local) {
- for(typename std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i) {
- if (i->address == local) {
- if ((v4ttl)&&(local.ss_family == AF_INET))
- phy.setIp4UdpTtl(i->udpSock,v4ttl);
- const bool result = phy.udpSend(i->udpSock,reinterpret_cast<const struct sockaddr *>(&remote),data,len);
- if ((v4ttl)&&(local.ss_family == AF_INET))
- phy.setIp4UdpTtl(i->udpSock,255);
- return result;
- }
- }
- return false;
- } else {
- bool result = false;
- for(typename std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i) {
- if (i->address.ss_family == remote.ss_family) {
- if ((v4ttl)&&(remote.ss_family == AF_INET))
- phy.setIp4UdpTtl(i->udpSock,v4ttl);
- result |= phy.udpSend(i->udpSock,reinterpret_cast<const struct sockaddr *>(&remote),data,len);
- if ((v4ttl)&&(remote.ss_family == AF_INET))
- phy.setIp4UdpTtl(i->udpSock,255);
- }
- }
- return result;
+ for(unsigned int b=0,c=_bindingCount;b<c;++b) {
+ if (ttl) phy.setIp4UdpTtl(_bindings[b].udpSock,ttl);
+ if (phy.udpSend(_bindings[b].udpSock,(const struct sockaddr *)addr,data,len)) r = true;
+ if (ttl) phy.setIp4UdpTtl(_bindings[b].udpSock,255);
}
+ return r;
}
/**
- * @return All currently bound local interface addresses
+ * @param addr Address to check
+ * @return True if this is a bound local interface address
*/
- inline std::vector<InetAddress> allBoundLocalInterfaceAddresses()
+ inline bool isBoundLocalInterfaceAddress(const InetAddress &addr) const
{
Mutex::Lock _l(_lock);
- std::vector<InetAddress> aa;
- for(std::vector<_Binding>::const_iterator i(_bindings.begin());i!=_bindings.end();++i)
- aa.push_back(i->address);
- return aa;
+ for(unsigned int b=0;b<_bindingCount;++b) {
+ if (_bindings[b].address == addr)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Quickly check that a UDP socket is valid
+ *
+ * @param udpSock UDP socket to check
+ * @return True if socket is currently bound/allocated
+ */
+ inline bool isUdpSocketValid(PhySocket *const udpSock)
+ {
+ for(unsigned int b=0,c=_bindingCount;b<c;++b) {
+ if (_bindings[b].udpSock == udpSock)
+ return (b < _bindingCount); // double check atomic which may have changed
+ }
+ return false;
}
private:
- std::vector<_Binding> _bindings;
+ _Binding _bindings[ZT_BINDER_MAX_BINDINGS];
+ std::atomic<unsigned int> _bindingCount;
Mutex _lock;
};
diff --git a/osdep/BlockingQueue.hpp b/osdep/BlockingQueue.hpp
index 6172f4da..351a095a 100644
--- a/osdep/BlockingQueue.hpp
+++ b/osdep/BlockingQueue.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_BLOCKINGQUEUE_HPP
@@ -22,6 +30,7 @@
#include <queue>
#include <mutex>
#include <condition_variable>
+#include <chrono>
namespace ZeroTier {
@@ -34,7 +43,7 @@ template <class T>
class BlockingQueue
{
public:
- BlockingQueue(void) {}
+ BlockingQueue(void) : r(true) {}
inline void post(T t)
{
@@ -43,19 +52,53 @@ public:
c.notify_one();
}
- inline T get(void)
+ inline void stop(void)
+ {
+ std::lock_guard<std::mutex> lock(m);
+ r = false;
+ c.notify_all();
+ }
+
+ inline bool get(T &value)
{
std::unique_lock<std::mutex> lock(m);
- while(q.empty())
+ if (!r) return false;
+ while (q.empty()) {
c.wait(lock);
- T val = q.front();
+ if (!r) return false;
+ }
+ value = q.front();
+ q.pop();
+ return true;
+ }
+
+ enum TimedWaitResult
+ {
+ OK,
+ TIMED_OUT,
+ STOP
+ };
+
+ inline TimedWaitResult get(T &value,const unsigned long ms)
+ {
+ const std::chrono::milliseconds ms2{ms};
+ std::unique_lock<std::mutex> lock(m);
+ if (!r) return STOP;
+ while (q.empty()) {
+ if (c.wait_for(lock,ms2) == std::cv_status::timeout)
+ return ((r) ? TIMED_OUT : STOP);
+ else if (!r)
+ return STOP;
+ }
+ value = q.front();
q.pop();
- return val;
+ return OK;
}
private:
+ volatile bool r;
std::queue<T> q;
- mutable std::mutex m;
+ std::mutex m;
std::condition_variable c;
};
diff --git a/osdep/Http.cpp b/osdep/Http.cpp
index 064ccd0c..16785c96 100644
--- a/osdep/Http.cpp
+++ b/osdep/Http.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include <stdio.h>
@@ -104,12 +112,12 @@ struct HttpPhyHandler
inline void phyOnTcpWritable(PhySocket *sock,void **uptr)
{
- if (writePtr < writeSize) {
- long n = phy->streamSend(sock,writeBuf + writePtr,writeSize - writePtr,true);
+ if (writePtr < (unsigned long)writeBuf.length()) {
+ long n = phy->streamSend(sock,writeBuf.data() + writePtr,(unsigned long)writeBuf.length() - writePtr,true);
if (n > 0)
writePtr += n;
}
- if (writePtr >= writeSize)
+ if (writePtr >= (unsigned long)writeBuf.length())
phy->setNotifyWritable(sock,false);
}
@@ -127,8 +135,7 @@ struct HttpPhyHandler
unsigned long messageSize;
unsigned long writePtr;
uint64_t lastActivity;
- unsigned long writeSize;
- char writeBuf[32768];
+ std::string writeBuf;
unsigned long maxResponseSize;
std::map<std::string,std::string> *responseHeaders;
@@ -236,24 +243,26 @@ unsigned int Http::_do(
handler.lastActivity = OSUtils::now();
try {
- handler.writeSize = Utils::snprintf(handler.writeBuf,sizeof(handler.writeBuf),"%s %s HTTP/1.1\r\n",method,path);
- for(std::map<std::string,std::string>::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h)
- handler.writeSize += Utils::snprintf(handler.writeBuf + handler.writeSize,sizeof(handler.writeBuf) - handler.writeSize,"%s: %s\r\n",h->first.c_str(),h->second.c_str());
- handler.writeSize += Utils::snprintf(handler.writeBuf + handler.writeSize,sizeof(handler.writeBuf) - handler.writeSize,"\r\n");
- if ((requestBody)&&(requestBodyLength)) {
- if ((handler.writeSize + requestBodyLength) > sizeof(handler.writeBuf)) {
- responseBody = "request too large";
- return 0;
- }
- memcpy(handler.writeBuf + handler.writeSize,requestBody,requestBodyLength);
- handler.writeSize += requestBodyLength;
+ char tmp[1024];
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s %s HTTP/1.1\r\n",method,path);
+ handler.writeBuf.append(tmp);
+ for(std::map<std::string,std::string>::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h) {
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s: %s\r\n",h->first.c_str(),h->second.c_str());
+ handler.writeBuf.append(tmp);
}
+ handler.writeBuf.append("\r\n");
+ if ((requestBody)&&(requestBodyLength))
+ handler.writeBuf.append((const char *)requestBody,requestBodyLength);
} catch ( ... ) {
responseBody = "request too large";
return 0;
}
- handler.maxResponseSize = maxResponseSize;
+ if (maxResponseSize) {
+ handler.maxResponseSize = maxResponseSize;
+ } else {
+ handler.maxResponseSize = 2147483647;
+ }
handler.responseHeaders = &responseHeaders;
handler.responseBody = &responseBody;
handler.error = false;
diff --git a/osdep/Http.hpp b/osdep/Http.hpp
index e7d4d03e..b717c5c9 100644
--- a/osdep/Http.hpp
+++ b/osdep/Http.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_HTTP_HPP
diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp
index f74efc0a..06bbbada 100644
--- a/osdep/LinuxEthernetTap.cpp
+++ b/osdep/LinuxEthernetTap.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include <stdint.h>
@@ -40,6 +48,7 @@
#include <algorithm>
#include <utility>
+#include <string>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
@@ -55,6 +64,19 @@ namespace ZeroTier {
static Mutex __tapCreateLock;
+static const char _base32_chars[32] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' };
+static void _base32_5_to_8(const uint8_t *in,char *out)
+{
+ out[0] = _base32_chars[(in[0]) >> 3];
+ out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6];
+ out[2] = _base32_chars[(in[1] & 0x3e) >> 1];
+ out[3] = _base32_chars[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4];
+ out[4] = _base32_chars[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7];
+ out[5] = _base32_chars[(in[3] & 0x7c) >> 2];
+ out[6] = _base32_chars[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5];
+ out[7] = _base32_chars[(in[4] & 0x1f)];
+}
+
LinuxEthernetTap::LinuxEthernetTap(
const char *homePath,
const MAC &mac,
@@ -75,13 +97,10 @@ LinuxEthernetTap::LinuxEthernetTap(
char procpath[128],nwids[32];
struct stat sbuf;
- Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid);
+ OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid);
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) {
_fd = ::open("/dev/tun",O_RDWR);
@@ -92,7 +111,7 @@ LinuxEthernetTap::LinuxEthernetTap(
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));
- // Try to recall our last device name, or pick an unused one if that fails.
+ // Restore device names from legacy devicemap, but for new devices we use a base32-based canonical naming
std::map<std::string,std::string> globalDeviceMap;
FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r");
if (devmapf) {
@@ -115,20 +134,36 @@ LinuxEthernetTap::LinuxEthernetTap(
std::map<std::string,std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
if (gdmEntry != globalDeviceMap.end()) {
Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),gdmEntry->second.c_str());
- Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
+ OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
recalledDevice = (stat(procpath,&sbuf) != 0);
}
+
if (!recalledDevice) {
- int devno = 0;
- do {
#ifdef __SYNOLOGY__
- devno+=50; // Arbitrary number to prevent interface name conflicts
- Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++);
+ int devno = 50;
+ do {
+ OSUtils::ztsnprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++);
+ OSUtils::ztsnprintf(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
#else
- Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++);
+ uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network
+ do {
+ const uint64_t nwid40 = (nwid ^ (nwid >> 24)) + trial++;
+ uint8_t tmp2[5];
+ char tmp3[11];
+ tmp2[0] = (uint8_t)((nwid40 >> 32) & 0xff);
+ tmp2[1] = (uint8_t)((nwid40 >> 24) & 0xff);
+ tmp2[2] = (uint8_t)((nwid40 >> 16) & 0xff);
+ tmp2[3] = (uint8_t)((nwid40 >> 8) & 0xff);
+ tmp2[4] = (uint8_t)(nwid40 & 0xff);
+ tmp3[0] = 'z';
+ tmp3[1] = 't';
+ _base32_5_to_8(tmp2,tmp3 + 2);
+ tmp3[10] = (char)0;
+ memcpy(ifr.ifr_name,tmp3,11);
+ OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
+ } while (stat(procpath,&sbuf) == 0);
#endif
- 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;
@@ -191,6 +226,7 @@ LinuxEthernetTap::LinuxEthernetTap(
(void)::pipe(_shutdownSignalPipe);
+ /*
globalDeviceMap[nwids] = _dev;
devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w");
if (devmapf) {
@@ -201,6 +237,7 @@ LinuxEthernetTap::LinuxEthernetTap(
}
fclose(devmapf);
}
+ */
_thread = Thread::start(this);
}
@@ -230,7 +267,8 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
if (cpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
- ::execlp("ip","ip","addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
+ char iptmp[128];
+ ::execlp("ip","ip","addr","del",ip.toString(iptmp),"dev",_dev.c_str(),(const char *)0);
::_exit(-1);
} else {
int exitcode = -1;
@@ -251,7 +289,7 @@ bool LinuxEthernetTap::addIpSyn(std::vector<InetAddress> ips)
if (cpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
- // We must know if there is at least (one) of each protocol version so we
+ // We must know if there is at least (one) of each protocol version so we
// can properly enumerate address/netmask combinations in the ifcfg-dev file
for(int i=0; i<(int)ips.size(); i++) {
if (ips[i].isV4())
@@ -262,25 +300,28 @@ bool LinuxEthernetTap::addIpSyn(std::vector<InetAddress> ips)
// Assemble and write contents of ifcfg-dev file
for(int i=0; i<(int)ips.size(); i++) {
if (ips[i].isV4()) {
+ char iptmp[64],iptmp2[64];
std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : "";
- cfg_contents += "\nIPADDR"+numstr4+"="+ips[i].toIpString()
- + "\nNETMASK"+numstr4+"="+ips[i].netmask().toIpString()+"\n";
+ cfg_contents += "\nIPADDR"+numstr4+"="+ips[i].toIpString(iptmp)
+ + "\nNETMASK"+numstr4+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
ip4++;
}
else {
+ char iptmp[64],iptmp2[64];
std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : "";
- cfg_contents += "\nIPV6ADDR"+numstr6+"="+ips[i].toIpString()
- + "\nNETMASK"+numstr6+"="+ips[i].netmask().toIpString()+"\n";
+ cfg_contents += "\nIPV6ADDR"+numstr6+"="+ips[i].toIpString(iptmp)
+ + "\nNETMASK"+numstr6+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
ip6++;
}
}
OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length());
// Finaly, add IPs
for(int i=0; i<(int)ips.size(); i++){
+ char iptmp[128],iptmp2[128];
if (ips[i].isV4())
- ::execlp("ip","ip","addr","add",ips[i].toString().c_str(),"broadcast",ips[i].broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
+ ::execlp("ip","ip","addr","add",ips[i].toString(iptmp),"broadcast",ips[i].broadcast().toIpString(iptmp2),"dev",_dev.c_str(),(const char *)0);
else
- ::execlp("ip","ip","addr","add",ips[i].toString().c_str(),"dev",_dev.c_str(),(const char *)0);
+ ::execlp("ip","ip","addr","add",ips[i].toString(iptmp),"dev",_dev.c_str(),(const char *)0);
}
::_exit(-1);
} else if (cpid > 0) {
@@ -311,10 +352,11 @@ bool LinuxEthernetTap::addIp(const InetAddress &ip)
if (cpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
+ char iptmp[128],iptmp2[128];
if (ip.isV4()) {
- ::execlp("ip","ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
+ ::execlp("ip","ip","addr","add",ip.toString(iptmp),"broadcast",ip.broadcast().toIpString(iptmp2),"dev",_dev.c_str(),(const char *)0);
} else {
- ::execlp("ip","ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
+ ::execlp("ip","ip","addr","add",ip.toString(iptmp),"dev",_dev.c_str(),(const char *)0);
}
::_exit(-1);
} else if (cpid > 0) {
@@ -378,7 +420,7 @@ std::vector<InetAddress> LinuxEthernetTap::ips() const
void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
- char putBuf[8194];
+ char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6);
@@ -447,13 +489,28 @@ void LinuxEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,st
_multicastGroups.swap(newGroups);
}
+void LinuxEthernetTap::setMtu(unsigned int mtu)
+{
+ if (_mtu != mtu) {
+ _mtu = mtu;
+ int sock = socket(AF_INET,SOCK_DGRAM,0);
+ if (sock > 0) {
+ struct ifreq ifr;
+ memset(&ifr,0,sizeof(ifr));
+ ifr.ifr_ifru.ifru_mtu = (int)mtu;
+ ioctl(sock,SIOCSIFMTU,(void *)&ifr);
+ close(sock);
+ }
+ }
+}
+
void LinuxEthernetTap::threadMain()
throw()
{
fd_set readfds,nullfds;
MAC to,from;
int n,nfds,r;
- char getBuf[8194];
+ char getBuf[ZT_MAX_MTU + 64];
Thread::sleep(500);
diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp
index a2a00a79..5142eec1 100644
--- a/osdep/LinuxEthernetTap.hpp
+++ b/osdep/LinuxEthernetTap.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_LINUXETHERNETTAP_HPP
@@ -61,6 +69,7 @@ public:
std::string deviceName() const;
void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
+ void setMtu(unsigned int mtu);
void threadMain()
throw();
diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp
index 3a020d61..d7c80704 100644
--- a/osdep/ManagedRoute.cpp
+++ b/osdep/ManagedRoute.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include "../node/Constants.hpp"
@@ -238,7 +246,6 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface)
{
- //printf("route %s %s %s %s %s\n",op,target.toString().c_str(),(via) ? via.toString().c_str() : "(null)",(ifscope) ? ifscope : "(null)",(localInterface) ? localInterface : "(null)");
long p = (long)fork();
if (p > 0) {
int exitcode = -1;
@@ -246,17 +253,19 @@ static void _routeCmd(const char *op,const InetAddress &target,const InetAddress
} else if (p == 0) {
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
+ char ttmp[64];
+ char iptmp[64];
if (via) {
if ((ifscope)&&(ifscope[0])) {
- ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),via.toIpString().c_str(),(const char *)0);
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
} else {
- ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),via.toIpString().c_str(),(const char *)0);
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
}
} else if ((localInterface)&&(localInterface[0])) {
if ((ifscope)&&(ifscope[0])) {
- ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),"-interface",localInterface,(const char *)0);
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
} else {
- ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),"-interface",localInterface,(const char *)0);
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
}
}
::_exit(-1);
@@ -277,12 +286,13 @@ static void _routeCmd(const char *op,const InetAddress &target,const InetAddress
} else if (p == 0) {
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
+ char ipbuf[64],ipbuf2[64];
if (via) {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"via",via.toIpString().c_str(),(const char *)0);
- ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"via",via.toIpString().c_str(),(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
} else if ((localInterface)&&(localInterface[0])) {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"dev",localInterface,(const char *)0);
- ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString().c_str(),"dev",localInterface,(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
}
::_exit(-1);
}
diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp
index fd77a79a..779ad6a1 100644
--- a/osdep/ManagedRoute.hpp
+++ b/osdep/ManagedRoute.hpp
@@ -1,3 +1,29 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * 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/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
+ */
+
#ifndef ZT_MANAGEDROUTE_HPP
#define ZT_MANAGEDROUTE_HPP
@@ -8,7 +34,6 @@
#include "../node/Utils.hpp"
#include "../node/SharedPtr.hpp"
#include "../node/AtomicCounter.hpp"
-#include "../node/NonCopyable.hpp"
#include <stdexcept>
#include <vector>
@@ -19,7 +44,7 @@ namespace ZeroTier {
/**
* A ZT-managed route that used C++ RAII semantics to automatically clean itself up on deallocate
*/
-class ManagedRoute : NonCopyable
+class ManagedRoute
{
friend class SharedPtr<ManagedRoute>;
@@ -65,6 +90,9 @@ public:
inline const char *device() const { return _device; }
private:
+ ManagedRoute(const ManagedRoute &) {}
+ inline ManagedRoute &operator=(const ManagedRoute &) { return *this; }
+
InetAddress _target;
InetAddress _via;
InetAddress _systemVia; // for route overrides
diff --git a/osdep/NeighborDiscovery.cpp b/osdep/NeighborDiscovery.cpp
index 4f636310..d9862f3d 100644
--- a/osdep/NeighborDiscovery.cpp
+++ b/osdep/NeighborDiscovery.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include "NeighborDiscovery.hpp"
@@ -24,7 +32,7 @@
#include <assert.h>
namespace ZeroTier {
-
+
uint16_t calc_checksum (uint16_t *addr, int len)
{
int count = len;
@@ -185,7 +193,7 @@ sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigne
assert(sizeof(_neighbor_advertisement) == 32);
const uint64_t now = OSUtils::now();
- sockaddr_storage ip = ZT_SOCKADDR_NULL;
+ sockaddr_storage ip = {0};
if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) {
// respond to Neighbor Solicitation request for local address
diff --git a/osdep/NeighborDiscovery.hpp b/osdep/NeighborDiscovery.hpp
index 47831bda..59186289 100644
--- a/osdep/NeighborDiscovery.hpp
+++ b/osdep/NeighborDiscovery.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_NEIGHBORDISCOVERY_HPP
diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp
index fd5efed0..cadd4e6b 100644
--- a/osdep/OSUtils.cpp
+++ b/osdep/OSUtils.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include <stdio.h>
@@ -49,6 +57,23 @@
namespace ZeroTier {
+unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap,fmt);
+ int n = (int)vsnprintf(buf,len,fmt,ap);
+ va_end(ap);
+
+ if ((n >= (int)len)||(n < 0)) {
+ if (len)
+ buf[len - 1] = (char)0;
+ throw std::length_error("buf[] overflow");
+ }
+
+ return (unsigned int)n;
+}
+
#ifdef __UNIX_LIKE__
bool OSUtils::redirectUnixOutputs(const char *stdoutPath,const char *stderrPath)
throw()
@@ -108,7 +133,7 @@ std::vector<std::string> OSUtils::listDirectory(const char *path,bool includeDir
return r;
}
-long OSUtils::cleanDirectory(const char *path,const uint64_t olderThan)
+long OSUtils::cleanDirectory(const char *path,const int64_t olderThan)
{
long cleaned = 0;
@@ -125,8 +150,8 @@ long OSUtils::cleanDirectory(const char *path,const uint64_t olderThan)
date.LowPart = ffd.ftLastWriteTime.dwLowDateTime;
if (date.QuadPart > 0) {
date.QuadPart -= adjust.QuadPart;
- if ((uint64_t)((date.QuadPart / 10000000) * 1000) < olderThan) {
- Utils::snprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName);
+ if ((int64_t)((date.QuadPart / 10000000) * 1000) < olderThan) {
+ ztsnprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName);
if (DeleteFileA(tmp))
++cleaned;
}
@@ -149,9 +174,9 @@ long OSUtils::cleanDirectory(const char *path,const uint64_t olderThan)
break;
if (dptr) {
if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))&&(dptr->d_type == DT_REG)) {
- Utils::snprintf(tmp,sizeof(tmp),"%s/%s",path,dptr->d_name);
+ ztsnprintf(tmp,sizeof(tmp),"%s/%s",path,dptr->d_name);
if (stat(tmp,&st) == 0) {
- uint64_t mt = (uint64_t)(st.st_mtime);
+ int64_t mt = (int64_t)(st.st_mtime);
if ((mt > 0)&&((mt * 1000) < olderThan)) {
if (unlink(tmp) == 0)
++cleaned;
@@ -279,7 +304,7 @@ int64_t OSUtils::getFileSize(const char *path)
bool OSUtils::readFile(const char *path,std::string &buf)
{
- char tmp[1024];
+ char tmp[16384];
FILE *f = fopen(path,"rb");
if (f) {
for(;;) {
@@ -355,6 +380,24 @@ std::vector<std::string> OSUtils::split(const char *s,const char *const sep,cons
std::string OSUtils::platformDefaultHomePath()
{
+#ifdef __QNAP__
+ char *cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf";
+ char buf[128];
+ FILE *fp;
+ if ((fp = popen(cmd, "r")) == NULL) {
+ printf("Error opening pipe!\n");
+ return NULL;
+ }
+ while (fgets(buf, 128, fp) != NULL) { }
+ if(pclose(fp)) {
+ printf("Command not found or exited with error status\n");
+ return NULL;
+ }
+ std::string homeDir = std::string(buf);
+ homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end());
+ return homeDir;
+#endif
+
#ifdef __UNIX_LIKE__
#ifdef __APPLE__
@@ -391,7 +434,7 @@ std::string OSUtils::platformDefaultHomePath()
// Inline these massive JSON operations in one place only to reduce binary footprint and compile time
nlohmann::json OSUtils::jsonParse(const std::string &buf) { return nlohmann::json::parse(buf.c_str()); }
-std::string OSUtils::jsonDump(const nlohmann::json &j) { return j.dump(1); }
+std::string OSUtils::jsonDump(const nlohmann::json &j,int indentation) { return j.dump(indentation); }
uint64_t OSUtils::jsonInt(const nlohmann::json &jv,const uint64_t dfl)
{
@@ -408,6 +451,21 @@ uint64_t OSUtils::jsonInt(const nlohmann::json &jv,const uint64_t dfl)
return dfl;
}
+uint64_t OSUtils::jsonIntHex(const nlohmann::json &jv,const uint64_t dfl)
+{
+ try {
+ if (jv.is_number()) {
+ return (uint64_t)jv;
+ } else if (jv.is_string()) {
+ std::string s = jv;
+ return Utils::hexStrToU64(s.c_str());
+ } else if (jv.is_boolean()) {
+ return ((bool)jv ? 1ULL : 0ULL);
+ }
+ } catch ( ... ) {}
+ return dfl;
+}
+
bool OSUtils::jsonBool(const nlohmann::json &jv,const bool dfl)
{
try {
@@ -438,7 +496,7 @@ std::string OSUtils::jsonString(const nlohmann::json &jv,const char *dfl)
return jv;
} else if (jv.is_number()) {
char tmp[64];
- Utils::snprintf(tmp,sizeof(tmp),"%llu",(uint64_t)jv);
+ ztsnprintf(tmp,sizeof(tmp),"%llu",(uint64_t)jv);
return tmp;
} else if (jv.is_boolean()) {
return ((bool)jv ? std::string("1") : std::string("0"));
@@ -451,9 +509,10 @@ std::string OSUtils::jsonBinFromHex(const nlohmann::json &jv)
{
std::string s(jsonString(jv,""));
if (s.length() > 0) {
- char *buf = new char[(s.length() / 2) + 1];
+ unsigned int buflen = (unsigned int)((s.length() / 2) + 1);
+ char *buf = new char[buflen];
try {
- unsigned int l = Utils::unhex(s,buf,(unsigned int)s.length());
+ unsigned int l = Utils::unhex(s.c_str(),buf,buflen);
std::string b(buf,l);
delete [] buf;
return b;
diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp
index b84d5d2d..324b7923 100644
--- a/osdep/OSUtils.hpp
+++ b/osdep/OSUtils.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_OSUTILS_HPP
@@ -25,7 +33,6 @@
#include <string.h>
#include <time.h>
-#include <string>
#include <stdexcept>
#include <vector>
#include <map>
@@ -43,6 +50,9 @@
#include <sys/time.h>
#include <sys/stat.h>
#include <arpa/inet.h>
+#ifdef __LINUX__
+#include <sys/syscall.h>
+#endif
#endif
#include "../ext/json/json.hpp"
@@ -55,6 +65,20 @@ namespace ZeroTier {
class OSUtils
{
public:
+ /**
+ * Variant of snprintf that is portable and throws an exception
+ *
+ * This just wraps the local implementation whatever it's called, while
+ * performing a few other checks and adding exceptions for overflow.
+ *
+ * @param buf Buffer to write to
+ * @param len Length of buffer in bytes
+ * @param fmt Format string
+ * @param ... Format arguments
+ * @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
+ */
+ static unsigned int ztsnprintf(char *buf,unsigned int len,const char *fmt,...);
+
#ifdef __UNIX_LIKE__
/**
* Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path
@@ -77,7 +101,6 @@ public:
* @return True if delete was successful
*/
static inline bool rm(const char *path)
- throw()
{
#ifdef __WINDOWS__
return (DeleteFileA(path) != FALSE);
@@ -85,7 +108,7 @@ public:
return (unlink(path) == 0);
#endif
}
- static inline bool rm(const std::string &path) throw() { return rm(path.c_str()); }
+ static inline bool rm(const std::string &path) { return rm(path.c_str()); }
static inline bool mkdir(const char *path)
{
@@ -99,7 +122,17 @@ public:
return true;
#endif
}
- static inline bool mkdir(const std::string &path) throw() { return OSUtils::mkdir(path.c_str()); }
+ static inline bool mkdir(const std::string &path) { return OSUtils::mkdir(path.c_str()); }
+
+ static inline bool rename(const char *o,const char *n)
+ {
+#ifdef __WINDOWS__
+ DeleteFileA(n);
+ return (::rename(o,n) == 0);
+#else
+ return (::rename(o,n) == 0);
+#endif
+ }
/**
* List a directory's contents
@@ -118,7 +151,7 @@ public:
* @param olderThan Last modified older than timestamp (ms since epoch)
* @return Number of cleaned files or negative on fatal error
*/
- static long cleanDirectory(const char *path,const uint64_t olderThan);
+ static long cleanDirectory(const char *path,const int64_t olderThan);
/**
* Delete a directory and all its files and subdirectories recursively
@@ -176,8 +209,7 @@ public:
/**
* @return Current time in milliseconds since epoch
*/
- static inline uint64_t now()
- throw()
+ static inline int64_t now()
{
#ifdef __WINDOWS__
FILETIME ft;
@@ -187,35 +219,17 @@ public:
SystemTimeToFileTime(&st,&ft);
tmp.LowPart = ft.dwLowDateTime;
tmp.HighPart = ft.dwHighDateTime;
- return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds );
+ return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds );
#else
struct timeval tv;
- gettimeofday(&tv,(struct timezone *)0);
- return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) );
-#endif
- };
-
- /**
- * @return Current time in seconds since epoch, to the highest available resolution
- */
- static inline double nowf()
- throw()
- {
-#ifdef __WINDOWS__
- FILETIME ft;
- SYSTEMTIME st;
- ULARGE_INTEGER tmp;
- GetSystemTime(&st);
- SystemTimeToFileTime(&st,&ft);
- tmp.LowPart = ft.dwLowDateTime;
- tmp.HighPart = ft.dwHighDateTime;
- return (((double)(tmp.QuadPart - 116444736000000000ULL)) / 10000000.0);
+#ifdef __LINUX__
+ syscall(SYS_gettimeofday,&tv,0); /* fix for musl libc broken gettimeofday bug */
#else
- struct timeval tv;
gettimeofday(&tv,(struct timezone *)0);
- return ( ((double)tv.tv_sec) + (((double)tv.tv_usec) / 1000000.0) );
#endif
- }
+ return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) );
+#endif
+ };
/**
* Read the full contents of a file into a string buffer
@@ -271,8 +285,9 @@ public:
static std::string platformDefaultHomePath();
static nlohmann::json jsonParse(const std::string &buf);
- static std::string jsonDump(const nlohmann::json &j);
+ static std::string jsonDump(const nlohmann::json &j,int indentation = 1);
static uint64_t jsonInt(const nlohmann::json &jv,const uint64_t dfl);
+ static uint64_t jsonIntHex(const nlohmann::json &jv,const uint64_t dfl);
static bool jsonBool(const nlohmann::json &jv,const bool dfl);
static std::string jsonString(const nlohmann::json &jv,const char *dfl);
static std::string jsonBinFromHex(const nlohmann::json &jv);
diff --git a/osdep/OSXEthernetTap.cpp b/osdep/OSXEthernetTap.cpp
index f70908b8..dbff6200 100644
--- a/osdep/OSXEthernetTap.cpp
+++ b/osdep/OSXEthernetTap.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include <stdint.h>
@@ -328,10 +336,7 @@ OSXEthernetTap::OSXEthernetTap(
char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32];
struct stat stattmp;
- Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid);
-
- if (mtu > 2800)
- throw std::runtime_error("max tap MTU is 2800");
+ OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid);
Mutex::Lock _gl(globalTapCreateLock);
@@ -386,13 +391,13 @@ OSXEthernetTap::OSXEthernetTap(
// 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);
+ OSUtils::ztsnprintf(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);
+ OSUtils::ztsnprintf(foo,sizeof(foo),"zt%d",i);
_dev = foo;
break;
}
@@ -408,9 +413,9 @@ OSXEthernetTap::OSXEthernetTap(
}
// 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);
+ OSUtils::ztsnprintf(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]);
+ OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu);
+ OSUtils::ztsnprintf(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);
@@ -494,7 +499,8 @@ bool OSXEthernetTap::addIp(const InetAddress &ip)
long cpid = (long)vfork();
if (cpid == 0) {
- ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toString().c_str(),"alias",(const char *)0);
+ char tmp[128];
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toString(tmp),"alias",(const char *)0);
::_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
@@ -514,7 +520,8 @@ bool OSXEthernetTap::removeIp(const InetAddress &ip)
if (*i == ip) {
long cpid = (long)vfork();
if (cpid == 0) {
- execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toIpString().c_str(),"-alias",(const char *)0);
+ char tmp[128];
+ execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toIpString(tmp),"-alias",(const char *)0);
_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
@@ -566,7 +573,7 @@ std::vector<InetAddress> OSXEthernetTap::ips() const
void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
- char putBuf[4096];
+ char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6);
@@ -624,13 +631,30 @@ void OSXEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std:
_multicastGroups.swap(newGroups);
}
+void OSXEthernetTap::setMtu(unsigned int mtu)
+{
+ if (mtu != _mtu) {
+ _mtu = mtu;
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ char tmp[64];
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu);
+ execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0);
+ _exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ waitpid(cpid,&exitcode,0);
+ }
+ }
+}
+
void OSXEthernetTap::threadMain()
throw()
{
fd_set readfds,nullfds;
MAC to,from;
int n,nfds,r;
- char getBuf[8194];
+ char getBuf[ZT_MAX_MTU + 64];
Thread::sleep(500);
diff --git a/osdep/OSXEthernetTap.hpp b/osdep/OSXEthernetTap.hpp
index 5a96c210..fe402901 100644
--- a/osdep/OSXEthernetTap.hpp
+++ b/osdep/OSXEthernetTap.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_OSXETHERNETTAP_HPP
@@ -62,6 +70,7 @@ public:
std::string deviceName() const;
void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
+ void setMtu(unsigned int mtu);
void threadMain()
throw();
diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp
index eab8a317..e359ccdd 100644
--- a/osdep/Phy.hpp
+++ b/osdep/Phy.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_PHY_HPP
@@ -680,25 +688,26 @@ public:
* until one works.
*
* @param sock Socket
- * @param bufferSize Desired buffer sizes
+ * @param receiveBufferSize Desired size of receive buffer
+ * @param sendBufferSize Desired size of send buffer
*/
- inline void setBufferSizes(const PhySocket *sock,int bufferSize)
+ inline void setBufferSizes(const PhySocket *sock,int receiveBufferSize,int sendBufferSize)
{
PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
- if (bufferSize > 0) {
- int bs = bufferSize;
- while (bs >= 65536) {
- int tmpbs = bs;
+ if (receiveBufferSize > 0) {
+ while (receiveBufferSize > 0) {
+ int tmpbs = receiveBufferSize;
if (::setsockopt(sws.sock,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
break;
- bs -= 16384;
+ receiveBufferSize -= 16384;
}
- bs = bufferSize;
- while (bs >= 65536) {
- int tmpbs = bs;
+ }
+ if (sendBufferSize > 0) {
+ while (sendBufferSize > 0) {
+ int tmpbs = sendBufferSize;
if (::setsockopt(sws.sock,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
break;
- bs -= 16384;
+ sendBufferSize -= 16384;
}
}
}
@@ -807,7 +816,7 @@ public:
* @param sock Stream connection socket
* @param notifyWritable Want writable notifications?
*/
- inline const void setNotifyWritable(PhySocket *sock,bool notifyWritable)
+ inline void setNotifyWritable(PhySocket *sock,bool notifyWritable)
{
PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
if (notifyWritable) {
@@ -827,7 +836,7 @@ public:
* @param sock Socket to modify
* @param notifyReadable True if socket should be monitored for readability
*/
- inline const void setNotifyReadable(PhySocket *sock,bool notifyReadable)
+ inline void setNotifyReadable(PhySocket *sock,bool notifyReadable)
{
PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
if (notifyReadable) {
@@ -957,7 +966,7 @@ public:
case ZT_PHY_SOCKET_UDP:
if (FD_ISSET(s->sock,&rfds)) {
- for(;;) {
+ for(int k=0;k<1024;++k) {
memset(&ss,0,sizeof(ss));
socklen_t slen = sizeof(ss);
long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen);
diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp
index d3a19384..a7dd3046 100644
--- a/osdep/PortMapper.cpp
+++ b/osdep/PortMapper.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifdef ZT_USE_MINIUPNPC
@@ -21,6 +29,13 @@
// Uncomment to dump debug messages
//#define ZT_PORTMAPPER_TRACE 1
+#ifdef __ANDROID__
+#include <android/log.h>
+#define PM_TRACE(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "PortMapper", __VA_ARGS__))
+#else
+#define PM_TRACE(...) fprintf(stderr, __VA_ARGS__)
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -45,15 +60,24 @@
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#else
+#ifdef __ANDROID__
+#include "miniupnpc.h"
+#include "upnpcommands.h"
+#else
#include "../ext/miniupnpc/miniupnpc.h"
#include "../ext/miniupnpc/upnpcommands.h"
#endif
+#endif
#ifdef ZT_USE_SYSTEM_NATPMP
#include <natpmp.h>
#else
+#ifdef __ANDROID__
+#include "natpmp.h"
+#else
#include "../ext/libnatpmp/natpmp.h"
#endif
+#endif
namespace ZeroTier {
@@ -75,7 +99,7 @@ public:
int mode = 0; // 0 == NAT-PMP, 1 == UPnP
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: started for UDP port %d"ZT_EOL_S,localPort);
+ fprintf(stderr,"PortMapper: started for UDP port %d" ZT_EOL_S,localPort);
#endif
while (run) {
@@ -99,15 +123,16 @@ public:
if (initnatpmp(&natpmp,0,0) != 0) {
mode = 1;
+ closenatpmp(&natpmp);
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: NAT-PMP: init failed, switching to UPnP mode"ZT_EOL_S);
+ PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S);
#endif
break;
}
InetAddress publicAddress;
sendpublicaddressrequest(&natpmp);
- uint64_t myTimeout = OSUtils::now() + 5000;
+ int64_t myTimeout = OSUtils::now() + 5000;
do {
fd_set fds;
struct timeval timeout;
@@ -123,7 +148,7 @@ public:
publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0);
} else {
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: NAT-PMP: request for external address failed, aborting..."ZT_EOL_S);
+ PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S);
#endif
closenatpmp(&natpmp);
break;
@@ -145,7 +170,8 @@ public:
if (r == 0) {
publicAddress.setPort(response.pnu.newportmapping.mappedpublicport);
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: NAT-PMP: mapped %u to %s"ZT_EOL_S,(unsigned int)localPort,publicAddress.toString().c_str());
+ char paddr[128];
+ PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S,(unsigned int)localPort,publicAddress.toString(paddr));
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@@ -162,7 +188,7 @@ public:
if (!natPmpSuccess) {
mode = 1;
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: NAT-PMP: request failed, switching to UPnP mode"ZT_EOL_S);
+ PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S);
#endif
}
}
@@ -187,7 +213,7 @@ public:
{
UPNPDev *dev = devlist;
while (dev) {
- fprintf(stderr,"PortMapper: found UPnP device at URL '%s': %s"ZT_EOL_S,dev->descURL,dev->st);
+ PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S,dev->descURL,dev->st);
dev = dev->pNext;
}
}
@@ -197,22 +223,22 @@ public:
memset(externalip,0,sizeof(externalip));
memset(&urls,0,sizeof(urls));
memset(&data,0,sizeof(data));
- Utils::snprintf(inport,sizeof(inport),"%d",localPort);
+ OSUtils::ztsnprintf(inport,sizeof(inport),"%d",localPort);
if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) {
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: UPnP: my LAN IP address: %s"ZT_EOL_S,lanaddr);
+ PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S,lanaddr);
#endif
if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) {
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: UPnP: my external IP address: %s"ZT_EOL_S,externalip);
+ PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S,externalip);
#endif
for(int tries=0;tries<60;++tries) {
int tryPort = (int)localPort + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
- Utils::snprintf(outport,sizeof(outport),"%u",tryPort);
+ OSUtils::ztsnprintf(outport,sizeof(outport),"%u",tryPort);
// First check and see if this port is already mapped to the
// same unique name. If so, keep this mapping and don't try
@@ -231,7 +257,7 @@ public:
memset(haveLeaseDuration,0,sizeof(haveLeaseDuration));
if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) {
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: UPnP: reusing previously reserved external port: %s"ZT_EOL_S,outport);
+ PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@@ -246,7 +272,7 @@ public:
int mapResult = 0;
if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) {
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: UPnP: reserved external port: %s"ZT_EOL_S,outport);
+ PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@@ -256,7 +282,7 @@ public:
break;
} else {
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d"ZT_EOL_S,outport,mapResult);
+ PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S,outport,mapResult);
#endif
Thread::sleep(1000);
}
@@ -265,13 +291,13 @@ public:
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode"ZT_EOL_S);
+ PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode"ZT_EOL_S);
+ PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
@@ -280,14 +306,14 @@ public:
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d"ZT_EOL_S,upnpError);
+ PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S,upnpError);
#endif
}
}
// ---------------------------------------------------------------------
#ifdef ZT_PORTMAPPER_TRACE
- fprintf(stderr,"UPNPClient: rescanning in %d ms"ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY);
+ PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY);
#endif
Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY);
}
diff --git a/osdep/PortMapper.hpp b/osdep/PortMapper.hpp
index 0b8d15fc..fa3cdc31 100644
--- a/osdep/PortMapper.hpp
+++ b/osdep/PortMapper.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifdef ZT_USE_MINIUPNPC
diff --git a/osdep/TestEthernetTap.hpp b/osdep/TestEthernetTap.hpp
new file mode 100644
index 00000000..6ccf92f3
--- /dev/null
+++ b/osdep/TestEthernetTap.hpp
@@ -0,0 +1,161 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * 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/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
+ */
+
+#ifndef ZT_TESTETHERNETTAP_HPP
+#define ZT_TESTETHERNETTAP_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <set>
+
+#include "../node/Constants.hpp"
+#include "../node/InetAddress.hpp"
+#include "../node/MulticastGroup.hpp"
+#include "../node/Mutex.hpp"
+#include "../node/Utils.hpp"
+#include "../osdep/OSUtils.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Dummy test Ethernet tap that does not actually open a device on the system
+ */
+class TestEthernetTap
+{
+public:
+ TestEthernetTap(
+ const char *homePath,
+ const MAC &mac,
+ unsigned int mtu,
+ unsigned int metric,
+ uint64_t nwid,
+ const char *friendlyName,
+ void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
+ void *arg) :
+ _nwid(nwid),
+ _dev("zt_test_"),
+ _enabled(true)
+ {
+ char tmp[32];
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",(unsigned long long)_nwid);
+ _dev.append(tmp);
+#ifdef ZT_TEST_TAP_REPORT_TO
+ _reportTo.fromString(ZT_TEST_TAP_REPORT_TO);
+ if (_reportTo.ss_family == AF_INET)
+ _reportsock = socket(AF_INET,SOCK_DGRAM,0);
+ else if (_reportTo.ss_family == AF_INET6)
+ _reportsock = socket(AF_INET6,SOCK_DGRAM,0);
+ else _reportsock = -1;
+#endif
+ }
+
+ ~TestEthernetTap()
+ {
+#ifdef ZT_TEST_TAP_REPORT_TO
+ if (_reportsock >= 0)
+ close(_reportsock);
+#endif
+ }
+
+ inline void setEnabled(bool en) { _enabled = en; }
+ inline bool enabled() const { return _enabled; }
+
+ inline bool addIp(const InetAddress &ip)
+ {
+ Mutex::Lock _l(_lock);
+ _ips.insert(ip);
+ return true;
+ }
+
+ inline bool removeIp(const InetAddress &ip)
+ {
+ Mutex::Lock _l(_lock);
+ _ips.erase(ip);
+ return true;
+ }
+
+ inline std::vector<InetAddress> ips() const
+ {
+ Mutex::Lock _l(_lock);
+ return std::vector<InetAddress>(_ips.begin(),_ips.end());
+ }
+
+ inline void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
+ {
+#ifdef ZT_TEST_TAP_REPORT_TO
+ char tmp[10000];
+ if ((_reportsock >= 0)&&(len < (sizeof(tmp) - 22))) {
+ const uint64_t nwid2 = Utils::hton(_nwid);
+ memcpy(tmp,&nwid2,8);
+ from.copyTo(tmp + 8,6);
+ to.copyTo(tmp + 14,6);
+ const uint16_t etherType2 = Utils::hton((uint16_t)etherType);
+ memcpy(tmp + 20,&etherType2,2);
+ memcpy(tmp + 22,data,len);
+ sendto(_reportsock,tmp,len + 22,0,reinterpret_cast<const struct sockaddr *>(&_reportTo),(_reportTo.ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
+ }
+#endif
+ }
+
+ inline std::string deviceName() const
+ {
+ return _dev;
+ }
+
+ inline void setFriendlyName(const char *friendlyName)
+ {
+ }
+
+ inline void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
+ {
+ }
+
+ inline void setMtu(unsigned int mtu)
+ {
+ }
+
+private:
+ uint64_t _nwid;
+ std::string _dev;
+ std::set<InetAddress> _ips;
+ InetAddress _reportTo;
+#ifdef ZT_TEST_TAP_REPORT_TO
+ int _reportsock;
+#endif
+ bool _enabled;
+ Mutex _lock;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp
index 227c2cfe..35ea5035 100644
--- a/osdep/Thread.hpp
+++ b/osdep/Thread.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_THREAD_HPP
@@ -46,7 +54,6 @@ class Thread
{
public:
Thread()
- throw()
{
_th = NULL;
_tid = 0;
@@ -54,7 +61,6 @@ public:
template<typename C>
static inline Thread start(C *instance)
- throw(std::runtime_error)
{
Thread t;
t._th = CreateThread(NULL,0,&___zt_threadMain<C>,(LPVOID)instance,0,&t._tid);
@@ -84,11 +90,13 @@ public:
// Not available on *nix platforms
static inline void cancelIO(const Thread &t)
{
+#if !defined(__MINGW32__) && !defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2
if (t._th != NULL)
CancelSynchronousIo(t._th);
+#endif
}
- inline operator bool() const throw() { return (_th != NULL); }
+ inline operator bool() const { return (_th != NULL); }
private:
HANDLE _th;
@@ -123,33 +131,18 @@ class Thread
{
public:
Thread()
- throw()
{
- memset(&_tid,0,sizeof(_tid));
- pthread_attr_init(&_tattr);
- // This corrects for systems with abnormally small defaults (musl) and also
- // shrinks the stack on systems with large defaults to save a bit of memory.
- pthread_attr_setstacksize(&_tattr,ZT_THREAD_MIN_STACK_SIZE);
- _started = false;
- }
-
- ~Thread()
- {
- pthread_attr_destroy(&_tattr);
+ memset(this,0,sizeof(Thread));
}
Thread(const Thread &t)
- throw()
{
- memcpy(&_tid,&(t._tid),sizeof(_tid));
- _started = t._started;
+ memcpy(this,&t,sizeof(Thread));
}
inline Thread &operator=(const Thread &t)
- throw()
{
- memcpy(&_tid,&(t._tid),sizeof(_tid));
- _started = t._started;
+ memcpy(this,&t,sizeof(Thread));
return *this;
}
@@ -163,12 +156,20 @@ public:
*/
template<typename C>
static inline Thread start(C *instance)
- throw(std::runtime_error)
{
Thread t;
- t._started = true;
- if (pthread_create(&t._tid,&t._tattr,&___zt_threadMain<C>,instance))
+ pthread_attr_t tattr;
+ pthread_attr_init(&tattr);
+ // This corrects for systems with abnormally small defaults (musl) and also
+ // shrinks the stack on systems with large defaults to save a bit of memory.
+ pthread_attr_setstacksize(&tattr,ZT_THREAD_MIN_STACK_SIZE);
+ if (pthread_create(&t._tid,&tattr,&___zt_threadMain<C>,instance)) {
+ pthread_attr_destroy(&tattr);
throw std::runtime_error("pthread_create() failed, unable to create thread");
+ } else {
+ t._started = true;
+ pthread_attr_destroy(&tattr);
+ }
return t;
}
@@ -190,11 +191,10 @@ public:
*/
static inline void sleep(unsigned long ms) { usleep(ms * 1000); }
- inline operator bool() const throw() { return (_started); }
+ inline operator bool() const { return (_started); }
private:
pthread_t _tid;
- pthread_attr_t _tattr;
volatile bool _started;
};
diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp
index 79b9d35e..aa96d33a 100644
--- a/osdep/WindowsEthernetTap.cpp
+++ b/osdep/WindowsEthernetTap.cpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#include <stdio.h>
@@ -462,7 +470,9 @@ WindowsEthernetTap::WindowsEthernetTap(
_arg(arg),
_mac(mac),
_nwid(nwid),
+ _mtu(mtu),
_tap(INVALID_HANDLE_VALUE),
+ _friendlyName(friendlyName),
_injectSemaphore(INVALID_HANDLE_VALUE),
_pathToHelpers(hp),
_run(true),
@@ -473,13 +483,9 @@ WindowsEthernetTap::WindowsEthernetTap(
char subkeyClass[1024];
char data[1024];
char tag[24];
- std::string mySubkeyName;
-
- if (mtu > 2800)
- throw std::runtime_error("MTU too large.");
// We "tag" registry entries with the network ID to identify persistent devices
- Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid);
+ OSUtils::ztsnprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid);
Mutex::Lock _l(_systemTapInitLock);
@@ -522,7 +528,7 @@ WindowsEthernetTap::WindowsEthernetTap(
_netCfgInstanceId = instanceId;
_deviceInstanceId = instanceIdPath;
- mySubkeyName = subkeyName;
+ _mySubkeyName = subkeyName;
break; // found it!
}
}
@@ -565,7 +571,7 @@ WindowsEthernetTap::WindowsEthernetTap(
if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
_deviceInstanceId.assign(data,dataLen);
- mySubkeyName = subkeyName;
+ _mySubkeyName = subkeyName;
// Disable DHCP by default on new devices
HKEY tcpIpInterfaces;
@@ -596,25 +602,25 @@ WindowsEthernetTap::WindowsEthernetTap(
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);
- tmpsl = Utils::snprintf(tmps, sizeof(tmps), "%d", mtu);
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MTU",REG_SZ,tmps,tmpsl);
+ unsigned int tmpsl = OSUtils::ztsnprintf(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);
+ tmpsl = OSUtils::ztsnprintf(tmps, sizeof(tmps), "%d", mtu);
+ RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"MTU",REG_SZ,tmps,tmpsl);
DWORD tmp = 0;
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*NdisDeviceType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
+ 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));
+ RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
if (creatingNewDevice) {
// Vista/2008 does not set this
if (newDeviceInstanceId.length() > 0)
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"DeviceInstanceID",REG_SZ,newDeviceInstanceId.c_str(),(DWORD)newDeviceInstanceId.length());
+ RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"DeviceInstanceID",REG_SZ,newDeviceInstanceId.c_str(),(DWORD)newDeviceInstanceId.length());
// Set EnableDHCP to 0 by default on new devices
tmp = 0;
- RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
+ RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
}
RegCloseKey(nwAdapters);
} else {
@@ -717,20 +723,21 @@ bool WindowsEthernetTap::removeIp(const InetAddress &ip)
DeleteUnicastIpAddressEntry(&(ipt->Table[i]));
FreeMibTable(ipt);
- if (ip.isV4()) {
- 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;
- }
- }
- }
+ if (ip.isV4()) {
+ std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress"));
+ std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask"));
+ char ipbuf[64];
+ std::string ipstr(ip.toIpString(ipbuf));
+ 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;
}
@@ -745,7 +752,7 @@ bool WindowsEthernetTap::removeIp(const InetAddress &ip)
std::vector<InetAddress> WindowsEthernetTap::ips() const
{
- static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it?
+ static const InetAddress linkLocalLoopback("fe80::1/64"); // what is this and why does Windows assign it?
std::vector<InetAddress> addrs;
if (!_initialized)
@@ -784,12 +791,13 @@ std::vector<InetAddress> WindowsEthernetTap::ips() const
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)))
+ if ((!_initialized)||(!_enabled)||(_tap == INVALID_HANDLE_VALUE)||(len > _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;
+ _injectPending.emplace();
+ _injectPending.back().len = len + 14;
+ char *const d = _injectPending.back().data;
to.copyTo(d,6);
from.copyTo(d + 6,6);
d[12] = (char)((etherType >> 8) & 0xff);
@@ -833,7 +841,7 @@ void WindowsEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
// 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)) {
+ if (DeviceIoControl(t,TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS,(LPVOID)mcastbuf,sizeof(mcastbuf),(LPVOID)mcastbuf,sizeof(mcastbuf),&bytesReturned,NULL)) {
if ((bytesReturned > 0)&&(bytesReturned <= TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE)) { // sanity check
MAC mac;
DWORD i = 0;
@@ -867,6 +875,20 @@ void WindowsEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
_multicastGroups.swap(newGroups);
}
+void WindowsEthernetTap::setMtu(unsigned int mtu)
+{
+ if (mtu != _mtu) {
+ _mtu = mtu;
+ HKEY nwAdapters;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ | KEY_WRITE, &nwAdapters) == ERROR_SUCCESS) {
+ char tmps[64];
+ unsigned int tmpsl = OSUtils::ztsnprintf(tmps, sizeof(tmps), "%d", mtu);
+ RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "MTU", REG_SZ, tmps, tmpsl);
+ RegCloseKey(nwAdapters);
+ }
+ }
+}
+
NET_IFINDEX WindowsEthernetTap::interfaceIndex() const
{
NET_IFINDEX idx = -1;
@@ -878,12 +900,12 @@ NET_IFINDEX WindowsEthernetTap::interfaceIndex() const
void WindowsEthernetTap::threadMain()
throw()
{
- char tapReadBuf[ZT_IF_MTU + 32];
+ char tapReadBuf[ZT_MAX_MTU + 32];
char tapPath[128];
HANDLE wait4[3];
OVERLAPPED tapOvlRead,tapOvlWrite;
- Utils::snprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str());
+ OSUtils::ztsnprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str());
try {
while (_run) {
@@ -1007,13 +1029,18 @@ void WindowsEthernetTap::threadMain()
ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead);
bool writeInProgress = false;
ULONGLONG timeOfLastBorkCheck = GetTickCount64();
+ _initialized = true;
+ unsigned int oldmtu = _mtu;
-
- _initialized = true;
+ setFriendlyName(_friendlyName.c_str());
while (_run) {
DWORD waitResult = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE);
- if (!_run) break; // will also break outer while(_run)
+ if (!_run) break; // will also break outer while(_run) since _run is false
+
+ // Check for changes in MTU and break to restart tap device to reconfigure in this case
+ if (_mtu != oldmtu)
+ break;
// Check for issues with adapter and close/reopen if any are detected. This
// check fixes a while boatload of Windows adapter 'coma' issues after
@@ -1062,7 +1089,7 @@ void WindowsEthernetTap::threadMain()
} catch ( ... ) {} // handlers should not throw
}
}
- ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead);
+ ReadFile(_tap,tapReadBuf,ZT_MAX_MTU + 32,NULL,&tapOvlRead);
}
if (writeInProgress) {
@@ -1074,7 +1101,7 @@ void WindowsEthernetTap::threadMain()
} else _injectPending_m.lock();
if (!_injectPending.empty()) {
- WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&tapOvlWrite);
+ WriteFile(_tap,_injectPending.front().data,_injectPending.front().len,NULL,&tapOvlWrite);
writeInProgress = true;
}
@@ -1204,18 +1231,18 @@ void WindowsEthernetTap::_syncIps()
CreateUnicastIpAddressEntry(&ipr);
}
- if (aip->isV4())
- {
- std::string ipStr(aip->toIpString());
- std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress"));
- if (std::find(regIps.begin(), regIps.end(), ipStr) == regIps.end()) {
- std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask"));
- regIps.push_back(ipStr);
- regSubnetMasks.push_back(aip->netmask().toIpString());
- _setRegistryIPv4Value("IPAddress", regIps);
- _setRegistryIPv4Value("SubnetMask", regSubnetMasks);
- }
- }
+ if (aip->isV4()) {
+ char ipbuf[64];
+ std::string ipStr(aip->toIpString(ipbuf));
+ std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress"));
+ if (std::find(regIps.begin(), regIps.end(), ipStr) == regIps.end()) {
+ std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask"));
+ regIps.push_back(ipStr);
+ regSubnetMasks.push_back(aip->netmask().toIpString(ipbuf));
+ _setRegistryIPv4Value("IPAddress", regIps);
+ _setRegistryIPv4Value("SubnetMask", regSubnetMasks);
+ }
+ }
}
}
diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp
index f2cf73f3..1e36bdd8 100644
--- a/osdep/WindowsEthernetTap.hpp
+++ b/osdep/WindowsEthernetTap.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* 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
@@ -14,6 +14,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
*/
#ifndef ZT_WINDOWSETHERNETTAP_HPP
@@ -30,7 +38,6 @@
#include "../node/Constants.hpp"
#include "../node/Mutex.hpp"
-#include "../node/Array.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/InetAddress.hpp"
#include "../osdep/Thread.hpp"
@@ -101,6 +108,7 @@ public:
std::string deviceName() const;
void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
+ void setMtu(unsigned int mtu);
inline const NET_LUID &luid() const { return _deviceLuid; }
inline const GUID &guid() const { return _deviceGuid; }
@@ -122,6 +130,7 @@ private:
void *_arg;
MAC _mac;
uint64_t _nwid;
+ volatile unsigned int _mtu;
Thread _thread;
volatile HANDLE _tap;
@@ -131,13 +140,21 @@ private:
NET_LUID _deviceLuid;
std::string _netCfgInstanceId;
std::string _deviceInstanceId;
+ std::string _mySubkeyName;
+
+ std::string _friendlyName;
std::vector<InetAddress> _assignedIps; // IPs assigned with addIp
Mutex _assignedIps_m;
std::vector<MulticastGroup> _multicastGroups;
- std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending;
+ struct _InjectPending
+ {
+ unsigned int len;
+ char data[ZT_MAX_MTU + 32];
+ };
+ std::queue<_InjectPending> _injectPending;
Mutex _injectPending_m;
std::string _pathToHelpers;