af-packet: add support for BPF filter.

This patch adds support for BPF in AF_PACKET running
mode. The command line syntax is the same as the one
used of PF_RING.
The method is the same too: The pcap_compile__nopcap()
function is used to build the BPF filter. It is then
injected into the kernel with a setsockopt() call. If
the adding of the BPF fail, suricata exit.
remotes/origin/HEAD
Eric Leblond 13 years ago committed by Victor Julien
parent c85ee1e3f6
commit f2a6fb8a5a

@ -109,6 +109,7 @@ void *ParseAFPConfig(const char *iface)
char *tmpctype;
intmax_t value;
int boolval;
char *bpf_filter = NULL;
if (aconf == NULL) {
return NULL;
@ -130,6 +131,15 @@ void *ParseAFPConfig(const char *iface)
aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL;
aconf->DerefFunc = AFPDerefConfig;
aconf->flags = 0;
aconf->bpf_filter = NULL;
if (ConfGet("bpf-filter", &bpf_filter) == 1) {
if (strlen(bpf_filter) > 0) {
aconf->bpf_filter = bpf_filter;
SCLogInfo("Going to use command-line provided bpf filter '%s'",
aconf->bpf_filter);
}
}
/* Find initial node */
af_packet_node = ConfGetNode("af-packet");
@ -196,6 +206,17 @@ void *ParseAFPConfig(const char *iface)
return NULL;
}
/*load af_packet bpf filter*/
/* command line value has precedence */
if (ConfGet("bpf-filter", &bpf_filter) != 1) {
if (ConfGetChildValue(if_root, "bpf-filter", &bpf_filter) == 1) {
if (strlen(bpf_filter) > 0) {
aconf->bpf_filter = bpf_filter;
SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter);
}
}
}
if ((ConfGetChildValueInt(if_root, "buffer-size", &value)) == 1) {
aconf->buffer_size = value;
} else {

@ -72,6 +72,10 @@
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_arp.h>
#include <pcap/pcap.h>
#include <pcap/bpf.h>
#include <linux/filter.h>
#endif
#include <sys/mman.h>
@ -131,6 +135,9 @@ TmEcode NoAFPSupportExit(ThreadVars *tv, void *initdata, void **data)
#define POLL_TIMEOUT 100
/** protect pfring_set_bpf_filter, as it is not thread safe */
static SCMutex afpacket_bpf_set_filter_lock = PTHREAD_MUTEX_INITIALIZER;
enum {
AFP_READ_OK,
AFP_READ_FAILURE,
@ -170,6 +177,9 @@ typedef struct AFPThreadVars_
char iface[AFP_IFACE_NAME_LENGTH];
LiveDevice *livedev;
/* Filter */
char *bpf_filter;
/* socket buffer size */
int buffer_size;
int promisc;
@ -199,6 +209,8 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot);
TmEcode DecodeAFPThreadInit(ThreadVars *, void *, void **);
TmEcode DecodeAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
TmEcode AFPSetBPFFilter(AFPThreadVars *ptv);
/**
* \brief Registration Function for RecieveAFP.
* \todo Unit tests are needed for this module.
@ -851,11 +863,64 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose)
ptv->cooked = 1;
}
TmEcode rc;
rc = AFPSetBPFFilter(ptv);
if (rc == TM_ECODE_FAILED) {
SCLogError(SC_ERR_AFP_CREATE, "Set AF_PACKET bpf filter \"%s\" failed.", ptv->bpf_filter);
return -1;
}
/* Init is ok */
ptv->afp_state = AFP_STATE_UP;
return 0;
}
TmEcode AFPSetBPFFilter(AFPThreadVars *ptv)
{
struct bpf_program filter;
struct sock_fprog fcode;
int rc;
if (!ptv->bpf_filter)
return TM_ECODE_OK;
SCMutexLock(&afpacket_bpf_set_filter_lock);
SCLogInfo("Using BPF '%s' on iface '%s'",
ptv->bpf_filter,
ptv->iface);
if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */
ptv->datalink, /* linktype_arg */
&filter, /* program */
ptv->bpf_filter, /* const char *buf */
0, /* optimize */
0 /* mask */
) == -1) {
SCLogError(SC_ERR_AFP_CREATE, "Filter compilation failed.");
SCMutexUnlock(&afpacket_bpf_set_filter_lock);
return TM_ECODE_FAILED;
}
SCMutexUnlock(&afpacket_bpf_set_filter_lock);
if (filter.bf_insns == NULL) {
SCLogError(SC_ERR_AFP_CREATE, "Filter badly setup.");
return TM_ECODE_FAILED;
}
fcode.len = filter.bf_len;
fcode.filter = (struct sock_filter*)filter.bf_insns;
rc = setsockopt(ptv->socket, SOL_SOCKET, SO_ATTACH_FILTER, &fcode, sizeof(fcode));
if(rc == -1) {
SCLogError(SC_ERR_AFP_CREATE, "Failed to attach filter: %s", strerror(errno));
return TM_ECODE_FAILED;
}
SCMutexUnlock(&afpacket_bpf_set_filter_lock);
return TM_ECODE_OK;
}
/**
* \brief Init function for ReceiveAFP.
@ -914,6 +979,10 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) {
#endif
ptv->flags = afpconfig->flags;
if (afpconfig->bpf_filter) {
ptv->bpf_filter = afpconfig->bpf_filter;
}
char *active_runmode = RunmodeGetActive();
if (active_runmode && !strcmp("workers", active_runmode)) {
@ -941,7 +1010,6 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) {
ptv->datalen = T_DATA_SIZE;
#undef T_DATA_SIZE
*data = (void *)ptv;
afpconfig->DerefFunc(afpconfig);
@ -987,6 +1055,8 @@ TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data) {
}
ptv->datalen = 0;
ptv->bpf_filter = NULL;
close(ptv->socket);
SCReturnInt(TM_ECODE_OK);
}

@ -60,6 +60,7 @@ typedef struct AFPIfaceConfig_
/* misc use flags including ring mode */
int flags;
ChecksumValidationMode checksum_mode;
char *bpf_filter;
SC_ATOMIC_DECLARE(unsigned int, ref);
void (*DerefFunc)(void *);
} AFPIfaceConfig;

@ -233,6 +233,8 @@ af-packet:
# checksum off-loading is used.
# Warning: 'checksum-validation' must be set to yes to have any validation
#checksum-checks: kernel
# BPF filter to apply to this interface. The pcap filter syntax apply here.
#bpf-filter: port 80 or udp
- interface: eth1
threads: 1
cluster-id: 98

Loading…
Cancel
Save