Browse Source

Tap works! At least in isolation. Time to create the Windows executable and the Windows service to run it and handle auto-update.

Adam Ierymenko 12 years ago
parent
commit
bbbc032959

+ 2 - 0
.gitignore

@@ -18,3 +18,5 @@ mac-tap/tuntap/tap.kext
 *.opensdf
 *.user
 *.cache
+
+/vsprojects/SelfTest/SelfTest.aps

+ 91 - 26
node/EthernetTap.cpp

@@ -692,6 +692,9 @@ void EthernetTap::threadMain()
 #include <WS2tcpip.h>
 #include <tchar.h>
 #include <winreg.h>
+#include <wchar.h>
+
+#include "..\vsprojects\TapDriver\tap-windows.h"
 
 namespace ZeroTier {
 
@@ -709,7 +712,10 @@ EthernetTap::EthernetTap(
 	_mtu(mtu),
 	_r(renv),
 	_handler(handler),
-	_arg(arg)
+	_arg(arg),
+	_tap(INVALID_HANDLE_VALUE),
+	_injectSemaphore(INVALID_HANDLE_VALUE),
+	_run(true)
 {
 	char subkeyName[4096];
 	char subkeyClass[4096];
@@ -724,8 +730,7 @@ EthernetTap::EthernetTap(
 	std::set<std::string> existingDeviceInstances;
 	std::string mySubkeyName;
 
-	// Enumerate all Microsoft Loopback Adapter instances and look for one
-	// that matches our tag.
+	// Enumerate tap instances and look for one tagged with this tag
 	for(DWORD subkeyIndex=0;subkeyIndex!=-1;) {
 		DWORD type;
 		DWORD dataLen;
@@ -739,7 +744,7 @@ EthernetTap::EthernetTap(
 				dataLen = sizeof(data);
 				if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
 					data[dataLen] = '\0';
-					if (!strcmpi(data,"*msloop")) {
+					if (!strnicmp(data,"zttap",5)) {
 						std::string instanceId;
 						type = 0;
 						dataLen = sizeof(data);
@@ -754,13 +759,9 @@ EthernetTap::EthernetTap(
 							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;
-										mySubkeyName = subkeyName;
-										subkeyIndex = -1; // break outer loop
-									}
+									_myDeviceInstanceId = instanceId;
+									mySubkeyName = subkeyName;
+									subkeyIndex = -1; // break outer loop
 								}
 							}
 						}
@@ -779,24 +780,21 @@ EthernetTap::EthernetTap(
 		BOOL f64 = FALSE;
 		const char *devcon = ((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)(std::string("\"") + _r->homePath + devcon + "\" install " + windir + "\\inf\\netloop.inf *msloop").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
+		if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _r->homePath + devcon + "\" install \"" + _r->homePath + "\\ztTap100.inf\" ztTap100").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.
+ 
+		// Scan for the new instance by simply looking for taps that weren't
+		// there originally.
 		for(DWORD subkeyIndex=0;subkeyIndex!=-1;) {
 			DWORD type;
 			DWORD dataLen;
@@ -810,7 +808,7 @@ EthernetTap::EthernetTap(
 					dataLen = sizeof(data);
 					if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
 						data[dataLen] = '\0';
-						if (!strcmpi(data,"*msloop")) {
+						if (!strnicmp(data,"zttap",5)) {
 							type = 0;
 							dataLen = sizeof(data);
 							if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
@@ -830,26 +828,48 @@ EthernetTap::EthernetTap(
 
 	if (_myDeviceInstanceId.length() > 0) {
 		char tmps[4096];
-		sprintf_s(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]);
-		RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,strlen(tmps)+1);
-		RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MAC",REG_SZ,tmps,strlen(tmps)+1);
+		unsigned int tmpsl = sprintf_s(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;
+		RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,tmpsl);
+		RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MAC",REG_SZ,tmps,tmpsl);
 		DWORD tmp = mtu;
 		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));
-		RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"DriverDesc",REG_SZ,"ZeroTier One Virtual LAN",25);
 	}
 
 	RegCloseKey(nwAdapters);	
 
 	if (_myDeviceInstanceId.length() == 0)
-		throw std::runtime_error("unable to create new loopback adapter for tap");
+		throw std::runtime_error("unable to create new tap adapter");
+
+	wchar_t tapPath[4096];
+	swprintf_s(tapPath,L"\\\\.\\Global\\%S.tap",_myDeviceInstanceId.c_str());
+	_tap = CreateFile(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL);
+	if (_tap == INVALID_HANDLE_VALUE)
+		throw std::runtime_error("unable to open tap in \\\\.\\Global\\ namespace");
 
-	//Thread::start(this);
+	uint32_t tmpi = 1;
+	DWORD bytesReturned = 0;
+	DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL);
+
+	memset(&_tapOvlRead,0,sizeof(_tapOvlRead));
+	_tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
+	memset(&_tapOvlWrite,0,sizeof(_tapOvlWrite));
+	_tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
+
+	_injectSemaphore = CreateSemaphore(NULL,0,1,NULL);
+	_thread = Thread::start(this);
 }
 
 EthernetTap::~EthernetTap()
 {
+	_run = false;
+	ReleaseSemaphore(_injectSemaphore,1,NULL);
+	Thread::join(_thread);
+	CloseHandle(_tap);
+	CloseHandle(_tapOvlRead.hEvent);
+	CloseHandle(_tapOvlWrite.hEvent);
+	CloseHandle(_injectSemaphore);
 }
 
 void EthernetTap::whack()
@@ -881,7 +901,7 @@ void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const
 		memcpy(d + 14,data,len);
 	}
 
-	//ReleaseSemaphore(_pcapIoThread.updateSem,1,NULL);
+	ReleaseSemaphore(_injectSemaphore,1,NULL);
 }
 
 std::string EthernetTap::deviceName() const
@@ -898,6 +918,51 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
 void EthernetTap::threadMain()
 	throw()
 {
+	HANDLE wait4[3];
+	wait4[0] = _injectSemaphore;
+	wait4[1] = _tapOvlRead.hEvent;
+	wait4[2] = _tapOvlWrite.hEvent;
+
+	ReadFile(_tap,_tapReadBuf,sizeof(_tapReadBuf),NULL,&_tapOvlRead);
+	bool writeInProgress = false;
+
+	for(;;) {
+		if (!_run) break;
+		WaitForMultipleObjectsEx(3,wait4,FALSE,INFINITE,TRUE);
+		if (!_run) break;
+
+		if (HasOverlappedIoCompleted(&_tapOvlRead)) {
+			DWORD bytesRead = 0;
+			if (GetOverlappedResult(_tap,&_tapOvlRead,&bytesRead,FALSE)) {
+				if (bytesRead > 14) {
+					MAC to(_tapReadBuf);
+					MAC from(_tapReadBuf + 6);
+					unsigned int etherType = Utils::ntoh(*((const uint16_t *)(_tapReadBuf + 12)));
+					Buffer<4096> tmp(_tapReadBuf + 14,bytesRead - 14);
+					printf("GOT FRAME: %u bytes: %s\r\n",(unsigned int)bytesRead,Utils::hex(_tapReadBuf,bytesRead).c_str());
+					//_handler(_arg,from,to,etherType,tmp);
+				}
+			}
+			ReadFile(_tap,_tapReadBuf,sizeof(_tapReadBuf),NULL,&_tapOvlRead);
+		}
+
+		if (writeInProgress) {
+			if (HasOverlappedIoCompleted(&_tapOvlWrite)) {
+				writeInProgress = false;
+				_injectPending_m.lock();
+				_injectPending.pop();
+			} else continue; // still writing, so skip code below and wait
+		} else _injectPending_m.lock();
+
+		if (!_injectPending.empty()) {
+			WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&_tapOvlWrite);
+			writeInProgress = true;
+		}
+
+		_injectPending_m.unlock();
+	}
+
+	CancelIo(_tap);
 }
 
 } // namespace ZeroTier

+ 12 - 2
node/EthernetTap.hpp

@@ -49,6 +49,11 @@
 #include "Buffer.hpp"
 #include "Array.hpp"
 
+#ifdef __WINDOWS__
+#include <WinSock2.h>
+#include <Windows.h>
+#endif
+
 namespace ZeroTier {
 
 class RuntimeEnvironment;
@@ -195,18 +200,23 @@ private:
 	void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
 	void *_arg;
 
-#ifdef __UNIX_LIKE__
 	Thread _thread;
+
+#ifdef __UNIX_LIKE__
 	char _dev[16];
 	int _fd;
 	int _shutdownSignalPipe[2];
 #endif
 
 #ifdef __WINDOWS__
+	HANDLE _tap;
+	OVERLAPPED _tapOvlRead,_tapOvlWrite;
+	char _tapReadBuf[ZT_IF_MTU + 32];
+	HANDLE _injectSemaphore;
 	std::string _myDeviceInstanceId;
 	std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending;
 	Mutex _injectPending_m;
-	Condition _injectPending_c;
+	volatile bool _run;
 #endif
 };
 

+ 1 - 1
selftest.cpp

@@ -411,7 +411,7 @@ int main(int argc,char **argv)
 	///* For testing windows tap
 	try {
 		RuntimeEnvironment renv;
-		renv.homePath = "C:";
+		renv.homePath = "C:\\ProgramData\\ZeroTier\\One";
 		EthernetTap tap(&renv,"test12345",MAC(0x32),2800,NULL,NULL);
 		Thread::sleep(100000000);
 	} catch (std::exception &exc) {

+ 1 - 0
vsprojects/SelfTest/SelfTest.vcxproj

@@ -125,6 +125,7 @@
     <ClInclude Include="..\..\node\Topology.hpp" />
     <ClInclude Include="..\..\node\UdpSocket.hpp" />
     <ClInclude Include="..\..\node\Utils.hpp" />
+    <ClInclude Include="resource.h" />
     <ClInclude Include="targetver.h" />
   </ItemGroup>
   <ItemGroup>

+ 3 - 4
vsprojects/SelfTest/SelfTest.vcxproj.filters

@@ -9,10 +9,6 @@
       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
       <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
     </Filter>
-    <Filter Include="Resource Files">
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
-    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="targetver.h">
@@ -144,6 +140,9 @@
     <ClInclude Include="..\..\node\Utils.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="resource.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\node\Defaults.cpp">