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-7.0.0-rc2~478 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=30a716a4ab102a3b39cca8c8dab84be88c092687;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. --- diff --git a/rules/stream-events.rules b/rules/stream-events.rules index 661e3d2b51..e589c81b13 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;) @@ -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 diff --git a/src/decode-events.c b/src/decode-events.c index 21c8eaba28..e0d9fd90a1 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -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, diff --git a/src/decode-events.h b/src/decode-events.h index 2555ed28b6..6e2d638c3c 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -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, diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 1b40022a28..b827535eff 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -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 diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 013feac9a0..904769b4dd 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -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));