diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/EthernetTap.cpp | 101 | ||||
-rw-r--r-- | node/EthernetTap.hpp | 20 | ||||
-rw-r--r-- | node/Network.cpp | 8 |
3 files changed, 101 insertions, 28 deletions
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp index fce30b61..c6decba8 100644 --- a/node/EthernetTap.cpp +++ b/node/EthernetTap.cpp @@ -570,6 +570,11 @@ std::string EthernetTap::deviceName() const return std::string(_dev); } +std::string EthernetTap::persistentId() const +{ + return std::string(); +} + #ifdef __LINUX__ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) { @@ -901,6 +906,11 @@ void EthernetTap::threadMain() } } +bool EthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const char *pid) +{ + return false; +} + } // namespace ZeroTier #endif // __UNIX_LIKE__ ////////////////////////////////////////////////////// @@ -1278,31 +1288,9 @@ bool EthernetTap::addIP(const InetAddress &ip) } } - // 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); + _syncIpsWithRegistry(haveIps); } catch (std::exception &exc) { - LOG("unexpected exception adding IP address to %s: %s",ip.toString().c_str(),deviceName().c_str(),exc.what()); + LOG("unexpected exception adding IP address %s to %s: %s",ip.toString().c_str(),deviceName().c_str(),exc.what()); } catch ( ... ) { LOG("unexpected exception adding IP address %s to %s: unknown exception",ip.toString().c_str(),deviceName().c_str()); } @@ -1331,13 +1319,18 @@ bool EthernetTap::removeIP(const InetAddress &ip) if (addr == ip) { DeleteUnicastIpAddressEntry(&(ipt->Table[i])); FreeMibTable(ipt); + _syncIpsWithRegistry(ips()); return true; } } } FreeMibTable((PVOID)ipt); } - } catch ( ... ) {} + } catch (std::exception &exc) { + LOG("unexpected exception removing IP address %s from %s: %s",ip.toString().c_str(),deviceName().c_str(),exc.what()); + } catch ( ... ) { + LOG("unexpected exception removing IP address %s from %s: unknown exception",ip.toString().c_str(),deviceName().c_str()); + } return false; } @@ -1398,6 +1391,11 @@ std::string EthernetTap::deviceName() const return _myDeviceInstanceId; } +std::string EthernetTap::persistentId() const +{ + return _myDeviceInstanceIdPath; +} + bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) { std::set<MulticastGroup> newGroups; @@ -1501,6 +1499,59 @@ void EthernetTap::threadMain() CancelIo(_tap); } +bool EthernetTap::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 + + STARTUPINFOA startupInfo; + startupInfo.cb = sizeof(startupInfo); + 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)) { + WaitForSingleObject(processInfo.hProcess,INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + return true; + } + + return false; +} + +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/EthernetTap.hpp b/node/EthernetTap.hpp index dd3654d4..15e7aede 100644 --- a/node/EthernetTap.hpp +++ b/node/EthernetTap.hpp @@ -176,6 +176,11 @@ public: 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 @@ -195,6 +200,19 @@ public: void threadMain() throw(); + /** + * 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 + */ + static bool deletePersistentTapDevice(const RuntimeEnvironment *_r,const char *pid); + private: const MAC _mac; const unsigned int _mtu; @@ -215,6 +233,8 @@ private: #endif #ifdef __WINDOWS__ + void _syncIpsWithRegistry(const std::set<InetAddress> &haveIps); + HANDLE _tap; OVERLAPPED _tapOvlRead,_tapOvlWrite; char _tapReadBuf[ZT_IF_MTU + 32]; diff --git a/node/Network.cpp b/node/Network.cpp index af7623c1..37d93b99 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -36,6 +36,7 @@ #include "Switch.hpp" #include "Packet.hpp" #include "Buffer.hpp" +#include "EthernetTap.hpp" #define ZT_NETWORK_CERT_WRITE_BUF_SIZE 131072 @@ -55,13 +56,14 @@ const char *Network::statusString(const Status s) Network::~Network() { + std::string devPersistentId(_tap->persistentId()); delete _tap; + if (_destroyOnDelete) { Utils::rm(std::string(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".conf")); Utils::rm(std::string(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".mcerts")); - - // TODO: on Windows we need to also remove the tap interface since they're - // sticky on that platform. + if (devPersistentId.length()) + EthernetTap::deletePersistentTapDevice(_r,devPersistentId.c_str()); } else { // Causes flush of membership certs to disk clean(); |