Tap driver basically builds in VS2012... fork of tap-windows from OpenVPN (compatible license).
This commit is contained in:
parent
b6248c7cb7
commit
e2effbd1ce
29 changed files with 6762 additions and 200 deletions
|
@ -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__ ////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue