]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: handle zero window probe acks 8638/head
authorVictor Julien <vjulien@oisf.net>
Mon, 6 Mar 2023 15:06:25 +0000 (16:06 +0100)
committerVictor Julien <vjulien@oisf.net>
Tue, 28 Mar 2023 12:05:57 +0000 (14:05 +0200)
These can be skipped for the most part.

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

index e0d98fb8ea6d0e460f90e7a41432c547ac774519..f986cdff4dc59f48ffa29f79d688baa292eb86b6 100644 (file)
@@ -357,6 +357,8 @@ static int EveStreamLogger(ThreadVars *tv, void *thread_data, const Packet *p)
             jb_append_string(js, "tcp_port_reuse");
         if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE)
             jb_append_string(js, "zero_window_probe");
+        if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE_ACK)
+            jb_append_string(js, "zero_window_probe_ack");
         jb_close(js);
     }
     jb_close(js);
index b827535eff178764d5d1160e6c590e1ade7dffa8..a06e9cf353e791713c1750ddd5cd985ecd481e67 100644 (file)
@@ -318,6 +318,7 @@ typedef struct TcpSession_ {
 #define STREAM_PKT_FLAG_ACK_UNSEEN_DATA         BIT_U16(9)
 #define STREAM_PKT_FLAG_TCP_PORT_REUSE          BIT_U16(10)
 #define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE      BIT_U16(11)
+#define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE_ACK  BIT_U16(12)
 
 #define STREAM_PKT_FLAG_SET(p, f) (p)->tcpvars.stream_pkt_flags |= (f)
 
index 904769b4dd9809cc3cfa985220d585b9e1893c31..2bc40137bb72f653a0b03df9e03953dd1576b2f0 100644 (file)
@@ -2851,6 +2851,42 @@ static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
     SCReturnUInt(ack);
 }
 
+static bool StreamTcpPacketIsZeroWindowProbeAck(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;
+        if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TS))
+            return false;
+    } else {
+        snd = &ssn->client;
+        rcv = &ssn->server;
+        if (!(ssn->flags & STREAMTCP_FLAG_ZWP_TC))
+            return false;
+    }
+
+    const uint32_t pkt_win = TCP_GET_WINDOW(p) << snd->wscale;
+    if (pkt_win != 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 " is a Zero Window Probe ACK", ssn, p->pcap_cnt);
+    return true;
+}
+
 /** \internal
  *  \brief check if an ACK packet is a dup-ACK
  */
@@ -5364,6 +5400,17 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
         }
         StreamTcpClearKeepAliveFlag(ssn, p);
 
+        const bool is_zwp_ack = StreamTcpPacketIsZeroWindowProbeAck(ssn, p);
+        if (PKT_IS_TOCLIENT(p)) {
+            ssn->flags &= ~STREAMTCP_FLAG_ZWP_TS;
+        } else {
+            ssn->flags &= ~STREAMTCP_FLAG_ZWP_TC;
+        }
+        if (is_zwp_ack) {
+            STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE_ACK);
+            goto skip;
+        }
+
         if (StreamTcpPacketIsDupAck(ssn, p) == true) {
             STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_DUP_ACK);
             // TODO see if we can skip work on these