From bbbc032959bc63e3f575f2fc45fe0054fb83d8f3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sun, 25 Aug 2013 18:18:02 -0400 Subject: [PATCH] Tap works! At least in isolation. Time to create the Windows executable and the Windows service to run it and handle auto-update. --- .gitignore | 2 + node/EthernetTap.cpp | 117 ++++++++++++++----- node/EthernetTap.hpp | 14 ++- selftest.cpp | 2 +- vsprojects/SelfTest/SelfTest.vcxproj | 1 + vsprojects/SelfTest/SelfTest.vcxproj.filters | 7 +- 6 files changed, 110 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 71053b0ed..fba7c321b 100755 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ mac-tap/tuntap/tap.kext *.opensdf *.user *.cache + +/vsprojects/SelfTest/SelfTest.aps diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp index 09af71791..48e93a34f 100644 --- a/node/EthernetTap.cpp +++ b/node/EthernetTap.cpp @@ -692,6 +692,9 @@ void EthernetTap::threadMain() #include #include #include +#include + +#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 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"); - //Thread::start(this); + 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"); + + 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 &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 diff --git a/node/EthernetTap.hpp b/node/EthernetTap.hpp index 69e5eafa9..cff0953be 100644 --- a/node/EthernetTap.hpp +++ b/node/EthernetTap.hpp @@ -49,6 +49,11 @@ #include "Buffer.hpp" #include "Array.hpp" +#ifdef __WINDOWS__ +#include +#include +#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,unsigned int > > _injectPending; Mutex _injectPending_m; - Condition _injectPending_c; + volatile bool _run; #endif }; diff --git a/selftest.cpp b/selftest.cpp index 836cee9a4..4927deac0 100644 --- a/selftest.cpp +++ b/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) { diff --git a/vsprojects/SelfTest/SelfTest.vcxproj b/vsprojects/SelfTest/SelfTest.vcxproj index 5189da462..0847e783e 100644 --- a/vsprojects/SelfTest/SelfTest.vcxproj +++ b/vsprojects/SelfTest/SelfTest.vcxproj @@ -125,6 +125,7 @@ + diff --git a/vsprojects/SelfTest/SelfTest.vcxproj.filters b/vsprojects/SelfTest/SelfTest.vcxproj.filters index 3704863eb..fa8c8331c 100644 --- a/vsprojects/SelfTest/SelfTest.vcxproj.filters +++ b/vsprojects/SelfTest/SelfTest.vcxproj.filters @@ -9,10 +9,6 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - @@ -144,6 +140,9 @@ Header Files + + Header Files +