From: Victor Julien Date: Fri, 3 Mar 2023 07:02:35 +0000 (+0100) Subject: stream: accept and flag ack of ZWP data X-Git-Tag: suricata-6.0.11~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6ee3e79849d8dd7b41961a08ad4e1fdb794bff1e;p=thirdparty%2Fsuricata.git stream: accept and flag ack of ZWP data 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) --- diff --git a/rules/stream-events.rules b/rules/stream-events.rules index cb1ae245e7..0c69337e2b 100644 --- a/rules/stream-events.rules +++ b/rules/stream-events.rules @@ -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 + diff --git a/src/decode-events.c b/src/decode-events.c index 78c3cd9acf..4e91ba092e 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -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, diff --git a/src/decode-events.h b/src/decode-events.h index e42afafae7..1d582769b1 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -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, diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index a85111275e..10652c6d93 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -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 */ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index b895bcd472..f4c7ce8420 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -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));