From 822e034753130234b6713f28f355adc2d004d606 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Aug 2016 13:05:09 +0200 Subject: [PATCH] detect-flow: implement prefilter --- src/detect-flow.c | 117 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/src/detect-flow.c b/src/detect-flow.c index 304d97d9b9..78032cd005 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -30,6 +30,7 @@ #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" +#include "detect-engine-prefilter-common.h" #include "flow.h" #include "flow-var.h" @@ -53,6 +54,9 @@ static int DetectFlowSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowRegisterTests(void); void DetectFlowFree(void *); +static int PrefilterSetupFlow(SigGroupHead *sgh); +static _Bool PrefilterFlowIsPrefilterable(const Signature *s); + /** * \brief Registration function for flow: keyword */ @@ -66,14 +70,39 @@ void DetectFlowRegister (void) sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; sigmatch_table[DETECT_FLOW].RegisterTests = DetectFlowRegisterTests; + sigmatch_table[DETECT_FLOW].SupportsPrefilter = PrefilterFlowIsPrefilterable; + sigmatch_table[DETECT_FLOW].SetupPrefilter = PrefilterSetupFlow; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/* - * returns 0: no match - * 1: match - * -1: error - */ +static inline int FlowMatch(const uint8_t pflowflags, const uint16_t tflags, + const uint8_t dflags, const uint8_t match_cnt) +{ + uint8_t cnt = 0; + + if ((dflags & DETECT_FLOW_FLAG_TOSERVER) && (pflowflags & FLOW_PKT_TOSERVER)) { + cnt++; + } else if ((dflags & DETECT_FLOW_FLAG_TOCLIENT) && (pflowflags & FLOW_PKT_TOCLIENT)) { + cnt++; + } + + if ((dflags & DETECT_FLOW_FLAG_ESTABLISHED) && (pflowflags & FLOW_PKT_ESTABLISHED)) { + cnt++; + } else if (dflags & DETECT_FLOW_FLAG_STATELESS) { + cnt++; + } + + if (tflags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { + if (dflags & DETECT_FLOW_FLAG_ONLYSTREAM) + cnt++; + } else { + if (dflags & DETECT_FLOW_FLAG_NOSTREAM) + cnt++; + } + + return (match_cnt == cnt) ? 1 : 0; +} /** * \brief This function is used to match flow flags set on a packet with those passed via flow: @@ -102,32 +131,11 @@ int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S SCLogDebug("FLOW_PKT_ESTABLISHED"); } - uint8_t cnt = 0; const DetectFlowData *fd = (const DetectFlowData *)ctx; - if ((fd->flags & DETECT_FLOW_FLAG_TOSERVER) && (p->flowflags & FLOW_PKT_TOSERVER)) { - cnt++; - } else if ((fd->flags & DETECT_FLOW_FLAG_TOCLIENT) && (p->flowflags & FLOW_PKT_TOCLIENT)) { - cnt++; - } - - if ((fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) && (p->flowflags & FLOW_PKT_ESTABLISHED)) { - cnt++; - } else if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { - cnt++; - } - - if (det_ctx->flags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { - if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) - cnt++; - } else { - if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) - cnt++; - } - - int ret = (fd->match_cnt == cnt) ? 1 : 0; - SCLogDebug("returning %" PRId32 " cnt %" PRIu8 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", - ret, cnt, fd->match_cnt, fd->flags, p->flowflags); + int ret = FlowMatch(p->flowflags, det_ctx->flags, fd->flags, fd->match_cnt);; + SCLogDebug("returning %" PRId32 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", + ret, fd->match_cnt, fd->flags, p->flowflags); SCReturnInt(ret); } @@ -338,6 +346,57 @@ void DetectFlowFree(void *ptr) SCFree(fd); } +static void +PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (FlowMatch(p->flowflags, det_ctx->flags, ctx->v1.u8[0], ctx->v1.u8[1])) + { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFlowSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFlowData *fb = smctx; + v->u8[0] = fb->flags; + v->u8[1] = fb->match_cnt; +} + +static _Bool +PrefilterPacketFlowCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFlowData *fb = smctx; + if (v.u8[0] == fb->flags && + v.u8[1] == fb->match_cnt) + { + return TRUE; + } + return FALSE; +} + +static int PrefilterSetupFlow(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FLOW, + PrefilterPacketFlowSet, + PrefilterPacketFlowCompare, + PrefilterPacketFlowMatch); +} + +static _Bool PrefilterFlowIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLOW: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS /**