]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: D-SACK detection and logging
authorVictor Julien <vjulien@oisf.net>
Tue, 21 Feb 2023 09:47:13 +0000 (10:47 +0100)
committerVictor Julien <vjulien@oisf.net>
Fri, 24 Feb 2023 09:45:38 +0000 (10:45 +0100)
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
src/stream-tcp-private.h
src/stream-tcp-sack.c

index 1775783becd560a60cff2ad78b0c843c8be4b937..3181a34392d8e2f94a0578785011cffbd34408d3 100644 (file)
@@ -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);
index b410b4f1da4ba9b0fcf61a6dc51838f656c8d48b..25f10b353dd7233ec9c80282e156e82cd68e3c29 100644 (file)
@@ -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)
 
index 9a36a94958bea3e8856554bc5fd15861f5166b3b..f97dfc4afdcd5c59452fbb84071d418eece28b67 100644 (file)
@@ -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");