]> 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>
Tue, 28 Mar 2023 12:05:57 +0000 (14:05 +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.

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

index 661e3d2b518b909dbf477b47713da607378a6604..e589c81b134d78958e3b8698ed9a2ab73cc583a5 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;)
@@ -105,5 +109,5 @@ alert tcp any any -> any any (msg:"SURICATA STREAM FIN SYN reuse"; stream-event:
 # Depth setting reached for a stream. Very common in normal traffic, so disable by default.
 #alert tcp any any -> any any (msg:"SURICATA STREAM reassembly depth reached"; stream-event:reassembly_depth_reached; classtype:protocol-command-decode; sid:2210062; rev:1;)
 
-# next sid 2210065
+# next sid 2210066
 
index 21c8eaba2831dedca009029698bd2610f5c4f558..e0d9fd90a19f32f4d8a7026f05335a32524f4fef 100644 (file)
@@ -730,6 +730,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 2555ed28b6f423b6feb71510a729c098da91e279..6e2d638c3c1cba92424f3f7e53d4d9f4020fc91f 100644 (file)
@@ -259,6 +259,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 1b40022a284592544b0073a7b3a59a35bdaf79ea..b827535eff178764d5d1160e6c590e1ade7dffa8 100644 (file)
@@ -204,6 +204,9 @@ enum TcpState {
 #define STREAMTCP_FLAG_TCP_FAST_OPEN BIT_U32(15)
 /** SYN/ACK ignored the data while ACKing the SYN */
 #define STREAMTCP_FLAG_TFO_DATA_IGNORED BIT_U32(16)
+/* zero window probe */
+#define STREAMTCP_FLAG_ZWP_TS BIT_U32(17)
+#define STREAMTCP_FLAG_ZWP_TC BIT_U32(18)
 
 /*
  * Per STREAM flags
index 013feac9a02ba6d75bfe588efd2155ac8e33f027..904769b4dd9809cc3cfa985220d585b9e1893c31 100644 (file)
@@ -2527,10 +2527,17 @@ static int HandleEstablishedPacketToServer(
                "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 */
@@ -2616,6 +2623,8 @@ static int HandleEstablishedPacketToServer(
         SCLogDebug("ssn %p: zero window probe", ssn);
         zerowindowprobe = 1;
         STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE);
+        ssn->flags |= STREAMTCP_FLAG_ZWP_TS;
+        StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p);
 
     } 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));
@@ -2694,10 +2703,17 @@ static int HandleEstablishedPacketToClient(
                " 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
@@ -2757,6 +2773,10 @@ static int HandleEstablishedPacketToClient(
         SCLogDebug("ssn %p: zero window probe", ssn);
         zerowindowprobe = 1;
         STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE);
+        ssn->flags |= STREAMTCP_FLAG_ZWP_TC;
+
+        /* accept the segment */
+        StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p);
 
     } 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));