From f09eedbd7adee2a804978182c1f9fdc2a1ad1d6a Mon Sep 17 00:00:00 2001 From: Daniel Skowroński Date: Sun, 25 Dec 2016 22:54:27 +0100 Subject: make it compilable --- osdep/NetBSDEthernetTap.cpp | 464 ++++++++++++++++++++++++++++++++++++++++++++ osdep/NetBSDEthernetTap.hpp | 84 ++++++++ osdep/freebsd_getifmaddrs.c | 202 +++++++++++++++++++ osdep/freebsd_getifmaddrs.h | 70 +++++++ 4 files changed, 820 insertions(+) create mode 100644 osdep/NetBSDEthernetTap.cpp create mode 100644 osdep/NetBSDEthernetTap.hpp create mode 100644 osdep/freebsd_getifmaddrs.c create mode 100644 osdep/freebsd_getifmaddrs.h (limited to 'osdep') diff --git a/osdep/NetBSDEthernetTap.cpp b/osdep/NetBSDEthernetTap.cpp new file mode 100644 index 00000000..109a2a34 --- /dev/null +++ b/osdep/NetBSDEthernetTap.cpp @@ -0,0 +1,464 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2016 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 . + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "freebsd_getifmaddrs.h" + +#include +#include +#include +#include +#include + +#include "../node/Constants.hpp" +#include "../node/Utils.hpp" +#include "../node/Mutex.hpp" +#include "OSUtils.hpp" +#include "NetBSDEthernetTap.hpp" + +#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv" + +// ff:ff:ff:ff:ff:ff with no ADI +static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); + +namespace ZeroTier { + +NetBSDEthernetTap::NetBSDEthernetTap( + const char *homePath, + const MAC &mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char *friendlyName, + void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void *arg) : + _handler(handler), + _arg(arg), + _nwid(nwid), + _mtu(mtu), + _metric(metric), + _fd(0), + _enabled(true) +{ + static Mutex globalTapCreateLock; + char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32]; + struct stat stattmp; + + // On FreeBSD at least we can rename, so use nwid to generate a deterministic unique zt#### name using base32 + // As a result we don't use desiredDevice + _dev = "zt"; + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 60) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 55) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 50) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 45) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 40) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 35) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 30) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 25) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 20) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 15) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 10) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 5) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]); + + Mutex::Lock _gl(globalTapCreateLock); + + if (mtu > 2800) + throw std::runtime_error("max tap MTU is 2800"); + + // On BSD we create taps and they can have high numbers, so use ones starting + // at 9993 to not conflict with other stuff. Then we rename it to zt + std::vector devFiles(OSUtils::listDirectory("/dev")); + for(int i=9993;i<(9993+128);++i) { + Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); + Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); + if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); + ::_exit(-1); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid,&exitcode,0); + } else throw std::runtime_error("fork() failed"); + + if (!stat(devpath,&stattmp)) { + cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0); + ::_exit(-1); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid,&exitcode,0); + if (exitcode) + throw std::runtime_error("ifconfig rename operation failed"); + } else throw std::runtime_error("fork() failed"); + + _fd = ::open(devpath,O_RDWR); + if (_fd > 0) + break; + else throw std::runtime_error("unable to open created tap device"); + } else { + throw std::runtime_error("cannot find /dev node for newly created tap device"); + } + } + } + + 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 + Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); + Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu); + Utils::snprintf(metstr,sizeof(metstr),"%u",_metric); + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"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"); + } + } + + // 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); + + _thread = Thread::start(this); +} + +NetBSDEthernetTap::~NetBSDEthernetTap() +{ + ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit + Thread::join(_thread); + ::close(_fd); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); + + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); + ::_exit(-1); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid,&exitcode,0); + } +} + +void NetBSDEthernetTap::setEnabled(bool en) +{ + _enabled = en; +} + +bool NetBSDEthernetTap::enabled() const +{ + return _enabled; +} + +static bool ___removeIp(const std::string &_dev,const InetAddress &ip) +{ + long cpid = (long)vfork(); + if (cpid == 0) { + execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0); + _exit(-1); + } else if (cpid > 0) { + int exitcode = -1; + waitpid(cpid,&exitcode,0); + return (exitcode == 0); + } + return false; // never reached, make compiler shut up about return value +} + +bool NetBSDEthernetTap::addIp(const InetAddress &ip) +{ + if (!ip) + return false; + + std::vector allIps(ips()); + if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) + return true; // IP/netmask already assigned + + // Remove and reconfigure if address is the same but netmask is different + for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { + if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { + if (___removeIp(_dev,*i)) + break; + } + } + + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); + ::_exit(-1); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid,&exitcode,0); + return (exitcode == 0); + } + return false; +} + +bool NetBSDEthernetTap::removeIp(const InetAddress &ip) +{ + if (!ip) + return false; + std::vector allIps(ips()); + if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { + if (___removeIp(_dev,ip)) + return true; + } + return false; +} + +std::vector NetBSDEthernetTap::ips() const +{ + struct ifaddrs *ifa = (struct ifaddrs *)0; + if (getifaddrs(&ifa)) + return std::vector(); + + std::vector 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()); + std::unique(r.begin(),r.end()); + + return r; +} + +void NetBSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +{ + char putBuf[4096]; + if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { + to.copyTo(putBuf,6); + from.copyTo(putBuf + 6,6); + *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); + memcpy(putBuf + 14,data,len); + len += 14; + ::write(_fd,putBuf,len); + } +} + +std::string NetBSDEthernetTap::deviceName() const +{ + return _dev; +} + +void NetBSDEthernetTap::setFriendlyName(const char *friendlyName) +{ +} + +void NetBSDEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) +{ + std::vector 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 allIps(ips()); + for(std::vector::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::iterator m(newGroups.begin());m!=newGroups.end();++m) { + if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) + added.push_back(*m); + } + for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { + if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) + removed.push_back(*m); + } + + _multicastGroups.swap(newGroups); +} + +/* +bool NetBSDEthernetTap::updateMulticastGroups(std::set &groups) +{ + std::set 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.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); + } + p = p->ifma_next; + } + freeifmaddrs(ifmap); + } + + { + std::set allIps(ips()); + for(std::set::const_iterator i(allIps.begin());i!=allIps.end();++i) + newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); + } + + bool changed = false; + + for(std::set::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { + if (!groups.count(*mg)) { + groups.insert(*mg); + changed = true; + } + } + for(std::set::iterator mg(groups.begin());mg!=groups.end();) { + if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) { + groups.erase(mg++); + changed = true; + } else ++mg; + } + + return changed; +} +*/ + +void NetBSDEthernetTap::threadMain() + throw() +{ + fd_set readfds,nullfds; + MAC to,from; + int n,nfds,r; + char getBuf[8194]; + + // Wait for a moment after startup -- wait for Network to finish + // constructing itself. + 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,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); + } + + r = 0; + } + } + } + } +} + +} // namespace ZeroTier diff --git a/osdep/NetBSDEthernetTap.hpp b/osdep/NetBSDEthernetTap.hpp new file mode 100644 index 00000000..a555a4b1 --- /dev/null +++ b/osdep/NetBSDEthernetTap.hpp @@ -0,0 +1,84 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2016 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 . + */ + +#ifndef ZT_NetBSDEthernetTap_HPP +#define ZT_NetBSDEthernetTap_HPP + +#include +#include + +#include +#include +#include + +#include "../node/Constants.hpp" +#include "../node/MulticastGroup.hpp" +#include "../node/MAC.hpp" +#include "Thread.hpp" + + + + + +namespace ZeroTier { + +class NetBSDEthernetTap +{ +public: + NetBSDEthernetTap( + const char *homePath, + const MAC &mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char *friendlyName, + void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void *arg); + + ~NetBSDEthernetTap(); + + void setEnabled(bool en); + bool enabled() const; + bool addIp(const InetAddress &ip); + bool removeIp(const InetAddress &ip); + std::vector ips() const; + void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + std::string deviceName() const; + void setFriendlyName(const char *friendlyName); + void scanMulticastGroups(std::vector &added,std::vector &removed); + + void threadMain() + throw(); + +private: + void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void *_arg; + uint64_t _nwid; + Thread _thread; + std::string _dev; + std::vector _multicastGroups; + unsigned int _mtu; + unsigned int _metric; + int _fd; + int _shutdownSignalPipe[2]; + volatile bool _enabled; +}; + +} // namespace ZeroTier + +#endif diff --git a/osdep/freebsd_getifmaddrs.c b/osdep/freebsd_getifmaddrs.c new file mode 100644 index 00000000..559fdc06 --- /dev/null +++ b/osdep/freebsd_getifmaddrs.c @@ -0,0 +1,202 @@ +#define NET_RT_IFMALIST 4 /* return multicast address list */ +#define RTM_NEWMADDR 0xf /* mcast group membership being added to if */ + + +/* + * Copyright (c) 2003 Bruce M. Simpson. + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +/* +__FBSDID("$FreeBSD$"); + +#include "namespace.h"*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +//#include "un-namespace.h" + +#define SALIGN (sizeof(long) - 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) + +int +getifmaddrs(struct 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_msghdr *ifmam; + struct 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] = NET_RT_IFMALIST; + mib[5] = 0; /* no flags */ + do { + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return (-1); + if ((buf = 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 RTM_NEWMADDR: + ifmam = (struct ifma_msghdr *)(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 = malloc(sizeof(struct ifmaddrs) * icnt + dcnt); + if (data == NULL) { + free(buf); + return (-1); + } + + ifa = (struct ifmaddrs *)(void *)data; + data += sizeof(struct ifmaddrs) * icnt; + + memset(ifa, 0, sizeof(struct 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 RTM_NEWMADDR: + ifmam = (struct ifma_msghdr *)(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); +} + +void +freeifmaddrs(struct ifmaddrs *ifmp) +{ + + free(ifmp); +} diff --git a/osdep/freebsd_getifmaddrs.h b/osdep/freebsd_getifmaddrs.h new file mode 100644 index 00000000..a3eeec71 --- /dev/null +++ b/osdep/freebsd_getifmaddrs.h @@ -0,0 +1,70 @@ +/* $FreeBSD$ */ + +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#ifndef _freebsd_getifmaddrs.h_ +#define _freebsd_getifmaddrs.h_ + +/* + * This may have been defined in . Note that if is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +struct ifmaddrs { + struct ifmaddrs *ifma_next; + struct sockaddr *ifma_name; + struct sockaddr *ifma_addr; + struct sockaddr *ifma_lladdr; +}; + +#include + + +/* + * Message format for use in obtaining information about multicast addresses + * 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_addrs; /* like rtm_addrs */ + int ifmam_flags; /* value of ifa_flags */ + int ifmam_index; /* index for associated ifp */ +}; + + +extern int getifaddrs(struct ifaddrs **); +extern void freeifaddrs(struct ifaddrs *); +extern int getifmaddrs(struct ifmaddrs **); +extern void freeifmaddrs(struct ifmaddrs *); +#include "freebsd_getifmaddrs.c" + + +#endif -- cgit v1.2.3 From 218ace51a749a976af7078a1bc433d82c7cd219e Mon Sep 17 00:00:00 2001 From: Daniel Skowroński Date: Mon, 26 Dec 2016 02:52:07 +0100 Subject: use /dev/tap{0..3}; it is fully working now --- osdep/NetBSDEthernetTap.cpp | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) (limited to 'osdep') diff --git a/osdep/NetBSDEthernetTap.cpp b/osdep/NetBSDEthernetTap.cpp index 109a2a34..1dbe312f 100644 --- a/osdep/NetBSDEthernetTap.cpp +++ b/osdep/NetBSDEthernetTap.cpp @@ -61,6 +61,8 @@ #include "OSUtils.hpp" #include "NetBSDEthernetTap.hpp" +#include +using namespace std; #define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv" // ff:ff:ff:ff:ff:ff with no ADI @@ -111,13 +113,12 @@ NetBSDEthernetTap::NetBSDEthernetTap( if (mtu > 2800) throw std::runtime_error("max tap MTU is 2800"); - // On BSD we create taps and they can have high numbers, so use ones starting - // at 9993 to not conflict with other stuff. Then we rename it to zt + // On NetBSD there are /dev/tap{0..3} pre-created and for a moment I will stick with only them std::vector devFiles(OSUtils::listDirectory("/dev")); - for(int i=9993;i<(9993+128);++i) { + for(int i=0;i<4;++i) { Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); - if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { + //if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { long cpid = (long)vfork(); if (cpid == 0) { ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); @@ -127,8 +128,10 @@ NetBSDEthernetTap::NetBSDEthernetTap( ::waitpid(cpid,&exitcode,0); } else throw std::runtime_error("fork() failed"); + _dev = tmpdevname; + _fd = ::open( devpath,O_RDWR); if (!stat(devpath,&stattmp)) { - cpid = (long)vfork(); + /*cpid = (long)vfork(); if (cpid == 0) { ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0); ::_exit(-1); @@ -137,16 +140,16 @@ NetBSDEthernetTap::NetBSDEthernetTap( ::waitpid(cpid,&exitcode,0); if (exitcode) throw std::runtime_error("ifconfig rename operation failed"); - } else throw std::runtime_error("fork() failed"); + } else throw std::runtime_error("fork() failed");*/ + - _fd = ::open(devpath,O_RDWR); if (_fd > 0) break; - else throw std::runtime_error("unable to open created tap device"); + //else throw std::runtime_error("unable to open created tap device "); } else { throw std::runtime_error("cannot find /dev node for newly created tap device"); } - } + //} } if (_fd <= 0) @@ -163,7 +166,7 @@ NetBSDEthernetTap::NetBSDEthernetTap( Utils::snprintf(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); + ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"link",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); ::_exit(-1); } else if (cpid > 0) { int exitcode = -1; @@ -174,12 +177,30 @@ NetBSDEthernetTap::NetBSDEthernetTap( } } + // ifconfig link seems to be different from address + // https://wiki.netbsd.org/tutorials/faking_a_mac_address/ + cpid = (long)vfork(); + if (cpid == 0) { + string cmdline = "net.link.tap."+string(_dev); + cmdline += "="+string(ethaddr); + ::execl("/sbin/sysctl","/sbin/sysctl","-w",cmdline.c_str(),(const char *)0); + ::_exit(-1); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid,&exitcode,0); + if (exitcode) { + ::close(_fd); + throw std::runtime_error("sysctl failure setting link-layer address and activating tap interface"); + } + } + // 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); _thread = Thread::start(this); + } NetBSDEthernetTap::~NetBSDEthernetTap() -- cgit v1.2.3 From 9a2310395d8e4b9666530e5b57547482877b2668 Mon Sep 17 00:00:00 2001 From: Daniel Skowroński Date: Tue, 27 Dec 2016 11:42:43 +0100 Subject: mimic BSDEthernetTap but with creating/destroying char tap device --- osdep/NetBSDEthernetTap.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'osdep') diff --git a/osdep/NetBSDEthernetTap.cpp b/osdep/NetBSDEthernetTap.cpp index 1dbe312f..8f715171 100644 --- a/osdep/NetBSDEthernetTap.cpp +++ b/osdep/NetBSDEthernetTap.cpp @@ -115,7 +115,8 @@ NetBSDEthernetTap::NetBSDEthernetTap( // On NetBSD there are /dev/tap{0..3} pre-created and for a moment I will stick with only them std::vector devFiles(OSUtils::listDirectory("/dev")); - for(int i=0;i<4;++i) { +// for(int i=0;i<4;++i) { + for(int i=9993;i<(9993+128);++i) { Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); //if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { @@ -128,6 +129,20 @@ NetBSDEthernetTap::NetBSDEthernetTap( ::waitpid(cpid,&exitcode,0); } else throw std::runtime_error("fork() failed"); + cpid = (long)vfork(); + if (cpid == 0) { + string tmp; + sprintf((char*)tmp.c_str(), "%d", i); + string minor = tmp.c_str(); + ::execl("/sbin/mknod","/sbin/mknod",devpath,"c","169",minor.c_str(),(const char *)0); //major 169 => tap + ::_exit(-1); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid,&exitcode,0); + } else throw std::runtime_error("fork() failed"); + + cerr<<"created device "< 0) { + int exitcode = -1; + ::waitpid(cpid,&exitcode,0); + } else throw std::runtime_error("fork() failed"); } void NetBSDEthernetTap::setEnabled(bool en) -- cgit v1.2.3 From ba07d1f91d49203856a28890521daf1a5cb2cfcf Mon Sep 17 00:00:00 2001 From: Daniel Skowroński Date: Tue, 27 Dec 2016 11:57:05 +0100 Subject: cleanup --- README.md | 2 +- osdep/NetBSDEthernetTap.cpp | 43 ++++++++----------------------------------- osdep/freebsd_getifmaddrs.c | 5 +++++ osdep/freebsd_getifmaddrs.h | 5 +++++ 4 files changed, 19 insertions(+), 36 deletions(-) (limited to 'osdep') diff --git a/README.md b/README.md index a34a1a53..f9ee85ee 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ For Mac, Linux, and BSD, just type "make" (or "gmake" on BSD). You won't need mu * **Mac**: Xcode command line tools. It should build on OSX 10.7 or newer. * **Linux**: gcc/g++ (4.9 or newer recommended) or clang/clang++ (3.4 or newer recommended) Makefile will use clang by default if available. The Linux build will auto-detect the presence of development headers for *json-parser*, *http-parser*, *li8bnatpmp*, and *libminiupnpc* and will link against the system libraries for these if they are present and recent enough. Otherwise the bundled versions in [ext/](ext/) will be used. Type `make install` to install the binaries and other files on the system, though this will not create init.d or systemd links. - * **FreeBSD**: C++ compiler (G++ usually) and GNU make (gmake). + * **FreeBSD/OpenBSD/NetBSD**: C++ compiler (G++ usually) and GNU make (gmake). Each supported platform has its own *make-XXX.mk* file that contains the actual make rules for the platform. The right .mk file is included by the main Makefile based on the GNU make *OSTYPE* variable. Take a look at the .mk file for your platform for other targets, debug build rules, etc. diff --git a/osdep/NetBSDEthernetTap.cpp b/osdep/NetBSDEthernetTap.cpp index 8f715171..5d1c9625 100644 --- a/osdep/NetBSDEthernetTap.cpp +++ b/osdep/NetBSDEthernetTap.cpp @@ -91,35 +91,17 @@ NetBSDEthernetTap::NetBSDEthernetTap( char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32]; struct stat stattmp; - // On FreeBSD at least we can rename, so use nwid to generate a deterministic unique zt#### name using base32 - // As a result we don't use desiredDevice - _dev = "zt"; - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 60) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 55) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 50) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 45) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 40) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 35) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 30) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 25) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 20) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 15) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 10) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 5) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]); - Mutex::Lock _gl(globalTapCreateLock); if (mtu > 2800) throw std::runtime_error("max tap MTU is 2800"); - // On NetBSD there are /dev/tap{0..3} pre-created and for a moment I will stick with only them + // we can create /dev/tap* std::vector devFiles(OSUtils::listDirectory("/dev")); -// for(int i=0;i<4;++i) { for(int i=9993;i<(9993+128);++i) { Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); - //if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { + if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { long cpid = (long)vfork(); if (cpid == 0) { ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); @@ -134,7 +116,9 @@ NetBSDEthernetTap::NetBSDEthernetTap( string tmp; sprintf((char*)tmp.c_str(), "%d", i); string minor = tmp.c_str(); - ::execl("/sbin/mknod","/sbin/mknod",devpath,"c","169",minor.c_str(),(const char *)0); //major 169 => tap + ::execl("/sbin/mknod","/sbin/mknod",devpath,"c","169",minor.c_str(),(const char *)0); + // http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/conf/majors + // major 169 => tap ::_exit(-1); } else if (cpid > 0) { int exitcode = -1; @@ -146,25 +130,14 @@ NetBSDEthernetTap::NetBSDEthernetTap( _dev = tmpdevname; _fd = ::open( devpath,O_RDWR); if (!stat(devpath,&stattmp)) { - /*cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) - throw std::runtime_error("ifconfig rename operation failed"); - } else throw std::runtime_error("fork() failed");*/ - - if (_fd > 0) break; - //else throw std::runtime_error("unable to open created tap device "); + else + throw std::runtime_error("unable to open created tap device "); } else { throw std::runtime_error("cannot find /dev node for newly created tap device"); } - //} + } } if (_fd <= 0) diff --git a/osdep/freebsd_getifmaddrs.c b/osdep/freebsd_getifmaddrs.c index 559fdc06..8b174146 100644 --- a/osdep/freebsd_getifmaddrs.c +++ b/osdep/freebsd_getifmaddrs.c @@ -1,3 +1,8 @@ +/* + this BSD licensed code is from https://github.com/freebsd/freebsd/blob/386ddae58459341ec567604707805814a2128a57/lib/libc/net/getifmaddrs.c + as in older OS X there is no getifmaddrs() and related functions is NetBSD +*/ + #define NET_RT_IFMALIST 4 /* return multicast address list */ #define RTM_NEWMADDR 0xf /* mcast group membership being added to if */ diff --git a/osdep/freebsd_getifmaddrs.h b/osdep/freebsd_getifmaddrs.h index a3eeec71..166b6d23 100644 --- a/osdep/freebsd_getifmaddrs.h +++ b/osdep/freebsd_getifmaddrs.h @@ -1,3 +1,8 @@ +/* + this BSD code is from https://github.com/freebsd/freebsd/blob/386ddae58459341ec567604707805814a2128a57/include/ifaddrs.h + as in older OS X there is no getifmaddrs() and related functions is NetBSD +*/ + /* $FreeBSD$ */ /* -- cgit v1.2.3 From e276b6463e3df3575386fdede8576c5c3179aac6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 12 Apr 2018 10:33:06 -0400 Subject: Release notes, and shorten Linux canonical network ID derived device names a bit. --- RELEASE-NOTES.md | 38 ++++++++++++++++++++------------------ osdep/LinuxEthernetTap.cpp | 27 +++++++++++++++------------ 2 files changed, 35 insertions(+), 30 deletions(-) (limited to 'osdep') diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index c7185792..9597fc54 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,38 +1,40 @@ ZeroTier Release Notes ====== -# 2018-01-XX -- Version 1.2.6 +# 2018-04-12 -- Version 1.2.6 * Features and Core Improvements * Path selection has been overhauled to improve path stability, simplify code, and prepare for multi-path and trunking in the next major release. - * This version introduces remote tracing for remote diagnostics. Network controllers can set a node (usually the controller itself) to receive remote tracing events from all members of the network or from select members. Events are only sent if they pertain to a given network for security reasons. These can be used to help remotely diagnose problems. In the future we'll be refining and enhancing this feature. - * Multicast replication can now be done by designated multicast replicators on a network (flagged as such at the controller) rather than by the sender. This offers a hub-and-spoke multicast replication topology that may be faster or more bandwidth efficient in certain cases. It's also attractive for use on networks with low powered devices that need to send multicast or where there are very large numbers of multicast recipients. - * Documentation fixes in network controller. - * Performance improvements in crypto and memory operations. + * This version introduces remote tracing for remote diagnostics. Network controllers can set a node (usually the controller itself) to receive remote tracing events from all members of the network or from select members. Events are only sent if they pertain to a given network for security reasons. + * Multicast replication can now be done by designated multicast replicators on a network (flagged as such at the controller) rather than by the sender. Most users won't want this, but it's useful for specialized use cases on hub-and-spoke networks and for low-power devices. + * Cryptographic performance improvements. * Multithreaded performance improvements throughout the code base, including the use of an inline lightweight spinlock for low-contention resources. - * Bug fixes + * Bugs fixed * Disappearing routes on Mac (GitHub issue #600) * Route flapping and path instability in some dual-stack V4/V6 networks * Blacklist (in local.conf) doesn't work reliably (GitHub issue #656) - * Connection instabilities due to unsigned integer overflows in timing comparisons under high load on some multi-core systems - * Binaries don't run on some 32-bit ARM chips (build problem) + * Connection instabilities due to unsigned integer overflows in timing comparisons (use int64_t instead of uint64_t) + * Binaries don't run on some older or lower-end 32-bit ARM chips (build problem) * ARM NEON crypto code crashes (build problem) * Fixed some lock ordering issues revealed by "valgrind" tool * The "zerotier-idtool" command could not be accessed from "zerotier-one" via command line switch - * Leaking UDP sockets on some platforms when NAT-PMP is enabled - * Fixed a very very rare thread deadlock that seemed to only manifest on some systems + * Leaking sockets on some platforms when uPnP/NAT-PMP is enabled + * Fixed two very rare multithreading issues that were only observed on certain systems * Platform-Specific Changes * MacOS - * Installer now loads the kernel extension right away so that High Sierra users will see the prompt to authorize it. This is done in the "Security & Privacy" preference pane and must be done driectly on the console (not via remote desktop). - * About dialog in UI now actually contains something useful. + * Installer now loads the kernel extension right away so that High Sierra users will see the prompt to authorize it. This is done in the "Security & Privacy" preference pane and must be done driectly on the console (not via remote desktop). On High Sierra and newer kexts must be authorized at the console via security settings system preferences pane. * Windows - * The Windows installer should now install the driver without requiring a special prompt in most cases. This should make it easier for our packages to be accepted into and updated in the Chocolatey repository and should make it easier to perform remote installs. - * The Windows official packages are now signed with an EV certificate (with hardware key) from DigiCert for better security and fewer warnings in some cases. - * The Windows UI now contains a preview of features to more deeply integrate it with ZeroTier Central. You can enter a ZeroTier Central API key and join networks, etc. from the UI itself. We'll be expanding this in the future and possibly changing it, so this is just a test to see how users respond. - * The `zerotier-idtool` command should now work on Windows. - * Hopefully we've fixed all instances of the "Windows package will not uninstall" problem on Windows 10. + * The Windows installer should now install the driver without requiring a special prompt in most cases. This should make it easier for our packages to be accepted into and updated in the Chocolatey repository and should make it easier to perform remote installs across groups of machines using IT management and provisioning tools. + * The Windows official packages are now signed with an EV certificate (with hardware key). + * The Windows UI can now log into ZeroTier Central and join networks via the Central API. + * The `zerotier-idtool` command should now work on Windows without ugly hacks. + * Upgraded the installer version. + * Made a few changes to hopefully fix sporadic "will not uninstall" problems, though we cannot duplicate these issues ourselves. * Linux - * Devices are now named deterministically from a base32-encoded packed version of the network ID for newly joined networks. This makes device names longer but also makes them globally unique and canonical. Now a given network will always have the same device name on every Linux system. This makes a lot of devops, deployment, and scripting tasks easier since you can hard code device names by network and they will always work in things like iptables rules and routes. (It's been this way on FreeBSD since the beginning.) + * Device names are now generated deterministically based on network IDs for all newly joined networks. + * Android + * Multicast now works on Android in most cases! Android apps can send and receive multicast and subscribe to multicast group IPs. Note that in some cases the app must bind to the specific correct interface for this to work. + * IPv6 can be disabled in UI for cases where it causes problems. # 2017-04-20 -- Version 1.2.4 diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index 6ef42744..06bbbada 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -146,18 +146,21 @@ LinuxEthernetTap::LinuxEthernetTap( OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); } while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist #else - char devno = 0; + uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network do { - uint64_t tmp2[2]; - tmp2[0] = Utils::hton(nwid); - tmp2[1] = 0; - char tmp3[17]; + const uint64_t nwid40 = (nwid ^ (nwid >> 24)) + trial++; + uint8_t tmp2[5]; + char tmp3[11]; + tmp2[0] = (uint8_t)((nwid40 >> 32) & 0xff); + tmp2[1] = (uint8_t)((nwid40 >> 24) & 0xff); + tmp2[2] = (uint8_t)((nwid40 >> 16) & 0xff); + tmp2[3] = (uint8_t)((nwid40 >> 8) & 0xff); + tmp2[4] = (uint8_t)(nwid40 & 0xff); tmp3[0] = 'z'; - tmp3[1] = 't' + (devno++); - _base32_5_to_8(reinterpret_cast(tmp2),tmp3 + 2); - _base32_5_to_8(reinterpret_cast(tmp2) + 5,tmp3 + 10); - tmp3[15] = (char)0; - memcpy(ifr.ifr_name,tmp3,16); + tmp3[1] = 't'; + _base32_5_to_8(tmp2,tmp3 + 2); + tmp3[10] = (char)0; + memcpy(ifr.ifr_name,tmp3,11); OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); } while (stat(procpath,&sbuf) == 0); #endif @@ -286,7 +289,7 @@ bool LinuxEthernetTap::addIpSyn(std::vector ips) if (cpid == 0) { OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1); - // We must know if there is at least (one) of each protocol version so we + // We must know if there is at least (one) of each protocol version so we // can properly enumerate address/netmask combinations in the ifcfg-dev file for(int i=0; i<(int)ips.size(); i++) { if (ips[i].isV4()) @@ -318,7 +321,7 @@ bool LinuxEthernetTap::addIpSyn(std::vector ips) if (ips[i].isV4()) ::execlp("ip","ip","addr","add",ips[i].toString(iptmp),"broadcast",ips[i].broadcast().toIpString(iptmp2),"dev",_dev.c_str(),(const char *)0); else - ::execlp("ip","ip","addr","add",ips[i].toString(iptmp),"dev",_dev.c_str(),(const char *)0); + ::execlp("ip","ip","addr","add",ips[i].toString(iptmp),"dev",_dev.c_str(),(const char *)0); } ::_exit(-1); } else if (cpid > 0) { -- cgit v1.2.3