diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/Buffer.hpp | 2 | ||||
-rw-r--r-- | node/Constants.hpp | 79 | ||||
-rw-r--r-- | node/EthernetTap.cpp | 562 | ||||
-rw-r--r-- | node/EthernetTap.hpp | 70 | ||||
-rw-r--r-- | node/Network.cpp | 38 | ||||
-rw-r--r-- | node/Network.hpp | 14 | ||||
-rw-r--r-- | node/Packet.hpp | 164 | ||||
-rw-r--r-- | node/Salsa20.cpp | 1 |
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 ðerType,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 ðerType,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 ðerType,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)) |