diff options
author | Adam Ierymenko <adam.ierymenko@zerotier.com> | 2014-04-08 12:00:21 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@zerotier.com> | 2014-04-08 12:00:21 -0700 |
commit | 5abfb11813d0db9a85903712db2b3389c7c34d6e (patch) | |
tree | 8bd6c240dd69f519a22147d54f308fefabe0f67c | |
parent | 0b8d6c7f4a9c7753e5da255bd213ef8fde59bb1e (diff) | |
download | infinitytier-5abfb11813d0db9a85903712db2b3389c7c34d6e.tar.gz infinitytier-5abfb11813d0db9a85903712db2b3389c7c34d6e.zip |
Some installer stuff, complete refactoring of Windows side of newly split tap driver. Seems to work. Now to see if the cleanup we did here gets rid of the zombie tap device issue on Windows.
-rw-r--r-- | ext/installfiles/windows/ZeroTier One.aip | 2 | ||||
-rw-r--r-- | node/WindowsEthernetTap.cpp | 1350 | ||||
-rw-r--r-- | node/WindowsEthernetTap.hpp | 180 | ||||
-rw-r--r-- | windows/ZeroTierOne/ZeroTierOne.vcxproj | 3 | ||||
-rw-r--r-- | windows/ZeroTierOne/ZeroTierOne.vcxproj.filters | 9 |
5 files changed, 223 insertions, 1321 deletions
diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index e8a68294..4b65a681 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -20,7 +20,7 @@ <ROW Property="CTRLS" Value="2"/> <ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/> <ROW Property="Manufacturer" Value="ZeroTier Networks LLC"/> - <ROW Property="ProductCode" Value="1033:{58C56791-D77F-4B3D-A5BF-AB3C11DDE4CF} " Type="16"/> + <ROW Property="ProductCode" Value="1033:{D74139EC-0303-454F-8812-2407A0ED13B3} " Type="16"/> <ROW Property="ProductLanguage" Value="1033"/> <ROW Property="ProductName" Value="ZeroTier One"/> <ROW Property="ProductVersion" Value="0.8.0" Type="32"/> diff --git a/node/WindowsEthernetTap.cpp b/node/WindowsEthernetTap.cpp index 5b7ea575..8a9bc035 100644 --- a/node/WindowsEthernetTap.cpp +++ b/node/WindowsEthernetTap.cpp @@ -25,1045 +25,174 @@ * LLC. Start here: http://www.zerotier.com/ */ -#include <string> -#include <map> -#include <set> -#include <algorithm> - #include "Constants.hpp" + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <WinSock2.h> +#include <Windows.h> +#include <tchar.h> +#include <winreg.h> +#include <wchar.h> +#include <ws2ipdef.h> +#include <WS2tcpip.h> +#include <IPHlpApi.h> +#include <nldef.h> +#include <netioapi.h> + #include "EthernetTap.hpp" +#include "WindowsEthernetTap.hpp" #include "Logger.hpp" #include "RuntimeEnvironment.hpp" #include "Utils.hpp" #include "Mutex.hpp" -#include "Utils.hpp" + +#include "..\windows\TapDriver\tap-windows.h" // ff:ff:ff:ff:ff:ff with no ADI static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); -// -// TAP implementation for *nix OSes, with some specialization for different flavors -// - -#ifdef __UNIX_LIKE__ ///////////////////////////////////////////////////////// - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <signal.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/wait.h> -#include <sys/select.h> -#include <netinet/in.h> -#include <net/if_arp.h> -#include <arpa/inet.h> - -// Command identifiers used with command finder static (on various *nixes) -#define ZT_UNIX_IP_COMMAND 1 -#define ZT_UNIX_IFCONFIG_COMMAND 2 -#define ZT_MAC_KEXTLOAD_COMMAND 3 -#define ZT_MAC_KEXTUNLOAD_COMMAND 4 - -// Finds external commands on startup -class _CommandFinder -{ -public: - _CommandFinder() - { - _findCmd(ZT_UNIX_IFCONFIG_COMMAND,"ifconfig"); -#ifdef __LINUX__ - _findCmd(ZT_UNIX_IP_COMMAND,"ip"); -#endif -#ifdef __APPLE__ - _findCmd(ZT_MAC_KEXTLOAD_COMMAND,"kextload"); - _findCmd(ZT_MAC_KEXTUNLOAD_COMMAND,"kextunload"); -#endif - } - - // returns NULL if command was not found - inline const char *operator[](int id) const - throw() - { - std::map<int,std::string>::const_iterator c(_paths.find(id)); - if (c == _paths.end()) - return (const char *)0; - return c->second.c_str(); - } - -private: - inline void _findCmd(int id,const char *name) - { - char tmp[4096]; - ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/sbin/%s",name); - if (ZeroTier::Utils::fileExists(tmp)) { - _paths[id] = tmp; - return; - } - ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/usr/sbin/%s",name); - if (ZeroTier::Utils::fileExists(tmp)) { - _paths[id] = tmp; - return; - } - ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/bin/%s",name); - if (ZeroTier::Utils::fileExists(tmp)) { - _paths[id] = tmp; - return; - } - ZeroTier::Utils::snprintf(tmp,sizeof(tmp),"/usr/bin/%s",name); - if (ZeroTier::Utils::fileExists(tmp)) { - _paths[id] = tmp; - return; - } - } - std::map<int,std::string> _paths; -}; -static const _CommandFinder UNIX_COMMANDS; - -#ifdef __LINUX__ -#include <linux/if.h> -#include <linux/if_tun.h> -#include <linux/if_addr.h> -#include <linux/if_ether.h> -#include <ifaddrs.h> -#endif // __LINUX__ - -#ifdef __APPLE__ - -#include <sys/cdefs.h> -#include <sys/uio.h> -#include <sys/param.h> -#include <sys/sysctl.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <net/route.h> -#include <net/if.h> -#include <net/if_dl.h> -#include <net/if_media.h> -struct prf_ra { // stupid OSX compile fix... in6_var defines this in a struct which namespaces it for C++ - u_char onlink : 1; - u_char autonomous : 1; - u_char reserved : 6; -} prf_ra; -#include <netinet6/in6_var.h> -#include <netinet/in.h> -#include <netinet/in_var.h> -#include <netinet/icmp6.h> -#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 - -static volatile int EthernetTap_instances = 0; -static ZeroTier::Mutex EthernetTap_instances_m; - -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; -} - -#endif // __APPLE__ - namespace ZeroTier { -// Only permit one tap to be opened concurrently across the entire process -static Mutex __tapCreateLock; - -#ifdef __LINUX__ -EthernetTap::EthernetTap( - const RuntimeEnvironment *renv, - const char *tag, - const MAC &mac, - unsigned int mtu, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg) - throw(std::runtime_error) : - _mac(mac), - _mtu(mtu), - _r(renv), - _handler(handler), - _arg(arg), - _fd(0) -{ - char procpath[128]; - struct stat sbuf; - Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally - - if (mtu > 4096) - throw std::runtime_error("max tap MTU is 4096"); - - _fd = ::open("/dev/net/tun",O_RDWR); - if (_fd <= 0) - throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno)); - - struct ifreq ifr; - memset(&ifr,0,sizeof(ifr)); - - // Try to recall our last device name, or pick an unused one if that fails. - bool recalledDevice = false; - if ((tag)&&(tag[0])) { - Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),tag); - Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); - recalledDevice = (stat(procpath,&sbuf) != 0); - } - if (!recalledDevice) { - int devno = 0; - do { - Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++); - Utils::snprintf(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 - } - - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) { - ::close(_fd); - throw std::runtime_error("unable to configure TUN/TAP device for TAP operation"); - } - - strcpy(_dev,ifr.ifr_name); - - ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here - - // Open an arbitrary socket to talk to netlink - int sock = socket(AF_INET,SOCK_DGRAM,0); - if (sock <= 0) { - ::close(_fd); - throw std::runtime_error("unable to open netlink socket"); - } - - // Set MAC address - ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; - memcpy(ifr.ifr_ifru.ifru_hwaddr.sa_data,mac.data,6); - if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to configure TAP hardware (MAC) address"); - return; - } - - // Set MTU - ifr.ifr_ifru.ifru_mtu = (int)mtu; - if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to configure TAP MTU"); - } - - 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"); - } - - /* Bring interface up */ - if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to get TAP interface flags"); - } - ifr.ifr_flags |= IFF_UP; - if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to set TAP interface flags"); - } - - ::close(sock); - - ::pipe(_shutdownSignalPipe); - - TRACE("tap %s created",_dev); - - _thread = Thread::start(this); -} -#endif // __LINUX__ - -#ifdef __APPLE__ -EthernetTap::EthernetTap( - const RuntimeEnvironment *renv, - const char *tag, - const MAC &mac, - unsigned int mtu, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg) - throw(std::runtime_error) : - _mac(mac), - _mtu(mtu), - _r(renv), - _handler(handler), - _arg(arg), - _fd(0) -{ - char devpath[64],ethaddr[64],mtustr[16],tmp[4096]; - struct stat stattmp; - Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally - - if (mtu > 4096) - throw std::runtime_error("max tap MTU is 4096"); - - // Check for existence of ZT tap devices, try to load module if not there - const char *kextload = UNIX_COMMANDS[ZT_MAC_KEXTLOAD_COMMAND]; - if ((stat("/dev/zt0",&stattmp))&&(kextload)) { - strcpy(tmp,_r->homePath.c_str()); - long kextpid = (long)vfork(); - if (kextpid == 0) { - chdir(tmp); - execl(kextload,kextload,"-q","-repository",tmp,"tap.kext",(const char *)0); - _exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - waitpid(kextpid,&exitcode,0); - usleep(500); - } else throw std::runtime_error("unable to create subprocess with fork()"); - } - if (stat("/dev/zt0",&stattmp)) - throw std::runtime_error("/dev/zt# tap devices do not exist and unable to load kernel extension"); - - // Try to reopen the last device we had, if we had one and it's still unused. - bool recalledDevice = false; - if ((tag)&&(tag[0])) { - Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tag); - if (stat(devpath,&stattmp) == 0) { - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - Utils::scopy(_dev,sizeof(_dev),tag); - recalledDevice = true; - } - } - } - - // Open the first unused tap device if we didn't recall a previous one. - if (!recalledDevice) { - for(int i=0;i<256;++i) { - Utils::snprintf(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) { - Utils::snprintf(_dev,sizeof(_dev),"zt%d",i); - 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"); - } - - const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND]; - if (!ifconfig) { - ::close(_fd); - throw std::runtime_error("unable to find 'ifconfig' command on system"); - } - - // 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); - long cpid; - if ((cpid = (long)vfork()) == 0) { - execl(ifconfig,ifconfig,_dev,"lladdr",ethaddr,"mtu",mtustr,"up",(const char *)0); - _exit(-1); - } else { - 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,true,false); - - ::pipe(_shutdownSignalPipe); - - _thread = Thread::start(this); - - EthernetTap_instances_m.lock(); - ++EthernetTap_instances; - EthernetTap_instances_m.unlock(); -} -#endif // __APPLE__ - -EthernetTap::~EthernetTap() -{ - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - Thread::join(_thread); - ::close(_fd); - -#ifdef __APPLE__ - EthernetTap_instances_m.lock(); - int instances = --EthernetTap_instances; - EthernetTap_instances_m.unlock(); - if (instances <= 0) { - // Unload OSX kernel extension on the deletion of the last EthernetTap - // instance. - const char *kextunload = UNIX_COMMANDS[ZT_MAC_KEXTUNLOAD_COMMAND]; - if (kextunload) { - char tmp[4096]; - sprintf(tmp,"%s/tap.kext",_r->homePath.c_str()); - long kextpid = (long)vfork(); - if (kextpid == 0) { - execl(kextunload,kextunload,tmp,(const char *)0); - _exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - waitpid(kextpid,&exitcode,0); - } - } - } -#endif // __APPLE__ -} - -void EthernetTap::setDisplayName(const char *dn) -{ -} - -#ifdef __LINUX__ -static bool ___removeIp(const char *_dev,const InetAddress &ip) -{ - const char *ipcmd = UNIX_COMMANDS[ZT_UNIX_IP_COMMAND]; - if (!ipcmd) - return false; - long cpid = (long)vfork(); - if (cpid == 0) { - execl(ipcmd,ipcmd,"addr","del",ip.toString().c_str(),"dev",_dev,(const char *)0); - _exit(-1); - } else { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } -} - -bool EthernetTap::addIP(const InetAddress &ip) -{ - const char *ipcmd = UNIX_COMMANDS[ZT_UNIX_IP_COMMAND]; - if (!ipcmd) { - LOG("ERROR: could not configure IP address for %s: unable to find 'ip' command on system (checked /sbin, /bin, /usr/sbin, /usr/bin)",_dev); - return false; - } - - if (!ip) - return false; - - std::set<InetAddress> allIps(ips()); - if (allIps.count(ip) > 0) - return true; - - // Remove and reconfigure if address is the same but netmask is different - for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) { - if (i->ipsEqual(ip)) { - if (___removeIp(_dev,*i)) { - break; - } else { - LOG("WARNING: failed to remove old IP/netmask %s to replace with %s",i->toString().c_str(),ip.toString().c_str()); - } - } - } - - long cpid; - if ((cpid = (long)vfork()) == 0) { - execl(ipcmd,ipcmd,"addr","add",ip.toString().c_str(),"dev",_dev,(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - - return false; -} -#endif // __LINUX__ - -#ifdef __APPLE__ -static bool ___removeIp(const char *_dev,const InetAddress &ip) -{ - const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND]; - if (!ifconfig) - return false; - long cpid; - if ((cpid = (long)vfork()) == 0) { - execl(ifconfig,ifconfig,_dev,"inet",ip.toIpString().c_str(),"-alias",(const char *)0); - _exit(-1); - } else { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; // never reached, make compiler shut up about return value -} - -bool EthernetTap::addIP(const InetAddress &ip) +// Helper function to get an adapter's LUID and index from its GUID. The LUID is +// constant but the index can change, so go ahead and just look them both up by +// the GUID which is constant. (The GUID is the instance ID in the registry.) +static inline std::pair<NET_LUID,NET_IFINDEX> _findAdapterByGuid(const GUID &guid) + throw(std::runtime_error) { - const char *ifconfig = UNIX_COMMANDS[ZT_UNIX_IFCONFIG_COMMAND]; - if (!ifconfig) { - LOG("ERROR: could not configure IP address for %s: unable to find 'ifconfig' command on system (checked /sbin, /bin, /usr/sbin, /usr/bin)",_dev); - return false; - } - - if (!ip) - return false; - - std::set<InetAddress> allIps(ips()); - if (allIps.count(ip) > 0) - return true; // IP/netmask already assigned - - // Remove and reconfigure if address is the same but netmask is different - for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) { - if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { - if (___removeIp(_dev,*i)) { - break; - } else { - LOG("WARNING: failed to remove old IP/netmask %s to replace with %s",i->toString().c_str(),ip.toString().c_str()); - } - } - } - - long cpid; - if ((cpid = (long)vfork()) == 0) { - execl(ifconfig,ifconfig,_dev,ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); - _exit(-1); - } else { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - - return false; -} -#endif // __APPLE__ + MIB_IF_TABLE2 *ift = (MIB_IF_TABLE2 *)0; -bool EthernetTap::removeIP(const InetAddress &ip) -{ - if (ips().count(ip) > 0) { - if (___removeIp(_dev,ip)) - return true; - } - return false; -} + if (GetIfTable2Ex(MibIfTableRaw,&ift) != NO_ERROR) + throw std::runtime_error("GetIfTable2Ex() failed"); -std::set<InetAddress> EthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::set<InetAddress>(); - - std::set<InetAddress> r; - - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev))&&(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.insert(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.insert(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } + for(ULONG i=0;i<ift->NumEntries;++i) { + if (ift->Table[i].InterfaceGuid == guid) { + std::pair<NET_LUID,NET_IFINDEX> tmp(ift->Table[i].InterfaceLuid,ift->Table[i].InterfaceIndex); + FreeMibTable(ift); + return tmp; } - p = p->ifa_next; } - if (ifa) - freeifaddrs(ifa); - - return r; -} - -void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - char putBuf[4096 + 14]; - if ((_fd > 0)&&(len <= _mtu)) { - for(int i=0;i<6;++i) - putBuf[i] = to.data[i]; - for(int i=0;i<6;++i) - putBuf[i+6] = from.data[i]; - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - - int n = ::write(_fd,putBuf,len); - if (n <= 0) { - LOG("error writing packet to Ethernet tap device: %s",strerror(errno)); - } else if (n != (int)len) { - // Saw this gremlin once, so log it if we see it again... OSX tap - // or something seems to have goofy issues with certain MTUs. - LOG("ERROR: write underrun: %s tap write() wrote %d of %u bytes of frame",_dev,n,len); - } - } -} + FreeMibTable(&ift); -std::string EthernetTap::deviceName() const -{ - return std::string(_dev); + throw std::runtime_error("interface not found"); } -std::string EthernetTap::persistentId() const -{ - return std::string(); -} +// Only create or manipulate devices one at a time to avoid weird driver layer demons +static Mutex _systemTapInitLock; -#ifdef __LINUX__ -bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) +// Compute some basic environment stuff on startup +class _WinSysEnv { - char *ptr,*ptr2; - unsigned char mac[6]; - std::set<MulticastGroup> newGroups; - - int fd = ::open("/proc/net/dev_mcast",O_RDONLY); - if (fd > 0) { - char buf[131072]; - int n = (int)::read(fd,buf,sizeof(buf)); - if ((n > 0)&&(n < (int)sizeof(buf))) { - buf[n] = (char)0; - for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) { - int fno = 0; - char *devname = (char *)0; - char *mcastmac = (char *)0; - for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) { - if (fno == 1) - devname = f; - else if (fno == 4) - mcastmac = f; - ++fno; - } - if ((devname)&&(!strcmp(devname,_dev))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6)) - newGroups.insert(MulticastGroup(MAC(mac),0)); - } - } - ::close(fd); - } - +public: + _WinSysEnv() { - std::set<InetAddress> allIps(ips()); - for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i) - newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); - } - - bool changed = false; - - newGroups.insert(_blindWildcardMulticastGroup); // always join this - - for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { - if (!groups.count(*mg)) { - groups.insert(*mg); - changed = true; - } - } - for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) { - if (!newGroups.count(*mg)) { - groups.erase(mg++); - changed = true; - } else ++mg; +#ifdef _WIN64 + is64Bit = TRUE; + devcon = "\\devcon_x64.exe"; + tapDriver = "\\tap-windows\\x64\\zttap200.inf"; +#else + is64Bit = FALSE; + IsWow64Process(GetCurrentProcess(),&is64Bit); + devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); + tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf"); +#endif } - - return changed; -} -#endif // __LINUX__ - -#ifdef __APPLE__ -// -------------------------------------------------------------------------- -// 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; + BOOL is64Bit; + const char *devcon; + const char *tapDriver; }; +static const _WinSysEnv _winEnv; -static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif) +static bool _disableTapDevice(const RuntimeEnvironment *_r,const std::string deviceInstanceId) { - 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; - } - } + HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if (devconLog != INVALID_HANDLE_VALUE) + SetFilePointer(devconLog,0,0,FILE_END); - data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); - if (data == NULL) { - free(buf); - return (-1); + STARTUPINFOA startupInfo; + startupInfo.cb = sizeof(startupInfo); + if (devconLog != INVALID_HANDLE_VALUE) { + startupInfo.hStdOutput = devconLog; + startupInfo.hStdError = devconLog; } - - 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; - } + PROCESS_INFORMATION processInfo; + memset(&startupInfo,0,sizeof(STARTUPINFOA)); + memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + _winEnv.devcon + "\" disable @" + deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (devconLog != INVALID_HANDLE_VALUE) + CloseHandle(devconLog); + return false; } + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); - free(buf); + if (devconLog != INVALID_HANDLE_VALUE) + CloseHandle(devconLog); - if (ift > ifa) { - ift--; - ift->ifma_next = NULL; - *pif = ifa; - } else { - *pif = NULL; - free(ifa); - } - return (0); + return true; } - -static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp) +static bool _enableTapDevice(const RuntimeEnvironment *_r,const std::string deviceInstanceId) { - free(ifmp); -} - -// -------------------------------------------------------------------------- + HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if (devconLog != INVALID_HANDLE_VALUE) + SetFilePointer(devconLog,0,0,FILE_END); -bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) -{ - std::set<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 <= sizeof(_dev))&&(!memcmp(_dev,in->sdl_data,in->sdl_nlen))) - newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen),0)); - } - p = p->ifma_next; - } - _intl_freeifmaddrs(ifmap); + STARTUPINFOA startupInfo; + startupInfo.cb = sizeof(startupInfo); + if (devconLog != INVALID_HANDLE_VALUE) { + startupInfo.hStdOutput = devconLog; + startupInfo.hStdError = devconLog; } - - { - std::set<InetAddress> allIps(ips()); - for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i) - newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); + PROCESS_INFORMATION processInfo; + memset(&startupInfo,0,sizeof(STARTUPINFOA)); + memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + _winEnv.devcon + "\" enable @" + deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (devconLog != INVALID_HANDLE_VALUE) + CloseHandle(devconLog); + return false; } + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); - bool changed = false; - - newGroups.insert(_blindWildcardMulticastGroup); // always join this - - for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { - if (!groups.count(*mg)) { - groups.insert(*mg); - changed = true; - } - } - for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) { - if (!newGroups.count(*mg)) { - groups.erase(mg++); - changed = true; - } else ++mg; - } + if (devconLog != INVALID_HANDLE_VALUE) + CloseHandle(devconLog); - return changed; + return true; } -#endif // __APPLE__ -void EthernetTap::threadMain() - throw() +static void _syncIpsWithRegistry(const std::set<InetAddress> &haveIps,const std::string netCfgInstanceId) { - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[8194]; - Buffer<4096> data; - - // 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)) { - TRACE("unexpected error reading from tap: %s",strerror(errno)); - 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; - for(int i=0;i<6;++i) - to.data[i] = (unsigned char)getBuf[i]; - for(int i=0;i<6;++i) - from.data[i] = (unsigned char)getBuf[i + 6]; - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - if (etherType != 0x8100) { // VLAN tagged frames are not supported! - data.copyFrom(getBuf + 14,(unsigned int)r - 14); - _handler(_arg,from,to,etherType,data); - } - r = 0; - } - } + // Update registry to contain all non-link-local IPs for this interface + std::string regMultiIps,regMultiNetmasks; + for(std::set<InetAddress>::const_iterator i(haveIps.begin());i!=haveIps.end();++i) { + if (!i->isLinkLocal()) { + regMultiIps.append(i->toIpString()); + regMultiIps.push_back((char)0); + regMultiNetmasks.append(i->netmask().toIpString()); + regMultiNetmasks.push_back((char)0); } } -} - -bool EthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const char *pid) -{ - return false; -} - -int EthernetTap::cleanPersistentTapDevices(const RuntimeEnvironment *_r,const std::set<std::string> &exceptThese,bool alsoRemoveUnassociatedDev) -{ - return 0; -} - -} // namespace ZeroTier - -#endif // __UNIX_LIKE__ ////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////// - -#ifdef __WINDOWS__ /////////////////////////////////////////////////////////// - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <WinSock2.h> -#include <Windows.h> -#include <iphlpapi.h> -#include <ws2ipdef.h> -#include <WS2tcpip.h> -#include <tchar.h> -#include <winreg.h> -#include <wchar.h> -#include <nldef.h> -#include <netioapi.h> - -#include "..\windows\TapDriver\tap-windows.h" - -namespace ZeroTier { - -// Helper function to get an adapter's LUID and index from its GUID. The LUID is -// constant but the index can change, so go ahead and just look them both up by -// the GUID which is constant. (The GUID is the instance ID in the registry.) -static inline std::pair<NET_LUID,NET_IFINDEX> _findAdapterByGuid(const GUID &guid) - throw(std::runtime_error) -{ - MIB_IF_TABLE2 *ift = (MIB_IF_TABLE2 *)0; - - if (GetIfTable2Ex(MibIfTableRaw,&ift) != NO_ERROR) - throw std::runtime_error("GetIfTable2Ex() failed"); - - for(ULONG i=0;i<ift->NumEntries;++i) { - if (ift->Table[i].InterfaceGuid == guid) { - std::pair<NET_LUID,NET_IFINDEX> tmp(ift->Table[i].InterfaceLuid,ift->Table[i].InterfaceIndex); - FreeMibTable(ift); - return tmp; + HKEY tcpIpInterfaces; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { + if (regMultiIps.length()) { + regMultiIps.push_back((char)0); + regMultiNetmasks.push_back((char)0); + RegSetKeyValueA(tcpIpInterfaces,netCfgInstanceId.c_str(),"IPAddress",REG_MULTI_SZ,regMultiIps.data(),(DWORD)regMultiIps.length()); + RegSetKeyValueA(tcpIpInterfaces,netCfgInstanceId.c_str(),"SubnetMask",REG_MULTI_SZ,regMultiNetmasks.data(),(DWORD)regMultiNetmasks.length()); + } else { + RegDeleteKeyValueA(tcpIpInterfaces,netCfgInstanceId.c_str(),"IPAddress"); + RegDeleteKeyValueA(tcpIpInterfaces,netCfgInstanceId.c_str(),"SubnetMask"); } } - - FreeMibTable(&ift); - - throw std::runtime_error("interface not found"); + RegCloseKey(tcpIpInterfaces); } -static Mutex _systemTapInitLock; - -EthernetTap::EthernetTap( +WindowsEthernetTap::WindowsEthernetTap( const RuntimeEnvironment *renv, const char *tag, const MAC &mac, @@ -1071,15 +200,15 @@ EthernetTap::EthernetTap( void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), void *arg) throw(std::runtime_error) : - _mac(mac), - _mtu(mtu), + EthernetTap("WindowsEthernetTap",mac,mtu), _r(renv), _handler(handler), _arg(arg), _tap(INVALID_HANDLE_VALUE), _injectSemaphore(INVALID_HANDLE_VALUE), _run(true), - _initialized(false) + _initialized(false), + _enabled(false) { char subkeyName[4096]; char subkeyClass[4096]; @@ -1088,17 +217,6 @@ EthernetTap::EthernetTap( if (mtu > ZT_IF_MTU) throw std::runtime_error("MTU too large for Windows tap"); -#ifdef _WIN64 - BOOL is64Bit = TRUE; - const char *devcon = "\\devcon_x64.exe"; - const char *tapDriver = "\\tap-windows\\x64\\zttap200.inf"; -#else - BOOL is64Bit = FALSE; - IsWow64Process(GetCurrentProcess(),&is64Bit); - const char *devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); - const char *tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf"); -#endif - Mutex::Lock _l(_systemTapInitLock); // only one thread may mess with taps at a time, process-wide HKEY nwAdapters; @@ -1135,14 +253,14 @@ EthernetTap::EthernetTap( if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) instanceIdPath.assign(data,dataLen); - if ((_myDeviceInstanceId.length() == 0)&&(instanceId.length() != 0)&&(instanceIdPath.length() != 0)) { + if ((_netCfgInstanceId.length() == 0)&&(instanceId.length() != 0)&&(instanceIdPath.length() != 0)) { type = 0; dataLen = sizeof(data); if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { data[dataLen] = '\0'; if (!strcmp(data,tag)) { - _myDeviceInstanceId = instanceId; - _myDeviceInstanceIdPath = instanceIdPath; + _netCfgInstanceId = instanceId; + _deviceInstanceId = instanceIdPath; mySubkeyName = subkeyName; break; // found it! } @@ -1154,7 +272,7 @@ EthernetTap::EthernetTap( } // If there is no device, try to create one - if (_myDeviceInstanceId.length() == 0) { + if (_netCfgInstanceId.length() == 0) { // Log devcon output to a file HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if (devconLog == INVALID_HANDLE_VALUE) { @@ -1174,11 +292,11 @@ EthernetTap::EthernetTap( PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + devcon + "\" install \"" + _r->homePath + tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + _winEnv.devcon + "\" install \"" + _r->homePath + _winEnv.tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { RegCloseKey(nwAdapters); if (devconLog != INVALID_HANDLE_VALUE) CloseHandle(devconLog); - throw std::runtime_error(std::string("unable to find or execute devcon at ")+devcon); + throw std::runtime_error(std::string("unable to find or execute devcon at ") + _winEnv.devcon); } WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); @@ -1207,18 +325,18 @@ EthernetTap::EthernetTap( if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { if (existingDeviceInstances.count(std::string(data,dataLen)) == 0) { RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1)); - _myDeviceInstanceId.assign(data,dataLen); + _netCfgInstanceId.assign(data,dataLen); type = 0; dataLen = sizeof(data); if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - _myDeviceInstanceIdPath.assign(data,dataLen); + _deviceInstanceId.assign(data,dataLen); mySubkeyName = subkeyName; // Disable DHCP by default on newly created devices HKEY tcpIpInterfaces; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { DWORD enable = 0; - RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable)); + RegSetKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable)); RegCloseKey(tcpIpInterfaces); } @@ -1231,7 +349,7 @@ EthernetTap::EthernetTap( } } - if (_myDeviceInstanceId.length() > 0) { + if (_netCfgInstanceId.length() > 0) { char tmps[4096]; unsigned int tmpsl = Utils::snprintf(tmps,sizeof(tmps),"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",(unsigned int)mac.data[0],(unsigned int)mac.data[1],(unsigned int)mac.data[2],(unsigned int)mac.data[3],(unsigned int)mac.data[4],(unsigned int)mac.data[5]) + 1; RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,tmpsl); @@ -1250,7 +368,7 @@ EthernetTap::EthernetTap( // Convert device GUID junk... blech... is there an easier way to do this? { char nobraces[128]; - const char *nbtmp1 = _myDeviceInstanceId.c_str(); + const char *nbtmp1 = _netCfgInstanceId.c_str(); char *nbtmp2 = nobraces; while (*nbtmp1) { if ((*nbtmp1 != '{')&&(*nbtmp1 != '}')) @@ -1263,59 +381,13 @@ EthernetTap::EthernetTap( } // Disable and enable interface to ensure registry settings take effect - { - HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if (devconLog != INVALID_HANDLE_VALUE) - SetFilePointer(devconLog,0,0,FILE_END); - { - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + devcon + "\" disable @" + _myDeviceInstanceIdPath).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - RegCloseKey(nwAdapters); - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - throw std::runtime_error(std::string("unable to find or execute devcon at ")+devcon); - } - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - Sleep(250); - { - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + devcon + "\" enable @" + _myDeviceInstanceIdPath).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - RegCloseKey(nwAdapters); - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - throw std::runtime_error(std::string("unable to find or execute devcon at ")+devcon); - } - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - Sleep(250); - } + _disableTapDevice(_r,_deviceInstanceId); + if (!_enableTapDevice(_r,_deviceInstanceId)) + throw std::runtime_error("cannot enable tap device driver"); // Open the tap, which is in this weird Windows analog of /dev char tapPath[4096]; - Utils::snprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_myDeviceInstanceId.c_str()); + Utils::snprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str()); for(int openTrials=0;;) { // Try multiple times, since there seem to be reports from the field // of driver init timing issues. Blech. @@ -1327,10 +399,11 @@ EthernetTap::EthernetTap( } else break; } - // Set media status to enabled - uint32_t tmpi = 1; - DWORD bytesReturned = 0; - DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL); + setEnabled(true); + if (!_enabled) { + CloseHandle(_tap); + throw std::runtime_error("cannot enable tap device using IOCTL"); + } // Initialized overlapped I/O structures and related events memset(&_tapOvlRead,0,sizeof(_tapOvlRead)); @@ -1346,7 +419,7 @@ EthernetTap::EthernetTap( _initialized = true; } -EthernetTap::~EthernetTap() +WindowsEthernetTap::~WindowsEthernetTap() { _run = false; @@ -1358,48 +431,39 @@ EthernetTap::~EthernetTap() CloseHandle(_tapOvlWrite.hEvent); CloseHandle(_injectSemaphore); -#ifdef _WIN64 - BOOL is64Bit = TRUE; - const char *devcon = "\\devcon_x64.exe"; -#else - BOOL is64Bit = FALSE; - IsWow64Process(GetCurrentProcess(),&is64Bit); - const char *devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); -#endif + _disableTapDevice(_r,_deviceInstanceId); +} - // Disable network device on shutdown - HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - SetFilePointer(devconLog,0,0,FILE_END); - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + devcon + "\" disable @" + _myDeviceInstanceIdPath).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); +void WindowsEthernetTap::setEnabled(bool en) +{ + if (_tap == INVALID_HANDLE_VALUE) { + _enabled = false; + } else { + uint32_t tmpi = (en ? 1 : 0); + DWORD bytesReturned = 0; + if (DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL)) + _enabled = en; + else _enabled = false; } - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); } -void EthernetTap::setDisplayName(const char *dn) +bool WindowsEthernetTap::enabled() const +{ + return _enabled; +} + +void WindowsEthernetTap::setDisplayName(const char *dn) { if (!_initialized) return; HKEY ifp; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,(std::string("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\") + _myDeviceInstanceId).c_str(),0,KEY_READ|KEY_WRITE,&ifp) == ERROR_SUCCESS) { + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,(std::string("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\") + _netCfgInstanceId).c_str(),0,KEY_READ|KEY_WRITE,&ifp) == ERROR_SUCCESS) { RegSetKeyValueA(ifp,"Connection","Name",REG_SZ,(LPCVOID)dn,(DWORD)(strlen(dn)+1)); RegCloseKey(ifp); } } -bool EthernetTap::addIP(const InetAddress &ip) +bool WindowsEthernetTap::addIP(const InetAddress &ip) { if (!_initialized) return false; @@ -1420,7 +484,9 @@ bool EthernetTap::addIP(const InetAddress &ip) ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)ip.rawIpData()); ipr.OnLinkPrefixLength = ip.port(); } else if (ip.isV6()) { - // TODO + ipr.Address.Ipv6.sin6_family = AF_INET6; + memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,ip.rawIpData(),16); + ipr.OnLinkPrefixLength = ip.port(); } else return false; ipr.PrefixOrigin = IpPrefixOriginManual; @@ -1439,7 +505,7 @@ bool EthernetTap::addIP(const InetAddress &ip) } } - _syncIpsWithRegistry(haveIps); + _syncIpsWithRegistry(haveIps,_netCfgInstanceId); } catch (std::exception &exc) { LOG("unexpected exception adding IP address %s to %s: %s",ip.toString().c_str(),deviceName().c_str(),exc.what()); } catch ( ... ) { @@ -1448,7 +514,7 @@ bool EthernetTap::addIP(const InetAddress &ip) return false; } -bool EthernetTap::removeIP(const InetAddress &ip) +bool WindowsEthernetTap::removeIP(const InetAddress &ip) { if (!_initialized) return false; @@ -1472,7 +538,7 @@ bool EthernetTap::removeIP(const InetAddress &ip) if (addr == ip) { DeleteUnicastIpAddressEntry(&(ipt->Table[i])); FreeMibTable(ipt); - _syncIpsWithRegistry(ips()); + _syncIpsWithRegistry(ips(),_netCfgInstanceId); return true; } } @@ -1487,7 +553,7 @@ bool EthernetTap::removeIP(const InetAddress &ip) return false; } -std::set<InetAddress> EthernetTap::ips() const +std::set<InetAddress> WindowsEthernetTap::ips() const { static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it? std::set<InetAddress> addrs; @@ -1518,14 +584,14 @@ std::set<InetAddress> EthernetTap::ips() const } FreeMibTable(ipt); } - } catch ( ... ) {} + } catch ( ... ) {} // sanity check, shouldn't happen unless out of memory return addrs; } -void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +void WindowsEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) { - if (!_initialized) + if ((!_initialized)||(!_enabled)) return; if (len > (ZT_IF_MTU)) return; // sanity check @@ -1544,17 +610,17 @@ void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const ReleaseSemaphore(_injectSemaphore,1,NULL); } -std::string EthernetTap::deviceName() const +std::string WindowsEthernetTap::deviceName() const { - return _myDeviceInstanceId; + return _netCfgInstanceId; } -std::string EthernetTap::persistentId() const +std::string WindowsEthernetTap::persistentId() const { - return _myDeviceInstanceIdPath; + return _deviceInstanceId; } -bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) +bool WindowsEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) { if (!_initialized) return false; @@ -1611,7 +677,7 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) return changed; } -void EthernetTap::threadMain() +void WindowsEthernetTap::threadMain() throw() { HANDLE wait4[3]; @@ -1623,6 +689,10 @@ void EthernetTap::threadMain() bool writeInProgress = false; for(;;) { + // Windows can DIAF + if (_enabled) + setEnabled(true); + if (!_run) break; DWORD r = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,INFINITE,TRUE); if (!_run) break; @@ -1630,12 +700,14 @@ void EthernetTap::threadMain() if (HasOverlappedIoCompleted(&_tapOvlRead)) { DWORD bytesRead = 0; if (GetOverlappedResult(_tap,&_tapOvlRead,&bytesRead,FALSE)) { - if (bytesRead > 14) { + if ((bytesRead > 14)&&(_enabled)) { MAC to(_tapReadBuf); MAC from(_tapReadBuf + 6); - unsigned int etherType = Utils::ntoh(*((const uint16_t *)(_tapReadBuf + 12))); - Buffer<4096> tmp(_tapReadBuf + 14,bytesRead - 14); - _handler(_arg,from,to,etherType,tmp); + unsigned int etherType = ((((unsigned int)_tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)_tapReadBuf[13]) & 0xff); + try { + Buffer<4096> tmp(_tapReadBuf + 14,bytesRead - 14); + _handler(_arg,from,to,etherType,tmp); + } catch ( ... ) {} // handlers should not throw } } ReadFile(_tap,_tapReadBuf,sizeof(_tapReadBuf),NULL,&_tapOvlRead); @@ -1660,17 +732,8 @@ void EthernetTap::threadMain() CancelIo(_tap); } -bool EthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const char *pid) +bool WindowsEthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const char *pid) { -#ifdef _WIN64 - BOOL is64Bit = TRUE; - const char *devcon = "\\devcon_x64.exe"; -#else - BOOL is64Bit = FALSE; - IsWow64Process(GetCurrentProcess(),&is64Bit); - const char *devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); -#endif - Mutex::Lock _l(_systemTapInitLock); // only one thread may mess with taps at a time, process-wide HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); @@ -1684,7 +747,7 @@ bool EthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const c PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + devcon + "\" remove @" + pid).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + _winEnv.devcon + "\" remove @" + pid).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); @@ -1698,7 +761,7 @@ bool EthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const c return false; } -int EthernetTap::cleanPersistentTapDevices(const RuntimeEnvironment *_r,const std::set<std::string> &exceptThese,bool alsoRemoveUnassociatedDevices) +int WindowsEthernetTap::cleanPersistentTapDevices(const RuntimeEnvironment *_r,const std::set<std::string> &exceptThese,bool alsoRemoveUnassociatedDevices) { char subkeyName[4096]; char subkeyClass[4096]; @@ -1759,33 +822,4 @@ int EthernetTap::cleanPersistentTapDevices(const RuntimeEnvironment *_r,const st return removed; } -void EthernetTap::_syncIpsWithRegistry(const std::set<InetAddress> &haveIps) -{ - // Update registry to contain all non-link-local IPs for this interface - std::string regMultiIps,regMultiNetmasks; - for(std::set<InetAddress>::const_iterator i(haveIps.begin());i!=haveIps.end();++i) { - if (!i->isLinkLocal()) { - regMultiIps.append(i->toIpString()); - regMultiIps.push_back((char)0); - regMultiNetmasks.append(i->netmask().toIpString()); - regMultiNetmasks.push_back((char)0); - } - } - HKEY tcpIpInterfaces; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { - if (regMultiIps.length()) { - regMultiIps.push_back((char)0); - regMultiNetmasks.push_back((char)0); - RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"IPAddress",REG_MULTI_SZ,regMultiIps.data(),(DWORD)regMultiIps.length()); - RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"SubnetMask",REG_MULTI_SZ,regMultiNetmasks.data(),(DWORD)regMultiNetmasks.length()); - } else { - RegDeleteKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"IPAddress"); - RegDeleteKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"SubnetMask"); - } - } - RegCloseKey(tcpIpInterfaces); -} - } // namespace ZeroTier - -#endif // __WINDOWS__ //////////////////////////////////////////////////////// diff --git a/node/WindowsEthernetTap.hpp b/node/WindowsEthernetTap.hpp index f58dc748..4d9d7c90 100644 --- a/node/WindowsEthernetTap.hpp +++ b/node/WindowsEthernetTap.hpp @@ -25,51 +25,39 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef ZT_ETHERNETTAP_HPP -#define ZT_ETHERNETTAP_HPP +#ifndef ZT_WINDOWSETHERNETTAP_HPP +#define ZT_WINDOWSETHERNETTAP_HPP #include <stdio.h> #include <stdlib.h> -#include <map> -#include <list> -#include <vector> -#include <set> #include <string> #include <queue> #include <stdexcept> #include "Constants.hpp" -#include "InetAddress.hpp" -#include "MAC.hpp" +#include "EthernetTap.hpp" #include "Mutex.hpp" -#include "MulticastGroup.hpp" #include "Thread.hpp" -#include "Buffer.hpp" -#include "Array.hpp" -#ifdef __WINDOWS__ #include <WinSock2.h> #include <Windows.h> -#endif namespace ZeroTier { class RuntimeEnvironment; /** - * System ethernet tap device + * Windows Ethernet tap device using bundled ztTap driver */ -class EthernetTap +class WindowsEthernetTap : public EthernetTap { public: /** - * Construct a new TAP device - * - * Handler arguments: arg,from,to,etherType,data + * Open tap device, installing and creating one if it does not exist * * @param renv Runtime environment - * @param tag A tag used to persist tap identity at the OS layer (e.g. nwid in hex for Windows or device name for *nix) + * @param tag A tag (presently the hex network ID) used to identify persistent tap devices in the registry * @param mac MAC address of device * @param mtu MTU of device * @param desc If non-NULL, a description (not used on all OSes) @@ -77,7 +65,7 @@ public: * @param arg First argument to handler function * @throws std::runtime_error Unable to allocate device */ - EthernetTap( + WindowsEthernetTap( const RuntimeEnvironment *renv, const char *tag, const MAC &mac, @@ -86,120 +74,18 @@ public: void *arg) throw(std::runtime_error); - /** - * Close tap and shut down thread - * - * This may block for a few seconds while thread exits. - */ - ~EthernetTap(); - - /** - * Set the user display name for this connection - * - * This does nothing on platforms that don't have this concept. - * - * @param dn User display name - */ - void setDisplayName(const char *dn); - - /** - * @return MAC address of this interface - */ - inline const MAC &mac() const throw() { return _mac; } - - /** - * @return MTU of this interface - */ - inline unsigned int mtu() const throw() { return _mtu; } - - /** - * Add an IP to this interface - * - * @param ip IP and netmask (netmask stored in port field) - * @return True if IP added successfully - */ - bool addIP(const InetAddress &ip); - - /** - * Remove an IP from this interface - * - * Link-local IP addresses may not be able to be removed, depending on platform and type. - * - * @param ip IP and netmask (netmask stored in port field) - * @return True if IP removed successfully - */ - bool removeIP(const InetAddress &ip); - - /** - * @return All IP addresses (V4 and V6) assigned to this interface (including link-local) - */ - std::set<InetAddress> ips() const; - - /** - * Set this tap's IP addresses to exactly this set of IPs - * - * New IPs are created, ones not in this list are removed. - * - * @param ips IP addresses with netmask in port field - */ - inline void setIps(const std::set<InetAddress> &allIps) - { - for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) - addIP(*i); - std::set<InetAddress> myIps(ips()); -#ifdef __APPLE__ - bool haveV6LinkLocal = false; - for(std::set<InetAddress>::iterator i(myIps.begin());i!=myIps.end();++i) { - if (i->isLinkLocal()) { - if (i->isV6()) - haveV6LinkLocal = true; - } else if (!allIps.count(*i)) - removeIP(*i); - } - if (!haveV6LinkLocal) - addIP(InetAddress::makeIpv6LinkLocal(_mac)); -#else - for(std::set<InetAddress>::iterator i(myIps.begin());i!=myIps.end();++i) { - if ((!i->isLinkLocal())&&(!allIps.count(*i))) - removeIP(*i); - } -#endif - } + virtual ~WindowsEthernetTap(); - /** - * Put a frame, making it available to the OS for processing - * - * @param from MAC address from which frame originated - * @param to MAC address of destination (typically MAC of tap itself) - * @param etherType Ethernet protocol ID - * @param data Frame payload - * @param len Length of frame - */ - void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - - /** - * @return OS-specific device or connection name - */ - std::string deviceName() const; - - /** - * @return OS-internal persistent device ID or empty string if not applicable to this platform or not persistent - */ - std::string persistentId() const; - - /** - * Fill or modify a set to contain multicast groups for this device - * - * This populates a set or, if already populated, modifies it to contain - * only multicast groups in which this device is interested. - * - * This should always include the blind wildcard MulticastGroup (MAC of - * ff:ff:ff:ff:ff:ff and 0 ADI field). - * - * @param groups Set to modify in place - * @return True if set was changed since last call - */ - bool updateMulticastGroups(std::set<MulticastGroup> &groups); + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual void setDisplayName(const char *dn); + virtual bool addIP(const InetAddress &ip); + virtual bool removeIP(const InetAddress &ip); + virtual std::set<InetAddress> ips() const; + virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + virtual std::string deviceName() const; + virtual std::string persistentId() const; + virtual bool updateMulticastGroups(std::set<MulticastGroup> &groups); /** * Thread main method; do not call elsewhere @@ -210,10 +96,6 @@ public: /** * Remove persistent tap device by device name * - * This has no effect on platforms that do not have persistent taps. - * On platforms like Windows with persistent devices the device is - * uninstalled. - * * @param _r Runtime environment * @param pdev Device name as returned by persistentId() while tap is running * @return True if a device was deleted @@ -223,10 +105,6 @@ public: /** * Clean persistent tap devices that are not in the supplied set * - * This has no effect on platforms that do not have persistent taps. - * On platforms like Windows with persistent devices the device is - * uninstalled. - * * @param _r Runtime environment * @param exceptThese Devices to leave in place * @param alsoRemoveUnassociatedDevices If true, remove devices not associated with any network as well @@ -235,37 +113,23 @@ public: static int cleanPersistentTapDevices(const RuntimeEnvironment *_r,const std::set<std::string> &exceptThese,bool alsoRemoveUnassociatedDevices); private: - const MAC _mac; - const unsigned int _mtu; - const RuntimeEnvironment *_r; - void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &); void *_arg; - Thread _thread; -#ifdef __UNIX_LIKE__ - char _dev[16]; - int _fd; - int _shutdownSignalPipe[2]; -#endif - -#ifdef __WINDOWS__ - void _syncIpsWithRegistry(const std::set<InetAddress> &haveIps); - HANDLE _tap; OVERLAPPED _tapOvlRead,_tapOvlWrite; char _tapReadBuf[ZT_IF_MTU + 32]; HANDLE _injectSemaphore; GUID _deviceGuid; - std::string _myDeviceInstanceId; // NetCfgInstanceId, a GUID - std::string _myDeviceInstanceIdPath; // DeviceInstanceID, another kind of "instance ID" + std::string _netCfgInstanceId; // NetCfgInstanceId, a GUID + std::string _deviceInstanceId; // DeviceInstanceID, another kind of "instance ID" std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending; Mutex _injectPending_m; volatile bool _run; volatile bool _initialized; -#endif + volatile bool _enabled; }; } // namespace ZeroTier diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index c682aeee..714896a6 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -25,7 +25,6 @@ <ClCompile Include="..\..\node\C25519.cpp" /> <ClCompile Include="..\..\node\CertificateOfMembership.cpp" /> <ClCompile Include="..\..\node\Defaults.cpp" /> - <ClCompile Include="..\..\node\EthernetTap.cpp" /> <ClCompile Include="..\..\node\HttpClient.cpp" /> <ClCompile Include="..\..\node\Identity.cpp" /> <ClCompile Include="..\..\node\InetAddress.cpp" /> @@ -52,6 +51,7 @@ <ClCompile Include="..\..\node\Topology.cpp" /> <ClCompile Include="..\..\node\UdpSocket.cpp" /> <ClCompile Include="..\..\node\Utils.cpp" /> + <ClCompile Include="..\..\node\WindowsEthernetTap.cpp" /> <ClCompile Include="ServiceBase.cpp" /> <ClCompile Include="ServiceInstaller.cpp" /> <ClCompile Include="ZeroTierOneService.cpp" /> @@ -107,6 +107,7 @@ <ClInclude Include="..\..\node\Topology.hpp" /> <ClInclude Include="..\..\node\UdpSocket.hpp" /> <ClInclude Include="..\..\node\Utils.hpp" /> + <ClInclude Include="..\..\node\WindowsEthernetTap.hpp" /> <ClInclude Include="resource.h" /> <ClInclude Include="ServiceBase.h" /> <ClInclude Include="ServiceInstaller.h" /> diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index 03a119fe..a58b54bb 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -30,9 +30,6 @@ <ClCompile Include="..\..\node\Defaults.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\..\node\EthernetTap.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="..\..\node\HttpClient.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -123,6 +120,9 @@ <ClCompile Include="..\..\node\TcpSocket.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\node\WindowsEthernetTap.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\ext\lz4\lz4.h"> @@ -287,6 +287,9 @@ <ClInclude Include="..\..\node\TcpSocket.hpp"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\node\WindowsEthernetTap.hpp"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="ZeroTierOne.rc"> |