clang-format

This commit is contained in:
Adam Ierymenko 2025-07-03 11:26:23 -04:00
parent d45f280cb7
commit ba2a4a605c
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
140 changed files with 19214 additions and 17403 deletions

View file

@ -11,29 +11,28 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Arp.hpp"
#include "OSUtils.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
namespace ZeroTier {
static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x01 };
static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x02 };
static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01 };
static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02 };
Arp::Arp() :
_cache(256),
_lastCleaned(OSUtils::now())
Arp::Arp() : _cache(256), _lastCleaned(OSUtils::now())
{
}
void Arp::addLocal(uint32_t ip,const MAC &mac)
void Arp::addLocal(uint32_t ip, const MAC& mac)
{
_ArpEntry &e = _cache[ip];
e.lastQuerySent = 0; // local IP
e.lastResponseReceived = 0; // local IP
_ArpEntry& e = _cache[ip];
e.lastQuerySent = 0; // local IP
e.lastResponseReceived = 0; // local IP
e.mac = mac;
e.local = true;
}
@ -43,7 +42,7 @@ void Arp::remove(uint32_t ip)
_cache.erase(ip);
}
uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest)
uint32_t Arp::processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest)
{
const uint64_t now = OSUtils::now();
uint32_t ip = 0;
@ -52,25 +51,26 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
responseDest.zero();
if (len >= 28) {
if (!memcmp(arp,ARP_REQUEST_HEADER,8)) {
if (! memcmp(arp, ARP_REQUEST_HEADER, 8)) {
// Respond to ARP requests for locally-known IPs
_ArpEntry *targetEntry = _cache.get(reinterpret_cast<const uint32_t *>(arp)[6]);
if ((targetEntry)&&(targetEntry->local)) {
memcpy(response,ARP_RESPONSE_HEADER,8);
targetEntry->mac.copyTo(reinterpret_cast<uint8_t *>(response) + 8,6);
memcpy(reinterpret_cast<uint8_t *>(response) + 14,reinterpret_cast<const uint8_t *>(arp) + 24,4);
memcpy(reinterpret_cast<uint8_t *>(response) + 18,reinterpret_cast<const uint8_t *>(arp) + 8,10);
_ArpEntry* targetEntry = _cache.get(reinterpret_cast<const uint32_t*>(arp)[6]);
if ((targetEntry) && (targetEntry->local)) {
memcpy(response, ARP_RESPONSE_HEADER, 8);
targetEntry->mac.copyTo(reinterpret_cast<uint8_t*>(response) + 8, 6);
memcpy(reinterpret_cast<uint8_t*>(response) + 14, reinterpret_cast<const uint8_t*>(arp) + 24, 4);
memcpy(reinterpret_cast<uint8_t*>(response) + 18, reinterpret_cast<const uint8_t*>(arp) + 8, 10);
responseLen = 28;
responseDest.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6);
responseDest.setTo(reinterpret_cast<const uint8_t*>(arp) + 8, 6);
}
} else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) {
}
else if (! memcmp(arp, ARP_RESPONSE_HEADER, 8)) {
// Learn cache entries for remote IPs from relevant ARP replies
uint32_t responseIp = 0;
memcpy(&responseIp,reinterpret_cast<const uint8_t *>(arp) + 14,4);
_ArpEntry *queryEntry = _cache.get(responseIp);
if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
memcpy(&responseIp, reinterpret_cast<const uint8_t*>(arp) + 14, 4);
_ArpEntry* queryEntry = _cache.get(responseIp);
if ((queryEntry) && (! queryEntry->local) && ((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
queryEntry->lastResponseReceived = now;
queryEntry->mac.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6);
queryEntry->mac.setTo(reinterpret_cast<const uint8_t*>(arp) + 8, 6);
ip = responseIp;
}
}
@ -78,11 +78,11 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) {
_lastCleaned = now;
Hashtable< uint32_t,_ArpEntry >::Iterator i(_cache);
uint32_t *k = (uint32_t *)0;
_ArpEntry *v = (_ArpEntry *)0;
while (i.next(k,v)) {
if ((!v->local)&&((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE))
Hashtable<uint32_t, _ArpEntry>::Iterator i(_cache);
uint32_t* k = (uint32_t*)0;
_ArpEntry* v = (_ArpEntry*)0;
while (i.next(k, v)) {
if ((! v->local) && ((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE))
_cache.erase(*k);
}
}
@ -90,27 +90,32 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
return ip;
}
MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest)
MAC Arp::query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest)
{
const uint64_t now = OSUtils::now();
_ArpEntry &e = _cache[targetIp];
_ArpEntry& e = _cache[targetIp];
if ( ((e.mac)&&((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) ||
((!e.mac)&&((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL)) ) {
if (((e.mac) && ((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || ((! e.mac) && ((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL))) {
e.lastQuerySent = now;
uint8_t *q = reinterpret_cast<uint8_t *>(query);
memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same
localMac.copyTo(q,6); q += 6; // sending host MAC address
memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order)
memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find
memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order)
uint8_t* q = reinterpret_cast<uint8_t*>(query);
memcpy(q, ARP_REQUEST_HEADER, 8);
q += 8; // ARP request header information, always the same
localMac.copyTo(q, 6);
q += 6; // sending host MAC address
memcpy(q, &localIp, 4);
q += 4; // sending host IP (IP already in big-endian byte order)
memset(q, 0, 6);
q += 6; // sending zeros for target MAC address as thats what we want to find
memcpy(q, &targetIp, 4); // target IP address for resolution (IP already in big-endian byte order)
queryLen = 28;
if (e.mac)
queryDest = e.mac; // confirmation query, send directly to address holder
else queryDest = (uint64_t)0xffffffffffffULL; // broadcast query
} else {
queryDest = e.mac; // confirmation query, send directly to address holder
else
queryDest = (uint64_t)0xffffffffffffULL; // broadcast query
}
else {
queryLen = 0;
queryDest.zero();
}
@ -118,4 +123,4 @@ MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *quer
return e.mac;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,14 +14,13 @@
#ifndef ZT_ARP_HPP
#define ZT_ARP_HPP
#include <stdint.h>
#include <utility>
#include "../node/Constants.hpp"
#include "../node/Hashtable.hpp"
#include "../node/MAC.hpp"
#include <stdint.h>
#include <utility>
/**
* Maximum possible ARP length
*
@ -67,9 +66,8 @@ namespace ZeroTier {
* This class is not thread-safe and must be guarded if used in multi-threaded
* code.
*/
class Arp
{
public:
class Arp {
public:
Arp();
/**
@ -78,7 +76,7 @@ public:
* @param mac Our local MAC address
* @param ip IP in big-endian byte order (sin_addr.s_addr)
*/
void addLocal(uint32_t ip,const MAC &mac);
void addLocal(uint32_t ip, const MAC& mac);
/**
* Delete a local IP entry or a cached ARP entry
@ -103,7 +101,7 @@ public:
* @param responseDest Destination of response, or set to null if no response
* @return IP address learned or 0 if no new IPs in cache
*/
uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest);
uint32_t processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest);
/**
* Get the MAC corresponding to an IP, generating a query if needed
@ -115,29 +113,30 @@ public:
* MAC returned is non-null.
*
* @param localMac Local MAC address of host interface
* @param localIp Local IP address of host interface
* @param localIp Local IP address of host interface
* @param targetIp IP to look up
* @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size
* @param queryLen Length of generated query, or set to 0 if no query generated
* @param queryDest Destination of query, or set to null if no query generated
* @return MAC or 0 if no cached entry for this IP
*/
MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest);
MAC query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest);
private:
struct _ArpEntry
{
_ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {}
uint64_t lastQuerySent; // Time last query was sent or 0 for local IP
uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP
MAC mac; // MAC address of device responsible for IP or null if not known yet
bool local; // True if this is a local ARP entry
private:
struct _ArpEntry {
_ArpEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false)
{
}
uint64_t lastQuerySent; // Time last query was sent or 0 for local IP
uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP
MAC mac; // MAC address of device responsible for IP or null if not known yet
bool local; // True if this is a local ARP entry
};
Hashtable< uint32_t,_ArpEntry > _cache;
Hashtable<uint32_t, _ArpEntry> _cache;
uint64_t _lastCleaned;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,81 +11,78 @@
*/
/****/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "BSDEthernetTap.hpp"
#include <unistd.h>
#include <signal.h>
#include "../node/Constants.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <algorithm>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <map>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/route.h>
#include <netinet/in.h>
#include <pthread_np.h>
#include <sched.h>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <utility>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "OSUtils.hpp"
#include "BSDEthernetTap.hpp"
#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv"
#define ZT_TAP_BUF_SIZE (1024 * 16)
// ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
namespace ZeroTier {
BSDEthernetTap::BSDEthernetTap(
const char *homePath,
const char* homePath,
unsigned int concurrency,
bool pinning,
const MAC &mac,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg) :
_handler(handler),
_concurrency(concurrency),
_pinning(pinning),
_arg(arg),
_nwid(nwid),
_mtu(mtu),
_metric(metric),
_fd(0),
_enabled(true),
_lastIfAddrsUpdate(0)
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg)
: _handler(handler)
, _concurrency(concurrency)
, _pinning(pinning)
, _arg(arg)
, _nwid(nwid)
, _mtu(mtu)
, _metric(metric)
, _fd(0)
, _enabled(true)
, _lastIfAddrsUpdate(0)
{
static Mutex globalTapCreateLock;
char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32];
char devpath[64], ethaddr[64], mtustr[32], metstr[32], tmpdevname[32];
Mutex::Lock _gl(globalTapCreateLock);
@ -108,43 +105,51 @@ BSDEthernetTap::BSDEthernetTap(
_dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]);
std::vector<std::string> devFiles(OSUtils::listDirectory("/dev"));
for(int i=9993;i<(9993+128);++i) {
OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) {
for (int i = 9993; i < (9993 + 128); ++i) {
OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i);
OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname);
if (std::find(devFiles.begin(), devFiles.end(), std::string(tmpdevname)) == devFiles.end()) {
long cpid = (long)vfork();
if (cpid == 0) {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s create" ZT_EOL_S, tmpdevname);
#endif
::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "create", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
} else throw std::runtime_error("fork() failed");
::waitpid(cpid, &exitcode, 0);
}
else
throw std::runtime_error("fork() failed");
struct stat stattmp;
if (!stat(devpath,&stattmp)) {
if (! stat(devpath, &stattmp)) {
cpid = (long)vfork();
if (cpid == 0) {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s name %s" ZT_EOL_S, tmpdevname, _dev.c_str());
#endif
::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "name", _dev.c_str(), (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
if (exitcode)
throw std::runtime_error("ifconfig rename operation failed");
} else throw std::runtime_error("fork() failed");
}
else
throw std::runtime_error("fork() failed");
_fd = ::open(devpath,O_RDWR);
_fd = ::open(devpath, O_RDWR);
if (_fd > 0)
break;
else throw std::runtime_error("unable to open created tap device");
} else {
else
throw std::runtime_error("unable to open created tap device");
}
else {
throw std::runtime_error("cannot find /dev node for newly created tap device");
}
}
@ -152,10 +157,10 @@ BSDEthernetTap::BSDEthernetTap(
#else
/* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */
for(int i=0;i<64;++i) {
OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
_fd = ::open(devpath,O_RDWR);
for (int i = 0; i < 64; ++i) {
OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i);
OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname);
_fd = ::open(devpath, O_RDWR);
if (_fd > 0) {
_dev = tmpdevname;
break;
@ -166,25 +171,26 @@ BSDEthernetTap::BSDEthernetTap(
if (_fd <= 0)
throw std::runtime_error("unable to open TAP device or no more devices available");
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) {
::close(_fd);
throw std::runtime_error("unable to set flags on file descriptor for TAP device");
}
// Configure MAC address and MTU, bring interface up
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]);
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu);
OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric);
OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", _mtu);
OSUtils::ztsnprintf(metstr, sizeof(metstr), "%u", _metric);
long cpid = (long)vfork();
if (cpid == 0) {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s lladdr %s mtu %s metric %s up" ZT_EOL_S, _dev.c_str(), ethaddr, mtustr, metstr);
#endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "lladdr", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
if (exitcode) {
::close(_fd);
throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
@ -192,7 +198,7 @@ BSDEthernetTap::BSDEthernetTap(
}
// Set close-on-exec so that devices cannot persist if we fork/exec for update
fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
::pipe(_shutdownSignalPipe);
@ -201,23 +207,24 @@ BSDEthernetTap::BSDEthernetTap(
BSDEthernetTap::~BSDEthernetTap()
{
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
::close(_fd);
::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]);
long cpid = (long)vfork();
if (cpid == 0) {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str());
fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str());
#endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "destroy", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
}
Thread::join(_thread);
for (std::thread &t : _rxThreads) {
for (std::thread& t : _rxThreads) {
t.join();
}
}
@ -232,7 +239,7 @@ bool BSDEthernetTap::enabled() const
return _enabled;
}
static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
static bool ___removeIp(const std::string& _dev, const InetAddress& ip)
{
long cpid = (long)vfork();
if (cpid == 0) {
@ -240,29 +247,30 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s inet %s -alias" ZT_EOL_S, _dev.c_str(), ip.toIpString(ipbuf));
#endif
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString(ipbuf),"-alias",(const char *)0);
execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "inet", ip.toIpString(ipbuf), "-alias", (const char*)0);
_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
waitpid(cpid, &exitcode, 0);
return (exitcode == 0);
}
return false; // never reached, make compiler shut up about return value
return false; // never reached, make compiler shut up about return value
}
bool BSDEthernetTap::addIp(const InetAddress &ip)
bool BSDEthernetTap::addIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return false;
std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end())
return true; // IP/netmask already assigned
if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end())
return true; // IP/netmask already assigned
// Remove and reconfigure if address is the same but netmask is different
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
if (___removeIp(_dev,*i))
for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if ((i->ipsEqual(ip)) && (i->netmaskBits() != ip.netmaskBits())) {
if (___removeIp(_dev, *i))
break;
}
}
@ -273,23 +281,24 @@ bool BSDEthernetTap::addIp(const InetAddress &ip)
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s %s %s alias" ZT_EOL_S, _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp));
#endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString(tmp),"alias",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp), "alias", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
return (exitcode == 0);
}
return false;
}
bool BSDEthernetTap::removeIp(const InetAddress &ip)
bool BSDEthernetTap::removeIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return false;
std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) {
if (___removeIp(_dev,ip))
if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) {
if (___removeIp(_dev, ip))
return true;
}
return false;
@ -304,28 +313,28 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
}
_lastIfAddrsUpdate = now;
struct ifaddrs *ifa = (struct ifaddrs *)0;
struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa))
return std::vector<InetAddress>();
std::vector<InetAddress> r;
struct ifaddrs *p = ifa;
struct ifaddrs* p = ifa;
while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) {
if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch (p->ifa_addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
}
}
p = p->ifa_next;
@ -334,24 +343,24 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
if (ifa)
freeifaddrs(ifa);
std::sort(r.begin(),r.end());
std::unique(r.begin(),r.end());
std::sort(r.begin(), r.end());
std::unique(r.begin(), r.end());
_ifaddrs = r;
return r;
}
void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
void BSDEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{
char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len);
if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6, 6);
*((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14, data, len);
len += 14;
::write(_fd,putBuf,len);
::write(_fd, putBuf, len);
}
}
@ -360,44 +369,44 @@ std::string BSDEthernetTap::deviceName() const
return _dev;
}
void BSDEthernetTap::setFriendlyName(const char *friendlyName)
void BSDEthernetTap::setFriendlyName(const char* friendlyName)
{
}
void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{
std::vector<MulticastGroup> newGroups;
#ifndef __OpenBSD__
struct ifmaddrs *ifmap = (struct ifmaddrs *)0;
if (!getifmaddrs(&ifmap)) {
struct ifmaddrs *p = ifmap;
struct ifmaddrs* ifmap = (struct ifmaddrs*)0;
if (! getifmaddrs(&ifmap)) {
struct ifmaddrs* p = ifmap;
while (p) {
if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
}
p = p->ifma_next;
}
freeifmaddrs(ifmap);
}
#endif // __OpenBSD__
#endif // __OpenBSD__
std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end());
std::unique(newGroups.begin(),newGroups.end());
std::sort(newGroups.begin(), newGroups.end());
std::unique(newGroups.begin(), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m);
}
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m);
}
@ -411,21 +420,21 @@ void BSDEthernetTap::setMtu(unsigned int mtu)
long cpid = (long)vfork();
if (cpid == 0) {
char tmp[64];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu);
OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu);
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s mtu %s" ZT_EOL_S, _dev.c_str(), tmp);
#endif
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0);
execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "mtu", tmp, (const char*)0);
_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
waitpid(cpid, &exitcode, 0);
}
}
}
void BSDEthernetTap::threadMain()
throw()
void BSDEthernetTap::threadMain() throw()
{
// Wait for a moment after startup -- wait for Network to finish
// constructing itself.
@ -436,7 +445,6 @@ void BSDEthernetTap::threadMain()
for (unsigned int i = 0; i < _concurrency; ++i) {
_rxThreads.push_back(std::thread([this, i, pinning] {
if (pinning) {
int pinCore = i % _concurrency;
fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore);
@ -444,15 +452,14 @@ void BSDEthernetTap::threadMain()
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(pinCore, &cpuset);
//int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset);
// int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset);
int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
if (rc != 0)
{
if (rc != 0) {
fprintf(stderr, "Failed to pin thread %d to core %d: %s\n", i, pinCore, strerror(errno));
exit(1);
}
}
#endif // __OpenBSD__
#endif // __OpenBSD__
uint8_t b[ZT_TAP_BUF_SIZE];
MAC to, from;
@ -461,37 +468,38 @@ void BSDEthernetTap::threadMain()
FD_ZERO(&readfds);
FD_ZERO(&nullfds);
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1;
r = 0;
for(;;) {
FD_SET(_shutdownSignalPipe[0],&readfds);
FD_SET(_fd,&readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
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
if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread
break;
if (FD_ISSET(_fd,&readfds)) {
n = (int)::read(_fd,b + r,sizeof(b) - r);
if (FD_ISSET(_fd, &readfds)) {
n = (int)::read(_fd, b + r, sizeof(b) - r);
if (n < 0) {
if ((errno != EINTR)&&(errno != ETIMEDOUT))
if ((errno != EINTR) && (errno != ETIMEDOUT))
break;
} else {
}
else {
// Some tap drivers like to send the ethernet frame and the
// payload in two chunks, so handle that by accumulating
// data until we have at least a frame.
r += n;
if (r > 14) {
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
r = _mtu + 14;
if (_enabled) {
to.setTo(b,6);
from.setTo(b + 6,6);
unsigned int etherType = ntohs(((const uint16_t *)b)[6]);
_handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(b + 14),r - 14);
to.setTo(b, 6);
from.setTo(b + 6, 6);
unsigned int etherType = ntohs(((const uint16_t*)b)[6]);
_handler(_arg, (void*)0, _nwid, from, to, etherType, 0, (const void*)(b + 14), r - 14);
}
r = 0;
@ -502,7 +510,7 @@ void BSDEthernetTap::threadMain()
#ifndef __OpenBSD__
}));
}
#endif // __OpenBSD__
#endif // __OpenBSD__
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,57 +14,56 @@
#ifndef ZT_BSDETHERNETTAP_HPP
#define ZT_BSDETHERNETTAP_HPP
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "Thread.hpp"
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <stdexcept>
#include <thread>
#include "../node/Constants.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/MAC.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp"
#include <vector>
namespace ZeroTier {
class BSDEthernetTap : public EthernetTap
{
public:
class BSDEthernetTap : public EthernetTap {
public:
BSDEthernetTap(
const char *homePath,
const char* homePath,
unsigned int concurrency,
bool pinning,
const MAC &mac,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg);
virtual ~BSDEthernetTap();
virtual void setEnabled(bool en);
virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip);
virtual bool removeIp(const InetAddress &ip);
virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) {}
virtual void setDns(const char* domain, const std::vector<InetAddress>& servers)
{
}
void threadMain()
throw();
void threadMain() throw();
private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
void *_arg;
private:
void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void* _arg;
unsigned int _concurrency;
bool _pinning;
uint64_t _nwid;
@ -81,6 +80,6 @@ private:
std::vector<std::thread> _rxThreads;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -22,11 +22,11 @@
#include <string.h>
#ifdef __WINDOWS__
#include <shlobj.h>
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
#include <netioapi.h>
#include <shlobj.h>
#include <windows.h>
#include <winsock2.h>
#else
#include <ifaddrs.h>
#include <sys/socket.h>
@ -34,13 +34,13 @@
#include <sys/wait.h>
#include <unistd.h>
#ifdef __LINUX__
#include <linux/if_addr.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_addr.h>
#endif
#endif
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK)
#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
#include <net/if.h>
#if TARGET_OS_OSX
#include <netinet6/in6_var.h>
@ -131,7 +131,7 @@ class Binder {
template <typename PHY_HANDLER_TYPE, typename INTERFACE_CHECKER> void refresh(Phy<PHY_HANDLER_TYPE>& phy, unsigned int* ports, unsigned int portCount, const std::vector<InetAddress> explicitBind, INTERFACE_CHECKER& ifChecker)
{
std::map<InetAddress, std::string> localIfAddrs;
PhySocket *udps;
PhySocket* udps;
Mutex::Lock _l(_lock);
bool interfacesEnumerated = true;
@ -232,7 +232,7 @@ class Binder {
}
}
if ( (flags & IFA_F_TEMPORARY) != 0) {
if ((flags & IFA_F_TEMPORARY) != 0) {
continue;
}
if (devname) {
@ -318,11 +318,11 @@ class Binder {
//
(void)gotViaProc;
#if ! defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android
#if ! defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android
if (! gotViaProc) {
struct ifaddrs* ifatbl = (struct ifaddrs*)0;
struct ifaddrs* ifa;
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK)
#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
// set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6
int infoSock = socket(AF_INET6, SOCK_DGRAM, 0);
#endif
@ -331,7 +331,7 @@ class Binder {
while (ifa) {
if ((ifa->ifa_name) && (ifa->ifa_addr)) {
InetAddress ip = *(ifa->ifa_addr);
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) && TARGET_OS_OSX
#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK) && TARGET_OS_OSX
// Check if the address is an IPv6 Temporary Address, macOS/BSD version
if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr;
@ -379,7 +379,7 @@ class Binder {
else {
interfacesEnumerated = false;
}
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK)
#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
close(infoSock);
#endif
}

View file

@ -14,11 +14,11 @@
#ifndef ZT_BLOCKINGQUEUE_HPP
#define ZT_BLOCKINGQUEUE_HPP
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <vector>
namespace ZeroTier {
@ -28,11 +28,11 @@ namespace ZeroTier {
*
* Do not use in node/ since we have not gone C++11 there yet.
*/
template <class T>
class BlockingQueue
{
public:
BlockingQueue(void) : r(true) {}
template <class T> class BlockingQueue {
public:
BlockingQueue(void) : r(true)
{
}
inline void post(T t)
{
@ -41,16 +41,16 @@ public:
c.notify_one();
}
inline void postLimit(T t,const unsigned long limit)
inline void postLimit(T t, const unsigned long limit)
{
std::unique_lock<std::mutex> lock(m);
for(;;) {
for (;;) {
if (q.size() < limit) {
q.push(t);
c.notify_one();
break;
}
if (!r)
if (! r)
break;
gc.wait(lock);
}
@ -64,14 +64,14 @@ public:
gc.notify_all();
}
inline bool get(T &value)
inline bool get(T& value)
{
std::unique_lock<std::mutex> lock(m);
if (!r)
if (! r)
return false;
while (q.empty()) {
c.wait(lock);
if (!r) {
if (! r) {
gc.notify_all();
return false;
}
@ -85,30 +85,25 @@ public:
inline std::vector<T> drain()
{
std::vector<T> v;
while (!q.empty()) {
while (! q.empty()) {
v.push_back(q.front());
q.pop();
}
return v;
}
enum TimedWaitResult
{
OK,
TIMED_OUT,
STOP
};
enum TimedWaitResult { OK, TIMED_OUT, STOP };
inline TimedWaitResult get(T &value,const unsigned long ms)
inline TimedWaitResult get(T& value, const unsigned long ms)
{
const std::chrono::milliseconds ms2{ms};
const std::chrono::milliseconds ms2 { ms };
std::unique_lock<std::mutex> lock(m);
if (!r)
if (! r)
return STOP;
while (q.empty()) {
if (c.wait_for(lock,ms2) == std::cv_status::timeout)
if (c.wait_for(lock, ms2) == std::cv_status::timeout)
return ((r) ? TIMED_OUT : STOP);
else if (!r)
else if (! r)
return STOP;
}
value = q.front();
@ -116,17 +111,18 @@ public:
return OK;
}
inline size_t size() const {
inline size_t size() const
{
return q.size();
}
private:
private:
std::queue<T> q;
mutable std::mutex m;
mutable std::condition_variable c,gc;
mutable std::condition_variable c, gc;
std::atomic_bool r;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,6 +12,7 @@
/****/
#include "EthernetTap.hpp"
#include "OSUtils.hpp"
#include <stdlib.h>
@ -20,82 +21,83 @@
#ifdef ZT_SDK
#include "../controller/EmbeddedNetworkController.hpp"
#include "../node/Node.hpp"
#include "../include/VirtualTap.hpp"
#include "../node/Node.hpp"
#else
#ifdef __APPLE__
#include <sys/sysctl.h>
#include "MacEthernetTap.hpp"
#include "MacKextEthernetTap.hpp"
#endif // __APPLE__
#include <sys/sysctl.h>
#endif // __APPLE__
#ifdef __LINUX__
#include "LinuxEthernetTap.hpp"
#endif // __LINUX__
#endif // __LINUX__
#ifdef __WINDOWS__
#include "WindowsEthernetTap.hpp"
#endif // __WINDOWS__
#endif // __WINDOWS__
#ifdef __FreeBSD__
#include "BSDEthernetTap.hpp"
#endif // __FreeBSD__
#endif // __FreeBSD__
#ifdef __NetBSD__
#include "NetBSDEthernetTap.hpp"
#endif // __NetBSD__
#endif // __NetBSD__
#ifdef __OpenBSD__
#include "BSDEthernetTap.hpp"
#endif // __OpenBSD__
#endif // __OpenBSD__
#endif
namespace ZeroTier {
std::shared_ptr<EthernetTap> EthernetTap::newInstance(
const char *tapDeviceType, // OS-specific, NULL for default
const char* tapDeviceType, // OS-specific, NULL for default
unsigned int concurrency,
bool pinning,
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg)
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg)
{
#ifdef ZT_SDK
return std::shared_ptr<EthernetTap>(new VirtualTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg));
return std::shared_ptr<EthernetTap>(new VirtualTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#else // not ZT_SDK
#else // not ZT_SDK
#ifdef __APPLE__
char osrelease[256];
size_t size = sizeof(osrelease);
if (sysctlbyname("kern.osrelease",osrelease,&size,nullptr,0) == 0) {
char *dotAt = strchr(osrelease,'.');
if (sysctlbyname("kern.osrelease", osrelease, &size, nullptr, 0) == 0) {
char* dotAt = strchr(osrelease, '.');
if (dotAt) {
*dotAt = (char)0;
// The "feth" virtual Ethernet device type appeared in Darwin 17.x.x. Older versions
// (Sierra and earlier) must use the a kernel extension.
if (strtol(osrelease,(char **)0,10) < 17) {
return std::shared_ptr<EthernetTap>(new MacKextEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg));
} else {
return std::shared_ptr<EthernetTap>(new MacEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg));
if (strtol(osrelease, (char**)0, 10) < 17) {
return std::shared_ptr<EthernetTap>(new MacKextEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
}
else {
return std::shared_ptr<EthernetTap>(new MacEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
}
}
}
#endif // __APPLE__
#endif // __APPLE__
#ifdef __LINUX__
return std::shared_ptr<EthernetTap>(new LinuxEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg));
#endif // __LINUX__
return std::shared_ptr<EthernetTap>(new LinuxEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __LINUX__
#ifdef __WINDOWS__
HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED);
@ -108,18 +110,8 @@ std::shared_ptr<EthernetTap> EthernetTap::newInstance(
{
Mutex::Lock l(_comInit_m);
if (!_comInit) {
hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
if (! _comInit) {
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (FAILED(hres)) {
CoUninitialize();
fprintf(stderr, "WinEthernetTap: Failed to initialize security");
@ -128,33 +120,37 @@ std::shared_ptr<EthernetTap> EthernetTap::newInstance(
_comInit = true;
}
}
return std::shared_ptr<EthernetTap>(new WindowsEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg));
#endif // __WINDOWS__
return std::shared_ptr<EthernetTap>(new WindowsEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __WINDOWS__
#ifdef __FreeBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg));
#endif // __FreeBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __FreeBSD__
#ifdef __NetBSD__
return std::shared_ptr<EthernetTap>(new NetBSDEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg));
#endif // __NetBSD__
return std::shared_ptr<EthernetTap>(new NetBSDEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __NetBSD__
#ifdef __OpenBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg));
#endif // __OpenBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __OpenBSD__
#endif // ZT_SDK?
#endif // ZT_SDK?
return std::shared_ptr<EthernetTap>();
}
EthernetTap::EthernetTap() {}
EthernetTap::~EthernetTap() {}
EthernetTap::EthernetTap()
{
}
EthernetTap::~EthernetTap()
{
}
bool EthernetTap::addIps(std::vector<InetAddress> ips)
{
for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) {
if (!addIp(*i))
for (std::vector<InetAddress>::const_iterator i(ips.begin()); i != ips.end(); ++i) {
if (! addIp(*i))
return false;
}
return true;
@ -166,4 +162,4 @@ std::string EthernetTap::friendlyName() const
return std::string();
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -15,52 +15,51 @@
#define ZT_ETHERNETTAP_HPP
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include <string>
#include <memory>
#include <string>
#include <vector>
#define GETIFADDRS_CACHE_TIME 1000
namespace ZeroTier {
class EthernetTap
{
public:
class EthernetTap {
public:
static std::shared_ptr<EthernetTap> newInstance(
const char *tapDeviceType, // OS-specific, NULL for default
const char* tapDeviceType, // OS-specific, NULL for default
unsigned int concurrency,
bool pinning,
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg);
EthernetTap();
virtual ~EthernetTap();
virtual void setEnabled(bool en) = 0;
virtual bool enabled() const = 0;
virtual bool addIp(const InetAddress &ip) = 0;
virtual bool addIps(std::vector<InetAddress> ips); // uses addIp() unless overridden
virtual bool removeIp(const InetAddress &ip) = 0;
virtual bool addIp(const InetAddress& ip) = 0;
virtual bool addIps(std::vector<InetAddress> ips); // uses addIp() unless overridden
virtual bool removeIp(const InetAddress& ip) = 0;
virtual std::vector<InetAddress> ips() const = 0;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0;
virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) = 0;
virtual std::string deviceName() const = 0;
virtual void setFriendlyName(const char *friendlyName) = 0;
virtual void setFriendlyName(const char* friendlyName) = 0;
virtual std::string friendlyName() const;
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) = 0;
virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed) = 0;
virtual void setMtu(unsigned int mtu) = 0;
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) = 0;
virtual void setDns(const char* domain, const std::vector<InetAddress>& servers) = 0;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,15 +11,16 @@
*/
/****/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "Http.hpp"
#include "Phy.hpp"
#include "OSUtils.hpp"
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include "Phy.hpp"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef ZT_USE_SYSTEM_HTTP_PARSER
#include <http_parser.h>
@ -31,90 +32,87 @@ namespace ZeroTier {
namespace {
static int ShttpOnMessageBegin(http_parser *parser);
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length);
static int ShttpOnMessageBegin(http_parser* parser);
static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length);
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length);
static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length);
#else
static int ShttpOnStatus(http_parser *parser);
static int ShttpOnStatus(http_parser* parser);
#endif
static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length);
static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length);
static int ShttpOnHeadersComplete(http_parser *parser);
static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length);
static int ShttpOnMessageComplete(http_parser *parser);
static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnHeadersComplete(http_parser* parser);
static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnMessageComplete(http_parser* parser);
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1)
static const struct http_parser_settings HTTP_PARSER_SETTINGS = {
ShttpOnMessageBegin,
ShttpOnUrl,
ShttpOnStatus,
ShttpOnHeaderField,
ShttpOnValue,
ShttpOnHeadersComplete,
ShttpOnBody,
ShttpOnMessageComplete
};
static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnStatus, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete };
#else
static const struct http_parser_settings HTTP_PARSER_SETTINGS = {
ShttpOnMessageBegin,
ShttpOnUrl,
ShttpOnHeaderField,
ShttpOnValue,
ShttpOnHeadersComplete,
ShttpOnBody,
ShttpOnMessageComplete
};
static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete };
#endif
struct HttpPhyHandler
{
struct HttpPhyHandler {
// not used
inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) {}
inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {}
inline void phyOnDatagram(PhySocket* sock, void** uptr, const struct sockaddr* localAddr, const struct sockaddr* from, void* data, unsigned long len)
{
}
inline void phyOnTcpAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN, const struct sockaddr* from)
{
}
inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
inline void phyOnTcpConnect(PhySocket* sock, void** uptr, bool success)
{
if (success) {
phy->setNotifyWritable(sock,true);
} else {
phy->setNotifyWritable(sock, true);
}
else {
*responseBody = "connection failed";
error = true;
done = true;
}
}
inline void phyOnTcpClose(PhySocket *sock,void **uptr)
inline void phyOnTcpClose(PhySocket* sock, void** uptr)
{
done = true;
}
inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
inline void phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len)
{
lastActivity = OSUtils::now();
http_parser_execute(&parser,&HTTP_PARSER_SETTINGS,(const char *)data,len);
if ((parser.upgrade)||(parser.http_errno != HPE_OK))
http_parser_execute(&parser, &HTTP_PARSER_SETTINGS, (const char*)data, len);
if ((parser.upgrade) || (parser.http_errno != HPE_OK))
phy->close(sock);
}
inline void phyOnTcpWritable(PhySocket *sock,void **uptr)
inline void phyOnTcpWritable(PhySocket* sock, void** uptr)
{
if (writePtr < (unsigned long)writeBuf.length()) {
long n = phy->streamSend(sock,writeBuf.data() + writePtr,(unsigned long)writeBuf.length() - writePtr,true);
long n = phy->streamSend(sock, writeBuf.data() + writePtr, (unsigned long)writeBuf.length() - writePtr, true);
if (n > 0)
writePtr += n;
}
if (writePtr >= (unsigned long)writeBuf.length())
phy->setNotifyWritable(sock,false);
phy->setNotifyWritable(sock, false);
}
inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {}
inline void phyOnFileDescriptorActivity(PhySocket* sock, void** uptr, bool readable, bool writable)
{
}
#ifdef __UNIX_LIKE__
inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {}
inline void phyOnUnixClose(PhySocket *sock,void **uptr) {}
inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {}
#endif // __UNIX_LIKE__
inline void phyOnUnixAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN)
{
}
inline void phyOnUnixClose(PhySocket* sock, void** uptr)
{
}
inline void phyOnUnixData(PhySocket* sock, void** uptr, void* data, unsigned long len)
{
}
inline void phyOnUnixWritable(PhySocket* sock, void** uptr)
{
}
#endif // __UNIX_LIKE__
http_parser parser;
std::string currentHeaderField;
@ -125,27 +123,27 @@ struct HttpPhyHandler
std::string writeBuf;
unsigned long maxResponseSize;
std::map<std::string,std::string> *responseHeaders;
std::string *responseBody;
std::map<std::string, std::string>* responseHeaders;
std::string* responseBody;
bool error;
bool done;
Phy<HttpPhyHandler *> *phy;
PhySocket *sock;
Phy<HttpPhyHandler*>* phy;
PhySocket* sock;
};
static int ShttpOnMessageBegin(http_parser *parser)
static int ShttpOnMessageBegin(http_parser* parser)
{
return 0;
}
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length)
static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length)
{
return 0;
}
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length)
static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length)
#else
static int ShttpOnStatus(http_parser *parser)
static int ShttpOnStatus(http_parser* parser)
#endif
{
/*
@ -156,66 +154,66 @@ static int ShttpOnStatus(http_parser *parser)
*/
return 0;
}
static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length)
static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length)
{
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data);
HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize)
return -1;
if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) {
if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length())) {
(*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
hh->currentHeaderField = "";
hh->currentHeaderValue = "";
}
for(size_t i=0;i<length;++i)
for (size_t i = 0; i < length; ++i)
hh->currentHeaderField.push_back(OSUtils::toLower(ptr[i]));
return 0;
}
static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length)
static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length)
{
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data);
HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize)
return -1;
hh->currentHeaderValue.append(ptr,length);
hh->currentHeaderValue.append(ptr, length);
return 0;
}
static int ShttpOnHeadersComplete(http_parser *parser)
static int ShttpOnHeadersComplete(http_parser* parser)
{
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data);
if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length()))
HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length()))
(*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
return 0;
}
static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length)
static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length)
{
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data);
HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize)
return -1;
hh->responseBody->append(ptr,length);
hh->responseBody->append(ptr, length);
return 0;
}
static int ShttpOnMessageComplete(http_parser *parser)
static int ShttpOnMessageComplete(http_parser* parser)
{
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data);
HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->phy->close(hh->sock);
return 0;
}
} // anonymous namespace
} // anonymous namespace
unsigned int Http::_do(
const char *method,
const char* method,
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
const void *requestBody,
const struct sockaddr* remoteAddress,
const char* path,
const std::map<std::string, std::string>& requestHeaders,
const void* requestBody,
unsigned long requestBodyLength,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
std::map<std::string, std::string>& responseHeaders,
std::string& responseBody)
{
try {
responseHeaders.clear();
@ -223,31 +221,33 @@ unsigned int Http::_do(
HttpPhyHandler handler;
http_parser_init(&(handler.parser),HTTP_RESPONSE);
handler.parser.data = (void *)&handler;
http_parser_init(&(handler.parser), HTTP_RESPONSE);
handler.parser.data = (void*)&handler;
handler.messageSize = 0;
handler.writePtr = 0;
handler.lastActivity = OSUtils::now();
try {
char tmp[1024];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s %s HTTP/1.1\r\n",method,path);
OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s %s HTTP/1.1\r\n", method, path);
handler.writeBuf.append(tmp);
for(std::map<std::string,std::string>::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h) {
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s: %s\r\n",h->first.c_str(),h->second.c_str());
for (std::map<std::string, std::string>::const_iterator h(requestHeaders.begin()); h != requestHeaders.end(); ++h) {
OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s: %s\r\n", h->first.c_str(), h->second.c_str());
handler.writeBuf.append(tmp);
}
handler.writeBuf.append("\r\n");
if ((requestBody)&&(requestBodyLength))
handler.writeBuf.append((const char *)requestBody,requestBodyLength);
} catch ( ... ) {
if ((requestBody) && (requestBodyLength))
handler.writeBuf.append((const char*)requestBody, requestBodyLength);
}
catch (...) {
responseBody = "request too large";
return 0;
}
if (maxResponseSize) {
handler.maxResponseSize = maxResponseSize;
} else {
}
else {
handler.maxResponseSize = 2147483647;
}
handler.responseHeaders = &responseHeaders;
@ -255,19 +255,19 @@ unsigned int Http::_do(
handler.error = false;
handler.done = false;
Phy<HttpPhyHandler *> phy(&handler,true,true);
Phy<HttpPhyHandler*> phy(&handler, true, true);
bool instantConnect = false;
handler.phy = &phy;
handler.sock = phy.tcpConnect((const struct sockaddr *)remoteAddress,instantConnect,(void *)0,true);
if (!handler.sock) {
handler.sock = phy.tcpConnect((const struct sockaddr*)remoteAddress, instantConnect, (void*)0, true);
if (! handler.sock) {
responseBody = "connection failed (2)";
return 0;
}
while (!handler.done) {
while (! handler.done) {
phy.poll(timeout / 2);
if ((timeout)&&((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) {
if ((timeout) && ((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) {
phy.close(handler.sock);
responseBody = "timed out";
return 0;
@ -275,13 +275,15 @@ unsigned int Http::_do(
}
return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code));
} catch (std::exception &exc) {
}
catch (std::exception& exc) {
responseBody = exc.what();
return 0;
} catch ( ... ) {
}
catch (...) {
responseBody = "unknown exception";
return 0;
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,21 +14,21 @@
#ifndef ZT_HTTP_HPP
#define ZT_HTTP_HPP
#include <string>
#include <map>
#include <stdexcept>
#include <string>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif
namespace ZeroTier {
@ -36,9 +36,8 @@ namespace ZeroTier {
/**
* Simple synchronous HTTP client used for updater and cli
*/
class Http
{
public:
class Http {
public:
/**
* Make HTTP GET request
*
@ -46,26 +45,16 @@ public:
*
* @return HTTP status code or 0 on error (responseBody will contain error message)
*/
static inline unsigned int GET(
unsigned long maxResponseSize,
static inline unsigned int
GET(unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
const struct sockaddr* remoteAddress,
const char* path,
const std::map<std::string, std::string>& requestHeaders,
std::map<std::string, std::string>& responseHeaders,
std::string& responseBody)
{
return _do(
"GET",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
(const void *)0,
0,
responseHeaders,
responseBody);
return _do("GET", maxResponseSize, timeout, remoteAddress, path, requestHeaders, (const void*)0, 0, responseHeaders, responseBody);
}
/**
@ -75,26 +64,16 @@ public:
*
* @return HTTP status code or 0 on error (responseBody will contain error message)
*/
static inline unsigned int DEL(
unsigned long maxResponseSize,
static inline unsigned int
DEL(unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
const struct sockaddr* remoteAddress,
const char* path,
const std::map<std::string, std::string>& requestHeaders,
std::map<std::string, std::string>& responseHeaders,
std::string& responseBody)
{
return _do(
"DELETE",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
(const void *)0,
0,
responseHeaders,
responseBody);
return _do("DELETE", maxResponseSize, timeout, remoteAddress, path, requestHeaders, (const void*)0, 0, responseHeaders, responseBody);
}
/**
@ -109,25 +88,15 @@ public:
static inline unsigned int POST(
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
const void *postData,
const struct sockaddr* remoteAddress,
const char* path,
const std::map<std::string, std::string>& requestHeaders,
const void* postData,
unsigned long postDataLength,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
std::map<std::string, std::string>& responseHeaders,
std::string& responseBody)
{
return _do(
"POST",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
postData,
postDataLength,
responseHeaders,
responseBody);
return _do("POST", maxResponseSize, timeout, remoteAddress, path, requestHeaders, postData, postDataLength, responseHeaders, responseBody);
}
/**
@ -139,44 +108,34 @@ public:
*
* @return HTTP status code or 0 on error (responseBody will contain error message)
*/
static inline unsigned int PUT(
unsigned long maxResponseSize,
static inline unsigned int
PUT(unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
const void *postData,
const struct sockaddr* remoteAddress,
const char* path,
const std::map<std::string, std::string>& requestHeaders,
const void* postData,
unsigned long postDataLength,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
std::map<std::string, std::string>& responseHeaders,
std::string& responseBody)
{
return _do(
"PUT",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
postData,
postDataLength,
responseHeaders,
responseBody);
return _do("PUT", maxResponseSize, timeout, remoteAddress, path, requestHeaders, postData, postDataLength, responseHeaders, responseBody);
}
private:
static unsigned int _do(
const char *method,
private:
static unsigned int
_do(const char* method,
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
const void *requestBody,
const struct sockaddr* remoteAddress,
const char* path,
const std::map<std::string, std::string>& requestHeaders,
const void* requestBody,
unsigned long requestBodyLength,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody);
std::map<std::string, std::string>& responseHeaders,
std::string& responseBody);
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -19,42 +19,39 @@
#ifdef __LINUX__
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Dictionary.hpp"
#include "OSUtils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "LinuxEthernetTap.hpp"
#include "LinuxNetLink.hpp"
#include "OSUtils.hpp"
#include <algorithm>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <ifaddrs.h>
#include <algorithm>
#include <utility>
#include <string>
#include <ctype.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
#include <utility>
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
@ -63,7 +60,7 @@
#define ZT_TAP_BUF_SIZE (1024 * 16)
// ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
namespace ZeroTier {
@ -72,9 +69,10 @@ namespace ZeroTier {
// the tap devices.
//
// Returns true if the kernel major version is < 3
bool isOldLinuxKernel() {
bool isOldLinuxKernel()
{
struct utsname buffer;
char *p;
char* p;
long ver[16];
int i = 0;
if (uname(&buffer) != 0) {
@ -84,20 +82,21 @@ bool isOldLinuxKernel() {
p = buffer.release;
while (*p) {
if (isdigit(*p)) {
ver[i] = strtol(p, &p, 10);
i++;
} else {
p++;
}
}
while (*p) {
if (isdigit(*p)) {
ver[i] = strtol(p, &p, 10);
i++;
}
else {
p++;
}
}
return ver[0] < 3;
}
static const char _base32_chars[32] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' };
static void _base32_5_to_8(const uint8_t *in,char *out)
static const char _base32_chars[32] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7' };
static void _base32_5_to_8(const uint8_t* in, char* out)
{
out[0] = _base32_chars[(in[0]) >> 3];
out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6];
@ -110,87 +109,89 @@ static void _base32_5_to_8(const uint8_t *in,char *out)
}
LinuxEthernetTap::LinuxEthernetTap(
const char *homePath,
const char* homePath,
unsigned int concurrency,
bool pinning,
const MAC &mac,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg) :
_handler(handler),
_arg(arg),
_nwid(nwid),
_mac(mac),
_homePath(homePath),
_mtu(mtu),
_fd(0),
_enabled(true),
_run(true),
_lastIfAddrsUpdate(0)
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg)
: _handler(handler)
, _arg(arg)
, _nwid(nwid)
, _mac(mac)
, _homePath(homePath)
, _mtu(mtu)
, _fd(0)
, _enabled(true)
, _run(true)
, _lastIfAddrsUpdate(0)
{
static std::mutex s_tapCreateLock;
char procpath[128],nwids[32];
char procpath[128], nwids[32];
struct stat sbuf;
// Create only one tap at a time globally.
std::lock_guard<std::mutex> tapCreateLock(s_tapCreateLock);
// Make sure Linux netlink is initialized.
(void)LinuxNetLink::getInstance();
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid);
OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", nwid);
_fd = ::open("/dev/net/tun",O_RDWR);
_fd = ::open("/dev/net/tun", O_RDWR);
if (_fd <= 0) {
_fd = ::open("/dev/tun",O_RDWR);
_fd = ::open("/dev/tun", O_RDWR);
if (_fd <= 0)
throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno));
}
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));
memset(&ifr, 0, sizeof(ifr));
// Restore device names from legacy devicemap, but for new devices we use a base32-based
// canonical device name.
std::map<std::string,std::string> globalDeviceMap;
FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r");
std::map<std::string, std::string> globalDeviceMap;
FILE* devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "r");
if (devmapf) {
char buf[256];
while (fgets(buf,sizeof(buf),devmapf)) {
char *x = (char *)0;
char *y = (char *)0;
char *saveptr = (char *)0;
for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) {
if (!x) x = f;
else if (!y) y = f;
else break;
while (fgets(buf, sizeof(buf), devmapf)) {
char* x = (char*)0;
char* y = (char*)0;
char* saveptr = (char*)0;
for (char* f = Utils::stok(buf, "\r\n=", &saveptr); (f); f = Utils::stok((char*)0, "\r\n=", &saveptr)) {
if (! x)
x = f;
else if (! y)
y = f;
else
break;
}
if ((x)&&(y)&&(x[0])&&(y[0]))
if ((x) && (y) && (x[0]) && (y[0]))
globalDeviceMap[x] = y;
}
fclose(devmapf);
}
bool recalledDevice = false;
std::map<std::string,std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
std::map<std::string, std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
if (gdmEntry != globalDeviceMap.end()) {
Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),gdmEntry->second.c_str());
OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
recalledDevice = (stat(procpath,&sbuf) != 0);
Utils::scopy(ifr.ifr_name, sizeof(ifr.ifr_name), gdmEntry->second.c_str());
OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name);
recalledDevice = (stat(procpath, &sbuf) != 0);
}
if (!recalledDevice) {
if (! recalledDevice) {
#ifdef __SYNOLOGY__
int devno = 50;
do {
OSUtils::ztsnprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++);
OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
} while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist
OSUtils::ztsnprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", devno++);
OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name);
} while (stat(procpath, &sbuf) == 0); // try zt#++ until we find one that does not exist
#else
uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network
uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network
do {
const uint64_t nwid40 = (nwid ^ (nwid >> 24)) + trial++;
uint8_t tmp2[5];
@ -202,29 +203,28 @@ LinuxEthernetTap::LinuxEthernetTap(
tmp2[4] = (uint8_t)(nwid40 & 0xff);
tmp3[0] = 'z';
tmp3[1] = 't';
_base32_5_to_8(tmp2,tmp3 + 2);
_base32_5_to_8(tmp2, tmp3 + 2);
tmp3[10] = (char)0;
memcpy(ifr.ifr_name,tmp3,11);
OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
} while (stat(procpath,&sbuf) == 0);
memcpy(ifr.ifr_name, tmp3, 11);
OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name);
} while (stat(procpath, &sbuf) == 0);
#endif
}
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) {
if (ioctl(_fd, TUNSETIFF, (void*)&ifr) < 0) {
::close(_fd);
throw std::runtime_error("unable to configure TUN/TAP device for TAP operation");
}
::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here
::ioctl(_fd, TUNSETPERSIST, 0); // valgrind may generate a false alarm here
_dev = ifr.ifr_name;
::fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
::fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
(void)::pipe(_shutdownSignalPipe);
for (unsigned int i = 0; i < concurrency; ++i) {
_rxThreads.push_back(std::thread([this, i, concurrency, pinning] {
if (pinning) {
int pinCore = i % concurrency;
fprintf(stderr, "Pinning tap thread %d to core %d\n", i, pinCore);
@ -233,8 +233,7 @@ LinuxEthernetTap::LinuxEthernetTap(
CPU_ZERO(&cpuset);
CPU_SET(pinCore, &cpuset);
int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
if (rc != 0)
{
if (rc != 0) {
fprintf(stderr, "Failed to pin tap thread %d to core %d: %s\n", i, pinCore, strerror(errno));
exit(1);
}
@ -364,11 +363,11 @@ LinuxEthernetTap::LinuxEthernetTap(
LinuxEthernetTap::~LinuxEthernetTap()
{
_run = false;
(void)::write(_shutdownSignalPipe[1],"\0",1);
(void)::write(_shutdownSignalPipe[1], "\0", 1);
::close(_fd);
::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]);
for (std::thread &t : _rxThreads) {
for (std::thread& t : _rxThreads) {
t.join();
}
}
@ -383,7 +382,7 @@ bool LinuxEthernetTap::enabled() const
return _enabled;
}
static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
static bool ___removeIp(const std::string& _dev, const InetAddress& ip)
{
LinuxNetLink::getInstance().removeAddress(ip, _dev.c_str());
return true;
@ -392,55 +391,54 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
bool LinuxEthernetTap::addIps(std::vector<InetAddress> ips)
{
#ifdef __SYNOLOGY__
std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-"+_dev;
std::string cfg_contents = "DEVICE="+_dev+"\nBOOTPROTO=static";
int ip4=0,ip6=0,ip4_tot=0,ip6_tot=0;
std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-" + _dev;
std::string cfg_contents = "DEVICE=" + _dev + "\nBOOTPROTO=static";
int ip4 = 0, ip6 = 0, ip4_tot = 0, ip6_tot = 0;
for(int i=0; i<(int)ips.size(); i++) {
for (int i = 0; i < (int)ips.size(); i++) {
if (ips[i].isV4())
ip4_tot++;
else
ip6_tot++;
}
// Assemble and write contents of ifcfg-dev file
for(int i=0; i<(int)ips.size(); i++) {
for (int i = 0; i < (int)ips.size(); i++) {
if (ips[i].isV4()) {
char iptmp[64],iptmp2[64];
char iptmp[64], iptmp2[64];
std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : "";
cfg_contents += "\nIPADDR"+numstr4+"="+ips[i].toIpString(iptmp)
+ "\nNETMASK"+numstr4+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
cfg_contents += "\nIPADDR" + numstr4 + "=" + ips[i].toIpString(iptmp) + "\nNETMASK" + numstr4 + "=" + ips[i].netmask().toIpString(iptmp2) + "\n";
ip4++;
} else {
char iptmp[64],iptmp2[64];
}
else {
char iptmp[64], iptmp2[64];
std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : "";
cfg_contents += "\nIPV6ADDR"+numstr6+"="+ips[i].toIpString(iptmp)
+ "\nNETMASK"+numstr6+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
cfg_contents += "\nIPV6ADDR" + numstr6 + "=" + ips[i].toIpString(iptmp) + "\nNETMASK" + numstr6 + "=" + ips[i].netmask().toIpString(iptmp2) + "\n";
ip6++;
}
}
OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length());
// Finally, add IPs
for(int i=0; i<(int)ips.size(); i++){
for (int i = 0; i < (int)ips.size(); i++) {
LinuxNetLink::getInstance().addAddress(ips[i], _dev.c_str());
}
return true;
#endif // __SYNOLOGY__
#endif // __SYNOLOGY__
return false;
}
bool LinuxEthernetTap::addIp(const InetAddress &ip)
bool LinuxEthernetTap::addIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return false;
std::vector<InetAddress> allIps(ips());
if (std::binary_search(allIps.begin(),allIps.end(),ip))
if (std::binary_search(allIps.begin(), allIps.end(), ip))
return true;
// Remove and reconfigure if address is the same but netmask is different
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if (i->ipsEqual(ip))
___removeIp(_dev,*i);
___removeIp(_dev, *i);
}
LinuxNetLink::getInstance().addAddress(ip, _dev.c_str());
@ -448,13 +446,13 @@ bool LinuxEthernetTap::addIp(const InetAddress &ip)
return true;
}
bool LinuxEthernetTap::removeIp(const InetAddress &ip)
bool LinuxEthernetTap::removeIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return true;
std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) {
if (___removeIp(_dev,ip))
if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) {
if (___removeIp(_dev, ip))
return true;
}
return false;
@ -462,7 +460,6 @@ bool LinuxEthernetTap::removeIp(const InetAddress &ip)
std::vector<InetAddress> LinuxEthernetTap::ips() const
{
uint64_t now = OSUtils::now();
if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) {
@ -470,28 +467,28 @@ std::vector<InetAddress> LinuxEthernetTap::ips() const
}
_lastIfAddrsUpdate = now;
struct ifaddrs *ifa = (struct ifaddrs *)0;
struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa))
return std::vector<InetAddress>();
std::vector<InetAddress> r;
struct ifaddrs *p = ifa;
struct ifaddrs* p = ifa;
while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) {
if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch (p->ifa_addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
}
}
p = p->ifa_next;
@ -500,24 +497,24 @@ std::vector<InetAddress> LinuxEthernetTap::ips() const
if (ifa)
freeifaddrs(ifa);
std::sort(r.begin(),r.end());
r.erase(std::unique(r.begin(),r.end()),r.end());
std::sort(r.begin(), r.end());
r.erase(std::unique(r.begin(), r.end()), r.end());
_ifaddrs = r;
return r;
}
void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
void LinuxEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{
char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len);
if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6, 6);
*((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14, data, len);
len += 14;
(void)::write(_fd,putBuf,len);
(void)::write(_fd, putBuf, len);
}
}
@ -526,53 +523,53 @@ std::string LinuxEthernetTap::deviceName() const
return _dev;
}
void LinuxEthernetTap::setFriendlyName(const char *friendlyName)
void LinuxEthernetTap::setFriendlyName(const char* friendlyName)
{
}
void LinuxEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
void LinuxEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{
char *ptr,*ptr2;
char *ptr, *ptr2;
unsigned char mac[6];
std::vector<MulticastGroup> newGroups;
int fd = ::open("/proc/net/dev_mcast",O_RDONLY);
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))) {
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)) {
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)) {
char* devname = (char*)0;
char* mcastmac = (char*)0;
for (char* f = strtok_r(l, " \t", &ptr2); (f); f = strtok_r((char*)0, " \t", &ptr2)) {
if (fno == 1)
devname = f;
else if (fno == 4)
mcastmac = f;
++fno;
}
if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6))
newGroups.push_back(MulticastGroup(MAC(mac,6),0));
if ((devname) && (! strcmp(devname, _dev.c_str())) && (mcastmac) && (Utils::unhex(mcastmac, mac, 6) == 6))
newGroups.push_back(MulticastGroup(MAC(mac, 6), 0));
}
}
::close(fd);
}
std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end());
newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end());
std::sort(newGroups.begin(), newGroups.end());
newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m);
}
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m);
}
@ -583,13 +580,13 @@ void LinuxEthernetTap::setMtu(unsigned int mtu)
{
if (_mtu != mtu) {
_mtu = mtu;
int sock = socket(AF_INET,SOCK_DGRAM,0);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock > 0) {
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));
strcpy(ifr.ifr_name,_dev.c_str());
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, _dev.c_str());
ifr.ifr_ifru.ifru_mtu = (int)mtu;
if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) {
if (ioctl(sock, SIOCSIFMTU, (void*)&ifr) < 0) {
printf("WARNING: ioctl() failed updating existing Linux tap device (set MTU)\n");
}
close(sock);
@ -597,6 +594,6 @@ void LinuxEthernetTap::setMtu(unsigned int mtu)
}
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif // __LINUX__
#endif // __LINUX__

View file

@ -14,55 +14,56 @@
#ifndef ZT_LINUXETHERNETTAP_HPP
#define ZT_LINUXETHERNETTAP_HPP
#include "../node/MulticastGroup.hpp"
#include "BlockingQueue.hpp"
#include "EthernetTap.hpp"
#include <array>
#include <atomic>
#include <mutex>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <stdexcept>
#include <atomic>
#include <array>
#include <thread>
#include <mutex>
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "BlockingQueue.hpp"
#include <vector>
namespace ZeroTier {
class LinuxEthernetTap : public EthernetTap
{
public:
class LinuxEthernetTap : public EthernetTap {
public:
LinuxEthernetTap(
const char *homePath,
const char* homePath,
unsigned int concurrency,
bool pinning,
const MAC &mac,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg);
virtual ~LinuxEthernetTap();
virtual void setEnabled(bool en);
virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip);
virtual bool addIp(const InetAddress& ip);
virtual bool addIps(std::vector<InetAddress> ips);
virtual bool removeIp(const InetAddress &ip);
virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) {}
virtual void setDns(const char* domain, const std::vector<InetAddress>& servers)
{
}
private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
void *_arg;
private:
void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void* _arg;
uint64_t _nwid;
MAC _mac;
std::string _homePath;
@ -78,6 +79,6 @@ private:
std::vector<std::thread> _rxThreads;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -18,68 +18,77 @@
#ifdef __LINUX__
#include <vector>
#include <map>
#include <set>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/rtnetlink.h>
#include <map>
#include <set>
#include <sys/socket.h>
//#include <linux/if.h>
#include <vector>
// #include <linux/if.h>
#include "../node/Hashtable.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "Thread.hpp"
#include "../node/Hashtable.hpp"
#include "../node/Mutex.hpp"
#include "Thread.hpp"
namespace ZeroTier {
/**
* Interface with Linux's RTNETLINK
*/
class LinuxNetLink
{
private:
class LinuxNetLink {
private:
LinuxNetLink();
~LinuxNetLink();
public:
public:
struct Route {
InetAddress target;
InetAddress via;
InetAddress src;
int ifidx;
inline bool operator==(const Route &r) const
{ return ((target == r.target)&&(via == r.via)&&(src == r.src)&&(ifidx == r.ifidx)); }
inline bool operator!=(const Route &r) const
{ return (!(*this == r)); }
inline bool operator<(const Route &r) const
inline bool operator==(const Route& r) const
{
return ((target == r.target) && (via == r.via) && (src == r.src) && (ifidx == r.ifidx));
}
inline bool operator!=(const Route& r) const
{
return (! (*this == r));
}
inline bool operator<(const Route& r) const
{
if (target < r.target) {
return true;
} else if (target == r.target) {
}
else if (target == r.target) {
if (via < r.via) {
return true;
} else if (via == r.via) {
}
else if (via == r.via) {
if (src < r.src) {
return true;
} else if (src == r.src) {
}
else if (src == r.src) {
return (ifidx < r.ifidx);
}
}
}
return false;
}
inline bool operator>(const Route &r) const
{ return (r < *this); }
inline bool operator<=(const Route &r) const
{ return !(r < *this); }
inline bool operator>=(const Route &r) const
{ return !(*this < r); }
inline bool operator>(const Route& r) const
{
return (r < *this);
}
inline bool operator<=(const Route& r) const
{
return ! (r < *this);
}
inline bool operator>=(const Route& r) const
{
return ! (*this < r);
}
};
static LinuxNetLink& getInstance()
@ -91,32 +100,32 @@ public:
LinuxNetLink(LinuxNetLink const&) = delete;
void operator=(LinuxNetLink const&) = delete;
void addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName);
void delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName);
void addRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName);
void delRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName);
void addAddress(const InetAddress &addr, const char *iface);
void removeAddress(const InetAddress &addr, const char *iface);
void addAddress(const InetAddress& addr, const char* iface);
void removeAddress(const InetAddress& addr, const char* iface);
bool routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname);
bool routeIsSet(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifname);
void threadMain() throw();
private:
private:
int _doRecv(int fd);
void _processMessage(struct nlmsghdr *nlp, int nll);
void _routeAdded(struct nlmsghdr *nlp);
void _routeDeleted(struct nlmsghdr *nlp);
void _linkAdded(struct nlmsghdr *nlp);
void _linkDeleted(struct nlmsghdr *nlp);
void _ipAddressAdded(struct nlmsghdr *nlp);
void _ipAddressDeleted(struct nlmsghdr *nlp);
void _processMessage(struct nlmsghdr* nlp, int nll);
void _routeAdded(struct nlmsghdr* nlp);
void _routeDeleted(struct nlmsghdr* nlp);
void _linkAdded(struct nlmsghdr* nlp);
void _linkDeleted(struct nlmsghdr* nlp);
void _ipAddressAdded(struct nlmsghdr* nlp);
void _ipAddressDeleted(struct nlmsghdr* nlp);
void _requestInterfaceList();
void _requestIPv4Routes();
void _requestIPv6Routes();
int _indexForInterface(const char *iface);
int _indexForInterface(const char* iface);
void _setSocketTimeout(int fd, int seconds = 1);
@ -125,14 +134,16 @@ private:
uint32_t _seq;
std::map< InetAddress,std::set<LinuxNetLink::Route> > _routes;
std::map<InetAddress, std::set<LinuxNetLink::Route> > _routes;
Mutex _routes_m;
struct iface_entry {
iface_entry()
{ memset(this,0,sizeof(iface_entry)); }
{
memset(this, 0, sizeof(iface_entry));
}
int index;
char ifacename[16]; // IFNAMSIZ on Linux == 16
char ifacename[16]; // IFNAMSIZ on Linux == 16
char mac[18];
char mac_bin[6];
unsigned int mtu;
@ -145,8 +156,8 @@ private:
struct sockaddr_nl _la;
};
}
} // namespace ZeroTier
#endif
#endif // ZT_LINUX_NETLINK_HPPS
#endif // ZT_LINUX_NETLINK_HPPS

View file

@ -1,23 +1,23 @@
#ifndef MAC_DNS_HELPER
#define MAC_DNS_HELPER
#include <vector>
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include <vector>
namespace ZeroTier {
class MacDNSHelper
{
public:
static void setDNS(uint64_t nwid, const char *domain, const std::vector<InetAddress> &servers);
static void removeDNS(uint64_t nwid);
static bool addIps4(uint64_t nwid, const MAC mac, const char *dev, const std::vector<InetAddress> &addrs);
static bool addIps6(uint64_t nwid, const MAC mac, const char *dev, const std::vector<InetAddress> &addrs);
static bool removeIps4(uint64_t nwid);
static bool removeIps6(uint64_t nwid);
class MacDNSHelper {
public:
static void setDNS(uint64_t nwid, const char* domain, const std::vector<InetAddress>& servers);
static void removeDNS(uint64_t nwid);
static bool addIps4(uint64_t nwid, const MAC mac, const char* dev, const std::vector<InetAddress>& addrs);
static bool addIps6(uint64_t nwid, const MAC mac, const char* dev, const std::vector<InetAddress>& addrs);
static bool removeIps4(uint64_t nwid);
static bool removeIps6(uint64_t nwid);
};
}
} // namespace ZeroTier
#endif

View file

@ -15,49 +15,45 @@
#ifdef __APPLE__
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Dictionary.hpp"
#include "OSUtils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "MacDNSHelper.hpp"
#include "MacEthernetTap.hpp"
#include "MacEthernetTapAgent.h"
#include "MacDNSHelper.hpp"
#include "OSUtils.hpp"
#include <algorithm>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <filesystem>
#include <ifaddrs.h>
#include <map>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <set>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <sys/sysctl.h>
#include <ifaddrs.h>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <filesystem>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
#define MACOS_FETH_MAX_MTU_SYSCTL "net.link.fake.max_mtu"
@ -68,45 +64,45 @@ static bool globalTapInitialized = false;
static bool fethMaxMtuAdjusted = false;
MacEthernetTap::MacEthernetTap(
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len),
void *arg) :
_handler(handler),
_arg(arg),
_nwid(nwid),
_homePath(homePath),
_mtu(mtu),
_metric(metric),
_devNo(0),
_agentStdin(-1),
_agentStdout(-1),
_agentStderr(-1),
_agentStdin2(-1),
_agentStdout2(-1),
_agentStderr2(-1),
_agentPid(-1),
_enabled(true),
_lastIfAddrsUpdate(0)
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void* data, unsigned int len),
void* arg)
: _handler(handler)
, _arg(arg)
, _nwid(nwid)
, _homePath(homePath)
, _mtu(mtu)
, _metric(metric)
, _devNo(0)
, _agentStdin(-1)
, _agentStdout(-1)
, _agentStderr(-1)
, _agentStdin2(-1)
, _agentStdout2(-1)
, _agentStderr2(-1)
, _agentPid(-1)
, _enabled(true)
, _lastIfAddrsUpdate(0)
{
char ethaddr[64],mtustr[16],devnostr[16],devstr[16],metricstr[16];
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]);
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",mtu);
OSUtils::ztsnprintf(metricstr,sizeof(metricstr),"%u",metric);
char ethaddr[64], mtustr[16], devnostr[16], devstr[16], metricstr[16];
OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", mtu);
OSUtils::ztsnprintf(metricstr, sizeof(metricstr), "%u", metric);
std::string agentPath(homePath);
agentPath.push_back(ZT_PATH_SEPARATOR);
agentPath.append("MacEthernetTapAgent");
if (!OSUtils::fileExists(agentPath.c_str()))
if (! OSUtils::fileExists(agentPath.c_str()))
throw std::runtime_error("MacEthernetTapAgent not present in ZeroTier home");
Mutex::Lock _gl(globalTapCreateLock); // only make one at a time
Mutex::Lock _gl(globalTapCreateLock); // only make one at a time
if (!fethMaxMtuAdjusted) {
if (! fethMaxMtuAdjusted) {
fethMaxMtuAdjusted = true;
int old_mtu = 0;
size_t old_mtu_len = sizeof(old_mtu);
@ -116,29 +112,30 @@ MacEthernetTap::MacEthernetTap(
// Destroy all feth devices on first tap start in case ZeroTier did not exit cleanly last time.
// We leave interfaces less than feth100 alone in case something else is messing with feth devices.
if (!globalTapInitialized) {
if (! globalTapInitialized) {
globalTapInitialized = true;
struct ifaddrs *ifa = (struct ifaddrs *)0;
struct ifaddrs* ifa = (struct ifaddrs*)0;
std::set<std::string> deleted;
if (!getifaddrs(&ifa)) {
struct ifaddrs *p = ifa;
if (! getifaddrs(&ifa)) {
struct ifaddrs* p = ifa;
while (p) {
int nameLen = (int)strlen(p->ifa_name);
// Delete feth# from feth0 to feth9999, but don't touch >10000.
if ((!strncmp(p->ifa_name,"feth",4))&&(nameLen >= 5)&&(nameLen <= 8)&&(deleted.count(std::string(p->ifa_name)) == 0)) {
if ((! strncmp(p->ifa_name, "feth", 4)) && (nameLen >= 5) && (nameLen <= 8) && (deleted.count(std::string(p->ifa_name)) == 0)) {
deleted.insert(std::string(p->ifa_name));
const char *args[4];
const char* args[4];
args[0] = "/sbin/ifconfig";
args[1] = p->ifa_name;
args[2] = "destroy";
args[3] = (char *)0;
args[3] = (char*)0;
const pid_t pid = vfork();
if (pid == 0) {
execv(args[0],const_cast<char **>(args));
execv(args[0], const_cast<char**>(args));
_exit(-1);
} else if (pid > 0) {
}
else if (pid > 0) {
int rv = 0;
waitpid(pid,&rv,0);
waitpid(pid, &rv, 0);
}
}
p = p->ifa_next;
@ -148,15 +145,15 @@ MacEthernetTap::MacEthernetTap(
}
unsigned int devNo = 100 + ((nwid ^ (nwid >> 32) ^ (nwid >> 48)) % 4900);
for(;;) {
OSUtils::ztsnprintf(devnostr,sizeof(devnostr),"%u",devNo);
OSUtils::ztsnprintf(devstr,sizeof(devstr),"feth%u",devNo);
for (;;) {
OSUtils::ztsnprintf(devnostr, sizeof(devnostr), "%u", devNo);
OSUtils::ztsnprintf(devstr, sizeof(devstr), "feth%u", devNo);
bool duplicate = false;
struct ifaddrs *ifa = (struct ifaddrs *)0;
if (!getifaddrs(&ifa)) {
struct ifaddrs *p = ifa;
struct ifaddrs* ifa = (struct ifaddrs*)0;
if (! getifaddrs(&ifa)) {
struct ifaddrs* p = ifa;
while (p) {
if (!strcmp(p->ifa_name,devstr)) {
if (! strcmp(p->ifa_name, devstr)) {
duplicate = true;
break;
}
@ -168,7 +165,8 @@ MacEthernetTap::MacEthernetTap(
devNo = (devNo + 1) % 5000;
if (devNo < 100)
devNo = 100;
} else {
}
else {
_dev = devstr;
_devNo = devNo;
break;
@ -196,29 +194,31 @@ MacEthernetTap::MacEthernetTap(
long apid = (long)fork();
if (apid < 0) {
throw std::runtime_error("fork failed");
} else if (apid == 0) {
::dup2(agentStdin[0],STDIN_FILENO);
::dup2(agentStdout[1],STDOUT_FILENO);
::dup2(agentStderr[1],STDERR_FILENO);
}
else if (apid == 0) {
::dup2(agentStdin[0], STDIN_FILENO);
::dup2(agentStdout[1], STDOUT_FILENO);
::dup2(agentStderr[1], STDERR_FILENO);
::close(agentStdin[0]);
::close(agentStdin[1]);
::close(agentStdout[0]);
::close(agentStdout[1]);
::close(agentStderr[0]);
::close(agentStderr[1]);
::execl(agentPath.c_str(),agentPath.c_str(),devnostr,ethaddr,mtustr,metricstr,(char *)0);
::execl(agentPath.c_str(), agentPath.c_str(), devnostr, ethaddr, mtustr, metricstr, (char*)0);
::_exit(-1);
} else {
}
else {
_agentPid = apid;
// Wait up to 10 seconds for the subprocess to actually create the device. This prevents
// things like routes from being created before the device exists.
for(int waitLoops=0;;++waitLoops) {
struct ifaddrs *ifa = (struct ifaddrs *)0;
if (!getifaddrs(&ifa)) {
struct ifaddrs *p = ifa;
for (int waitLoops = 0;; ++waitLoops) {
struct ifaddrs* ifa = (struct ifaddrs*)0;
if (! getifaddrs(&ifa)) {
struct ifaddrs* p = ifa;
while (p) {
if ((p->ifa_name)&&(!strcmp(devstr, p->ifa_name))) {
if ((p->ifa_name) && (! strcmp(devstr, p->ifa_name))) {
waitLoops = -1;
break;
}
@ -228,7 +228,8 @@ MacEthernetTap::MacEthernetTap(
}
if (waitLoops == -1) {
break;
} else if (waitLoops >= 100) { // 10 seconds
}
else if (waitLoops >= 100) { // 10 seconds
throw std::runtime_error("feth device creation timed out");
}
Thread::sleep(100);
@ -241,61 +242,67 @@ MacEthernetTap::MacEthernetTap(
MacEthernetTap::~MacEthernetTap()
{
char tmp[64];
const char *args[4];
pid_t pid0,pid1;
const char* args[4];
pid_t pid0, pid1;
MacDNSHelper::removeDNS(_nwid);
MacDNSHelper::removeIps4(_nwid);
MacDNSHelper::removeIps6(_nwid);
Mutex::Lock _gl(globalTapCreateLock);
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
int ec = 0;
::kill(_agentPid,SIGKILL);
::waitpid(_agentPid,&ec,0);
::kill(_agentPid, SIGKILL);
::waitpid(_agentPid, &ec, 0);
args[0] = "/sbin/ifconfig";
args[1] = _dev.c_str();
args[2] = "destroy";
args[3] = (char *)0;
args[3] = (char*)0;
pid0 = vfork();
if (pid0 == 0) {
execv(args[0],const_cast<char **>(args));
execv(args[0], const_cast<char**>(args));
_exit(-1);
}
snprintf(tmp,sizeof(tmp),"feth%u",_devNo + 5000);
//args[0] = "/sbin/ifconfig";
snprintf(tmp, sizeof(tmp), "feth%u", _devNo + 5000);
// args[0] = "/sbin/ifconfig";
args[1] = tmp;
//args[2] = "destroy";
//args[3] = (char *)0;
// args[2] = "destroy";
// args[3] = (char *)0;
pid1 = vfork();
if (pid1 == 0) {
execv(args[0],const_cast<char **>(args));
execv(args[0], const_cast<char**>(args));
_exit(-1);
}
if (pid0 > 0) {
int rv = 0;
waitpid(pid0,&rv,0);
waitpid(pid0, &rv, 0);
}
if (pid1 > 0) {
int rv = 0;
waitpid(pid1,&rv,0);
waitpid(pid1, &rv, 0);
}
Thread::join(_thread);
}
void MacEthernetTap::setEnabled(bool en) { _enabled = en; }
bool MacEthernetTap::enabled() const { return _enabled; }
void MacEthernetTap::setEnabled(bool en)
{
_enabled = en;
}
bool MacEthernetTap::enabled() const
{
return _enabled;
}
bool MacEthernetTap::addIp(const InetAddress &ip)
bool MacEthernetTap::addIp(const InetAddress& ip)
{
char tmp[128];
if (!ip)
if (! ip)
return false;
std::string cmd;
@ -309,18 +316,18 @@ bool MacEthernetTap::addIp(const InetAddress &ip)
uint16_t l = (uint16_t)cmd.length();
_putLock.lock();
write(_agentStdin,&l,2);
write(_agentStdin,cmd.data(),cmd.length());
write(_agentStdin, &l, 2);
write(_agentStdin, cmd.data(), cmd.length());
_putLock.unlock();
return true;
}
bool MacEthernetTap::removeIp(const InetAddress &ip)
bool MacEthernetTap::removeIp(const InetAddress& ip)
{
char tmp[128];
if (!ip)
if (! ip)
return false;
std::string cmd;
@ -334,8 +341,8 @@ bool MacEthernetTap::removeIp(const InetAddress &ip)
uint16_t l = (uint16_t)cmd.length();
_putLock.lock();
write(_agentStdin,&l,2);
write(_agentStdin,cmd.data(),cmd.length());
write(_agentStdin, &l, 2);
write(_agentStdin, cmd.data(), cmd.length());
_putLock.unlock();
return true;
@ -350,49 +357,49 @@ std::vector<InetAddress> MacEthernetTap::ips() const
}
_lastIfAddrsUpdate = now;
struct ifaddrs *ifa = (struct ifaddrs *)0;
struct ifaddrs* ifa = (struct ifaddrs*)0;
std::vector<InetAddress> r;
if (!getifaddrs(&ifa)) {
struct ifaddrs *p = ifa;
if (! getifaddrs(&ifa)) {
struct ifaddrs* p = ifa;
while (p) {
if ((p->ifa_name)&&(!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)) {
switch(p->ifa_addr->sa_family) {
if ((p->ifa_name) && (! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr)) {
switch (p->ifa_addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
}
}
p = p->ifa_next;
}
freeifaddrs(ifa);
}
std::sort(r.begin(),r.end());
r.erase(std::unique(r.begin(),r.end()),r.end());
std::sort(r.begin(), r.end());
r.erase(std::unique(r.begin(), r.end()), r.end());
_ifaddrs = r;
return r;
}
void MacEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
void MacEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{
struct iovec iov[3];
unsigned char hdr[15];
uint16_t l;
if ((_agentStdin > 0)&&(len <= _mtu)&&(_enabled)) {
if ((_agentStdin > 0) && (len <= _mtu) && (_enabled)) {
hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET;
to.copyTo(hdr + 1,6);
from.copyTo(hdr + 7,6);
to.copyTo(hdr + 1, 6);
from.copyTo(hdr + 7, 6);
hdr[13] = (unsigned char)((etherType >> 8) & 0xff);
hdr[14] = (unsigned char)(etherType & 0xff);
l = (uint16_t)(len + 15);
@ -400,30 +407,35 @@ void MacEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,co
iov[0].iov_len = 2;
iov[1].iov_base = hdr;
iov[1].iov_len = 15;
iov[2].iov_base = const_cast<void *>(data);
iov[2].iov_base = const_cast<void*>(data);
iov[2].iov_len = len;
_putLock.lock();
writev(_agentStdin,iov,3);
writev(_agentStdin, iov, 3);
_putLock.unlock();
}
}
std::string MacEthernetTap::deviceName() const { return _dev; }
void MacEthernetTap::setFriendlyName(const char *friendlyName) {}
std::string MacEthernetTap::deviceName() const
{
return _dev;
}
void MacEthernetTap::setFriendlyName(const char* friendlyName)
{
}
void MacEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
void MacEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{
std::vector<MulticastGroup> newGroups;
struct ifmaddrs *ifmap = (struct ifmaddrs *)0;
if (!getifmaddrs(&ifmap)) {
struct ifmaddrs *p = ifmap;
struct ifmaddrs* ifmap = (struct ifmaddrs*)0;
if (! getifmaddrs(&ifmap)) {
struct ifmaddrs* p = ifmap;
while (p) {
if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
}
p = p->ifma_next;
}
@ -431,18 +443,18 @@ void MacEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std:
}
std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end());
newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end());
std::sort(newGroups.begin(), newGroups.end());
newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m);
}
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m);
}
@ -457,13 +469,13 @@ void MacEthernetTap::setMtu(unsigned int mtu)
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
cmd.append("mtu");
cmd.push_back(0);
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu);
OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu);
cmd.append(tmp);
cmd.push_back(0);
uint16_t l = (uint16_t)cmd.length();
_putLock.lock();
write(_agentStdin,&l,2);
write(_agentStdin,cmd.data(),cmd.length());
write(_agentStdin, &l, 2);
write(_agentStdin, cmd.data(), cmd.length());
_putLock.unlock();
_mtu = mtu;
}
@ -471,61 +483,62 @@ void MacEthernetTap::setMtu(unsigned int mtu)
#define ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE 131072
void MacEthernetTap::threadMain()
throw()
void MacEthernetTap::threadMain() throw()
{
char agentReadBuf[ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE];
char agentStderrBuf[256];
fd_set readfds,nullfds;
MAC to,from;
fd_set readfds, nullfds;
MAC to, from;
Thread::sleep(250);
const int nfds = std::max(std::max(_shutdownSignalPipe[0],_agentStdout),_agentStderr) + 1;
const int nfds = std::max(std::max(_shutdownSignalPipe[0], _agentStdout), _agentStderr) + 1;
long agentReadPtr = 0;
fcntl(_agentStdout,F_SETFL,fcntl(_agentStdout,F_GETFL)|O_NONBLOCK);
fcntl(_agentStderr,F_SETFL,fcntl(_agentStderr,F_GETFL)|O_NONBLOCK);
fcntl(_agentStdout, F_SETFL, fcntl(_agentStdout, F_GETFL) | O_NONBLOCK);
fcntl(_agentStderr, F_SETFL, fcntl(_agentStderr, F_GETFL) | O_NONBLOCK);
FD_ZERO(&readfds);
FD_ZERO(&nullfds);
for(;;) {
FD_SET(_shutdownSignalPipe[0],&readfds);
FD_SET(_agentStdout,&readfds);
FD_SET(_agentStderr,&readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
for (;;) {
FD_SET(_shutdownSignalPipe[0], &readfds);
FD_SET(_agentStdout, &readfds);
FD_SET(_agentStderr, &readfds);
select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0);
if (FD_ISSET(_shutdownSignalPipe[0],&readfds))
if (FD_ISSET(_shutdownSignalPipe[0], &readfds))
break;
if (FD_ISSET(_agentStdout,&readfds)) {
long n = (long)read(_agentStdout,agentReadBuf + agentReadPtr,ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE - agentReadPtr);
if (FD_ISSET(_agentStdout, &readfds)) {
long n = (long)read(_agentStdout, agentReadBuf + agentReadPtr, ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE - agentReadPtr);
if (n > 0) {
agentReadPtr += n;
while (agentReadPtr >= 2) {
long len = *((uint16_t *)agentReadBuf);
long len = *((uint16_t*)agentReadBuf);
if (agentReadPtr >= (len + 2)) {
char *msg = agentReadBuf + 2;
char* msg = agentReadBuf + 2;
if ((len > 14)&&(_enabled)) {
to.setTo(msg,6);
from.setTo(msg + 6,6);
_handler(_arg,(void *)0,_nwid,from,to,ntohs(((const uint16_t *)msg)[6]),0,(const void *)(msg + 14),(unsigned int)len - 14);
if ((len > 14) && (_enabled)) {
to.setTo(msg, 6);
from.setTo(msg + 6, 6);
_handler(_arg, (void*)0, _nwid, from, to, ntohs(((const uint16_t*)msg)[6]), 0, (const void*)(msg + 14), (unsigned int)len - 14);
}
if (agentReadPtr > (len + 2)) {
memmove(agentReadBuf,agentReadBuf + len + 2,agentReadPtr -= (len + 2));
} else {
memmove(agentReadBuf, agentReadBuf + len + 2, agentReadPtr -= (len + 2));
}
else {
agentReadPtr = 0;
}
} else {
}
else {
break;
}
}
}
}
if (FD_ISSET(_agentStderr,&readfds)) {
read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf));
if (FD_ISSET(_agentStderr, &readfds)) {
read(_agentStderr, agentStderrBuf, sizeof(agentStderrBuf));
/*
const ssize_t n = read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf));
if (n > 0)
@ -544,11 +557,11 @@ void MacEthernetTap::threadMain()
::close(_shutdownSignalPipe[1]);
}
void MacEthernetTap::setDns(const char *domain, const std::vector<InetAddress> &servers)
void MacEthernetTap::setDns(const char* domain, const std::vector<InetAddress>& servers)
{
MacDNSHelper::setDNS(this->_nwid, domain, servers);
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif // __APPLE__
#endif // __APPLE__

View file

@ -15,55 +15,52 @@
#define ZT_OSXETHERNETTAP_HPP
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/Mutex.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp"
#include <stdio.h>
#include <stdlib.h>
#include "Thread.hpp"
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
namespace ZeroTier {
class MacEthernetTap : public EthernetTap
{
public:
class MacEthernetTap : public EthernetTap {
public:
MacEthernetTap(
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg);
virtual ~MacEthernetTap();
virtual void setEnabled(bool en);
virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip);
virtual bool removeIp(const InetAddress &ip);
virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers);
virtual void setDns(const char* domain, const std::vector<InetAddress>& servers);
void threadMain()
throw();
void threadMain() throw();
private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
void *_arg;
private:
void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void* _arg;
uint64_t _nwid;
Thread _thread;
std::string _homePath;
@ -74,14 +71,13 @@ private:
unsigned int _metric;
unsigned int _devNo;
int _shutdownSignalPipe[2];
int _agentStdin,_agentStdout,_agentStderr,_agentStdin2,_agentStdout2,_agentStderr2;
int _agentStdin, _agentStdout, _agentStderr, _agentStdin2, _agentStdout2, _agentStderr2;
long _agentPid;
volatile bool _enabled;
mutable std::vector<InetAddress> _ifaddrs;
mutable uint64_t _lastIfAddrsUpdate;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,39 +11,36 @@
*/
/****/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "MacDNSHelper.hpp"
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <sys/sysctl.h>
#include <netinet6/in6_var.h>
#include <netinet/in_var.h>
#include <net/route.h>
#include <netinet/icmp6.h>
#include "MacDNSHelper.hpp"
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet6/in6_var.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!?
struct prf_ra {
@ -52,15 +49,15 @@ struct prf_ra {
u_char reserved : 6;
} prf_ra;
#include <netinet6/nd6.h>
#include <ifaddrs.h>
#include <netinet6/nd6.h>
// These are KERNEL_PRIVATE... why?
#ifndef SIOCAUTOCONF_START
#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
#endif
#ifndef SIOCAUTOCONF_STOP
#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
#endif
// --------------------------------------------------------------------------
@ -69,33 +66,32 @@ struct prf_ra {
// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt
// It's here because OSX 10.6 does not have this convenience function.
#define SALIGN (sizeof(uint32_t) - 1)
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
(SALIGN + 1))
#define MAX_SYSCTL_TRY 5
#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
#define SALIGN (sizeof(uint32_t) - 1)
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
#define MAX_SYSCTL_TRY 5
#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */
/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */
//#define DARWIN_COMPAT
// #define DARWIN_COMPAT
//#ifdef DARWIN_COMPAT
// #ifdef DARWIN_COMPAT
#define GIM_SYSCTL_MIB NET_RT_IFLIST2
#define GIM_RTM_ADDR RTM_NEWMADDR2
//#else
//#define GIM_SYSCTL_MIB NET_RT_IFMALIST
//#define GIM_RTM_ADDR RTM_NEWMADDR
//#endif
#define GIM_RTM_ADDR RTM_NEWMADDR2
// #else
// #define GIM_SYSCTL_MIB NET_RT_IFMALIST
// #define GIM_RTM_ADDR RTM_NEWMADDR
// #endif
// Not in 10.6 includes so use our own
struct _intl_ifmaddrs {
struct _intl_ifmaddrs *ifma_next;
struct sockaddr *ifma_name;
struct sockaddr *ifma_addr;
struct sockaddr *ifma_lladdr;
struct _intl_ifmaddrs* ifma_next;
struct sockaddr* ifma_name;
struct sockaddr* ifma_addr;
struct sockaddr* ifma_lladdr;
};
static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
static inline int _intl_getifmaddrs(struct _intl_ifmaddrs** pif)
{
int icnt = 1;
int dcnt = 0;
@ -104,25 +100,25 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
size_t needed;
int mib[6];
int i;
char *buf;
char *data;
char *next;
char *p;
struct ifma_msghdr2 *ifmam;
char* buf;
char* data;
char* next;
char* p;
struct ifma_msghdr2* ifmam;
struct _intl_ifmaddrs *ifa, *ift;
struct rt_msghdr *rtm;
struct sockaddr *sa;
struct rt_msghdr* rtm;
struct sockaddr* sa;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
mib[3] = 0; /* wildcard address family */
mib[2] = 0; /* protocol */
mib[3] = 0; /* wildcard address family */
mib[4] = GIM_SYSCTL_MIB;
mib[5] = 0; /* no flags */
mib[5] = 0; /* no flags */
do {
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return (-1);
if ((buf = (char *)malloc(needed)) == NULL)
if ((buf = (char*)malloc(needed)) == NULL)
return (-1);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
@ -135,21 +131,20 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
} while (buf == NULL);
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next;
rtm = (struct rt_msghdr*)(void*)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case GIM_RTM_ADDR:
ifmam = (struct ifma_msghdr2 *)(void *)rtm;
ifmam = (struct ifma_msghdr2*)(void*)rtm;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break;
icnt++;
p = (char *)(ifmam + 1);
p = (char*)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs &
(1 << i)) == 0)
if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0)
continue;
sa = (struct sockaddr *)(void *)p;
sa = (struct sockaddr*)(void*)p;
len = SA_RLEN(sa);
dcnt += len;
p += len;
@ -158,54 +153,50 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
}
}
data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
data = (char*)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
if (data == NULL) {
free(buf);
return (-1);
}
ifa = (struct _intl_ifmaddrs *)(void *)data;
ifa = (struct _intl_ifmaddrs*)(void*)data;
data += sizeof(struct _intl_ifmaddrs) * icnt;
memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt);
ift = ifa;
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next;
rtm = (struct rt_msghdr*)(void*)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case GIM_RTM_ADDR:
ifmam = (struct ifma_msghdr2 *)(void *)rtm;
ifmam = (struct ifma_msghdr2*)(void*)rtm;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break;
p = (char *)(ifmam + 1);
p = (char*)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs &
(1 << i)) == 0)
if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0)
continue;
sa = (struct sockaddr *)(void *)p;
sa = (struct sockaddr*)(void*)p;
len = SA_RLEN(sa);
switch (i) {
case RTAX_GATEWAY:
ift->ifma_lladdr =
(struct sockaddr *)(void *)data;
ift->ifma_lladdr = (struct sockaddr*)(void*)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_IFP:
ift->ifma_name =
(struct sockaddr *)(void *)data;
ift->ifma_name = (struct sockaddr*)(void*)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_IFA:
ift->ifma_addr =
(struct sockaddr *)(void *)data;
ift->ifma_addr = (struct sockaddr*)(void*)data;
memcpy(data, p, len);
data += len;
break;
@ -228,14 +219,15 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
ift--;
ift->ifma_next = NULL;
*pif = ifa;
} else {
}
else {
*pif = NULL;
free(ifa);
}
return (0);
}
static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs* ifmp)
{
free(ifmp);
}
@ -243,34 +235,34 @@ static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
#include <string>
#include "../node/Constants.hpp"
#include "../node/Dictionary.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "MacKextEthernetTap.hpp"
#include "OSUtils.hpp"
#include <algorithm>
#include <map>
#include <set>
#include <algorithm>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Dictionary.hpp"
#include "OSUtils.hpp"
#include "MacKextEthernetTap.hpp"
#include <string>
// ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts)
static inline bool _setIpv6Stuff(const char* ifname, bool performNUD, bool acceptRouterAdverts)
{
struct in6_ndireq nd;
struct in6_ifreq ifr;
int s = socket(AF_INET6,SOCK_DGRAM,0);
int s = socket(AF_INET6, SOCK_DGRAM, 0);
if (s <= 0)
return false;
memset(&nd,0,sizeof(nd));
strncpy(nd.ifname,ifname,sizeof(nd.ifname));
memset(&nd, 0, sizeof(nd));
strncpy(nd.ifname, ifname, sizeof(nd.ifname));
if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
if (ioctl(s, SIOCGIFINFO_IN6, &nd)) {
close(s);
return false;
}
@ -279,18 +271,19 @@ static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptR
if (performNUD)
nd.ndi.flags |= ND6_IFF_PERFORMNUD;
else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
else
nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
if (oldFlags != (unsigned long)nd.ndi.flags) {
if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) {
if (ioctl(s, SIOCSIFINFO_FLAGS, &nd)) {
close(s);
return false;
}
}
memset(&ifr,0,sizeof(ifr));
strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) {
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(s, acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP, &ifr)) {
close(s);
return false;
}
@ -305,71 +298,76 @@ static long globalTapsRunning = 0;
static Mutex globalTapCreateLock;
MacKextEthernetTap::MacKextEthernetTap(
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len),
void *arg) :
_handler(handler),
_arg(arg),
_nwid(nwid),
_homePath(homePath),
_mtu(mtu),
_metric(metric),
_fd(0),
_enabled(true)
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void* data, unsigned int len),
void* arg)
: _handler(handler)
, _arg(arg)
, _nwid(nwid)
, _homePath(homePath)
, _mtu(mtu)
, _metric(metric)
, _fd(0)
, _enabled(true)
{
char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32];
char devpath[64], ethaddr[64], mtustr[32], metstr[32], nwids[32];
struct stat stattmp;
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid);
OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", nwid);
Mutex::Lock _gl(globalTapCreateLock);
if (::stat("/dev/zt0",&stattmp)) {
if (::stat("/dev/zt0", &stattmp)) {
long kextpid = (long)fork();
if (kextpid == 0) {
::chdir(homePath);
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0);
OSUtils::redirectUnixOutputs("/dev/null", (const char*)0);
::execl("/sbin/kextload", "/sbin/kextload", "-q", "-repository", homePath, "tap.kext", (const char*)0);
::_exit(-1);
} else if (kextpid > 0) {
int exitcode = -1;
::waitpid(kextpid,&exitcode,0);
}
::usleep(500); // give tap device driver time to start up and try again
if (::stat("/dev/zt0",&stattmp))
else if (kextpid > 0) {
int exitcode = -1;
::waitpid(kextpid, &exitcode, 0);
}
::usleep(500); // give tap device driver time to start up and try again
if (::stat("/dev/zt0", &stattmp))
throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext");
}
// Try to reopen the last device we had, if we had one and it's still unused.
std::map<std::string,std::string> globalDeviceMap;
FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r");
std::map<std::string, std::string> globalDeviceMap;
FILE* devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "r");
if (devmapf) {
char buf[256];
while (fgets(buf,sizeof(buf),devmapf)) {
char *x = (char *)0;
char *y = (char *)0;
char *saveptr = (char *)0;
for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) {
if (!x) x = f;
else if (!y) y = f;
else break;
while (fgets(buf, sizeof(buf), devmapf)) {
char* x = (char*)0;
char* y = (char*)0;
char* saveptr = (char*)0;
for (char* f = Utils::stok(buf, "\r\n=", &saveptr); (f); f = Utils::stok((char*)0, "\r\n=", &saveptr)) {
if (! x)
x = f;
else if (! y)
y = f;
else
break;
}
if ((x)&&(y)&&(x[0])&&(y[0]))
if ((x) && (y) && (x[0]) && (y[0]))
globalDeviceMap[x] = y;
}
fclose(devmapf);
}
bool recalledDevice = false;
std::map<std::string,std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
std::map<std::string, std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
if (gdmEntry != globalDeviceMap.end()) {
std::string devpath("/dev/"); devpath.append(gdmEntry->second);
if (stat(devpath.c_str(),&stattmp) == 0) {
_fd = ::open(devpath.c_str(),O_RDWR);
std::string devpath("/dev/");
devpath.append(gdmEntry->second);
if (stat(devpath.c_str(), &stattmp) == 0) {
_fd = ::open(devpath.c_str(), O_RDWR);
if (_fd > 0) {
_dev = gdmEntry->second;
recalledDevice = true;
@ -378,15 +376,15 @@ MacKextEthernetTap::MacKextEthernetTap(
}
// Open the first unused tap device if we didn't recall a previous one.
if (!recalledDevice) {
for(int i=0;i<64;++i) {
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/zt%d",i);
if (stat(devpath,&stattmp))
if (! recalledDevice) {
for (int i = 0; i < 64; ++i) {
OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/zt%d", i);
if (stat(devpath, &stattmp))
throw std::runtime_error("no more TAP devices available");
_fd = ::open(devpath,O_RDWR);
_fd = ::open(devpath, O_RDWR);
if (_fd > 0) {
char foo[16];
OSUtils::ztsnprintf(foo,sizeof(foo),"zt%d",i);
OSUtils::ztsnprintf(foo, sizeof(foo), "zt%d", i);
_dev = foo;
break;
}
@ -396,43 +394,44 @@ MacKextEthernetTap::MacKextEthernetTap(
if (_fd <= 0)
throw std::runtime_error("unable to open TAP device or no more devices available");
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) {
::close(_fd);
throw std::runtime_error("unable to set flags on file descriptor for TAP device");
}
// Configure MAC address and MTU, bring interface up
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]);
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu);
OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric);
OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", _mtu);
OSUtils::ztsnprintf(metstr, sizeof(metstr), "%u", _metric);
long cpid = (long)fork();
if (cpid == 0) {
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "lladdr", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
if (exitcode) {
::close(_fd);
throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
}
}
_setIpv6Stuff(_dev.c_str(),true,false);
_setIpv6Stuff(_dev.c_str(), true, false);
// Set close-on-exec so that devices cannot persist if we fork/exec for update
fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
::pipe(_shutdownSignalPipe);
++globalTapsRunning;
globalDeviceMap[nwids] = _dev;
devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w");
devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "w");
if (devmapf) {
gdmEntry = globalDeviceMap.begin();
while (gdmEntry != globalDeviceMap.end()) {
fprintf(devmapf,"%s=%s\n",gdmEntry->first.c_str(),gdmEntry->second.c_str());
fprintf(devmapf, "%s=%s\n", gdmEntry->first.c_str(), gdmEntry->second.c_str());
++gdmEntry;
}
fclose(devmapf);
@ -445,9 +444,9 @@ MacKextEthernetTap::~MacKextEthernetTap()
{
MacDNSHelper::removeDNS(_nwid);
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
Thread::join(_thread);
for (std::thread &t : _rxThreads) {
for (std::thread& t : _rxThreads) {
t.join();
}
::close(_fd);
@ -457,18 +456,19 @@ MacKextEthernetTap::~MacKextEthernetTap()
{
Mutex::Lock _gl(globalTapCreateLock);
if (--globalTapsRunning <= 0) {
globalTapsRunning = 0; // sanity check -- should not be possible
globalTapsRunning = 0; // sanity check -- should not be possible
char tmp[16384];
sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext");
sprintf(tmp, "%s/%s", _homePath.c_str(), "tap.kext");
long kextpid = (long)fork();
if (kextpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0);
OSUtils::redirectUnixOutputs("/dev/null", (const char*)0);
::execl("/sbin/kextunload", "/sbin/kextunload", tmp, (const char*)0);
::_exit(-1);
} else if (kextpid > 0) {
}
else if (kextpid > 0) {
int exitcode = -1;
::waitpid(kextpid,&exitcode,0);
::waitpid(kextpid, &exitcode, 0);
}
}
}
@ -485,40 +485,42 @@ bool MacKextEthernetTap::enabled() const
return _enabled;
}
bool MacKextEthernetTap::addIp(const InetAddress &ip)
bool MacKextEthernetTap::addIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return false;
long cpid = (long)fork();
if (cpid == 0) {
char tmp[128];
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toString(tmp),"alias",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), (ip.ss_family == AF_INET6) ? "inet6" : "inet", ip.toString(tmp), "alias", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
return (exitcode == 0);
} // else return false...
} // else return false...
return false;
}
bool MacKextEthernetTap::removeIp(const InetAddress &ip)
bool MacKextEthernetTap::removeIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return true;
std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if (*i == ip) {
long cpid = (long)fork();
if (cpid == 0) {
char tmp[128];
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toIpString(tmp),"-alias",(const char *)0);
execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), (ip.ss_family == AF_INET6) ? "inet6" : "inet", ip.toIpString(tmp), "-alias", (const char*)0);
_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
waitpid(cpid, &exitcode, 0);
return (exitcode == 0);
}
}
@ -528,28 +530,28 @@ bool MacKextEthernetTap::removeIp(const InetAddress &ip)
std::vector<InetAddress> MacKextEthernetTap::ips() const
{
struct ifaddrs *ifa = (struct ifaddrs *)0;
struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa))
return std::vector<InetAddress>();
std::vector<InetAddress> r;
struct ifaddrs *p = ifa;
struct ifaddrs* p = ifa;
while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) {
if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch (p->ifa_addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
}
}
p = p->ifa_next;
@ -558,22 +560,22 @@ std::vector<InetAddress> MacKextEthernetTap::ips() const
if (ifa)
freeifaddrs(ifa);
std::sort(r.begin(),r.end());
r.erase(std::unique(r.begin(),r.end()),r.end());
std::sort(r.begin(), r.end());
r.erase(std::unique(r.begin(), r.end()), r.end());
return r;
}
void MacKextEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
void MacKextEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{
char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len);
if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6, 6);
*((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14, data, len);
len += 14;
::write(_fd,putBuf,len);
::write(_fd, putBuf, len);
}
}
@ -582,23 +584,23 @@ std::string MacKextEthernetTap::deviceName() const
return _dev;
}
void MacKextEthernetTap::setFriendlyName(const char *friendlyName)
void MacKextEthernetTap::setFriendlyName(const char* friendlyName)
{
}
void MacKextEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
void MacKextEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{
std::vector<MulticastGroup> newGroups;
struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0;
if (!_intl_getifmaddrs(&ifmap)) {
struct _intl_ifmaddrs *p = ifmap;
struct _intl_ifmaddrs* ifmap = (struct _intl_ifmaddrs*)0;
if (! _intl_getifmaddrs(&ifmap)) {
struct _intl_ifmaddrs* p = ifmap;
while (p) {
if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
}
p = p->ifma_next;
}
@ -606,18 +608,18 @@ void MacKextEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
}
std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end());
std::unique(newGroups.begin(),newGroups.end());
std::sort(newGroups.begin(), newGroups.end());
std::unique(newGroups.begin(), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m);
}
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m);
}
@ -631,59 +633,60 @@ void MacKextEthernetTap::setMtu(unsigned int mtu)
long cpid = (long)fork();
if (cpid == 0) {
char tmp[64];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu);
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0);
OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu);
execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "mtu", tmp, (const char*)0);
_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
waitpid(cpid, &exitcode, 0);
}
}
}
void MacKextEthernetTap::threadMain()
throw()
void MacKextEthernetTap::threadMain() throw()
{
fd_set readfds,nullfds;
MAC to,from;
int n,nfds,r;
fd_set readfds, nullfds;
MAC to, from;
int n, nfds, r;
char getBuf[ZT_MAX_MTU + 64];
Thread::sleep(500);
FD_ZERO(&readfds);
FD_ZERO(&nullfds);
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1;
r = 0;
for(;;) {
FD_SET(_shutdownSignalPipe[0],&readfds);
FD_SET(_fd,&readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
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
if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread
break;
if (FD_ISSET(_fd,&readfds)) {
n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
if (FD_ISSET(_fd, &readfds)) {
n = (int)::read(_fd, getBuf + r, sizeof(getBuf) - r);
if (n < 0) {
if ((errno != EINTR)&&(errno != ETIMEDOUT))
if ((errno != EINTR) && (errno != ETIMEDOUT))
break;
} else {
}
else {
// Some tap drivers like to send the ethernet frame and the
// payload in two chunks, so handle that by accumulating
// data until we have at least a frame.
r += n;
if (r > 14) {
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
r = _mtu + 14;
if (_enabled) {
to.setTo(getBuf,6);
from.setTo(getBuf + 6,6);
unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
to.setTo(getBuf, 6);
from.setTo(getBuf + 6, 6);
unsigned int etherType = ntohs(((const uint16_t*)getBuf)[6]);
// TODO: VLAN support
_handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14);
_handler(_arg, (void*)0, _nwid, from, to, etherType, 0, (const void*)(getBuf + 14), r - 14);
}
r = 0;
@ -693,9 +696,9 @@ void MacKextEthernetTap::threadMain()
}
}
void MacKextEthernetTap::setDns(const char *domain, const std::vector<InetAddress> &servers)
void MacKextEthernetTap::setDns(const char* domain, const std::vector<InetAddress>& servers)
{
MacDNSHelper::setDNS(_nwid, domain, servers);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,58 +14,53 @@
#ifndef ZT_MacKextEthernetTap_HPP
#define ZT_MacKextEthernetTap_HPP
#include <stdio.h>
#include <stdlib.h>
#include "../node/Constants.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "Thread.hpp"
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <thread>
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MulticastGroup.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp"
#include <vector>
namespace ZeroTier {
class MacKextEthernetTap : public EthernetTap
{
public:
class MacKextEthernetTap : public EthernetTap {
public:
MacKextEthernetTap(
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg);
virtual ~MacKextEthernetTap();
virtual void setEnabled(bool en);
virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip);
virtual bool removeIp(const InetAddress &ip);
virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers);
virtual void setDns(const char* domain, const std::vector<InetAddress>& servers);
void threadMain() throw();
void threadMain()
throw();
private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
void *_arg;
private:
void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void* _arg;
uint64_t _nwid;
Thread _thread;
std::string _homePath;
@ -79,6 +74,6 @@ private:
std::vector<std::thread> _rxThreads;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -20,20 +20,20 @@
#include <string.h>
#ifdef __WINDOWS__
#include <winsock2.h>
#include <windows.h>
#include <netioapi.h>
#include <IPHlpApi.h>
#include <netioapi.h>
#include <windows.h>
#include <winsock2.h>
#endif
#ifdef __UNIX_LIKE__
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#ifndef ZT_SDK
#include <net/route.h>
#endif
@ -45,11 +45,11 @@
#include <ifaddrs.h>
#endif
#include <vector>
#include "ManagedRoute.hpp"
#include <algorithm>
#include <utility>
#include "ManagedRoute.hpp"
#include <vector>
#ifdef __LINUX__
#include "LinuxNetLink.hpp"
#endif
@ -62,7 +62,7 @@ namespace {
// Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1
// If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't'
static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right)
static void _forkTarget(const InetAddress& t, InetAddress& left, InetAddress& right)
{
const unsigned int bits = t.netmaskBits() + 1;
left = t;
@ -70,26 +70,28 @@ static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &righ
if (bits <= 32) {
left.setPort(bits);
right = t;
reinterpret_cast<struct sockaddr_in *>(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits)));
reinterpret_cast<struct sockaddr_in*>(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits)));
right.setPort(bits);
} else {
}
else {
right.zero();
}
} else if (t.ss_family == AF_INET6) {
}
else if (t.ss_family == AF_INET6) {
if (bits <= 128) {
left.setPort(bits);
right = t;
uint8_t *b = reinterpret_cast<uint8_t *>(reinterpret_cast<struct sockaddr_in6 *>(&right)->sin6_addr.s6_addr);
uint8_t* b = reinterpret_cast<uint8_t*>(reinterpret_cast<struct sockaddr_in6*>(&right)->sin6_addr.s6_addr);
b[bits / 8] ^= 1 << (8 - (bits % 8));
right.setPort(bits);
} else {
}
else {
right.zero();
}
}
}
struct _RTE
{
struct _RTE {
InetAddress target;
InetAddress via;
char device[128];
@ -98,11 +100,11 @@ struct _RTE
bool isDefault;
};
#ifdef __BSD__ // ------------------------------------------------------------
#ifdef __BSD__ // ------------------------------------------------------------
#define ZT_ROUTING_SUPPORT_FOUND 1
#ifndef ZT_SDK
static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
static std::vector<_RTE> _getRTEs(const InetAddress& target, bool contains)
{
std::vector<_RTE> rtes;
int mib[6];
@ -114,29 +116,29 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (!sysctl(mib,6,NULL,&needed,NULL,0)) {
if (! sysctl(mib, 6, NULL, &needed, NULL, 0)) {
if (needed <= 0)
return rtes;
char *buf = (char *)::malloc(needed);
char* buf = (char*)::malloc(needed);
if (buf) {
if (!sysctl(mib,6,buf,&needed,NULL,0)) {
struct rt_msghdr *rtm;
for(char *next=buf,*end=buf+needed;next<end;) {
rtm = (struct rt_msghdr *)next;
char *saptr = (char *)(rtm + 1);
char *saend = next + rtm->rtm_msglen;
if (! sysctl(mib, 6, buf, &needed, NULL, 0)) {
struct rt_msghdr* rtm;
for (char *next = buf, *end = buf + needed; next < end;) {
rtm = (struct rt_msghdr*)next;
char* saptr = (char*)(rtm + 1);
char* saend = next + rtm->rtm_msglen;
InetAddress sa_t,sa_v;
InetAddress sa_t, sa_v;
int deviceIndex = -9999;
bool isDefault = false;
if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) {
if (((rtm->rtm_flags & RTF_LLINFO) == 0) && ((rtm->rtm_flags & RTF_HOST) == 0) && ((rtm->rtm_flags & RTF_UP) != 0) && ((rtm->rtm_flags & RTF_MULTICAST) == 0)) {
int which = 0;
while (saptr < saend) {
struct sockaddr *sa = (struct sockaddr *)saptr;
struct sockaddr* sa = (struct sockaddr*)saptr;
unsigned int salen = sa->sa_len;
if (!salen)
if (! salen)
break;
// Skip missing fields in rtm_addrs bit field
@ -150,32 +152,33 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
break;
rtm->rtm_addrs >>= 1;
switch(which++) {
switch (which++) {
case 0:
//printf("RTA_DST\n");
// printf("RTA_DST\n");
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
if ((sin6->sin6_addr.s6_addr[0] == 0xfe) && ((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) {
// BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec.
unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff);
sin6->sin6_addr.s6_addr[2] = 0;
sin6->sin6_addr.s6_addr[3] = 0;
if (!sin6->sin6_scope_id)
if (! sin6->sin6_scope_id)
sin6->sin6_scope_id = interfaceIndex;
}
#ifdef __APPLE__
isDefault = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && !(rtm->rtm_flags & RTF_IFSCOPE);
isDefault = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && ! (rtm->rtm_flags & RTF_IFSCOPE);
#endif
} else {
struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
}
else {
struct sockaddr_in* sin4 = (struct sockaddr_in*)sa;
isDefault = sin4->sin_addr.s_addr == 0;
}
sa_t = *sa;
break;
case 1:
//printf("RTA_GATEWAY\n");
switch(sa->sa_family) {
// printf("RTA_GATEWAY\n");
switch (sa->sa_family) {
case AF_LINK:
// deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index;
case AF_INET:
@ -185,53 +188,54 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
}
break;
case 2: {
//printf("RTA_NETMASK\n");
// printf("RTA_NETMASK\n");
if (sa_t.ss_family == AF_INET6) {
salen = sizeof(struct sockaddr_in6);
unsigned int bits = 0;
for(int i=0;i<16;++i) {
unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i];
for (int i = 0; i < 16; ++i) {
unsigned char c = (unsigned char)((const struct sockaddr_in6*)sa)->sin6_addr.s6_addr[i];
if (c == 0xff)
bits += 8;
else break;
else
break;
}
sa_t.setPort(bits);
} else if (sa_t.ss_family == AF_INET) {
salen = sizeof(struct sockaddr_in);
sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr));
}
} break;
/*
case 3:
//printf("RTA_GENMASK\n");
break;
case 4:
//printf("RTA_IFP\n");
break;
case 5:
//printf("RTA_IFA\n");
break;
case 6:
//printf("RTA_AUTHOR\n");
break;
*/
else if (sa_t.ss_family == AF_INET) {
salen = sizeof(struct sockaddr_in);
sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in*)sa)->sin_addr.s_addr));
}
} break;
/*
case 3:
//printf("RTA_GENMASK\n");
break;
case 4:
//printf("RTA_IFP\n");
break;
case 5:
//printf("RTA_IFA\n");
break;
case 6:
//printf("RTA_AUTHOR\n");
break;
*/
}
saptr += salen;
}
deviceIndex = rtm->rtm_index;
if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) {
if (((contains) && (sa_t.containsAddress(target))) || (sa_t == target)) {
rtes.push_back(_RTE());
rtes.back().target = sa_t;
rtes.back().via = sa_v;
rtes.back().isDefault = isDefault;
if (deviceIndex >= 0) {
if_indextoname(deviceIndex,rtes.back().device);
} else {
if_indextoname(deviceIndex, rtes.back().device);
}
else {
rtes.back().device[0] = (char)0;
}
rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount;
@ -250,60 +254,64 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
}
#endif
static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface)
static void _routeCmd(const char* op, const InetAddress& target, const InetAddress& via, const char* ifscope, const char* localInterface)
{
// char f1[1024],f2[1024]; printf("cmd %s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface);
long p = (long)fork();
if (p > 0) {
int exitcode = -1;
::waitpid(p,&exitcode,0);
} else if (p == 0) {
::waitpid(p, &exitcode, 0);
}
else if (p == 0) {
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
char ttmp[64];
char iptmp[64];
if (via) {
if ((ifscope)&&(ifscope[0])) {
if ((ifscope) && (ifscope[0])) {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s" ZT_EOL_S, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp));
fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s" ZT_EOL_S, ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp));
#endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
} else {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s %s %s %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp));
#endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, "-ifscope", ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp), (const char*)0);
}
} else if ((localInterface)&&(localInterface[0])) {
if ((ifscope)&&(ifscope[0])) {
else {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s -interface %s" ZT_EOL_S, op, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface);
fprintf(stderr, "DEBUG: route %s %s %s %s" ZT_EOL_S, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp));
#endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
} else {
::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp), (const char*)0);
}
}
else if ((localInterface) && (localInterface[0])) {
if ((ifscope) && (ifscope[0])) {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s %s %s -interface %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface);
fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s -interface %s" ZT_EOL_S, op, ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), localInterface);
#endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, "-ifscope", ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), "-interface", localInterface, (const char*)0);
}
else {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s %s %s -interface %s" ZT_EOL_S, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), localInterface);
#endif
::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), "-interface", localInterface, (const char*)0);
}
}
::_exit(-1);
}
}
#endif // __BSD__ ------------------------------------------------------------
#endif // __BSD__ ------------------------------------------------------------
#ifdef __LINUX__ // ----------------------------------------------------------
#ifdef __LINUX__ // ----------------------------------------------------------
#define ZT_ROUTING_SUPPORT_FOUND 1
// This has been replaced by LinuxNetLink
#endif // __LINUX__ ----------------------------------------------------------
#endif // __LINUX__ ----------------------------------------------------------
#ifdef __WINDOWS__ // --------------------------------------------------------
#ifdef __WINDOWS__ // --------------------------------------------------------
#define ZT_ROUTING_SUPPORT_FOUND 1
static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &interfaceIndex,const InetAddress &target,const InetAddress &via)
static bool _winRoute(bool del, const NET_LUID& interfaceLuid, const NET_IFINDEX& interfaceIndex, const InetAddress& target, const InetAddress& via)
{
MIB_IPFORWARD_ROW2 rtrow;
InitializeIpForwardEntry(&rtrow);
@ -312,22 +320,24 @@ static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &
if (target.ss_family == AF_INET) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&target)->sin_addr.S_un.S_addr;
if (via.ss_family == AF_INET) {
rtrow.NextHop.si_family = AF_INET;
rtrow.NextHop.Ipv4.sin_family = AF_INET;
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr;
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&via)->sin_addr.S_un.S_addr;
}
} else if (target.ss_family == AF_INET6) {
}
else if (target.ss_family == AF_INET6) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte,16);
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&target)->sin6_addr.u.Byte, 16);
if (via.ss_family == AF_INET6) {
rtrow.NextHop.si_family = AF_INET6;
rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte,16);
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&via)->sin6_addr.u.Byte, 16);
}
} else {
}
else {
return false;
}
rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
@ -344,19 +354,22 @@ static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &
rtrow.Origin = NlroManual;
if (del) {
return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR);
} else {
}
else {
NTSTATUS r = CreateIpForwardEntry2(&rtrow);
if (r == NO_ERROR) {
return true;
} else if (r == ERROR_OBJECT_ALREADY_EXISTS) {
}
else if (r == ERROR_OBJECT_ALREADY_EXISTS) {
return (SetIpForwardEntry2(&rtrow) == NO_ERROR);
} else {
}
else {
return false;
}
}
}
static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &interfaceIndex, const InetAddress &target, const InetAddress &via)
static bool _winHasRoute(const NET_LUID& interfaceLuid, const NET_IFINDEX& interfaceIndex, const InetAddress& target, const InetAddress& via)
{
MIB_IPFORWARD_ROW2 rtrow;
InitializeIpForwardEntry(&rtrow);
@ -365,22 +378,24 @@ static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &inter
if (target.ss_family == AF_INET) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&target)->sin_addr.S_un.S_addr;
if (via.ss_family == AF_INET) {
rtrow.NextHop.si_family = AF_INET;
rtrow.NextHop.Ipv4.sin_family = AF_INET;
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr;
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&via)->sin_addr.S_un.S_addr;
}
} else if (target.ss_family == AF_INET6) {
}
else if (target.ss_family == AF_INET6) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte, 16);
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&target)->sin6_addr.u.Byte, 16);
if (via.ss_family == AF_INET6) {
rtrow.NextHop.si_family = AF_INET6;
rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte, 16);
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&via)->sin6_addr.u.Byte, 16);
}
} else {
}
else {
return false;
}
rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
@ -388,15 +403,16 @@ static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &inter
return (GetIpForwardEntry2(&rtrow) == NO_ERROR);
}
#endif // __WINDOWS__ --------------------------------------------------------
#endif // __WINDOWS__ --------------------------------------------------------
#ifndef ZT_ROUTING_SUPPORT_FOUND
#error "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS."
#error \
"ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS."
#endif
} // anonymous namespace
} // anonymous namespace
ManagedRoute::ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device)
ManagedRoute::ManagedRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* device)
{
_target = target;
_via = via;
@ -404,17 +420,19 @@ ManagedRoute::ManagedRoute(const InetAddress &target,const InetAddress &via,cons
if (_via.ss_family == AF_INET) {
_via.setPort(32);
} else if (_via.ss_family == AF_INET6) {
}
else if (_via.ss_family == AF_INET6) {
_via.setPort(128);
}
if (_src.ss_family == AF_INET) {
_src.setPort(32);
} else if (_src.ss_family == AF_INET6) {
}
else if (_src.ss_family == AF_INET6) {
_src.setPort(128);
}
Utils::scopy(_device,sizeof(_device),device);
Utils::scopy(_device, sizeof(_device), device);
_systemDevice[0] = (char)0;
}
@ -440,26 +458,27 @@ bool ManagedRoute::sync()
{
#ifdef __WINDOWS__
NET_LUID interfaceLuid;
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
NET_IFINDEX interfaceIndex = -1;
if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR)
if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR)
return false;
#endif
InetAddress leftt,rightt;
if (_target.netmaskBits() == 0) // bifurcate only the default route
_forkTarget(_target,leftt,rightt);
else leftt = _target;
InetAddress leftt, rightt;
if (_target.netmaskBits() == 0) // bifurcate only the default route
_forkTarget(_target, leftt, rightt);
else
leftt = _target;
#ifdef __BSD__ // ------------------------------------------------------------
#ifdef __BSD__ // ------------------------------------------------------------
if (_device[0]) {
bool haveDevice = false;
struct ifaddrs *ifa = (struct ifaddrs *)0;
if (!getifaddrs(&ifa)) {
struct ifaddrs *p = ifa;
struct ifaddrs* ifa = (struct ifaddrs*)0;
if (! getifaddrs(&ifa)) {
struct ifaddrs* p = ifa;
while (p) {
if ((p->ifa_name)&&(!strcmp(_device, p->ifa_name))) {
if ((p->ifa_name) && (! strcmp(_device, p->ifa_name))) {
haveDevice = true;
break;
}
@ -467,112 +486,113 @@ bool ManagedRoute::sync()
}
freeifaddrs(ifa);
}
if (!haveDevice)
if (! haveDevice)
return false;
}
std::vector<_RTE> rtes(_getRTEs(_target,false));
std::vector<_RTE> rtes(_getRTEs(_target, false));
bool hasRoute = false;
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
hasRoute = _target == r->target && _via.ipOnly() == r->via.ipOnly() && (strcmp(r->device,_device) == 0);
if (hasRoute) { break; }
for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) {
hasRoute = _target == r->target && _via.ipOnly() == r->via.ipOnly() && (strcmp(r->device, _device) == 0);
if (hasRoute) {
break;
}
}
// char buf[255];
// fprintf(stderr, "hasRoute %d %s\n", !!hasRoute, _target.toString(buf));
if (!hasRoute) {
if (_target && _target.netmaskBits() == 0) { // Allow Default
if (! hasRoute) {
if (_target && _target.netmaskBits() == 0) { // Allow Default
InetAddress newSystemVia;
char newSystemDevice[128];
newSystemDevice[0] = (char)0;
// if our routes got deleted
// delete the systemd via that we had added with -ifscope
if (_systemVia && !!_systemDevice[0]) {
_routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0);
if (_systemVia && ! ! _systemDevice[0]) {
_routeCmd("delete", _target, _systemVia, _systemDevice, (const char*)0);
}
_systemVia = newSystemVia;
Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice);
Utils::scopy(_systemDevice, sizeof(_systemDevice), newSystemDevice);
// If macos has a network hiccup, it deletes what the route we set, and it's own physical routes.
// if !hasRoute (our 0.0.0.0 has been deleted), the OS has changed stuff
// So don't assume _systemX are valid anymore. Always get for _system{Via,Device}
// Find system default route that this route should override
// We need to put it back when default route is turned off
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) {
if (r->via) {
if ( r->isDefault == 1 && (strcmp(r->device,_device) != 0) ) {
if (r->isDefault == 1 && (strcmp(r->device, _device) != 0)) {
// char buf[255];
// fprintf(stderr, "system device1 %s %s\n", r->via.toString(buf), r->device);
newSystemVia = r->via;
Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device);
Utils::scopy(newSystemDevice, sizeof(newSystemDevice), r->device);
break;
}
}
}
if (newSystemVia) { _systemVia = newSystemVia; }
if (newSystemVia) {
_systemVia = newSystemVia;
}
if (newSystemDevice[0]) {
Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice);
Utils::scopy(_systemDevice, sizeof(_systemDevice), newSystemDevice);
}
// if there's no newSystemVia, the OS might not have
// ipv4 or ipv6 connectivity.
// we should still add our ZeroTier ipv4 or 6 routes though
if (!!_systemVia && !!_systemDevice[0]) {
_routeCmd("delete",_target,_systemVia,(const char *)0,(const char *)0);
if (! ! _systemVia && ! ! _systemDevice[0]) {
_routeCmd("delete", _target, _systemVia, (const char*)0, (const char*)0);
}
_routeCmd("add",_target,_via,(const char *)0,(const char *)0);
_routeCmd("add", _target, _via, (const char*)0, (const char*)0);
if (!!_systemVia && !!_systemDevice[0]) {
_routeCmd("add",_target,_systemVia,_systemDevice,(const char *)0);
if (! ! _systemVia && ! ! _systemDevice[0]) {
_routeCmd("add", _target, _systemVia, _systemDevice, (const char*)0);
}
_applied[_target] = true;
} else {
}
else {
// Do Non-Default route commands
_applied[_target] = true;
_routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
_routeCmd("add", leftt, _via, (const char*)0, (_via) ? (const char*)0 : _device);
}
}
#endif // __BSD__ ------------------------------------------------------------
#endif // __BSD__ ------------------------------------------------------------
#ifdef __LINUX__ // ----------------------------------------------------------
#ifdef __LINUX__ // ----------------------------------------------------------
if ((leftt)&&(!LinuxNetLink::getInstance().routeIsSet(leftt,_via,_src,_device))) {
_applied[leftt] = false; // boolean unused
if ((leftt) && (! LinuxNetLink::getInstance().routeIsSet(leftt, _via, _src, _device))) {
_applied[leftt] = false; // boolean unused
LinuxNetLink::getInstance().addRoute(leftt, _via, _src, _device);
}
if ((rightt)&&(!LinuxNetLink::getInstance().routeIsSet(rightt,_via,_src,_device))) {
_applied[rightt] = false; // boolean unused
if ((rightt) && (! LinuxNetLink::getInstance().routeIsSet(rightt, _via, _src, _device))) {
_applied[rightt] = false; // boolean unused
LinuxNetLink::getInstance().addRoute(rightt, _via, _src, _device);
}
#endif // __LINUX__ ----------------------------------------------------------
#endif // __LINUX__ ----------------------------------------------------------
#ifdef __WINDOWS__ // --------------------------------------------------------
#ifdef __WINDOWS__ // --------------------------------------------------------
if ( (!_applied.count(leftt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,leftt,_via)) ) {
_applied[leftt] = false; // boolean unused
_winRoute(false,interfaceLuid,interfaceIndex,leftt,_via);
if ((! _applied.count(leftt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, leftt, _via))) {
_applied[leftt] = false; // boolean unused
_winRoute(false, interfaceLuid, interfaceIndex, leftt, _via);
}
if ( (rightt) && ( (!_applied.count(rightt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,rightt,_via)) ) ) {
_applied[rightt] = false; // boolean unused
_winRoute(false,interfaceLuid,interfaceIndex,rightt,_via);
if ((rightt) && ((! _applied.count(rightt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, rightt, _via)))) {
_applied[rightt] = false; // boolean unused
_winRoute(false, interfaceLuid, interfaceIndex, rightt, _via);
}
#endif // __WINDOWS__ --------------------------------------------------------
#endif // __WINDOWS__ --------------------------------------------------------
return true;
}
@ -582,39 +602,39 @@ void ManagedRoute::remove()
{
#ifdef __WINDOWS__
NET_LUID interfaceLuid;
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
NET_IFINDEX interfaceIndex = -1;
if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR)
if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR)
return;
#endif
#ifdef __BSD__
#endif // __BSD__ ------------------------------------------------------------
#endif // __BSD__ ------------------------------------------------------------
for(std::map<InetAddress,bool>::iterator r(_applied.begin());r!=_applied.end();++r) {
#ifdef __BSD__ // ------------------------------------------------------------
for (std::map<InetAddress, bool>::iterator r(_applied.begin()); r != _applied.end(); ++r) {
#ifdef __BSD__ // ------------------------------------------------------------
if (_target && _target.netmaskBits() == 0) {
_routeCmd("delete",_target,_via,(const char *)0,(const char *)0);
_routeCmd("delete", _target, _via, (const char*)0, (const char*)0);
if (_systemVia && _systemDevice[0]) {
_routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0);
_routeCmd("add",_target,_systemVia,(const char *)0,(const char *)0);
_routeCmd("delete", _target, _systemVia, _systemDevice, (const char*)0);
_routeCmd("add", _target, _systemVia, (const char*)0, (const char*)0);
}
} else {
_routeCmd("delete",_target,_via, (const char *)0, _via ? (const char *)0 : _device);
}
break;
#endif // __BSD__ ------------------------------------------------------------
}
else {
_routeCmd("delete", _target, _via, (const char*)0, _via ? (const char*)0 : _device);
}
break;
#endif // __BSD__ ------------------------------------------------------------
#ifdef __LINUX__ // ----------------------------------------------------------
#ifdef __LINUX__ // ----------------------------------------------------------
//_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device);
LinuxNetLink::getInstance().delRoute(r->first,_via,_src,(_via) ? (const char *)0 : _device);
#endif // __LINUX__ ----------------------------------------------------------
LinuxNetLink::getInstance().delRoute(r->first, _via, _src, (_via) ? (const char*)0 : _device);
#endif // __LINUX__ ----------------------------------------------------------
#ifdef __WINDOWS__ // --------------------------------------------------------
_winRoute(true,interfaceLuid,interfaceIndex,r->first,_via);
#endif // __WINDOWS__ --------------------------------------------------------
#ifdef __WINDOWS__ // --------------------------------------------------------
_winRoute(true, interfaceLuid, interfaceIndex, r->first, _via);
#endif // __WINDOWS__ --------------------------------------------------------
}
_target.zero();
@ -625,4 +645,4 @@ void ManagedRoute::remove()
_applied.clear();
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,29 +14,27 @@
#ifndef ZT_MANAGEDROUTE_HPP
#define ZT_MANAGEDROUTE_HPP
#include "../node/AtomicCounter.hpp"
#include "../node/InetAddress.hpp"
#include "../node/SharedPtr.hpp"
#include "../node/Utils.hpp"
#include <map>
#include <stdexcept>
#include <stdlib.h>
#include <string.h>
#include "../node/InetAddress.hpp"
#include "../node/Utils.hpp"
#include "../node/SharedPtr.hpp"
#include "../node/AtomicCounter.hpp"
#include <stdexcept>
#include <vector>
#include <map>
namespace ZeroTier {
/**
* A ZT-managed route that used C++ RAII semantics to automatically clean itself up on deallocate
*/
class ManagedRoute
{
class ManagedRoute {
friend class SharedPtr<ManagedRoute>;
public:
ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device);
public:
ManagedRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* device);
~ManagedRoute();
/**
@ -58,26 +56,43 @@ public:
*/
void remove();
inline const InetAddress &target() const { return _target; }
inline const InetAddress &via() const { return _via; }
inline const InetAddress &src() const { return _src; }
inline const char *device() const { return _device; }
inline const InetAddress& target() const
{
return _target;
}
inline const InetAddress& via() const
{
return _via;
}
inline const InetAddress& src() const
{
return _src;
}
inline const char* device() const
{
return _device;
}
private:
ManagedRoute(const ManagedRoute &) {}
inline ManagedRoute &operator=(const ManagedRoute &) { return *this; }
private:
ManagedRoute(const ManagedRoute&)
{
}
inline ManagedRoute& operator=(const ManagedRoute&)
{
return *this;
}
InetAddress _target;
InetAddress _via;
InetAddress _src;
InetAddress _systemVia; // for route overrides
std::map<InetAddress,bool> _applied; // routes currently applied
InetAddress _systemVia; // for route overrides
std::map<InetAddress, bool> _applied; // routes currently applied
char _device[128];
char _systemDevice[128]; // for route overrides
char _systemDevice[128]; // for route overrides
AtomicCounter __refCount;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,248 +12,240 @@
/****/
#include "NeighborDiscovery.hpp"
#include "OSUtils.hpp"
#include "../include/ZeroTierOne.h"
#include "OSUtils.hpp"
#include <assert.h>
namespace ZeroTier {
uint16_t calc_checksum (uint16_t *addr, int len)
uint16_t calc_checksum(uint16_t* addr, int len)
{
int count = len;
uint32_t sum = 0;
uint16_t answer = 0;
int count = len;
uint32_t sum = 0;
uint16_t answer = 0;
// Sum up 2-byte values until none or only one byte left.
while (count > 1) {
sum += *(addr++);
count -= 2;
}
// Sum up 2-byte values until none or only one byte left.
while (count > 1) {
sum += *(addr++);
count -= 2;
}
// Add left-over byte, if any.
if (count > 0) {
sum += *(uint8_t *) addr;
}
// Add left-over byte, if any.
if (count > 0) {
sum += *(uint8_t*)addr;
}
// Fold 32-bit sum into 16 bits; we lose information by doing this,
// increasing the chances of a collision.
// sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
// Fold 32-bit sum into 16 bits; we lose information by doing this,
// increasing the chances of a collision.
// sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
// Checksum is one's compliment of sum.
answer = ~sum;
// Checksum is one's compliment of sum.
answer = ~sum;
return (answer);
return (answer);
}
struct _pseudo_header {
uint8_t sourceAddr[16];
uint8_t targetAddr[16];
uint32_t length;
uint8_t zeros[3];
uint8_t next; // 58
uint8_t sourceAddr[16];
uint8_t targetAddr[16];
uint32_t length;
uint8_t zeros[3];
uint8_t next; // 58
};
struct _option {
_option(int optionType)
: type(optionType)
, length(8)
{
memset(mac, 0, sizeof(mac));
}
_option(int optionType) : type(optionType), length(8)
{
memset(mac, 0, sizeof(mac));
}
uint8_t type;
uint8_t length;
uint8_t mac[6];
uint8_t type;
uint8_t length;
uint8_t mac[6];
};
struct _neighbor_solicitation {
_neighbor_solicitation()
: type(135)
, code(0)
, checksum(0)
, option(1)
{
memset(&reserved, 0, sizeof(reserved));
memset(target, 0, sizeof(target));
}
_neighbor_solicitation() : type(135), code(0), checksum(0), option(1)
{
memset(&reserved, 0, sizeof(reserved));
memset(target, 0, sizeof(target));
}
void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) {
_pseudo_header ph;
memset(&ph, 0, sizeof(_pseudo_header));
const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
void calculateChecksum(const sockaddr_storage& sourceIp, const sockaddr_storage& destIp)
{
_pseudo_header ph;
memset(&ph, 0, sizeof(_pseudo_header));
const sockaddr_in6* src = (const sockaddr_in6*)&sourceIp;
const sockaddr_in6* dest = (const sockaddr_in6*)&destIp;
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
ph.next = 58;
ph.length = htonl(sizeof(_neighbor_solicitation));
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
ph.next = 58;
ph.length = htonl(sizeof(_neighbor_solicitation));
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation);
uint8_t *tmp = (uint8_t*)malloc(len);
memcpy(tmp, &ph, sizeof(_pseudo_header));
memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation));
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation);
uint8_t* tmp = (uint8_t*)malloc(len);
memcpy(tmp, &ph, sizeof(_pseudo_header));
memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation));
checksum = calc_checksum((uint16_t*)tmp, (int)len);
checksum = calc_checksum((uint16_t*)tmp, (int)len);
free(tmp);
tmp = NULL;
}
free(tmp);
tmp = NULL;
}
uint8_t type; // 135
uint8_t code; // 0
uint16_t checksum;
uint32_t reserved;
uint8_t target[16];
_option option;
uint8_t type; // 135
uint8_t code; // 0
uint16_t checksum;
uint32_t reserved;
uint8_t target[16];
_option option;
};
struct _neighbor_advertisement {
_neighbor_advertisement()
: type(136)
, code(0)
, checksum(0)
, rso(0x40)
, option(2)
{
memset(padding, 0, sizeof(padding));
memset(target, 0, sizeof(target));
}
_neighbor_advertisement() : type(136), code(0), checksum(0), rso(0x40), option(2)
{
memset(padding, 0, sizeof(padding));
memset(target, 0, sizeof(target));
}
void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) {
_pseudo_header ph;
memset(&ph, 0, sizeof(_pseudo_header));
const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
void calculateChecksum(const sockaddr_storage& sourceIp, const sockaddr_storage& destIp)
{
_pseudo_header ph;
memset(&ph, 0, sizeof(_pseudo_header));
const sockaddr_in6* src = (const sockaddr_in6*)&sourceIp;
const sockaddr_in6* dest = (const sockaddr_in6*)&destIp;
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
ph.next = 58;
ph.length = htonl(sizeof(_neighbor_advertisement));
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
ph.next = 58;
ph.length = htonl(sizeof(_neighbor_advertisement));
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement);
uint8_t *tmp = (uint8_t*)malloc(len);
memcpy(tmp, &ph, sizeof(_pseudo_header));
memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement));
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement);
uint8_t* tmp = (uint8_t*)malloc(len);
memcpy(tmp, &ph, sizeof(_pseudo_header));
memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement));
checksum = calc_checksum((uint16_t*)tmp, (int)len);
checksum = calc_checksum((uint16_t*)tmp, (int)len);
free(tmp);
tmp = NULL;
}
free(tmp);
tmp = NULL;
}
uint8_t type; // 136
uint8_t code; // 0
uint16_t checksum;
uint8_t rso;
uint8_t padding[3];
uint8_t target[16];
_option option;
uint8_t type; // 136
uint8_t code; // 0
uint16_t checksum;
uint8_t rso;
uint8_t padding[3];
uint8_t target[16];
_option option;
};
NeighborDiscovery::NeighborDiscovery()
: _cache(256)
, _lastCleaned(OSUtils::now())
{}
void NeighborDiscovery::addLocal(const sockaddr_storage &address, const MAC &mac)
NeighborDiscovery::NeighborDiscovery() : _cache(256), _lastCleaned(OSUtils::now())
{
_NDEntry &e = _cache[InetAddress(address)];
e.lastQuerySent = 0;
e.lastResponseReceived = 0;
e.mac = mac;
e.local = true;
}
void NeighborDiscovery::remove(const sockaddr_storage &address)
void NeighborDiscovery::addLocal(const sockaddr_storage& address, const MAC& mac)
{
_cache.erase(InetAddress(address));
_NDEntry& e = _cache[InetAddress(address)];
e.lastQuerySent = 0;
e.lastResponseReceived = 0;
e.mac = mac;
e.local = true;
}
sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest)
void NeighborDiscovery::remove(const sockaddr_storage& address)
{
assert(sizeof(_neighbor_solicitation) == 28);
assert(sizeof(_neighbor_advertisement) == 32);
const uint64_t now = OSUtils::now();
sockaddr_storage ip = {0};
if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) {
// respond to Neighbor Solicitation request for local address
_neighbor_solicitation solicitation;
memcpy(&solicitation, nd, len);
InetAddress targetAddress(solicitation.target, 16, 0);
_NDEntry *targetEntry = _cache.get(targetAddress);
if (targetEntry && targetEntry->local) {
_neighbor_advertisement adv;
targetEntry->mac.copyTo(adv.option.mac, 6);
memcpy(adv.target, solicitation.target, 16);
adv.calculateChecksum(localIp, targetAddress);
memcpy(response, &adv, sizeof(_neighbor_advertisement));
responseLen = sizeof(_neighbor_advertisement);
responseDest.setTo(solicitation.option.mac, 6);
}
} else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) {
_neighbor_advertisement adv;
memcpy(&adv, nd, len);
InetAddress responseAddress(adv.target, 16, 0);
_NDEntry *queryEntry = _cache.get(responseAddress);
if(queryEntry && !queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) {
queryEntry->lastResponseReceived = now;
queryEntry->mac.setTo(adv.option.mac, 6);
ip = responseAddress;
}
}
if ((now - _lastCleaned) >= ZT_ND_EXPIRE) {
_lastCleaned = now;
Hashtable<InetAddress, _NDEntry>::Iterator i(_cache);
InetAddress *k = NULL;
_NDEntry *v = NULL;
while (i.next(k, v)) {
if(!v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) {
_cache.erase(*k);
}
}
}
return ip;
_cache.erase(InetAddress(address));
}
MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest)
sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t* nd, unsigned int len, const sockaddr_storage& localIp, uint8_t* response, unsigned int& responseLen, MAC& responseDest)
{
const uint64_t now = OSUtils::now();
assert(sizeof(_neighbor_solicitation) == 28);
assert(sizeof(_neighbor_advertisement) == 32);
InetAddress localAddress(localIp);
localAddress.setPort(0);
InetAddress targetAddress(targetIp);
targetAddress.setPort(0);
const uint64_t now = OSUtils::now();
sockaddr_storage ip = { 0 };
_NDEntry &e = _cache[targetAddress];
if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) {
// respond to Neighbor Solicitation request for local address
_neighbor_solicitation solicitation;
memcpy(&solicitation, nd, len);
InetAddress targetAddress(solicitation.target, 16, 0);
_NDEntry* targetEntry = _cache.get(targetAddress);
if (targetEntry && targetEntry->local) {
_neighbor_advertisement adv;
targetEntry->mac.copyTo(adv.option.mac, 6);
memcpy(adv.target, solicitation.target, 16);
adv.calculateChecksum(localIp, targetAddress);
memcpy(response, &adv, sizeof(_neighbor_advertisement));
responseLen = sizeof(_neighbor_advertisement);
responseDest.setTo(solicitation.option.mac, 6);
}
}
else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) {
_neighbor_advertisement adv;
memcpy(&adv, nd, len);
InetAddress responseAddress(adv.target, 16, 0);
_NDEntry* queryEntry = _cache.get(responseAddress);
if (queryEntry && ! queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) {
queryEntry->lastResponseReceived = now;
queryEntry->mac.setTo(adv.option.mac, 6);
ip = responseAddress;
}
}
if ( (e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) ||
(!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) {
e.lastQuerySent = now;
if ((now - _lastCleaned) >= ZT_ND_EXPIRE) {
_lastCleaned = now;
Hashtable<InetAddress, _NDEntry>::Iterator i(_cache);
InetAddress* k = NULL;
_NDEntry* v = NULL;
while (i.next(k, v)) {
if (! v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) {
_cache.erase(*k);
}
}
}
_neighbor_solicitation ns;
memcpy(ns.target, targetAddress.rawIpData(), 16);
localMac.copyTo(ns.option.mac, 6);
ns.calculateChecksum(localIp, targetIp);
if (e.mac) {
queryDest = e.mac;
} else {
queryDest = (uint64_t)0xffffffffffffULL;
}
} else {
queryLen = 0;
queryDest.zero();
}
return e.mac;
return ip;
}
MAC NeighborDiscovery::query(const MAC& localMac, const sockaddr_storage& localIp, const sockaddr_storage& targetIp, uint8_t* query, unsigned int& queryLen, MAC& queryDest)
{
const uint64_t now = OSUtils::now();
InetAddress localAddress(localIp);
localAddress.setPort(0);
InetAddress targetAddress(targetIp);
targetAddress.setPort(0);
_NDEntry& e = _cache[targetAddress];
if ((e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) || (! e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) {
e.lastQuerySent = now;
_neighbor_solicitation ns;
memcpy(ns.target, targetAddress.rawIpData(), 16);
localMac.copyTo(ns.option.mac, 6);
ns.calculateChecksum(localIp, targetIp);
if (e.mac) {
queryDest = e.mac;
}
else {
queryDest = (uint64_t)0xffffffffffffULL;
}
}
else {
queryLen = 0;
queryDest.zero();
}
return e.mac;
}
} // namespace ZeroTier

View file

@ -15,9 +15,8 @@
#define ZT_NEIGHBORDISCOVERY_HPP
#include "../node/Hashtable.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#define ZT_ND_QUERY_INTERVAL 2000
@ -25,47 +24,46 @@
#define ZT_ND_EXPIRE 600000
namespace ZeroTier {
class NeighborDiscovery
{
public:
NeighborDiscovery();
class NeighborDiscovery {
public:
NeighborDiscovery();
/**
* Set a local IP entry that we should respond to Neighbor Requests withPrefix64k
*
* @param mac Our local MAC address
* @param ip Our IPv6 address
*/
void addLocal(const sockaddr_storage &address, const MAC &mac);
/**
* Set a local IP entry that we should respond to Neighbor Requests withPrefix64k
*
* @param mac Our local MAC address
* @param ip Our IPv6 address
*/
void addLocal(const sockaddr_storage& address, const MAC& mac);
/**
* Delete a local IP entry or cached Neighbor entry
*
* @param address IPv6 address to remove
*/
void remove(const sockaddr_storage &address);
/**
* Delete a local IP entry or cached Neighbor entry
*
* @param address IPv6 address to remove
*/
void remove(const sockaddr_storage& address);
sockaddr_storage processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest);
sockaddr_storage processIncomingND(const uint8_t* nd, unsigned int len, const sockaddr_storage& localIp, uint8_t* response, unsigned int& responseLen, MAC& responseDest);
MAC query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest);
MAC query(const MAC& localMac, const sockaddr_storage& localIp, const sockaddr_storage& targetIp, uint8_t* query, unsigned int& queryLen, MAC& queryDest);
private:
struct _NDEntry
{
_NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) {}
uint64_t lastQuerySent;
uint64_t lastResponseReceived;
MAC mac;
bool local;
};
private:
struct _NDEntry {
_NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false)
{
}
uint64_t lastQuerySent;
uint64_t lastResponseReceived;
MAC mac;
bool local;
};
Hashtable<InetAddress, _NDEntry> _cache;
uint64_t _lastCleaned;
Hashtable<InetAddress, _NDEntry> _cache;
uint64_t _lastCleaned;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,79 +11,73 @@
*/
/****/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "NetBSDEthernetTap.hpp"
#include <unistd.h>
#include <signal.h>
#include "../node/Constants.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include "freebsd_getifmaddrs.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <algorithm>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <iostream>
#include <map>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/route.h>
#include <sys/sysctl.h>
#include "freebsd_getifmaddrs.h"
#include <string>
#include <map>
#include <netinet/in.h>
#include <set>
#include <algorithm>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <utility>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "OSUtils.hpp"
#include "NetBSDEthernetTap.hpp"
#include <iostream>
using namespace std;
#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv"
// ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
namespace ZeroTier {
NetBSDEthernetTap::NetBSDEthernetTap(
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg) :
_handler(handler),
_arg(arg),
_nwid(nwid),
_mtu(mtu),
_metric(metric),
_fd(0),
_enabled(true)
const char* friendlyName,
void (*handler)(void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg)
: _handler(handler)
, _arg(arg)
, _nwid(nwid)
, _mtu(mtu)
, _metric(metric)
, _fd(0)
, _enabled(true)
{
static Mutex globalTapCreateLock;
char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32];
char devpath[64], ethaddr[64], mtustr[32], metstr[32], tmpdevname[32];
struct stat stattmp;
Mutex::Lock _gl(globalTapCreateLock);
@ -93,43 +87,50 @@ NetBSDEthernetTap::NetBSDEthernetTap(
// we can create /dev/tap*
std::vector<std::string> devFiles(OSUtils::listDirectory("/dev"));
for(int i=9993;i<(9993+128);++i) {
Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i);
Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname);
if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) {
for (int i = 9993; i < (9993 + 128); ++i) {
Utils::snprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i);
Utils::snprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname);
if (std::find(devFiles.begin(), devFiles.end(), std::string(tmpdevname)) == devFiles.end()) {
long cpid = (long)vfork();
if (cpid == 0) {
::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "create", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
} else throw std::runtime_error("fork() failed");
::waitpid(cpid, &exitcode, 0);
}
else
throw std::runtime_error("fork() failed");
cpid = (long)vfork();
if (cpid == 0) {
string tmp;
sprintf((char*)tmp.c_str(), "%d", i);
string minor = tmp.c_str();
::execl("/sbin/mknod","/sbin/mknod",devpath,"c","169",minor.c_str(),(const char *)0);
::execl("/sbin/mknod", "/sbin/mknod", devpath, "c", "169", minor.c_str(), (const char*)0);
// http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/conf/majors
// major 169 => tap
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
} else throw std::runtime_error("fork() failed");
::waitpid(cpid, &exitcode, 0);
}
else
throw std::runtime_error("fork() failed");
cerr<<"created device "<<devpath<<endl;
cerr << "created device " << devpath << endl;
_dev = tmpdevname;
_fd = ::open( devpath,O_RDWR);
if (!stat(devpath,&stattmp)) {
_fd = ::open(devpath, O_RDWR);
if (! stat(devpath, &stattmp)) {
if (_fd > 0)
break;
else
throw std::runtime_error("unable to open created tap device ");
} else {
}
else {
throw std::runtime_error("cannot find /dev node for newly created tap device");
}
}
@ -138,22 +139,23 @@ NetBSDEthernetTap::NetBSDEthernetTap(
if (_fd <= 0)
throw std::runtime_error("unable to open TAP device or no more devices available");
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) {
::close(_fd);
throw std::runtime_error("unable to set flags on file descriptor for TAP device");
}
// Configure MAC address and MTU, bring interface up
Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]);
Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu);
Utils::snprintf(metstr,sizeof(metstr),"%u",_metric);
Utils::snprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
Utils::snprintf(mtustr, sizeof(mtustr), "%u", _mtu);
Utils::snprintf(metstr, sizeof(metstr), "%u", _metric);
long cpid = (long)vfork();
if (cpid == 0) {
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"link",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "link", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
if (exitcode) {
::close(_fd);
throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
@ -164,13 +166,14 @@ NetBSDEthernetTap::NetBSDEthernetTap(
// https://wiki.netbsd.org/tutorials/faking_a_mac_address/
cpid = (long)vfork();
if (cpid == 0) {
string cmdline = "net.link.tap."+string(_dev);
cmdline += "="+string(ethaddr);
::execl("/sbin/sysctl","/sbin/sysctl","-w",cmdline.c_str(),(const char *)0);
string cmdline = "net.link.tap." + string(_dev);
cmdline += "=" + string(ethaddr);
::execl("/sbin/sysctl", "/sbin/sysctl", "-w", cmdline.c_str(), (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
if (exitcode) {
::close(_fd);
throw std::runtime_error("sysctl failure setting link-layer address and activating tap interface");
@ -178,17 +181,16 @@ NetBSDEthernetTap::NetBSDEthernetTap(
}
// Set close-on-exec so that devices cannot persist if we fork/exec for update
fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
::pipe(_shutdownSignalPipe);
_thread = Thread::start(this);
}
NetBSDEthernetTap::~NetBSDEthernetTap()
{
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
Thread::join(_thread);
::close(_fd);
::close(_shutdownSignalPipe[0]);
@ -196,23 +198,27 @@ NetBSDEthernetTap::~NetBSDEthernetTap()
long cpid = (long)vfork();
if (cpid == 0) {
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "destroy", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
}
cpid = (long)vfork();
if (cpid == 0) {
string tmp="/dev/";
tmp+=_dev.c_str();
::execl("/bin/rm","/bin/rm",tmp.c_str(),(const char *)0);
string tmp = "/dev/";
tmp += _dev.c_str();
::execl("/bin/rm", "/bin/rm", tmp.c_str(), (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
} else throw std::runtime_error("fork() failed");
::waitpid(cpid, &exitcode, 0);
}
else
throw std::runtime_error("fork() failed");
}
void NetBSDEthernetTap::setEnabled(bool en)
@ -225,56 +231,58 @@ bool NetBSDEthernetTap::enabled() const
return _enabled;
}
static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
static bool ___removeIp(const std::string& _dev, const InetAddress& ip)
{
long cpid = (long)vfork();
if (cpid == 0) {
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0);
execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "inet", ip.toIpString().c_str(), "-alias", (const char*)0);
_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
waitpid(cpid, &exitcode, 0);
return (exitcode == 0);
}
return false; // never reached, make compiler shut up about return value
return false; // never reached, make compiler shut up about return value
}
bool NetBSDEthernetTap::addIp(const InetAddress &ip)
bool NetBSDEthernetTap::addIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return false;
std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end())
return true; // IP/netmask already assigned
if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end())
return true; // IP/netmask already assigned
// Remove and reconfigure if address is the same but netmask is different
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
if (___removeIp(_dev,*i))
for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if ((i->ipsEqual(ip)) && (i->netmaskBits() != ip.netmaskBits())) {
if (___removeIp(_dev, *i))
break;
}
}
long cpid = (long)vfork();
if (cpid == 0) {
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0);
::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString().c_str(), "alias", (const char*)0);
::_exit(-1);
} else if (cpid > 0) {
}
else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
::waitpid(cpid, &exitcode, 0);
return (exitcode == 0);
}
return false;
}
bool NetBSDEthernetTap::removeIp(const InetAddress &ip)
bool NetBSDEthernetTap::removeIp(const InetAddress& ip)
{
if (!ip)
if (! ip)
return false;
std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) {
if (___removeIp(_dev,ip))
if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) {
if (___removeIp(_dev, ip))
return true;
}
return false;
@ -282,28 +290,28 @@ bool NetBSDEthernetTap::removeIp(const InetAddress &ip)
std::vector<InetAddress> NetBSDEthernetTap::ips() const
{
struct ifaddrs *ifa = (struct ifaddrs *)0;
struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa))
return std::vector<InetAddress>();
std::vector<InetAddress> r;
struct ifaddrs *p = ifa;
struct ifaddrs* p = ifa;
while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) {
if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch (p->ifa_addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break;
case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break;
}
}
p = p->ifa_next;
@ -312,22 +320,22 @@ std::vector<InetAddress> NetBSDEthernetTap::ips() const
if (ifa)
freeifaddrs(ifa);
std::sort(r.begin(),r.end());
std::unique(r.begin(),r.end());
std::sort(r.begin(), r.end());
std::unique(r.begin(), r.end());
return r;
}
void NetBSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
void NetBSDEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{
char putBuf[4096];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len);
if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6, 6);
*((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14, data, len);
len += 14;
::write(_fd,putBuf,len);
::write(_fd, putBuf, len);
}
}
@ -336,23 +344,23 @@ std::string NetBSDEthernetTap::deviceName() const
return _dev;
}
void NetBSDEthernetTap::setFriendlyName(const char *friendlyName)
void NetBSDEthernetTap::setFriendlyName(const char* friendlyName)
{
}
void NetBSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
void NetBSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{
std::vector<MulticastGroup> newGroups;
struct ifmaddrs *ifmap = (struct ifmaddrs *)0;
if (!getifmaddrs(&ifmap)) {
struct ifmaddrs *p = ifmap;
struct ifmaddrs* ifmap = (struct ifmaddrs*)0;
if (! getifmaddrs(&ifmap)) {
struct ifmaddrs* p = ifmap;
while (p) {
if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
}
p = p->ifma_next;
}
@ -360,18 +368,18 @@ void NetBSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,s
}
std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end());
std::unique(newGroups.begin(),newGroups.end());
std::sort(newGroups.begin(), newGroups.end());
std::unique(newGroups.begin(), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m);
}
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m);
}
@ -422,12 +430,11 @@ bool NetBSDEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
}
*/
void NetBSDEthernetTap::threadMain()
throw()
void NetBSDEthernetTap::threadMain() throw()
{
fd_set readfds,nullfds;
MAC to,from;
int n,nfds,r;
fd_set readfds, nullfds;
MAC to, from;
int n, nfds, r;
char getBuf[8194];
// Wait for a moment after startup -- wait for Network to finish
@ -436,37 +443,38 @@ void NetBSDEthernetTap::threadMain()
FD_ZERO(&readfds);
FD_ZERO(&nullfds);
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1;
r = 0;
for(;;) {
FD_SET(_shutdownSignalPipe[0],&readfds);
FD_SET(_fd,&readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
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
if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread
break;
if (FD_ISSET(_fd,&readfds)) {
n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
if (FD_ISSET(_fd, &readfds)) {
n = (int)::read(_fd, getBuf + r, sizeof(getBuf) - r);
if (n < 0) {
if ((errno != EINTR)&&(errno != ETIMEDOUT))
if ((errno != EINTR) && (errno != ETIMEDOUT))
break;
} else {
}
else {
// Some tap drivers like to send the ethernet frame and the
// payload in two chunks, so handle that by accumulating
// data until we have at least a frame.
r += n;
if (r > 14) {
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
r = _mtu + 14;
if (_enabled) {
to.setTo(getBuf,6);
from.setTo(getBuf + 6,6);
unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
to.setTo(getBuf, 6);
from.setTo(getBuf + 6, 6);
unsigned int etherType = ntohs(((const uint16_t*)getBuf)[6]);
// TODO: VLAN support
_handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14);
_handler(_arg, _nwid, from, to, etherType, 0, (const void*)(getBuf + 14), r - 14);
}
r = 0;
@ -476,4 +484,4 @@ void NetBSDEthernetTap::threadMain()
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,53 +14,52 @@
#ifndef ZT_NetBSDEthernetTap_HPP
#define ZT_NetBSDEthernetTap_HPP
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "Thread.hpp"
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <stdexcept>
#include "../node/Constants.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/MAC.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp"
namespace ZeroTier {
class NetBSDEthernetTap : public EthernetTap
{
public:
class NetBSDEthernetTap : public EthernetTap {
public:
NetBSDEthernetTap(
const char *homePath,
const MAC &mac,
const char* homePath,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
const char* friendlyName,
void (*handler)(void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg);
virtual ~NetBSDEthernetTap();
virtual void setEnabled(bool en);
virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip);
virtual bool removeIp(const InetAddress &ip);
virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) {}
virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setDns(const char* domain, const std::vector<InetAddress>& servers)
{
}
void threadMain()
throw();
void threadMain() throw();
private:
void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
void *_arg;
private:
void (*_handler)(void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void* _arg;
uint64_t _nwid;
Thread _thread;
std::string _dev;
@ -72,6 +71,6 @@ private:
volatile bool _enabled;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,35 +11,34 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <inttypes.h>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#ifdef __UNIX_LIKE__
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <dirent.h>
#include <netdb.h>
#include <unistd.h>
#endif
#ifdef __WINDOWS__
#include <windows.h>
#include <wincrypt.h>
#include <shlobj.h>
#include <netioapi.h>
#include <iphlpapi.h>
#include <netioapi.h>
#include <shlobj.h>
#include <wincrypt.h>
#include <windows.h>
#endif
#include "OSUtils.hpp"
@ -50,15 +49,15 @@
namespace ZeroTier {
unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)
unsigned int OSUtils::ztsnprintf(char* buf, unsigned int len, const char* fmt, ...)
{
va_list ap;
va_start(ap,fmt);
int n = (int)vsnprintf(buf,len,fmt,ap);
va_start(ap, fmt);
int n = (int)vsnprintf(buf, len, fmt, ap);
va_end(ap);
if ((n >= (int)len)||(n < 0)) {
if ((n >= (int)len) || (n < 0)) {
if (len)
buf[len - 1] = (char)0;
throw std::length_error("buf[] overflow");
@ -67,70 +66,75 @@ unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)
return (unsigned int)n;
}
std::string OSUtils::networkIDStr(const uint64_t nwid) {
std::string OSUtils::networkIDStr(const uint64_t nwid)
{
char tmp[32] = {};
ztsnprintf(tmp, sizeof(tmp), "%.16" PRIx64, nwid);
return std::string(tmp);
}
std::string OSUtils::nodeIDStr(const uint64_t nid) {
std::string OSUtils::nodeIDStr(const uint64_t nid)
{
char tmp[32] = {};
ztsnprintf(tmp, sizeof(tmp), "%.10" PRIx64, nid);
return std::string(tmp);
}
#ifdef __UNIX_LIKE__
bool OSUtils::redirectUnixOutputs(const char *stdoutPath,const char *stderrPath)
throw()
bool OSUtils::redirectUnixOutputs(const char* stdoutPath, const char* stderrPath) throw()
{
int fdout = ::open(stdoutPath,O_WRONLY|O_CREAT,0600);
int fdout = ::open(stdoutPath, O_WRONLY | O_CREAT, 0600);
if (fdout > 0) {
int fderr;
if (stderrPath) {
fderr = ::open(stderrPath,O_WRONLY|O_CREAT,0600);
fderr = ::open(stderrPath, O_WRONLY | O_CREAT, 0600);
if (fderr <= 0) {
::close(fdout);
return false;
}
} else fderr = fdout;
}
else
fderr = fdout;
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
::dup2(fdout,STDOUT_FILENO);
::dup2(fderr,STDERR_FILENO);
::dup2(fdout, STDOUT_FILENO);
::dup2(fderr, STDERR_FILENO);
return true;
}
return false;
}
#endif // __UNIX_LIKE__
#endif // __UNIX_LIKE__
std::vector<std::string> OSUtils::listDirectory(const char *path,bool includeDirectories)
std::vector<std::string> OSUtils::listDirectory(const char* path, bool includeDirectories)
{
std::vector<std::string> r;
#ifdef __WINDOWS__
HANDLE hFind;
WIN32_FIND_DATAA ffd;
if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) {
if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) {
do {
if ( (strcmp(ffd.cFileName,".")) && (strcmp(ffd.cFileName,"..")) && (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)||(((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)&&(includeDirectories))) )
if ((strcmp(ffd.cFileName, ".")) && (strcmp(ffd.cFileName, "..")) && (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) || (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && (includeDirectories))))
r.push_back(std::string(ffd.cFileName));
} while (FindNextFileA(hFind,&ffd));
} while (FindNextFileA(hFind, &ffd));
FindClose(hFind);
}
#else
struct dirent de;
struct dirent *dptr;
DIR *d = opendir(path);
if (!d)
struct dirent* dptr;
DIR* d = opendir(path);
if (! d)
return r;
dptr = (struct dirent *)0;
for(;;) {
if (readdir_r(d,&de,&dptr))
dptr = (struct dirent*)0;
for (;;) {
if (readdir_r(d, &de, &dptr))
break;
if (dptr) {
if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))&&((dptr->d_type != DT_DIR)||(includeDirectories)))
if ((strcmp(dptr->d_name, ".")) && (strcmp(dptr->d_name, "..")) && ((dptr->d_type != DT_DIR) || (includeDirectories)))
r.push_back(std::string(dptr->d_name));
} else break;
}
else
break;
}
closedir(d);
#endif
@ -138,57 +142,59 @@ std::vector<std::string> OSUtils::listDirectory(const char *path,bool includeDir
return r;
}
long OSUtils::cleanDirectory(const char *path,const int64_t olderThan)
long OSUtils::cleanDirectory(const char* path, const int64_t olderThan)
{
long cleaned = 0;
#ifdef __WINDOWS__
HANDLE hFind;
WIN32_FIND_DATAA ffd;
LARGE_INTEGER date,adjust;
LARGE_INTEGER date, adjust;
adjust.QuadPart = 11644473600000 * 10000;
char tmp[4096];
if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) {
if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) {
do {
if ((strcmp(ffd.cFileName,"."))&&(strcmp(ffd.cFileName,".."))&&((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
date.HighPart = ffd.ftLastWriteTime.dwHighDateTime;
date.LowPart = ffd.ftLastWriteTime.dwLowDateTime;
if (date.QuadPart > 0) {
date.QuadPart -= adjust.QuadPart;
if ((int64_t)((date.QuadPart / 10000000) * 1000) < olderThan) {
ztsnprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName);
if (DeleteFileA(tmp))
++cleaned;
}
if ((strcmp(ffd.cFileName, ".")) && (strcmp(ffd.cFileName, "..")) && ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
date.HighPart = ffd.ftLastWriteTime.dwHighDateTime;
date.LowPart = ffd.ftLastWriteTime.dwLowDateTime;
if (date.QuadPart > 0) {
date.QuadPart -= adjust.QuadPart;
if ((int64_t)((date.QuadPart / 10000000) * 1000) < olderThan) {
ztsnprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName);
if (DeleteFileA(tmp))
++cleaned;
}
}
}
} while (FindNextFileA(hFind,&ffd));
} while (FindNextFileA(hFind, &ffd));
FindClose(hFind);
}
#else
struct dirent de;
struct dirent *dptr;
struct dirent* dptr;
struct stat st;
char tmp[4096];
DIR *d = opendir(path);
if (!d)
DIR* d = opendir(path);
if (! d)
return -1;
dptr = (struct dirent *)0;
for(;;) {
if (readdir_r(d,&de,&dptr))
dptr = (struct dirent*)0;
for (;;) {
if (readdir_r(d, &de, &dptr))
break;
if (dptr) {
if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))&&(dptr->d_type == DT_REG)) {
ztsnprintf(tmp,sizeof(tmp),"%s/%s",path,dptr->d_name);
if (stat(tmp,&st) == 0) {
if ((strcmp(dptr->d_name, ".")) && (strcmp(dptr->d_name, "..")) && (dptr->d_type == DT_REG)) {
ztsnprintf(tmp, sizeof(tmp), "%s/%s", path, dptr->d_name);
if (stat(tmp, &st) == 0) {
int64_t mt = (int64_t)(st.st_mtime);
if ((mt > 0)&&((mt * 1000) < olderThan)) {
if ((mt > 0) && ((mt * 1000) < olderThan)) {
if (unlink(tmp) == 0)
++cleaned;
}
}
}
} else break;
}
else
break;
}
closedir(d);
#endif
@ -196,44 +202,45 @@ long OSUtils::cleanDirectory(const char *path,const int64_t olderThan)
return cleaned;
}
bool OSUtils::rmDashRf(const char *path)
bool OSUtils::rmDashRf(const char* path)
{
#ifdef __WINDOWS__
HANDLE hFind;
WIN32_FIND_DATAA ffd;
if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) {
if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) {
do {
if ((strcmp(ffd.cFileName,".") != 0)&&(strcmp(ffd.cFileName,"..") != 0)) {
if ((strcmp(ffd.cFileName, ".") != 0) && (strcmp(ffd.cFileName, "..") != 0)) {
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
if (DeleteFileA((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()) == FALSE)
return false;
} else {
if (!rmDashRf((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()))
}
else {
if (! rmDashRf((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()))
return false;
}
}
} while (FindNextFileA(hFind,&ffd));
} while (FindNextFileA(hFind, &ffd));
FindClose(hFind);
}
return (RemoveDirectoryA(path) != FALSE);
#else
struct dirent de;
struct dirent *dptr;
DIR *d = opendir(path);
if (!d)
struct dirent* dptr;
DIR* d = opendir(path);
if (! d)
return true;
dptr = (struct dirent *)0;
for(;;) {
if (readdir_r(d,&de,&dptr) != 0)
dptr = (struct dirent*)0;
for (;;) {
if (readdir_r(d, &de, &dptr) != 0)
break;
if (!dptr)
if (! dptr)
break;
if ((strcmp(dptr->d_name,".") != 0)&&(strcmp(dptr->d_name,"..") != 0)&&(strlen(dptr->d_name) > 0)) {
if ((strcmp(dptr->d_name, ".") != 0) && (strcmp(dptr->d_name, "..") != 0) && (strlen(dptr->d_name) > 0)) {
std::string p(path);
p.push_back(ZT_PATH_SEPARATOR);
p.append(dptr->d_name);
if (unlink(p.c_str()) != 0) { // unlink first will remove symlinks instead of recursing them
if (!rmDashRf(p.c_str()))
if (unlink(p.c_str()) != 0) { // unlink first will remove symlinks instead of recursing them
if (! rmDashRf(p.c_str()))
return false;
}
}
@ -243,10 +250,10 @@ bool OSUtils::rmDashRf(const char *path)
#endif
}
void OSUtils::lockDownFile(const char *path,bool isDir)
void OSUtils::lockDownFile(const char* path, bool isDir)
{
#ifdef __UNIX_LIKE__
chmod(path,isDir ? 0700 : 0600);
chmod(path, isDir ? 0700 : 0600);
#else
#ifdef __WINDOWS__
{
@ -254,19 +261,19 @@ void OSUtils::lockDownFile(const char *path,bool isDir)
PROCESS_INFORMATION processInfo;
startupInfo.cb = sizeof(startupInfo);
memset(&startupInfo,0,sizeof(STARTUPINFOA));
memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) {
WaitForSingleObject(processInfo.hProcess,INFINITE);
memset(&startupInfo, 0, sizeof(STARTUPINFOA));
memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
if (CreateProcessA(NULL, (LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) {
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
startupInfo.cb = sizeof(startupInfo);
memset(&startupInfo,0,sizeof(STARTUPINFOA));
memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) {
WaitForSingleObject(processInfo.hProcess,INFINITE);
memset(&startupInfo, 0, sizeof(STARTUPINFOA));
memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
if (CreateProcessA(NULL, (LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) {
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
@ -285,28 +292,28 @@ void OSUtils::lockDownFile(const char *path,bool isDir)
#endif
}
uint64_t OSUtils::getLastModified(const char *path)
uint64_t OSUtils::getLastModified(const char* path)
{
struct stat s;
if (stat(path,&s))
if (stat(path, &s))
return 0;
return (((uint64_t)s.st_mtime) * 1000ULL);
}
bool OSUtils::fileExists(const char *path,bool followLinks)
bool OSUtils::fileExists(const char* path, bool followLinks)
{
struct stat s;
#ifdef __UNIX_LIKE__
if (!followLinks)
return (lstat(path,&s) == 0);
if (! followLinks)
return (lstat(path, &s) == 0);
#endif
return (stat(path,&s) == 0);
return (stat(path, &s) == 0);
}
int64_t OSUtils::getFileSize(const char *path)
int64_t OSUtils::getFileSize(const char* path)
{
struct stat s;
if (stat(path,&s))
if (stat(path, &s))
return -1;
#ifdef __WINDOWS__
return s.st_size;
@ -317,16 +324,17 @@ int64_t OSUtils::getFileSize(const char *path)
return -1;
}
bool OSUtils::readFile(const char *path,std::string &buf)
bool OSUtils::readFile(const char* path, std::string& buf)
{
char tmp[16384];
FILE *f = fopen(path,"rb");
FILE* f = fopen(path, "rb");
if (f) {
for(;;) {
long n = (long)fread(tmp,1,sizeof(tmp),f);
for (;;) {
long n = (long)fread(tmp, 1, sizeof(tmp), f);
if (n > 0)
buf.append(tmp,n);
else break;
buf.append(tmp, n);
else
break;
}
fclose(f);
return true;
@ -334,14 +342,15 @@ bool OSUtils::readFile(const char *path,std::string &buf)
return false;
}
bool OSUtils::writeFile(const char *path,const void *buf,unsigned int len)
bool OSUtils::writeFile(const char* path, const void* buf, unsigned int len)
{
FILE *f = fopen(path,"wb");
FILE* f = fopen(path, "wb");
if (f) {
if ((long)fwrite(buf,1,len,f) != (long)len) {
if ((long)fwrite(buf, 1, len, f) != (long)len) {
fclose(f);
return false;
} else {
}
else {
fclose(f);
return true;
}
@ -349,14 +358,14 @@ bool OSUtils::writeFile(const char *path,const void *buf,unsigned int len)
return false;
}
std::vector<std::string> OSUtils::split(const char *s,const char *const sep,const char *esc,const char *quot)
std::vector<std::string> OSUtils::split(const char* s, const char* const sep, const char* esc, const char* quot)
{
std::vector<std::string> fields;
std::string buf;
if (!esc)
if (! esc)
esc = "";
if (!quot)
if (! quot)
quot = "";
bool escapeState = false;
@ -365,24 +374,30 @@ std::vector<std::string> OSUtils::split(const char *s,const char *const sep,cons
if (escapeState) {
escapeState = false;
buf.push_back(*s);
} else if (quoteState) {
}
else if (quoteState) {
if (*s == quoteState) {
quoteState = 0;
fields.push_back(buf);
buf.clear();
} else buf.push_back(*s);
} else {
const char *quotTmp;
if (strchr(esc,*s))
}
else
buf.push_back(*s);
}
else {
const char* quotTmp;
if (strchr(esc, *s))
escapeState = true;
else if ((buf.size() <= 0)&&((quotTmp = strchr(quot,*s))))
else if ((buf.size() <= 0) && ((quotTmp = strchr(quot, *s))))
quoteState = *quotTmp;
else if (strchr(sep,*s)) {
if (!buf.empty()) {
else if (strchr(sep, *s)) {
if (! buf.empty()) {
fields.push_back(buf);
buf.clear();
} // else skip runs of separators
} else buf.push_back(*s);
} // else skip runs of separators
}
else
buf.push_back(*s);
}
++s;
}
@ -396,28 +411,28 @@ std::vector<std::string> OSUtils::split(const char *s,const char *const sep,cons
std::string OSUtils::platformDefaultHomePath()
{
#ifdef __QNAP__
char *cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf";
char buf[128];
FILE *fp;
if ((fp = popen(cmd, "r")) == NULL) {
printf("Error opening pipe!\n");
return NULL;
}
while (fgets(buf, 128, fp) != NULL) { }
if(pclose(fp)) {
printf("Command not found or exited with error status\n");
return NULL;
}
std::string homeDir = std::string(buf);
homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end());
return homeDir;
char* cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf";
char buf[128];
FILE* fp;
if ((fp = popen(cmd, "r")) == NULL) {
printf("Error opening pipe!\n");
return NULL;
}
while (fgets(buf, 128, fp) != NULL) {}
if (pclose(fp)) {
printf("Command not found or exited with error status\n");
return NULL;
}
std::string homeDir = std::string(buf);
homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end());
return homeDir;
#endif
#ifdef __UBIQUITI__
// Only persistent location after firmware upgrades
return std::string("/config/zerotier-one");
#endif
// Check for user-defined environment variable before using defaults
// Check for user-defined environment variable before using defaults
#ifdef __WINDOWS__
DWORD bufferSize = 65535;
std::string userDefinedPath;
@ -426,7 +441,7 @@ std::string OSUtils::platformDefaultHomePath()
return userDefinedPath;
}
#else
if(const char* userDefinedPath = getenv("ZEROTIER_HOME")) {
if (const char* userDefinedPath = getenv("ZEROTIER_HOME")) {
return std::string(userDefinedPath);
}
#endif
@ -449,44 +464,55 @@ std::string OSUtils::platformDefaultHomePath()
#endif
#else // not __UNIX_LIKE__
#else // not __UNIX_LIKE__
#ifdef __WINDOWS__
// Look up app data folder on Windows, e.g. C:\ProgramData\...
char buf[16384];
if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_COMMON_APPDATA,NULL,0,buf)))
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_APPDATA, NULL, 0, buf)))
return (std::string(buf) + "\\ZeroTier\\One");
else return std::string("C:\\ZeroTier\\One");
else
return std::string("C:\\ZeroTier\\One");
#else
return (std::string(ZT_PATH_SEPARATOR_S) + "ZeroTier" + ZT_PATH_SEPARATOR_S + "One"); // UNKNOWN PLATFORM
return (std::string(ZT_PATH_SEPARATOR_S) + "ZeroTier" + ZT_PATH_SEPARATOR_S + "One"); // UNKNOWN PLATFORM
#endif
#endif // __UNIX_LIKE__ or not...
#endif // __UNIX_LIKE__ or not...
}
#ifndef OMIT_JSON_SUPPORT
// Inline these massive JSON operations in one place only to reduce binary footprint and compile time
nlohmann::json OSUtils::jsonParse(const std::string &buf) { return nlohmann::json::parse(buf.c_str()); }
std::string OSUtils::jsonDump(const nlohmann::json &j,int indentation) { return j.dump(indentation); }
nlohmann::json OSUtils::jsonParse(const std::string& buf)
{
return nlohmann::json::parse(buf.c_str());
}
std::string OSUtils::jsonDump(const nlohmann::json& j, int indentation)
{
return j.dump(indentation);
}
uint64_t OSUtils::jsonInt(const nlohmann::json &jv,const uint64_t dfl)
uint64_t OSUtils::jsonInt(const nlohmann::json& jv, const uint64_t dfl)
{
try {
if (jv.is_number()) {
return (uint64_t)jv;
} else if (jv.is_string()) {
}
else if (jv.is_string()) {
std::string s = jv;
return Utils::strToU64(s.c_str());
} else if (jv.is_boolean()) {
}
else if (jv.is_boolean()) {
return ((bool)jv ? 1ULL : 0ULL);
}
} catch ( ... ) {}
}
catch (...) {
}
return dfl;
}
double OSUtils::jsonDouble(const nlohmann::json &jv,const double dfl)
double OSUtils::jsonDouble(const nlohmann::json& jv, const double dfl)
{
try {
if (jv.is_number()) {
@ -495,39 +521,48 @@ double OSUtils::jsonDouble(const nlohmann::json &jv,const double dfl)
else if (jv.is_string()) {
std::string s = jv;
return Utils::strToDouble(s.c_str());
} else if (jv.is_boolean()) {
}
else if (jv.is_boolean()) {
return (double)jv;
}
} catch ( ... ) {}
}
catch (...) {
}
return dfl;
}
uint64_t OSUtils::jsonIntHex(const nlohmann::json &jv,const uint64_t dfl)
uint64_t OSUtils::jsonIntHex(const nlohmann::json& jv, const uint64_t dfl)
{
try {
if (jv.is_number()) {
return (uint64_t)jv;
} else if (jv.is_string()) {
}
else if (jv.is_string()) {
std::string s = jv;
return Utils::hexStrToU64(s.c_str());
} else if (jv.is_boolean()) {
}
else if (jv.is_boolean()) {
return ((bool)jv ? 1ULL : 0ULL);
}
} catch ( ... ) {}
}
catch (...) {
}
return dfl;
}
bool OSUtils::jsonBool(const nlohmann::json &jv,const bool dfl)
bool OSUtils::jsonBool(const nlohmann::json& jv, const bool dfl)
{
try {
if (jv.is_boolean()) {
return (bool)jv;
} else if (jv.is_number()) {
}
else if (jv.is_number()) {
return ((uint64_t)jv > 0ULL);
} else if (jv.is_string()) {
}
else if (jv.is_string()) {
std::string s = jv;
if (s.length() > 0) {
switch(s[0]) {
switch (s[0]) {
case 't':
case 'T':
case '1':
@ -536,47 +571,62 @@ bool OSUtils::jsonBool(const nlohmann::json &jv,const bool dfl)
}
return false;
}
} catch ( ... ) {}
}
catch (...) {
}
return dfl;
}
std::string OSUtils::jsonString(const nlohmann::json &jv,const char *dfl)
std::string OSUtils::jsonString(const nlohmann::json& jv, const char* dfl)
{
try {
if (jv.is_string()) {
return jv;
} else if (jv.is_number()) {
}
else if (jv.is_number()) {
char tmp[64];
ztsnprintf(tmp,sizeof(tmp),"%llu",(uint64_t)jv);
ztsnprintf(tmp, sizeof(tmp), "%llu", (uint64_t)jv);
return tmp;
} else if (jv.is_boolean()) {
}
else if (jv.is_boolean()) {
return ((bool)jv ? std::string("1") : std::string("0"));
}
} catch ( ... ) {}
}
catch (...) {
}
return std::string((dfl) ? dfl : "");
}
std::string OSUtils::jsonBinFromHex(const nlohmann::json &jv)
std::string OSUtils::jsonBinFromHex(const nlohmann::json& jv)
{
std::string s(jsonString(jv,""));
std::string s(jsonString(jv, ""));
if (s.length() > 0) {
unsigned int buflen = (unsigned int)((s.length() / 2) + 1);
char *buf = new char[buflen];
char* buf = new char[buflen];
try {
unsigned int l = Utils::unhex(s.c_str(),buf,buflen);
std::string b(buf,l);
delete [] buf;
unsigned int l = Utils::unhex(s.c_str(), buf, buflen);
std::string b(buf, l);
delete[] buf;
return b;
} catch ( ... ) {
delete [] buf;
}
catch (...) {
delete[] buf;
}
}
return std::string();
}
#endif // OMIT_JSON_SUPPORT
#endif // OMIT_JSON_SUPPORT
// Used to convert HTTP header names to ASCII lower case
const unsigned char OSUtils::TOLOWER_TABLE[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
const unsigned char OSUtils::TOLOWER_TABLE[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '{', '|', '}', '~', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,29 +14,28 @@
#ifndef ZT_OSUTILS_HPP
#define ZT_OSUTILS_HPP
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <stdexcept>
#include <vector>
#include <map>
#include "../node/Constants.hpp"
#include "../node/InetAddress.hpp"
#include <map>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <vector>
#ifdef __WINDOWS__
#include <winsock2.h>
#include <windows.h>
#include <shlwapi.h>
#include <windows.h>
#include <winsock2.h>
#else
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#ifdef __LINUX__
#include <sys/syscall.h>
#endif
@ -51,9 +50,8 @@ namespace ZeroTier {
/**
* Miscellaneous utility functions and global constants
*/
class OSUtils
{
public:
class OSUtils {
public:
/**
* Variant of snprintf that is portable and throws an exception
*
@ -66,11 +64,11 @@ public:
* @param ... Format arguments
* @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
*/
static unsigned int ztsnprintf(char *buf,unsigned int len,const char *fmt,...);
static unsigned int ztsnprintf(char* buf, unsigned int len, const char* fmt, ...);
/**
* Converts a uint64_t network ID into a string
*
*
* @param nwid network ID
* @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
*/
@ -78,7 +76,7 @@ public:
/**
* Converts a uint64_t node ID into a string
*
*
* @param nid node ID
* @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
*/
@ -95,9 +93,8 @@ public:
* @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default)
* @return True on success
*/
static bool redirectUnixOutputs(const char *stdoutPath,const char *stderrPath = (const char *)0)
throw();
#endif // __UNIX_LIKE__
static bool redirectUnixOutputs(const char* stdoutPath, const char* stderrPath = (const char*)0) throw();
#endif // __UNIX_LIKE__
/**
* Delete a file
@ -105,7 +102,7 @@ public:
* @param path Path to delete
* @return True if delete was successful
*/
static inline bool rm(const char *path)
static inline bool rm(const char* path)
{
#ifdef __WINDOWS__
return (DeleteFileA(path) != FALSE);
@ -113,29 +110,35 @@ public:
return (unlink(path) == 0);
#endif
}
static inline bool rm(const std::string &path) { return rm(path.c_str()); }
static inline bool rm(const std::string& path)
{
return rm(path.c_str());
}
static inline bool mkdir(const char *path)
static inline bool mkdir(const char* path)
{
#ifdef __WINDOWS__
if (::PathIsDirectoryA(path))
return true;
return (::CreateDirectoryA(path,NULL) == TRUE);
return (::CreateDirectoryA(path, NULL) == TRUE);
#else
if (::mkdir(path,0755) != 0)
if (::mkdir(path, 0755) != 0)
return (errno == EEXIST);
return true;
#endif
}
static inline bool mkdir(const std::string &path) { return OSUtils::mkdir(path.c_str()); }
static inline bool mkdir(const std::string& path)
{
return OSUtils::mkdir(path.c_str());
}
static inline bool rename(const char *o,const char *n)
static inline bool rename(const char* o, const char* n)
{
#ifdef __WINDOWS__
DeleteFileA(n);
return (::rename(o,n) == 0);
return (::rename(o, n) == 0);
#else
return (::rename(o,n) == 0);
return (::rename(o, n) == 0);
#endif
}
@ -146,7 +149,7 @@ public:
* @param includeDirectories If true, include directories as well as files
* @return Names of files in directory (without path prepended)
*/
static std::vector<std::string> listDirectory(const char *path,bool includeDirectories = false);
static std::vector<std::string> listDirectory(const char* path, bool includeDirectories = false);
/**
* Clean a directory of files whose last modified time is older than this
@ -156,7 +159,7 @@ public:
* @param olderThan Last modified older than timestamp (ms since epoch)
* @return Number of cleaned files or negative on fatal error
*/
static long cleanDirectory(const char *path,const int64_t olderThan);
static long cleanDirectory(const char* path, const int64_t olderThan);
/**
* Delete a directory and all its files and subdirectories recursively
@ -164,7 +167,7 @@ public:
* @param path Path to delete
* @return True on success
*/
static bool rmDashRf(const char *path);
static bool rmDashRf(const char* path);
/**
* Set modes on a file to something secure
@ -175,7 +178,7 @@ public:
* @param path Path to lock
* @param isDir True if this is a directory
*/
static void lockDownFile(const char *path,bool isDir);
static void lockDownFile(const char* path, bool isDir);
/**
* Get file last modification time
@ -186,20 +189,20 @@ public:
* @param path Path to file to get time
* @return Last modification time in ms since epoch or 0 if not found
*/
static uint64_t getLastModified(const char *path);
static uint64_t getLastModified(const char* path);
/**
* @param path Path to check
* @param followLinks Follow links (on platforms with that concept)
* @return True if file or directory exists at path location
*/
static bool fileExists(const char *path,bool followLinks = true);
static bool fileExists(const char* path, bool followLinks = true);
/**
* @param path Path to file
* @return File size or -1 if nonexistent or other failure
*/
static int64_t getFileSize(const char *path);
static int64_t getFileSize(const char* path);
/**
* Get IP (v4 and/or v6) addresses for a given host
@ -209,7 +212,7 @@ public:
* @param name Host name
* @return IP addresses in InetAddress sort order or empty vector if not found
*/
static std::vector<InetAddress> resolve(const char *name);
static std::vector<InetAddress> resolve(const char* name);
/**
* @return Current time in milliseconds since epoch
@ -221,14 +224,14 @@ public:
SYSTEMTIME st;
ULARGE_INTEGER tmp;
GetSystemTime(&st);
SystemTimeToFileTime(&st,&ft);
SystemTimeToFileTime(&st, &ft);
tmp.LowPart = ft.dwLowDateTime;
tmp.HighPart = ft.dwHighDateTime;
return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds );
return (int64_t)(((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds);
#else
struct timeval tv;
gettimeofday(&tv,(struct timezone *)0);
return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) );
gettimeofday(&tv, (struct timezone*)0);
return ((1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000));
#endif
};
@ -242,7 +245,7 @@ public:
* @param buf Buffer to fill
* @return True if open and read successful
*/
static bool readFile(const char *path,std::string &buf);
static bool readFile(const char* path, std::string& buf);
/**
* Write a block of data to disk, replacing any current file contents
@ -252,7 +255,7 @@ public:
* @param len Length of buffer
* @return True if entire file was successfully written
*/
static bool writeFile(const char *path,const void *buf,unsigned int len);
static bool writeFile(const char* path, const void* buf, unsigned int len);
/**
* Split a string by delimiter, with optional escape and quote characters
@ -263,7 +266,7 @@ public:
* @param quot Zero or more quote characters
* @return Vector of tokens
*/
static std::vector<std::string> split(const char *s,const char *const sep,const char *esc,const char *quot);
static std::vector<std::string> split(const char* s, const char* const sep, const char* esc, const char* quot);
/**
* Write a block of data to disk, replacing any current file contents
@ -272,13 +275,19 @@ public:
* @param s Data to write
* @return True if entire file was successfully written
*/
static inline bool writeFile(const char *path,const std::string &s) { return writeFile(path,s.data(),(unsigned int)s.length()); }
static inline bool writeFile(const char* path, const std::string& s)
{
return writeFile(path, s.data(), (unsigned int)s.length());
}
/**
* @param c ASCII character to convert
* @return Lower case ASCII character or unchanged if not a letter
*/
static inline char toLower(char c) throw() { return (char)OSUtils::TOLOWER_TABLE[(unsigned long)c]; }
static inline char toLower(char c) throw()
{
return (char)OSUtils::TOLOWER_TABLE[(unsigned long)c];
}
/**
* @return Platform default ZeroTier One home path
@ -286,20 +295,20 @@ public:
static std::string platformDefaultHomePath();
#ifndef OMIT_JSON_SUPPORT
static nlohmann::json jsonParse(const std::string &buf);
static std::string jsonDump(const nlohmann::json &j,int indentation = 1);
static uint64_t jsonInt(const nlohmann::json &jv,const uint64_t dfl);
static double jsonDouble(const nlohmann::json &jv,const double dfl);
static uint64_t jsonIntHex(const nlohmann::json &jv,const uint64_t dfl);
static bool jsonBool(const nlohmann::json &jv,const bool dfl);
static std::string jsonString(const nlohmann::json &jv,const char *dfl);
static std::string jsonBinFromHex(const nlohmann::json &jv);
#endif // OMIT_JSON_SUPPORT
static nlohmann::json jsonParse(const std::string& buf);
static std::string jsonDump(const nlohmann::json& j, int indentation = 1);
static uint64_t jsonInt(const nlohmann::json& jv, const uint64_t dfl);
static double jsonDouble(const nlohmann::json& jv, const double dfl);
static uint64_t jsonIntHex(const nlohmann::json& jv, const uint64_t dfl);
static bool jsonBool(const nlohmann::json& jv, const bool dfl);
static std::string jsonString(const nlohmann::json& jv, const char* dfl);
static std::string jsonBinFromHex(const nlohmann::json& jv);
#endif // OMIT_JSON_SUPPORT
private:
private:
static const unsigned char TOLOWER_TABLE[256];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@
#ifdef ZT_USE_MINIUPNPC
// Uncomment to dump debug messages
//#define ZT_PORTMAPPER_TRACE 1
// #define ZT_PORTMAPPER_TRACE 1
#ifdef __ANDROID__
#include <android/log.h>
@ -23,16 +23,15 @@
#define PM_TRACE(...) fprintf(stderr, __VA_ARGS__)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include "PortMapper.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
// These must be defined to get rid of dynamic export stuff in libminiupnpc and libnatpmp
#ifdef __WINDOWS__
#ifndef MINIUPNP_STATICLIB
@ -63,34 +62,30 @@
namespace ZeroTier {
class PortMapperImpl
{
public:
PortMapperImpl(int localUdpPortToMap,const char *un) :
run(true),
localPort(localUdpPortToMap),
uniqueName(un)
class PortMapperImpl {
public:
PortMapperImpl(int localUdpPortToMap, const char* un) : run(true), localPort(localUdpPortToMap), uniqueName(un)
{
}
~PortMapperImpl() {}
void threadMain()
throw()
~PortMapperImpl()
{
int mode = 0; // 0 == NAT-PMP, 1 == UPnP
}
void threadMain() throw()
{
int mode = 0; // 0 == NAT-PMP, 1 == UPnP
int retrytime = 500;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: started for UDP port %d" ZT_EOL_S,localPort);
fprintf(stderr, "PortMapper: started for UDP port %d" ZT_EOL_S, localPort);
#endif
while (run) {
{
// use initnatpmp to check if we can bind a port at all
natpmp_t _natpmp;
int result = initnatpmp(&_natpmp,0,0);
int result = initnatpmp(&_natpmp, 0, 0);
if (result == NATPMP_ERR_CANNOTGETGATEWAY || result == NATPMP_ERR_SOCKETERROR) {
closenatpmp(&_natpmp);
#ifdef ZT_PORTMAPPER_TRACE
@ -102,7 +97,8 @@ public:
retrytime = ZT_PORTMAPPER_REFRESH_DELAY / 10;
}
continue;
} else {
}
else {
closenatpmp(&_natpmp);
retrytime = 500;
}
@ -111,24 +107,24 @@ public:
// NAT-PMP mode (preferred)
// ---------------------------------------------------------------------
if (mode == 0) {
natpmp_t natpmp;
natpmpresp_t response;
natpmp_t natpmp;
natpmpresp_t response;
int r = 0;
bool natPmpSuccess = false;
for(int tries=0;tries<60;++tries) {
for (int tries = 0; tries < 60; ++tries) {
int tryPort = (int)localPort + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
memset(&natpmp,0,sizeof(natpmp));
memset(&response,0,sizeof(response));
memset(&natpmp, 0, sizeof(natpmp));
memset(&response, 0, sizeof(response));
if (initnatpmp(&natpmp,0,0) != 0) {
if (initnatpmp(&natpmp, 0, 0) != 0) {
mode = 1;
closenatpmp(&natpmp);
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S);
PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S);
#endif
break;
}
@ -148,33 +144,34 @@ public:
break;
} while (r == NATPMP_TRYAGAIN);
if (r == 0) {
publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0);
} else {
publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr, 0);
}
else {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S);
PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S);
#endif
closenatpmp(&natpmp);
break;
}
sendnewportmappingrequest(&natpmp,NATPMP_PROTOCOL_UDP,localPort,tryPort,(ZT_PORTMAPPER_REFRESH_DELAY * 2) / 1000);
sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, localPort, tryPort, (ZT_PORTMAPPER_REFRESH_DELAY * 2) / 1000);
myTimeout = OSUtils::now() + 10000;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
if (OSUtils::now() >= myTimeout)
break;
} while (r == NATPMP_TRYAGAIN);
} while (r == NATPMP_TRYAGAIN);
if (r == 0) {
publicAddress.setPort(response.pnu.newportmapping.mappedpublicport);
#ifdef ZT_PORTMAPPER_TRACE
char paddr[128];
PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S,(unsigned int)localPort,publicAddress.toString(paddr));
char paddr[128];
PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S, (unsigned int)localPort, publicAddress.toString(paddr));
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@ -182,16 +179,17 @@ public:
natPmpSuccess = true;
closenatpmp(&natpmp);
break;
} else {
}
else {
closenatpmp(&natpmp);
// continue
}
}
if (!natPmpSuccess) {
if (! natPmpSuccess) {
mode = 1;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S);
PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S);
#endif
continue;
}
@ -203,66 +201,66 @@ public:
// ---------------------------------------------------------------------
if (mode == 1) {
char lanaddr[4096];
char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P
char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P
char inport[16];
char outport[16];
struct UPNPUrls urls;
struct IGDdatas data;
int upnpError = 0;
UPNPDev *devlist = upnpDiscoverAll(5000,(const char *)0,(const char *)0,0,0,2,&upnpError);
UPNPDev* devlist = upnpDiscoverAll(5000, (const char*)0, (const char*)0, 0, 0, 2, &upnpError);
if (devlist) {
#ifdef ZT_PORTMAPPER_TRACE
{
UPNPDev *dev = devlist;
UPNPDev* dev = devlist;
while (dev) {
PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S,dev->descURL,dev->st);
PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S, dev->descURL, dev->st);
dev = dev->pNext;
}
}
#endif
memset(lanaddr,0,sizeof(lanaddr));
memset(externalip,0,sizeof(externalip));
memset(&urls,0,sizeof(urls));
memset(&data,0,sizeof(data));
OSUtils::ztsnprintf(inport,sizeof(inport),"%d",localPort);
memset(lanaddr, 0, sizeof(lanaddr));
memset(externalip, 0, sizeof(externalip));
memset(&urls, 0, sizeof(urls));
memset(&data, 0, sizeof(data));
OSUtils::ztsnprintf(inport, sizeof(inport), "%d", localPort);
int foundValidIGD = 0;
if ((foundValidIGD = UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) {
if ((foundValidIGD = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))) && (lanaddr[0])) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S,lanaddr);
PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S, lanaddr);
#endif
if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) {
if ((UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalip) == UPNPCOMMAND_SUCCESS) && (externalip[0])) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S,externalip);
PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S, externalip);
#endif
for(int tries=0;tries<60;++tries) {
for (int tries = 0; tries < 60; ++tries) {
int tryPort = (int)localPort + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
OSUtils::ztsnprintf(outport,sizeof(outport),"%u",tryPort);
OSUtils::ztsnprintf(outport, sizeof(outport), "%u", tryPort);
// First check and see if this port is already mapped to the
// same unique name. If so, keep this mapping and don't try
// to map again since this can break buggy routers. But don't
// fail if this command fails since not all routers support it.
{
char haveIntClient[128]; // 128 == big enough for all these as per miniupnpc "documentation"
char haveIntClient[128]; // 128 == big enough for all these as per miniupnpc "documentation"
char haveIntPort[128];
char haveDesc[128];
char haveEnabled[128];
char haveLeaseDuration[128];
memset(haveIntClient,0,sizeof(haveIntClient));
memset(haveIntPort,0,sizeof(haveIntPort));
memset(haveDesc,0,sizeof(haveDesc));
memset(haveEnabled,0,sizeof(haveEnabled));
memset(haveLeaseDuration,0,sizeof(haveLeaseDuration));
if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) {
memset(haveIntClient, 0, sizeof(haveIntClient));
memset(haveIntPort, 0, sizeof(haveIntPort));
memset(haveDesc, 0, sizeof(haveDesc));
memset(haveEnabled, 0, sizeof(haveEnabled));
memset(haveLeaseDuration, 0, sizeof(haveLeaseDuration));
if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL, data.first.servicetype, outport, "UDP", (const char*)0, haveIntClient, haveIntPort, haveDesc, haveEnabled, haveLeaseDuration) == UPNPCOMMAND_SUCCESS)
&& (uniqueName == haveDesc)) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S,outport);
PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S, outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@ -275,9 +273,9 @@ public:
// Try to map this port
int mapResult = 0;
if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) {
if ((mapResult = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, outport, inport, lanaddr, uniqueName.c_str(), "UDP", (const char*)0, "0")) == UPNPCOMMAND_SUCCESS) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S,outport);
PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S, outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@ -285,42 +283,45 @@ public:
tmp.setPort(tryPort);
surface.push_back(tmp);
break;
} else {
}
else {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S,outport,mapResult);
PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S, outport, mapResult);
#endif
Thread::sleep(1000);
}
}
} else {
}
else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S);
PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
} else {
}
else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S);
PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
freeUPNPDevlist(devlist);
if(foundValidIGD) {
if (foundValidIGD) {
FreeUPNPUrls(&urls);
}
} else {
}
else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S,upnpError);
PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S, upnpError);
#endif
}
}
// ---------------------------------------------------------------------
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY);
PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S, ZT_PORTMAPPER_REFRESH_DELAY);
#endif
Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY);
}
@ -336,9 +337,9 @@ public:
std::vector<InetAddress> surface;
};
PortMapper::PortMapper(int localUdpPortToMap,const char *uniqueName)
PortMapper::PortMapper(int localUdpPortToMap, const char* uniqueName)
{
_impl = new PortMapperImpl(localUdpPortToMap,uniqueName);
_impl = new PortMapperImpl(localUdpPortToMap, uniqueName);
Thread::start(_impl);
}
@ -353,6 +354,6 @@ std::vector<InetAddress> PortMapper::get() const
return _impl->surface;
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_USE_MINIUPNPC
#endif // ZT_USE_MINIUPNPC

View file

@ -16,13 +16,13 @@
#ifndef ZT_PORTMAPPER_HPP
#define ZT_PORTMAPPER_HPP
#include <vector>
#include "../node/Constants.hpp"
#include "../node/InetAddress.hpp"
#include "../node/Mutex.hpp"
#include "Thread.hpp"
#include <vector>
/**
* How frequently should we refresh our UPNP/NAT-PnP/whatever state?
*/
@ -35,18 +35,17 @@ class PortMapperImpl;
/**
* UPnP/NAT-PnP port mapping "daemon"
*/
class PortMapper
{
class PortMapper {
friend class PortMapperImpl;
public:
public:
/**
* Create and start port mapper service
*
* @param localUdpPortToMap Port we want visible to the outside world
* @param name Unique name of this endpoint (based on ZeroTier address)
*/
PortMapper(int localUdpPortToMap,const char *uniqueName);
PortMapper(int localUdpPortToMap, const char* uniqueName);
~PortMapper();
@ -55,12 +54,12 @@ public:
*/
std::vector<InetAddress> get() const;
private:
PortMapperImpl *_impl;
private:
PortMapperImpl* _impl;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif
#endif // ZT_USE_MINIUPNPC
#endif // ZT_USE_MINIUPNPC

View file

@ -14,57 +14,57 @@
#ifndef ZT_THREAD_HPP
#define ZT_THREAD_HPP
#include <stdexcept>
#include "../node/Constants.hpp"
#include <stdexcept>
#ifdef __WINDOWS__
#include <winsock2.h>
#include <windows.h>
#include <string.h>
#include "../node/Mutex.hpp"
#include <string.h>
#include <windows.h>
#include <winsock2.h>
namespace ZeroTier {
template<typename C>
static DWORD WINAPI ___zt_threadMain(LPVOID lpParam)
template <typename C> static DWORD WINAPI ___zt_threadMain(LPVOID lpParam)
{
try {
((C *)lpParam)->threadMain();
} catch ( ... ) {}
((C*)lpParam)->threadMain();
}
catch (...) {
}
return 0;
}
class Thread
{
public:
class Thread {
public:
Thread()
{
_th = NULL;
_tid = 0;
}
template<typename C>
static inline Thread start(C *instance)
template <typename C> static inline Thread start(C* instance)
{
Thread t;
t._th = CreateThread(NULL,0,&___zt_threadMain<C>,(LPVOID)instance,0,&t._tid);
t._th = CreateThread(NULL, 0, &___zt_threadMain<C>, (LPVOID)instance, 0, &t._tid);
if (t._th == NULL)
throw std::runtime_error("CreateThread() failed");
return t;
}
static inline void join(const Thread &t)
static inline void join(const Thread& t)
{
if (t._th != NULL) {
for(;;) {
for (;;) {
DWORD ec = STILL_ACTIVE;
GetExitCodeThread(t._th,&ec);
GetExitCodeThread(t._th, &ec);
if (ec == STILL_ACTIVE)
WaitForSingleObject(t._th,1000);
else break;
WaitForSingleObject(t._th, 1000);
else
break;
}
}
}
@ -75,61 +75,64 @@ public:
}
// Not available on *nix platforms
static inline void cancelIO(const Thread &t)
static inline void cancelIO(const Thread& t)
{
#if !defined(__MINGW32__) && !defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2
#if ! defined(__MINGW32__) && ! defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2
if (t._th != NULL)
CancelSynchronousIo(t._th);
#endif
}
inline operator bool() const { return (_th != NULL); }
inline operator bool() const
{
return (_th != NULL);
}
private:
private:
HANDLE _th;
DWORD _tid;
};
} // namespace ZeroTier
} // namespace ZeroTier
#else
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
namespace ZeroTier {
template<typename C>
static void *___zt_threadMain(void *instance)
template <typename C> static void* ___zt_threadMain(void* instance)
{
try {
((C *)instance)->threadMain();
} catch ( ... ) {}
return (void *)0;
((C*)instance)->threadMain();
}
catch (...) {
}
return (void*)0;
}
/**
* A thread identifier, and static methods to start and join threads
*/
class Thread
{
public:
class Thread {
public:
Thread()
{
memset(this,0,sizeof(Thread));
memset(this, 0, sizeof(Thread));
}
Thread(const Thread &t)
Thread(const Thread& t)
{
memcpy(this,&t,sizeof(Thread));
memcpy(this, &t, sizeof(Thread));
}
inline Thread &operator=(const Thread &t)
inline Thread& operator=(const Thread& t)
{
memcpy(this,&t,sizeof(Thread));
memcpy(this, &t, sizeof(Thread));
return *this;
}
@ -141,19 +144,19 @@ public:
* @throws std::runtime_error Unable to create thread
* @tparam C Class containing threadMain()
*/
template<typename C>
static inline Thread start(C *instance)
template <typename C> static inline Thread start(C* instance)
{
Thread t;
pthread_attr_t tattr;
pthread_attr_init(&tattr);
// This corrects for systems with abnormally small defaults (musl) and also
// shrinks the stack on systems with large defaults to save a bit of memory.
pthread_attr_setstacksize(&tattr,ZT_THREAD_MIN_STACK_SIZE);
if (pthread_create(&t._tid,&tattr,&___zt_threadMain<C>,instance)) {
pthread_attr_setstacksize(&tattr, ZT_THREAD_MIN_STACK_SIZE);
if (pthread_create(&t._tid, &tattr, &___zt_threadMain<C>, instance)) {
pthread_attr_destroy(&tattr);
throw std::runtime_error("pthread_create() failed, unable to create thread");
} else {
}
else {
t._started = true;
pthread_attr_destroy(&tattr);
}
@ -165,10 +168,10 @@ public:
*
* @param t Thread to join
*/
static inline void join(const Thread &t)
static inline void join(const Thread& t)
{
if (t._started)
pthread_join(t._tid,(void **)0);
pthread_join(t._tid, (void**)0);
}
/**
@ -176,17 +179,23 @@ public:
*
* @param ms Number of milliseconds to sleep
*/
static inline void sleep(unsigned long ms) { usleep(ms * 1000); }
static inline void sleep(unsigned long ms)
{
usleep(ms * 1000);
}
inline operator bool() const { return (_started); }
inline operator bool() const
{
return (_started);
}
private:
private:
pthread_t _tid;
volatile bool _started;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif // __WINDOWS__ / !__WINDOWS__
#endif // __WINDOWS__ / !__WINDOWS__
#endif

View file

@ -1,18 +1,16 @@
#include "WinDNSHelper.hpp"
#include <comdef.h>
#include <WbemIdl.h>
#include <vector>
#include <string>
#include <comdef.h>
#include <sstream>
#include <string>
#include <strsafe.h>
#include <vector>
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
namespace ZeroTier
{
namespace ZeroTier {
BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey)
{
@ -33,8 +31,7 @@ BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey)
lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS)
{
if (lResult != ERROR_SUCCESS) {
if (lResult == ERROR_FILE_NOT_FOUND) {
return TRUE;
}
@ -47,8 +44,7 @@ BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey)
lpEnd = lpSubKey + lstrlen(lpSubKey);
if (*(lpEnd - 1) != TEXT('\\'))
{
if (*(lpEnd - 1) != TEXT('\\')) {
*lpEnd = TEXT('\\');
lpEnd++;
*lpEnd = TEXT('\0');
@ -57,24 +53,20 @@ BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey)
// Enumerate the keys
dwSize = MAX_PATH;
lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
NULL, NULL, &ftWrite);
lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
if (lResult == ERROR_SUCCESS)
{
if (lResult == ERROR_SUCCESS) {
do {
*lpEnd = TEXT('\0');
StringCchCat(lpSubKey, MAX_PATH * 2, szName);
if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) {
if (! RegDelnodeRecurse(hKeyRoot, lpSubKey)) {
break;
}
dwSize = MAX_PATH;
lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
NULL, NULL, &ftWrite);
lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
} while (lResult == ERROR_SUCCESS);
}
@ -114,61 +106,47 @@ BOOL RegDelnode(HKEY hKeyRoot, LPCTSTR lpSubKey)
StringCchCopy(szDelKey, MAX_PATH * 2, lpSubKey);
return RegDelnodeRecurse(hKeyRoot, szDelKey);
}
std::vector<std::string> getSubKeys(const char* key)
{
std::vector<std::string> subkeys;
HKEY hKey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
key,
0,
KEY_READ,
&hKey) == ERROR_SUCCESS) {
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys = 0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys = 0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i, retCode;
TCHAR achValue[MAX_VALUE_NAME];
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
retCode = RegQueryInfoKey(
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
for (i = 0; i < cSubKeys; ++i) {
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(
hKey,
i,
achKey,
&cbName,
NULL,
NULL,
NULL,
&ftLastWriteTime);
retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime);
if (retCode == ERROR_SUCCESS) {
subkeys.push_back(achKey);
}
@ -178,59 +156,47 @@ std::vector<std::string> getSubKeys(const char* key)
return subkeys;
}
std::vector<std::string> getValueList(const char* key) {
std::vector<std::string> getValueList(const char* key)
{
std::vector<std::string> values;
HKEY hKey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
key,
0,
KEY_READ,
&hKey) == ERROR_SUCCESS) {
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys = 0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys = 0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i, retCode;
TCHAR achValue[MAX_VALUE_NAME];
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
retCode = RegQueryInfoKey(
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
for (i = 0, retCode = ERROR_SUCCESS; i < cValues; ++i) {
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue(
hKey,
i,
achValue,
&cchValue,
NULL,
NULL,
NULL,
NULL);
retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL);
if (retCode == ERROR_SUCCESS) {
values.push_back(achValue);
}
@ -254,22 +220,10 @@ std::pair<bool, std::string> WinDNSHelper::hasDNSConfig(uint64_t nwid)
for (auto it2 = dnsRecords.begin(); it2 != dnsRecords.end(); ++it2) {
if ((*it2) == "Comment") {
HKEY hKey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
sub,
0,
KEY_READ,
&hKey) == ERROR_SUCCESS) {
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, sub, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
char buf[16384] = { 0 };
DWORD size = sizeof(buf);
DWORD retCode = RegGetValueA(
HKEY_LOCAL_MACHINE,
sub,
it2->c_str(),
RRF_RT_REG_SZ,
NULL,
&buf,
&size);
DWORD retCode = RegGetValueA(HKEY_LOCAL_MACHINE, sub, it2->c_str(), RRF_RT_REG_SZ, NULL, &buf, &size);
if (retCode == ERROR_SUCCESS) {
if (std::string(networkStr) == std::string(buf)) {
RegCloseKey(hKey);
@ -277,11 +231,10 @@ std::pair<bool, std::string> WinDNSHelper::hasDNSConfig(uint64_t nwid)
}
}
else {
}
}
RegCloseKey(hKey);
}
}
}
}
@ -311,7 +264,8 @@ void WinDNSHelper::setDNS(uint64_t nwid, const char* domain, const std::vector<I
fprintf(stderr, "Error writing dns servers: %d\n", retCode);
}
}
} else {
}
else {
// add new config
const char* baseKey = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
GUID guid;
@ -350,4 +304,4 @@ void WinDNSHelper::removeDNS(uint64_t nwid)
}
}
}
} // namespace ZeroTier

View file

@ -1,24 +1,22 @@
#ifndef WIN_DNS_HELPER_H_
#define WIN_DNS_HELPER_H_
#include <vector>
#include <cstdint>
#include "../node/InetAddress.hpp"
#include <cstdint>
#include <vector>
namespace ZeroTier
{
namespace ZeroTier {
class WinDNSHelper
{
public:
class WinDNSHelper {
public:
static void setDNS(uint64_t nwid, const char* domain, const std::vector<InetAddress>& servers);
static void removeDNS(uint64_t nwid);
private:
private:
static std::pair<bool, std::string> hasDNSConfig(uint64_t nwid);
};
}
} // namespace ZeroTier
#endif

View file

@ -1,10 +1,7 @@
#include "WinFWHelper.hpp"
namespace ZeroTier {
void ZeroTier::WinFWHelper::newICMPRule(const InetAddress& ip, uint64_t nwid)
{
char nwString[32] = { 0 };
@ -12,7 +9,7 @@ void ZeroTier::WinFWHelper::newICMPRule(const InetAddress& ip, uint64_t nwid)
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
ip.toString(ipbuf);
if (ip.isV4()) {
@ -41,7 +38,6 @@ void ZeroTier::WinFWHelper::removeICMPRule(const InetAddress& ip, uint64_t nwid)
}
}
void WinFWHelper::newICMPv4Rule(std::string address, uint64_t nwid)
{
// allows icmp, scoped to a specific ip address and interface name
@ -50,123 +46,112 @@ void WinFWHelper::newICMPv4Rule(std::string address, uint64_t nwid)
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + address +
R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')" +
" -Protocol ICMPv4 -Action Allow" +
" -LocalAddress " + address + "\"\r\n";
_run(cmd);
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + address + R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')"
+ " -Protocol ICMPv4 -Action Allow" + " -LocalAddress " + address + "\"\r\n";
_run(cmd);
}
void WinFWHelper::newICMPv6Rule(std::string address, uint64_t nwid)
{
// allows icmp, scoped to a specific ip address and interface name
// allows icmp, scoped to a specific ip address and interface name
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + address +
R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')" +
" -Protocol ICMPv6 -Action Allow" +
" -LocalAddress " + address + "\"\r\n";
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + address + R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')"
+ " -Protocol ICMPv6 -Action Allow" + " -LocalAddress " + address + "\"\r\n";
_run(cmd);
_run(cmd);
}
void WinFWHelper::removeICMPv4Rule(std::string addr, uint64_t nwid)
{
// removes 1 icmp firewall rule
// removes 1 icmp firewall rule
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + addr +
"\"\r\n";
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + addr + "\"\r\n";
_run(cmd);
_run(cmd);
}
void WinFWHelper::removeICMPv6Rule(std::string addr, uint64_t nwid)
{
// removes 1 icmp firewall rule
// removes 1 icmp firewall rule
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + addr +
"\"\r\n";
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + addr + "\"\r\n";
_run(cmd);
_run(cmd);
}
void WinFWHelper::removeICMPv4Rules(uint64_t nwid)
{
// removes all icmp firewall rules for this network id
// removes all icmp firewall rules for this network id
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + "*\" \r\n";
_run(cmd);
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + "*\" \r\n";
_run(cmd);
}
void WinFWHelper::removeICMPv6Rules(uint64_t nwid)
{
// removes all icmp firewall rules for this network id
// removes all icmp firewall rules for this network id
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
char nwString[32] = { 0 };
sprintf(nwString, "%.16llx", nwid);
std::string nwString2 = { nwString };
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + "*\" \r\n";
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + "*\" \r\n";
_run(cmd);
_run(cmd);
}
void WinFWHelper::removeICMPRules()
{
// removes all icmp firewall rules for all networks
// removes all icmp firewall rules for all networks
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmp*)" + std::string("\r\n");
std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmp*)" + std::string("\r\n");
_run(cmd);
_run(cmd);
}
void WinFWHelper::removeICMPRules(uint64_t nwid)
{
// removes all icmp firewall rules for this network
WinFWHelper::removeICMPv4Rules(nwid);
WinFWHelper::removeICMPv6Rules(nwid);
// removes all icmp firewall rules for this network
WinFWHelper::removeICMPv4Rules(nwid);
WinFWHelper::removeICMPv6Rules(nwid);
}
void WinFWHelper::_run(std::string cmd)
{
#ifdef ZT_DEBUG
fprintf(stderr, cmd.c_str());
#endif
#ifdef ZT_DEBUG
fprintf(stderr, cmd.c_str());
#endif
STARTUPINFOA startupInfo;
PROCESS_INFORMATION processInfo;
startupInfo.cb = sizeof(startupInfo);
memset(&startupInfo, 0, sizeof(STARTUPINFOA));
memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
STARTUPINFOA startupInfo;
PROCESS_INFORMATION processInfo;
startupInfo.cb = sizeof(startupInfo);
memset(&startupInfo, 0, sizeof(STARTUPINFOA));
memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
if (CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) {
WaitForSingleObject(processInfo.hProcess, INFINITE);
if (CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) {
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
}
} // namespace ZeroTier

View file

@ -15,7 +15,6 @@ class WinFWHelper {
static void removeICMPRules(uint64_t nwid);
static void removeICMPRules();
private:
static void _run(std::string cmd);
static void newICMPv4Rule(std::string address, uint64_t nwid);

File diff suppressed because it is too large Load diff

View file

@ -14,27 +14,24 @@
#ifndef ZT_WINDOWSETHERNETTAP_HPP
#define ZT_WINDOWSETHERNETTAP_HPP
#include <stdio.h>
#include <stdlib.h>
#include <ifdef.h>
#include <string>
#include <queue>
#include <stdexcept>
#include "../node/Constants.hpp"
#include "../node/Mutex.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/Mutex.hpp"
#include "../osdep/Thread.hpp"
#include "EthernetTap.hpp"
#include <ifdef.h>
#include <queue>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
namespace ZeroTier {
class WindowsEthernetTap : public EthernetTap
{
public:
class WindowsEthernetTap : public EthernetTap {
public:
/**
* Installs a new instance of the ZT tap driver
*
@ -42,7 +39,7 @@ public:
* @param deviceInstanceId Buffer to fill with device instance ID on success (and if SetupDiGetDeviceInstanceIdA succeeds, which it should)
* @return Empty string on success, otherwise an error message
*/
static std::string addNewPersistentTapDevice(const char *pathToInf,std::string &deviceInstanceId);
static std::string addNewPersistentTapDevice(const char* pathToInf, std::string& deviceInstanceId);
/**
* Uninstalls all persistent tap devices that have legacy drivers
@ -64,7 +61,7 @@ public:
* @param instanceId Device instance ID
* @return Empty string on success, otherwise an error message
*/
static std::string deletePersistentTapDevice(const char *instanceId);
static std::string deletePersistentTapDevice(const char* instanceId);
/**
* Disable a persistent tap device by instance ID
@ -73,51 +70,62 @@ public:
* @param enabled Enable device?
* @return True if device was found and disabled
*/
static bool setPersistentTapDeviceState(const char *instanceId,bool enabled);
static bool setPersistentTapDeviceState(const char* instanceId, bool enabled);
WindowsEthernetTap(
const char *hp,
const MAC &mac,
const char* hp,
const MAC& mac,
unsigned int mtu,
unsigned int metric,
uint64_t nwid,
const char *friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
const char* friendlyName,
void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void* arg);
virtual ~WindowsEthernetTap();
virtual void setEnabled(bool en);
virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip);
virtual bool removeIp(const InetAddress &ip);
virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName);
virtual void setFriendlyName(const char* friendlyName);
virtual std::string friendlyName() const;
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu);
virtual void setDns(const char* domain, const std::vector<InetAddress> &servers);
virtual void setDns(const char* domain, const std::vector<InetAddress>& servers);
inline const NET_LUID &luid() const { return _deviceLuid; }
inline const GUID &guid() const { return _deviceGuid; }
inline const std::string &instanceId() const { return _deviceInstanceId; }
inline const NET_LUID& luid() const
{
return _deviceLuid;
}
inline const GUID& guid() const
{
return _deviceGuid;
}
inline const std::string& instanceId() const
{
return _deviceInstanceId;
}
NET_IFINDEX interfaceIndex() const;
void threadMain()
throw();
void threadMain() throw();
bool isInitialized() const { return _initialized; };
bool isInitialized() const
{
return _initialized;
};
private:
NET_IFINDEX _getDeviceIndex(); // throws on failure
std::vector<std::string> _getRegistryIPv4Value(const char *regKey);
void _setRegistryIPv4Value(const char *regKey,const std::vector<std::string> &value);
private:
NET_IFINDEX _getDeviceIndex(); // throws on failure
std::vector<std::string> _getRegistryIPv4Value(const char* regKey);
void _setRegistryIPv4Value(const char* regKey, const std::vector<std::string>& value);
void _syncIps();
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
void *_arg;
void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void* _arg;
MAC _mac;
uint64_t _nwid;
volatile unsigned int _mtu;
@ -134,13 +142,12 @@ private:
std::string _friendlyName;
Mutex _friendlyName_m;
std::vector<InetAddress> _assignedIps; // IPs assigned with addIp
std::vector<InetAddress> _assignedIps; // IPs assigned with addIp
Mutex _assignedIps_m;
std::vector<MulticastGroup> _multicastGroups;
struct _InjectPending
{
struct _InjectPending {
unsigned int len;
char data[ZT_MAX_MTU + 32];
};
@ -157,6 +164,6 @@ private:
mutable uint64_t _lastIfAddrsUpdate;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif