Browse Source

Tap now creates Microsoft Loopback Adapter instances and tags them with a special ID... work in progress.

Adam Ierymenko 12 years ago
parent
commit
ca5334509c
2 changed files with 123 additions and 10 deletions
  1. 108 10
      node/EthernetTap.cpp
  2. 15 0
      selftest.cpp

+ 108 - 10
node/EthernetTap.cpp

@@ -27,6 +27,8 @@
 
 #include <string>
 #include <map>
+#include <set>
+#include <algorithm>
 
 #include "Constants.hpp"
 #include "EthernetTap.hpp"
@@ -687,6 +689,8 @@ void EthernetTap::threadMain()
 
 namespace ZeroTier {
 
+static Mutex _systemTapInitLock;
+
 EthernetTap::EthernetTap(
 	const RuntimeEnvironment *renv,
 	const char *tag,
@@ -701,31 +705,125 @@ EthernetTap::EthernetTap(
 	_handler(handler),
 	_arg(arg)
 {
+	char subkeyName[1024];
+	char subkeyClass[1024];
+	char data[1024];
+
+	Mutex::Lock _l(_systemTapInitLock); // only do one at a time, process-wide
+
 	HKEY nwAdapters;
-	if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_ALL_ACCESS,&nwAdapters) != ERROR_SUCCESS)
+	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::string myDeviceInstanceId;
+	std::set<std::string> existingDeviceInstances;
+
+	// Enumerate all Microsoft Loopback Adapter instances and look for one
+	// that matches our tag.
 	for(DWORD subkeyIndex=0;subkeyIndex!=-1;) {
-		char subkeyName[1024];
-		char subkeyClass[1024];
+		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: {
-				DWORD type = 0;
-				char data[1024];
-				DWORD dataLen = sizeof(data);
-				if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
+			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';
-					printf("%s: %s\r\n",subkeyName,data);
+					if (!strcmpi(data,"*msloop")) {
+						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 ((myDeviceInstanceId.length() == 0)&&(instanceId.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)) {
+									type = 0;
+									dataLen = sizeof(data);
+									if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
+										myDeviceInstanceId = instanceId;
+										subkeyIndex = -1; // break outer loop
+									}
+								}
+							}
+						}
+					}
 				}
-			}	break;
+				break;
+		}
+	}
+
+	// If there is no device, try to create one
+	if (myDeviceInstanceId.length() == 0) {
+		// Execute devcon to install an instance of the Microsoft Loopback Adapter
+#ifdef _WIN64
+		std::string devcon(_r->homePath + "\\devcon64.exe");
+#else
+		BOOL f64 = FALSE;
+		std::string devcon(_r->homePath + ((IsWow64Process(GetCurrentProcess(),&f64) == TRUE) ? "\\devcon64.exe" : "\\devcon32.exe"));
+#endif
+		char windir[4096];
+		windir[0] = '\0';
+		GetWindowsDirectoryA(windir,sizeof(windir));
+		STARTUPINFOA startupInfo;
+		startupInfo.cb = sizeof(startupInfo);
+		PROCESS_INFORMATION processInfo;
+		memset(&startupInfo,0,sizeof(STARTUPINFOA));
+		memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
+		if (!CreateProcessA(NULL,(LPSTR)(devcon + " install " + windir + "\\inf\\netloop.inf *msloop").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);
+		}
+		WaitForSingleObject(processInfo.hProcess,INFINITE);
+		CloseHandle(processInfo.hProcess);
+		CloseHandle(processInfo.hThread);
+
+		// Scan for that new instance by looking for adapters of type
+		// *msloop that we did not already see on the first scan.
+		for(DWORD subkeyIndex=0;subkeyIndex!=-1;) {
+			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 (!strcmpi(data,"*msloop")) {
+							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,strlen(tag)+1);
+									myDeviceInstanceId.assign(data,dataLen);
+									subkeyIndex = -1; // break outer loop
+								}
+							}
+						}
+					}
+					break;
+			}
 		}
 	}
 
 	RegCloseKey(nwAdapters);	
+
+	if (myDeviceInstanceId.length() == 0)
+		throw std::runtime_error("unable to create new loopback adapter for tap");
 }
 
 EthernetTap::~EthernetTap()

+ 15 - 0
selftest.cpp

@@ -29,11 +29,14 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+
+#include <stdexcept>
 #include <iostream>
 #include <string>
 #include <vector>
 
 #include "node/Constants.hpp"
+#include "node/RuntimeEnvironment.hpp"
 #include "node/InetAddress.hpp"
 #include "node/EllipticCurveKey.hpp"
 #include "node/EllipticCurveKeyPair.hpp"
@@ -48,6 +51,7 @@
 #include "node/NodeConfig.hpp"
 #include "node/Dictionary.hpp"
 #include "node/RateLimiter.hpp"
+#include "node/EthernetTap.hpp"
 
 #include <openssl/rand.h>
 
@@ -404,6 +408,16 @@ int _tmain(int argc, _TCHAR* argv[])
 int main(int argc,char **argv)
 #endif
 {
+	try {
+		RuntimeEnvironment renv;
+		renv.homePath = "C:";
+		EthernetTap tap(&renv,"test12345",MAC(),2800,NULL,NULL);
+		return 0;
+	} catch (std::exception &exc) {
+		std::cout << exc.what() << std::endl;
+		return 0;
+	}
+/*
 	int r = 0;
 
 	_initLibCrypto();
@@ -419,4 +433,5 @@ int main(int argc,char **argv)
 		std::cout << std::endl << "SOMETHING FAILED!" << std::endl;
 
 	return r;
+*/
 }