|  | @@ -44,42 +44,71 @@
 | 
	
		
			
				|  |  |  #include <nldef.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include <iostream>
 | 
	
		
			
				|  |  | +#include <set>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #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<InetAddress> haveIps(ips());
 | 
	
		
			
				|  |  | +	std::vector<InetAddress> 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<std::string> 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<InetAddress> WindowsEthernetTap::ips() const
 | 
	
		
			
				|  |  | +std::vector<InetAddress> WindowsEthernetTap::ips() const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it?
 | 
	
		
			
				|  |  | -	std::set<InetAddress> addrs;
 | 
	
		
			
				|  |  | +	std::vector<InetAddress> addrs;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (!_initialized)
 | 
	
		
			
				|  |  |  		return addrs;
 | 
	
	
		
			
				|  | @@ -419,12 +444,12 @@ std::set<InetAddress> 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<InetAddress> 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<MulticastGroup> &groups)
 | 
	
		
			
				|  |  | +void WindowsEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	if (!_initialized)
 | 
	
		
			
				|  |  | -		return false;
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  |  	HANDLE t = _tap;
 | 
	
		
			
				|  |  |  	if (t == INVALID_HANDLE_VALUE)
 | 
	
		
			
				|  |  | -		return false;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	std::set<MulticastGroup> newGroups;
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	// 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<InetAddress> ipaddrs(ips());
 | 
	
		
			
				|  |  | -	for(std::set<InetAddress>::const_iterator i(ipaddrs.begin());i!=ipaddrs.end();++i)
 | 
	
		
			
				|  |  | -		newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
 | 
	
		
			
				|  |  | +	std::vector<MulticastGroup> 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<MulticastGroup> &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<InetAddress> allIps(ips());
 | 
	
		
			
				|  |  | +	for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
 | 
	
		
			
				|  |  | +		newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	for(std::set<MulticastGroup>::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<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
 | 
	
		
			
				|  |  | +		if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
 | 
	
		
			
				|  |  | +			added.push_back(*m);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
 | 
	
		
			
				|  |  | -		if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
 | 
	
		
			
				|  |  | -			groups.erase(mg++);
 | 
	
		
			
				|  |  | -			changed = true;
 | 
	
		
			
				|  |  | -		} else ++mg;
 | 
	
		
			
				|  |  | +	for(std::vector<MulticastGroup>::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<std::string> 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<std::string>::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
 |