Răsfoiți Sursa

(1) Fix menu bar item font size on Windows, (2) fix for possible Windows EthernetTap infinite loop while enumerating registry.

Adam Ierymenko 11 ani în urmă
părinte
comite
742261c7fc
4 a modificat fișierele cu 182 adăugiri și 136 ștergeri
  1. 3 1
      ZeroTierUI/mainwindow.cpp
  2. 3 3
      ext/installfiles/windows/ZeroTier One.aip
  3. 3 2
      main.cpp
  4. 173 130
      node/EthernetTap.cpp

+ 3 - 1
ZeroTierUI/mainwindow.cpp

@@ -109,9 +109,11 @@ MainWindow::MainWindow(QWidget *parent) :
 #endif
 
 #ifdef __WINDOWS__
+	// Windows operates at a different DPI, so we have to rescale the default Qt
+	// font sizes so everything isn't huge. Yeah.
 	QWidgetList widgets = this->findChildren<QWidget*>();
 	foreach(QWidget *widget, widgets) {
-		if ((typeid(*widget) != typeid(ui->menuBar))&&(typeid(*widget) != typeid(ui->menuFile))) {
+		if (typeid(*widget) != typeid(*ui->menuFile)) { // menus don't need the DPI shift apparently
 			QFont font(widget->font());
 			font.setPointSizeF(font.pointSizeF() * 0.75);
 			widget->setFont(font);

+ 3 - 3
ext/installfiles/windows/ZeroTier One.aip

@@ -6,19 +6,19 @@
   <COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
     <ROW Property="AI_BITMAP_DISPLAY_MODE" Value="0"/>
     <ROW Property="ALLUSERS" Value="1"/>
-    <ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]." ValueLocId="*"/>
     <ROW Property="ARPCONTACT" Value="[email protected]"/>
     <ROW Property="ARPNOMODIFY" MultiBuildValue="DefaultBuild:1"/>
     <ROW Property="ARPNOREPAIR" Value="1"/>
     <ROW Property="ARPPRODUCTICON" Value="zt1icon.exe" Type="8"/>
     <ROW Property="ARPURLINFOABOUT" Value="https://www.zerotier.com/"/>
+    <ROW Property="ARPURLUPDATEINFO" Value="https://www.zerotier.com/download.html"/>
     <ROW Property="CTRLS" Value="2"/>
     <ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/>
     <ROW Property="Manufacturer" Value="ZeroTier Networks LLC"/>
     <ROW Property="ProductCode" Value="1033:{24DFCEE7-3AC9-4D39-BD53-974220C12043} " Type="16"/>
     <ROW Property="ProductLanguage" Value="1033"/>
     <ROW Property="ProductName" Value="ZeroTier One"/>
-    <ROW Property="ProductVersion" Value="0.7.0" Type="32"/>
+    <ROW Property="ProductVersion" Value="0.7.1" Type="32"/>
     <ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/>
     <ROW Property="RUNAPPLICATION" Value="1" Type="4"/>
     <ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>
@@ -262,7 +262,7 @@
     <ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent">
-    <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Order="2" Flags="14" Text="0"/>
+    <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Order="2" Flags="14" Text="1"/>
     <ROW XmlElement="swidentitlement_required_indicator" ParentElement="swidsoftware_identification_tag" Name="swid:entitlement_required_indicator" Order="0" Flags="14" Text="false"/>
     <ROW XmlElement="swidmajor" ParentElement="swidnumeric" Name="swid:major" Order="0" Flags="14" Text="0"/>
     <ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Order="1" Flags="14" Text="7"/>

+ 3 - 2
main.cpp

@@ -599,12 +599,13 @@ int main(int argc,char **argv)
 #else
 						pathToInf = ZT_DEFAULTS.defaultHomePath + "\\tap-windows\\x86\\zttap200.inf";
 #endif
+						printf("Installing ZeroTier One virtual Ethernet port driver. You may be"ZT_EOL_S"prompted to authorize driver installation."ZT_EOL_S""ZT_EOL_S);
 						BOOL needReboot = FALSE;
 						if (DiInstallDriverA(NULL,pathToInf.c_str(),DIIRFLAG_FORCE_INF,&needReboot)) {
-							fprintf(stderr,"%s: driver successfully installed from %s"ZT_EOL_S,argv[0],pathToInf.c_str());
+							printf("%s: driver successfully installed from %s"ZT_EOL_S,argv[0],pathToInf.c_str());
 							return 0;
 						} else {
-							fprintf(stderr,"%s: failed installing %s: %d"ZT_EOL_S,argv[0],pathToInf.c_str(),(int)GetLastError());
+							printf("%s: failed installing %s: %d"ZT_EOL_S,argv[0],pathToInf.c_str(),(int)GetLastError());
 							return 3;
 						}
 					} break;

+ 173 - 130
node/EthernetTap.cpp

@@ -1108,117 +1108,129 @@ EthernetTap::EthernetTap(
 	std::set<std::string> existingDeviceInstances;
 	std::string mySubkeyName;
 
-	// Enumerate tap instances and look for one tagged with this tag
-	for(DWORD subkeyIndex=0;subkeyIndex!=-1;) {
+	// Look for the tap instance that corresponds with our interface tag (network ID)
+	for(DWORD subkeyIndex=0;;++subkeyIndex) {
 		DWORD type;
 		DWORD dataLen;
 		DWORD subkeyNameLen = sizeof(subkeyName);
 		DWORD subkeyClassLen = sizeof(subkeyClass);
 		FILETIME lastWriteTime;
-		switch (RegEnumKeyExA(nwAdapters,subkeyIndex++,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime)) {
-			case ERROR_NO_MORE_ITEMS: subkeyIndex = -1; break;
-			case 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 instanceId;
-						type = 0;
-						dataLen = sizeof(data);
-						if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
-							instanceId.assign(data,dataLen);
-							existingDeviceInstances.insert(instanceId);
-						}
+		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 instanceId;
+					type = 0;
+					dataLen = sizeof(data);
+					if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
+						instanceId.assign(data,dataLen);
+						existingDeviceInstances.insert(instanceId);
+					}
 
-						std::string instanceIdPath;
+					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 ((_myDeviceInstanceId.length() == 0)&&(instanceId.length() != 0)&&(instanceIdPath.length() != 0)) {
 						type = 0;
 						dataLen = sizeof(data);
-						if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
-							instanceIdPath.assign(data,dataLen);
-
-						if ((_myDeviceInstanceId.length() == 0)&&(instanceId.length() != 0)&&(instanceIdPath.length() != 0)) {
-							type = 0;
-							dataLen = sizeof(data);
-							if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
-								data[dataLen] = '\0';
-								if (!strcmp(data,tag)) {
-									_myDeviceInstanceId = instanceId;
-									_myDeviceInstanceIdPath = instanceIdPath;
-									mySubkeyName = subkeyName;
-									subkeyIndex = -1; // break outer loop
-								}
+						if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
+							data[dataLen] = '\0';
+							if (!strcmp(data,tag)) {
+								_myDeviceInstanceId = instanceId;
+								_myDeviceInstanceIdPath = instanceIdPath;
+								mySubkeyName = subkeyName;
+								break; // found it!
 							}
 						}
 					}
 				}
-				break;
-		}
+			}
+		} else break; // no more subkeys or error occurred enumerating them
 	}
 
 	// If there is no device, try to create one
 	if (_myDeviceInstanceId.length() == 0) {
+		// Log devcon output to a file
+		HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
+		if (devconLog == INVALID_HANDLE_VALUE) {
+			LOG("WARNING: unable to open devcon.log");
+		} else {
+			SetFilePointer(devconLog,0,0,FILE_END);
+		}
+
 		// Execute devcon to install an instance of the Microsoft Loopback Adapter
 		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("\"") + _r->homePath + devcon + "\" install \"" + _r->homePath + 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 ")+devcon);
 		}
 		WaitForSingleObject(processInfo.hProcess,INFINITE);
 		CloseHandle(processInfo.hProcess);
 		CloseHandle(processInfo.hThread);
- 
+
+		if (devconLog != INVALID_HANDLE_VALUE)
+			CloseHandle(devconLog);
+
 		// Scan for the new instance by simply looking for taps that weren't
-		// there originally.
-		for(DWORD subkeyIndex=0;subkeyIndex!=-1;) {
+		// there originally. The static mutex we lock ensures this can't step
+		// on its own toes.
+		for(DWORD subkeyIndex=0;;++subkeyIndex) {
 			DWORD type;
 			DWORD dataLen;
 			DWORD subkeyNameLen = sizeof(subkeyName);
 			DWORD subkeyClassLen = sizeof(subkeyClass);
 			FILETIME lastWriteTime;
-			switch (RegEnumKeyExA(nwAdapters,subkeyIndex++,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime)) {
-				case ERROR_NO_MORE_ITEMS: subkeyIndex = -1; break;
-				case 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)) {
-							type = 0;
-							dataLen = sizeof(data);
-							if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
-								if (existingDeviceInstances.count(std::string(data,dataLen)) == 0) {
-									RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1));
-									_myDeviceInstanceId.assign(data,dataLen);
-									type = 0;
-									dataLen = sizeof(data);
-									if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
-										_myDeviceInstanceIdPath.assign(data,dataLen);
-									mySubkeyName = subkeyName;
-
-									// Disable DHCP by default on newly created devices
-									HKEY tcpIpInterfaces;
-									if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
-										DWORD enable = 0;
-										RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable));
-										RegCloseKey(tcpIpInterfaces);
-									}
-
-									subkeyIndex = -1; // break outer loop
+			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)) {
+						type = 0;
+						dataLen = sizeof(data);
+						if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
+							if (existingDeviceInstances.count(std::string(data,dataLen)) == 0) {
+								RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1));
+								_myDeviceInstanceId.assign(data,dataLen);
+								type = 0;
+								dataLen = sizeof(data);
+								if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
+									_myDeviceInstanceIdPath.assign(data,dataLen);
+								mySubkeyName = subkeyName;
+
+								// Disable DHCP by default on newly created devices
+								HKEY tcpIpInterfaces;
+								if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
+									DWORD enable = 0;
+									RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable));
+									RegCloseKey(tcpIpInterfaces);
 								}
+
+								break; // found it!
 							}
 						}
 					}
-					break;
-			}
+				}
+			} else break; // no more keys or error occurred
 		}
 	}
 
-	// If we have a device, configure it
 	if (_myDeviceInstanceId.length() > 0) {
 		char tmps[4096];
 		unsigned int tmpsl = Utils::snprintf(tmps,sizeof(tmps),"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",(unsigned int)mac.data[0],(unsigned int)mac.data[1],(unsigned int)mac.data[2],(unsigned int)mac.data[3],(unsigned int)mac.data[4],(unsigned int)mac.data[5]) + 1;
@@ -1228,16 +1240,14 @@ EthernetTap::EthernetTap(
 		RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MTU",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
 		tmp = 0;
 		RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
+	} else {
+		RegCloseKey(nwAdapters);	
+		throw std::runtime_error("unable to find or create tap adapter");
 	}
 
-	// Done with registry
 	RegCloseKey(nwAdapters);	
 
-	// If we didn't get a device, we can't start
-	if (_myDeviceInstanceId.length() == 0)
-		throw std::runtime_error("unable to create new tap adapter");
-
-	// Convert device GUID junk... blech
+	// Convert device GUID junk... blech... is there an easier way to do this?
 	{
 		char nobraces[128];
 		const char *nbtmp1 = _myDeviceInstanceId.c_str();
@@ -1254,32 +1264,51 @@ EthernetTap::EthernetTap(
 
 	// Disable and enable interface to ensure registry settings take effect
 	{
-		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 + "\" disable @" + _myDeviceInstanceIdPath).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
-			RegCloseKey(nwAdapters);
-			throw std::runtime_error(std::string("unable to find or execute devcon at ")+devcon);
+		HANDLE devconLog = CreateFileA((_r->homePath + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
+		if (devconLog != INVALID_HANDLE_VALUE)
+			SetFilePointer(devconLog,0,0,FILE_END);
+		{
+			STARTUPINFOA startupInfo;
+			startupInfo.cb = sizeof(startupInfo);
+			if (devconLog != INVALID_HANDLE_VALUE) {
+				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("\"") + _r->homePath + devcon + "\" disable @" + _myDeviceInstanceIdPath).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 ")+devcon);
+			}
+			WaitForSingleObject(processInfo.hProcess,INFINITE);
+			CloseHandle(processInfo.hProcess);
+			CloseHandle(processInfo.hThread);
 		}
-		WaitForSingleObject(processInfo.hProcess,INFINITE);
-		CloseHandle(processInfo.hProcess);
-		CloseHandle(processInfo.hThread);
-	}
-	{
-		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 + "\" enable @" + _myDeviceInstanceIdPath).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
-			RegCloseKey(nwAdapters);
-			throw std::runtime_error(std::string("unable to find or execute devcon at ")+devcon);
+		{
+			STARTUPINFOA startupInfo;
+			startupInfo.cb = sizeof(startupInfo);
+			if (devconLog != INVALID_HANDLE_VALUE) {
+				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("\"") + _r->homePath + devcon + "\" enable @" + _myDeviceInstanceIdPath).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 ")+devcon);
+			}
+			WaitForSingleObject(processInfo.hProcess,INFINITE);
+			CloseHandle(processInfo.hProcess);
+			CloseHandle(processInfo.hThread);
 		}
-		WaitForSingleObject(processInfo.hProcess,INFINITE);
-		CloseHandle(processInfo.hProcess);
-		CloseHandle(processInfo.hThread);
+		if (devconLog != INVALID_HANDLE_VALUE)
+			CloseHandle(devconLog);
 	}
 
 	// Open the tap, which is in this weird Windows analog of /dev
@@ -1314,6 +1343,7 @@ EthernetTap::~EthernetTap()
 
 	ReleaseSemaphore(_injectSemaphore,1,NULL);
 	Thread::join(_thread);
+
 	CloseHandle(_tap);
 	CloseHandle(_tapOvlRead.hEvent);
 	CloseHandle(_tapOvlWrite.hEvent);
@@ -1329,8 +1359,14 @@ EthernetTap::~EthernetTap()
 #endif
 
 	// Disable network device on shutdown
+	HANDLE devconLog = CreateFileA((_r->homePath + "\\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));
@@ -1339,6 +1375,8 @@ EthernetTap::~EthernetTap()
 		CloseHandle(processInfo.hProcess);
 		CloseHandle(processInfo.hThread);
 	}
+	if (devconLog != INVALID_HANDLE_VALUE)
+		CloseHandle(devconLog);
 }
 
 void EthernetTap::setDisplayName(const char *dn)
@@ -1481,7 +1519,7 @@ void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const
 	if (!_initialized)
 		return;
 	if (len > (ZT_IF_MTU))
-		return;
+		return; // sanity check
 
 	{
 		Mutex::Lock _l(_injectPending_m);
@@ -1626,8 +1664,14 @@ bool EthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const c
 
 	Mutex::Lock _l(_systemTapInitLock); // only one thread may mess with taps at a time, process-wide
 
+	HANDLE devconLog = CreateFileA((_r->homePath + "\\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));
@@ -1635,8 +1679,12 @@ bool EthernetTap::deletePersistentTapDevice(const RuntimeEnvironment *_r,const c
 		WaitForSingleObject(processInfo.hProcess,INFINITE);
 		CloseHandle(processInfo.hProcess);
 		CloseHandle(processInfo.hThread);
+		if (devconLog != INVALID_HANDLE_VALUE)
+			CloseHandle(devconLog);
 		return true;
 	}
+	if (devconLog != INVALID_HANDLE_VALUE)
+		CloseHandle(devconLog);
 
 	return false;
 }
@@ -1655,55 +1703,50 @@ int EthernetTap::cleanPersistentTapDevices(const RuntimeEnvironment *_r,const st
 		if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS)
 			return -1;
 
-		for(DWORD subkeyIndex=0;subkeyIndex!=-1;) {
+		for(DWORD subkeyIndex=0;;++subkeyIndex) {
 			DWORD type;
 			DWORD dataLen;
 			DWORD subkeyNameLen = sizeof(subkeyName);
 			DWORD subkeyClassLen = sizeof(subkeyClass);
 			FILETIME lastWriteTime;
-			switch (RegEnumKeyExA(nwAdapters,subkeyIndex++,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime)) {
-				case ERROR_NO_MORE_ITEMS: subkeyIndex = -1; break;
-				case 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;
+			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) {
 							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) {
-								type = 0;
-								dataLen = sizeof(data);
-								if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
-									if (dataLen <= 0) {
-										if (alsoRemoveUnassociatedDevices)
-											instanceIdPathsToRemove.insert(instanceIdPath);
-									} else {
-										if (!exceptThese.count(std::string(data,dataLen)))
-											instanceIdPathsToRemove.insert(instanceIdPath);
-									}
-								} else if (alsoRemoveUnassociatedDevices)
-									instanceIdPathsToRemove.insert(instanceIdPath);
-							}
+							if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
+								if (dataLen <= 0) {
+									if (alsoRemoveUnassociatedDevices)
+										instanceIdPathsToRemove.insert(instanceIdPath);
+								} else {
+									if (!exceptThese.count(std::string(data,dataLen)))
+										instanceIdPathsToRemove.insert(instanceIdPath);
+								}
+							} else if (alsoRemoveUnassociatedDevices)
+								instanceIdPathsToRemove.insert(instanceIdPath);
 						}
 					}
-					break;
-			}
+				}
+			} else break; // end of list or failure
 		}
 
 		RegCloseKey(nwAdapters);
 	}
 
 	int removed = 0;
-
 	for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) {
 		if (deletePersistentTapDevice(_r,iidp->c_str()))
 			++removed;
 	}
-
 	return removed;
 }