From d79a926085ce66e0be4bb22ede1671928b6995fb Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 21 Feb 2023 10:47:13 +0100 Subject: [PATCH] stream: D-SACK detection and logging RFC 2883 specifies a special use of SACKs to indicate a host has received a segment it considers a spurious retransmission. --- src/output-eve-stream.c | 2 ++ src/stream-tcp-private.h | 1 + src/stream-tcp-sack.c | 27 +++++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/output-eve-stream.c b/src/output-eve-stream.c index 1775783bec..3181a34392 100644 --- a/src/output-eve-stream.c +++ b/src/output-eve-stream.c @@ -344,6 +344,8 @@ static int EveStreamLogger(ThreadVars *tv, void *thread_data, const Packet *p) jb_append_string(js, "state_update"); if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_DUP_ACK) jb_append_string(js, "dup_ack"); + if (p->tcpvars.stream_pkt_flags & STREAM_PKT_FLAG_DSACK) + jb_append_string(js, "dsack"); jb_close(js); } jb_close(js); diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index b410b4f1da..25f10b353d 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -307,6 +307,7 @@ typedef struct TcpSession_ { #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_DSACK BIT_U16(8) #define STREAM_PKT_FLAG_SET(p, f) (p)->tcpvars.stream_pkt_flags |= (f) diff --git a/src/stream-tcp-sack.c b/src/stream-tcp-sack.c index 9a36a94958..f97dfc4afd 100644 --- a/src/stream-tcp-sack.c +++ b/src/stream-tcp-sack.c @@ -259,12 +259,35 @@ int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p) TCPOptSackRecord rec[records], *sack_rec = rec; memcpy(&rec, data, sizeof(TCPOptSackRecord) * records); + uint32_t first_le = 0; + uint32_t first_re = 0; + for (int record = 0; record < records; record++) { const uint32_t le = SCNtohl(sack_rec->le); const uint32_t re = SCNtohl(sack_rec->re); - SCLogDebug("%p last_ack %u, left edge %u, right edge %u", sack_rec, - stream->last_ack, le, re); + if (!first_le) + first_le = le; + if (!first_re) + first_re = re; + + SCLogDebug("%p last_ack %u, left edge %u, right edge %u pkt ACK %u", sack_rec, + stream->last_ack, le, re, TCP_GET_ACK(p)); + + /* RFC 2883 D-SACK */ + if (SEQ_LT(le, TCP_GET_ACK(p))) { + SCLogDebug("packet: %" PRIu64 ": D-SACK? %u-%u before ACK %u", p->pcap_cnt, le, re, + TCP_GET_ACK(p)); + STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_DSACK); + goto next; + } else if (record == 1) { // 2nd record + if (SEQ_GEQ(first_le, le) && SEQ_LEQ(first_re, re)) { + SCLogDebug("packet: %" PRIu64 ": D-SACK? %u-%u inside 2nd range %u-%u ACK %u", + p->pcap_cnt, first_le, first_re, le, re, TCP_GET_ACK(p)); + STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_DSACK); + } + goto next; + } if (SEQ_LEQ(re, stream->last_ack)) { SCLogDebug("record before last_ack");