mirror of
https://github.com/ZeroTier/ZeroTierOne
synced 2025-08-14 10:37:33 -07:00
Merge master into multipath
This commit is contained in:
commit
77ae929eb3
300 changed files with 20343 additions and 34032 deletions
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
465
osdep/MacEthernetTap.cpp
Normal 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
|
|
@ -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
438
osdep/MacEthernetTapAgent.c
Normal 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;
|
||||
}
|
41
osdep/MacEthernetTapAgent.h
Normal file
41
osdep/MacEthernetTapAgent.h
Normal 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
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue