Delete persistent tap device on Windows when we leave a network.

This commit is contained in:
Adam Ierymenko 2014-01-26 22:47:08 -08:00
parent 28665079a0
commit afbbf61588
3 changed files with 101 additions and 28 deletions

View File

@ -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__ ////////////////////////////////////////////////////////

View File

@ -175,6 +175,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
*
@ -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];

View File

@ -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();