From: Victor Julien Date: Wed, 19 Jun 2019 10:53:52 +0000 (+0200) Subject: detect: pkt inspect engines X-Git-Tag: suricata-5.0.0-rc1~249 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0965afd661327f33b3f494e88e33bd38e28e3a5e;p=thirdparty%2Fsuricata.git detect: pkt inspect engines Instead of hard coded calls to the inspection logic for payload inspection and 'MATCH'-list inspection use a callback approach. This will register a callback per 'sm_list' much like how app-layer inspect engines are registered. This will allow for adding more types later without adding runtime overhead. Implement the callback for the PMATCH and MATCH logic. --- diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index 65665c7e3f..47c6c3d11a 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -1845,6 +1845,9 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) SigMatch *sm = s->init_data->smlists[type]; s->sm_arrays[type] = SigMatchList2DataArray(sm); } + /* set up the pkt inspection engines */ + DetectEnginePktInspectionSetup(s); + if (rule_engine_analysis_set) { #ifdef HAVE_LIBJANSSON EngineAnalysisRules2(de_ctx, s); diff --git a/src/detect-engine.c b/src/detect-engine.c index 73cc890228..681c1e15ee 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1116,6 +1116,148 @@ int DetectBufferTypeGetByIdTransforms(DetectEngineCtx *de_ctx, const int id, return map->id; } +/* returns false if no match, true if match */ +static bool DetectEngineInspectRulePacketMatches( + ThreadVars *tv, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *sm_data, + Flow *f, Packet *p, + uint8_t *alert_flags) +{ + SCEnter(); + BUG_ON(sm_data != s->sm_arrays[DETECT_SM_LIST_MATCH]); + + /* run the packet match functions */ + KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH); + const SigMatchData *smd = sm_data; + + SCLogDebug("running match functions, sm %p", smd); + while (1) { + KEYWORD_PROFILING_START; + if (sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx) <= 0) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); + SCLogDebug("no match"); + return false; + } + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) { + SCLogDebug("match and is_last"); + break; + } + smd++; + } + return true; +} + +static bool DetectEngineInspectRulePayloadMatches( + ThreadVars *tv, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *sm_data, + Flow *f, Packet *p, + uint8_t *alert_flags) +{ + SCEnter(); + + BUG_ON(alert_flags == NULL); + DetectEngineCtx *de_ctx = det_ctx->de_ctx; + + KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH); + /* if we have stream msgs, inspect against those first, + * but not for a "dsize" signature */ + if (s->flags & SIG_FLAG_REQUIRE_STREAM) { + int pmatch = 0; + if (p->flags & PKT_DETECT_HAS_STREAMDATA) { + pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, f, p); + if (pmatch) { + det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH; + /* Tell the engine that this reassembled stream can drop the + * rest of the pkts with no further inspection */ + if (s->action & ACTION_DROP) + *alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; + + *alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH; + } + } + /* no match? then inspect packet payload */ + if (pmatch == 0) { + SCLogDebug("no match in stream, fall back to packet payload"); + + /* skip if we don't have to inspect the packet and segment was + * added to stream */ + if (!(s->flags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) { + return false; + } + if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, f, p) != 1) { + return false; + } + } + } else { + if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, f, p) != 1) { + return false; + } + } + return true; +} + +bool DetectEnginePktInspectionRun(ThreadVars *tv, + DetectEngineThreadCtx *det_ctx, const Signature *s, + Flow *f, Packet *p, + uint8_t *alert_flags) +{ + SCEnter(); + for (DetectEnginePktInspectionEngine *e = s->pkt_inspect; e != NULL; e = e->next) { + if (e->Callback(tv, det_ctx, s, e->sm_data, f, p, alert_flags) == false) { + SCLogDebug("sid %u: e %p Callback returned false", s->id, e); + return false; + } + SCLogDebug("sid %u: e %p Callback returned true", s->id, e); + } + SCLogDebug("sid %u: returning true", s->id); + return true; +} + +static int DetectEnginePktInspectionAppend(Signature *s, + DetectEnginePktInspectionFunc Callback, + SigMatchData *data) +{ + DetectEnginePktInspectionEngine *e = SCCalloc(1, sizeof(*e)); + if (e == NULL) + return -1; + + e->Callback = Callback; + e->sm_data = data; + + if (s->pkt_inspect == NULL) { + s->pkt_inspect = e; + } else { + DetectEnginePktInspectionEngine *a = s->pkt_inspect; + while (a->next != NULL) { + a = a->next; + } + a->next = e; + } + + return 0; +} + +int DetectEnginePktInspectionSetup(Signature *s) +{ + /* only handle PMATCH here if we're not an app inspect rule */ + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] && (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) == 0) { + if (DetectEnginePktInspectionAppend(s, DetectEngineInspectRulePayloadMatches, + s->sm_arrays[DETECT_SM_LIST_PMATCH]) < 0) + return -1; + SCLogDebug("sid %u: DetectEngineInspectRulePayloadMatches appended", s->id); + } + + if (s->sm_arrays[DETECT_SM_LIST_MATCH]) { + if (DetectEnginePktInspectionAppend(s, DetectEngineInspectRulePacketMatches, + s->sm_arrays[DETECT_SM_LIST_MATCH]) < 0) + return -1; + SCLogDebug("sid %u: DetectEngineInspectRulePacketMatches appended", s->id); + } + + return 0; +} + /* code to control the main thread to do a reload */ enum DetectEngineSyncState { diff --git a/src/detect-engine.h b/src/detect-engine.h index e4435a5413..7bf6f0fd78 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -145,6 +145,12 @@ void DetectAppLayerInspectEngineRegister2(const char *name, int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s); void DetectEngineAppInspectionEngineSignatureFree(Signature *s); +bool DetectEnginePktInspectionRun(ThreadVars *tv, + DetectEngineThreadCtx *det_ctx, const Signature *s, + Flow *f, Packet *p, + uint8_t *alert_flags); +int DetectEnginePktInspectionSetup(Signature *s); + void DetectEngineSetParseMetadata(void); void DetectEngineUnsetParseMetadata(void); int DetectEngineMustParseMetadata(void); diff --git a/src/detect-parse.c b/src/detect-parse.c index 5ef1cb7c49..2710a24de9 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1369,6 +1369,15 @@ void SigFree(Signature *s) DetectEngineAppInspectionEngineSignatureFree(s); + if (s->pkt_inspect) { + DetectEnginePktInspectionEngine *e = s->pkt_inspect; + while (e) { + DetectEnginePktInspectionEngine *next = e->next; + SCFree(e); + e = next; + } + } + SCFree(s); } diff --git a/src/detect.c b/src/detect.c index 3540ef2228..d224747e17 100644 --- a/src/detect.c +++ b/src/detect.c @@ -658,38 +658,6 @@ static inline int DetectRunInspectRuleHeader( return 1; } -/* returns 0 if no match, 1 if match */ -static inline int DetectRunInspectRulePacketMatches( - ThreadVars *tv, - DetectEngineThreadCtx *det_ctx, - Packet *p, - const Flow *f, - const Signature *s) -{ - /* run the packet match functions */ - if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) { - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH); - SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH]; - - SCLogDebug("running match functions, sm %p", smd); - while (1) { - KEYWORD_PROFILING_START; - if (sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx) <= 0) { - KEYWORD_PROFILING_END(det_ctx, smd->type, 0); - SCLogDebug("no match"); - return 0; - } - KEYWORD_PROFILING_END(det_ctx, smd->type, 1); - if (smd->is_last) { - SCLogDebug("match and is_last"); - break; - } - smd++; - } - } - return 1; -} - /** \internal * \brief run packet/stream prefilter engines */ @@ -827,49 +795,9 @@ static inline void DetectRulePacketRules( goto next; } - /* Check the payload keywords. If we are a MPM sig and we've made - * to here, we've had at least one of the patterns match */ - if (s->sm_arrays[DETECT_SM_LIST_PMATCH] != NULL) { - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH); - /* if we have stream msgs, inspect against those first, - * but not for a "dsize" signature */ - if (sflags & SIG_FLAG_REQUIRE_STREAM) { - int pmatch = 0; - if (p->flags & PKT_DETECT_HAS_STREAMDATA) { - pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, pflow, p); - if (pmatch) { - det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH; - /* Tell the engine that this reassembled stream can drop the - * rest of the pkts with no further inspection */ - if (s->action & ACTION_DROP) - alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; - - alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH; - } - } - /* no match? then inspect packet payload */ - if (pmatch == 0) { - SCLogDebug("no match in stream, fall back to packet payload"); - - /* skip if we don't have to inspect the packet and segment was - * added to stream */ - if (!(sflags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) { - goto next; - } - - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { - goto next; - } - } - } else { - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { - goto next; - } - } - } - - if (DetectRunInspectRulePacketMatches(tv, det_ctx, p, pflow, s) == 0) + if (DetectEnginePktInspectionRun(tv, det_ctx, s, pflow, p, &alert_flags) == false) { goto next; + } #ifdef PROFILING smatch = true; @@ -1154,8 +1082,8 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, TRACE_SID_TXS(s->id, tx, "DetectRunInspectRuleHeader() no match"); return false; } - if (DetectRunInspectRulePacketMatches(tv, det_ctx, p, f, s) == 0) { - TRACE_SID_TXS(s->id, tx, "DetectRunInspectRulePacketMatches no match"); + if (DetectEnginePktInspectionRun(tv, det_ctx, s, f, p, NULL) == false) { + TRACE_SID_TXS(s->id, tx, "DetectEnginePktInspectionRun no match"); return false; } /* stream mpm and negated mpm sigs can end up here with wrong proto */ diff --git a/src/detect.h b/src/detect.h index 30c26bc4c2..8702a4be28 100644 --- a/src/detect.h +++ b/src/detect.h @@ -438,6 +438,23 @@ typedef struct DetectBufferType_ { DetectEngineTransforms transforms; } DetectBufferType; +/* Function pointer for the pkt inspect engines. Goal for this + * function will be to process the complete list of conditions + * passed to it through 'sm_data'. */ +typedef bool (*DetectEnginePktInspectionFunc)(ThreadVars *, + struct DetectEngineThreadCtx_ *, + const struct Signature_ *s, + const struct SigMatchData_ *sm_data, + Flow *f, + Packet *p, + uint8_t *alert_flags); + +typedef struct DetectEnginePktInspectionEngine { + DetectEnginePktInspectionFunc Callback; + SigMatchData *sm_data; + struct DetectEnginePktInspectionEngine *next; +} DetectEnginePktInspectionEngine; + #ifdef UNITTESTS #define sm_lists init_data->smlists #define sm_lists_tail init_data->smlists_tail @@ -542,6 +559,7 @@ typedef struct Signature_ { IPOnlyCIDRItem *CidrSrc, *CidrDst; DetectEngineAppInspectionEngine *app_inspect; + DetectEnginePktInspectionEngine *pkt_inspect; /* Matching structures for the built-ins. The others are in * their inspect engines. */