]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: detect spurious retransmissions early
authorVictor Julien <vjulien@oisf.net>
Tue, 22 Mar 2022 16:00:29 +0000 (17:00 +0100)
committerVictor Julien <vjulien@oisf.net>
Tue, 7 Jun 2022 08:37:53 +0000 (10:37 +0200)
src/decode-events.c
src/decode-events.h
src/stream-tcp.c

index cd93e310523480e60b2da0529154ae4f018e1424..95fa1176db5ddcffef5275a22025b6e23391eedc 100644 (file)
@@ -802,6 +802,10 @@ const struct DecodeEvents_ DEvents[] = {
             "stream.pkt_retransmission",
             STREAM_PKT_RETRANSMISSION,
     },
+    {
+            "stream.pkt_spurious_retransmission",
+            STREAM_PKT_SPURIOUS_RETRANSMISSION,
+    },
     {
             "stream.pkt_bad_window_update",
             STREAM_PKT_BAD_WINDOW_UPDATE,
index 715b46e8d14a5b48afa945454ddc4e8e61f56a5f..8ec9123a8214160ed4ed0546b7d0c589142ee953 100644 (file)
@@ -277,6 +277,7 @@ enum {
     STREAM_PKT_BROKEN_ACK,
     STREAM_RST_INVALID_ACK,
     STREAM_PKT_RETRANSMISSION,
+    STREAM_PKT_SPURIOUS_RETRANSMISSION,
     STREAM_PKT_BAD_WINDOW_UPDATE,
 
     STREAM_SUSPECTED_RST_INJECT,
index d1c5371c8ef148c4d405ebd18bcb43cafc7979e4..f6a76a190f25b49b887790769b420fc48b412987 100644 (file)
@@ -2560,6 +2560,33 @@ static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p)
     return false;
 }
 
+/** \internal
+ *  \brief check if packet is before ack'd windows
+ *  If packet is before last ack, we will not accept it
+ */
+static bool StreamTcpPacketIsSpuriousRetransmission(TcpSession *ssn, Packet *p)
+{
+    TcpStream *stream;
+    if (PKT_IS_TOCLIENT(p)) {
+        stream = &ssn->server;
+    } else {
+        stream = &ssn->client;
+    }
+    /* take base_seq into account to avoid edge cases where last_ack might be
+     * too far ahead during heavy packet loss */
+    const uint32_t le = MIN(stream->last_ack, stream->base_seq);
+    if (p->payload_len > 0 && (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, le))) {
+        SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) "
+                   "last_ack %u",
+                ssn, TCP_GET_SEQ(p), TCP_GET_SEQ(p) + p->payload_len, stream->last_ack);
+        return true;
+    }
+    SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ "
+               "%u(%u) last_ack %u, le %u",
+            ssn, TCP_GET_SEQ(p), TCP_GET_SEQ(p) + p->payload_len, stream->last_ack, le);
+    return false;
+}
+
 /**
  *  \brief  Function to handle the TCP_ESTABLISHED state. The function handles
  *          ACK, FIN, RST packets and correspondingly changes the connection
@@ -4960,6 +4987,11 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
             }
         }
 
+        if (StreamTcpPacketIsSpuriousRetransmission(ssn, p)) {
+            StreamTcpSetEvent(p, STREAM_PKT_SPURIOUS_RETRANSMISSION);
+            goto error;
+        }
+
         /* handle the per 'state' logic */
         if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->state) < 0)
             goto error;