From: Victor Julien Date: Tue, 21 Feb 2023 09:08:31 +0000 (+0100) Subject: stream: Dup-ACK detection X-Git-Tag: suricata-7.0.0-rc2~557 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6a2fdc456b64d14ddcad1b9fb58be0afbc43b964;p=thirdparty%2Fsuricata.git stream: Dup-ACK detection Modeled after Wiresharks Dup-ACK detection. --- diff --git a/src/output-eve-stream.c b/src/output-eve-stream.c index 1b1075321a..1775783bec 100644 --- a/src/output-eve-stream.c +++ b/src/output-eve-stream.c @@ -342,6 +342,8 @@ static int EveStreamLogger(ThreadVars *tv, void *thread_data, const Packet *p) jb_append_string(js, "event_set"); if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_STATE_UPDATE) jb_append_string(js, "state_update"); + if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_DUP_ACK) + jb_append_string(js, "dup_ack"); jb_close(js); } jb_close(js); diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 77d0dc4307..b410b4f1da 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -306,6 +306,7 @@ typedef struct TcpSession_ { #define STREAM_PKT_FLAG_KEEPALIVEACK BIT_U16(4) #define STREAM_PKT_FLAG_WINDOWUPDATE BIT_U16(5) #define STREAM_PKT_FLAG_EVENTSET BIT_U16(6) +#define STREAM_PKT_FLAG_DUP_ACK BIT_U16(7) #define STREAM_PKT_FLAG_SET(p, f) (p)->tcpvars.stream_pkt_flags |= (f) diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 464ef75292..d136367421 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -2799,6 +2799,44 @@ static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq) SCReturnUInt(ack); } +/** \internal + * \brief check if an ACK packet is a dup-ACK + */ +static bool StreamTcpPacketIsDupAck(const TcpSession *ssn, const Packet *p) +{ + if (ssn->state < TCP_ESTABLISHED) + return false; + if (p->payload_len != 0) + return false; + if ((p->tcph->th_flags & (TH_ACK | TH_SYN | TH_FIN | TH_RST)) != TH_ACK) + return false; + + const TcpStream *snd, *rcv; + if (PKT_IS_TOCLIENT(p)) { + snd = &ssn->server; + rcv = &ssn->client; + } else { + snd = &ssn->client; + rcv = &ssn->server; + } + + const uint32_t pkt_win = TCP_GET_WINDOW(p) << snd->wscale; + if (pkt_win == 0 || rcv->window == 0) + return false; + if (pkt_win != rcv->window) + return false; + + if (TCP_GET_SEQ(p) != snd->next_seq) + return false; + if (TCP_GET_ACK(p) != rcv->last_ack) + return false; + + SCLogDebug("ssn %p: packet:%" PRIu64 " seq:%u ack:%u win:%u snd %u:%u:%u rcv %u:%u:%u", ssn, + p->pcap_cnt, TCP_GET_SEQ(p), TCP_GET_ACK(p), pkt_win, snd->next_seq, snd->last_ack, + rcv->window, snd->next_seq, rcv->last_ack, rcv->window); + return true; +} + /** \internal * \brief check if a ACK packet is outdated so processing can be fast tracked * @@ -5254,6 +5292,11 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } StreamTcpClearKeepAliveFlag(ssn, p); + if (StreamTcpPacketIsDupAck(ssn, p) == true) { + STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_DUP_ACK); + // TODO see if we can skip work on these + } + /* if packet is not a valid window update, check if it is perhaps * a bad window update that we should ignore (and alert on) */ if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) {