af_packet: pre-commit fixes

This commit is contained in:
Tim Wojtulewicz 2025-08-17 21:33:37 -07:00
parent 709f876947
commit 62e27ee6f7
8 changed files with 362 additions and 413 deletions

View file

@ -1,4 +1,3 @@
cmake_minimum_required(VERSION 3.15 FATAL_ERROR) cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
project(ZeekPluginAF_Packet) project(ZeekPluginAF_Packet)

View file

@ -91,7 +91,7 @@ To use the AF_Packet plugin with `zeekctl`, the `custom` load balance method can
af_packet_fanout_mode=AF_Packet::FANOUT_HASH af_packet_fanout_mode=AF_Packet::FANOUT_HASH
af_packet_buffer_size=128*1024*1024 af_packet_buffer_size=128*1024*1024
If all interfaces using `lb_method=custom` should be configured for AF_Packet, the prefix can be globally definied by adding the following line to `zeekctl.conf`: If all interfaces using `lb_method=custom` should be configured for AF_Packet, the prefix can be globally defined by adding the following line to `zeekctl.conf`:
lb_custom.InterfacePrefix=af_packet:: lb_custom.InterfacePrefix=af_packet::

View file

@ -1,3 +1,5 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/zeek-config.h" #include "zeek/zeek-config.h"
// Starting with Zeek 6.0, zeek-config.h does not provide the // Starting with Zeek 6.0, zeek-config.h does not provide the
@ -9,7 +11,6 @@
#include "AF_Packet.h" #include "AF_Packet.h"
#include "RX_Ring.h" #include "RX_Ring.h"
#include "af_packet.bif.h" #include "af_packet.bif.h"
// CentOS 7 if_packet.h does not yet have this define, provide it // CentOS 7 if_packet.h does not yet have this define, provide it
@ -20,189 +21,169 @@
using namespace zeek::iosource::pktsrc; using namespace zeek::iosource::pktsrc;
AF_PacketSource::~AF_PacketSource() AF_PacketSource::~AF_PacketSource() { Close(); }
{
Close();
}
AF_PacketSource::AF_PacketSource(const std::string& path, bool is_live) AF_PacketSource::AF_PacketSource(const std::string& path, bool is_live) {
{
if ( ! is_live ) if ( ! is_live )
Error("AF_Packet source does not support offline input"); Error("AF_Packet source does not support offline input");
current_filter = -1; current_filter = -1;
props.path = path; props.path = path;
props.is_live = is_live; props.is_live = is_live;
socket_fd = -1; socket_fd = -1;
rx_ring = nullptr; rx_ring = nullptr;
checksum_mode = zeek::BifConst::AF_Packet::checksum_validation_mode->AsEnum(); checksum_mode = zeek::BifConst::AF_Packet::checksum_validation_mode->AsEnum();
} }
void AF_PacketSource::Open() void AF_PacketSource::Open() {
{ uint64_t buffer_size = zeek::BifConst::AF_Packet::buffer_size;
uint64_t buffer_size = zeek::BifConst::AF_Packet::buffer_size; uint64_t block_size = zeek::BifConst::AF_Packet::block_size;
uint64_t block_size = zeek::BifConst::AF_Packet::block_size; int block_timeout_msec = static_cast<int>(zeek::BifConst::AF_Packet::block_timeout * 1000.0);
int block_timeout_msec = static_cast<int>(zeek::BifConst::AF_Packet::block_timeout * 1000.0); int link_type = zeek::BifConst::AF_Packet::link_type;
int link_type = zeek::BifConst::AF_Packet::link_type;
bool enable_hw_timestamping = zeek::BifConst::AF_Packet::enable_hw_timestamping; bool enable_hw_timestamping = zeek::BifConst::AF_Packet::enable_hw_timestamping;
bool enable_fanout = zeek::BifConst::AF_Packet::enable_fanout; bool enable_fanout = zeek::BifConst::AF_Packet::enable_fanout;
bool enable_defrag = zeek::BifConst::AF_Packet::enable_defrag; bool enable_defrag = zeek::BifConst::AF_Packet::enable_defrag;
socket_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); socket_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if ( socket_fd < 0 ) if ( socket_fd < 0 ) {
{
Error(errno ? strerror(errno) : "unable to create socket"); Error(errno ? strerror(errno) : "unable to create socket");
return; return;
} }
auto info = GetInterfaceInfo(props.path); auto info = GetInterfaceInfo(props.path);
if ( ! info.Valid() ) if ( ! info.Valid() ) {
{ Error(errno ? strerror(errno) : "unable to get interface information");
Error(errno ? strerror(errno) : "unable to get interface information"); close(socket_fd);
close(socket_fd); socket_fd = -1;
socket_fd = -1; return;
return; }
}
if ( ! info.IsUp() ) if ( ! info.IsUp() ) {
{ Error("interface is down");
Error("interface is down"); close(socket_fd);
close(socket_fd); socket_fd = -1;
socket_fd = -1; return;
return; }
}
// Create RX-ring // Create RX-ring
try { try {
rx_ring = new RX_Ring(socket_fd, buffer_size, block_size, block_timeout_msec); rx_ring = new RX_Ring(socket_fd, buffer_size, block_size, block_timeout_msec);
} catch (RX_RingException& e) { } catch ( RX_RingException& e ) {
Error(errno ? strerror(errno) : "unable to create RX-ring"); Error(errno ? strerror(errno) : "unable to create RX-ring");
close(socket_fd); close(socket_fd);
return; return;
} }
// Setup interface // Setup interface
if ( ! BindInterface(info) ) if ( ! BindInterface(info) ) {
{ Error(errno ? strerror(errno) : "unable to bind to interface");
Error(errno ? strerror(errno) : "unable to bind to interface"); close(socket_fd);
close(socket_fd); return;
return; }
}
if ( ! EnablePromiscMode(info) ) if ( ! EnablePromiscMode(info) ) {
{ Error(errno ? strerror(errno) : "unable enter promiscuous mode");
Error(errno ? strerror(errno) : "unable enter promiscious mode"); close(socket_fd);
close(socket_fd); return;
return; }
}
if ( ! ConfigureFanoutGroup(enable_fanout, enable_defrag) ) if ( ! ConfigureFanoutGroup(enable_fanout, enable_defrag) ) {
{ Error(errno ? strerror(errno) : "failed to join fanout group");
Error(errno ? strerror(errno) : "failed to join fanout group"); close(socket_fd);
close(socket_fd); return;
return; }
}
if ( ! ConfigureHWTimestamping(enable_hw_timestamping) ) if ( ! ConfigureHWTimestamping(enable_hw_timestamping) ) {
{
Error(errno ? strerror(errno) : "failed to configure hardware timestamping"); Error(errno ? strerror(errno) : "failed to configure hardware timestamping");
close(socket_fd); close(socket_fd);
return; return;
} }
props.netmask = NETMASK_UNKNOWN; props.netmask = NETMASK_UNKNOWN;
props.selectable_fd = socket_fd; props.selectable_fd = socket_fd;
props.is_live = true; props.is_live = true;
props.link_type = link_type; props.link_type = link_type;
stats.received = stats.dropped = stats.link = stats.bytes_received = 0; stats.received = stats.dropped = stats.link = stats.bytes_received = 0;
num_discarded = 0; num_discarded = 0;
Opened(props); Opened(props);
} }
AF_PacketSource::InterfaceInfo AF_PacketSource::GetInterfaceInfo(const std::string& path) AF_PacketSource::InterfaceInfo AF_PacketSource::GetInterfaceInfo(const std::string& path) {
{ AF_PacketSource::InterfaceInfo info;
AF_PacketSource::InterfaceInfo info; struct ifreq ifr;
struct ifreq ifr; int ret;
int ret;
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", path.c_str()); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", path.c_str());
ret = ioctl(socket_fd, SIOCGIFFLAGS, &ifr); ret = ioctl(socket_fd, SIOCGIFFLAGS, &ifr);
if ( ret < 0 ) if ( ret < 0 )
return info; return info;
info.flags = ifr.ifr_flags; info.flags = ifr.ifr_flags;
ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr); ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr);
if ( ret < 0 ) if ( ret < 0 )
return info; return info;
info.index = ifr.ifr_ifindex; info.index = ifr.ifr_ifindex;
return info; return info;
} }
bool AF_PacketSource::BindInterface(const AF_PacketSource::InterfaceInfo& info) bool AF_PacketSource::BindInterface(const AF_PacketSource::InterfaceInfo& info) {
{ struct sockaddr_ll saddr_ll;
struct sockaddr_ll saddr_ll; int ret;
int ret;
memset(&saddr_ll, 0, sizeof(saddr_ll)); memset(&saddr_ll, 0, sizeof(saddr_ll));
saddr_ll.sll_family = AF_PACKET; saddr_ll.sll_family = AF_PACKET;
saddr_ll.sll_protocol = htons(ETH_P_ALL); saddr_ll.sll_protocol = htons(ETH_P_ALL);
saddr_ll.sll_ifindex = info.index; saddr_ll.sll_ifindex = info.index;
ret = bind(socket_fd, (struct sockaddr *) &saddr_ll, sizeof(saddr_ll)); ret = bind(socket_fd, (struct sockaddr*)&saddr_ll, sizeof(saddr_ll));
return (ret >= 0); return (ret >= 0);
} }
bool AF_PacketSource::EnablePromiscMode(const AF_PacketSource::InterfaceInfo& info) bool AF_PacketSource::EnablePromiscMode(const AF_PacketSource::InterfaceInfo& info) {
{ struct packet_mreq mreq;
struct packet_mreq mreq; int ret;
int ret;
memset(&mreq, 0, sizeof(mreq)); memset(&mreq, 0, sizeof(mreq));
mreq.mr_ifindex = info.index; mreq.mr_ifindex = info.index;
mreq.mr_type = PACKET_MR_PROMISC; mreq.mr_type = PACKET_MR_PROMISC;
ret = setsockopt(socket_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); ret = setsockopt(socket_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
return (ret >= 0); return (ret >= 0);
} }
bool AF_PacketSource::ConfigureFanoutGroup(bool enabled, bool defrag) bool AF_PacketSource::ConfigureFanoutGroup(bool enabled, bool defrag) {
{ if ( enabled ) {
if ( enabled ) uint32_t fanout_arg, fanout_id;
{ int ret;
uint32_t fanout_arg, fanout_id;
int ret;
fanout_id = zeek::BifConst::AF_Packet::fanout_id; fanout_id = zeek::BifConst::AF_Packet::fanout_id;
fanout_arg = ((fanout_id & 0xffff) | (GetFanoutMode(defrag) << 16)); fanout_arg = ((fanout_id & 0xffff) | (GetFanoutMode(defrag) << 16));
ret = setsockopt(socket_fd, SOL_PACKET, PACKET_FANOUT, ret = setsockopt(socket_fd, SOL_PACKET, PACKET_FANOUT, &fanout_arg, sizeof(fanout_arg));
&fanout_arg, sizeof(fanout_arg));
if ( ret < 0 ) if ( ret < 0 )
return false; return false;
}
return true;
} }
return true;
}
bool AF_PacketSource::ConfigureHWTimestamping(bool enabled) bool AF_PacketSource::ConfigureHWTimestamping(bool enabled) {
{ if ( enabled ) {
if ( enabled ) struct ifreq ifr;
{ struct hwtstamp_config hwts_cfg;
struct ifreq ifr; int ret, opt;
struct hwtstamp_config hwts_cfg;
int ret, opt;
memset(&hwts_cfg, 0, sizeof(hwts_cfg)); memset(&hwts_cfg, 0, sizeof(hwts_cfg));
hwts_cfg.tx_type = HWTSTAMP_TX_OFF; hwts_cfg.tx_type = HWTSTAMP_TX_OFF;
@ -216,175 +197,150 @@ bool AF_PacketSource::ConfigureHWTimestamping(bool enabled)
return false; return false;
opt = SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE; opt = SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
ret = setsockopt(socket_fd, SOL_PACKET, PACKET_TIMESTAMP, ret = setsockopt(socket_fd, SOL_PACKET, PACKET_TIMESTAMP, &opt, sizeof(opt));
&opt, sizeof(opt)); if ( ret < 0 )
if( ret < 0 )
return false; return false;
}
return true;
} }
return true;
}
uint32_t AF_PacketSource::GetFanoutMode(bool defrag) uint32_t AF_PacketSource::GetFanoutMode(bool defrag) {
{ uint32_t fanout_mode;
uint32_t fanout_mode;
switch ( zeek::BifConst::AF_Packet::fanout_mode->AsEnum() ) { switch ( zeek::BifConst::AF_Packet::fanout_mode->AsEnum() ) {
case BifEnum::AF_Packet::FANOUT_CPU: fanout_mode = PACKET_FANOUT_CPU; case BifEnum::AF_Packet::FANOUT_CPU: fanout_mode = PACKET_FANOUT_CPU; break;
break; #ifdef PACKET_FANOUT_QM
#ifdef PACKET_FANOUT_QM case BifEnum::AF_Packet::FANOUT_QM: fanout_mode = PACKET_FANOUT_QM; break;
case BifEnum::AF_Packet::FANOUT_QM: fanout_mode = PACKET_FANOUT_QM; #endif
break; #ifdef PACKET_FANOUT_CBPF
#endif case BifEnum::AF_Packet::FANOUT_CBPF: fanout_mode = PACKET_FANOUT_CBPF; break;
#ifdef PACKET_FANOUT_CBPF #endif
case BifEnum::AF_Packet::FANOUT_CBPF: fanout_mode = PACKET_FANOUT_CBPF; #ifdef PACKET_FANOUT_EBPF
break; case BifEnum::AF_Packet::FANOUT_EBPF: fanout_mode = PACKET_FANOUT_EBPF; break;
#endif #endif
#ifdef PACKET_FANOUT_EBPF default: fanout_mode = PACKET_FANOUT_HASH; break;
case BifEnum::AF_Packet::FANOUT_EBPF: fanout_mode = PACKET_FANOUT_EBPF;
break;
#endif
default: fanout_mode = PACKET_FANOUT_HASH;
break;
} }
if ( defrag ) if ( defrag )
fanout_mode |= PACKET_FANOUT_FLAG_DEFRAG; fanout_mode |= PACKET_FANOUT_FLAG_DEFRAG;
return fanout_mode; return fanout_mode;
} }
void AF_PacketSource::Close() void AF_PacketSource::Close() {
{ if ( socket_fd < 0 )
if ( socket_fd < 0 ) return;
return;
delete rx_ring; delete rx_ring;
rx_ring = nullptr; rx_ring = nullptr;
close(socket_fd); close(socket_fd);
socket_fd = -1; socket_fd = -1;
Closed(); Closed();
} }
bool AF_PacketSource::ExtractNextPacket(zeek::Packet* pkt) bool AF_PacketSource::ExtractNextPacket(zeek::Packet* pkt) {
{
if ( ! socket_fd ) if ( ! socket_fd )
return false; return false;
struct tpacket3_hdr *packet = 0; struct tpacket3_hdr* packet = 0;
const u_char *data; const u_char* data;
while ( true ) while ( true ) {
{ if ( ! rx_ring->GetNextPacket(&packet) )
if ( ! rx_ring->GetNextPacket(&packet) ) return false;
return false;
current_hdr.ts.tv_sec = packet->tp_sec; current_hdr.ts.tv_sec = packet->tp_sec;
current_hdr.ts.tv_usec = packet->tp_nsec / 1000; current_hdr.ts.tv_usec = packet->tp_nsec / 1000;
current_hdr.caplen = packet->tp_snaplen; current_hdr.caplen = packet->tp_snaplen;
current_hdr.len = packet->tp_len; current_hdr.len = packet->tp_len;
data = (u_char *) packet + packet->tp_mac; data = (u_char*)packet + packet->tp_mac;
if ( !ApplyBPFFilter(current_filter, &current_hdr, data) ) if ( ! ApplyBPFFilter(current_filter, &current_hdr, data) ) {
{
++num_discarded; ++num_discarded;
DoneWithPacket(); DoneWithPacket();
continue; continue;
} }
pkt->Init(props.link_type, &current_hdr.ts, current_hdr.caplen, current_hdr.len, data); pkt->Init(props.link_type, &current_hdr.ts, current_hdr.caplen, current_hdr.len, data);
if ( packet->tp_status & TP_STATUS_VLAN_VALID ) if ( packet->tp_status & TP_STATUS_VLAN_VALID )
pkt->vlan = packet->hv1.tp_vlan_tci & 0x0fff; pkt->vlan = packet->hv1.tp_vlan_tci & 0x0fff;
#if ZEEK_VERSION_NUMBER >= 50100 #if ZEEK_VERSION_NUMBER >= 50100
switch ( checksum_mode ) switch ( checksum_mode ) {
{ case BifEnum::AF_Packet::CHECKSUM_OFF: {
case BifEnum::AF_Packet::CHECKSUM_OFF: // If set to off, just accept whatever checksum in the packet is correct and
{ // skip checking it here and in Zeek.
// If set to off, just accept whatever checksum in the packet is correct and pkt->l4_checksummed = true;
// skip checking it here and in Zeek. break;
pkt->l4_checksummed = true; }
break; case BifEnum::AF_Packet::CHECKSUM_KERNEL: {
} // If set to kernel, check whether the kernel thinks the checksum is valid. If it
case BifEnum::AF_Packet::CHECKSUM_KERNEL: // does, tell Zeek to skip checking by itself.
{ if ( ((packet->tp_status & TP_STATUS_CSUM_VALID) != 0) ||
// If set to kernel, check whether the kernel thinks the checksum is valid. If it ((packet->tp_status & TP_STATUS_CSUMNOTREADY) != 0) )
// does, tell Zeek to skip checking by itself. pkt->l4_checksummed = true;
if ( ( (packet->tp_status & TP_STATUS_CSUM_VALID) != 0 ) || else
( (packet->tp_status & TP_STATUS_CSUMNOTREADY) != 0 ) ) pkt->l4_checksummed = false;
pkt->l4_checksummed = true; break;
else }
pkt->l4_checksummed = false; case BifEnum::AF_Packet::CHECKSUM_ON:
break; default: {
} // Let Zeek handle it.
case BifEnum::AF_Packet::CHECKSUM_ON: pkt->l4_checksummed = false;
default: break;
{ }
// Let Zeek handle it. }
pkt->l4_checksummed = false;
break;
}
}
#endif #endif
if ( current_hdr.len == 0 || current_hdr.caplen == 0 ) if ( current_hdr.len == 0 || current_hdr.caplen == 0 ) {
{ Weird("empty_af_packet_header", pkt);
Weird("empty_af_packet_header", pkt); return false;
return false; }
}
stats.received++; stats.received++;
stats.bytes_received += current_hdr.len; stats.bytes_received += current_hdr.len;
return true; return true;
} }
return false; return false;
} }
void AF_PacketSource::DoneWithPacket() void AF_PacketSource::DoneWithPacket() { rx_ring->ReleasePacket(); }
{
rx_ring->ReleasePacket();
}
bool AF_PacketSource::PrecompileFilter(int index, const std::string& filter) bool AF_PacketSource::PrecompileFilter(int index, const std::string& filter) {
{
return PktSrc::PrecompileBPFFilter(index, filter); return PktSrc::PrecompileBPFFilter(index, filter);
} }
bool AF_PacketSource::SetFilter(int index) bool AF_PacketSource::SetFilter(int index) {
{
current_filter = index; current_filter = index;
return true; return true;
} }
void AF_PacketSource::Statistics(Stats* s) void AF_PacketSource::Statistics(Stats* s) {
{ if ( ! socket_fd ) {
if ( ! socket_fd )
{
s->received = s->bytes_received = s->link = s->dropped = 0; s->received = s->bytes_received = s->link = s->dropped = 0;
return; return;
} }
struct tpacket_stats_v3 tp_stats; struct tpacket_stats_v3 tp_stats;
socklen_t tp_stats_len = sizeof (struct tpacket_stats_v3); socklen_t tp_stats_len = sizeof(struct tpacket_stats_v3);
int ret; int ret;
ret = getsockopt(socket_fd, SOL_PACKET, PACKET_STATISTICS, &tp_stats, &tp_stats_len); ret = getsockopt(socket_fd, SOL_PACKET, PACKET_STATISTICS, &tp_stats, &tp_stats_len);
if ( ret < 0 ) if ( ret < 0 ) {
{
Error(errno ? strerror(errno) : "unable to retrieve statistics"); Error(errno ? strerror(errno) : "unable to retrieve statistics");
s->received = s->bytes_received = s->link = s->dropped = 0; s->received = s->bytes_received = s->link = s->dropped = 0;
return; return;
} }
stats.link += tp_stats.tp_packets; stats.link += tp_stats.tp_packets;
stats.dropped += tp_stats.tp_drops; stats.dropped += tp_stats.tp_drops;
memcpy(s, &stats, sizeof(Stats)); memcpy(s, &stats, sizeof(Stats));
} }
zeek::iosource::PktSrc* AF_PacketSource::InstantiateAF_Packet(const std::string& path, bool is_live) zeek::iosource::PktSrc* AF_PacketSource::InstantiateAF_Packet(const std::string& path, bool is_live) {
{
return new AF_PacketSource(path, is_live); return new AF_PacketSource(path, is_live);
} }

View file

@ -3,82 +3,81 @@
#pragma once #pragma once
extern "C" { extern "C" {
#include <sys/types.h> #include <errno.h> // errorno
#include <sys/socket.h> #include <linux/if.h> // ifreq
#include <sys/ioctl.h> #include <linux/if_packet.h> // AF_PACKET, etc.
#include <linux/net_tstamp.h> // hwtstamp_config
#include <errno.h> // errorno #include <linux/sockios.h> // SIOCSHWTSTAMP
#include <unistd.h> // close() #include <net/ethernet.h> // ETH_P_ALL
#include <net/ethernet.h> // ETH_P_ALL
#include <linux/if.h> // ifreq
#include <linux/if_packet.h> // AF_PACKET, etc.
#include <linux/sockios.h> // SIOCSHWTSTAMP
#include <linux/net_tstamp.h> // hwtstamp_config
#include <pcap.h> #include <pcap.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // close()
} }
#include "zeek/iosource/PktSrc.h" #include "zeek/iosource/PktSrc.h"
#include "RX_Ring.h" #include "RX_Ring.h"
namespace af_packet::iosource::pktsrc { namespace af_packet::iosource::pktsrc {
class AF_PacketSource : public zeek::iosource::PktSrc { class AF_PacketSource : public zeek::iosource::PktSrc {
public: public:
/** /**
* Constructor. * Constructor.
* *
* path: Name of the interface to open (the AF_Packet source doesn't * path: Name of the interface to open (the AF_Packet source doesn't
* support reading from files). * support reading from files).
* *
* is_live: Must be true (the AF_Packet source doesn't support offline * is_live: Must be true (the AF_Packet source doesn't support offline
* operation). * operation).
*/ */
AF_PacketSource(const std::string& path, bool is_live); AF_PacketSource(const std::string& path, bool is_live);
/** /**
* Destructor. * Destructor.
*/ */
~AF_PacketSource() override; ~AF_PacketSource() override;
static PktSrc* InstantiateAF_Packet(const std::string& path, bool is_live); static PktSrc* InstantiateAF_Packet(const std::string& path, bool is_live);
protected: protected:
// PktSrc interface. // PktSrc interface.
void Open() override; void Open() override;
void Close() override; void Close() override;
bool ExtractNextPacket(zeek::Packet* pkt) override; bool ExtractNextPacket(zeek::Packet* pkt) override;
void DoneWithPacket() override; void DoneWithPacket() override;
bool PrecompileFilter(int index, const std::string& filter) override; bool PrecompileFilter(int index, const std::string& filter) override;
bool SetFilter(int index) override; bool SetFilter(int index) override;
void Statistics(Stats* stats) override; void Statistics(Stats* stats) override;
private: private:
Properties props; Properties props;
Stats stats; Stats stats;
int current_filter = 0; int current_filter = 0;
unsigned int num_discarded = 0; unsigned int num_discarded = 0;
int checksum_mode = 0; int checksum_mode = 0;
int socket_fd = -1; int socket_fd = -1;
RX_Ring *rx_ring = nullptr; RX_Ring* rx_ring = nullptr;
struct pcap_pkthdr current_hdr = {}; struct pcap_pkthdr current_hdr = {};
struct InterfaceInfo { struct InterfaceInfo {
int index = -1; int index = -1;
int flags = 0; int flags = 0;
bool Valid () { return index >= 0; } bool Valid() { return index >= 0; }
bool IsUp() { return flags & IFF_UP; } bool IsUp() { return flags & IFF_UP; }
}; };
InterfaceInfo GetInterfaceInfo(const std::string& path); InterfaceInfo GetInterfaceInfo(const std::string& path);
bool BindInterface(const InterfaceInfo& info); bool BindInterface(const InterfaceInfo& info);
bool EnablePromiscMode(const InterfaceInfo& info); bool EnablePromiscMode(const InterfaceInfo& info);
bool ConfigureFanoutGroup(bool enabled, bool defrag); bool ConfigureFanoutGroup(bool enabled, bool defrag);
bool ConfigureHWTimestamping(bool enabled); bool ConfigureHWTimestamping(bool enabled);
uint32_t GetFanoutMode(bool defrag); uint32_t GetFanoutMode(bool defrag);
}; };
} } // namespace zeek::iosource::pktsrc

View file

@ -1,21 +1,27 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "Plugin.h" #include "Plugin.h"
#include "AF_Packet.h"
#include "zeek/iosource/Component.h" #include "zeek/iosource/Component.h"
namespace af_packet::plugin::Zeek_AF_Packet { Plugin plugin; } #include "AF_Packet.h"
namespace plugin::Zeek_AF_Packet {
Plugin plugin;
}
using namespace af_packet::plugin::Zeek_AF_Packet; using namespace af_packet::plugin::Zeek_AF_Packet;
zeek::plugin::Configuration Plugin::Configure() zeek::plugin::Configuration Plugin::Configure() {
{ AddComponent(
AddComponent(new ::zeek::iosource::PktSrcComponent("AF_PacketReader", "af_packet", ::zeek::iosource::PktSrcComponent::LIVE, ::af_packet::iosource::pktsrc::AF_PacketSource::InstantiateAF_Packet)); new ::zeek::iosource::PktSrcComponent("AF_PacketReader", "af_packet", ::zeek::iosource::PktSrcComponent::LIVE,
::zeek::iosource::pktsrc::AF_PacketSource::InstantiateAF_Packet));
zeek::plugin::Configuration config; zeek::plugin::Configuration config;
config.name = "Zeek::AF_Packet"; config.name = "Zeek::AF_Packet";
config.description = "Packet acquisition via AF_Packet"; config.description = "Packet acquisition via AF_Packet";
config.version.major = 4; config.version.major = 4;
config.version.minor = 0; config.version.minor = 0;
config.version.patch = 0; config.version.patch = 0;
return config; return config;
} }

View file

@ -1,16 +1,17 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once #pragma once
#include <zeek/plugin/Plugin.h> #include <zeek/plugin/Plugin.h>
namespace af_packet::plugin::Zeek_AF_Packet { namespace af_packet::plugin::Zeek_AF_Packet {
class Plugin : public zeek::plugin::Plugin class Plugin : public zeek::plugin::Plugin {
{
protected: protected:
// Overridden from zeek::plugin::Plugin. // Overridden from zeek::plugin::Plugin.
zeek::plugin::Configuration Configure() override; zeek::plugin::Configuration Configure() override;
}; };
extern Plugin plugin; extern Plugin plugin;
} } // namespace plugin::Zeek_AF_Packet

View file

@ -1,3 +1,4 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "RX_Ring.h" #include "RX_Ring.h"
@ -5,108 +6,95 @@
#include <utility> #include <utility>
extern "C" { extern "C" {
#include <linux/if_packet.h> // AF_PACKET, etc. #include <linux/if_packet.h> // AF_PACKET, etc.
#include <sys/socket.h> // socketopt consts #include <sys/mman.h> // mmap
#include <sys/mman.h> // mmap #include <sys/socket.h> // socketopt consts
#include <unistd.h> // sysconf #include <unistd.h> // sysconf
} }
RX_Ring::RX_Ring(int sock, size_t bufsize, size_t blocksize, int blocktimeout_msec) RX_Ring::RX_Ring(int sock, size_t bufsize, size_t blocksize, int blocktimeout_msec) {
{ int ret, ver = TPACKET_VERSION;
int ret, ver = TPACKET_VERSION;
if ( sock < 0 ) if ( sock < 0 )
throw RX_RingException("invalid socket"); throw RX_RingException("invalid socket");
// Configure socket // Configure socket
ret = setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver)); ret = setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver));
if ( ret ) if ( ret )
throw RX_RingException("unable to set TPacket version"); throw RX_RingException("unable to set TPacket version");
InitLayout(bufsize, blocksize, blocktimeout_msec); InitLayout(bufsize, blocksize, blocktimeout_msec);
ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING, (uint8_t *) &layout, ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING, (uint8_t*)&layout, sizeof(layout));
sizeof(layout)); if ( ret )
if ( ret ) throw RX_RingException("unable to set ring layout");
throw RX_RingException("unable to set ring layout");
// Map memory // Map memory
size = layout.tp_block_size * layout.tp_block_nr; size = layout.tp_block_size * layout.tp_block_nr;
ring = (uint8_t *) mmap(NULL, size, PROT_READ | PROT_WRITE, ring = (uint8_t*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, sock, 0);
MAP_SHARED, sock, 0); if ( ring == MAP_FAILED )
if ( ring == MAP_FAILED ) throw RX_RingException("unable to map ring memory");
throw RX_RingException("unable to map ring memory");
block_num = packet_num = 0; block_num = packet_num = 0;
packet = NULL; packet = NULL;
// Init block mapping // Init block mapping
blocks = new tpacket_block_desc*[layout.tp_block_nr]; blocks = new tpacket_block_desc*[layout.tp_block_nr];
for ( unsigned int i = 0; i < layout.tp_block_nr; i++ ) for ( unsigned int i = 0; i < layout.tp_block_nr; i++ )
blocks[i] = (struct tpacket_block_desc *)(ring + blocks[i] = (struct tpacket_block_desc*)(ring + i * layout.tp_block_size);
i * layout.tp_block_size); }
}
RX_Ring::~RX_Ring() RX_Ring::~RX_Ring() {
{ ReleasePacket();
ReleasePacket();
delete[] blocks; delete[] blocks;
munmap(ring, size); munmap(ring, size);
blocks = 0; blocks = 0;
size = 0; size = 0;
} }
bool RX_Ring::GetNextPacket(tpacket3_hdr** hdr) bool RX_Ring::GetNextPacket(tpacket3_hdr** hdr) {
{ struct tpacket_hdr_v1* block_hdr = &(blocks[block_num]->hdr.bh1);
struct tpacket_hdr_v1 *block_hdr = &(blocks[block_num]->hdr.bh1);
if ( (block_hdr->block_status & TP_STATUS_USER) == 0 ) if ( (block_hdr->block_status & TP_STATUS_USER) == 0 )
return false; return false;
if ( packet == NULL ) if ( packet == NULL ) {
{ // New block
// New block packet_num = block_hdr->num_pkts;
packet_num = block_hdr->num_pkts; if ( packet_num == 0 ) {
if ( packet_num == 0 ) NextBlock();
{ return false;
NextBlock(); }
return false; packet = (struct tpacket3_hdr*)((uint8_t*)blocks[block_num] + block_hdr->offset_to_first_pkt);
} }
packet = (struct tpacket3_hdr *) else
((uint8_t *) blocks[block_num] + block_hdr->offset_to_first_pkt); // Continue with block
} packet = (struct tpacket3_hdr*)((uint8_t*)packet + packet->tp_next_offset);
else
// Continue with block
packet = (struct tpacket3_hdr *)
((uint8_t *) packet + packet->tp_next_offset);
*hdr = packet; *hdr = packet;
packet_num--; packet_num--;
return true; return true;
} }
void RX_Ring::ReleasePacket() void RX_Ring::ReleasePacket() {
{ if ( packet_num == 0 )
if ( packet_num == 0 ) NextBlock();
NextBlock(); }
}
void RX_Ring::InitLayout(size_t bufsize, size_t blocksize, int blocktimeout_msec) void RX_Ring::InitLayout(size_t bufsize, size_t blocksize, int blocktimeout_msec) {
{ memset(&layout, 0, sizeof(layout));
memset(&layout, 0, sizeof(layout)); layout.tp_block_size = blocksize;
layout.tp_block_size = blocksize; layout.tp_frame_size = TPACKET_ALIGNMENT << 7; // Seems to be irrelevant for V3
layout.tp_frame_size = TPACKET_ALIGNMENT << 7; // Seems to be irrelevant for V3 layout.tp_block_nr = bufsize / layout.tp_block_size;
layout.tp_block_nr = bufsize / layout.tp_block_size; layout.tp_frame_nr = (layout.tp_block_size / layout.tp_frame_size) * layout.tp_block_nr;
layout.tp_frame_nr = (layout.tp_block_size / layout.tp_frame_size) * layout.tp_block_nr; layout.tp_retire_blk_tov = blocktimeout_msec;
layout.tp_retire_blk_tov = blocktimeout_msec; }
}
void RX_Ring::NextBlock() void RX_Ring::NextBlock() {
{ struct tpacket_hdr_v1* block_hdr = &(blocks[block_num]->hdr.bh1);
struct tpacket_hdr_v1 *block_hdr = &(blocks[block_num]->hdr.bh1);
block_hdr->block_status = TP_STATUS_KERNEL; block_hdr->block_status = TP_STATUS_KERNEL;
block_num = (block_num +1) % layout.tp_block_nr; block_num = (block_num + 1) % layout.tp_block_nr;
packet = NULL; packet = NULL;
} }

View file

@ -13,32 +13,32 @@ extern "C" {
class RX_RingException : public std::runtime_error { class RX_RingException : public std::runtime_error {
public: public:
RX_RingException(const std::string& what_arg) : std::runtime_error(what_arg) {} RX_RingException(const std::string& what_arg) : std::runtime_error(what_arg) {}
}; };
class RX_Ring { class RX_Ring {
public: public:
/** /**
* Constructor * Constructor
*/ */
RX_Ring(int sock, size_t bufsize, size_t blocksize, int blocktimeout_msec); RX_Ring(int sock, size_t bufsize, size_t blocksize, int blocktimeout_msec);
~RX_Ring(); ~RX_Ring();
bool GetNextPacket(tpacket3_hdr** hdr); bool GetNextPacket(tpacket3_hdr** hdr);
void ReleasePacket(); void ReleasePacket();
protected: protected:
void InitLayout(size_t bufsize, size_t blocksize, int blocktimeout_msec); void InitLayout(size_t bufsize, size_t blocksize, int blocktimeout_msec);
void NextBlock(); void NextBlock();
private: private:
struct tpacket_req3 layout; struct tpacket_req3 layout;
struct tpacket_block_desc** blocks; struct tpacket_block_desc** blocks;
struct tpacket3_hdr* packet; struct tpacket3_hdr* packet;
unsigned int block_num; unsigned int block_num;
unsigned int packet_num; unsigned int packet_num;
uint8_t* ring; uint8_t* ring;
size_t size; size_t size;
}; };