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
This commit is contained in:
Srivats P 2020-02-12 18:14:48 +05:30
parent 018a8490cf
commit db66d7c5ea
6 changed files with 105 additions and 13 deletions

View File

@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include "params.h"
#include "pcapextra.h"
#include <unistd.h>
@ -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:

View File

@ -24,7 +24,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
/* 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<LPBYTE>(&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;

View File

@ -23,7 +23,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include <pcap.h>
#include <QtGlobal>
#ifndef Q_OS_WIN32
#ifdef Q_OS_WIN32
const char* pcapServiceStatus(const wchar_t *name);
#else // non-windows
#define PCAP_OPENFLAG_PROMISCUOUS 1

View File

@ -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)

View File

@ -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)

View File

@ -26,10 +26,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#ifdef Q_OS_WIN32
#include <ntddndis.h>
#include <ws2ipdef.h>
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()