zeek/src/iosource/BPF_Program.cc
2014-09-03 17:37:35 -07:00

148 lines
2.9 KiB
C++

// 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
// Simple heuristic to identify filters that always match, so that we can
// skip the filtering in that case. "ip or not ip" is Bro's default filter.
static bool filter_matches_anything(const char *filter)
{
return (! filter) || strlen(filter) == 0 || strcmp(filter, "ip or not ip") == 0;
}
BPF_Program::BPF_Program() : m_compiled(), m_matches_anything(false), 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;
m_matches_anything = filter_matches_anything(filter);
return true;
}
bool BPF_Program::Compile(int snaplen, int linktype, const char* filter,
uint32 netmask, char* errbuf, unsigned int errbuf_len,
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, my_error);
if ( err < 0 && errbuf )
safe_strncpy(errbuf, my_error, errbuf_len);
*errbuf = '\0';
#else
int err = pcap_compile_nopcap(snaplen, linktype, &m_program,
(char*) filter, optimize, netmask);
if ( err < 0 && errbuf && errbuf_len )
*errbuf = '\0';
#endif
if ( err == 0 )
{
m_compiled = true;
m_matches_anything = filter_matches_anything(filter);
}
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;
}
}