diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/EthernetTap.cpp | 208 | ||||
-rw-r--r-- | node/EthernetTap.hpp | 19 |
2 files changed, 32 insertions, 195 deletions
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp index d9a66b3e..9e07d160 100644 --- a/node/EthernetTap.cpp +++ b/node/EthernetTap.cpp @@ -677,10 +677,14 @@ void EthernetTap::threadMain() #endif // __UNIX_LIKE__ ////////////////////////////////////////////////////// -#ifdef __WINDOWS__ +////////////////////////////////////////////////////////////////////////////// -#include <queue> +#ifdef __WINDOWS__ /////////////////////////////////////////////////////////// +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> #include <WinSock2.h> #include <Windows.h> #include <iphlpapi.h> @@ -691,165 +695,6 @@ void EthernetTap::threadMain() namespace ZeroTier { -/* Background thread that handles I/O to/from all running - * EthernetTap instances using WinPcap -- this must be - * managed from a single thread because of the need to - * "reboot" npf every time a new interface is added. */ -class _WinEthernetTapPcapIOThread -{ -public: - _WinEthernetTapPcapIOThread() - { - scManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); - if (scManager == NULL) - fprintf(stderr,"ZeroTier One: WARNING: unable to OpenSCManager(), tap will have issues with new devices!\r\n"); - updateSem = CreateSemaphore(NULL,0,1,NULL); // binary - run = true; - needReload = false; - thread = Thread::start(this); - } - - ~_WinEthernetTapPcapIOThread() - { - run = false; - needReload = false; - ReleaseSemaphore(updateSem,1,NULL); - Thread::join(thread); - CloseHandle(updateSem); - if (scManager != NULL) - CloseServiceHandle(scManager); - } - - void threadMain() - throw() - { - HANDLE *objects = new HANDLE[1]; - objects[0] = updateSem; - DWORD numObjects = 1; - - for(;;) { - if (!run) { - delete [] objects; - return; - } - - printf("waiting on: %d\r\n",(int)numObjects); - WaitForMultipleObjects(numObjects,objects,FALSE,INFINITE); - - { - Mutex::Lock _l(taps_m); - - for(std::list<EthernetTap *>::iterator tapptr(taps.begin());tapptr!=taps.end();++tapptr) { - EthernetTap *tap = *tapptr; - if (tap->_pcap) { - { - Mutex::Lock _l2(tap->_injectPending_m); - while (!tap->_injectPending.empty()) { - pcap_sendpacket(tap->_pcap,(const u_char *)(tap->_injectPending.front().first.data),tap->_injectPending.front().second); - tap->_injectPending.pop(); - } - } - printf("dispatch: %s\r\n",tap->_myDeviceInstanceId.c_str()); - pcap_dispatch(tap->_pcap,-1,&EthernetTap::_pcapHandler,(u_char *)tap); - } - } - - if (needReload) { - // Close all taps and restart WinPcap driver to scan for possible new - // interfaces... yuck. This is done because WinPcap does not support - // hot plug, so if we've added a new loopback adapter it won't show - // up without this full system refresh. - needReload = false; - - for(std::list<EthernetTap *>::iterator tapptr(taps.begin());tapptr!=taps.end();++tapptr) { - if ((*tapptr)->_pcap) { - pcap_close((*tapptr)->_pcap); - (*tapptr)->_pcap = (pcap_t *)0; - } - } - - if (scManager != NULL) { - Thread::sleep(250); - SC_HANDLE npfService = OpenServiceA(scManager,"npf",SERVICE_ALL_ACCESS); - if (npfService != NULL) { - SERVICE_STATUS sstatus; - memset(&sstatus,0,sizeof(SERVICE_STATUS)); - ControlService(npfService,SERVICE_CONTROL_STOP,&sstatus); - printf("service restart\r\n"); - CloseServiceHandle(npfService); - } - Thread::sleep(250); - } - - delete [] objects; - objects = new HANDLE[taps.size() + 1]; - objects[0] = updateSem; - numObjects = 1; - - pcap_if_t *alldevs; - char pcaperrbuf[PCAP_ERRBUF_SIZE+1]; - if (pcap_findalldevs(&alldevs,pcaperrbuf) != -1) { - for(std::list<EthernetTap *>::iterator tapptr(taps.begin());tapptr!=taps.end();++tapptr) { - EthernetTap *tap = *tapptr; - pcap_if_t *mydev = (pcap_if_t *)0; - for(mydev=alldevs;(mydev);mydev=mydev->next) { - if (strstr(mydev->name,tap->_myDeviceInstanceId.c_str())) - break; - } - if (mydev) { - tap->_pcap = pcap_open_live(mydev->name,65535,1,0,pcaperrbuf); - pcap_setnonblock(tap->_pcap,1,pcaperrbuf); - if (tap->_pcap) { - printf("pcap opened: %s\r\n",mydev->name); - objects[numObjects++] = pcap_getevent(tap->_pcap); - } - } else { - tap->_pcap = (pcap_t *)0; - } - } - pcap_freealldevs(alldevs); - } - } - } - - if (!run) { - delete [] objects; - return; - } - } - } - - inline void addTap(EthernetTap *t) - { - Mutex::Lock _l(taps_m); - taps.push_back(t); - needReload = true; - ReleaseSemaphore(updateSem,1,NULL); - } - - inline void removeTap(EthernetTap *t) - { - Mutex::Lock _l(taps_m); - for(std::list<EthernetTap *>::iterator tapptr(taps.begin());tapptr!=taps.end();++tapptr) { - if (*tapptr == t) { - taps.erase(tapptr); - break; - } - } - needReload = true; - ReleaseSemaphore(updateSem,1,NULL); - } - - std::list<EthernetTap *> taps; - Mutex taps_m; - SC_HANDLE scManager; - HANDLE updateSem; - volatile bool run; - volatile bool needReload; - Thread thread; -}; - -static _WinEthernetTapPcapIOThread _pcapIoThread; static Mutex _systemTapInitLock; EthernetTap::EthernetTap( @@ -864,20 +709,20 @@ EthernetTap::EthernetTap( _mtu(mtu), _r(renv), _handler(handler), - _arg(arg), - _pcap((pcap_t *)0) + _arg(arg) { - char subkeyName[1024]; - char subkeyClass[1024]; - char data[1024]; + char subkeyName[4096]; + char subkeyClass[4096]; + char data[4096]; - Mutex::Lock _l(_systemTapInitLock); // only do one at a time, process-wide + Mutex::Lock _l(_systemTapInitLock); // only init one tap at a time, process-wide 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; // Enumerate all Microsoft Loopback Adapter instances and look for one // that matches our tag. @@ -913,6 +758,7 @@ EthernetTap::EthernetTap( 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 } } @@ -971,6 +817,7 @@ EthernetTap::EthernetTap( if (existingDeviceInstances.count(std::string(data,dataLen)) == 0) { RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,strlen(tag)+1); _myDeviceInstanceId.assign(data,dataLen); + mySubkeyName = subkeyName; subkeyIndex = -1; // break outer loop } } @@ -981,20 +828,27 @@ 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); + 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"); - // pcap is opened and managed by the pcap I/O thread - _pcapIoThread.addTap(this); + //Thread::start(this); } EthernetTap::~EthernetTap() { - _pcapIoThread.removeTap(this); - if (_pcap) - pcap_close(_pcap); } void EthernetTap::whack() @@ -1026,7 +880,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(_pcapIoThread.updateSem,1,NULL); } std::string EthernetTap::deviceName() const @@ -1040,13 +894,11 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups) return false; } -void EthernetTap::_pcapHandler(u_char *user,const struct pcap_pkthdr *pkt_header,const u_char *pkt_data) +void EthernetTap::threadMain() + throw() { - printf("got packet: %d\r\n",(int)pkt_header->len); - if (pkt_header->len > 14) - ((EthernetTap *)user)->_handler(((EthernetTap *)user)->_arg,MAC(pkt_data + 6),MAC(pkt_data),Utils::ntoh(*((const uint16_t *)(pkt_data + 12))),Buffer<4096>(pkt_data + 14,pkt_header->len - 14)); } } // namespace ZeroTier -#endif // __WINDOWS__ +#endif // __WINDOWS__ //////////////////////////////////////////////////////// diff --git a/node/EthernetTap.hpp b/node/EthernetTap.hpp index a409b412..69e5eafa 100644 --- a/node/EthernetTap.hpp +++ b/node/EthernetTap.hpp @@ -43,33 +43,21 @@ #include "InetAddress.hpp" #include "MAC.hpp" #include "Mutex.hpp" +#include "Condition.hpp" #include "MulticastGroup.hpp" #include "Thread.hpp" #include "Buffer.hpp" #include "Array.hpp" -#ifdef __WINDOWS__ -#include <pcap/pcap.h> -#include <pcap/bpf.h> -#include <Win32-Extensions.h> -#endif - namespace ZeroTier { class RuntimeEnvironment; -#ifdef __WINDOWS__ -class _WinEthernetTapPcapIOThread; -#endif /** * System ethernet tap device */ class EthernetTap { -#ifdef __WINDOWS__ - friend class _WinEthernetTapPcapIOThread; -#endif - public: /** * Construct a new TAP device @@ -189,13 +177,11 @@ public: */ bool updateMulticastGroups(std::set<MulticastGroup> &groups); -#ifdef __UNIX_LIKE__ /** * Thread main method; do not call elsewhere */ void threadMain() throw(); -#endif private: const MAC _mac; @@ -217,11 +203,10 @@ private: #endif #ifdef __WINDOWS__ - pcap_t *_pcap; std::string _myDeviceInstanceId; std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending; Mutex _injectPending_m; - static void _pcapHandler(u_char *user,const struct pcap_pkthdr *pkt_header,const u_char *pkt_data); + Condition _injectPending_c; #endif }; |