]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: Dup-ACK detection
authorVictor Julien <vjulien@oisf.net>
Tue, 21 Feb 2023 09:08:31 +0000 (10:08 +0100)
committerVictor Julien <vjulien@oisf.net>
Fri, 24 Feb 2023 09:45:38 +0000 (10:45 +0100)
Modeled after Wiresharks Dup-ACK detection.

src/output-eve-stream.c
src/stream-tcp-private.h
src/stream-tcp.c

index 1b1075321a84c75ab98f8c81aa19080b7bb50e02..1775783becd560a60cff2ad78b0c843c8be4b937 100644 (file)
@@ -342,6 +342,8 @@ static int EveStreamLogger(ThreadVars *tv, void *thread_data, const Packet *p)
             jb_append_string(js, "event_set");
         if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_STATE_UPDATE)
             jb_append_string(js, "state_update");
+        if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_DUP_ACK)
+            jb_append_string(js, "dup_ack");
         jb_close(js);
     }
     jb_close(js);
index 77d0dc43073bbfa91bbb4645ea04937b41af304c..b410b4f1da4ba9b0fcf61a6dc51838f656c8d48b 100644 (file)
@@ -306,6 +306,7 @@ typedef struct TcpSession_ {
 #define STREAM_PKT_FLAG_KEEPALIVEACK            BIT_U16(4)
 #define STREAM_PKT_FLAG_WINDOWUPDATE            BIT_U16(5)
 #define STREAM_PKT_FLAG_EVENTSET                BIT_U16(6)
+#define STREAM_PKT_FLAG_DUP_ACK                 BIT_U16(7)
 
 #define STREAM_PKT_FLAG_SET(p, f) (p)->tcpvars.stream_pkt_flags |= (f)
 
index 464ef75292aefe1dcd77d7a5dbd12e002d0d7a3c..d13636742162413ed30de6a6204d414dffd48a0f 100644 (file)
@@ -2799,6 +2799,44 @@ static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
     SCReturnUInt(ack);
 }
 
+/** \internal
+ *  \brief check if an ACK packet is a dup-ACK
+ */
+static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p)
+{
+    if (ssn->state < TCP_ESTABLISHED)
+        return false;
+    if (p->payload_len != 0)
+        return false;
+    if ((p->tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK)
+        return false;
+
+    const TcpStream *snd, *rcv;
+    if (PKT_IS_TOCLIENT(p)) {
+        snd = &ssn->server;
+        rcv = &ssn->client;
+    } else {
+        snd = &ssn->client;
+        rcv = &ssn->server;
+    }
+
+    const uint32_t pkt_win = TCP_GET_WINDOW(p) << snd->wscale;
+    if (pkt_win == 0 || rcv->window == 0)
+        return false;
+    if (pkt_win != rcv->window)
+        return false;
+
+    if (TCP_GET_SEQ(p) != snd->next_seq)
+        return false;
+    if (TCP_GET_ACK(p) != rcv->last_ack)
+        return false;
+
+    SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn,
+            p->pcap_cnt, TCP_GET_SEQ(p), TCP_GET_ACK(p), pkt_win, snd->next_seq, snd->last_ack,
+            rcv->window, snd->next_seq, rcv->last_ack, rcv->window);
+    return true;
+}
+
 /** \internal
  *  \brief check if a ACK packet is outdated so processing can be fast tracked
  *
@@ -5254,6 +5292,11 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
         }
         StreamTcpClearKeepAliveFlag(ssn, p);
 
+        if (StreamTcpPacketIsDupAck(ssn, p) == true) {
+            STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_DUP_ACK);
+            // TODO see if we can skip work on these
+        }
+
         /* if packet is not a valid window update, check if it is perhaps
          * a bad window update that we should ignore (and alert on) */
         if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {