]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
log/pcap: dump segments of both sides of tcp session.
authorScott Jordan <scottfgjordan@gmail.com>
Wed, 17 Feb 2021 22:36:42 +0000 (16:36 -0600)
committerVictor Julien <vjulien@oisf.net>
Thu, 26 May 2022 11:33:33 +0000 (13:33 +0200)
This patch updates tcp segment dumping to dump segments
from both sides of the session in order when capturing
alerts and tags.

src/log-pcap.c
src/stream-tcp.c
src/stream-tcp.h
src/stream.c
src/stream.h

index 631031e080bb5b64c67f614e5754e509ca915956..88c4f14be3eae6a9508a2d4048f688d09a7d17e5 100644 (file)
@@ -575,17 +575,11 @@ 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;
+    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);
+    StreamSegmentForSession(p, flag, PcapLogSegmentCallback, (void *)&data);
 }
 
 /**
@@ -702,6 +696,21 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
 #else
             PcapLogDumpSegments(td, NULL, p);
 #endif
+            /* PcapLogDumpSegment has writtens over the PcapLogData variables so need to update */
+            pl->h->ts.tv_sec = p->ts.tv_sec;
+            pl->h->ts.tv_usec = p->ts.tv_usec;
+            if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
+                rp = p->root;
+                SCMutexLock(&rp->tunnel_mutex);
+                pl->h->caplen = GET_PKT_LEN(rp);
+                pl->h->len = GET_PKT_LEN(rp);
+                len = sizeof(*pl->h) + GET_PKT_LEN(rp);
+                SCMutexUnlock(&rp->tunnel_mutex);
+            } else {
+                pl->h->caplen = GET_PKT_LEN(p);
+                pl->h->len = GET_PKT_LEN(p);
+                len = sizeof(*pl->h) + GET_PKT_LEN(p);
+            }
         }
     }
 
index 42c120fd9b56e0fa6ef2cbe0ea77f88e1162e46e..4fa19c74a760179f1b725b46c77b9182cc956feb 100644 (file)
@@ -6296,12 +6296,13 @@ void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Pack
 }
 
 /**
- * \brief Run callback function on each TCP segment
+ * \brief Run callback function on each TCP segment in a single direction.
  *
  * \note when stream engine is running in inline mode all segments are used,
  *       in IDS/non-inline mode only ack'd segments are iterated.
  *
  * \note Must be called under flow lock.
+ * \var flag determines the direction to run callback on (either to server or to client).
  *
  * \return -1 in case of error, the number of segment in case of success
  *
@@ -6354,6 +6355,100 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback
     return cnt;
 }
 
+/**
+ * \brief Run callback function on each TCP segment in both directions of a session.
+ *
+ * \note when stream engine is running in inline mode all segments are used,
+ *       in IDS/non-inline mode only ack'd segments are iterated.
+ *
+ * \note Must be called under flow lock.
+ *
+ * \return -1 in case of error, the number of segment in case of success
+ *
+ */
+int StreamTcpSegmentForSession(
+        const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
+{
+    int ret = 0;
+    int cnt = 0;
+
+    if (p->flow == NULL)
+        return 0;
+
+    TcpSession *ssn = (TcpSession *)p->flow->protoctx;
+
+    if (ssn == NULL) {
+        return -1;
+    }
+
+    TcpStream *server_stream = &(ssn->server);
+    TcpStream *client_stream = &(ssn->client);
+
+    TcpSegment *server_node = RB_ROOT(&(server_stream->seg_tree));
+    TcpSegment *client_node = RB_ROOT(&(client_stream->seg_tree));
+    if (server_node == NULL && client_node == NULL) {
+        return cnt;
+    }
+
+    while (server_node != NULL || client_node != NULL) {
+        const uint8_t *seg_data;
+        uint32_t seg_datalen;
+        if (server_node == NULL) {
+            /*
+             * This means the server side RB Tree has been completely searched,
+             * thus all that remains is to dump the TcpSegments on the client
+             * side.
+             */
+            StreamingBufferSegmentGetData(
+                    &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
+            ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
+            if (ret != 1) {
+                SCLogDebug("Callback function has failed");
+                return -1;
+            }
+            client_node = TCPSEG_RB_NEXT(client_node);
+        } else if (client_node == NULL) {
+            /*
+             * This means the client side RB Tree has been completely searched,
+             * thus all that remains is to dump the TcpSegments on the server
+             * side.
+             */
+            StreamingBufferSegmentGetData(
+                    &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
+            ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
+            if (ret != 1) {
+                SCLogDebug("Callback function has failed");
+                return -1;
+            }
+            server_node = TCPSEG_RB_NEXT(server_node);
+        } else {
+            if (TIMEVAL_EARLIER(
+                        client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) {
+                StreamingBufferSegmentGetData(
+                        &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen);
+                ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen);
+                if (ret != 1) {
+                    SCLogDebug("Callback function has failed");
+                    return -1;
+                }
+                client_node = TCPSEG_RB_NEXT(client_node);
+            } else {
+                StreamingBufferSegmentGetData(
+                        &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen);
+                ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen);
+                if (ret != 1) {
+                    SCLogDebug("Callback function has failed");
+                    return -1;
+                }
+                server_node = TCPSEG_RB_NEXT(server_node);
+            }
+        }
+
+        cnt++;
+    }
+    return cnt;
+}
+
 int StreamTcpBypassEnabled(void)
 {
     return (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS);
index 2f3ddb9ec0c8cb3dfb796ce22c69116d4b2421e8..7918bf468f093863e7187d9aa57ad5cc11235a5e 100644 (file)
@@ -124,6 +124,8 @@ Packet *StreamTcpPseudoSetup(Packet *, uint8_t *, uint32_t);
 int StreamTcpSegmentForEach(const Packet *p, uint8_t flag,
                         StreamSegmentCallback CallbackFunc,
                         void *data);
+int StreamTcpSegmentForSession(
+        const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data);
 void StreamTcpReassembleConfigEnableOverlapCheck(void);
 void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size);
 
index a09f125e3556275478c05ce1b15d2c63e3e1f820..59cc251f111ae9add85fa72189974ccc2559219c 100644 (file)
 #include "stream-tcp.h"
 #include "flow-util.h"
 
-/** \brief Run callback for all segments
+/** \brief Run callback for all segments in a single direction.
  *
  * Must be called under flow lock.
+ * \var flag determines the direction to run callback on (either to server or to client).
  *
  * \return -1 in case of error, the number of segment in case of success
  */
@@ -53,3 +54,28 @@ int StreamSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback Ca
     }
     return 0;
 }
+
+/** \brief Run callback for all segments on both directions of the session
+ *
+ * Must be called under flow lock.
+ *
+ * \return -1 in case of error, the number of segments in case of success.
+ */
+int StreamSegmentForSession(
+        const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
+{
+    switch (p->proto) {
+        case IPPROTO_TCP:
+            return StreamTcpSegmentForSession(p, flag, CallbackFunc, data);
+            break;
+#ifdef DEBUG
+        case IPPROTO_UDP:
+            SCLogWarning(SC_ERR_UNKNOWN_PROTOCOL, "UDP is currently unsupported");
+            break;
+        default:
+            SCLogWarning(SC_ERR_UNKNOWN_PROTOCOL, "This protocol is currently unsupported");
+            break;
+#endif
+    }
+    return 0;
+}
index e8f2cad7e0d1e6ff514029d66511d022aae8fe54..583747ca558679f69d2052f50e615b19c5bfcd5f 100644 (file)
@@ -38,6 +38,8 @@ typedef int (*StreamSegmentCallback)(
 int StreamSegmentForEach(const Packet *p, uint8_t flag,
                          StreamSegmentCallback CallbackFunc,
                          void *data);
+int StreamSegmentForSession(
+        const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data);
 
 #endif /* __STREAM_H__ */