From: Victor Julien Date: Tue, 16 Oct 2012 13:27:30 +0000 (+0200) Subject: stream: detect retransmissions on closewait and finwait2 states X-Git-Tag: suricata-1.4beta3~82 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc37cb6b8ef4a695b37674200a2b3b8fccb0145b;p=thirdparty%2Fsuricata.git stream: detect retransmissions on closewait and finwait2 states --- diff --git a/rules/stream-events.rules b/rules/stream-events.rules index 3e57b6a935..a2bafe2936 100644 --- a/rules/stream-events.rules +++ b/rules/stream-events.rules @@ -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 diff --git a/src/decode-events.h b/src/decode-events.h index 3e08f2c2f6..697279fdd8 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -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, diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 52653e3581..5bde8df714 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -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, }, diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 8f1da11e73..b801826246 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -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 ""