Moving some of the BPF filtering code into base class.

This will allow packet sources that don't support BPF natively to
emulate the filtering via libpcap.
This commit is contained in:
Robin Sommer 2014-08-22 17:27:20 -07:00
parent 0186061aa8
commit ce9f16490c
8 changed files with 110 additions and 85 deletions

View file

@ -7,6 +7,7 @@ include_directories(BEFORE
)
set(iosource_SRCS
BPF_Program.cc
Component.cc
Manager.cc
PktDumper.cc

View file

@ -25,6 +25,10 @@ PktSrc::PktSrc()
PktSrc::~PktSrc()
{
BPF_Program* code;
IterCookie* cookie = filters.InitForIteration();
while ( (code = filters.NextEntry(cookie)) )
delete code;
}
const std::string& PktSrc::Path() const
@ -43,6 +47,11 @@ int PktSrc::LinkType() const
return IsOpen() ? props.link_type : -1;
}
uint32 PktSrc::Netmask() const
{
return IsOpen() ? props.netmask : PCAP_NETMASK_UNKNOWN;
}
int PktSrc::HdrSize() const
{
return IsOpen() ? props.hdr_size : -1;
@ -77,6 +86,12 @@ void PktSrc::Opened(const Properties& arg_props)
props = arg_props;
SetClosed(false);
if ( ! PrecompileFilter(0, props.filter) || ! SetFilter(0) )
{
Close();
return;
}
DBG_LOG(DBG_PKTIO, "Opened source %s", props.path.c_str());
}
@ -409,12 +424,50 @@ int PktSrc::ExtractNextPacketInternal()
return 0;
}
int PktSrc::PrecompileFilter(int index, const std::string& filter)
int PktSrc::PrecompileBPFFilter(int index, const std::string& filter)
{
char errbuf[PCAP_ERRBUF_SIZE];
// Compile filter.
BPF_Program* code = new BPF_Program();
if ( ! code->Compile(SnapLen(), LinkType(), filter.c_str(), Netmask(), errbuf, sizeof(errbuf)) )
{
Error(fmt("cannot compile BPF filter \"%s\": %s", filter.c_str(), errbuf));
Close();
delete code;
return 0;
}
// Store it in hash.
HashKey* hash = new HashKey(HashKey(bro_int_t(index)));
BPF_Program* oldcode = filters.Lookup(hash);
if ( oldcode )
delete oldcode;
filters.Insert(hash, code);
delete hash;
return 1;
}
int PktSrc::SetFilter(int index)
BPF_Program* PktSrc::GetBPFFilter(int index)
{
return 1;
HashKey* hash = new HashKey(HashKey(bro_int_t(index)));
BPF_Program* code = filters.Lookup(hash);
delete hash;
return code;
}
int PktSrc::ApplyBPFFilter(int index, const struct pcap_pkthdr *hdr, const u_char *pkt)
{
BPF_Program* code = GetBPFFilter(index);
if ( ! code )
{
Error(fmt("BPF filter %d not compiled", index));
Close();
}
return pcap_offline_filter(code->GetProgram(), hdr, pkt);
}

View file

@ -8,6 +8,10 @@ extern "C" {
}
#include "IOSource.h"
#include "BPF_Program.h"
#include "Dict.h"
declare(PDict,BPF_Program);
namespace iosource {
@ -29,6 +33,7 @@ public:
const std::string& Filter() const;
bool IsLive() const;
int LinkType() const;
uint32 Netmask() const;
const char* ErrorMsg() const;
int HdrSize() const;
int SnapLen() const;
@ -41,7 +46,22 @@ public:
// going to be continued.
void ContinueAfterSuspend();
virtual void Statistics(Stats* stats) = 0;
// Precompiles a BPF filter and associates the given index with it.
// Returns true on success, 0 if a problem occurred. The compiled
// filter will be then available via GetBPFFilter*(.
int PrecompileBPFFilter(int index, const std::string& filter);
// Returns the BPF filter with the given index, as compiled by
// PrecompileBPFFilter(), or null if none has been (successfully)
// compiled.
BPF_Program* GetBPFFilter(int index);
// Applies a precompiled BPF filter to a packet, returning true if it
// maches. This will close the source with an error message if no
// filter with that index has been compiled.
int ApplyBPFFilter(int index, const struct pcap_pkthdr *hdr, const u_char *pkt);
// PacketSource interace for derived classes to override.
// Returns the packet last processed; false if there is no
// current packet available.
@ -50,12 +70,15 @@ public:
// Precompiles a filter and associates the given index with it.
// Returns true on success, 0 if a problem occurred or filtering is
// not supported.
virtual int PrecompileFilter(int index, const std::string& filter);
virtual int PrecompileFilter(int index, const std::string& filter) = 0;
// Activates the filter with the given index. Returns true on
// success, 0 if a problem occurred or the filtering is not
// supported.
virtual int SetFilter(int index);
virtual int SetFilter(int index) = 0;
// Returns current statistics about the source.
virtual void Statistics(Stats* stats) = 0;
static int GetLinkHeaderSize(int link_type);
@ -68,7 +91,13 @@ protected:
int selectable_fd;
int link_type;
int hdr_size;
uint32 netmask;
bool is_live;
Properties()
{
netmask = PCAP_NETMASK_UNKNOWN;
}
};
struct Packet {
@ -113,6 +142,9 @@ private:
bool have_packet;
Packet current_packet;
// For BPF filtering support.
PDict(BPF_Program) filters;
// Only set in pseudo-realtime mode.
double first_timestamp;
double first_wallclock;

View file

@ -4,5 +4,5 @@ include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
bro_plugin_begin(Bro Pcap)
bro_plugin_cc(Source.cc Dumper.cc BPF_Program.cc Plugin.cc)
bro_plugin_cc(Source.cc Dumper.cc Plugin.cc)
bro_plugin_end()

View file

@ -37,13 +37,6 @@ void PcapSource::Close()
if ( ! pd )
return;
BPF_Program* code;
IterCookie* cookie = filters.InitForIteration();
while ( (code = filters.NextEntry(cookie)) )
delete code;
filters.Clear();
pcap_close(pd);
pd = 0;
last_data = 0;
@ -56,10 +49,6 @@ void PcapSource::OpenLive()
char errbuf[PCAP_ERRBUF_SIZE];
char tmp_errbuf[PCAP_ERRBUF_SIZE];
#if 0
filter_type = ft;
#endif
// Determine interface if not specified.
if ( props.path.empty() )
props.path = pcap_lookupdev(tmp_errbuf);
@ -74,7 +63,7 @@ void PcapSource::OpenLive()
// Determine network and netmask.
uint32 net;
if ( pcap_lookupnet(props.path.c_str(), &net, &netmask, tmp_errbuf) < 0 )
if ( pcap_lookupnet(props.path.c_str(), &net, &props.netmask, tmp_errbuf) < 0 )
{
// ### The lookup can fail if no address is assigned to
// the interface; and libpcap doesn't have any useful notion
@ -82,7 +71,7 @@ void PcapSource::OpenLive()
// just kludge around the error :-(.
// sprintf(errbuf, "pcap_lookupnet %s", tmp_errbuf);
// return;
netmask = 0xffffff00;
props.netmask = 0xffffff00;
}
// We use the smallest time-out possible to return almost immediately if
@ -113,31 +102,22 @@ void PcapSource::OpenLive()
props.selectable_fd = pcap_fileno(pd);
if ( PrecompileFilter(0, props.filter) && SetFilter(0) )
{
SetHdrSize();
if ( ! pd )
// Was closed, couldn't get header size.
return;
Info(fmt("listening on %s, capture length %d bytes\n", props.path.c_str(), SnapLen()));
}
else
Close();
props.is_live = true;
Opened(props);
Info(fmt("listening on %s, capture length %d bytes\n", props.path.c_str(), SnapLen()));
}
void PcapSource::OpenOffline()
{
char errbuf[PCAP_ERRBUF_SIZE];
#if 0
filter_type = ft;
#endif
pd = pcap_open_offline(props.path.c_str(), errbuf);
if ( ! pd )
@ -146,25 +126,16 @@ void PcapSource::OpenOffline()
return;
}
if ( PrecompileFilter(0, props.filter) && SetFilter(0) )
{
SetHdrSize();
if ( ! pd )
// Was closed, unknown link layer type.
return;
// We don't put file sources into non-blocking mode as
// otherwise we would not be able to identify the EOF.
props.selectable_fd = fileno(pcap_file(pd));
if ( props.selectable_fd < 0 )
InternalError("OS does not support selectable pcap fd");
}
else
Close();
props.is_live = false;
Opened(props);
@ -211,31 +182,7 @@ void PcapSource::DoneWithPacket(Packet* pkt)
int PcapSource::PrecompileFilter(int index, const std::string& filter)
{
if ( ! pd )
return 1; // Prevent error message.
char errbuf[PCAP_ERRBUF_SIZE];
// Compile filter.
BPF_Program* code = new BPF_Program();
if ( ! code->Compile(pd, filter.c_str(), netmask, errbuf, sizeof(errbuf)) )
{
PcapError();
delete code;
return 0;
}
// Store it in hash.
HashKey* hash = new HashKey(HashKey(bro_int_t(index)));
BPF_Program* oldcode = filters.Lookup(hash);
if ( oldcode )
delete oldcode;
filters.Insert(hash, code);
delete hash;
return 1;
return PktSrc::PrecompileBPFFilter(index, filter).
}
int PcapSource::SetFilter(int index)
@ -245,9 +192,7 @@ int PcapSource::SetFilter(int index)
char errbuf[PCAP_ERRBUF_SIZE];
HashKey* hash = new HashKey(HashKey(bro_int_t(index)));
BPF_Program* code = filters.Lookup(hash);
delete hash;
BPF_Program* code = GetFilter(index);
if ( ! code )
{

View file

@ -4,10 +4,6 @@
#define IOSOURCE_PKTSRC_PCAP_SOURCE_H
#include "../PktSrc.h"
#include "BPF_Program.h"
#include "Dict.h"
declare(PDict,BPF_Program);
namespace iosource {
namespace pktsrc {
@ -42,8 +38,6 @@ private:
Stats stats;
pcap_t *pd;
uint32 netmask;
PDict(BPF_Program) filters;
struct pcap_pkthdr current_hdr;
struct pcap_pkthdr last_hdr;