From f5848972f992e20093da85e91761c327e2f3d3ce Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 15:05:28 -0700 Subject: [PATCH] Windows now builds and runs selftest correctly, and fixed a Windows (and possibly other platforms) issue in Phy<>. --- node/IncomingPacket.cpp | 2 +- node/Network.cpp | 2 +- node/Node.cpp | 6 +- osdep/Http.cpp | 14 +-- osdep/Http.hpp | 2 +- osdep/OSUtils.hpp | 7 ++ osdep/Phy.hpp | 22 ++-- osdep/Thread.hpp | 2 +- osdep/WindowsEthernetTap.cpp | 193 +++++++++++++++++++++++++---------- osdep/WindowsEthernetTap.hpp | 40 ++++---- selftest.cpp | 7 +- service/OneService.cpp | 38 ++++--- 12 files changed, 223 insertions(+), 112 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5397d51c8..a8d564bb8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -685,7 +685,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append(pid); outp.append(nwid); outp.append((uint16_t)netconfStr.length()); - outp.append(netconfStr.data(),netconfStr.length()); + outp.append(netconfStr.data(),(unsigned int)netconfStr.length()); outp.compress(); if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length()); diff --git a/node/Network.cpp b/node/Network.cpp index 08856f02f..ddfb01c7f 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -437,7 +437,7 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr) void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) { Mutex::Lock _l(_lock); - unsigned long tmp = _multicastGroupsBehindMe.size(); + unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe[mg] = now; if (tmp != _multicastGroupsBehindMe.size()) _announceMulticastGroups(); diff --git a/node/Node.cpp b/node/Node.cpp index 855b8266e..e77a977eb 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -426,7 +426,7 @@ std::string Node::dataStoreGet(const char *name) std::string r; unsigned long olen = 0; do { - long n = _dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),r.length(),&olen); + long n = _dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); if (n <= 0) return std::string(); r.append(buf,n); @@ -454,14 +454,14 @@ void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) Mutex::Lock _l(traceLock); + time_t now = (time_t)(_now / 1000ULL); #ifdef __WINDOWS__ ctime_s(tmp3,sizeof(tmp3),&now); char *nowstr = tmp3; #else - time_t now = (time_t)(_now / 1000ULL); char *nowstr = ctime_r(&now,tmp3); #endif - unsigned long nowstrlen = strlen(nowstr); + unsigned long nowstrlen = (unsigned long)strlen(nowstr); if (nowstr[nowstrlen-1] == '\n') nowstr[--nowstrlen] = (char)0; if (nowstr[nowstrlen-1] == '\r') diff --git a/osdep/Http.cpp b/osdep/Http.cpp index 1abf49034..cd3cf1370 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -130,7 +130,7 @@ static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; return 0; @@ -138,13 +138,13 @@ static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) { (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; - hh->currentHeaderField.assign("",0); - hh->currentHeaderValue.assign("",0); + hh->currentHeaderField = ""; + hh->currentHeaderValue = ""; } for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); @@ -153,7 +153,7 @@ static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; hh->currentHeaderValue.append(ptr,length); @@ -169,7 +169,7 @@ static int ShttpOnHeadersComplete(http_parser *parser) static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) { HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += length; + hh->messageSize += (unsigned long)length; if (hh->messageSize > hh->maxResponseSize) return -1; hh->responseBody->append(ptr,length); @@ -198,7 +198,7 @@ unsigned int Http::_do( { try { responseHeaders.clear(); - responseBody.assign("",0); + responseBody = ""; HttpPhyHandler handler; diff --git a/osdep/Http.hpp b/osdep/Http.hpp index a1882add8..86759ad20 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -89,7 +89,7 @@ public: * * @return HTTP status code or 0 on error (responseBody will contain error message) */ - static inline unsigned int DELETE( + static inline unsigned int DEL( unsigned long maxResponseSize, unsigned long timeout, const struct sockaddr *remoteAddress, diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 4422ab7d1..bfe9b68aa 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -45,6 +45,7 @@ #ifdef __WINDOWS__ #include #include +#include #else #include #include @@ -96,9 +97,15 @@ public: static inline bool mkdir(const char *path) throw() { +#ifdef __WINDOWS__ + if (::PathIsDirectoryA(path)) + return true; + return (::CreateDirectoryA(path,NULL) == TRUE); +#else if (::mkdir(path,0755) != 0) return (errno == EEXIST); return true; +#endif } static inline bool mkdir(const std::string &path) throw() { return OSUtils::mkdir(path.c_str()); } diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index 9bbfe43f1..5cebe1692 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -339,7 +339,11 @@ public: inline bool udpSend(PhySocket *sock,const struct sockaddr *remoteAddress,const void *data,unsigned long len) { PhySocketImpl &sws = *(reinterpret_cast(sock)); +#if defined(_WIN32) || defined(_WIN64) + return ((long)::sendto(sws.sock,reinterpret_cast(data),len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); +#else return ((long)::sendto(sws.sock,data,len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); +#endif } /** @@ -522,8 +526,8 @@ public: inline long tcpSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler = true) { PhySocketImpl &sws = *(reinterpret_cast(sock)); - long n = (long)::send(sws.sock,data,len,0); #if defined(_WIN32) || defined(_WIN64) + long n = (long)::send(sws.sock,reinterpret_cast(data),len,0); if (n == SOCKET_ERROR) { switch(WSAGetLastError()) { case WSAEINTR: @@ -535,6 +539,7 @@ public: } } #else // not Windows + long n = (long)::send(sws.sock,data,len,0); if (n < 0) { switch(errno) { #ifdef EAGAIN @@ -614,8 +619,10 @@ public: #endif } - for(typename std::list::iterator s(_socks.begin()),nexts;s!=_socks.end();s=nexts) { + bool atEnd = false; + for(typename std::list::iterator s(_socks.begin()),nexts;(!atEnd);s=nexts) { nexts = s; ++nexts; // we can delete the linked list item, so traverse now + atEnd = (nexts == _socks.end()); // if we delete the last element, s!=_socks.end() will no longer terminate our loop switch (s->type) { @@ -644,9 +651,10 @@ public: break; case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: - case ZT_PHY_SOCKET_TCP_IN: - if (FD_ISSET(s->sock,&rfds)) { - long n = (long)::recv(s->sock,buf,sizeof(buf),0); + case ZT_PHY_SOCKET_TCP_IN: { + ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable + if (FD_ISSET(sock,&rfds)) { + long n = (long)::recv(sock,buf,sizeof(buf),0); if (n <= 0) { this->close((PhySocket *)&(*s),true); } else { @@ -655,12 +663,12 @@ public: } catch ( ... ) {} } } - if ((FD_ISSET(s->sock,&wfds))&&(FD_ISSET(s->sock,&_writefds))) { + if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) { try { _handler->phyOnTcpWritable((PhySocket *)&(*s),&(s->uptr)); } catch ( ... ) {} } - break; + } break; case ZT_PHY_SOCKET_TCP_LISTEN: if (FD_ISSET(s->sock,&rfds)) { diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index f0dd37770..1dfb9ab57 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -37,7 +37,7 @@ #include #include #include -#include "Mutex.hpp" +#include "../node/Mutex.hpp" namespace ZeroTier { diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 682e33d70..d8fb3957e 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -44,42 +44,71 @@ #include #include +#include #include "../node/Constants.hpp" #include "../node/Utils.hpp" #include "../node/Mutex.hpp" #include "WindowsEthernetTap.hpp" +#include "OSUtils.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); +//static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); #define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE namespace ZeroTier { +namespace { + +class WindowsEthernetTapEnv +{ +public: + WindowsEthernetTapEnv() + { +#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 + } + + BOOL is64Bit; + std::string devcon; + std::string tapDriver; +}; + +static const WindowsEthernetTapEnv WINENV; + +} // anonymous namespace + // Only create or delete devices one at a time static Mutex _systemTapInitLock; WindowsEthernetTap::WindowsEthernetTap( - const char *pathToHelpers, + const char *hp, const MAC &mac, unsigned int mtu, unsigned int metric, uint64_t nwid, - const char *desiredDevice, const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), + void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : - EthernetTap("WindowsEthernetTap",mac,mtu,metric), _handler(handler), _arg(arg), + _mac(mac), _nwid(nwid), _tap(INVALID_HANDLE_VALUE), _injectSemaphore(INVALID_HANDLE_VALUE), - _pathToHelpers(pathToHelpers), + _pathToHelpers(hp), _run(true), _initialized(false), _enabled(true) @@ -169,11 +198,11 @@ WindowsEthernetTap::WindowsEthernetTap( PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" install \"" + _pathToHelpers + WindowsEthernetTapFactory::WINENV.tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" install \"" + _pathToHelpers + 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 ") + WindowsEthernetTapFactory::WINENV.devcon); + throw std::runtime_error(std::string("unable to find or execute devcon at ") + WINENV.devcon); } WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); @@ -296,18 +325,18 @@ bool WindowsEthernetTap::enabled() const return _enabled; } -bool WindowsEthernetTap::addIP(const InetAddress &ip) +bool WindowsEthernetTap::addIp(const InetAddress &ip) { if (!_initialized) return false; if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT? return false; - std::set haveIps(ips()); + std::vector haveIps(ips()); try { // Add IP to interface at the netlink level if not already assigned. - if (!haveIps.count(ip)) { + if (!std::binary_search(haveIps.begin(),haveIps.end(),ip)) { MIB_UNICASTIPADDRESS_ROW ipr; InitializeUnicastIpAddressEntry(&ipr); @@ -333,11 +362,8 @@ bool WindowsEthernetTap::addIP(const InetAddress &ip) ipr.InterfaceLuid = _deviceLuid; ipr.InterfaceIndex = _getDeviceIndex(); - if (CreateUnicastIpAddressEntry(&ipr) == NO_ERROR) { - haveIps.insert(ip); - } else { + if (CreateUnicastIpAddressEntry(&ipr) != NO_ERROR) return false; - } } std::vector regIps(_getRegistryIPv4Value("IPAddress")); @@ -348,14 +374,13 @@ bool WindowsEthernetTap::addIP(const InetAddress &ip) _setRegistryIPv4Value("IPAddress",regIps); _setRegistryIPv4Value("SubnetMask",regSubnetMasks); } - //_syncIpsWithRegistry(haveIps,_netCfgInstanceId); } catch ( ... ) { return false; } return true; } -bool WindowsEthernetTap::removeIP(const InetAddress &ip) +bool WindowsEthernetTap::removeIp(const InetAddress &ip) { if (!_initialized) return false; @@ -371,7 +396,7 @@ bool WindowsEthernetTap::removeIP(const InetAddress &ip) break; case AF_INET6: addr.set(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); - if (addr.isLinkLocal()) + if (addr.ipScope() == InetAddress::IP_SCOPE_LINK_LOCAL) continue; // can't remove link-local IPv6 addresses break; } @@ -402,10 +427,10 @@ bool WindowsEthernetTap::removeIP(const InetAddress &ip) return false; } -std::set WindowsEthernetTap::ips() const +std::vector WindowsEthernetTap::ips() const { static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it? - std::set addrs; + std::vector addrs; if (!_initialized) return addrs; @@ -419,12 +444,12 @@ std::set WindowsEthernetTap::ips() const case AF_INET: { InetAddress ip(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength); if (ip != InetAddress::LO4) - addrs.insert(ip); + addrs.push_back(ip); } break; case AF_INET6: { InetAddress ip(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); if ((ip != linkLocalLoopback)&&(ip != InetAddress::LO6)) - addrs.insert(ip); + addrs.push_back(ip); } break; } } @@ -433,6 +458,9 @@ std::set WindowsEthernetTap::ips() const } } catch ( ... ) {} // sanity check, shouldn't happen unless out of memory + std::sort(addrs.begin(),addrs.end()); + std::unique(addrs.begin(),addrs.end()); + return addrs; } @@ -472,23 +500,15 @@ void WindowsEthernetTap::setFriendlyName(const char *dn) } } -bool WindowsEthernetTap::updateMulticastGroups(std::set &groups) +void WindowsEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) { if (!_initialized) - return false; + return; HANDLE t = _tap; if (t == INVALID_HANDLE_VALUE) - return false; + return; - std::set newGroups; - - // Ensure that groups are added for each IP... this handles the MAC:ADI - // groups that are created from IPv4 addresses. Some of these may end - // up being duplicates of what the IOCTL returns but that's okay since - // the set<> will filter that. - std::set ipaddrs(ips()); - for(std::set::const_iterator i(ipaddrs.begin());i!=ipaddrs.end();++i) - newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); + std::vector newGroups; // The ZT1 tap driver supports an IOCTL to get multicast memberships at the L2 // level... something Windows does not seem to expose ordinarily. This lets @@ -503,32 +523,28 @@ bool WindowsEthernetTap::updateMulticastGroups(std::set &groups) i += 6; if ((mac.isMulticast())&&(!mac.isBroadcast())) { // exclude the nulls that may be returned or any other junk Windows puts in there - newGroups.insert(MulticastGroup(mac,0)); + newGroups.push_back(MulticastGroup(mac,0)); } } } - bool changed = false; + std::vector allIps(ips()); + for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - for(std::set::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { - if (!groups.count(*mg)) { - groups.insert(*mg); - changed = true; - } + 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::set::iterator mg(groups.begin());mg!=groups.end();) { - if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) { - groups.erase(mg++); - changed = true; - } else ++mg; + for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { + if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) + removed.push_back(*m); } - return changed; -} - -bool WindowsEthernetTap::injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - return false; + _multicastGroups.swap(newGroups); } void WindowsEthernetTap::threadMain() @@ -699,8 +715,8 @@ void WindowsEthernetTap::threadMain() MAC from(tapReadBuf + 6,6); 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); + // TODO: decode vlans + _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); } catch ( ... ) {} // handlers should not throw } } @@ -733,6 +749,49 @@ void WindowsEthernetTap::threadMain() ::free(tapReadBuf); } +void WindowsEthernetTap::destroyAllPersistentTapDevices(const char *pathToHelpers) +{ + char subkeyName[4096]; + char subkeyClass[4096]; + char data[4096]; + + std::set instanceIdPathsToRemove; + { + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) + return; + + for(DWORD subkeyIndex=0;;++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; + if (!strnicmp(data,"zttap",5)) { + std::string instanceIdPath; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) + instanceIdPath.assign(data,dataLen); + if (instanceIdPath.length() != 0) + instanceIdPathsToRemove.insert(instanceIdPath); + } + } + } else break; // end of list or failure + } + + RegCloseKey(nwAdapters); + } + + for(std::set::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) + _deletePersistentTapDevice(pathToHelpers,iidp->c_str()); +} + bool WindowsEthernetTap::_disableTapDevice() { HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); @@ -748,7 +807,7 @@ bool WindowsEthernetTap::_disableTapDevice() PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" disable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" disable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { if (devconLog != INVALID_HANDLE_VALUE) CloseHandle(devconLog); return false; @@ -778,7 +837,7 @@ bool WindowsEthernetTap::_enableTapDevice() PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WindowsEthernetTapFactory::WINENV.devcon + "\" enable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" enable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { if (devconLog != INVALID_HANDLE_VALUE) CloseHandle(devconLog); return false; @@ -863,4 +922,26 @@ void WindowsEthernetTap::_setRegistryIPv4Value(const char *regKey,const std::vec } } +void WindowsEthernetTap::_deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId) +{ + HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\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("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } + if (devconLog != INVALID_HANDLE_VALUE) + CloseHandle(devconLog); +} + } // namespace ZeroTier diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 9c513a5db..7ec8cf19c 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -37,42 +37,38 @@ #include #include -#include "EthernetTap.hpp" - #include "../node/Constants.hpp" #include "../node/Mutex.hpp" -#include "../node/Thread.hpp" #include "../node/Array.hpp" #include "../node/MulticastGroup.hpp" +#include "../osdep/Thread.hpp" namespace ZeroTier { -class WindowsEthernetTap : public EthernetTap +class WindowsEthernetTap { public: WindowsEthernetTap( - const char *pathToHelpers, + const char *hp, const MAC &mac, unsigned int mtu, unsigned int metric, uint64_t nwid, - const char *desiredDevice, const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), + void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); - virtual ~WindowsEthernetTap(); + ~WindowsEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIP(const InetAddress &ip); - virtual bool removeIP(const InetAddress &ip); - virtual std::set 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 void setFriendlyName(const char *friendlyName); - virtual bool updateMulticastGroups(std::set &groups); - virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + 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); inline const NET_LUID &luid() const { return _deviceLuid; } inline const GUID &guid() const { return _deviceGuid; } @@ -81,15 +77,19 @@ public: void threadMain() throw(); + static void destroyAllPersistentTapDevices(const char *pathToHelpers); + private: bool _disableTapDevice(); bool _enableTapDevice(); NET_IFINDEX _getDeviceIndex(); // throws on failure std::vector _getRegistryIPv4Value(const char *regKey); void _setRegistryIPv4Value(const char *regKey,const std::vector &value); + static void _deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId); - void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &); + void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; + MAC _mac; uint64_t _nwid; Thread _thread; @@ -101,6 +101,8 @@ private: std::string _netCfgInstanceId; // NetCfgInstanceId, a GUID std::string _deviceInstanceId; // DeviceInstanceID, another kind of "instance ID" + std::vector _multicastGroups; + std::queue< std::pair< Array,unsigned int > > _injectPending; Mutex _injectPending_m; diff --git a/selftest.cpp b/selftest.cpp index ea90813e5..319271f32 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -628,7 +628,7 @@ struct TestPhyHandlers { std::string *testMessage = (std::string *)*uptr; if ((testMessage)&&(testMessage->length() > 0)) { - long sent = testPhyInstance->tcpSend(sock,(const void *)testMessage->data(),testMessage->length(),true); + long sent = testPhyInstance->tcpSend(sock,(const void *)testMessage->data(),(unsigned long)testMessage->length(),true); if (sent > 0) testMessage->erase(0,sent); } @@ -804,6 +804,11 @@ int main(int argc,char **argv) { int r = 0; +#ifdef __WINDOWS__ + WSADATA wsaData; + WSAStartup(MAKEWORD(2,2),&wsaData); +#endif + // Code to generate the C25519 test vectors -- did this once and then // put these up top so that we can ensure that every platform produces // the same result. diff --git a/service/OneService.cpp b/service/OneService.cpp index 2c67dbf1d..c32fb7927 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -53,6 +53,10 @@ #include "OneService.hpp" #include "ControlPlane.hpp" +#ifdef __WINDOWS__ +#include +#endif + // Include the right tap device driver for this platform -- add new platforms here #ifdef __APPLE__ #include "../osdep/OSXEthernetTap.hpp" @@ -62,6 +66,10 @@ namespace ZeroTier { typedef OSXEthernetTap EthernetTap; } #include "../osdep/LinuxEthernetTap.hpp" namespace ZeroTier { typedef LinuxEthernetTap EthernetTap; } #endif +#ifdef __WINDOWS__ +#include "../osdep/WindowsEthernetTap.hpp" +namespace ZeroTier { typedef WindowsEthernetTap EthernetTap; } +#endif // Sanity limits for HTTP #define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 8) @@ -384,7 +392,7 @@ public: inline void phyOnTcpWritable(PhySocket *sock,void **uptr) { HttpConnection *htc = reinterpret_cast(*uptr); - long sent = _phy.tcpSend(sock,htc->body.data() + htc->writePtr,htc->body.length() - htc->writePtr,true); + long sent = _phy.tcpSend(sock,htc->body.data() + htc->writePtr,(unsigned long)htc->body.length() - htc->writePtr,true); if (sent < 0) { return; // close handler will have been called, so everything's dead } else { @@ -395,7 +403,7 @@ public: if (htc->shouldKeepAlive) { htc->writing = false; htc->writePtr = 0; - htc->body.assign("",0); + htc->body = ""; } else { _phy.close(sock); // will call close handler to delete from _httpConnections } @@ -417,7 +425,7 @@ public: _homePath.c_str(), MAC(nwc->mac), nwc->mtu, - ZT_IF_METRIC, + (unsigned int)ZT_IF_METRIC, nwid, friendlyName, StapFrameHandler, @@ -683,19 +691,19 @@ static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC static int ShttpOnMessageBegin(http_parser *parser) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->currentHeaderField.assign("",0); - htc->currentHeaderValue.assign("",0); + htc->currentHeaderField = ""; + htc->currentHeaderValue = ""; htc->messageSize = 0; - htc->url.assign("",0); - htc->status.assign("",0); + htc->url = ""; + htc->status = ""; htc->headers.clear(); - htc->body.assign("",0); + htc->body = ""; return 0; } static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->url.append(ptr,length); @@ -704,7 +712,7 @@ static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->status.append(ptr,length); @@ -713,13 +721,13 @@ static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; if ((htc->currentHeaderField.length())&&(htc->currentHeaderValue.length())) { htc->headers[htc->currentHeaderField] = htc->currentHeaderValue; - htc->currentHeaderField.assign("",0); - htc->currentHeaderValue.assign("",0); + htc->currentHeaderField = ""; + htc->currentHeaderValue = ""; } for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); @@ -728,7 +736,7 @@ static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->currentHeaderValue.append(ptr,length); @@ -744,7 +752,7 @@ static int ShttpOnHeadersComplete(http_parser *parser) static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) { HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += length; + htc->messageSize += (unsigned long)length; if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; htc->body.append(ptr,length);