]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: detect retransmissions on closewait and finwait2 states
authorVictor Julien <victor@inliniac.net>
Tue, 16 Oct 2012 13:27:30 +0000 (15:27 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 16 Oct 2012 13:27:30 +0000 (15:27 +0200)
rules/stream-events.rules
src/decode-events.h
src/detect-engine-event.h
src/stream-tcp.c

index 3e57b6a9359c02d817d368d0113075bfe05da4aa..a2bafe293618d9d29c1e75074d7bcec9a4cdd31b 100644 (file)
@@ -20,6 +20,7 @@ alert tcp any any -> any any (msg:"SURICATA STREAM 4way handshake invalid ack";
 alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT ACK out of window"; stream-event:closewait_ack_out_of_window; sid:2210015; rev:1;)
 alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT FIN out of window"; stream-event:closewait_fin_out_of_window; sid:2210016; rev:1;)
 alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT invalid ACK"; stream-event:closewait_invalid_ack; sid:2210017; rev:1;)
+#alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT retransmission packet before last ack"; stream-event:closewait_pkt_before_last_ack; sid:2210052; rev:2;)
 alert tcp any any -> any any (msg:"SURICATA STREAM CLOSING ACK wrong seq"; stream-event:closing_ack_wrong_seq; sid:2210018; rev:1;)
 alert tcp any any -> any any (msg:"SURICATA STREAM CLOSING invalid ACK"; stream-event:closing_invalid_ack; sid:2210019; rev:1;)
 alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED packet out of window"; stream-event:est_packet_out_of_window; sid:2210020; rev:1;)
@@ -60,5 +61,5 @@ alert tcp any any -> any any (msg:"SURICATA STREAM SHUTDOWN RST invalid ack"; st
 # Sequence gap: missing data in the reassembly engine. Usually due to packet loss. Will be very noisy on a overloaded link / sensor.
 #alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; sid:2210048; rev:1;)
 alert tcp any any -> any any (msg:"SURICATA STREAM reassembly overlap with different data"; stream-event:reassembly_overlap_different_data; sid:2210050; rev:1;)
-# next sid 2210052
+# next sid 2210053
 
index 3e08f2c2f673807fc075e68f4ef92c654ad6e469..697279fdd84f3e267f2ad43204732c1861d6b276 100644 (file)
@@ -146,6 +146,7 @@ enum {
     STREAM_4WHS_INVALID_ACK,
     STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW,
     STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW,
+    STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK,
     STREAM_CLOSEWAIT_INVALID_ACK,
     STREAM_CLOSING_ACK_WRONG_SEQ,
     STREAM_CLOSING_INVALID_ACK,
index 52653e35818ec6f6642cad05448d134d0e7344de..5bde8df7149ccdf407b2b25538b09c23e64fcf9e 100644 (file)
@@ -137,6 +137,7 @@ struct DetectEngineEvents_ {
     { "stream.4whs_invalid_ack", STREAM_4WHS_INVALID_ACK, },
     { "stream.closewait_ack_out_of_window", STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, },
     { "stream.closewait_fin_out_of_window", STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, },
+    { "stream.closewait_pkt_before_last_ack", STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK, },
     { "stream.closewait_invalid_ack", STREAM_CLOSEWAIT_INVALID_ACK, },
     { "stream.closing_ack_wrong_seq", STREAM_CLOSING_ACK_WRONG_SEQ, },
     { "stream.closing_invalid_ack", STREAM_CLOSING_INVALID_ACK, },
index 8f1da11e731dec9c7bcde4dfc3551b778dad0c9a..b8018262468068ff8ff3d7e27eb482f62921f985 100644 (file)
@@ -2673,8 +2673,14 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
             SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
                     "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
                     TCP_GET_SEQ(p), TCP_GET_ACK(p));
+            int retransmission = 0;
 
-            if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
+            if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) &&
+                SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) {
+                SCLogDebug("ssn %p: retransmission", ssn);
+                retransmission = 1;
+
+            } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
                     SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
             {
                 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
@@ -2690,9 +2696,11 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
                 return -1;
             }
 
-            StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
-            ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED;
-            SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
+            if (!retransmission) {
+                StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
+                ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED;
+                SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
+            }
 
             ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
 
@@ -2719,8 +2727,14 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
             SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
                     "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
                     TCP_GET_SEQ(p), TCP_GET_ACK(p));
+            int retransmission = 0;
 
-            if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
+            if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) &&
+                SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) {
+                SCLogDebug("ssn %p: retransmission", ssn);
+                retransmission = 1;
+
+            } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
                     SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
             {
                 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
@@ -2736,10 +2750,11 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
                 return -1;
             }
 
-            StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
-            ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED;
-            SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
-
+            if (!retransmission) {
+                StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
+                ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED;
+                SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
+            }
             ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
 
             StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
@@ -3219,7 +3234,12 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p,
                     "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
                     TCP_GET_SEQ(p), TCP_GET_ACK(p));
 
-            if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
+            if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) {
+                SCLogDebug("ssn %p: -> retransmission", ssn);
+                StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK);
+                SCReturnInt(-1);
+
+            } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
                     SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
             {
                 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
@@ -3261,7 +3281,12 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p,
                     "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
                     TCP_GET_SEQ(p), TCP_GET_ACK(p));
 
-            if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
+            if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) {
+                SCLogDebug("ssn %p: -> retransmission", ssn);
+                StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK);
+                SCReturnInt(-1);
+
+            } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
                     SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
             {
                 SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""