From: Victor Julien Date: Mon, 1 Apr 2019 20:20:53 +0000 (+0200) Subject: app-layer/probing-parser: implement reverse flow X-Git-Tag: suricata-5.0.0-beta1~93 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bb78d48c0a72598c9a01ba429f63940099f80e46;p=thirdparty%2Fsuricata.git app-layer/probing-parser: implement reverse flow Implement midstream support for the pure probing parsers. These need to look up the appropriate parsers based on the reverse tuple. --- diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 84b671ce4a..3e75482ee2 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -444,6 +444,39 @@ static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t ipproto, return alproto; } +static inline AppProto PPGetProto( + const AppLayerProtoDetectProbingParserElement *pe, + Flow *f, uint8_t direction, + uint8_t *buf, uint32_t buflen, + uint32_t *alproto_masks, uint8_t *rdir +) +{ + while (pe != NULL) { + if ((buflen < pe->min_depth) || + (alproto_masks[0] & pe->alproto_mask)) { + pe = pe->next; + continue; + } + + AppProto alproto = ALPROTO_UNKNOWN; + if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { + alproto = pe->ProbingParserTs(f, direction, buf, buflen, rdir); + } else if (pe->ProbingParserTc != NULL) { + alproto = pe->ProbingParserTc(f, direction, buf, buflen, rdir); + } + if (AppProtoIsValid(alproto)) { + SCReturnUInt(alproto); + } + if (alproto == ALPROTO_FAILED || + (pe->max_depth != 0 && buflen > pe->max_depth)) { + alproto_masks[0] |= pe->alproto_mask; + } + pe = pe->next; + } + + SCReturnUInt(ALPROTO_UNKNOWN); +} + /** * \brief Call the probing parser if it exists for this flow. * @@ -453,22 +486,28 @@ static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t ipproto, */ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, uint8_t *buf, uint32_t buflen, - uint8_t ipproto, uint8_t direction, + uint8_t ipproto, const uint8_t idir, bool *reverse_flow) { const AppLayerProtoDetectProbingParserPort *pp_port_dp = NULL; const AppLayerProtoDetectProbingParserPort *pp_port_sp = NULL; - const AppLayerProtoDetectProbingParserElement *pe = NULL; const AppLayerProtoDetectProbingParserElement *pe1 = NULL; const AppLayerProtoDetectProbingParserElement *pe2 = NULL; AppProto alproto = ALPROTO_UNKNOWN; uint32_t *alproto_masks; uint32_t mask = 0; + uint8_t dir = idir; + uint16_t dp = f->protodetect_dp ? f->protodetect_dp : FLOW_GET_DP(f); + uint16_t sp = FLOW_GET_SP(f); - const uint16_t dp = f->protodetect_dp ? f->protodetect_dp : f->dp; - const uint16_t sp = f->sp; +again_midstream: + if (idir != dir) { + SWAP_VARS(uint16_t, dp, sp); /* look up parsers in rev dir */ + } + SCLogDebug("%u->%u %s", sp, dp, + (dir == STREAM_TOSERVER) ? "toserver" : "toclient"); - if (direction & STREAM_TOSERVER) { + if (dir == STREAM_TOSERVER) { /* first try the destination port */ pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp); alproto_masks = &f->probing_parser_toserver_alproto_masks; @@ -515,82 +554,62 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, if (pe1 == NULL && pe2 == NULL) { SCLogDebug("%s - No probing parsers found for either port", - (direction & STREAM_TOSERVER) ? "toserver":"toclient"); - FLOW_SET_PP_DONE(f, direction); - goto end; + (dir == STREAM_TOSERVER) ? "toserver":"toclient"); + if (dir == idir) + FLOW_SET_PP_DONE(f, dir); + goto noparsers; } - /* run the parser(s) */ + /* run the parser(s): always call with original direction */ uint8_t rdir = 0; - pe = pe1; - while (pe != NULL) { - if ((buflen < pe->min_depth) || - (alproto_masks[0] & pe->alproto_mask)) { - pe = pe->next; - continue; - } + alproto = PPGetProto(pe1, f, idir, buf, buflen, alproto_masks, &rdir); + if (AppProtoIsValid(alproto)) + goto end; + alproto = PPGetProto(pe2, f, idir, buf, buflen, alproto_masks, &rdir); + if (AppProtoIsValid(alproto)) + goto end; - if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { - alproto = pe->ProbingParserTs(f, direction, buf, buflen, &rdir); - } else if (pe->ProbingParserTc != NULL) { - alproto = pe->ProbingParserTc(f, direction, buf, buflen, &rdir); - } - if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) - goto end; - if (alproto == ALPROTO_FAILED || - (pe->max_depth != 0 && buflen > pe->max_depth)) { - alproto_masks[0] |= pe->alproto_mask; + /* get the mask we need for this direction */ + if (dir == idir) { + if (pp_port_dp && pp_port_sp) + mask = pp_port_dp->alproto_mask|pp_port_sp->alproto_mask; + else if (pp_port_dp) + mask = pp_port_dp->alproto_mask; + else if (pp_port_sp) + mask = pp_port_sp->alproto_mask; + + if (alproto_masks[0] == mask) { + FLOW_SET_PP_DONE(f, dir); + SCLogDebug("%s, mask is now %08x, needed %08x, so done", + (dir == STREAM_TOSERVER) ? "toserver":"toclient", + alproto_masks[0], mask); + } else { + SCLogDebug("%s, mask is now %08x, need %08x", + (dir == STREAM_TOSERVER) ? "toserver":"toclient", + alproto_masks[0], mask); } - pe = pe->next; } - pe = pe2; - while (pe != NULL) { - if ((buflen < pe->min_depth) || - (alproto_masks[0] & pe->alproto_mask)) { - pe = pe->next; - continue; - } - if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { - alproto = pe->ProbingParserTs(f, direction, buf, buflen, &rdir); - } else if (pe->ProbingParserTc != NULL) { - alproto = pe->ProbingParserTc(f, direction, buf, buflen, &rdir); - } - if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) - goto end; - if (alproto == ALPROTO_FAILED || - (pe->max_depth != 0 && buflen > pe->max_depth)) { - alproto_masks[0] |= pe->alproto_mask; + noparsers: + if (stream_config.midstream == true && idir == dir) { + if (idir == STREAM_TOSERVER) { + dir = STREAM_TOCLIENT; + } else { + dir = STREAM_TOSERVER; } - pe = pe->next; - } - - /* get the mask we need for this direction */ - if (pp_port_dp && pp_port_sp) - mask = pp_port_dp->alproto_mask|pp_port_sp->alproto_mask; - else if (pp_port_dp) - mask = pp_port_dp->alproto_mask; - else if (pp_port_sp) - mask = pp_port_sp->alproto_mask; - - if (alproto_masks[0] == mask) { - FLOW_SET_PP_DONE(f, direction); - SCLogDebug("%s, mask is now %08x, needed %08x, so done", - (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0], mask); - } else { - SCLogDebug("%s, mask is now %08x, need %08x", - (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0], mask); + SCLogDebug("no match + midstream, retry the other direction %s", + (dir == STREAM_TOSERVER) ? "toserver" : "toclient"); + goto again_midstream; } end: - if (alproto != ALPROTO_FAILED && alproto != ALPROTO_UNKNOWN && - rdir == (direction & (STREAM_TOSERVER|STREAM_TOCLIENT))) { + if (AppProtoIsValid(alproto) && rdir != 0 && rdir != idir) { SCLogDebug("PP found %u, is reverse flow", alproto); *reverse_flow = true; } SCLogDebug("%s, mask is now %08x", - (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]); + (idir == STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]); SCReturnUInt(alproto); } @@ -1482,8 +1501,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, if (!FLOW_IS_PM_DONE(f, direction)) { AppProto pm_results[ALPROTO_MAX]; uint16_t pm_matches = AppLayerProtoDetectPMGetProto(tctx, f, - buf, buflen, direction, - pm_results, reverse_flow); + buf, buflen, direction, pm_results, reverse_flow); if (pm_matches > 0) { alproto = pm_results[0]; @@ -1500,13 +1518,13 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, if (!FLOW_IS_PP_DONE(f, direction)) { bool rflow = false; - alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, - ipproto, direction, - &rflow); - if (alproto != ALPROTO_UNKNOWN) + alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, ipproto, + direction & (STREAM_TOSERVER|STREAM_TOCLIENT), &rflow); + if (AppProtoIsValid(alproto)) { + if (rflow) { + *reverse_flow = true; + } goto end; - if (rflow) { - *reverse_flow = true; } } @@ -1516,7 +1534,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, } end: - if (alproto == ALPROTO_UNKNOWN) + if (!AppProtoIsValid(alproto)) alproto = pm_alproto; SCReturnUInt(alproto);