From 25f5589078bb60d4d06331446834937da0cffea2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 7 Jan 2011 10:18:04 +0100 Subject: [PATCH] First round of adding 'stream events'. Basic stream tracking events added. --- src/decode-events.h | 36 +++++++ src/decode.h | 9 +- src/stream-tcp.c | 227 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 241 insertions(+), 31 deletions(-) diff --git a/src/decode-events.h b/src/decode-events.h index d5ffa6e544..3075aed409 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -125,6 +125,42 @@ enum { /* RAW EVENTS */ IPRAW_INVALID_IPV, /**< invalid ip version in ip raw */ + STREAM_3WHS_ACK_IN_WRONG_DIR, + STREAM_3WHS_ASYNC_WRONG_SEQ, + STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION, + STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION, + STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK, + STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ, + STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV, + STREAM_3WHS_SYNACK_WITH_WRONG_ACK, + STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV, + STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV, + STREAM_3WHS_WRONG_SEQ_WRONG_ACK, + STREAM_4WHS_SYNACK_WITH_WRONG_ACK, + STREAM_4WHS_SYNACK_WITH_WRONG_SYN, + STREAM_4WHS_WRONG_SEQ, + STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, + STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, + STREAM_CLOSING_ACK_WRONG_SEQ, + STREAM_EST_PACKET_OUT_OF_WINDOW, + STREAM_EST_SEQ_BEFORE_LAST_ACK, + STREAM_EST_SYNACK_RESEND, + STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, + STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, + STREAM_EST_SYNACK_TOSERVER, + STREAM_EST_SYN_RESEND, + STREAM_EST_SYN_RESEND_DIFF_SEQ, + STREAM_EST_SYN_TOCLIENT, + STREAM_FIN1_ACK_WRONG_SEQ, + STREAM_FIN1_FIN_WRONG_SEQ, + STREAM_FIN2_ACK_WRONG_SEQ, + STREAM_FIN2_FIN_WRONG_SEQ, + STREAM_FIN_BUT_NO_SESSION, + STREAM_FIN_OUT_OF_WINDOW, + STREAM_LASTACK_ACK_WRONG_SEQ, + STREAM_RST_BUT_NO_SESSION, + STREAM_TIMEWAIT_ACK_WRONG_SEQ, + /* should always be last! */ DECODE_EVENT_MAX, }; diff --git a/src/decode.h b/src/decode.h index d6a9ffe271..3664baf68c 100644 --- a/src/decode.h +++ b/src/decode.h @@ -225,11 +225,14 @@ typedef struct PacketAlerts_ { PacketAlert alerts[PACKET_ALERT_MAX]; } PacketAlerts; -#define PACKET_DECODER_EVENT_MAX 16 +/** number of decoder events we support per packet. Power of 2 minus 1 + * for memory layout */ +#define PACKET_DECODER_EVENT_MAX 15 +/** data structure to store decoder, defrag and stream events */ typedef struct PacketDecoderEvents_ { - uint8_t cnt; - uint8_t events[PACKET_DECODER_EVENT_MAX]; + uint8_t cnt; /**< number of events */ + uint8_t events[PACKET_DECODER_EVENT_MAX]; /**< array of events */ } PacketDecoderEvents; typedef struct PktVar_ { diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 99cf70b8d6..a8f3f29b33 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -148,7 +148,10 @@ void StreamTcpDecrMemuse(uint32_t size) { SCSpinUnlock(&stream_memuse_spinlock); } -/** \retval 1 if in bounds +/** + * \brief Check if alloc'ing "size" would mean we're over memcap + * + * \retval 1 if in bounds * \retval 0 if not in bounds */ int StreamTcpCheckMemcap(uint32_t size) { @@ -596,6 +599,10 @@ void StreamTcpSetOSPolicy(TcpStream *stream, Packet *p) } +void StreamTcpSetEvent(Packet *p, uint8_t e) { + DECODER_SET_EVENT(p, e); +} + /** * \brief Function to test the received ACK values against the stream window * and previous ack value. ACK values should be higher than previous @@ -614,7 +621,7 @@ static inline uint8_t StreamTcpValidateAck(TcpStream *stream, Packet *p) (SEQ_LEQ(TCP_GET_ACK(p) + p->payload_len, stream->next_win))) { ret = TRUE; - } + } return ret; } @@ -638,13 +645,13 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, * TH_CWR -> Establish a new connection reducing window * TH_ECN -> Echo Congestion flag */ - case TH_SYN | TH_CWR | TH_ECN: + case TH_SYN: case TH_SYN | TH_ECN: case TH_SYN | TH_CWR: case TH_SYN | TH_PUSH: case TH_SYN | TH_URG: - case TH_SYN: - case TH_SYN|TH_PUSH|TH_URG: + case TH_SYN | TH_CWR | TH_ECN: + case TH_SYN | TH_PUSH | TH_URG: { if (ssn == NULL) { ssn = StreamTcpNewSession(p); @@ -854,6 +861,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, case TH_RST|TH_ACK|TH_PUSH: case TH_RST|TH_ACK|TH_PUSH|TH_ECN: case TH_RST|TH_ACK|TH_PUSH|TH_ECN|TH_CWR: + StreamTcpSetEvent(p, STREAM_RST_BUT_NO_SESSION); + BUG_ON(p->flow->protoctx != NULL); + SCLogDebug("RST packet received, no session setup"); + break; case TH_FIN: case TH_FIN|TH_ACK: case TH_FIN|TH_ACK|TH_ECN: @@ -861,8 +872,9 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, case TH_FIN|TH_ACK|TH_PUSH: case TH_FIN|TH_ACK|TH_PUSH|TH_ECN: case TH_FIN|TH_ACK|TH_PUSH|TH_ECN|TH_CWR: + StreamTcpSetEvent(p, STREAM_FIN_BUT_NO_SESSION); BUG_ON(p->flow->protoctx != NULL); - SCLogDebug("FIN or RST packet received, no session setup"); + SCLogDebug("FIN packet received, no session setup"); break; default: SCLogDebug("default case"); @@ -896,9 +908,10 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, case TH_SYN|TH_CWR: case TH_SYN|TH_CWR|TH_ECN: SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn); - if (ssn->flags & STREAMTCP_FLAG_4WHS) + if (ssn->flags & STREAMTCP_FLAG_4WHS) { SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of " "4WHS SYN", ssn); + } if (PKT_IS_TOCLIENT(p)) { /** a SYN only packet in the opposite direction could be: @@ -950,6 +963,8 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, ssn->client.last_ack); } + /** \todo check if it's correct or set event */ + break; case TH_SYN|TH_ACK: case TH_SYN|TH_ACK|TH_ECN: @@ -960,6 +975,8 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Check if the SYN/ACK packet ack's the earlier * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) { + StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_ACK); + SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %"PRIu32"" " != %" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->server.isn + 1); @@ -969,6 +986,8 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN * packet. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) { + StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_SYN); + SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %"PRIu32"" " != %" PRIu32 " from *first* SYN pkt", ssn, TCP_GET_SEQ(p), ssn->client.isn); @@ -1041,6 +1060,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, } if (PKT_IS_TOSERVER(p)) { + StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION); SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn); return -1; } @@ -1048,6 +1068,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Check if the SYN/ACK packet ack's the earlier * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) { + StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK); SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->client.isn + 1); @@ -1130,16 +1151,18 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, case TH_ACK|TH_PUSH|TH_ECN: case TH_ACK|TH_PUSH|TH_ECN|TH_CWR: /* Handle the asynchronous stream, when we receive a SYN packet - and now istead of receving a SYN/ACK we receive a ACK from the - same host, which sent the SYN, this suggests the ASNYC streams.*/ + and now istead of receving a SYN/ACK we receive a ACK from the + same host, which sent the SYN, this suggests the ASNYC streams.*/ if (stream_config.async_oneside == FALSE) break; - /* Check if the ACK packet seq no is equal to the expected seq. no.*/ - /*XXX GS what if we missed the initial ACK here, then we can't setup - the session. I was thinking to check the SEQ_GEQ instead of SEQ_EQ - your thoughts ?? It will quite relax then in checking.*/ + /* we are in AYNC (one side) mode now. */ + + /* one side async means we won't see a SYN/ACK, so we can + * only check the SYN. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) { + StreamTcpSetEvent(p, STREAM_3WHS_ASYNC_WRONG_SEQ); + SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p), ssn->client.next_seq); @@ -1193,7 +1216,8 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, if (PKT_IS_TOSERVER(p)) { if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) && SEQ_EQ(TCP_GET_WINDOW(p), 0) && - SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) { + SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) + { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -1224,6 +1248,9 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling + * + * \retval 0 ok + * \retval -1 error */ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, @@ -1238,11 +1265,56 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, case TH_SYN|TH_CWR: case TH_SYN|TH_CWR|TH_ECN: SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn); + + if (PKT_IS_TOCLIENT(p)) { + SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn); + + StreamTcpSetEvent(p, STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV); + return -1; + } + + if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) { + SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn); + + StreamTcpSetEvent(p, STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV); + return -1; + } + break; case TH_SYN|TH_ACK: case TH_SYN|TH_ACK|TH_ECN: case TH_SYN|TH_ACK|TH_ECN|TH_CWR: SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn); + + if (PKT_IS_TOSERVER(p)) { + SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn); + + StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV); + return -1; + } + + /* Check if the SYN/ACK packets ACK matches the earlier + * received SYN/ACK packet. */ + if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) { + SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " + "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), + ssn->client.isn + 1); + + StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK); + return -1; + } + + /* Check if the SYN/ACK packet SEQ the earlier + * received SYN packet. */ + if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) { + SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " + "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), + ssn->client.isn + 1); + + StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ); + return -1; + } + break; case TH_ACK: case TH_ACK|TH_URG: @@ -1257,8 +1329,9 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, * stream->last_ts. If the timestamp is valid then process the * packet normally otherwise the drop the packet (RFC 1323)*/ if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { - if (!ValidTimestamp(ssn, p)) + if (!(ValidTimestamp(ssn, p))) { return -1; + } } if (ssn->flags & STREAMTCP_FLAG_4WHS && PKT_IS_TOCLIENT(p)) { @@ -1281,6 +1354,8 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, &ssn->server, p, pq); } else { SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn); + + StreamTcpSetEvent(p, STREAM_4WHS_WRONG_SEQ); return -1; } @@ -1312,6 +1387,8 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, } else { SCLogDebug("ssn %p: ACK received in the wrong direction", ssn); + + StreamTcpSetEvent(p, STREAM_3WHS_ACK_IN_WRONG_DIR); return -1; } } @@ -1327,7 +1404,7 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, /* we need to make sure that both sequence and the ack are of sane values */ if ((StreamTcpValidateAck(&ssn->server, p) == TRUE)) - ssn->server.last_ack = TCP_GET_ACK(p); + ssn->server.last_ack = TCP_GET_ACK(p); ssn->client.next_seq += p->payload_len; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -1387,9 +1464,13 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, ssn->flags |= STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT; SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!", ssn); + + StreamTcpSetEvent(p, STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION); return -1; } else { SCLogDebug("ssn %p: wrong seq nr on packet", ssn); + + StreamTcpSetEvent(p, STREAM_3WHS_WRONG_SEQ_WRONG_ACK); return -1; } @@ -1417,7 +1498,7 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, systems will not closed the connection. As they consider the packet as stray packet and not belonging to the current session, for more information check -http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */ + http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */ if (ssn->flags & STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT) { if (PKT_IS_TOSERVER(p)) { if ((ssn->server.os_policy == OS_POLICY_LINUX) || @@ -1543,6 +1624,8 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); + + StreamTcpSetEvent(p, STREAM_EST_SEQ_BEFORE_LAST_ACK); return -1; } } @@ -1591,6 +1674,9 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); + + StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW); + return -1; } return 0; } @@ -1639,6 +1725,7 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack ssn->server.last_ack = TCP_GET_SEQ(p); } else { + StreamTcpSetEvent(p, STREAM_EST_SEQ_BEFORE_LAST_ACK); return -1; } } @@ -1689,6 +1776,8 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->server.last_ack, ssn->server.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win); + StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW); + return -1; } return 0; } @@ -1716,12 +1805,63 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, case TH_SYN|TH_CWR: case TH_SYN|TH_CWR|TH_ECN: SCLogDebug("ssn %p: SYN packet on state ESTABLISED... resent", ssn); + if (PKT_IS_TOCLIENT(p)) { + SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn); + + StreamTcpSetEvent(p, STREAM_EST_SYN_TOCLIENT); + return -1; + } + + if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) { + SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn); + + StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND_DIFF_SEQ); + return -1; + } + + /* a resend of a SYN while we are established already -- fishy */ + StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND); + return -1; break; + case TH_SYN|TH_ACK: case TH_SYN|TH_ACK|TH_ECN: case TH_SYN|TH_ACK|TH_ECN|TH_CWR: SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent", ssn); + + if (PKT_IS_TOSERVER(p)) { + SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn); + + StreamTcpSetEvent(p, STREAM_EST_SYNACK_TOSERVER); + return -1; + } + + /* Check if the SYN/ACK packets ACK matches the earlier + * received SYN/ACK packet. */ + if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) { + SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " + "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), + ssn->client.isn + 1); + + StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK); + return -1; + } + + /* Check if the SYN/ACK packet SEQ the earlier + * received SYN packet. */ + if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) { + SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " + "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), + ssn->client.isn + 1); + + StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ); + return -1; + } + + /* a resend of a SYN while we are established already -- fishy */ + StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND); + return -1; break; case TH_ACK|TH_URG: case TH_ACK: @@ -1764,6 +1904,7 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, ssn->server.next_win, ssn->server.window); } break; + case TH_FIN: case TH_FIN|TH_ACK: case TH_FIN|TH_ACK|TH_ECN: @@ -1786,6 +1927,7 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, if((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1) return -1; break; + case TH_RST: case TH_RST|TH_ACK: case TH_RST|TH_ACK|TH_ECN: @@ -1868,16 +2010,18 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, if (PKT_IS_TOSERVER(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)); + " 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) || - SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) + SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { - SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), - ssn->client.next_seq); - return -1; + SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != " + "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), + ssn->client.next_seq); + + StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW); + return -1; } StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT); @@ -1914,6 +2058,8 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + + StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW); return -1; } @@ -1941,6 +2087,7 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } + return 0; } @@ -1961,8 +2108,8 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, return -1; switch (p->tcph->th_flags) { - case TH_ACK|TH_URG: case TH_ACK: + case TH_ACK|TH_URG: case TH_ACK|TH_ECN: case TH_ACK|TH_ECN|TH_CWR: @@ -1976,6 +2123,8 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + + StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ); return -1; } SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " @@ -2013,6 +2162,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ); return -1; } SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " @@ -2046,6 +2196,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, ssn->client.last_ack); } break; + case TH_FIN: case TH_FIN|TH_ACK: case TH_FIN|TH_ACK|TH_ECN: @@ -2071,6 +2222,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } @@ -2112,6 +2264,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } @@ -2187,8 +2340,8 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, return -1; switch (p->tcph->th_flags) { - case TH_ACK|TH_URG: case TH_ACK: + case TH_ACK|TH_URG: case TH_ACK|TH_ECN: case TH_ACK|TH_ECN|TH_CWR: @@ -2206,6 +2359,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ); return -1; } StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); @@ -2243,6 +2397,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ); return -1; } StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); @@ -2273,6 +2428,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, ssn->client.last_ack); } break; + case TH_RST: case TH_RST|TH_ACK: case TH_RST|TH_ACK|TH_ECN: @@ -2292,8 +2448,8 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, else return -1; break; - case TH_FIN: + case TH_FIN: if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!ValidTimestamp(ssn, p)) return -1; @@ -2311,6 +2467,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ " "%" PRIu32 " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ); return -1; } @@ -2345,6 +2502,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ " "%" PRIu32 " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ); return -1; } @@ -2411,6 +2569,7 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ); return -1; } @@ -2442,6 +2601,7 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ); return -1; } @@ -2486,8 +2646,11 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { SCEnter(); - if (ssn == NULL) + + if (ssn == NULL) { SCReturnInt(-1); + } + if (PKT_IS_TOCLIENT(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, @@ -2521,6 +2684,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW); SCReturnInt(-1); } @@ -2554,6 +2718,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW); SCReturnInt(-1); } @@ -2577,6 +2742,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, ssn->server.last_ack); } break; + case TH_ACK: case TH_ACK|TH_PUSH: case TH_ACK|TH_ECN: @@ -2598,6 +2764,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW); SCReturnInt(-1); } ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -2632,6 +2799,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); SCReturnInt(-1); + StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW); } ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -2696,6 +2864,7 @@ static int StreamTcpPakcetStateLastAck(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + StreamTcpSetEvent(p, STREAM_LASTACK_ACK_WRONG_SEQ); return -1; } @@ -2764,6 +2933,7 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); + StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ); return -1; } @@ -2797,6 +2967,7 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); + StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ); return -1; }