pcap-log: add bpf filter for packets that are logged

Add an optional bpf filter to pcap-log. If set, packets must match the
filter to be logged, otherwise they will be ignored.

This allows a user to limit what is logged to disk if they have pcap-log
enabled, but still inspect all data captured.

Ticket: #6832
pull/12968/head
Jason Ish 3 months ago committed by Victor Julien
parent c203ff774d
commit 2fce106aec

@ -497,6 +497,8 @@ By default all packets are logged except:
- TCP streams beyond stream.reassembly.depth
- encrypted streams after the key exchange
- If a ``bpf-filter`` is set, packets that don't match the filter will
not be logged
It is possible to do conditional pcap logging by using the `conditional`
option in the pcap-log section. By default the variable is set to `all`
@ -520,6 +522,11 @@ the alert.
mode: normal # "normal" or multi
conditional: alerts
# A BPF filter that will be applied to all packets being
# logged. If set, packets must match this filter otherwise they
# will not be logged.
#bpf-filter:
In ``normal`` mode a pcap file "filename" is created in the default-log-dir or as
specified by "dir". ``normal`` mode is generally not as performant as ``multi``
mode.

@ -140,6 +140,7 @@ typedef struct PcapLogCompressionData_ {
typedef struct PcapLogData_ {
int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */
int honor_pass_rules; /**< don't log if pass rules have matched */
char *bpf_filter; /**< bpf filter to apply to output */
SCMutex plog_lock;
uint64_t pkt_cnt; /**< total number of packets */
struct pcap_pkthdr *h; /**< pcap header struct */
@ -150,6 +151,7 @@ typedef struct PcapLogData_ {
uint64_t size_limit; /**< file size limit */
pcap_t *pcap_dead_handle; /**< pcap_dumper_t needs a handle */
pcap_dumper_t *pcap_dumper; /**< actually writes the packets */
struct bpf_program *bpfp; /**< compiled bpf program */
uint64_t profile_data_size; /**< track in bytes how many bytes we wrote */
uint32_t file_cnt; /**< count of pcap files we currently have */
uint32_t max_files; /**< maximum files to use in ring buffer mode */
@ -391,6 +393,18 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p)
SCLogDebug("Error opening dead pcap handle");
return TM_ECODE_FAILED;
}
if (pl->bpfp == NULL && pl->bpf_filter) {
struct bpf_program bpfp;
if (pcap_compile(pl->pcap_dead_handle, &bpfp, pl->bpf_filter, 0,
PCAP_NETMASK_UNKNOWN) == PCAP_ERROR) {
FatalError("Failed to compile BPF filter, aborting: %s: %s", pl->bpf_filter,
pcap_geterr(pl->pcap_dead_handle));
} else {
pl->bpfp = SCCalloc(1, sizeof(*pl->bpfp));
*pl->bpfp = bpfp;
}
}
}
if (pl->pcap_dumper == NULL) {
@ -483,6 +497,14 @@ static inline int PcapWrite(
{
struct timeval current_dump;
gettimeofday(&current_dump, NULL);
if (pl->bpfp) {
if (pcap_offline_filter(pl->bpfp, pl->h, data) == 0) {
SCLogDebug("Packet doesn't match filter, will not be logged.");
return TM_ECODE_OK;
}
}
pcap_dump((u_char *)pl->pcap_dumper, pl->h, data);
if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) {
pl->size_current += len;
@ -1142,6 +1164,11 @@ static void PcapLogDataFree(PcapLogData *pl)
pcap_close(pl->pcap_dead_handle);
}
if (pl->bpfp) {
pcap_freecode(pl->bpfp);
SCFree(pl->bpfp);
}
#ifdef HAVE_LIBLZ4
if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) {
SCFree(pl->compression.buffer);
@ -1608,6 +1635,8 @@ static OutputInitResult PcapLogInitCtx(SCConfNode *conf)
}
}
pl->bpf_filter = conf == NULL ? NULL : (char *)SCConfNodeLookupChildValue(conf, "bpf-filter");
/* create the output ctx and send it back */
OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));

@ -448,6 +448,11 @@ outputs:
# to log only flow tagged via the "tag" keyword
#conditional: all
# A BPF filter that will be applied to all packets being
# logged. If set, packets must match this filter otherwise they
# will not be logged.
#bpf-filter:
# a full alert log containing much information for signature writers
# or for investigating suspected false positives.
- alert-debug:

Loading…
Cancel
Save