From e7b1c52c1ca018e9821012ebb5cf6816026456c0 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sat, 6 Feb 2021 22:18:25 +0100 Subject: [PATCH] log/pcap: add existing stream logging This patch update the alert mode of pcap logging. It uses the packet header data added to the TCP segments to build packets corresponding to the acked data that did trigger the alert. It then write it to the pcap file before starting to dump all packet for the flow that did alert. --- src/log-pcap.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/log-pcap.h | 2 ++ 2 files changed, 70 insertions(+) diff --git a/src/log-pcap.c b/src/log-pcap.c index c7c66dc563..77c760719d 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -26,7 +26,9 @@ */ #include "suricata-common.h" +#include "util-buffer.h" #include "util-fmemopen.h" +#include "stream-tcp-util.h" #ifdef HAVE_LIBLZ4 #include @@ -189,6 +191,7 @@ typedef struct PcapLogData_ { typedef struct PcapLogThreadData_ { PcapLogData *pcap_log; + MemBuffer *buf; } PcapLogThreadData; /* Pattern for extracting timestamp from pcap log files. */ @@ -516,6 +519,48 @@ static inline int PcapWrite( return TM_ECODE_OK; } +struct PcapLogCallbackContext { + PcapLogData *pl; + PcapLogCompressionData *connp; + MemBuffer *buf; +}; + +static int PcapLogSegmentCallback( + const Packet *p, TcpSegment *seg, void *data, const uint8_t *buf, uint32_t buflen) +{ + struct PcapLogCallbackContext *pctx = (struct PcapLogCallbackContext *)data; + + if (seg->pcap_hdr_storage->pktlen) { + pctx->pl->h->ts.tv_sec = seg->pcap_hdr_storage->ts.tv_sec; + pctx->pl->h->ts.tv_usec = seg->pcap_hdr_storage->ts.tv_usec; + pctx->pl->h->len = seg->pcap_hdr_storage->pktlen + buflen; + pctx->pl->h->caplen = seg->pcap_hdr_storage->pktlen + buflen; + MemBufferReset(pctx->buf); + MemBufferWriteRaw(pctx->buf, seg->pcap_hdr_storage->pkt_hdr, seg->pcap_hdr_storage->pktlen); + MemBufferWriteRaw(pctx->buf, buf, buflen); + + PcapWrite(pctx->pl, pctx->connp, (uint8_t *)pctx->buf->buffer, pctx->pl->h->len); + } + return 1; +} + +static void PcapLogDumpSegments( + PcapLogThreadData *td, PcapLogCompressionData *connp, const Packet *p) +{ + uint8_t flag; + /* check which side is packet */ + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag = STREAM_DUMP_TOCLIENT; + } else { + flag = STREAM_DUMP_TOSERVER; + } + flag |= STREAM_DUMP_HEADERS; + + /* Loop on segment from this side */ + struct PcapLogCallbackContext data = { td->pcap_log, connp, td->buf }; + StreamSegmentForEach(p, flag, PcapLogSegmentCallback, (void *)&data); +} + /** * \brief Pcap logging main function * @@ -611,6 +656,19 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) PCAPLOG_PROFILE_START; + /* if we are using alerted logging and if packet is first one with alert in flow + * then we need to dump in the pcap the stream acked by the packet */ + if ((p->flags & PKT_FIRST_ALERTS) && (td->pcap_log->conditional == LOGMODE_COND_ALERTS)) { + if (PKT_IS_TCP(p)) { + /* dump fake packets for all segments we have on acked by packet */ +#ifdef HAVE_LIBLZ4 + PcapLogDumpSegments(td, connp, p); +#else + PcapLogDumpSegments(td, NULL, p); +#endif + } + } + #ifdef HAVE_LIBLZ4 ret = PcapWrite(pl, comp, GET_PKT_DATA(p), len); #else @@ -984,6 +1042,12 @@ static TmEcode PcapLogDataInit(ThreadVars *t, const void *initdata, void **data) *data = (void *)td; + if (IsTcpSessionDumpingEnabled()) { + td->buf = MemBufferCreateNew(PCAP_OUTPUT_BUFFER_SIZE); + } else { + td->buf = NULL; + } + if (pl->max_files && (pl->mode == LOGMODE_MULTI || pl->threads == 1)) { #ifdef INIT_RING_BUFFER if (PcapLogInitRingBuffer(td->pcap_log) == TM_ECODE_FAILED) { @@ -1094,6 +1158,9 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data) PcapLogDataFree(pl); } + if (td->buf) + MemBufferFree(td->buf); + SCFree(td); return TM_ECODE_OK; } @@ -1456,6 +1523,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) if (s_conditional != NULL) { if (strcasecmp(s_conditional, "alerts") == 0) { pl->conditional = LOGMODE_COND_ALERTS; + EnableTcpSessionDumping(); } else if (strcasecmp(s_conditional, "all") != 0) { FatalError(SC_ERR_INVALID_ARGUMENT, "log-pcap: invalid conditional \"%s\". Valid options: \"all\", " diff --git a/src/log-pcap.h b/src/log-pcap.h index 8b68d43329..ebfe305f44 100644 --- a/src/log-pcap.h +++ b/src/log-pcap.h @@ -28,6 +28,8 @@ #ifndef __LOG_PCAP_H__ #define __LOG_PCAP_H__ +#define PCAP_OUTPUT_BUFFER_SIZE 65535 + void PcapLogRegister(void); void PcapLogProfileSetup(void);