]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
log/pcap: add existing stream logging
authorEric Leblond <eric@regit.org>
Sat, 6 Feb 2021 21:18:25 +0000 (22:18 +0100)
committerVictor Julien <vjulien@oisf.net>
Thu, 26 May 2022 10:45:15 +0000 (12:45 +0200)
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
src/log-pcap.h

index c7c66dc563b339be58150b682e87f0b29419eafc..77c760719d0214bfb0392447b5a5633ef127577a 100644 (file)
@@ -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 <lz4frame.h>
@@ -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\", "
index 8b68d433292937f52d49c4e9a967f0f0bc37b518..ebfe305f44cb3ab16fba9b7414168d5807cb5591 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef __LOG_PCAP_H__
 #define __LOG_PCAP_H__
 
+#define PCAP_OUTPUT_BUFFER_SIZE 65535
+
 void PcapLogRegister(void);
 void PcapLogProfileSetup(void);