"stream.pkt_retransmission",
STREAM_PKT_RETRANSMISSION,
},
+ {
+ "stream.pkt_spurious_retransmission",
+ STREAM_PKT_SPURIOUS_RETRANSMISSION,
+ },
{
"stream.pkt_bad_window_update",
STREAM_PKT_BAD_WINDOW_UPDATE,
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
}
}
+ 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;