From: Victor Julien Date: Tue, 22 Mar 2022 16:00:29 +0000 (+0100) Subject: stream: detect spurious retransmissions early X-Git-Tag: suricata-7.0.0-beta1~493 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cc4e8f09367a6152c95d66cd317531166b707a31;p=thirdparty%2Fsuricata.git stream: detect spurious retransmissions early --- diff --git a/src/decode-events.c b/src/decode-events.c index cd93e31052..95fa1176db 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -802,6 +802,10 @@ const struct DecodeEvents_ DEvents[] = { "stream.pkt_retransmission", STREAM_PKT_RETRANSMISSION, }, + { + "stream.pkt_spurious_retransmission", + STREAM_PKT_SPURIOUS_RETRANSMISSION, + }, { "stream.pkt_bad_window_update", STREAM_PKT_BAD_WINDOW_UPDATE, diff --git a/src/decode-events.h b/src/decode-events.h index 715b46e8d1..8ec9123a82 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -277,6 +277,7 @@ enum { STREAM_PKT_BROKEN_ACK, STREAM_RST_INVALID_ACK, STREAM_PKT_RETRANSMISSION, + STREAM_PKT_SPURIOUS_RETRANSMISSION, STREAM_PKT_BAD_WINDOW_UPDATE, STREAM_SUSPECTED_RST_INJECT, diff --git a/src/stream-tcp.c b/src/stream-tcp.c index d1c5371c8e..f6a76a190f 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -2560,6 +2560,33 @@ static bool StreamTcpPacketIsOutdatedAck(TcpSession *ssn, Packet *p) return false; } +/** \internal + * \brief check if packet is before ack'd windows + * If packet is before last ack, we will not accept it + */ +static bool StreamTcpPacketIsSpuriousRetransmission(TcpSession *ssn, Packet *p) +{ + TcpStream *stream; + if (PKT_IS_TOCLIENT(p)) { + stream = &ssn->server; + } else { + stream = &ssn->client; + } + /* take base_seq into account to avoid edge cases where last_ack might be + * too far ahead during heavy packet loss */ + const uint32_t le = MIN(stream->last_ack, stream->base_seq); + if (p->payload_len > 0 && (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, le))) { + SCLogDebug("ssn %p: spurious retransmission; packet entirely before last_ack: SEQ %u(%u) " + "last_ack %u", + ssn, TCP_GET_SEQ(p), TCP_GET_SEQ(p) + p->payload_len, stream->last_ack); + return true; + } + SCLogDebug("ssn %p: NOT spurious retransmission; packet NOT entirely before last_ack: SEQ " + "%u(%u) last_ack %u, le %u", + ssn, TCP_GET_SEQ(p), TCP_GET_SEQ(p) + p->payload_len, stream->last_ack, le); + return false; +} + /** * \brief Function to handle the TCP_ESTABLISHED state. The function handles * ACK, FIN, RST packets and correspondingly changes the connection @@ -4960,6 +4987,11 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } } + if (StreamTcpPacketIsSpuriousRetransmission(ssn, p)) { + StreamTcpSetEvent(p, STREAM_PKT_SPURIOUS_RETRANSMISSION); + goto error; + } + /* handle the per 'state' logic */ if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->state) < 0) goto error;