From: Victor Julien Date: Thu, 11 Jun 2015 10:39:53 +0000 (+0200) Subject: app-layer: improve EOF handling X-Git-Tag: suricata-3.0RC1~302 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cf9ff6adbd4842010be805ac27f3d09ed7767643;p=thirdparty%2Fsuricata.git app-layer: improve EOF handling On receiving TCP end of stream packets (e.g. RST, but also sometimes FIN packets), in some cases the AppLayer parser would not be notified. This could happen in IDS mode, but would especially be an issue in IPS mode. This patch changes the logic of the AppLayer API to handle this. When no new data is available, and the stream ends, the AppLayer API now gets called with a NULL/0 input, but with the EOF flag set. This allows the AppLayer parser to call it's final routines still in the context of a real packet. --- diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index c6a6e412be..aed1ddeb47 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -739,28 +739,30 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec }; /* pass the new data to the htp parser */ - r = htp_connp_req_data(hstate->connp, &ts, input, input_len); + if (input_len > 0) { + r = htp_connp_req_data(hstate->connp, &ts, input, input_len); - switch(r) { - case HTP_STREAM_ERROR: + switch(r) { + case HTP_STREAM_ERROR: - hstate->flags |= HTP_FLAG_STATE_ERROR; - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - ret = -1; - break; - case HTP_STREAM_DATA: - case HTP_STREAM_DATA_OTHER: + hstate->flags |= HTP_FLAG_STATE_ERROR; + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + ret = -1; + break; + case HTP_STREAM_DATA: + case HTP_STREAM_DATA_OTHER: - hstate->flags |= HTP_FLAG_STATE_DATA; - break; - case HTP_STREAM_TUNNEL: - break; - default: - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + hstate->flags |= HTP_FLAG_STATE_DATA; + break; + case HTP_STREAM_TUNNEL: + break; + default: + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + } + HTPHandleError(hstate); } - HTPHandleError(hstate); /* if the TCP connection is closed, then close the HTTP connection */ if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) && @@ -815,25 +817,27 @@ static int HTPHandleResponseData(Flow *f, void *htp_state, hstate->flags &=~ HTP_FLAG_NEW_BODY_SET; htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec }; - r = htp_connp_res_data(hstate->connp, &ts, input, input_len); - switch(r) { - case HTP_STREAM_ERROR: - hstate->flags = HTP_FLAG_STATE_ERROR; - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - ret = -1; - break; - case HTP_STREAM_DATA: - case HTP_STREAM_DATA_OTHER: - hstate->flags |= HTP_FLAG_STATE_DATA; - break; - case HTP_STREAM_TUNNEL: - break; - default: - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - } - HTPHandleError(hstate); + if (input_len > 0) { + r = htp_connp_res_data(hstate->connp, &ts, input, input_len); + switch(r) { + case HTP_STREAM_ERROR: + hstate->flags = HTP_FLAG_STATE_ERROR; + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + ret = -1; + break; + case HTP_STREAM_DATA: + case HTP_STREAM_DATA_OTHER: + hstate->flags |= HTP_FLAG_STATE_DATA; + break; + case HTP_STREAM_TUNNEL: + break; + default: + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + } + HTPHandleError(hstate); + } /* if we the TCP connection is closed, then close the HTTP connection */ if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) && diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 655da90213..2c4d2f8b2c 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -890,7 +890,7 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp } /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */ - if (input_len > 0) { + if (input_len > 0 || (flags & STREAM_EOF)) { /* invoke the parser */ if (p->Parser[(flags & STREAM_TOSERVER) ? 0 : 1](f, alstate, pstate, input, input_len,