]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: unify ack'd right edge handling
authorVictor Julien <vjulien@oisf.net>
Sat, 11 Dec 2021 07:12:31 +0000 (08:12 +0100)
committerJeff Lucovsky <jeff@lucovsky.org>
Sat, 15 Jan 2022 13:01:17 +0000 (08:01 -0500)
Use util function in all code needing the ack'd data.

(cherry picked from commit 258415b23f455e3aaee6d97a0e485e5690959011)

src/stream-tcp-reassemble.c

index 514e906ed4150360b7e16326952da4041281bd38..a67a072b753365b92f94897bb2bd821c1e0806ca 100644 (file)
@@ -321,6 +321,15 @@ void StreamTcpReturnStreamSegments (TcpStream *stream)
     }
 }
 
+static inline uint64_t GetAbsLastAck(const TcpStream *stream)
+{
+    if (STREAM_LASTACK_GT_BASESEQ(stream)) {
+        return STREAM_BASE_OFFSET(stream) + (stream->last_ack - stream->base_seq);
+    } else {
+        return STREAM_BASE_OFFSET(stream);
+    }
+}
+
 #ifdef UNITTESTS
 /** \internal
  *  \brief check if segments falls before stream 'offset' */
@@ -746,44 +755,21 @@ static int StreamTcpReassembleRawCheckLimit(const TcpSession *ssn,
     if (p->flags & PKT_PSEUDO_STREAM_END)
         SCReturnInt(1);
 
+    const uint64_t last_ack_abs = GetAbsLastAck(stream);
+    int64_t diff = last_ack_abs - STREAM_RAW_PROGRESS(stream);
+    int64_t chunk_size = PKT_IS_TOSERVER(p) ? (int64_t)stream_config.reassembly_toserver_chunk_size
+                                            : (int64_t)stream_config.reassembly_toclient_chunk_size;
+
     /* check if we have enough data to do raw reassembly */
-    if (PKT_IS_TOSERVER(p)) {
-        if (STREAM_LASTACK_GT_BASESEQ(stream)) {
-            uint32_t delta = stream->last_ack - stream->base_seq;
-            /* get max absolute offset */
-            uint64_t max_offset = STREAM_BASE_OFFSET(stream) + delta;
-
-            int64_t diff = max_offset - STREAM_RAW_PROGRESS(stream);
-            if ((int64_t)stream_config.reassembly_toserver_chunk_size <= diff) {
-                SCReturnInt(1);
-            } else {
-                SCLogDebug("toserver min chunk len not yet reached: "
-                        "last_ack %"PRIu32", ra_raw_base_seq %"PRIu32", %"PRIu32" < "
-                        "%"PRIu32"", stream->last_ack, stream->base_seq,
-                        (stream->last_ack - stream->base_seq),
-                        stream_config.reassembly_toserver_chunk_size);
-                SCReturnInt(0);
-            }
-        }
+    if (chunk_size <= diff) {
+        SCReturnInt(1);
     } else {
-        if (STREAM_LASTACK_GT_BASESEQ(stream)) {
-            uint32_t delta = stream->last_ack - stream->base_seq;
-            /* get max absolute offset */
-            uint64_t max_offset = STREAM_BASE_OFFSET(stream) + delta;
-
-            int64_t diff = max_offset - STREAM_RAW_PROGRESS(stream);
-
-            if ((int64_t)stream_config.reassembly_toclient_chunk_size <= diff) {
-                SCReturnInt(1);
-            } else {
-                SCLogDebug("toclient min chunk len not yet reached: "
-                        "last_ack %"PRIu32", base_seq %"PRIu32",  %"PRIu32" < "
-                        "%"PRIu32"", stream->last_ack, stream->base_seq,
-                        (stream->last_ack - stream->base_seq),
-                        stream_config.reassembly_toclient_chunk_size);
-                SCReturnInt(0);
-            }
-        }
+        SCLogDebug("%s min chunk len not yet reached: "
+                   "last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
+                   "%" PRIi64,
+                PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
+                (stream->last_ack - stream->base_seq), chunk_size);
+        SCReturnInt(0);
     }
 
     SCReturnInt(0);
@@ -958,51 +944,43 @@ static void GetAppBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data
 static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p)
 {
     const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
-    uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream);
-
-    if (STREAM_LASTACK_GT_BASESEQ(stream)) {
-        /* get window of data that is acked */
-        const uint32_t delta = stream->last_ack - stream->base_seq;
-        /* get max absolute offset */
-        last_ack_abs += delta;
-
-        const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
-        last_ack_abs -= ackadded;
-
-        SCLogDebug("last_ack %u abs %"PRIu64, stream->last_ack, last_ack_abs);
-        SCLogDebug("next_seq %u", stream->next_seq);
-
-        /* if last_ack_abs is beyond the app_progress data that we haven't seen
-         * has been ack'd. This looks like a GAP. */
-        if (last_ack_abs > app_progress) {
-            /* however, we can accept ACKs a bit too liberally. If last_ack
-             * is beyond next_seq, we only consider it a gap now if we do
-             * already have data beyond the gap. */
-            if (SEQ_GT(stream->last_ack, stream->next_seq)) {
-                if (RB_EMPTY(&stream->sb.sbb_tree)) {
-                    SCLogDebug("packet %"PRIu64": no GAP. "
-                            "next_seq %u < last_ack %u, but no data in list",
+    const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
+    const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
+
+    SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
+    SCLogDebug("next_seq %u", stream->next_seq);
+
+    /* if last_ack_abs is beyond the app_progress data that we haven't seen
+     * has been ack'd. This looks like a GAP. */
+    if (last_ack_abs > app_progress) {
+        /* however, we can accept ACKs a bit too liberally. If last_ack
+         * is beyond next_seq, we only consider it a gap now if we do
+         * already have data beyond the gap. */
+        if (SEQ_GT(stream->last_ack, stream->next_seq)) {
+            if (RB_EMPTY(&stream->sb.sbb_tree)) {
+                SCLogDebug("packet %" PRIu64 ": no GAP. "
+                           "next_seq %u < last_ack %u, but no data in list",
+                        p->pcap_cnt, stream->next_seq, stream->last_ack);
+                return false;
+            } else {
+                const uint64_t next_seq_abs =
+                        STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
+                const StreamingBufferBlock *blk = stream->sb.head;
+                if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
+                    /* ack'd data after the gap */
+                    SCLogDebug("packet %" PRIu64 ": GAP. "
+                               "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
                             p->pcap_cnt, stream->next_seq, stream->last_ack);
-                    return false;
-                } else {
-                    const uint64_t next_seq_abs = STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
-                    const StreamingBufferBlock *blk = stream->sb.head;
-                    if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
-                        /* ack'd data after the gap */
-                        SCLogDebug("packet %"PRIu64": GAP. "
-                                "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
-                                p->pcap_cnt, stream->next_seq, stream->last_ack);
-                        return true;
-                    }
+                    return true;
                 }
             }
-
-            SCLogDebug("packet %"PRIu64": GAP! "
-                    "last_ack_abs %"PRIu64" > app_progress %"PRIu64", "
-                    "but we have no data.",
-                    p->pcap_cnt, last_ack_abs, app_progress);
-            return true;
         }
+
+        SCLogDebug("packet %" PRIu64 ": GAP! "
+                   "last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
+                   "but we have no data.",
+                p->pcap_cnt, last_ack_abs, app_progress);
+        return true;
     }
     SCLogDebug("packet %"PRIu64": no GAP. "
             "last_ack_abs %"PRIu64" <= app_progress %"PRIu64,
@@ -1499,12 +1477,7 @@ static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p,
          * - if our block matches or starts before last ack, return right edge of
          *   our block.
          */
-        uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream);
-        if (STREAM_LASTACK_GT_BASESEQ(stream)) {
-            uint32_t delta = stream->last_ack - stream->base_seq;
-            /* get max absolute offset */
-            last_ack_abs += delta;
-        }
+        const uint64_t last_ack_abs = GetAbsLastAck(stream);
         SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
 
         if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) {
@@ -1563,7 +1536,9 @@ static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream,
 
     StreamingBufferBlock *iter = NULL;
     uint64_t progress = progress_in;
-    uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream); /* absolute right edge of ack'd data */
+    /* absolute right edge of ack'd data */
+    const uint64_t last_ack_abs = GetAbsLastAck(stream);
+    SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
 
     /* if the app layer triggered a flush, and we're supposed to
      * use a minimal inspect depth, we actually take the app progress
@@ -1594,15 +1569,6 @@ static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream,
 
     SCLogDebug("progress %"PRIu64", min inspect depth %u %s", progress, stream->min_inspect_depth, stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW":"(no trigger)");
 
-    /* get window of data that is acked */
-    if (STREAM_LASTACK_GT_BASESEQ(stream)) {
-        SCLogDebug("last_ack %u, base_seq %u", stream->last_ack, stream->base_seq);
-        uint32_t delta = stream->last_ack - stream->base_seq;
-        /* get max absolute offset */
-        last_ack_abs += delta;
-        SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
-    }
-
     /* loop through available buffers. On no packet loss we'll have a single
      * iteration. On missing data we'll walk the blocks */
     while (1) {