From db66d7c5ea9ca0eba91b9c21988f31b5d729d247 Mon Sep 17 00:00:00 2001 From: Srivats P Date: Wed, 12 Feb 2020 18:14:48 +0530 Subject: [PATCH] Add support for npcap as winpcap replacement For now both winpcap and npcap are supported with the latter being experimentally supported till we get some feedback from users and confirm that things are all working fine with npcap. OID for link state has been changed to one that supports both. To check which is being used, run 'drone -v'. Fixes #236 --- server/params.cpp | 6 +++++ server/pcapextra.cpp | 61 +++++++++++++++++++++++++++++++++++++++++- server/pcapextra.h | 6 ++++- server/pcapport.cpp | 8 +++++- server/portmanager.cpp | 5 ++++ server/winpcapport.cpp | 32 +++++++++++++++------- 6 files changed, 105 insertions(+), 13 deletions(-) diff --git a/server/params.cpp b/server/params.cpp index 11541cb..2337bc3 100644 --- a/server/params.cpp +++ b/server/params.cpp @@ -18,6 +18,7 @@ along with this program. If not, see */ #include "params.h" +#include "pcapextra.h" #include @@ -46,6 +47,11 @@ int Params::parseCommandLine(int argc, char* argv[]) break; case 'v': printf("Ostinato Drone %s rev %s\n", version, revision); + printf("PCAP Lib: %s\n", pcap_lib_version()); +#ifdef Q_OS_WIN32 + printf("Service npf status %s\n", pcapServiceStatus(L"npf")); + printf("Service npcap status %s\n", pcapServiceStatus(L"npcap")); +#endif exit(0); case 'h': default: diff --git a/server/pcapextra.cpp b/server/pcapextra.cpp index 4acbda9..fc459a2 100644 --- a/server/pcapextra.cpp +++ b/server/pcapextra.cpp @@ -24,7 +24,66 @@ along with this program. If not, see /* NOTE: All code borrowed from WinPcap */ -#ifndef Q_OS_WIN32 +#ifdef Q_OS_WIN32 + +const char* pcapServiceStatus(const wchar_t* name) +{ + SC_HANDLE scm, svc; + SERVICE_STATUS_PROCESS svcStatus; + DWORD size; + BOOL result; + const char *status = "unknown"; + + scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE); + if(!scm) + goto _exit; + + svc = OpenService(scm, name, SERVICE_QUERY_STATUS); + if(!svc) + goto _close_exit; + + result = QueryServiceStatusEx(svc, SC_STATUS_PROCESS_INFO, + reinterpret_cast(&svcStatus), sizeof(svcStatus), + &size); + + if(result == 0) + goto _close_exit; + + switch(svcStatus.dwCurrentState) { + case SERVICE_CONTINUE_PENDING: + status = "continue pending"; + break; + case SERVICE_PAUSE_PENDING: + status = "pause pending"; + break; + case SERVICE_PAUSED: + status = "paused"; + break; + case SERVICE_RUNNING: + status = "running"; + break; + case SERVICE_START_PENDING: + status = "start pending"; + break; + case SERVICE_STOP_PENDING: + status = "stop pending"; + break; + case SERVICE_STOPPED: + status = "stopped"; + break; + } + +_close_exit: + if (svc) + CloseServiceHandle(svc); + if (scm) + CloseServiceHandle(scm); +_exit: + return status; +} + +#else // non-Windows + pcap_send_queue* pcap_sendqueue_alloc (u_int memsize) { pcap_send_queue *tqueue; diff --git a/server/pcapextra.h b/server/pcapextra.h index 415fe3e..6d6168e 100644 --- a/server/pcapextra.h +++ b/server/pcapextra.h @@ -23,7 +23,11 @@ along with this program. If not, see #include #include -#ifndef Q_OS_WIN32 +#ifdef Q_OS_WIN32 + +const char* pcapServiceStatus(const wchar_t *name); + +#else // non-windows #define PCAP_OPENFLAG_PROMISCUOUS 1 diff --git a/server/pcapport.cpp b/server/pcapport.cpp index fbb9c84..136813a 100644 --- a/server/pcapport.cpp +++ b/server/pcapport.cpp @@ -342,7 +342,8 @@ void PcapPort::PortMonitor::run() void PcapPort::PortMonitor::stop() { stop_ = true; - pcap_breakloop(handle()); + if (handle()) + pcap_breakloop(handle()); } /* @@ -404,6 +405,11 @@ _retry: } dumpHandle_ = pcap_dump_open(handle_, qPrintable(capFile_.fileName())); + if (!dumpHandle_) { + qDebug("failed to start capture: %s", pcap_geterr(handle_)); + goto _exit; + } + PcapSession::preRun(); state_ = kRunning; while (1) diff --git a/server/portmanager.cpp b/server/portmanager.cpp index cca4e90..0ca37de 100644 --- a/server/portmanager.cpp +++ b/server/portmanager.cpp @@ -51,6 +51,11 @@ PortManager::PortManager() AbstractPort::Accuracy txRateAccuracy; qDebug("PCAP Lib: %s", pcap_lib_version()); +#ifdef Q_OS_WIN32 + qDebug("Service npf status %s\n", pcapServiceStatus(L"npf")); + qDebug("Service npcap status %s\n", pcapServiceStatus(L"npcap")); +#endif + qDebug("Retrieving the device list from the local machine\n"); #if defined(Q_OS_WIN32) diff --git a/server/winpcapport.cpp b/server/winpcapport.cpp index 1f3b2b3..39ade84 100644 --- a/server/winpcapport.cpp +++ b/server/winpcapport.cpp @@ -26,10 +26,10 @@ along with this program. If not, see #ifdef Q_OS_WIN32 +#include #include PIP_ADAPTER_ADDRESSES WinPcapPort::adapterList_ = NULL; -const uint OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114; WinPcapPort::WinPcapPort(int id, const char *device, const char *description) : PcapPort(id, device) @@ -53,7 +53,7 @@ WinPcapPort::WinPcapPort(int id, const char *device, const char *description) if (!adapter_) qFatal("Unable to open adapter %s", device); linkStateOid_ = (PPACKET_OID_DATA) malloc(sizeof(PACKET_OID_DATA) + - sizeof(uint)); + sizeof(NDIS_LINK_STATE)); if (!linkStateOid_) qFatal("failed to alloc oidData"); @@ -67,27 +67,39 @@ WinPcapPort::~WinPcapPort() OstProto::LinkState WinPcapPort::linkState() { - memset(linkStateOid_, 0, sizeof(PACKET_OID_DATA) + sizeof(uint)); + memset(linkStateOid_, 0, sizeof(PACKET_OID_DATA) + sizeof(NDIS_LINK_STATE)); - linkStateOid_->Oid = OID_GEN_MEDIA_CONNECT_STATUS; - linkStateOid_->Length = sizeof(uint); + linkStateOid_->Oid = OID_GEN_LINK_STATE; + linkStateOid_->Length = sizeof(NDIS_LINK_STATE); + // TODO: migrate to the npcap-only pcap_oid_get_request() when Ostinato + // stops supporting WinPcap if (PacketRequest(adapter_, 0, linkStateOid_)) { uint state; - if (linkStateOid_->Length == sizeof(state)) + if (linkStateOid_->Length == sizeof(NDIS_LINK_STATE)) { - memcpy((void*)&state, (void*)linkStateOid_->Data, - linkStateOid_->Length); + memcpy((void*)&state, + (void*)(linkStateOid_->Data+sizeof(NDIS_OBJECT_HEADER)), + sizeof(state)); + //qDebug("%s: state = %d", data_.description().c_str(), state); if (state == 0) - linkState_ = OstProto::LinkStateUp; + linkState_ = OstProto::LinkStateUnknown; else if (state == 1) + linkState_ = OstProto::LinkStateUp; + else if (state == 2) linkState_ = OstProto::LinkStateDown; } + else { + //qDebug("%s: link state fail", data_.description().c_str()); + } + } + else { + //qDebug("%s: link state request fail", data_.description().c_str()); } - return linkState_; + return linkState_; } bool WinPcapPort::hasExclusiveControl()