summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/Buffer.hpp2
-rw-r--r--node/Constants.hpp79
-rw-r--r--node/EthernetTap.cpp562
-rw-r--r--node/EthernetTap.hpp70
-rw-r--r--node/Network.cpp38
-rw-r--r--node/Network.hpp14
-rw-r--r--node/Packet.hpp164
-rw-r--r--node/Salsa20.cpp1
8 files changed, 421 insertions, 509 deletions
diff --git a/node/Buffer.hpp b/node/Buffer.hpp
index d3603d38..0320ddb7 100644
--- a/node/Buffer.hpp
+++ b/node/Buffer.hpp
@@ -388,7 +388,7 @@ public:
return !(*this < b);
}
-protected:
+private:
unsigned int _l;
char ZT_VAR_MAY_ALIAS _b[C];
};
diff --git a/node/Constants.hpp b/node/Constants.hpp
index 394c89eb..4517cc07 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -28,10 +28,55 @@
#ifndef _ZT_CONSTANTS_HPP
#define _ZT_CONSTANTS_HPP
-// Assume these are little-endian, since we don't support old PPC MACs
-// and all newer Mac or Windows systems are either x86_32, x86_64, or
-// ARM in little-endian mode.
-#if defined(__APPLE__) || defined(_WIN32)
+//
+// This include file also auto-detects and canonicalizes some environment
+// information defines:
+//
+// __LINUX__
+// __APPLE__
+// __UNIX_LIKE__ - any "unix like" OS (BSD, posix, etc.)
+// __WINDOWS__
+//
+// Also makes sure __BYTE_ORDER is defined reasonably.
+//
+
+// Canonicalize Linux... is this necessary? Do it anyway to be defensive.
+#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
+#ifndef __LINUX__
+#define __LINUX__
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#endif
+#endif
+
+// TODO: Android is what? Linux technically, but does it define it?
+
+// OSX and iOS are unix-like OSes far as we're concerned
+#ifdef __APPLE__
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#endif
+
+// Linux has endian.h
+#ifdef __LINUX__
+#include <endian.h>
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+#ifndef __WINDOWS__
+#define __WINDOWS__
+#endif
+#undef __UNIX_LIKE__
+#define ZT_PATH_SEPARATOR '\\'
+#define ZT_PATH_SEPARATOR_S "\\"
+#define ZT_EOL_S "\r\n"
+#endif
+
+// Assume these are little-endian. PPC is not supported for OSX, and ARM
+// runs in little-endian mode for these OS families.
+#if defined(__APPLE__) || defined(__WINDOWS__)
#undef __BYTE_ORDER
#undef __LITTLE_ENDIAN
#undef __BIG_ENDIAN
@@ -40,31 +85,21 @@
#define __BYTE_ORDER 1234
#endif
-// Linux has endian.h, which should tell us
-#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
-#include <endian.h>
+#ifdef __UNIX_LIKE__
+#define ZT_PATH_SEPARATOR '/'
+#define ZT_PATH_SEPARATOR_S "/"
+#define ZT_EOL_S "\n"
#endif
+// Error out if required symbols are missing
#ifndef __BYTE_ORDER
-error_no_byte_order_defined
+error_no_byte_order_defined;
#endif
-
#ifndef ZT_OSNAME
-error_no_ZT_OSNAME
+error_no_ZT_OSNAME_defined;
#endif
-
#ifndef ZT_ARCH
-error_no_ZT_ARCH
-#endif
-
-#ifdef _WIN32
-#define ZT_PATH_SEPARATOR '\\'
-#define ZT_PATH_SEPARATOR_S "\\"
-#define ZT_EOL_S "\r\n"
-#else
-#define ZT_PATH_SEPARATOR '/'
-#define ZT_PATH_SEPARATOR_S "/"
-#define ZT_EOL_S "\n"
+error_no_ZT_ARCH_defined;
#endif
/**
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp
index 62eee69c..9158e937 100644
--- a/node/EthernetTap.cpp
+++ b/node/EthernetTap.cpp
@@ -30,15 +30,17 @@
#include "EthernetTap.hpp"
#include "Logger.hpp"
#include "RuntimeEnvironment.hpp"
+#include "Utils.hpp"
#include "Mutex.hpp"
-#include "MulticastGroup.hpp"
// ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
-/* ======================================================================== */
-#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
-/* ======================================================================== */
+//
+// TAP implementation for *nix OSes, with some specialization for different flavors
+//
+
+#ifdef __UNIX_LIKE__ /////////////////////////////////////////////////////////
#include <stdint.h>
#include <stdio.h>
@@ -52,10 +54,13 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
+#include <sys/select.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
+#ifdef __LINUX__
+
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/if_addr.h>
@@ -64,23 +69,49 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
#define ZT_ETHERTAP_IP_COMMAND "/sbin/ip"
#define ZT_ETHERTAP_SYSCTL_COMMAND "/sbin/sysctl"
+#endif // __LINUX__
+
+#ifdef __APPLE__
+
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+
+#define ZT_ETHERTAP_IFCONFIG "/sbin/ifconfig"
+#define ZT_MAC_KEXTLOAD "/sbin/kextload"
+#define ZT_MAC_IPCONFIG "/usr/sbin/ipconfig"
+
+#endif // __APPLE__
+
namespace ZeroTier {
+// Only permit one tap to be opened concurrently across the entire process
static Mutex __tapCreateLock;
-EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned int mtu)
+#ifdef __LINUX__
+EthernetTap::EthernetTap(
+ const RuntimeEnvironment *renv,
+ const MAC &mac,
+ unsigned int mtu,
+ void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
+ void *arg)
throw(std::runtime_error) :
_mac(mac),
_mtu(mtu),
_r(renv),
- _putBuf((unsigned char *)0),
- _getBuf((unsigned char *)0),
- _fd(0),
- _isReading(false)
+ _handler(handler),
+ _arg(arg),
+ _fd(0)
{
char procpath[128];
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
+ if (mtu > 4096)
+ throw std::runtime_error("max tap MTU is 4096");
+
_fd = ::open("/dev/net/tun",O_RDWR);
if (_fd <= 0)
throw std::runtime_error("could not open TUN/TAP device");
@@ -152,266 +183,36 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
::close(sock);
- _putBuf = new unsigned char[((mtu + 16) * 2)];
- _getBuf = _putBuf + (mtu + 16);
+ ::pipe(_shutdownSignalPipe);
TRACE("tap %s created",_dev);
-}
-
-EthernetTap::~EthernetTap()
-{
- this->close();
- delete [] _putBuf;
-}
-
-void EthernetTap::whack()
-{
- // Linux requires nothing here
-}
-
-static bool ___removeIp(const char *_dev,std::set<InetAddress> &_ips,const InetAddress &ip)
-{
- long cpid;
- if ((cpid = (long)fork()) == 0) {
- execl(ZT_ETHERTAP_IP_COMMAND,ZT_ETHERTAP_IP_COMMAND,"addr","del",ip.toString().c_str(),"dev",_dev,(const char *)0);
- exit(1); /* not reached unless exec fails */
- } else {
- int exitcode = 1;
- waitpid(cpid,&exitcode,0);
- if (exitcode == 0) {
- _ips.erase(ip);
- return true;
- } else return false;
- }
-}
-
-bool EthernetTap::addIP(const InetAddress &ip)
-{
- Mutex::Lock _l(_ips_m);
-
- if (!ip)
- return false;
- if (_ips.count(ip) > 0)
- return true;
-
- // Remove and reconfigure if address is the same but netmask is different
- for(std::set<InetAddress>::iterator i(_ips.begin());i!=_ips.end();++i) {
- if (i->ipsEqual(ip)) {
- ___removeIp(_dev,_ips,*i);
- break;
- }
- }
-
- int cpid;
- if ((cpid = (int)fork()) == 0) {
- execl(ZT_ETHERTAP_IP_COMMAND,ZT_ETHERTAP_IP_COMMAND,"addr","add",ip.toString().c_str(),"dev",_dev,(const char *)0);
- exit(-1);
- } else {
- int exitcode = -1;
- waitpid(cpid,&exitcode,0);
- if (exitcode == 0) {
- _ips.insert(ip);
- return true;
- } else return false;
- }
-
- return false;
-}
-
-bool EthernetTap::removeIP(const InetAddress &ip)
-{
- Mutex::Lock _l(_ips_m);
- if (_ips.count(ip) > 0)
- return ___removeIp(_dev,_ips,ip);
- return false;
-}
-
-void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
-{
- if ((_fd > 0)&&(len <= _mtu)) {
- for(int i=0;i<6;++i)
- _putBuf[i] = to.data[i];
- for(int i=0;i<6;++i)
- _putBuf[i+6] = from.data[i];
- *((uint16_t *)(_putBuf + 12)) = htons((uint16_t)etherType);
- memcpy(_putBuf + 14,data,len);
- ::write(_fd,_putBuf,len + 14);
- }
-}
-
-unsigned int EthernetTap::get(MAC &from,MAC &to,unsigned int &etherType,void *buf)
-{
- for(;;) {
- if (_fd > 0) {
- _isReading_m.lock();
- _isReading = true;
- _isReadingThreadId = pthread_self();
- _isReading_m.unlock();
-
- int n = (int)::read(_fd,_getBuf,_mtu + 14);
-
- _isReading_m.lock();
- _isReading = false;
- _isReading_m.unlock();
-
- if (n > 14) {
- for(int i=0;i<6;++i)
- to.data[i] = _getBuf[i];
- for(int i=0;i<6;++i)
- from.data[i] = _getBuf[i + 6];
- etherType = ntohs(((uint16_t *)_getBuf)[6]);
- n -= 14;
- memcpy(buf,_getBuf + 14,n);
- return (unsigned int)n;
- } else if (n < 0) {
- if (_fd <= 0)
- break;
- else if ((errno == EINTR)||(errno == ETIMEDOUT))
- continue;
- else {
- TRACE("unexpected error reading from tap: %s",strerror(errno));
- ::close(_fd);
- _fd = 0;
- break;
- }
- } else {
- TRACE("incomplete read from tap: %d bytes",n);
- continue;
- }
- }
- }
- return 0;
-}
-
-std::string EthernetTap::deviceName()
-{
- return std::string(_dev);
-}
-bool EthernetTap::open() const
-{
- return (_fd > 0);
+ start();
}
-
-void EthernetTap::close()
-{
- Mutex::Lock _l(__tapCreateLock); // also prevent create during close()
- if (_fd > 0) {
- int f = _fd;
- _fd = 0;
- ::close(f);
-
- _isReading_m.lock();
- if (_isReading)
- pthread_kill(_isReadingThreadId,SIGUSR2);
- _isReading_m.unlock();
- }
-}
-
-bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
-{
- char *ptr,*ptr2;
- unsigned char mac[6];
- std::set<MulticastGroup> newGroups;
-
- int fd = ::open("/proc/net/dev_mcast",O_RDONLY);
- if (fd > 0) {
- char buf[131072];
- int n = (int)::read(fd,buf,sizeof(buf));
- if ((n > 0)&&(n < (int)sizeof(buf))) {
- buf[n] = (char)0;
- for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) {
- int fno = 0;
- char *devname = (char *)0;
- char *mcastmac = (char *)0;
- for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) {
- if (fno == 1)
- devname = f;
- else if (fno == 4)
- mcastmac = f;
- ++fno;
- }
- if ((devname)&&(!strcmp(devname,_dev))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6))
- newGroups.insert(MulticastGroup(MAC(mac),0));
- }
- }
- ::close(fd);
- }
-
- {
- Mutex::Lock _l(_ips_m);
- for(std::set<InetAddress>::const_iterator i(_ips.begin());i!=_ips.end();++i)
- newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
- }
-
- bool changed = false;
-
- newGroups.insert(_blindWildcardMulticastGroup); // always join this
-
- 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)) {
- groups.erase(mg++);
- changed = true;
- } else ++mg;
- }
-
- return changed;
-}
-
-} // namespace ZeroTier
-
-/* ======================================================================== */
-#elif defined(__APPLE__) /* ----------------------------------------------- */
-/* ======================================================================== */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/route.h>
-#include <net/if_dl.h>
-#include <ifaddrs.h>
-
-#define ZT_ETHERTAP_IFCONFIG "/sbin/ifconfig"
-#define ZT_MAC_KEXTLOAD "/sbin/kextload"
-#define ZT_MAC_IPCONFIG "/usr/sbin/ipconfig"
-
-namespace ZeroTier {
-
-static Mutex __tapCreateLock;
-
-EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned int mtu)
+#endif // __LINUX__
+
+#ifdef __APPLE__
+EthernetTap::EthernetTap(
+ const RuntimeEnvironment *renv,
+ const MAC &mac,
+ unsigned int mtu,
+ void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
+ void *arg)
throw(std::runtime_error) :
_mac(mac),
_mtu(mtu),
_r(renv),
- _putBuf((unsigned char *)0),
- _getBuf((unsigned char *)0),
- _fd(0),
- _isReading(false)
+ _handler(handler),
+ _arg(arg),
+ _fd(0)
{
char devpath[64],ethaddr[64],mtustr[16];
struct stat tmp;
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
+ if (mtu > 4096)
+ throw std::runtime_error("max tap MTU is 4096");
+
// Check for existence of ZT tap devices, try to load module if not there
if (stat("/dev/zt0",&tmp)) {
int kextpid;
@@ -453,8 +254,8 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
sprintf(mtustr,"%u",mtu);
// Configure MAC address and MTU, bring interface up
- int cpid;
- if ((cpid = (int)fork()) == 0) {
+ long cpid;
+ if ((cpid = (long)fork()) == 0) {
execl(ZT_ETHERTAP_IFCONFIG,ZT_ETHERTAP_IFCONFIG,_dev,"lladdr",ethaddr,"mtu",mtustr,"up",(const char *)0);
exit(-1);
} else {
@@ -468,19 +269,23 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
whack(); // turns on IPv6 on OSX
- _putBuf = new unsigned char[((mtu + 14) * 2)];
- _getBuf = _putBuf + (mtu + 14);
+ ::pipe(_shutdownSignalPipe);
+
+ start();
}
+#endif // __APPLE__
EthernetTap::~EthernetTap()
{
- this->close();
- delete [] _putBuf;
+ ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
+ join();
+ ::close(_fd);
}
+#ifdef __APPLE__
void EthernetTap::whack()
{
- int cpid = fork();
+ long cpid = (long)fork();
if (cpid == 0) {
execl(ZT_MAC_IPCONFIG,ZT_MAC_IPCONFIG,"set",_dev,"AUTOMATIC-V6",(const char *)0);
exit(-1);
@@ -492,8 +297,63 @@ void EthernetTap::whack()
}
}
}
+#else
+void EthernetTap::whack() {}
+#endif // __APPLE__ / !__APPLE__
-// Helper function to actually remove IP from network device, execs ifconfig
+#ifdef __LINUX__
+static bool ___removeIp(const char *_dev,const InetAddress &ip)
+{
+ long cpid = (long)fork();
+ if (cpid == 0) {
+ execl(ZT_ETHERTAP_IP_COMMAND,ZT_ETHERTAP_IP_COMMAND,"addr","del",ip.toString().c_str(),"dev",_dev,(const char *)0);
+ exit(1); /* not reached unless exec fails */
+ } else {
+ int exitcode = 1;
+ waitpid(cpid,&exitcode,0);
+ return (exitcode == 0);
+ }
+}
+
+bool EthernetTap::addIP(const InetAddress &ip)
+{
+ Mutex::Lock _l(_ips_m);
+
+ if (!ip)
+ return false;
+ if (_ips.count(ip) > 0)
+ return true;
+
+ // Remove and reconfigure if address is the same but netmask is different
+ for(std::set<InetAddress>::iterator i(_ips.begin());i!=_ips.end();++i) {
+ if (i->ipsEqual(ip)) {
+ if (___removeIp(_dev,*i)) {
+ _ips.erase(i);
+ break;
+ } else {
+ LOG("WARNING: failed to remove old IP/netmask %s to replace with %s",i->toString().c_str(),ip.toString().c_str());
+ }
+ }
+ }
+
+ long cpid;
+ if ((cpid = (long)fork()) == 0) {
+ execl(ZT_ETHERTAP_IP_COMMAND,ZT_ETHERTAP_IP_COMMAND,"addr","add",ip.toString().c_str(),"dev",_dev,(const char *)0);
+ exit(-1);
+ } else {
+ int exitcode = -1;
+ waitpid(cpid,&exitcode,0);
+ if (exitcode == 0) {
+ _ips.insert(ip);
+ return true;
+ } else return false;
+ }
+
+ return false;
+}
+#endif // __LINUX__
+
+#ifdef __APPLE__
static bool ___removeIp(const char *_dev,const InetAddress &ip)
{
int cpid;
@@ -544,6 +404,7 @@ bool EthernetTap::addIP(const InetAddress &ip)
return false;
}
+#endif // __APPLE__
bool EthernetTap::removeIP(const InetAddress &ip)
{
@@ -559,94 +420,90 @@ bool EthernetTap::removeIP(const InetAddress &ip)
void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
+ char putBuf[4096 + 14];
if ((_fd > 0)&&(len <= _mtu)) {
for(int i=0;i<6;++i)
- _putBuf[i] = to.data[i];
+ putBuf[i] = to.data[i];
for(int i=0;i<6;++i)
- _putBuf[i+6] = from.data[i];
- *((uint16_t *)(_putBuf + 12)) = htons((uint16_t)etherType);
- memcpy(_putBuf + 14,data,len);
+ putBuf[i+6] = from.data[i];
+ *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
+ memcpy(putBuf + 14,data,len);
len += 14;
- int n = (int)::write(_fd,_putBuf,len);
+ int n = ::write(_fd,putBuf,len);
if (n <= 0) {
LOG("error writing packet to Ethernet tap device: %s",strerror(errno));
} else if (n != (int)len) {
// Saw this gremlin once, so log it if we see it again... OSX tap
// or something seems to have goofy issues with certain MTUs.
- LOG("WARNING: Apple gremlin: tap write() wrote %d of %u bytes of frame",n,len);
+ LOG("ERROR: write underrun: %s tap write() wrote %d of %u bytes of frame",_dev,n,len);
}
}
}
-unsigned int EthernetTap::get(MAC &from,MAC &to,unsigned int &etherType,void *buf)
+std::string EthernetTap::deviceName() const
{
- for(;;) {
- if (_fd > 0) {
- _isReading_m.lock();
- _isReading = true;
- _isReadingThreadId = pthread_self();
- _isReading_m.unlock();
-
- int n = (int)::read(_fd,_getBuf,_mtu + 14);
+ return std::string(_dev);
+}
- _isReading_m.lock();
- _isReading = false;
- _isReading_m.unlock();
+#ifdef __LINUX__
+bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
+{
+ char *ptr,*ptr2;
+ unsigned char mac[6];
+ std::set<MulticastGroup> newGroups;
- if (n > 14) {
- for(int i=0;i<6;++i)
- to.data[i] = _getBuf[i];
- for(int i=0;i<6;++i)
- from.data[i] = _getBuf[i + 6];
- etherType = ntohs(((uint16_t *)_getBuf)[6]);
- n -= 14;
- memcpy(buf,_getBuf + 14,n);
- return (unsigned int)n;
- } else if (n < 0) {
- if (_fd <= 0)
- break;
- else if ((errno == EINTR)||(errno == ETIMEDOUT))
- continue;
- else {
- TRACE("unexpected error reading from tap: %s",strerror(errno));
- ::close(_fd);
- _fd = 0;
- break;
+ int fd = ::open("/proc/net/dev_mcast",O_RDONLY);
+ if (fd > 0) {
+ char buf[131072];
+ int n = (int)::read(fd,buf,sizeof(buf));
+ if ((n > 0)&&(n < (int)sizeof(buf))) {
+ buf[n] = (char)0;
+ for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) {
+ int fno = 0;
+ char *devname = (char *)0;
+ char *mcastmac = (char *)0;
+ for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) {
+ if (fno == 1)
+ devname = f;
+ else if (fno == 4)
+ mcastmac = f;
+ ++fno;
}
- } else {
- TRACE("incomplete read from tap: %d bytes",n);
- continue;
+ if ((devname)&&(!strcmp(devname,_dev))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6))
+ newGroups.insert(MulticastGroup(MAC(mac),0));
}
}
+ ::close(fd);
}
- return 0;
-}
-std::string EthernetTap::deviceName()
-{
- return std::string(_dev);
-}
+ {
+ Mutex::Lock _l(_ips_m);
+ for(std::set<InetAddress>::const_iterator i(_ips.begin());i!=_ips.end();++i)
+ newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
+ }
-bool EthernetTap::open() const
-{
- return (_fd > 0);
-}
+ bool changed = false;
-void EthernetTap::close()
-{
- Mutex::Lock _l(__tapCreateLock); // also prevent create during close()
- if (_fd > 0) {
- int f = _fd;
- _fd = 0;
- ::close(f);
-
- _isReading_m.lock();
- if (_isReading)
- pthread_kill(_isReadingThreadId,SIGUSR2);
- _isReading_m.unlock();
+ newGroups.insert(_blindWildcardMulticastGroup); // always join this
+
+ 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)) {
+ groups.erase(mg++);
+ changed = true;
+ } else ++mg;
+ }
+
+ return changed;
}
+#endif __LINUX__
+#ifdef __APPLE__
bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
{
std::set<MulticastGroup> newGroups;
@@ -690,13 +547,54 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
return changed;
}
+#endif // __APPLE__
+
+void EthernetTap::main()
+ throw()
+{
+ fd_set readfds,nullfds;
+ MAC to,from;
+ char getBuf[4096 + 14];
+ Buffer<4096> data;
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&nullfds);
+ int nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
+
+ for(;;) {
+ FD_SET(_shutdownSignalPipe[0],&readfds);
+ FD_SET(_fd,&readfds);
+ select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
+
+ if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
+ break;
+
+ if (FD_ISSET(_fd,&readfds)) {
+ int n = (int)::read(_fd,getBuf,_mtu + 14);
+
+ if (n > 14) {
+ for(int i=0;i<6;++i)
+ to.data[i] = (unsigned char)getBuf[i];
+ for(int i=0;i<6;++i)
+ from.data[i] = (unsigned char)getBuf[i + 6];
+ data.copyFrom(getBuf + 14,(unsigned int)n - 14);
+ _handler(_arg,from,to,ntohs(((const uint16_t *)getBuf)[6]),data);
+ } else if (n < 0) {
+ if ((errno != EINTR)&&(errno != ETIMEDOUT)) {
+ TRACE("unexpected error reading from tap: %s",strerror(errno));
+ break;
+ }
+ }
+ }
+ }
+}
} // namespace ZeroTier
-/* ======================================================================== */
-#elif defined(_WIN32) /* -------------------------------------------------- */
-/* ======================================================================== */
+#endif // __UNIX_LIKE__ //////////////////////////////////////////////////////
+
+#ifdef __WINDOWS__
+
+// TODO
-/* ======================================================================== */
-#endif
-/* ======================================================================== */
+#endif // __WINDOWS__
diff --git a/node/EthernetTap.hpp b/node/EthernetTap.hpp
index 280bd990..3bc7cad8 100644
--- a/node/EthernetTap.hpp
+++ b/node/EthernetTap.hpp
@@ -36,14 +36,13 @@
#include <set>
#include <string>
#include <stdexcept>
-#include "Array.hpp"
-#include "Utils.hpp"
+#include "Constants.hpp"
#include "InetAddress.hpp"
-#include "NonCopyable.hpp"
#include "MAC.hpp"
-#include "Constants.hpp"
#include "Mutex.hpp"
#include "MulticastGroup.hpp"
+#include "Thread.hpp"
+#include "Buffer.hpp"
namespace ZeroTier {
@@ -52,21 +51,35 @@ class RuntimeEnvironment;
/**
* System ethernet tap device
*/
-class EthernetTap : NonCopyable
+class EthernetTap : protected Thread
{
public:
/**
* Construct a new TAP device
*
+ * Handler arguments: arg,from,to,etherType,data
+ *
* @param renv Runtime environment
* @param mac MAC address of device
* @param mtu MTU of device
+ * @param handler Handler function to be called when data is received from the tap
+ * @param arg First argument to handler function
* @throws std::runtime_error Unable to allocate device
*/
- EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned int mtu)
+ EthernetTap(
+ const RuntimeEnvironment *renv,
+ const MAC &mac,
+ unsigned int mtu,
+ void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
+ void *arg)
throw(std::runtime_error);
- ~EthernetTap();
+ /**
+ * Close tap and shut down thread
+ *
+ * This may block for a few seconds while thread exits.
+ */
+ virtual ~EthernetTap();
/**
* Perform OS dependent actions on network configuration change detection
@@ -138,30 +151,9 @@ public:
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
/**
- * Get the next packet from the interface, blocking if none is available.
- *
- * @param from Filled with MAC address of source (normally our own)
- * @param to Filled with MAC address of destination
- * @param etherType Filled with Ethernet frame type
- * @param buf Buffer to fill (must have room for MTU bytes)
- * @return Number of bytes read or 0 if none
- */
- unsigned int get(MAC &from,MAC &to,unsigned int &etherType,void *buf);
-
- /**
* @return OS-specific device or connection name
*/
- std::string deviceName();
-
- /**
- * @return True if tap is open
- */
- bool open() const;
-
- /**
- * Close this tap, invalidating the object and causing get() to abort
- */
- void close();
+ std::string deviceName() const;
/**
* Fill or modify a set to contain multicast groups for this device
@@ -177,6 +169,10 @@ public:
*/
bool updateMulticastGroups(std::set<MulticastGroup> &groups);
+protected:
+ virtual void main()
+ throw();
+
private:
const MAC _mac;
const unsigned int _mtu;
@@ -186,20 +182,14 @@ private:
std::set<InetAddress> _ips;
Mutex _ips_m;
-#if defined(__APPLE__) || defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
+ void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
+ void *_arg;
+#ifdef __UNIX_LIKE__
char _dev[16];
- unsigned char *_putBuf;
- unsigned char *_getBuf;
int _fd;
-
- bool _isReading;
- pthread_t _isReadingThreadId;
- Mutex _isReading_m;
-
-#elif defined(_WIN32) /* -------------------------------------------------- */
-
-#endif /* ----------------------------------------------------------------- */
+ int _shutdownSignalPipe[2];
+#endif
};
} // namespace ZeroTier
diff --git a/node/Network.cpp b/node/Network.cpp
index 41f04e9f..f34e07e0 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -32,49 +32,29 @@ namespace ZeroTier {
Network::Network(const RuntimeEnvironment *renv,uint64_t id)
throw(std::runtime_error) :
- Thread(),
_r(renv),
_id(id),
- _tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU),
+ _tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this),
_members(),
_open(false),
_lock()
{
- TRACE("new network %llu created, TAP device: %s",id,_tap.deviceName().c_str());
- start();
}
Network::~Network()
{
- _tap.close();
- join();
- TRACE("network %llu (%s) closed",_id,_tap.deviceName().c_str());
}
-void Network::main()
- throw()
+void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data)
{
- Buffer<4096> buf;
- MAC from,to;
- unsigned int etherType = 0;
-
- while (_tap.open()) {
- unsigned int len = _tap.get(from,to,etherType,buf.data());
- if (len) {
- buf.setSize(len);
- try {
- if (!*__refCount)
- break; // sanity check
- _r->sw->onLocalEthernet(SharedPtr<Network>(this),from,to,etherType,buf);
- } catch (std::exception &exc) {
- TRACE("unexpected exception handling local packet: %s",exc.what());
- } catch ( ... ) {
- TRACE("unexpected exception handling local packet");
- }
- } else break;
+ const RuntimeEnvironment *_r = ((Network *)arg)->_r;
+ try {
+ _r->sw->onLocalEthernet(SharedPtr<Network>((Network *)arg),from,to,etherType,data);
+ } catch (std::exception &exc) {
+ TRACE("unexpected exception handling local packet: %s",exc.what());
+ } catch ( ... ) {
+ TRACE("unexpected exception handling local packet");
}
-
- TRACE("network %llu thread terminating",_id);
}
} // namespace ZeroTier
diff --git a/node/Network.hpp b/node/Network.hpp
index 1bbf0a9f..0ed3bef5 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -40,8 +40,8 @@
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "RuntimeEnvironment.hpp"
-#include "Thread.hpp"
#include "MulticastGroup.hpp"
+#include "NonCopyable.hpp"
namespace ZeroTier {
@@ -50,17 +50,17 @@ class NodeConfig;
/**
* Local network endpoint
*/
-class Network : protected Thread
+class Network : NonCopyable
{
friend class SharedPtr<Network>;
friend class NodeConfig;
private:
- virtual ~Network();
-
Network(const RuntimeEnvironment *renv,uint64_t id)
throw(std::runtime_error);
+ ~Network();
+
public:
/**
* @return Network ID
@@ -141,11 +141,9 @@ public:
return _multicastGroups;
}
-protected:
- virtual void main()
- throw();
-
private:
+ static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
+
const RuntimeEnvironment *_r;
uint64_t _id;
EthernetTap _tap;
diff --git a/node/Packet.hpp b/node/Packet.hpp
index f8f340b8..914fac84 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -263,13 +263,13 @@ public:
setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
// NOTE: this copies both the IV/packet ID and the destination address.
- memcpy(_b + ZT_PACKET_FRAGMENT_IDX_PACKET_ID,p.data() + ZT_PACKET_IDX_IV,13);
+ memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.data() + ZT_PACKET_IDX_IV,13);
- _b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
- _b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
- _b[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0;
+ (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
+ (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
+ (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0;
- memcpy(_b + ZT_PACKET_FRAGMENT_IDX_PAYLOAD,p.data() + fragStart,fragLen);
+ memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.data() + fragStart,fragLen);
}
/**
@@ -277,12 +277,12 @@ public:
*
* @return Destination ZT address
*/
- inline Address destination() const { return Address(_b + ZT_PACKET_FRAGMENT_IDX_DEST); }
+ inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH)); }
/**
* @return True if fragment is of a valid length
*/
- inline bool lengthValid() const { return (_l >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
+ inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
/**
* @return ID of packet this is a fragment of
@@ -292,36 +292,38 @@ public:
/**
* @return Total number of fragments in packet
*/
- inline unsigned int totalFragments() const { return (((unsigned int)_b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] >> 4) & 0xf); }
+ inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); }
/**
* @return Fragment number of this fragment
*/
- inline unsigned int fragmentNumber() const { return ((unsigned int)_b[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] & 0xf); }
+ inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); }
/**
* @return Fragment ZT hop count
*/
- inline unsigned int hops() const { return (unsigned int)_b[ZT_PACKET_FRAGMENT_IDX_HOPS]; }
+ inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); }
/**
* Increment this packet's hop count
*/
inline void incrementHops()
{
- _b[ZT_PACKET_FRAGMENT_IDX_HOPS] = (_b[ZT_PACKET_FRAGMENT_IDX_HOPS] + 1) & ZT_PROTO_MAX_HOPS;
+ (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS;
}
/**
- * @return Fragment payload
+ * @return Length of payload in bytes
*/
- inline unsigned char *payload() { return (unsigned char *)(_b + ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
- inline const unsigned char *payload() const { return (const unsigned char *)(_b + ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
+ inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); }
/**
- * @return Length of payload in bytes
+ * @return Raw packet payload
*/
- inline unsigned int payloadLength() const { return ((_l > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (_l - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); }
+ inline const unsigned char *payload() const
+ {
+ return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
+ }
};
/**
@@ -495,8 +497,8 @@ public:
Packet() :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
{
- Utils::getSecureRandom(_b + ZT_PACKET_IDX_IV,8);
- _b[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
+ Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
+ (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
}
/**
@@ -509,10 +511,10 @@ public:
Packet(const Address &dest,const Address &source,const Verb v) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
{
- Utils::getSecureRandom(_b + ZT_PACKET_IDX_IV,8);
+ Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
setDestination(dest);
setSource(source);
- _b[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
+ (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
setVerb(v);
}
@@ -526,10 +528,10 @@ public:
inline void reset(const Address &dest,const Address &source,const Verb v)
{
setSize(ZT_PROTO_MIN_PACKET_LENGTH);
- Utils::getSecureRandom(_b + ZT_PACKET_IDX_IV,8);
+ Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
setDestination(dest);
setSource(source);
- _b[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
+ (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
setVerb(v);
}
@@ -540,8 +542,9 @@ public:
*/
inline void setDestination(const Address &dest)
{
+ unsigned char *d = field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH);
for(unsigned int i=0;i<ZT_ADDRESS_LENGTH;++i)
- _b[i + ZT_PACKET_IDX_DEST] = dest[i];
+ d[i] = dest[i];
}
/**
@@ -551,8 +554,9 @@ public:
*/
inline void setSource(const Address &source)
{
+ unsigned char *s = field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH);
for(unsigned int i=0;i<ZT_ADDRESS_LENGTH;++i)
- _b[i + ZT_PACKET_IDX_SOURCE] = source[i];
+ s[i] = source[i];
}
/**
@@ -560,29 +564,29 @@ public:
*
* @return Destination ZT address
*/
- inline Address destination() const { return Address(_b + ZT_PACKET_IDX_DEST); }
+ inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH)); }
/**
* Get this packet's source
*
* @return Source ZT address
*/
- inline Address source() const { return Address(_b + ZT_PACKET_IDX_SOURCE); }
+ inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH)); }
/**
* @return True if packet is of valid length
*/
- inline bool lengthValid() const { return (_l >= ZT_PROTO_MIN_PACKET_LENGTH); }
+ inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); }
/**
* @return True if packet is encrypted
*/
- inline bool encrypted() const { return (((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_ENCRYPTED)); }
+ inline bool encrypted() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_ENCRYPTED)); }
/**
* @return True if packet is fragmented (expect fragments)
*/
- inline bool fragmented() const { return (((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED)); }
+ inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED)); }
/**
* Set this packet's fragmented flag
@@ -592,26 +596,26 @@ public:
inline void setFragmented(bool f)
{
if (f)
- _b[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
- else _b[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
+ (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
+ else (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
}
/**
* @return True if compressed (result only valid if unencrypted)
*/
- inline bool compressed() const { return (((unsigned char)_b[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED)); }
+ inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED)); }
/**
* @return ZeroTier forwarding hops (0 to 7)
*/
- inline unsigned int hops() const { return ((unsigned int)_b[ZT_PACKET_IDX_FLAGS] & 0x07); }
+ inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); }
/**
* Increment this packet's hop count
*/
inline void incrementHops()
{
- _b[ZT_PACKET_IDX_FLAGS] = (char)((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & 0xf8) | (((unsigned char)_b[ZT_PACKET_IDX_FLAGS] + 1) & 0x07);
+ (*this)[ZT_PACKET_IDX_FLAGS] = (char)((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & 0xf8) | (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] + 1) & 0x07);
}
/**
@@ -629,23 +633,25 @@ public:
*
* @param v New packet verb
*/
- inline void setVerb(Verb v) { _b[ZT_PACKET_IDX_VERB] = (char)v; }
+ inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; }
/**
* @return Packet verb (not including flag bits)
*/
- inline Verb verb() const { return (Verb)(_b[ZT_PACKET_IDX_VERB] & 0x1f); }
+ inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); }
/**
* @return Length of packet payload
*/
- inline unsigned int payloadLength() const throw() { return ((_l < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (_l - ZT_PROTO_MIN_PACKET_LENGTH)); }
+ inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); }
/**
- * @return Packet payload
+ * @return Raw packet payload
*/
- inline unsigned char *payload() throw() { return (unsigned char *)(_b + ZT_PACKET_IDX_PAYLOAD); }
- inline const unsigned char *payload() const throw() { return (const unsigned char *)(_b + ZT_PACKET_IDX_PAYLOAD); }
+ inline const unsigned char *payload() const
+ {
+ return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
+ }
/**
* Compute the HMAC of this packet's payload and set HMAC field
@@ -655,13 +661,13 @@ public:
* @param key 256-bit (32 byte) key
*/
inline void hmacSet(const void *key)
- throw()
{
unsigned char mac[32];
unsigned char key2[32];
_mangleKey((const unsigned char *)key,key2);
- HMAC::sha256(key2,sizeof(key2),_b + ZT_PACKET_IDX_VERB,(_l >= ZT_PACKET_IDX_VERB) ? (_l - ZT_PACKET_IDX_VERB) : 0,mac);
- memcpy(_b + ZT_PACKET_IDX_HMAC,mac,8);
+ unsigned int hmacLen = (size() >= ZT_PACKET_IDX_VERB) ? (size() - ZT_PACKET_IDX_VERB) : 0;
+ HMAC::sha256(key2,sizeof(key2),field(ZT_PACKET_IDX_VERB,hmacLen),hmacLen,mac);
+ memcpy(field(ZT_PACKET_IDX_HMAC,8),mac,8);
}
/**
@@ -672,15 +678,15 @@ public:
* @param key 256-bit (32 byte) key
*/
inline bool hmacVerify(const void *key) const
- throw()
{
unsigned char mac[32];
unsigned char key2[32];
- if (_l < ZT_PACKET_IDX_VERB)
+ if (size() < ZT_PACKET_IDX_VERB)
return false; // incomplete packets fail
_mangleKey((const unsigned char *)key,key2);
- HMAC::sha256(key2,sizeof(key2),_b + ZT_PACKET_IDX_VERB,_l - ZT_PACKET_IDX_VERB,mac);
- return (!memcmp(_b + ZT_PACKET_IDX_HMAC,mac,8));
+ unsigned int hmacLen = size() - ZT_PACKET_IDX_VERB;
+ HMAC::sha256(key2,sizeof(key2),field(ZT_PACKET_IDX_VERB,hmacLen),hmacLen,mac);
+ return (!memcmp(field(ZT_PACKET_IDX_HMAC,8),mac,8));
}
/**
@@ -689,13 +695,16 @@ public:
* @param key 256-bit (32 byte) key
*/
inline void encrypt(const void *key)
- throw()
{
- _b[ZT_PACKET_IDX_FLAGS] |= ZT_PROTO_FLAG_ENCRYPTED;
+ (*this)[ZT_PACKET_IDX_FLAGS] |= ZT_PROTO_FLAG_ENCRYPTED;
unsigned char key2[32];
- _mangleKey((const unsigned char *)key,key2);
- Salsa20 s20(key2,256,_b + ZT_PACKET_IDX_IV);
- s20.encrypt(_b + ZT_PACKET_IDX_VERB,_b + ZT_PACKET_IDX_VERB,(_l >= ZT_PACKET_IDX_VERB) ? (_l - ZT_PACKET_IDX_VERB) : 0);
+ if (size() >= ZT_PACKET_IDX_VERB) {
+ _mangleKey((const unsigned char *)key,key2);
+ Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
+ unsigned int encLen = size() - ZT_PACKET_IDX_VERB;
+ unsigned char *const encBuf = field(ZT_PACKET_IDX_VERB,encLen);
+ s20.encrypt(encBuf,encBuf,encLen);
+ }
}
/**
@@ -704,13 +713,16 @@ public:
* @param key 256-bit (32 byte) key
*/
inline void decrypt(const void *key)
- throw()
{
unsigned char key2[32];
- _mangleKey((const unsigned char *)key,key2);
- Salsa20 s20(key2,256,_b + ZT_PACKET_IDX_IV);
- s20.decrypt(_b + ZT_PACKET_IDX_VERB,_b + ZT_PACKET_IDX_VERB,(_l >= ZT_PACKET_IDX_VERB) ? (_l - ZT_PACKET_IDX_VERB) : 0);
- _b[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
+ if (size() >= ZT_PACKET_IDX_VERB) {
+ _mangleKey((const unsigned char *)key,key2);
+ Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
+ unsigned int decLen = size() - ZT_PACKET_IDX_VERB;
+ unsigned char *const decBuf = field(ZT_PACKET_IDX_VERB,decLen);
+ s20.decrypt(decBuf,decBuf,decLen);
+ }
+ (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
}
/**
@@ -724,20 +736,19 @@ public:
* @return True if compression occurred
*/
inline bool compress()
- throw()
{
unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2];
- if ((!compressed())&&(_l > (ZT_PACKET_IDX_PAYLOAD + 32))) {
- int pl = (int)(_l - ZT_PACKET_IDX_PAYLOAD);
- int cl = LZ4_compress((const char *)(_b + ZT_PACKET_IDX_PAYLOAD),(char *)buf,pl);
+ if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 32))) {
+ int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD);
+ int cl = LZ4_compress((const char *)field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)pl),(char *)buf,pl);
if ((cl > 0)&&(cl < pl)) {
- _b[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED;
- memcpy(_b + ZT_PACKET_IDX_PAYLOAD,buf,cl);
- _l = (unsigned int)cl + ZT_PACKET_IDX_PAYLOAD;
+ (*this)[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED;
+ setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD);
+ memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)cl),buf,cl);
return true;
}
}
- _b[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
+ (*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
return false;
}
@@ -750,18 +761,18 @@ public:
* @return True if data is now decompressed and valid, false on error
*/
inline bool uncompress()
- throw()
{
unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH];
- if ((compressed())&&(_l >= ZT_PROTO_MIN_PACKET_LENGTH)) {
- if (_l > ZT_PACKET_IDX_PAYLOAD) {
- int ucl = LZ4_uncompress_unknownOutputSize((const char *)(_b + ZT_PACKET_IDX_PAYLOAD),(char *)buf,_l - ZT_PACKET_IDX_PAYLOAD,sizeof(buf));
+ if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) {
+ if (size() > ZT_PACKET_IDX_PAYLOAD) {
+ unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD;
+ int ucl = LZ4_uncompress_unknownOutputSize((const char *)field(ZT_PACKET_IDX_PAYLOAD,compLen),(char *)buf,compLen,sizeof(buf));
if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) {
- memcpy(_b + ZT_PACKET_IDX_PAYLOAD,buf,ucl);
- _l = (unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD;
+ setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD);
+ memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)ucl),buf,ucl);
} else return false;
}
- _b[ZT_PACKET_IDX_VERB] &= ~ZT_PROTO_VERB_FLAG_COMPRESSED;
+ (*this)[ZT_PACKET_IDX_VERB] &= ~ZT_PROTO_VERB_FLAG_COMPRESSED;
}
return true;
}
@@ -788,19 +799,18 @@ private:
* @param out Output buffer (32 bytes)
*/
inline void _mangleKey(const unsigned char *in,unsigned char *out) const
- throw()
{
// Random IV (Salsa20 also uses the IV natively, but HMAC doesn't), and
// destination and source addresses. Using dest and source addresses
// gives us a (likely) different key space for a->b vs b->a.
for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
- out[i] = in[i] ^ (unsigned char)_b[i];
+ out[i] = in[i] ^ (unsigned char)(*this)[i];
// Flags, but masking off hop count which is altered by forwarding nodes
- out[18] = in[18] ^ ((unsigned char)_b[ZT_PACKET_IDX_FLAGS] & 0xf8);
+ out[18] = in[18] ^ ((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & 0xf8);
// Raw packet size in bytes -- each raw packet size defines a possibly
// different space of keys.
- out[19] = in[19] ^ (unsigned char)(_l & 0xff);
- out[20] = in[20] ^ (unsigned char)((_l >> 8) & 0xff); // little endian
+ out[19] = in[19] ^ (unsigned char)(size() & 0xff);
+ out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian
// Rest of raw key is used unchanged
for(unsigned int i=21;i<32;++i)
out[i] = in[i];
diff --git a/node/Salsa20.cpp b/node/Salsa20.cpp
index 802f82e9..d80ea28d 100644
--- a/node/Salsa20.cpp
+++ b/node/Salsa20.cpp
@@ -5,6 +5,7 @@
*/
#include "Salsa20.hpp"
+#include "Constants.hpp"
#define ROTATE(v,c) (((v) << (c)) | ((v) >> (32 - (c))))
#define XOR(v,w) ((v) ^ (w))