summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/EthernetTap.cpp101
-rw-r--r--node/EthernetTap.hpp20
-rw-r--r--node/Network.cpp8
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();