summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-07-09 14:06:55 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-07-09 14:06:55 -0400
commitef3e319c64600a921c9d6b33391f026644ec2492 (patch)
treeb2781949894625ebfae9d5c5f2dceb7cd1c4b395 /node
parent41cd980bf72b9b22636dff91a1f6067a8474c819 (diff)
downloadinfinitytier-ef3e319c64600a921c9d6b33391f026644ec2492.tar.gz
infinitytier-ef3e319c64600a921c9d6b33391f026644ec2492.zip
Several things:
(1) Probable fix for issue #7 and major cleanup of EthernetTap code with consolidation for all unix-like systems and specialization for different flavors only when needed. (2) Refactor of Buffer<> to make its members private, and Packet to use Buffer's methods exclusively to access them. This improves clarity and means we're no longer lying about Buffer's role in the code's security posture. (3) Add -fstack-protect to Makefile to bounds check stack variables.
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))