Implement set/clear promisc for Windows ports
With windows if stats, we need to put the ports explicitly in promisc mode; with internal-stats this happens implicitly when we create monitorRx/Tx
This commit is contained in:
parent
6d312764e8
commit
e5375247a9
@ -100,6 +100,10 @@ WinPcapPort::~WinPcapPort()
|
||||
delete monitor_;
|
||||
monitor_ = nullptr;
|
||||
}
|
||||
|
||||
// npcap will already clear promisc at exit, but we still do explicitly
|
||||
if (clearPromiscAtExit_)
|
||||
clearPromisc();
|
||||
}
|
||||
|
||||
void WinPcapPort::init()
|
||||
@ -110,10 +114,8 @@ void WinPcapPort::init()
|
||||
monitor_->waitForSetupFinished();
|
||||
}
|
||||
|
||||
#if 0 // TODO
|
||||
if (!isPromisc_)
|
||||
addNote("Non Promiscuous Mode");
|
||||
#endif
|
||||
|
||||
if (monitor_)
|
||||
AbstractPort::init();
|
||||
@ -203,6 +205,106 @@ bool WinPcapPort::setExclusiveControl(bool exclusive)
|
||||
return (exclusive == hasExclusiveControl());
|
||||
}
|
||||
|
||||
bool WinPcapPort::setPromisc()
|
||||
{
|
||||
if (!promiscHandle_) {
|
||||
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
||||
|
||||
promiscHandle_ = pcap_create(name(), errbuf);
|
||||
if (!promiscHandle_) {
|
||||
qDebug("%s: Error opening port to set promisc mode: %s",
|
||||
name(), errbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = pcap_activate(promiscHandle_);
|
||||
if (status) {
|
||||
qDebug("%s: Error activating port to set promisc mode: %s",
|
||||
name(), pcap_statustostr(status));
|
||||
pcap_close(promiscHandle_);
|
||||
promiscHandle_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint data = NDIS_PACKET_TYPE_PROMISCUOUS;
|
||||
uint size = sizeof(data);
|
||||
int status = pcap_oid_set_request(promiscHandle_,
|
||||
OID_GEN_CURRENT_PACKET_FILTER, &data, &size);
|
||||
if (status) {
|
||||
qDebug("%s: Unable to set promisc mode: %s",
|
||||
name(), pcap_statustostr(status));
|
||||
pcap_close(promiscHandle_);
|
||||
promiscHandle_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
isPromisc_ = clearPromiscAtExit_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinPcapPort::clearPromisc()
|
||||
{
|
||||
if (!promiscHandle_) {
|
||||
qDebug("%s: No promisc handle to clear promisc mode", name());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint data = NDIS_PACKET_TYPE_ALL_LOCAL
|
||||
| NDIS_PACKET_TYPE_DIRECTED
|
||||
| NDIS_PACKET_TYPE_BROADCAST
|
||||
| NDIS_PACKET_TYPE_MULTICAST;
|
||||
uint size = sizeof(data);
|
||||
int status = pcap_oid_set_request(promiscHandle_,
|
||||
OID_GEN_CURRENT_PACKET_FILTER, &data, &size);
|
||||
if (status) {
|
||||
qDebug("%s: Unable to clear promisc mode: %s",
|
||||
name(), pcap_statustostr(status));
|
||||
pcap_close(promiscHandle_);
|
||||
promiscHandle_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
isPromisc_ = clearPromiscAtExit_ = false;
|
||||
pcap_close(promiscHandle_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// The above set/clearPromisc implementation using standard npcap APIs.
|
||||
// The below implementation uses packet.dll APIs directly and may be
|
||||
// slightly more performant? To be verified!
|
||||
bool WinPcapPort::setPromiscAlt(bool promisc)
|
||||
{
|
||||
bool ret = false;
|
||||
uint data = promisc ? NDIS_PACKET_TYPE_PROMISCUOUS :
|
||||
(NDIS_PACKET_TYPE_ALL_LOCAL
|
||||
| NDIS_PACKET_TYPE_DIRECTED
|
||||
| NDIS_PACKET_TYPE_BROADCAST
|
||||
| NDIS_PACKET_TYPE_MULTICAST);
|
||||
|
||||
PPACKET_OID_DATA oid = (PPACKET_OID_DATA) malloc(sizeof(PACKET_OID_DATA) +
|
||||
sizeof(data));
|
||||
if (oid) {
|
||||
memset(oid, 0, sizeof(PACKET_OID_DATA) + sizeof(data));
|
||||
|
||||
oid->Oid = OID_GEN_CURRENT_PACKET_FILTER;
|
||||
oid->Length = sizeof(data);
|
||||
memcpy(oid->Data, &data, sizeof(data));
|
||||
if (PacketRequest(adapter_, true, oid)) {
|
||||
isPromisc_ = clearPromiscAtExit_ = promisc;
|
||||
ret = true;
|
||||
} else
|
||||
qDebug("%s: Unable to %s promisc mode", name(),
|
||||
promisc ? "set" : "clear");
|
||||
} else
|
||||
qDebug("%s: failed to alloc promisc oid", name());
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
WinPcapPort::PortMonitor::PortMonitor(const char *device, Direction direction,
|
||||
AbstractPort::PortStats *stats)
|
||||
: PcapPort::PortMonitor(device, direction, stats)
|
||||
@ -330,6 +432,7 @@ void WinPcapPort::StatsMonitor::run()
|
||||
if (port->luid_.Value) {
|
||||
portList.append(
|
||||
{port->luid_, &(port->stats_), &(port->linkState_), false});
|
||||
port->setPromisc();
|
||||
} else {
|
||||
qWarning("No LUID for port %s - stats will not be available",
|
||||
port->name());
|
||||
|
@ -26,6 +26,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "pcapport.h"
|
||||
|
||||
// BPF_MAJOR_VERSION definition is needed to prevent redefinition of
|
||||
// bpf_program, bpf_insn etc. - this was not needed in WinPcap as it
|
||||
// defines it, but npcap doesn't
|
||||
#define BPF_MAJOR_VERSION 1
|
||||
#include <packet32.h>
|
||||
|
||||
#include <ws2ipdef.h>
|
||||
@ -70,6 +74,10 @@ protected:
|
||||
bool setupDone_;
|
||||
};
|
||||
|
||||
bool isPromisc_{false};
|
||||
bool clearPromiscAtExit_{false};
|
||||
pcap_t *promiscHandle_{nullptr};
|
||||
|
||||
static QList<WinPcapPort*> allPorts_;
|
||||
static StatsMonitor *monitor_; // rx/tx stats for ALL ports
|
||||
static bool internalPortStats_;
|
||||
@ -77,6 +85,9 @@ protected:
|
||||
private:
|
||||
void populateInterfaceInfo();
|
||||
|
||||
bool setPromisc();
|
||||
bool clearPromisc();
|
||||
|
||||
LPADAPTER adapter_;
|
||||
NET_LUID luid_;
|
||||
PPACKET_OID_DATA linkStateOid_ ;
|
||||
|
Loading…
Reference in New Issue
Block a user