]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: accept and flag ack of ZWP data
authorVictor Julien <vjulien@oisf.net>
Fri, 3 Mar 2023 07:02:35 +0000 (08:02 +0100)
committerVictor Julien <vjulien@oisf.net>
Wed, 29 Mar 2023 05:47:14 +0000 (07:47 +0200)
Tcp Zero Window Probes try to send a single byte payload to "probe" if
the window has reopened. This single byte is, if accepted, not retransmitted.

(cherry picked from commit 30a716a4ab102a3b39cca8c8dab84be88c092687)

rules/stream-events.rules
src/decode-events.c
src/decode-events.h
src/stream-tcp-private.h
src/stream-tcp.c

index cb1ae245e7ba126bc76f8566f180ea144a8071b5..0c69337e2ba4fba90a302523b6006eaf7945c14b 100644 (file)
@@ -42,6 +42,10 @@ alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYN resend"; stre
 alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYN resend with different seq"; stream-event:est_syn_resend_diff_seq; classtype:protocol-command-decode; sid:2210027; rev:2;)
 alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYN to client"; stream-event:est_syn_toclient; classtype:protocol-command-decode; sid:2210028; rev:2;)
 alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED invalid ack"; stream-event:est_invalid_ack; classtype:protocol-command-decode; sid:2210029; rev:2;)
+
+# ACK received for Zero Window Probe segment.
+#alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED ack for ZWP data"; stream-event:est_invalid_ack; classtype:protocol-command-decode; sid:2210065; rev:1;)
+
 alert tcp any any -> any any (msg:"SURICATA STREAM FIN invalid ack"; stream-event:fin_invalid_ack; classtype:protocol-command-decode; sid:2210030; rev:2;)
 alert tcp any any -> any any (msg:"SURICATA STREAM FIN1 ack with wrong seq"; stream-event:fin1_ack_wrong_seq; classtype:protocol-command-decode; sid:2210031; rev:2;)
 alert tcp any any -> any any (msg:"SURICATA STREAM FIN1 FIN with wrong seq"; stream-event:fin1_fin_wrong_seq; classtype:protocol-command-decode; sid:2210032; rev:2;)
@@ -98,4 +102,6 @@ alert tcp any any -> any any (msg:"SURICATA STREAM pkt seen on wrong thread"; st
 # Packet with FIN+SYN set
 alert tcp any any -> any any (msg:"SURICATA STREAM FIN SYN reuse"; stream-event:fin_syn; classtype:protocol-command-decode; sid:2210060; rev:1;)
 
-# next sid 2210065
+
+# next sid 2210066
+
index 78c3cd9acff05bcd12552546d7090b845870b67a..4e91ba092e55efed08ddc2b22bf14a8206d9a308 100644 (file)
@@ -699,6 +699,10 @@ const struct DecodeEvents_ DEvents[] = {
             "stream.est_invalid_ack",
             STREAM_EST_INVALID_ACK,
     },
+    {
+            "stream.est_ack_zwp_data",
+            STREAM_EST_ACK_ZWP_DATA,
+    },
     {
             "stream.fin_invalid_ack",
             STREAM_FIN_INVALID_ACK,
index e42afafae72256045a3cd7a97b9a90b3cc745519..1d582769b1691cbe8628ebafa651ff15acbed423 100644 (file)
@@ -248,6 +248,7 @@ enum {
     STREAM_EST_SYN_RESEND_DIFF_SEQ,
     STREAM_EST_SYN_TOCLIENT,
     STREAM_EST_INVALID_ACK,
+    STREAM_EST_ACK_ZWP_DATA,
     STREAM_FIN_INVALID_ACK,
     STREAM_FIN1_ACK_WRONG_SEQ,
     STREAM_FIN1_FIN_WRONG_SEQ,
index a85111275ec36f880a504648e811633380eecb95..10652c6d9382ef61edb58e63ed66a7ed1592d1d1 100644 (file)
@@ -191,6 +191,10 @@ enum TcpState
 /** SSN uses TCP Fast Open */
 #define STREAMTCP_FLAG_TCP_FAST_OPEN BIT_U32(15)
 
+/* zero window probe */
+#define STREAMTCP_FLAG_ZWP_TS BIT_U32(17)
+#define STREAMTCP_FLAG_ZWP_TC BIT_U32(18)
+
 /*
  * Per STREAM flags
  */
index b895bcd4727205cbe6088d5e100a69cd7d587e25..f4c7ce8420236799619173ec72264230915257b2 100644 (file)
@@ -2441,10 +2441,17 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack
                "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
                 TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p));
 
-    if (StreamTcpValidateAck(ssn, &(ssn->server), p) == -1) {
-        SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
-        StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
-        return -1;
+    const bool has_ack = (p->tcph->th_flags & TH_ACK) != 0;
+    if (has_ack) {
+        if ((ssn->flags & STREAMTCP_FLAG_ZWP_TC) && TCP_GET_ACK(p) == ssn->server.next_seq + 1) {
+            SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
+            StreamTcpSetEvent(p, STREAM_EST_ACK_ZWP_DATA);
+
+        } else if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
+            SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
+            StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
+            return -1;
+        }
     }
 
     /* check for Keep Alive */
@@ -2532,6 +2539,8 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack
     if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->client.next_seq && ssn->client.window == 0) {
         SCLogDebug("ssn %p: zero window probe", ssn);
         zerowindowprobe = 1;
+        ssn->flags |= STREAMTCP_FLAG_ZWP_TS;
+        StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
 
     } else if (SEQ_GEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_seq)) {
         StreamTcpUpdateNextSeq(ssn, &ssn->client, (TCP_GET_SEQ(p) + p->payload_len));
@@ -2603,10 +2612,17 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack
                " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
                 TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p));
 
-    if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
-        SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
-        StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
-        return -1;
+    const bool has_ack = (p->tcph->th_flags & TH_ACK) != 0;
+    if (has_ack) {
+        if ((ssn->flags & STREAMTCP_FLAG_ZWP_TS) && TCP_GET_ACK(p) == ssn->client.next_seq + 1) {
+            SCLogDebug("ssn %p: accepting ACK as it ACKs the one byte from the ZWP", ssn);
+            StreamTcpSetEvent(p, STREAM_EST_ACK_ZWP_DATA);
+
+        } else if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
+            SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
+            StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
+            return -1;
+        }
     }
 
     /* To get the server window value from the servers packet, when connection
@@ -2665,6 +2681,10 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack
     if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->server.next_seq && ssn->server.window == 0) {
         SCLogDebug("ssn %p: zero window probe", ssn);
         zerowindowprobe = 1;
+        ssn->flags |= STREAMTCP_FLAG_ZWP_TC;
+
+        /* accept the segment */
+        StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
 
     } else if (SEQ_GEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_seq)) {
         StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len));