Merge master into multipath

This commit is contained in:
Joseph Henry 2019-08-12 11:40:13 -07:00
commit 77ae929eb3
300 changed files with 20343 additions and 34032 deletions

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -373,7 +373,7 @@ public:
tcps = phy.tcpListen(reinterpret_cast<const struct sockaddr *>(&(ii->first)),(void *)0);
if ((udps)&&(tcps)) {
#ifdef __LINUX__
// Bind Linux sockets to their device so routes tha we manage do not override physical routes (wish all platforms had this!)
// Bind Linux sockets to their device so routes that we manage do not override physical routes (wish all platforms had this!)
if (ii->second.length() > 0) {
char tmp[256];
Utils::scopy(tmp,sizeof(tmp),ii->second.c_str());
@ -389,7 +389,7 @@ public:
_bindings[_bindingCount].udpSock = udps;
_bindings[_bindingCount].tcpListenSock = tcps;
_bindings[_bindingCount].address = ii->first;
phy.setIfName(udps, (char*)ii->second.c_str(), ii->second.length());
phy.setIfName(udps,(char*)ii->second.c_str(),(int)ii->second.length());
++_bindingCount;
}
} else {

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -32,6 +32,8 @@
#include <condition_variable>
#include <chrono>
#include "Thread.hpp"
namespace ZeroTier {
/**
@ -52,11 +54,27 @@ public:
c.notify_one();
}
inline void postLimit(T t,const unsigned long limit)
{
std::unique_lock<std::mutex> lock(m);
for(;;) {
if (q.size() < limit) {
q.push(t);
c.notify_one();
break;
}
if (!r)
break;
gc.wait(lock);
}
}
inline void stop(void)
{
std::lock_guard<std::mutex> lock(m);
r = false;
c.notify_all();
gc.notify_all();
}
inline bool get(T &value)
@ -65,10 +83,14 @@ public:
if (!r) return false;
while (q.empty()) {
c.wait(lock);
if (!r) return false;
if (!r) {
gc.notify_all();
return false;
}
}
value = q.front();
q.pop();
gc.notify_all();
return true;
}
@ -98,8 +120,8 @@ public:
private:
volatile bool r;
std::queue<T> q;
std::mutex m;
std::condition_variable c;
mutable std::mutex m;
mutable std::condition_variable c,gc;
};
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -29,19 +29,18 @@
#include <unistd.h>
#include <linux/if_tun.h>
namespace ZeroTier {
struct nl_route_req {
struct nlmsghdr nl;
struct rtmsg rt;
char buf[8192];
struct nlmsghdr nl;
struct rtmsg rt;
char buf[8192];
};
struct nl_if_req {
struct nlmsghdr nl;
struct ifinfomsg ifa;
char buf[8192];
struct nlmsghdr nl;
struct ifinfomsg ifa;
char buf[8192];
};
struct nl_adr_req {
@ -63,7 +62,6 @@ LinuxNetLink::LinuxNetLink()
, _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
, _la({0})
{
// set socket timeout to 1 sec so we're not permablocking recv() calls
_setSocketTimeout(_fd, 1);
int yes=1;
@ -77,11 +75,8 @@ LinuxNetLink::LinuxNetLink()
::exit(1);
}
fprintf(stderr, "Requesting IPV4 Routes\n");
_requestIPv4Routes();
fprintf(stderr, "Requesting IPV6 Routes\n");
_requestIPv6Routes();
fprintf(stderr, "Requesting Interface List\n");
_requestInterfaceList();
_running = true;
@ -92,7 +87,6 @@ LinuxNetLink::~LinuxNetLink()
{
_running = false;
Thread::join(_t);
::close(_fd);
}
@ -108,17 +102,23 @@ void LinuxNetLink::_setSocketTimeout(int fd, int seconds)
}
}
#define ZT_NL_BUF_SIZE 16384
int LinuxNetLink::_doRecv(int fd)
{
char buf[8192];
char *const buf = (char *)valloc(ZT_NL_BUF_SIZE);
if (!buf) {
fprintf(stderr,"malloc failed!\n");
::exit(1);
}
char *p = NULL;
struct nlmsghdr *nlp;
int nll = 0;
int rtn = 0;
p = buf;
while(true) {
rtn = recv(fd, p, sizeof(buf) - nll, 0);
for(;;) {
rtn = recv(fd, p, ZT_NL_BUF_SIZE - nll, 0);
if (rtn > 0) {
nlp = (struct nlmsghdr *)p;
@ -127,7 +127,7 @@ int LinuxNetLink::_doRecv(int fd)
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlp);
if (err->error != 0) {
#ifdef ZT_TRACE
fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error)));
//fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error)));
#endif
}
p = buf;
@ -152,9 +152,9 @@ int LinuxNetLink::_doRecv(int fd)
}
if (nlp->nlmsg_type == NLMSG_OVERRUN) {
#ifdef ZT_TRACE
//#ifdef ZT_TRACE
fprintf(stderr, "NLMSG_OVERRUN: Data lost\n");
#endif
//#endif
p = buf;
nll = 0;
break;
@ -163,6 +163,7 @@ int LinuxNetLink::_doRecv(int fd)
nll += rtn;
_processMessage(nlp, nll);
p = buf;
nll = 0;
break;
@ -170,6 +171,9 @@ int LinuxNetLink::_doRecv(int fd)
break;
}
}
free(buf);
return rtn;
}
@ -244,8 +248,9 @@ void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp)
break;
}
}
#ifdef ZT_TRACE
fprintf(stderr,"Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);
//fprintf(stderr,"Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);
#endif
}
@ -259,7 +264,7 @@ void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp)
char local[40] = {0};
char label[40] = {0};
char bcast[40] = {0};
for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal))
{
switch(rtap->rta_type) {
@ -277,8 +282,9 @@ void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp)
break;
}
}
#ifdef ZT_TRACE
fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);
//fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);
#endif
}
@ -290,7 +296,7 @@ void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp)
char ifs[16] = {0};
char ms[24] = {0};
struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);
struct rtmsg *rtp = (struct rtmsg *)NLMSG_DATA(nlp);
struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);
int rtl = RTM_PAYLOAD(nlp);
@ -313,8 +319,9 @@ void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp)
}
}
sprintf(ms, "%d", rtp->rtm_dst_len);
#ifdef ZT_TRACE
fprintf(stderr, "Route Added: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs);
//fprintf(stderr, "Route Added: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs);
#endif
}
@ -351,14 +358,13 @@ void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp)
sprintf(ms, "%d", rtp->rtm_dst_len);
#ifdef ZT_TRACE
fprintf(stderr, "Route Deleted: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs);
//fprintf(stderr, "Route Deleted: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs);
#endif
}
void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp)
{
char mac[18] = {0};
char mac_bin[6] = {0};
unsigned char mac_bin[6] = {0};
unsigned int mtu = 0;
char ifname[IFNAMSIZ] = {0};
@ -366,19 +372,16 @@ void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp)
struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
int ifil = RTM_PAYLOAD(nlp);
const char *ptr;
unsigned char *ptr2;
const char *ptr = (const char *)0;
for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil))
{
switch(rtap->rta_type) {
case IFLA_ADDRESS:
ptr2 = (unsigned char*)RTA_DATA(rtap);
snprintf(mac, 20, "%02x:%02x:%02x:%02x:%02x:%02x",
ptr2[0], ptr2[1], ptr2[2], ptr2[3], ptr2[4], ptr2[5]);
ptr = (const char *)RTA_DATA(rtap);
memcpy(mac_bin, ptr, 6);
break;
case IFLA_IFNAME:
ptr = (const char*)RTA_DATA(rtap);
ptr = (const char *)RTA_DATA(rtap);
memcpy(ifname, ptr, strlen(ptr));
break;
case IFLA_MTU:
@ -392,18 +395,14 @@ void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp)
struct iface_entry &entry = _interfaces[ifip->ifi_index];
entry.index = ifip->ifi_index;
memcpy(entry.ifacename, ifname, sizeof(ifname));
memcpy(entry.mac, mac, sizeof(mac));
snprintf(entry.mac,sizeof(entry.mac),"%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",(unsigned int)mac_bin[0],(unsigned int)mac_bin[1],(unsigned int)mac_bin[2],(unsigned int)mac_bin[3],(unsigned int)mac_bin[4],(unsigned int)mac_bin[5]);
memcpy(entry.mac_bin, mac_bin, 6);
entry.mtu = mtu;
}
#ifdef ZT_TRACE
fprintf(stderr, "Link Added: %s mac: %s, mtu: %d\n", ifname, mac, mtu);
#endif
}
void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp)
{
char mac[18] = {0};
unsigned int mtu = 0;
char ifname[40] = {0};
@ -411,16 +410,10 @@ void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp)
struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
int ifil = RTM_PAYLOAD(nlp);
const char *ptr;
unsigned char *ptr2;
const char *ptr = (const char *)0;
for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil))
{
switch(rtap->rta_type) {
case IFLA_ADDRESS:
ptr2 = (unsigned char*)RTA_DATA(rtap);
snprintf(mac, 20, "%02x:%02x:%02x:%02x:%02x:%02x",
ptr2[0], ptr2[1], ptr2[2], ptr2[3], ptr2[4], ptr2[5]);
break;
case IFLA_IFNAME:
ptr = (const char*)RTA_DATA(rtap);
memcpy(ifname, ptr, strlen(ptr));
@ -430,9 +423,7 @@ void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp)
break;
}
}
#ifdef ZT_TRACE
fprintf(stderr, "Link Deleted: %s mac: %s, mtu: %d\n", ifname, mac, mtu);
#endif
{
Mutex::Lock l(_if_m);
if(_interfaces.contains(ifip->ifi_index)) {
@ -458,7 +449,8 @@ void LinuxNetLink::_requestIPv4Routes()
la.nl_pid = getpid();
la.nl_groups = RTMGRP_IPV4_ROUTE;
if(bind(fd, (struct sockaddr*)&la, sizeof(la))) {
fprintf(stderr, "Error binding RTNETLINK: %s\n", strerror(errno));
fprintf(stderr, "Error binding RTNETLINK (_requiestIPv4Routes #1): %s\n", strerror(errno));
close(fd);
return;
}
@ -512,7 +504,8 @@ void LinuxNetLink::_requestIPv6Routes()
la.nl_pid = getpid();
la.nl_groups = RTMGRP_IPV6_ROUTE;
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK: %s\n", strerror(errno));
fprintf(stderr, "Error binding RTNETLINK (_requestIPv6Routes #1): %s\n", strerror(errno));
close(fd);
return;
}
@ -566,7 +559,8 @@ void LinuxNetLink::_requestInterfaceList()
la.nl_pid = getpid();
la.nl_groups = RTMGRP_LINK;
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK: %s\n", strerror(errno));
fprintf(stderr, "Error binding RTNETLINK (_requestInterfaceList #1): %s\n", strerror(errno));
close(fd);
return;
}
@ -603,6 +597,8 @@ void LinuxNetLink::_requestInterfaceList()
void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName)
{
if (!target) return;
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
int yes=1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes));
@ -619,24 +615,18 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
la.nl_pid = getpid();
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK: %s\n", strerror(errno));
fprintf(stderr, "Error binding RTNETLINK (addRoute #1): %s\n", strerror(errno));
close(fd);
return;
}
#ifdef ZT_TRACE
char tmp[64];
char tmp2[64];
char tmp3[64];
fprintf(stderr, "Adding Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName);
//char tmp[64];
//char tmp2[64];
//char tmp3[64];
//fprintf(stderr, "Adding Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName);
#endif
if(!target) {
#ifdef ZT_TRACE
fprintf(stderr, "Uhhhh adding an empty route?!?!?");
#endif
return;
}
int rtl = sizeof(struct rtmsg);
struct nl_route_req req;
bzero(&req, sizeof(req));
@ -688,8 +678,6 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
}
}
req.nl.nlmsg_len = NLMSG_LENGTH(rtl);
req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE | NLM_F_ACK;
req.nl.nlmsg_type = RTM_NEWROUTE;
@ -727,6 +715,8 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName)
{
if (!target) return;
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
int yes=1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes));
@ -742,22 +732,17 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c
la.nl_pid = getpid();
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK: %s\n", strerror(errno));
fprintf(stderr, "Error binding RTNETLINK (delRoute #1): %s\n", strerror(errno));
close(fd);
return;
}
#ifdef ZT_TRACE
char tmp[64];
char tmp2[64];
char tmp3[64];
fprintf(stderr, "Removing Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName);
#endif
if(!target) {
#ifdef ZT_TRACE
fprintf(stderr, "Uhhhh deleting an empty route?!?!?");
//char tmp[64];
//char tmp2[64];
//char tmp3[64];
//fprintf(stderr, "Removing Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName);
#endif
return;
}
int rtl = sizeof(struct rtmsg);
struct nl_route_req req;
@ -810,8 +795,6 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c
}
}
req.nl.nlmsg_len = NLMSG_LENGTH(rtl);
req.nl.nlmsg_flags = NLM_F_REQUEST;
req.nl.nlmsg_type = RTM_DELROUTE;
@ -860,6 +843,7 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
_setSocketTimeout(fd);
struct sockaddr_nl la;
memset(&la,0,sizeof(la));
la.nl_family = AF_NETLINK;
la.nl_pid = getpid();
if (addr.isV4()) {
@ -867,18 +851,27 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
} else {
la.nl_groups = RTMGRP_IPV6_IFADDR;
}
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK: %s\n", strerror(errno));
fprintf(stderr, "Error binding RTNETLINK (addAddress #1): %s\n", strerror(errno));
close(fd);
return;
}
#ifdef ZT_TRACE
char tmp[128];
fprintf(stderr, "Adding IP address %s to interface %s", addr.toString(tmp), iface);
//char tmp[128];
//fprintf(stderr, "Adding IP address %s to interface %s", addr.toString(tmp), iface);
#endif
int interface_index = _indexForInterface(iface);
for (int reps = 0; interface_index == -1 && reps < 10; ++reps) {
Thread::sleep(100);
interface_index = _indexForInterface(iface);
}
if (interface_index == -1) {
fprintf(stderr, "Unable to find index for interface %s\n", iface);
close(fd);
return;
}
@ -978,17 +971,21 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface)
la.nl_groups = RTMGRP_IPV6_IFADDR;
}
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK: %s\n", strerror(errno));
fprintf(stderr, "Error binding RTNETLINK (removeAddress #1): %s\n", strerror(errno));
close(fd);
return;
}
#ifdef ZT_TRACE
char tmp[128];
fprintf(stderr, "Removing IP address %s from interface %s", addr.toString(tmp), iface);
//char tmp[128];
//fprintf(stderr, "Removing IP address %s from interface %s", addr.toString(tmp), iface);
#endif
int interface_index = _indexForInterface(iface);
if (interface_index == -1) {
fprintf(stderr, "Unable to find index for interface %s\n", iface);
close(fd);
return;
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

465
osdep/MacEthernetTap.cpp Normal file
View file

@ -0,0 +1,465 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#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 "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Dictionary.hpp"
#include "OSUtils.hpp"
#include "MacEthernetTap.hpp"
#include "MacEthernetTapAgent.h"
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
namespace ZeroTier {
static Mutex globalTapCreateLock;
static bool globalTapInitialized = false;
MacEthernetTap::MacEthernetTap(
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),
_agentStdin(-1),
_agentStdout(-1),
_agentStderr(-1),
_agentStdin2(-1),
_agentStdout2(-1),
_agentStderr2(-1),
_agentPid(-1),
_enabled(true)
{
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()))
throw std::runtime_error("MacEthernetTapAgent not installed in ZeroTier home");
Mutex::Lock _gl(globalTapCreateLock); // only make one at a time
// 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) {
globalTapInitialized = true;
struct ifaddrs *ifa = (struct ifaddrs *)0;
std::set<std::string> deleted;
if (!getifaddrs(&ifa)) {
struct ifaddrs *p = ifa;
while (p) {
if ((!strncmp(p->ifa_name,"feth",4))&&(strlen(p->ifa_name) >= 7)&&(deleted.count(std::string(p->ifa_name)) == 0)) {
deleted.insert(std::string(p->ifa_name));
const char *args[4];
args[0] = "/sbin/ifconfig";
args[1] = p->ifa_name;
args[2] = "destroy";
args[3] = (char *)0;
const pid_t pid = vfork();
if (pid == 0) {
execv(args[0],const_cast<char **>(args));
_exit(-1);
} else if (pid > 0) {
int rv = 0;
waitpid(pid,&rv,0);
}
}
p = p->ifa_next;
}
freeifaddrs(ifa);
}
}
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);
bool duplicate = false;
struct ifaddrs *ifa = (struct ifaddrs *)0;
if (!getifaddrs(&ifa)) {
struct ifaddrs *p = ifa;
while (p) {
if (!strcmp(p->ifa_name,devstr)) {
duplicate = true;
break;
}
p = p->ifa_next;
}
freeifaddrs(ifa);
}
if (duplicate) {
devNo = (devNo + 1) % 5000;
if (devNo < 100)
devNo = 100;
} else {
break;
}
}
_dev = devstr;
if (::pipe(_shutdownSignalPipe))
throw std::runtime_error("pipe creation failed");
int agentStdin[2];
int agentStdout[2];
int agentStderr[2];
if (::pipe(agentStdin))
throw std::runtime_error("pipe creation failed");
if (::pipe(agentStdout))
throw std::runtime_error("pipe creation failed");
if (::pipe(agentStderr))
throw std::runtime_error("pipe creation failed");
_agentStdin = agentStdin[1];
_agentStdout = agentStdout[0];
_agentStderr = agentStderr[0];
_agentStdin2 = agentStdin[0];
_agentStdout2 = agentStdout[1];
_agentStderr2 = agentStderr[1];
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);
::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);
::_exit(-1);
} else {
_agentPid = apid;
}
Thread::sleep(100); // this causes them to come up in a more user-friendly order on launch
_thread = Thread::start(this);
}
MacEthernetTap::~MacEthernetTap()
{
Mutex::Lock _gl(globalTapCreateLock);
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
Thread::join(_thread);
::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]);
int ec = 0;
::kill(_agentPid,SIGTERM);
::waitpid(_agentPid,&ec,0);
::close(_agentStdin);
::close(_agentStdout);
::close(_agentStderr);
::close(_agentStdin2);
::close(_agentStdout2);
::close(_agentStderr2);
}
void MacEthernetTap::setEnabled(bool en) { _enabled = en; }
bool MacEthernetTap::enabled() const { return _enabled; }
bool MacEthernetTap::addIp(const InetAddress &ip)
{
char tmp[128];
if (!ip)
return false;
std::string cmd;
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet");
cmd.push_back(0);
cmd.append(ip.toString(tmp));
cmd.push_back(0);
cmd.append("alias");
cmd.push_back(0);
uint16_t l = (uint16_t)cmd.length();
_putLock.lock();
write(_agentStdin,&l,2);
write(_agentStdin,cmd.data(),cmd.length());
_putLock.unlock();
return true;
}
bool MacEthernetTap::removeIp(const InetAddress &ip)
{
char tmp[128];
if (!ip)
return false;
std::string cmd;
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet");
cmd.push_back(0);
cmd.append(ip.toString(tmp));
cmd.push_back(0);
cmd.append("-alias");
cmd.push_back(0);
uint16_t l = (uint16_t)cmd.length();
_putLock.lock();
write(_agentStdin,&l,2);
write(_agentStdin,cmd.data(),cmd.length());
_putLock.unlock();
return true;
}
std::vector<InetAddress> MacEthernetTap::ips() const
{
struct ifaddrs *ifa = (struct ifaddrs *)0;
std::vector<InetAddress> r;
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) {
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;
case AF_INET6: {
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;
}
}
p = p->ifa_next;
}
freeifaddrs(ifa);
}
std::sort(r.begin(),r.end());
r.erase(std::unique(r.begin(),r.end()),r.end());
return r;
}
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)) {
hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET;
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);
iov[0].iov_base = &l;
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_len = len;
_putLock.lock();
writev(_agentStdin,iov,3);
_putLock.unlock();
}
}
std::string MacEthernetTap::deviceName() const { return _dev; }
void MacEthernetTap::setFriendlyName(const char *friendlyName) {}
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;
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));
}
p = p->ifma_next;
}
freeifmaddrs(ifmap);
}
std::vector<InetAddress> allIps(ips());
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());
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))
removed.push_back(*m);
}
_multicastGroups.swap(newGroups);
}
void MacEthernetTap::setMtu(unsigned int mtu)
{
if (_mtu != mtu) {
char tmp[16];
std::string cmd;
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
cmd.append("mtu");
cmd.push_back(0);
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());
_putLock.unlock();
_mtu = mtu;
}
}
#define ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE 131072
void MacEthernetTap::threadMain()
throw()
{
char agentReadBuf[ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE];
char agentStderrBuf[256];
fd_set readfds,nullfds;
MAC to,from;
Thread::sleep(250);
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);
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);
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 (n > 0) {
agentReadPtr += n;
while (agentReadPtr >= 2) {
long len = *((uint16_t *)agentReadBuf);
if (agentReadPtr >= (len + 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 (agentReadPtr > (len + 2)) {
memmove(agentReadBuf,agentReadBuf + len + 2,agentReadPtr -= (len + 2));
} else {
agentReadPtr = 0;
}
} else {
break;
}
}
}
}
if (FD_ISSET(_agentStderr,&readfds)) {
read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf));
/*
const ssize_t n = read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf));
if (n > 0)
write(STDERR_FILENO,agentStderrBuf,(size_t)n);
*/
}
}
}
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -38,18 +38,16 @@
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/Mutex.hpp"
#include "Thread.hpp"
namespace ZeroTier {
/**
* OSX Ethernet tap using ZeroTier kernel extension zt# devices
*/
class OSXEthernetTap
class MacEthernetTap
{
public:
OSXEthernetTap(
MacEthernetTap(
const char *homePath,
const MAC &mac,
unsigned int mtu,
@ -59,7 +57,7 @@ public:
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
void *arg);
~OSXEthernetTap();
~MacEthernetTap();
void setEnabled(bool en);
bool enabled() const;
@ -83,10 +81,12 @@ private:
std::string _homePath;
std::string _dev;
std::vector<MulticastGroup> _multicastGroups;
Mutex _putLock;
unsigned int _mtu;
unsigned int _metric;
int _fd;
int _shutdownSignalPipe[2];
int _agentStdin,_agentStdout,_agentStderr,_agentStdin2,_agentStdout2,_agentStderr2;
long _agentPid;
volatile bool _enabled;
};

438
osdep/MacEthernetTapAgent.c Normal file
View file

@ -0,0 +1,438 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
/*
* This creates a pair of feth devices with the lower numbered device
* being the ZeroTier virtual interface and the other being the device
* used to actually read and write packets. The latter gets no IP config
* and is only used for I/O. The behavior of feth is similar to the
* veth pairs that exist on Linux.
*
* The feth device has only existed since MacOS Sierra, but that's fairly
* long ago in Mac terms.
*
* I/O with feth must be done using two different sockets. The BPF socket
* is used to receive packets, while an AF_NDRV (low-level network driver
* access) socket must be used to inject. AF_NDRV can't read IP frames
* since BSD doesn't forward packets out the NDRV tap if they've already
* been handled, and while BPF can inject its MTU for injected packets
* is limited to 2048. AF_NDRV packet injection is required to inject
* ZeroTier's large MTU frames.
*
* Benchmarks show that this performs similarly to the old tap.kext driver,
* and a kext is no longer required. Splitting it off into an agent will
* also make it easier to have zerotier-one itself drop permissions.
*
* All this stuff is basically undocumented. A lot of tracing through
* the Darwin/XNU kernel source was required to figure out how to make
* this actually work.
*
* See also:
*
* https://apple.stackexchange.com/questions/337715/fake-ethernet-interfaces-feth-if-fake-anyone-ever-seen-this
* https://opensource.apple.com/source/xnu/xnu-4570.41.2/bsd/net/if_fake.c.auto.html
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/signal.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 <sys/sysctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/bpf.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/ndrv.h>
#include <netinet/in_var.h>
#include <netinet/icmp6.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#include <ifaddrs.h>
#include "../version.h"
#include "MacEthernetTapAgent.h"
#ifndef SIOCAUTOCONF_START
#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 */
#endif
#define P_IFCONFIG "/sbin/ifconfig"
static unsigned char s_pktReadBuf[131072] __attribute__ ((__aligned__(16)));
static unsigned char s_stdinReadBuf[131072] __attribute__ ((__aligned__(16)));
static char s_deviceName[IFNAMSIZ];
static char s_peerDeviceName[IFNAMSIZ];
static int s_bpffd = -1;
static int s_ndrvfd = -1;
static pid_t s_parentPid;
static void configureIpv6Parameters(const char *ifname,int performNUD,int acceptRouterAdverts)
{
struct in6_ndireq nd;
struct in6_ifreq ifr;
int s = socket(AF_INET6,SOCK_DGRAM,0);
if (s <= 0)
return;
memset(&nd,0,sizeof(nd));
strncpy(nd.ifname,ifname,sizeof(nd.ifname));
if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
close(s);
return;
}
unsigned long oldFlags = (unsigned long)nd.ndi.flags;
if (performNUD)
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)) {
close(s);
return;
}
}
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;
}
close(s);
}
static int run(const char *path,...)
{
va_list ap;
char *args[16];
int argNo = 1;
va_start(ap,path);
args[0] = (char *)path;
for(;argNo<15;++argNo) {
args[argNo] = va_arg(ap,char *);
if (!args[argNo]) {
break;
}
}
args[argNo++] = (char *)0;
va_end(ap);
pid_t pid = vfork();
if (pid < 0) {
return -1;
} else if (pid == 0) {
dup2(STDERR_FILENO,STDOUT_FILENO);
execv(args[0],args);
_exit(-1);
}
int rv = 0;
waitpid(pid,&rv,0);
return rv;
}
static void die()
{
if (s_ndrvfd >= 0)
close(s_ndrvfd);
if (s_bpffd >= 0)
close(s_bpffd);
if (s_deviceName[0])
run("/sbin/ifconfig",s_deviceName,"destroy",(char *)0);
if (s_peerDeviceName[0])
run("/sbin/ifconfig",s_peerDeviceName,"destroy",(char *)0);
}
int main(int argc,char **argv)
{
char buf[128];
struct ifreq ifr;
u_int fl;
fd_set rfds,wfds,efds;
struct iovec iov[2];
s_deviceName[0] = 0;
s_peerDeviceName[0] = 0;
s_parentPid = getppid();
atexit(&die);
signal(SIGIO,SIG_IGN);
signal(SIGCHLD,SIG_IGN);
signal(SIGPIPE,SIG_IGN);
signal(SIGUSR1,SIG_IGN);
signal(SIGUSR2,SIG_IGN);
signal(SIGALRM,SIG_IGN);
signal(SIGQUIT,&exit);
signal(SIGTERM,&exit);
signal(SIGKILL,&exit);
signal(SIGINT,&exit);
signal(SIGPIPE,&exit);
if (getuid() != 0) {
if (setuid(0) != 0) {
fprintf(stderr,"E must be run as root or with root setuid bit on executable\n");
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
}
}
if (argc < 5) {
fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> <mac> <mtu> <metric>)\n");
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
}
const int deviceNo = atoi(argv[1]);
if ((deviceNo < 0)||(deviceNo > 4999)) {
fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> <mac> <mtu> <metric>)\n");
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
}
const char *mac = argv[2];
const char *mtu = argv[3];
const char *metric = argv[4];
s_ndrvfd = socket(AF_NDRV,SOCK_RAW,0);
if (s_ndrvfd < 0) {
fprintf(stderr,"E unable to open AF_NDRV socket\n");
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
snprintf(s_deviceName,sizeof(s_deviceName),"feth%d",deviceNo);
snprintf(s_peerDeviceName,sizeof(s_peerDeviceName),"feth%d",deviceNo+5000);
if (run(P_IFCONFIG,s_peerDeviceName,"create",(char *)0) != 0) {
fprintf(stderr,"E unable to create %s\n",s_deviceName);
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
usleep(10);
if (run(P_IFCONFIG,s_deviceName,"create",(char *)0) != 0) {
fprintf(stderr,"E unable to create %s\n",s_deviceName);
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
run(P_IFCONFIG,s_deviceName,"lladdr",mac,(char *)0);
usleep(10);
run(P_IFCONFIG,s_peerDeviceName,"peer",s_deviceName,(char *)0);
usleep(10);
run(P_IFCONFIG,s_peerDeviceName,"mtu","16370","up",(char *)0); /* 16370 is the largest MTU MacOS/Darwin seems to allow */
usleep(10);
run(P_IFCONFIG,s_deviceName,"mtu",mtu,"metric",metric,"up",(char *)0);
usleep(10);
configureIpv6Parameters(s_deviceName,1,0);
usleep(10);
struct sockaddr_ndrv nd;
nd.snd_len = sizeof(struct sockaddr_ndrv);
nd.snd_family = AF_NDRV;
memcpy(nd.snd_name,s_peerDeviceName,sizeof(nd.snd_name));
if (bind(s_ndrvfd,(struct sockaddr *)&nd,sizeof(nd)) != 0) {
fprintf(stderr,"E unable to bind AF_NDRV socket\n");
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
if (connect(s_ndrvfd,(struct sockaddr *)&nd,sizeof(nd)) != 0) {
fprintf(stderr,"E unable to connect AF_NDRV socket\n");
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
/* Start at /dev/bpf1 since some simple bpf-using net utilities hard-code /dev/bpf0.
* Things like libpcap are smart enough to search. */
for(int bpfno=1;bpfno<5000;++bpfno) {
char tmp[32];
snprintf(tmp,sizeof(tmp),"/dev/bpf%d",bpfno);
s_bpffd = open(tmp,O_RDWR);
if (s_bpffd >= 0) {
break;
}
}
if (s_bpffd < 0) {
fprintf(stderr,"E unable to open bpf device\n");
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
fl = sizeof(s_pktReadBuf);
if (ioctl(s_bpffd,BIOCSBLEN,&fl) != 0) {
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
const size_t readPktSize = (size_t)fl;
fl = 1;
if (ioctl(s_bpffd,BIOCIMMEDIATE,&fl) != 0) {
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
fl = 0;
if (ioctl(s_bpffd,BIOCSSEESENT,&fl) != 0) {
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
memset(&ifr,0,sizeof(ifr));
memcpy(ifr.ifr_name,s_peerDeviceName,IFNAMSIZ);
if (ioctl(s_bpffd,BIOCSETIF,&ifr) != 0) {
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
fl = 1;
if (ioctl(s_bpffd,BIOCSHDRCMPLT,&fl) != 0) {
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
fl = 1;
if (ioctl(s_bpffd,BIOCPROMISC,&fl) != 0) {
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
}
fprintf(stderr,"I %s %s %d.%d.%d.%d\n",s_deviceName,s_peerDeviceName,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD);
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
long stdinReadPtr = 0;
for(;;) {
FD_SET(STDIN_FILENO,&rfds);
FD_SET(s_bpffd,&rfds);
if (select(s_bpffd+1,&rfds,&wfds,&efds,(struct timeval *)0) < 0) {
if ((errno == EAGAIN)||(errno == EINTR)) {
usleep(10);
continue;
}
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR;
}
if (FD_ISSET(s_bpffd,&rfds)) {
long n = (long)read(s_bpffd,s_pktReadBuf,readPktSize);
if (n > 0) {
for(unsigned char *p=s_pktReadBuf,*eof=p+n;p<eof;) {
struct bpf_hdr *h = (struct bpf_hdr *)p;
if ((h->bh_caplen > 0)&&((p + h->bh_hdrlen + h->bh_caplen) <= eof)) {
uint16_t len = (uint16_t)h->bh_caplen;
iov[0].iov_base = &len;
iov[0].iov_len = 2;
iov[1].iov_base = p + h->bh_hdrlen;
iov[1].iov_len = h->bh_caplen;
writev(STDOUT_FILENO,iov,2);
}
p += BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen);
}
}
}
if (FD_ISSET(STDIN_FILENO,&rfds)) {
long n = (long)read(STDIN_FILENO,s_stdinReadBuf + stdinReadPtr,sizeof(s_stdinReadBuf) - stdinReadPtr);
if (n > 0) {
stdinReadPtr += n;
while (stdinReadPtr >= 2) {
long len = *((uint16_t *)s_stdinReadBuf);
if (stdinReadPtr >= (len + 2)) {
if (len > 0) {
unsigned char *msg = s_stdinReadBuf + 2;
switch(msg[0]) {
case ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET:
if (len > 1) {
if (write(s_ndrvfd,msg+1,len-1) < 0) {
fprintf(stderr,"E inject failed size==%ld errno==%d\n",len-1,errno);
}
}
break;
case ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG: {
char *args[16];
args[0] = P_IFCONFIG;
args[1] = s_deviceName;
int argNo = 2;
for(int argPtr=0,k=1,l=(int)len;k<l;++k) {
if (!msg[k]) {
if (argPtr > 0) {
argPtr = 0;
++argNo;
if (argNo >= 15) {
break;
}
}
} else {
if (argPtr == 0) {
args[argNo] = (char *)(msg + k);
}
argPtr++;
}
}
args[argNo] = (char *)0;
if (argNo > 2) {
pid_t pid = fork();
if (pid < 0) {
return -1;
} else if (pid == 0) {
dup2(STDERR_FILENO,STDOUT_FILENO);
execv(args[0],args);
_exit(-1);
}
int rv = 0;
waitpid(pid,&rv,0);
}
} break;
case ZT_MACETHERNETTAPAGENT_STDIN_CMD_EXIT:
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS;
default:
fprintf(stderr,"E unrecognized message type over pipe from host process: %d (length: %d)\n",(int)msg[0],(int)len);
break;
}
}
if (stdinReadPtr > (len + 2)) {
memmove(s_stdinReadBuf,s_stdinReadBuf + len + 2,stdinReadPtr -= (len + 2));
} else {
stdinReadPtr = 0;
}
} else {
break;
}
}
}
}
}
return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS;
}

View file

@ -0,0 +1,41 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_MACETHERNETTAPAGENT_H
#define ZT_MACETHERNETTAPAGENT_H
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS 0
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST -1
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE -2
#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR -3
#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET 0
#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG 1
#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_EXIT 2
#define ZT_MACETHERNETTAPAGENT_DEFAULT_SYSTEM_PATH "/Library/Application Support/ZeroTier/One/MacEthernetTapAgent"
#endif

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#include <stdint.h>

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_NetBSDEthernetTap_HPP
@ -31,10 +39,6 @@
#include "../node/MAC.hpp"
#include "Thread.hpp"
namespace ZeroTier {
class NetBSDEthernetTap

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -29,6 +29,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <stdlib.h>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
@ -398,6 +399,21 @@ std::string OSUtils::platformDefaultHomePath()
return homeDir;
#endif
// Check for user-defined environment variable before using defaults
#ifdef __WINDOWS__
DWORD bufferSize = 65535;
std::string userDefinedPath;
bufferSize = GetEnvironmentVariable("ZEROTIER_HOME", &userDefinedPath[0], bufferSize);
if (bufferSize) {
return userDefinedPath;
}
#else
if(const char* userDefinedPath = getenv("ZEROTIER_HOME")) {
return std::string(userDefinedPath);
}
#endif
// Finally, resort to using default paths if no user-defined path was provided
#ifdef __UNIX_LIKE__
#ifdef __APPLE__
@ -432,6 +448,7 @@ std::string OSUtils::platformDefaultHomePath()
#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); }
@ -523,6 +540,8 @@ std::string OSUtils::jsonBinFromHex(const nlohmann::json &jv)
return std::string();
}
#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 };

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -55,7 +55,9 @@
#endif
#endif
#ifndef OMIT_JSON_SUPPORT
#include "../ext/json/json.hpp"
#endif
namespace ZeroTier {
@ -284,6 +286,7 @@ 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);
@ -291,6 +294,7 @@ public:
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:
static const unsigned char TOLOWER_TABLE[256];

View file

@ -1,703 +0,0 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#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_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 <netinet/icmp6.h>
// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!?
struct prf_ra {
u_char onlink : 1;
u_char autonomous : 1;
u_char reserved : 6;
} prf_ra;
#include <netinet6/nd6.h>
#include <ifaddrs.h>
// These are KERNEL_PRIVATE... why?
#ifndef SIOCAUTOCONF_START
#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 */
#endif
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// This source is from:
// 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)
/* 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
//#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
// 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;
};
static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
{
int icnt = 1;
int dcnt = 0;
int ntry = 0;
size_t len;
size_t needed;
int mib[6];
int i;
char *buf;
char *data;
char *next;
char *p;
struct ifma_msghdr2 *ifmam;
struct _intl_ifmaddrs *ifa, *ift;
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[4] = GIM_SYSCTL_MIB;
mib[5] = 0; /* no flags */
do {
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return (-1);
if ((buf = (char *)malloc(needed)) == NULL)
return (-1);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
free(buf);
return (-1);
}
free(buf);
buf = NULL;
}
} while (buf == NULL);
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
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;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break;
icnt++;
p = (char *)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs &
(1 << i)) == 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
dcnt += len;
p += len;
}
break;
}
}
data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
if (data == NULL) {
free(buf);
return (-1);
}
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;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case GIM_RTM_ADDR:
ifmam = (struct ifma_msghdr2 *)(void *)rtm;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break;
p = (char *)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs &
(1 << i)) == 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
switch (i) {
case RTAX_GATEWAY:
ift->ifma_lladdr =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_IFP:
ift->ifma_name =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_IFA:
ift->ifma_addr =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
default:
data += len;
break;
}
p += len;
}
ift->ifma_next = ift + 1;
ift = ift->ifma_next;
break;
}
}
free(buf);
if (ift > ifa) {
ift--;
ift->ifma_next = NULL;
*pif = ifa;
} else {
*pif = NULL;
free(ifa);
}
return (0);
}
static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
{
free(ifmp);
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
#include <string>
#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 "OSXEthernetTap.hpp"
// ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
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);
if (s <= 0)
return false;
memset(&nd,0,sizeof(nd));
strncpy(nd.ifname,ifname,sizeof(nd.ifname));
if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
close(s);
return false;
}
unsigned long oldFlags = (unsigned long)nd.ndi.flags;
if (performNUD)
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)) {
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)) {
close(s);
return false;
}
close(s);
return true;
}
namespace ZeroTier {
static long globalTapsRunning = 0;
static Mutex globalTapCreateLock;
OSXEthernetTap::OSXEthernetTap(
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)
{
char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32];
struct stat stattmp;
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid);
Mutex::Lock _gl(globalTapCreateLock);
if (::stat("/dev/zt0",&stattmp)) {
long kextpid = (long)vfork();
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);
::_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))
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");
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;
}
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);
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);
if (_fd > 0) {
_dev = gdmEntry->second;
recalledDevice = true;
}
}
}
// 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))
throw std::runtime_error("no more TAP devices available");
_fd = ::open(devpath,O_RDWR);
if (_fd > 0) {
char foo[16];
OSUtils::ztsnprintf(foo,sizeof(foo),"zt%d",i);
_dev = foo;
break;
}
}
}
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) {
::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);
long cpid = (long)vfork();
if (cpid == 0) {
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
::_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
::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);
// 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);
::pipe(_shutdownSignalPipe);
++globalTapsRunning;
globalDeviceMap[nwids] = _dev;
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());
++gdmEntry;
}
fclose(devmapf);
}
_thread = Thread::start(this);
}
OSXEthernetTap::~OSXEthernetTap()
{
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
Thread::join(_thread);
::close(_fd);
::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]);
{
Mutex::Lock _gl(globalTapCreateLock);
if (--globalTapsRunning <= 0) {
globalTapsRunning = 0; // sanity check -- should not be possible
char tmp[16384];
sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext");
long kextpid = (long)vfork();
if (kextpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0);
::_exit(-1);
} else if (kextpid > 0) {
int exitcode = -1;
::waitpid(kextpid,&exitcode,0);
}
}
}
}
void OSXEthernetTap::setEnabled(bool en)
{
_enabled = en;
// TODO: interface status change
}
bool OSXEthernetTap::enabled() const
{
return _enabled;
}
bool OSXEthernetTap::addIp(const InetAddress &ip)
{
if (!ip)
return false;
long cpid = (long)vfork();
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);
::_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
::waitpid(cpid,&exitcode,0);
return (exitcode == 0);
} // else return false...
return false;
}
bool OSXEthernetTap::removeIp(const InetAddress &ip)
{
if (!ip)
return true;
std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
if (*i == ip) {
long cpid = (long)vfork();
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);
_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
return (exitcode == 0);
}
}
}
return false;
}
std::vector<InetAddress> OSXEthernetTap::ips() const
{
struct ifaddrs *ifa = (struct ifaddrs *)0;
if (getifaddrs(&ifa))
return std::vector<InetAddress>();
std::vector<InetAddress> r;
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) {
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;
case AF_INET6: {
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;
}
}
p = p->ifa_next;
}
if (ifa)
freeifaddrs(ifa);
std::sort(r.begin(),r.end());
r.erase(std::unique(r.begin(),r.end()),r.end());
return r;
}
void OSXEthernetTap::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);
len += 14;
::write(_fd,putBuf,len);
}
}
std::string OSXEthernetTap::deviceName() const
{
return _dev;
}
void OSXEthernetTap::setFriendlyName(const char *friendlyName)
{
}
void OSXEthernetTap::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;
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));
}
p = p->ifma_next;
}
_intl_freeifmaddrs(ifmap);
}
std::vector<InetAddress> allIps(ips());
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());
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))
removed.push_back(*m);
}
_multicastGroups.swap(newGroups);
}
void OSXEthernetTap::setMtu(unsigned int mtu)
{
if (mtu != _mtu) {
_mtu = mtu;
long cpid = (long)vfork();
if (cpid == 0) {
char tmp[64];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu);
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0);
_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
}
}
}
void OSXEthernetTap::threadMain()
throw()
{
fd_set readfds,nullfds;
MAC to,from;
int n,nfds,r;
char getBuf[ZT_MAX_MTU + 64];
Thread::sleep(500);
FD_ZERO(&readfds);
FD_ZERO(&nullfds);
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);
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 (n < 0) {
if ((errno != EINTR)&&(errno != ETIMEDOUT))
break;
} 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
r = _mtu + 14;
if (_enabled) {
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);
}
r = 0;
}
}
}
}
}
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -58,6 +58,8 @@
#include "..\windows\TapDriver6\tap-windows.h"
#include <netcon.h>
// Create a fake unused default route to force detection of network type on networks without gateways
#define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE
@ -824,6 +826,61 @@ void WindowsEthernetTap::setFriendlyName(const char *dn)
RegSetKeyValueA(ifp,"Connection","Name",REG_SZ,(LPCVOID)dn,(DWORD)(strlen(dn)+1));
RegCloseKey(ifp);
}
HRESULT hr = CoInitialize(nullptr);
if (hr != S_OK) return;
CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, EOAC_NONE, NULL);
if (hr != S_OK) return;
INetSharingManager *nsm;
hr = CoCreateInstance(__uuidof(NetSharingManager), NULL, CLSCTX_ALL, __uuidof(INetSharingManager), (void**)&nsm);
if (hr != S_OK) return;
bool found = false;
INetSharingEveryConnectionCollection *nsecc = nullptr;
hr = nsm->get_EnumEveryConnection(&nsecc);
if (!nsecc) {
fprintf(stderr, "Failed to get NSM connections");
return;
}
IEnumVARIANT *ev = nullptr;
IUnknown *unk = nullptr;
hr = nsecc->get__NewEnum(&unk);
if (unk) {
hr = unk->QueryInterface(__uuidof(IEnumVARIANT), (void**)&ev);
unk->Release();
}
if (ev) {
VARIANT v;
VariantInit(&v);
while ((S_OK == ev->Next(1, &v, NULL)) && found == FALSE) {
if (V_VT(&v) == VT_UNKNOWN) {
INetConnection *nc = nullptr;
V_UNKNOWN(&v)->QueryInterface(__uuidof(INetConnection), (void**)&nc);
if (nc) {
NETCON_PROPERTIES *ncp = nullptr;
nc->GetProperties(&ncp);
GUID curId = ncp->guidId;
if (curId == _deviceGuid) {
wchar_t wtext[255];
mbstowcs(wtext, dn, strlen(dn)+1);
nc->Rename(wtext);
found = true;
}
nc->Release();
}
}
VariantClear(&v);
}
ev->Release();
}
nsecc->Release();
}
void WindowsEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -53,12 +53,12 @@ struct ifmaddrs {
/*
* Message format for use in obtaining information about multicast addresses
* from the routing socket
* from the routing socket.
*/
struct ifma_msghdr {
int ifmam_msglen; /* to skip over non-understood messages */
int ifmam_version; /* future binary compatibility */
int ifmam_type; /* message type */
int ifmam_type; /* message type */
int ifmam_addrs; /* like rtm_addrs */
int ifmam_flags; /* value of ifa_flags */
int ifmam_index; /* index for associated ifp */