|
@@ -32,6 +32,7 @@
|
|
|
#include <WinSock2.h>
|
|
|
#include <Windows.h>
|
|
|
#include <tchar.h>
|
|
|
+#include <malloc.h>
|
|
|
#include <winreg.h>
|
|
|
#include <wchar.h>
|
|
|
#include <ws2ipdef.h>
|
|
@@ -42,6 +43,9 @@
|
|
|
#include <atlbase.h>
|
|
|
#include <netlistmgr.h>
|
|
|
#include <nldef.h>
|
|
|
+#include <SetupAPI.h>
|
|
|
+#include <newdev.h>
|
|
|
+#include <cfgmgr32.h>
|
|
|
|
|
|
#include <iostream>
|
|
|
#include <set>
|
|
@@ -55,15 +59,28 @@
|
|
|
|
|
|
#include "..\windows\TapDriver6\tap-windows.h"
|
|
|
|
|
|
-// ff:ff:ff:ff:ff:ff with no ADI
|
|
|
-//static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
|
|
|
-
|
|
|
+// Create a fake unused default route to force detection of network type on networks without gateways
|
|
|
#define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE
|
|
|
|
|
|
+// Function signatures of dynamically loaded functions, from newdev.h, setupapi.h, and cfgmgr32.h
|
|
|
+typedef BOOL (WINAPI *UpdateDriverForPlugAndPlayDevicesA_t)(_In_opt_ HWND hwndParent,_In_ LPCSTR HardwareId,_In_ LPCSTR FullInfPath,_In_ DWORD InstallFlags,_Out_opt_ PBOOL bRebootRequired);
|
|
|
+typedef BOOL (WINAPI *SetupDiGetINFClassA_t)(_In_ PCSTR InfName,_Out_ LPGUID ClassGuid,_Out_writes_(ClassNameSize) PSTR ClassName,_In_ DWORD ClassNameSize,_Out_opt_ PDWORD RequiredSize);
|
|
|
+typedef HDEVINFO (WINAPI *SetupDiCreateDeviceInfoList_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ HWND hwndParent);
|
|
|
+typedef BOOL (WINAPI *SetupDiCreateDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceName,_In_ CONST GUID *ClassGuid,_In_opt_ PCSTR DeviceDescription,_In_opt_ HWND hwndParent,_In_ DWORD CreationFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData);
|
|
|
+typedef BOOL (WINAPI *SetupDiSetDeviceRegistryPropertyA_t)(_In_ HDEVINFO DeviceInfoSet,_Inout_ PSP_DEVINFO_DATA DeviceInfoData,_In_ DWORD Property,_In_reads_bytes_opt_(PropertyBufferSize) CONST BYTE *PropertyBuffer,_In_ DWORD PropertyBufferSize);
|
|
|
+typedef BOOL (WINAPI *SetupDiCallClassInstaller_t)(_In_ DI_FUNCTION InstallFunction,_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData);
|
|
|
+typedef BOOL (WINAPI *SetupDiDestroyDeviceInfoList_t)(_In_ HDEVINFO DeviceInfoSet);
|
|
|
+typedef HDEVINFO (WINAPI *SetupDiGetClassDevsExA_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ PCSTR Enumerator,_In_opt_ HWND hwndParent,_In_ DWORD Flags,_In_opt_ HDEVINFO DeviceInfoSet,_In_opt_ PCSTR MachineName,_Reserved_ PVOID Reserved);
|
|
|
+typedef BOOL (WINAPI *SetupDiOpenDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceInstanceId,_In_opt_ HWND hwndParent,_In_ DWORD OpenFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData);
|
|
|
+typedef BOOL (WINAPI *SetupDiEnumDeviceInfo_t)(_In_ HDEVINFO DeviceInfoSet,_In_ DWORD MemberIndex,_Out_ PSP_DEVINFO_DATA DeviceInfoData);
|
|
|
+typedef BOOL (WINAPI *SetupDiSetClassInstallParamsA_t)(_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData,_In_reads_bytes_opt_(ClassInstallParamsSize) PSP_CLASSINSTALL_HEADER ClassInstallParams,_In_ DWORD ClassInstallParamsSize);
|
|
|
+typedef CONFIGRET (WINAPI *CM_Get_Device_ID_ExA_t)(_In_ DEVINST dnDevInst,_Out_writes_(BufferLen) PSTR Buffer,_In_ ULONG BufferLen,_In_ ULONG ulFlags,_In_opt_ HMACHINE hMachine);
|
|
|
+
|
|
|
namespace ZeroTier {
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
+// Static/singleton class that when initialized loads a bunch of environment information and a few dynamically loaded DLLs
|
|
|
class WindowsEthernetTapEnv
|
|
|
{
|
|
|
public:
|
|
@@ -71,29 +88,364 @@ public:
|
|
|
{
|
|
|
#ifdef _WIN64
|
|
|
is64Bit = TRUE;
|
|
|
- devcon = "\\devcon_x64.exe";
|
|
|
- tapDriverNdis5 = "\\tap-windows\\x64\\zttap200.inf";
|
|
|
- tapDriverNdis6 = "\\tap-windows\\x64\\zttap300.inf";
|
|
|
+ tapDriverPath = "\\tap-windows\\x64\\zttap300.inf";
|
|
|
#else
|
|
|
is64Bit = FALSE;
|
|
|
IsWow64Process(GetCurrentProcess(),&is64Bit);
|
|
|
- devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe");
|
|
|
- tapDriverNdis5 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf");
|
|
|
- tapDriverNdis6 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap300.inf" : "\\tap-windows\\x86\\zttap300.inf");
|
|
|
+ if (is64Bit) {
|
|
|
+ fprintf(stderr,"FATAL: you must use the 64-bit ZeroTier One service on 64-bit Windows systems\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ tapDriverPath = "\\tap-windows\\x86\\zttap300.inf";
|
|
|
#endif
|
|
|
+ tapDriverName = "zttap300";
|
|
|
+
|
|
|
+ setupApiMod = LoadLibraryA("setupapi.dll");
|
|
|
+ if (!setupApiMod) {
|
|
|
+ fprintf(stderr,"FATAL: unable to dynamically load setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiGetINFClassA = (SetupDiGetINFClassA_t)GetProcAddress(setupApiMod,"SetupDiGetINFClassA"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiGetINFClassA not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiCreateDeviceInfoList = (SetupDiCreateDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoList"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoList not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiCreateDeviceInfoA = (SetupDiCreateDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoA"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoA not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiSetDeviceRegistryPropertyA = (SetupDiSetDeviceRegistryPropertyA_t)GetProcAddress(setupApiMod,"SetupDiSetDeviceRegistryPropertyA"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiSetDeviceRegistryPropertyA not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiCallClassInstaller = (SetupDiCallClassInstaller_t)GetProcAddress(setupApiMod,"SetupDiCallClassInstaller"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiCallClassInstaller not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiDestroyDeviceInfoList = (SetupDiDestroyDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiDestroyDeviceInfoList"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiDestroyDeviceInfoList not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiGetClassDevsExA = (SetupDiGetClassDevsExA_t)GetProcAddress(setupApiMod,"SetupDiGetClassDevsExA"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiGetClassDevsExA not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiOpenDeviceInfoA = (SetupDiOpenDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiOpenDeviceInfoA"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiOpenDeviceInfoA not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiEnumDeviceInfo = (SetupDiEnumDeviceInfo_t)GetProcAddress(setupApiMod,"SetupDiEnumDeviceInfo"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiEnumDeviceInfo not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->SetupDiSetClassInstallParamsA = (SetupDiSetClassInstallParamsA_t)GetProcAddress(setupApiMod,"SetupDiSetClassInstallParamsA"))) {
|
|
|
+ fprintf(stderr,"FATAL: SetupDiSetClassInstallParamsA not found in setupapi.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ newDevMod = LoadLibraryA("newdev.dll");
|
|
|
+ if (!newDevMod) {
|
|
|
+ fprintf(stderr,"FATAL: unable to dynamically load newdev.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->UpdateDriverForPlugAndPlayDevicesA = (UpdateDriverForPlugAndPlayDevicesA_t)GetProcAddress(newDevMod,"UpdateDriverForPlugAndPlayDevicesA"))) {
|
|
|
+ fprintf(stderr,"FATAL: UpdateDriverForPlugAndPlayDevicesA not found in newdev.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ cfgMgrMod = LoadLibraryA("cfgmgr32.dll");
|
|
|
+ if (!cfgMgrMod) {
|
|
|
+ fprintf(stderr,"FATAL: unable to dynamically load cfgmgr32.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
+ if (!(this->CM_Get_Device_ID_ExA = (CM_Get_Device_ID_ExA_t)GetProcAddress(cfgMgrMod,"CM_Get_Device_ID_ExA"))) {
|
|
|
+ fprintf(stderr,"FATAL: CM_Get_Device_ID_ExA not found in cfgmgr32.dll\r\n");
|
|
|
+ _exit(1);
|
|
|
+ }
|
|
|
}
|
|
|
- BOOL is64Bit;
|
|
|
- const char *devcon;
|
|
|
- const char *tapDriverNdis5;
|
|
|
- const char *tapDriverNdis6;
|
|
|
+
|
|
|
+ BOOL is64Bit; // is the system 64-bit, regardless of whether this binary is or not
|
|
|
+ std::string tapDriverPath;
|
|
|
+ std::string tapDriverName;
|
|
|
+
|
|
|
+ UpdateDriverForPlugAndPlayDevicesA_t UpdateDriverForPlugAndPlayDevicesA;
|
|
|
+
|
|
|
+ SetupDiGetINFClassA_t SetupDiGetINFClassA;
|
|
|
+ SetupDiCreateDeviceInfoList_t SetupDiCreateDeviceInfoList;
|
|
|
+ SetupDiCreateDeviceInfoA_t SetupDiCreateDeviceInfoA;
|
|
|
+ SetupDiSetDeviceRegistryPropertyA_t SetupDiSetDeviceRegistryPropertyA;
|
|
|
+ SetupDiCallClassInstaller_t SetupDiCallClassInstaller;
|
|
|
+ SetupDiDestroyDeviceInfoList_t SetupDiDestroyDeviceInfoList;
|
|
|
+ SetupDiGetClassDevsExA_t SetupDiGetClassDevsExA;
|
|
|
+ SetupDiOpenDeviceInfoA_t SetupDiOpenDeviceInfoA;
|
|
|
+ SetupDiEnumDeviceInfo_t SetupDiEnumDeviceInfo;
|
|
|
+ SetupDiSetClassInstallParamsA_t SetupDiSetClassInstallParamsA;
|
|
|
+
|
|
|
+ CM_Get_Device_ID_ExA_t CM_Get_Device_ID_ExA;
|
|
|
+
|
|
|
+private:
|
|
|
+ HMODULE setupApiMod;
|
|
|
+ HMODULE newDevMod;
|
|
|
+ HMODULE cfgMgrMod;
|
|
|
};
|
|
|
static const WindowsEthernetTapEnv WINENV;
|
|
|
|
|
|
// Only create or delete devices one at a time
|
|
|
static Mutex _systemTapInitLock;
|
|
|
|
|
|
+// Only perform installation or uninstallation options one at a time
|
|
|
+static Mutex _systemDeviceManagementLock;
|
|
|
+
|
|
|
} // anonymous namespace
|
|
|
|
|
|
+std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf)
|
|
|
+{
|
|
|
+ Mutex::Lock _l(_systemDeviceManagementLock);
|
|
|
+
|
|
|
+ GUID classGuid;
|
|
|
+ char className[4096];
|
|
|
+ if (!WINENV.SetupDiGetINFClassA(pathToInf,&classGuid,className,sizeof(className),(PDWORD)0)) {
|
|
|
+ return std::string("SetupDiGetINFClassA() failed -- unable to read zttap driver INF file");
|
|
|
+ }
|
|
|
+
|
|
|
+ HDEVINFO deviceInfoSet = WINENV.SetupDiCreateDeviceInfoList(&classGuid,(HWND)0);
|
|
|
+ if (deviceInfoSet == INVALID_HANDLE_VALUE) {
|
|
|
+ return std::string("SetupDiCreateDeviceInfoList() failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ SP_DEVINFO_DATA deviceInfoData;
|
|
|
+ memset(&deviceInfoData,0,sizeof(deviceInfoData));
|
|
|
+ deviceInfoData.cbSize = sizeof(deviceInfoData);
|
|
|
+ if (!WINENV.SetupDiCreateDeviceInfoA(deviceInfoSet,className,&classGuid,(PCSTR)0,(HWND)0,DICD_GENERATE_ID,&deviceInfoData)) {
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
+ return std::string("SetupDiCreateDeviceInfoA() failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!WINENV.SetupDiSetDeviceRegistryPropertyA(deviceInfoSet,&deviceInfoData,SPDRP_HARDWAREID,(const BYTE *)WINENV.tapDriverName.c_str(),(DWORD)(WINENV.tapDriverName.length() + 1))) {
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
+ return std::string("SetupDiSetDeviceRegistryPropertyA() failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!WINENV.SetupDiCallClassInstaller(DIF_REGISTERDEVICE,deviceInfoSet,&deviceInfoData)) {
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
+ return std::string("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ // HACK: During upgrades, this can fail while the installer is still running. So make 60 attempts
|
|
|
+ // with a 1s delay between each attempt.
|
|
|
+ bool driverInstalled = false;
|
|
|
+ for(int retryCounter=0;retryCounter<60;++retryCounter) {
|
|
|
+ BOOL rebootRequired = FALSE;
|
|
|
+ if (WINENV.UpdateDriverForPlugAndPlayDevicesA((HWND)0,WINENV.tapDriverName.c_str(),pathToInf,INSTALLFLAG_FORCE|INSTALLFLAG_NONINTERACTIVE,&rebootRequired)) {
|
|
|
+ driverInstalled = true;
|
|
|
+ break;
|
|
|
+ } else Sleep(1000);
|
|
|
+ }
|
|
|
+ if (!driverInstalled) {
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
+ return std::string("UpdateDriverForPlugAndPlayDevices() failed (made 60 attempts)");
|
|
|
+ }
|
|
|
+
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
+
|
|
|
+ return std::string();
|
|
|
+}
|
|
|
+
|
|
|
+std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices()
|
|
|
+{
|
|
|
+ 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 std::string("Could not open registry key");
|
|
|
+
|
|
|
+ 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))&&(WINENV.tapDriverName != data)) {
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string errlist;
|
|
|
+ for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) {
|
|
|
+ std::string err = deletePersistentTapDevice(iidp->c_str());
|
|
|
+ if (err.length() > 0) {
|
|
|
+ if (errlist.length() > 0)
|
|
|
+ errlist.push_back(',');
|
|
|
+ errlist.append(err);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return errlist;
|
|
|
+}
|
|
|
+
|
|
|
+std::string WindowsEthernetTap::destroyAllPersistentTapDevices()
|
|
|
+{
|
|
|
+ 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 std::string("Could not open registry key");
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string errlist;
|
|
|
+ for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) {
|
|
|
+ std::string err = deletePersistentTapDevice(iidp->c_str());
|
|
|
+ if (err.length() > 0) {
|
|
|
+ if (errlist.length() > 0)
|
|
|
+ errlist.push_back(',');
|
|
|
+ errlist.append(err);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return errlist;
|
|
|
+}
|
|
|
+
|
|
|
+std::string WindowsEthernetTap::deletePersistentTapDevice(const char *instanceId)
|
|
|
+{
|
|
|
+ char iid[256];
|
|
|
+ SP_REMOVEDEVICE_PARAMS rmdParams;
|
|
|
+
|
|
|
+ memset(&rmdParams,0,sizeof(rmdParams));
|
|
|
+ rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
|
+ rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
|
|
|
+ rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
|
|
|
+ rmdParams.HwProfile = 0;
|
|
|
+
|
|
|
+ Mutex::Lock _l(_systemDeviceManagementLock);
|
|
|
+
|
|
|
+ HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0);
|
|
|
+ if (devInfo == INVALID_HANDLE_VALUE)
|
|
|
+ return std::string("SetupDiGetClassDevsExA() failed");
|
|
|
+ WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0);
|
|
|
+
|
|
|
+ SP_DEVINFO_DATA devInfoData;
|
|
|
+ memset(&devInfoData,0,sizeof(devInfoData));
|
|
|
+ devInfoData.cbSize = sizeof(devInfoData);
|
|
|
+ for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) {
|
|
|
+ if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) {
|
|
|
+ if (!WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,&rmdParams.ClassInstallHeader,sizeof(rmdParams))) {
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(devInfo);
|
|
|
+ return std::string("SetupDiSetClassInstallParams() failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!WINENV.SetupDiCallClassInstaller(DIF_REMOVE,devInfo,&devInfoData)) {
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(devInfo);
|
|
|
+ return std::string("SetupDiCallClassInstaller(DIF_REMOVE) failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(devInfo);
|
|
|
+ return std::string();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(devInfo);
|
|
|
+ return std::string("instance ID not found");
|
|
|
+}
|
|
|
+
|
|
|
+bool WindowsEthernetTap::setPersistentTapDeviceState(const char *instanceId,bool enabled)
|
|
|
+{
|
|
|
+ char iid[256];
|
|
|
+ SP_PROPCHANGE_PARAMS params;
|
|
|
+
|
|
|
+ Mutex::Lock _l(_systemDeviceManagementLock);
|
|
|
+
|
|
|
+ HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0);
|
|
|
+ if (devInfo == INVALID_HANDLE_VALUE)
|
|
|
+ return false;
|
|
|
+ WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0);
|
|
|
+
|
|
|
+ SP_DEVINFO_DATA devInfoData;
|
|
|
+ memset(&devInfoData,0,sizeof(devInfoData));
|
|
|
+ devInfoData.cbSize = sizeof(devInfoData);
|
|
|
+ for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) {
|
|
|
+ if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) {
|
|
|
+ memset(¶ms,0,sizeof(params));
|
|
|
+ params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
|
+ params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
|
|
|
+ params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE;
|
|
|
+ params.Scope = DICS_FLAG_GLOBAL;
|
|
|
+ params.HwProfile = 0;
|
|
|
+
|
|
|
+ WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params));
|
|
|
+ WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData);
|
|
|
+
|
|
|
+ memset(¶ms,0,sizeof(params));
|
|
|
+ params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
|
+ params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
|
|
|
+ params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE;
|
|
|
+ params.Scope = DICS_FLAG_CONFIGSPECIFIC;
|
|
|
+ params.HwProfile = 0;
|
|
|
+
|
|
|
+ WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params));
|
|
|
+ WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData);
|
|
|
+
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(devInfo);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ WINENV.SetupDiDestroyDeviceInfoList(devInfo);
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
WindowsEthernetTap::WindowsEthernetTap(
|
|
|
const char *hp,
|
|
|
const MAC &mac,
|
|
@@ -118,35 +470,20 @@ WindowsEthernetTap::WindowsEthernetTap(
|
|
|
char subkeyClass[4096];
|
|
|
char data[4096];
|
|
|
char tag[24];
|
|
|
+ std::string mySubkeyName;
|
|
|
|
|
|
if (mtu > 2800)
|
|
|
throw std::runtime_error("MTU too large for Windows tap");
|
|
|
|
|
|
- Mutex::Lock _l(_systemTapInitLock);
|
|
|
+ // We "tag" registry entries with the network ID to identify persistent devices
|
|
|
+ Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid);
|
|
|
|
|
|
- // Use NDIS5 if it's installed, since we don't want to switch out the driver on
|
|
|
- // pre-existing installs (yet). We won't ship NDIS5 anymore so new installs will
|
|
|
- // use NDIS6.
|
|
|
- std::string tapDriverPath(_pathToHelpers + WINENV.tapDriverNdis5);
|
|
|
- const char *tapDriverName = "zttap200";
|
|
|
- if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) {
|
|
|
- tapDriverPath = _pathToHelpers + WINENV.tapDriverNdis6;
|
|
|
- tapDriverName = "zttap300";
|
|
|
- if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) {
|
|
|
- throw std::runtime_error("no tap driver available: cannot find zttap300.inf (NDIS6) or zttap200.inf (NDIS5) under home path");
|
|
|
- }
|
|
|
- }
|
|
|
+ Mutex::Lock _l(_systemTapInitLock);
|
|
|
|
|
|
HKEY nwAdapters;
|
|
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS)
|
|
|
throw std::runtime_error("unable to open registry key for network adapter enumeration");
|
|
|
|
|
|
- std::set<std::string> existingDeviceInstances;
|
|
|
- std::string mySubkeyName;
|
|
|
-
|
|
|
- // We "tag" registry entries with the network ID to identify persistent devices
|
|
|
- Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid);
|
|
|
-
|
|
|
// Look for the tap instance that corresponds with this network
|
|
|
for(DWORD subkeyIndex=0;;++subkeyIndex) {
|
|
|
DWORD type;
|
|
@@ -158,15 +495,14 @@ WindowsEthernetTap::WindowsEthernetTap(
|
|
|
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)) {
|
|
|
+ data[dataLen] = (char)0;
|
|
|
+
|
|
|
+ if (WINENV.tapDriverName == data) {
|
|
|
std::string instanceId;
|
|
|
type = 0;
|
|
|
dataLen = sizeof(data);
|
|
|
- if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
|
|
|
+ if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
|
|
|
instanceId.assign(data,dataLen);
|
|
|
- existingDeviceInstances.insert(instanceId);
|
|
|
- }
|
|
|
|
|
|
std::string instanceIdPath;
|
|
|
type = 0;
|
|
@@ -196,74 +532,61 @@ WindowsEthernetTap::WindowsEthernetTap(
|
|
|
// If there is no device, try to create one
|
|
|
bool creatingNewDevice = (_netCfgInstanceId.length() == 0);
|
|
|
if (creatingNewDevice) {
|
|
|
- // Log devcon output to a file
|
|
|
- HANDLE devconLog = CreateFileA((_pathToHelpers + "\\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);
|
|
|
-
|
|
|
- // Execute devcon to create a new tap device
|
|
|
- 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 + "\" install \"" + tapDriverPath + "\" " + tapDriverName).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 ") + WINENV.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 originally there...
|
|
|
- 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)) {
|
|
|
- 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));
|
|
|
- _netCfgInstanceId.assign(data,dataLen);
|
|
|
+ for(int getNewAttemptCounter=0;getNewAttemptCounter<2;++getNewAttemptCounter) {
|
|
|
+ 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 (WINENV.tapDriverName == data) {
|
|
|
+ type = 0;
|
|
|
+ dataLen = sizeof(data);
|
|
|
+ if ((RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) != ERROR_SUCCESS)||(dataLen <= 0)) {
|
|
|
type = 0;
|
|
|
dataLen = sizeof(data);
|
|
|
- if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
|
|
|
- _deviceInstanceId.assign(data,dataLen);
|
|
|
- mySubkeyName = subkeyName;
|
|
|
+ if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
|
|
|
+ RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1));
|
|
|
|
|
|
- // 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,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable));
|
|
|
- RegCloseKey(tcpIpInterfaces);
|
|
|
- }
|
|
|
+ _netCfgInstanceId.assign(data,dataLen);
|
|
|
|
|
|
- break; // found it!
|
|
|
+ type = 0;
|
|
|
+ dataLen = sizeof(data);
|
|
|
+ if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
|
|
|
+ _deviceInstanceId.assign(data,dataLen);
|
|
|
+
|
|
|
+ mySubkeyName = subkeyName;
|
|
|
+
|
|
|
+ // Disable DHCP by default on new 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,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable));
|
|
|
+ RegCloseKey(tcpIpInterfaces);
|
|
|
+ }
|
|
|
+
|
|
|
+ break; // found an unused zttap device
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- } else break; // no more keys or error occurred
|
|
|
+ } else break; // no more keys or error occurred
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_netCfgInstanceId.length() > 0) {
|
|
|
+ break; // found an unused zttap device
|
|
|
+ } else {
|
|
|
+ // no unused zttap devices, so create one
|
|
|
+ std::string errm = addNewPersistentTapDevice((std::string(_pathToHelpers) + WINENV.tapDriverPath).c_str());
|
|
|
+ if (errm.length() > 0)
|
|
|
+ throw std::runtime_error(std::string("unable to create new device instance: ")+errm);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -281,6 +604,7 @@ WindowsEthernetTap::WindowsEthernetTap(
|
|
|
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
|
|
|
|
|
|
if (creatingNewDevice) {
|
|
|
+ // Set EnableDHCP to 0 by default on new devices
|
|
|
tmp = 0;
|
|
|
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
|
|
|
}
|
|
@@ -291,7 +615,7 @@ WindowsEthernetTap::WindowsEthernetTap(
|
|
|
}
|
|
|
|
|
|
{
|
|
|
- char nobraces[128];
|
|
|
+ char nobraces[128]; // strip braces from GUID before converting it, because Windows
|
|
|
const char *nbtmp1 = _netCfgInstanceId.c_str();
|
|
|
char *nbtmp2 = nobraces;
|
|
|
while (*nbtmp1) {
|
|
@@ -304,17 +628,15 @@ WindowsEthernetTap::WindowsEthernetTap(
|
|
|
throw std::runtime_error("unable to convert instance ID GUID to native GUID (invalid NetCfgInstanceId in registry?)");
|
|
|
}
|
|
|
|
|
|
- // Look up interface LUID... why are there (at least) four fucking ways to refer to a network device in Windows?
|
|
|
+ // Get the LUID, which is one of like four fucking ways to refer to a network device in Windows
|
|
|
if (ConvertInterfaceGuidToLuid(&_deviceGuid,&_deviceLuid) != NO_ERROR)
|
|
|
throw std::runtime_error("unable to convert device interface GUID to LUID");
|
|
|
|
|
|
- // Certain functions can now work (e.g. ips())
|
|
|
_initialized = true;
|
|
|
|
|
|
if (friendlyName)
|
|
|
setFriendlyName(friendlyName);
|
|
|
|
|
|
- // Start background thread that actually performs I/O
|
|
|
_injectSemaphore = CreateSemaphore(NULL,0,1,NULL);
|
|
|
_thread = Thread::start(this);
|
|
|
}
|
|
@@ -325,7 +647,7 @@ WindowsEthernetTap::~WindowsEthernetTap()
|
|
|
ReleaseSemaphore(_injectSemaphore,1,NULL);
|
|
|
Thread::join(_thread);
|
|
|
CloseHandle(_injectSemaphore);
|
|
|
- _disableTapDevice();
|
|
|
+ setPersistentTapDeviceState(_deviceInstanceId.c_str(),false);
|
|
|
}
|
|
|
|
|
|
void WindowsEthernetTap::setEnabled(bool en)
|
|
@@ -340,63 +662,28 @@ bool WindowsEthernetTap::enabled() const
|
|
|
|
|
|
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::vector<InetAddress> haveIps(ips());
|
|
|
-
|
|
|
- try {
|
|
|
- // Add IP to interface at the netlink level if not already assigned.
|
|
|
- if (!std::binary_search(haveIps.begin(),haveIps.end(),ip)) {
|
|
|
- MIB_UNICASTIPADDRESS_ROW ipr;
|
|
|
-
|
|
|
- InitializeUnicastIpAddressEntry(&ipr);
|
|
|
- if (ip.isV4()) {
|
|
|
- ipr.Address.Ipv4.sin_family = AF_INET;
|
|
|
- ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)ip.rawIpData());
|
|
|
- ipr.OnLinkPrefixLength = ip.port();
|
|
|
- if (ipr.OnLinkPrefixLength >= 32)
|
|
|
- return false;
|
|
|
- } else if (ip.isV6()) {
|
|
|
- ipr.Address.Ipv6.sin6_family = AF_INET6;
|
|
|
- memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,ip.rawIpData(),16);
|
|
|
- ipr.OnLinkPrefixLength = ip.port();
|
|
|
- if (ipr.OnLinkPrefixLength >= 128)
|
|
|
- return false;
|
|
|
- } else return false;
|
|
|
-
|
|
|
- ipr.PrefixOrigin = IpPrefixOriginManual;
|
|
|
- ipr.SuffixOrigin = IpSuffixOriginManual;
|
|
|
- ipr.ValidLifetime = 0xffffffff;
|
|
|
- ipr.PreferredLifetime = 0xffffffff;
|
|
|
-
|
|
|
- ipr.InterfaceLuid = _deviceLuid;
|
|
|
- ipr.InterfaceIndex = _getDeviceIndex();
|
|
|
-
|
|
|
- if (CreateUnicastIpAddressEntry(&ipr) != NO_ERROR)
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress"));
|
|
|
- if (std::find(regIps.begin(),regIps.end(),ip.toIpString()) == regIps.end()) {
|
|
|
- std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask"));
|
|
|
- regIps.push_back(ip.toIpString());
|
|
|
- regSubnetMasks.push_back(ip.netmask().toIpString());
|
|
|
- _setRegistryIPv4Value("IPAddress",regIps);
|
|
|
- _setRegistryIPv4Value("SubnetMask",regSubnetMasks);
|
|
|
- }
|
|
|
- } catch ( ... ) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ Mutex::Lock _l(_assignedIps_m);
|
|
|
+ if (std::find(_assignedIps.begin(),_assignedIps.end(),ip) != _assignedIps.end())
|
|
|
+ return true;
|
|
|
+ _assignedIps.push_back(ip);
|
|
|
+ _syncIps();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool WindowsEthernetTap::removeIp(const InetAddress &ip)
|
|
|
{
|
|
|
+ {
|
|
|
+ Mutex::Lock _l(_assignedIps_m);
|
|
|
+ std::vector<InetAddress>::iterator aip(std::find(_assignedIps.begin(),_assignedIps.end(),ip));
|
|
|
+ if (aip != _assignedIps.end())
|
|
|
+ _assignedIps.erase(aip);
|
|
|
+ }
|
|
|
+
|
|
|
if (!_initialized)
|
|
|
return false;
|
|
|
+
|
|
|
try {
|
|
|
MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0;
|
|
|
if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) {
|
|
@@ -572,13 +859,18 @@ void WindowsEthernetTap::threadMain()
|
|
|
|
|
|
try {
|
|
|
while (_run) {
|
|
|
- _enableTapDevice();
|
|
|
+ // Because Windows
|
|
|
+ setPersistentTapDeviceState(_deviceInstanceId.c_str(),false);
|
|
|
+ Sleep(500);
|
|
|
+ setPersistentTapDeviceState(_deviceInstanceId.c_str(),true);
|
|
|
+ Sleep(500);
|
|
|
+ setPersistentTapDeviceState(_deviceInstanceId.c_str(),false);
|
|
|
+ Sleep(500);
|
|
|
+ setPersistentTapDeviceState(_deviceInstanceId.c_str(),true);
|
|
|
Sleep(500);
|
|
|
|
|
|
_tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL);
|
|
|
if (_tap == INVALID_HANDLE_VALUE) {
|
|
|
- _disableTapDevice();
|
|
|
- _enableTapDevice();
|
|
|
Sleep(1000);
|
|
|
continue;
|
|
|
}
|
|
@@ -668,6 +960,12 @@ void WindowsEthernetTap::threadMain()
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+ // Assign or re-assign any should-be-assigned IPs in case we have restarted
|
|
|
+ {
|
|
|
+ Mutex::Lock _l(_assignedIps_m);
|
|
|
+ _syncIps();
|
|
|
+ }
|
|
|
+
|
|
|
memset(&tapOvlRead,0,sizeof(tapOvlRead));
|
|
|
tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
|
memset(&tapOvlWrite,0,sizeof(tapOvlWrite));
|
|
@@ -761,131 +1059,6 @@ void WindowsEthernetTap::threadMain()
|
|
|
} catch ( ... ) {} // catch unexpected exceptions -- this should not happen but would prevent program crash or other weird issues since threads should not throw
|
|
|
}
|
|
|
|
|
|
-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());
|
|
|
-}
|
|
|
-
|
|
|
-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);
|
|
|
-}
|
|
|
-
|
|
|
-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);
|
|
|
- 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("\"") + _pathToHelpers + WINENV.devcon + "\" disable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
|
|
|
- if (devconLog != INVALID_HANDLE_VALUE)
|
|
|
- CloseHandle(devconLog);
|
|
|
- return false;
|
|
|
- }
|
|
|
- WaitForSingleObject(processInfo.hProcess,INFINITE);
|
|
|
- CloseHandle(processInfo.hProcess);
|
|
|
- CloseHandle(processInfo.hThread);
|
|
|
-
|
|
|
- if (devconLog != INVALID_HANDLE_VALUE)
|
|
|
- CloseHandle(devconLog);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-bool WindowsEthernetTap::_enableTapDevice()
|
|
|
-{
|
|
|
- HANDLE devconLog = CreateFileA((_pathToHelpers + "\\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("\"") + _pathToHelpers + WINENV.devcon + "\" enable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
|
|
|
- if (devconLog != INVALID_HANDLE_VALUE)
|
|
|
- CloseHandle(devconLog);
|
|
|
- return false;
|
|
|
- }
|
|
|
- WaitForSingleObject(processInfo.hProcess,INFINITE);
|
|
|
- CloseHandle(processInfo.hProcess);
|
|
|
- CloseHandle(processInfo.hThread);
|
|
|
-
|
|
|
- if (devconLog != INVALID_HANDLE_VALUE)
|
|
|
- CloseHandle(devconLog);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
NET_IFINDEX WindowsEthernetTap::_getDeviceIndex()
|
|
|
{
|
|
|
MIB_IF_TABLE2 *ift = (MIB_IF_TABLE2 *)0;
|
|
@@ -956,4 +1129,55 @@ void WindowsEthernetTap::_setRegistryIPv4Value(const char *regKey,const std::vec
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void WindowsEthernetTap::_syncIps()
|
|
|
+{
|
|
|
+ // assumes _assignedIps_m is locked
|
|
|
+
|
|
|
+ if (!_initialized)
|
|
|
+ return;
|
|
|
+
|
|
|
+ std::vector<InetAddress> haveIps(ips());
|
|
|
+
|
|
|
+ for(std::vector<InetAddress>::const_iterator aip(_assignedIps.begin());aip!=_assignedIps.end();++aip) {
|
|
|
+ if (std::find(haveIps.begin(),haveIps.end(),*aip) == haveIps.end()) {
|
|
|
+ MIB_UNICASTIPADDRESS_ROW ipr;
|
|
|
+
|
|
|
+ InitializeUnicastIpAddressEntry(&ipr);
|
|
|
+ if (aip->isV4()) {
|
|
|
+ ipr.Address.Ipv4.sin_family = AF_INET;
|
|
|
+ ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)aip->rawIpData());
|
|
|
+ ipr.OnLinkPrefixLength = aip->netmaskBits();
|
|
|
+ if (ipr.OnLinkPrefixLength >= 32)
|
|
|
+ continue;
|
|
|
+ } else if (aip->isV6()) {
|
|
|
+ ipr.Address.Ipv6.sin6_family = AF_INET6;
|
|
|
+ memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,aip->rawIpData(),16);
|
|
|
+ ipr.OnLinkPrefixLength = aip->netmaskBits();
|
|
|
+ if (ipr.OnLinkPrefixLength >= 128)
|
|
|
+ continue;
|
|
|
+ } else continue;
|
|
|
+
|
|
|
+ ipr.PrefixOrigin = IpPrefixOriginManual;
|
|
|
+ ipr.SuffixOrigin = IpSuffixOriginManual;
|
|
|
+ ipr.ValidLifetime = 0xffffffff;
|
|
|
+ ipr.PreferredLifetime = 0xffffffff;
|
|
|
+
|
|
|
+ ipr.InterfaceLuid = _deviceLuid;
|
|
|
+ ipr.InterfaceIndex = _getDeviceIndex();
|
|
|
+
|
|
|
+ CreateUnicastIpAddressEntry(&ipr);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string ipStr(aip->toString());
|
|
|
+ std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress"));
|
|
|
+ if (std::find(regIps.begin(),regIps.end(),ipStr) == regIps.end()) {
|
|
|
+ std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask"));
|
|
|
+ regIps.push_back(ipStr);
|
|
|
+ regSubnetMasks.push_back(aip->netmask().toIpString());
|
|
|
+ _setRegistryIPv4Value("IPAddress",regIps);
|
|
|
+ _setRegistryIPv4Value("SubnetMask",regSubnetMasks);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
} // namespace ZeroTier
|