]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: pkt inspect engines
authorVictor Julien <victor@inliniac.net>
Wed, 19 Jun 2019 10:53:52 +0000 (12:53 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 21 Jun 2019 05:16:17 +0000 (07:16 +0200)
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.

src/detect-engine-build.c
src/detect-engine.c
src/detect-engine.h
src/detect-parse.c
src/detect.c
src/detect.h

index 65665c7e3f3b6266cb1d4e007433eb34fcda4633..47c6c3d11a03824bb248467bd5b12a9d7ec63263 100644 (file)
@@ -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);
index 73cc890228934bc13b2988ad77adc548f8db9c96..681c1e15ee20cf8f08c8a9ec00a0c636fafcda4e 100644 (file)
@@ -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 {
index e4435a5413993b571a1961a76fb1fc1a2e12e921..7bf6f0fd78baab3faf9bbd7b7ce3cdef83b5a6ea 100644 (file)
@@ -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);
index 5ef1cb7c49e7244aff3c8ba35ea64fe4205c9f90..2710a24de967bc4ebb97552f92a9f9b84f44cd68 100644 (file)
@@ -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);
 }
 
index 3540ef2228deb561dcb98ae198cd37cc3f4c964d..d224747e17edddc31b315ab13470990831ac26de 100644 (file)
@@ -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 */
index 30c26bc4c2d98c6d5687fe4342500fda605ca1af..8702a4be281f13cabfbbc1a92f78ec64fca8c3f7 100644 (file)
@@ -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. */