mirror of
https://github.com/zeek/zeek.git
synced 2025-10-13 20:18:20 +00:00
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:
parent
0186061aa8
commit
ce9f16490c
8 changed files with 110 additions and 85 deletions
|
@ -1,131 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "BPF_Program.h"
|
||||
|
||||
#ifdef DONT_HAVE_LIBPCAP_PCAP_FREECODE
|
||||
extern "C" {
|
||||
#include "pcap-int.h"
|
||||
|
||||
int pcap_freecode(pcap_t* unused, struct bpf_program* program)
|
||||
{
|
||||
program->bf_len = 0;
|
||||
|
||||
if ( program->bf_insns )
|
||||
{
|
||||
free((char*) program->bf_insns); // copied from libpcap
|
||||
program->bf_insns = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcap_t* pcap_open_dead(int linktype, int snaplen)
|
||||
{
|
||||
pcap_t* p;
|
||||
|
||||
p = (pcap_t*) malloc(sizeof(*p));
|
||||
if ( ! p )
|
||||
return 0;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->fd = -1;
|
||||
p->snapshot = snaplen;
|
||||
p->linktype = linktype;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int pcap_compile_nopcap(int snaplen_arg, int linktype_arg,
|
||||
struct bpf_program* program, char* buf,
|
||||
int optimize, bpf_u_int32 mask)
|
||||
{
|
||||
pcap_t* p;
|
||||
int ret;
|
||||
|
||||
p = pcap_open_dead(linktype_arg, snaplen_arg);
|
||||
if ( ! p )
|
||||
return -1;
|
||||
|
||||
ret = pcap_compile(p, program, buf, optimize, mask);
|
||||
pcap_close(p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BPF_Program::BPF_Program() : m_compiled(), m_program()
|
||||
{
|
||||
}
|
||||
|
||||
BPF_Program::~BPF_Program()
|
||||
{
|
||||
FreeCode();
|
||||
}
|
||||
|
||||
bool BPF_Program::Compile(pcap_t* pcap, const char* filter, uint32 netmask,
|
||||
char* errbuf, unsigned int errbuf_len, bool optimize)
|
||||
{
|
||||
if ( ! pcap )
|
||||
return false;
|
||||
|
||||
FreeCode();
|
||||
|
||||
if ( pcap_compile(pcap, &m_program, (char *) filter, optimize, netmask) < 0 )
|
||||
{
|
||||
if ( errbuf )
|
||||
safe_snprintf(errbuf, errbuf_len,
|
||||
"pcap_compile(%s): %s", filter,
|
||||
pcap_geterr(pcap));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_compiled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BPF_Program::Compile(int snaplen, int linktype, const char* filter,
|
||||
uint32 netmask, char* errbuf, bool optimize)
|
||||
{
|
||||
FreeCode();
|
||||
|
||||
#ifdef LIBPCAP_PCAP_COMPILE_NOPCAP_HAS_ERROR_PARAMETER
|
||||
char my_error[PCAP_ERRBUF_SIZE];
|
||||
|
||||
int err = pcap_compile_nopcap(snaplen, linktype, &m_program,
|
||||
(char *) filter, optimize, netmask, error);
|
||||
if ( err < 0 && errbuf )
|
||||
safe_strncpy(errbuf, my_errbuf, PCAP_ERRBUF_SIZE);
|
||||
#else
|
||||
int err = pcap_compile_nopcap(snaplen, linktype, &m_program,
|
||||
(char*) filter, optimize, netmask);
|
||||
#endif
|
||||
if ( err == 0 )
|
||||
m_compiled = true;
|
||||
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
bpf_program* BPF_Program::GetProgram()
|
||||
{
|
||||
return m_compiled ? &m_program : 0;
|
||||
}
|
||||
|
||||
void BPF_Program::FreeCode()
|
||||
{
|
||||
if ( m_compiled )
|
||||
{
|
||||
#ifdef DONT_HAVE_LIBPCAP_PCAP_FREECODE
|
||||
pcap_freecode(NULL, &m_program);
|
||||
#else
|
||||
pcap_freecode(&m_program);
|
||||
#endif
|
||||
m_compiled = false;
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef bpf_program_h
|
||||
#define bpf_program_h
|
||||
|
||||
extern "C" {
|
||||
#include <pcap.h>
|
||||
}
|
||||
|
||||
#include "util.h"
|
||||
|
||||
// BPF_Programs are an abstraction around struct bpf_program,
|
||||
// to create a clean facility for creating, compiling, and
|
||||
// freeing such programs.
|
||||
|
||||
class BPF_Program {
|
||||
public:
|
||||
// Creates an empty, uncompiled BPF program.
|
||||
BPF_Program();
|
||||
~BPF_Program();
|
||||
|
||||
// Creates a BPF program for the given pcap handle.
|
||||
// Parameters are like in pcap_compile(). Returns true
|
||||
// for successful compilation, false otherwise.
|
||||
bool Compile(pcap_t* pcap, const char* filter, uint32 netmask,
|
||||
char* errbuf = 0, unsigned int errbuf_len = 0,
|
||||
bool optimize = true);
|
||||
|
||||
// Creates a BPF program when no pcap handle is around,
|
||||
// similarly to pcap_compile_nopcap(). Parameters are
|
||||
// similar. Returns true on success.
|
||||
bool Compile(int snaplen, int linktype, const char* filter,
|
||||
uint32 netmask, char* errbuf = 0, bool optimize = true);
|
||||
|
||||
// Returns true if this program currently contains compiled
|
||||
// code, false otherwise.
|
||||
bool IsCompiled() { return m_compiled; }
|
||||
|
||||
// Accessor to the compiled program. Returns nil when
|
||||
// no program is currently compiled.
|
||||
bpf_program* GetProgram();
|
||||
|
||||
protected:
|
||||
void FreeCode();
|
||||
|
||||
// (I like to prefix member variables with m_, makes it clear
|
||||
// in the implementation whether it's a global or not. --ck)
|
||||
bool m_compiled;
|
||||
struct bpf_program m_program;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
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();
|
||||
if ( ! pd )
|
||||
// Was closed, couldn't get header size.
|
||||
return;
|
||||
|
||||
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();
|
||||
SetHdrSize();
|
||||
|
||||
if ( ! pd )
|
||||
// Was closed, unknown link layer type.
|
||||
return;
|
||||
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));
|
||||
|
||||
props.selectable_fd = fileno(pcap_file(pd));
|
||||
|
||||
if ( props.selectable_fd < 0 )
|
||||
InternalError("OS does not support selectable pcap fd");
|
||||
}
|
||||
|
||||
else
|
||||
Close();
|
||||
if ( props.selectable_fd < 0 )
|
||||
InternalError("OS does not support selectable pcap fd");
|
||||
|
||||
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 )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue