From 64625675ce8fc4cf9b9421b1009f721a0794c64d Mon Sep 17 00:00:00 2001 From: Anoop Saldanha Date: Thu, 17 May 2012 13:41:23 +0530 Subject: [PATCH] set stream_eof flag per stream, only when the stream initiates a close. Fix htp parser to close connection per direction based on this --- src/app-layer-htp.c | 24 ++++++++++++----------- src/app-layer-htp.h | 22 +++++++++++---------- src/stream-tcp-private.h | 2 ++ src/stream-tcp-reassemble.c | 12 ++++++------ src/stream-tcp.c | 39 +++++++++++++++++++++++++++++++++++-- 5 files changed, 70 insertions(+), 29 deletions(-) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 2f2574b22c..bac04c49e0 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -686,12 +686,13 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, /* if the TCP connection is closed, then close the HTTP connection */ if ((pstate->flags & APP_LAYER_PARSER_EOF) && - ! (hstate->flags & HTP_FLAG_STATE_CLOSED) && - ! (hstate->flags & HTP_FLAG_STATE_DATA)) - { - htp_connp_close(hstate->connp, 0); - hstate->flags |= HTP_FLAG_STATE_CLOSED; - SCLogDebug("stream eof encountered, closing htp handle"); + !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS)) { + hstate->connp->in_status = STREAM_STATE_CLOSED; + // Call the parsers one last time, which will allow them + // to process the events that depend on stream closure + htp_connp_req_data(hstate->connp, 0, NULL, 0); + hstate->flags |= HTP_FLAG_STATE_CLOSED_TS; + SCLogDebug("stream eof encountered, closing htp handle for ts"); } SCLogDebug("hstate->connp %p", hstate->connp); @@ -766,11 +767,12 @@ static int HTPHandleResponseData(Flow *f, void *htp_state, /* if we the TCP connection is closed, then close the HTTP connection */ if ((pstate->flags & APP_LAYER_PARSER_EOF) && - ! (hstate->flags & HTP_FLAG_STATE_CLOSED) && - ! (hstate->flags & HTP_FLAG_STATE_DATA)) - { - htp_connp_close(hstate->connp, 0); - hstate->flags |= HTP_FLAG_STATE_CLOSED; + !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC)) { + hstate->connp->out_status = STREAM_STATE_CLOSED; + // Call the parsers one last time, which will allow them + // to process the events that depend on stream closure + htp_connp_res_data(hstate->connp, 0, NULL, 0); + hstate->flags |= HTP_FLAG_STATE_CLOSED_TC; } SCLogDebug("hstate->connp %p", hstate->connp); diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 2999495fc3..2579b9229a 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -47,24 +47,26 @@ #define HTP_FLAG_STATE_OPEN 0x0001 /**< Flag to indicate that HTTP connection is open */ -#define HTP_FLAG_STATE_CLOSED 0x0002 /**< Flag to indicate that HTTP +#define HTP_FLAG_STATE_CLOSED_TS 0x0002 /**< Flag to indicate that HTTP connection is closed */ -#define HTP_FLAG_STATE_DATA 0x0004 /**< Flag to indicate that HTTP +#define HTP_FLAG_STATE_CLOSED_TC 0x0004 /**< Flag to indicate that HTTP + connection is closed */ +#define HTP_FLAG_STATE_DATA 0x0008 /**< Flag to indicate that HTTP connection needs more data */ -#define HTP_FLAG_STATE_ERROR 0x0008 /**< Flag to indicate that an error +#define HTP_FLAG_STATE_ERROR 0x0010 /**< Flag to indicate that an error has been occured on HTTP connection */ -#define HTP_FLAG_NEW_BODY_SET 0x0010 /**< Flag to indicate that HTTP +#define HTP_FLAG_NEW_BODY_SET 0x0020 /**< Flag to indicate that HTTP has parsed a new body (for pcre) */ -#define HTP_FLAG_STORE_FILES_TS 0x0020 -#define HTP_FLAG_STORE_FILES_TC 0x0040 -#define HTP_FLAG_STORE_FILES_TX_TS 0x0080 -#define HTP_FLAG_STORE_FILES_TX_TC 0x0100 +#define HTP_FLAG_STORE_FILES_TS 0x0040 +#define HTP_FLAG_STORE_FILES_TC 0x0080 +#define HTP_FLAG_STORE_FILES_TX_TS 0x0100 +#define HTP_FLAG_STORE_FILES_TX_TC 0x0200 /** flag the state that a new file has been set in this tx */ -#define HTP_FLAG_NEW_FILE_TX_TS 0x0200 +#define HTP_FLAG_NEW_FILE_TX_TS 0x0400 /** flag the state that a new file has been set in this tx */ -#define HTP_FLAG_NEW_FILE_TX_TC 0x0400 +#define HTP_FLAG_NEW_FILE_TX_TC 0x0800 enum { HTP_BODY_NONE = 0, /**< Flag to indicate the current diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index fc5ff65383..385c48a062 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -132,6 +132,8 @@ enum #define STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY 0x04 /** Stream has reached it's reassembly depth, all further packets are ignored */ #define STREAMTCP_STREAM_FLAG_DEPTH_REACHED 0x08 +/** Stream has sent a FIN/RST */ +#define STREAMTCP_STREAM_FLAG_CLOSE_INITIATED 0x10 /* * Per SEGMENT flags diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index ea9c5a9f4f..d30b6520ab 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1624,7 +1624,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ flag |= STREAM_START; \ } \ - if ((ssn)->state > TCP_ESTABLISHED) { \ + if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ flag |= STREAM_EOF; \ } \ if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ @@ -1639,7 +1639,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ flag |= STREAM_START; \ } \ - if ((ssn)->state > TCP_ESTABLISHED) { \ + if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ flag |= STREAM_EOF; \ } \ if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ @@ -1660,7 +1660,7 @@ static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p, SCLogDebug("setting STREAM_START"); smsg->flags = STREAM_START; } - if (ssn->state > TCP_ESTABLISHED) { + if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { SCLogDebug("setting STREAM_EOF"); smsg->flags |= STREAM_EOF; } @@ -1823,7 +1823,7 @@ static int StreamTcpReassembleInlineAppLayer (ThreadVars *tv, /* send EOF to app layer */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, - NULL, 0, flags|STREAM_EOF); + NULL, 0, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); } else { @@ -2110,7 +2110,7 @@ static int StreamTcpReassembleInlineAppLayer (ThreadVars *tv, /* send EOF to app layer */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, - NULL, 0, flags|STREAM_EOF); + NULL, 0, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); } @@ -2484,7 +2484,7 @@ static int StreamTcpReassembleAppLayer (ThreadVars *tv, /* send EOF to app layer */ STREAM_SET_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, - NULL, 0, flags|STREAM_EOF); + NULL, 0, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); SCReturnInt(0); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index f1e97bbd6f..c840ccabd2 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -1263,11 +1263,15 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } @@ -1577,6 +1581,8 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, if (reset == TRUE) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2036,6 +2042,8 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, if(PKT_IS_TOSERVER(p)) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2066,6 +2074,8 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, * cleanup. */ } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2146,6 +2156,7 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, } StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT); + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) @@ -2193,6 +2204,7 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, } StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) @@ -2414,6 +2426,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, } 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; @@ -2463,6 +2476,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, } 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; @@ -2504,6 +2518,8 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -2689,6 +2705,8 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -2759,6 +2777,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, } 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; @@ -2804,6 +2823,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, } 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; @@ -2956,6 +2976,8 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3060,6 +3082,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, } StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK); + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -3102,6 +3125,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, } StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -3232,6 +3256,8 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3355,6 +3381,8 @@ static int StreamTcpPakcetStateLastAck(ThreadVars *tv, Packet *p, SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3522,6 +3550,8 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); + ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; + ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); @@ -3715,8 +3745,13 @@ static int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, if (ssn->state >= TCP_ESTABLISHED) { p->flags |= PKT_STREAM_EST; } - if (ssn->state > TCP_ESTABLISHED) { - p->flags |= PKT_STREAM_EOF; + + if (PKT_IS_TOSERVER(p)) { + if (ssn->client.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) + p->flags |= PKT_STREAM_EOF; + } else { + if (ssn->server.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) + p->flags |= PKT_STREAM_EOF; } }