From 78251dfb771443fe4e24b36171ad2a16b7581008 Mon Sep 17 00:00:00 2001
From: Eric Leblond <eric@regit.org>
Date: Fri, 10 Aug 2012 15:32:30 +0200
Subject: [PATCH] Delay Detect threads initialization

This patch modifies the init of Detect threads. They are now started
with a dummy function and their initialisation is done after the
signatures are loaded. Just after this, the dummy function is switched
to normal one.

In IPS mode, this permit to route packets without waiting for the
signature to start and should fix #488.

Offline mode such as pcap file don't use this mode to be sure to
analyse all packets in the file.

The patch introduces a "delayed-detect" configuration variable
which can be use to restore previous behavior (set to "no" to
have signature loaded first).
---
 src/suricata.c      |   46 +++++++++++++++++++++------
 src/tm-threads.c    |   87 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/tm-threads.h    |    4 +++
 src/util-runmodes.c |   12 +++----
 suricata.yaml.in    |    4 +++
 5 files changed, 136 insertions(+), 17 deletions(-)

diff --git a/src/suricata.c b/src/suricata.c
index 0ae3719..7d31fcc 100644
--- a/src/suricata.c
+++ b/src/suricata.c
@@ -685,6 +685,7 @@ int main(int argc, char **argv)
 #endif /* OS_WIN32 */
     int build_info = 0;
     int rule_reload = 0;
+    int delayed_detect = 1;
 
     char *log_dir;
 #ifdef OS_WIN32
@@ -1705,18 +1706,30 @@ int main(int argc, char **argv)
     if (MagicInit() != 0)
         exit(EXIT_FAILURE);
 
-    if (SigLoadSignatures(de_ctx, sig_file, sig_file_exclusive) < 0) {
-        if (sig_file == NULL) {
-            SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided");
-        } else {
-            SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
+    /* In offline mode delayed init of detect is a bad idea */
+    if ((run_mode == RUNMODE_PCAP_FILE) ||
+        (run_mode == RUNMODE_ERF_FILE) ||
+        engine_analysis) {
+        delayed_detect = 0;
+    } else {
+        if (ConfGetBool("delayed-detect", &delayed_detect) != 1) {
+            delayed_detect = 1;
         }
-        if (de_ctx->failure_fatal)
-            exit(EXIT_FAILURE);
     }
 
-    if (engine_analysis) {
-        exit(EXIT_SUCCESS);
+    if (!delayed_detect) {
+        if (SigLoadSignatures(de_ctx, sig_file, sig_file_exclusive) < 0) {
+            if (sig_file == NULL) {
+                SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided");
+            } else {
+                SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
+            }
+            if (de_ctx->failure_fatal)
+                exit(EXIT_FAILURE);
+        }
+        if (engine_analysis) {
+            exit(EXIT_SUCCESS);
+        }
     }
 
     /* registering singal handlers we use.  We register usr2 here, so that one
@@ -1826,6 +1839,21 @@ int main(int argc, char **argv)
     /* Un-pause all the paused threads */
     TmThreadContinueThreads();
 
+    if (delayed_detect) {
+        if (SigLoadSignatures(de_ctx, sig_file, sig_file_exclusive) < 0) {
+            if (sig_file == NULL) {
+                SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided");
+            } else {
+                SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
+            }
+            if (de_ctx->failure_fatal)
+                exit(EXIT_FAILURE);
+        }
+        SCLogInfo("Signature(s) loaded, Detect thread(s) activated.");
+    }
+
+    TmThreadActivateDummySlot();
+
 #ifdef DBG_MEM_ALLOC
     SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem);
 #ifdef DBG_MEM_ALLOC_SKIP_STARTUP
diff --git a/src/tm-threads.c b/src/tm-threads.c
index 196d7da..5ee8211 100644
--- a/src/tm-threads.c
+++ b/src/tm-threads.c
@@ -43,6 +43,7 @@
 #include "util-optimize.h"
 #include "util-profiling.h"
 #include "util-signal.h"
+#include "queue.h"
 
 #ifdef PROFILE_LOCKING
 __thread uint64_t mutex_lock_contention;
@@ -119,6 +120,12 @@ void TmThreadsUnsetFlag(ThreadVars *tv, uint8_t flag)
     SC_ATOMIC_AND(tv->flags, ~flag);
 }
 
+
+TmEcode TmDummyFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
+{
+    return TM_ECODE_OK;
+}
+
 /* 1 slot functions */
 void *TmThreadsSlot1NoIn(void *td)
 {
@@ -885,13 +892,14 @@ ThreadVars *TmThreadsGetTVContainingSlot(TmSlot *tm_slot)
  * \param tm   TM to append.
  * \param data Data to be passed on to the slot init function.
  */
-void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data)
+
+static inline TmSlot * _TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data)
 {
     TmSlot *s = (TmSlot *)tv->tm_slots;
 
     TmSlot *slot = SCMalloc(sizeof(TmSlot));
     if (slot == NULL)
-        return;
+        return NULL;
     memset(slot, 0, sizeof(TmSlot));
     SC_ATOMIC_INIT(slot->slot_data);
     slot->tv = tv;
@@ -924,9 +932,84 @@ void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data)
         }
     }
 
+    return slot;
+}
+
+void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data)
+{
+    _TmSlotSetFuncAppend(tv, tm, data);
+}
+
+typedef struct TmDummySlot_ {
+    TmSlot *slot;
+    TmEcode (*SlotFunc)(ThreadVars *, Packet *, void *, PacketQueue *,
+                        PacketQueue *);
+    TmEcode (*SlotThreadInit)(ThreadVars *, void *, void **);
+    TAILQ_ENTRY(TmDummySlot_) next;
+} TmDummySlot;
+
+static TAILQ_HEAD(, TmDummySlot_) dummy_slots =
+    TAILQ_HEAD_INITIALIZER(dummy_slots);
+
+void TmSlotSetFuncAppendDelayed(ThreadVars *tv, TmModule *tm, void *data)
+{
+    TmSlot *slot = _TmSlotSetFuncAppend(tv, tm, data);
+    TmDummySlot *dslot = SCMalloc(sizeof(TmDummySlot));
+
+    if (slot == NULL) {
+        return;
+    }
+    if (dslot == NULL) {
+        return;
+    }
+
+    memset(dslot, 0, sizeof(*dslot));
+
+    dslot->SlotFunc = slot->SlotFunc;
+    slot->SlotFunc = TmDummyFunc;
+    dslot->SlotThreadInit = slot->SlotThreadInit;
+    slot->SlotThreadInit = NULL;
+    dslot->slot = slot;
+
+    TAILQ_INSERT_TAIL(&dummy_slots, dslot, next);
+
     return;
 }
 
+void TmThreadActivateDummySlot()
+{
+    TmDummySlot *dslot;
+    TmSlot *s;
+    TmEcode r = TM_ECODE_OK;
+
+    TAILQ_FOREACH(dslot, &dummy_slots, next) {
+        void *slot_data = NULL;
+        s = dslot->slot;
+        if (dslot->SlotThreadInit != NULL) {
+            s->SlotThreadInit = dslot->SlotThreadInit;
+            r = s->SlotThreadInit(s->tv, s->slot_initdata, &slot_data);
+            if (r != TM_ECODE_OK) {
+                EngineKill();
+                TmThreadsSetFlag(s->tv, THV_CLOSED | THV_RUNNING_DONE);
+            }
+            SC_ATOMIC_SET(s->slot_data, slot_data);
+        }
+        s->SlotFunc = dslot->SlotFunc;
+    }
+}
+
+void TmThreadDeActivateDummySlot()
+{
+    TmDummySlot *dslot;
+
+    TAILQ_FOREACH(dslot, &dummy_slots, next) {
+        dslot->slot->SlotFunc = TmDummyFunc;
+        dslot->slot->SlotThreadInit = NULL;
+    }
+}
+
+
+
 /**
  * \brief Returns the slot holding a TM with the particular tm_id.
  *
diff --git a/src/tm-threads.h b/src/tm-threads.h
index 7f16384..3733758 100644
--- a/src/tm-threads.h
+++ b/src/tm-threads.h
@@ -72,6 +72,7 @@ extern ThreadVars *tv_root[TVT_MAX];
 extern SCMutex tv_root_lock;
 
 void TmSlotSetFuncAppend(ThreadVars *, TmModule *, void *);
+void TmSlotSetFuncAppendDelayed(ThreadVars *, TmModule *, void *);
 TmSlot *TmSlotGetSlotForTM(int);
 
 ThreadVars *TmThreadCreate(char *, char *, char *, char *, char *, char *,
@@ -104,6 +105,9 @@ void TmThreadCheckThreadState(void);
 TmEcode TmThreadWaitOnThreadInit(void);
 ThreadVars *TmThreadsGetCallingThread(void);
 
+void TmThreadActivateDummySlot(void);
+void TmThreadDeActivateDummySlot(void);
+
 int TmThreadsCheckFlag(ThreadVars *, uint8_t);
 void TmThreadsSetFlag(ThreadVars *, uint8_t);
 void TmThreadsUnsetFlag(ThreadVars *, uint8_t);
diff --git a/src/util-runmodes.c b/src/util-runmodes.c
index 7aa693a..23769bb 100644
--- a/src/util-runmodes.c
+++ b/src/util-runmodes.c
@@ -330,7 +330,7 @@ int RunModeSetLiveCaptureAuto(DetectEngineCtx *de_ctx,
             SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed");
             exit(EXIT_FAILURE);
         }
-        TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx);
+        TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx);
 
         TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET);
 
@@ -574,7 +574,7 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx,
             SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed");
             exit(EXIT_FAILURE);
         }
-        TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx);
+        TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx);
 
         TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET);
 
@@ -674,7 +674,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx,
             SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed");
             exit(EXIT_FAILURE);
         }
-        TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx);
+        TmSlotSetFuncAppendDelayed(tv, tm_module, (void *)de_ctx);
 
         tm_module = TmModuleGetByName("RespondReject");
         if (tm_module == NULL) {
@@ -879,7 +879,7 @@ int RunModeSetIPSAuto(DetectEngineCtx *de_ctx,
             printf("ERROR: TmModuleGetByName Detect failed\n");
             exit(EXIT_FAILURE);
         }
-        TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx);
+        TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx);
 
         TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET);
 
@@ -1064,7 +1064,7 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx,
             SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed");
             exit(EXIT_FAILURE);
         }
-        TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx);
+        TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx);
 
         TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET);
 
@@ -1181,7 +1181,7 @@ int RunModeSetIPSWorker(DetectEngineCtx *de_ctx,
             SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed");
             exit(EXIT_FAILURE);
         }
-        TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx);
+        TmSlotSetFuncAppendDelayed(tv, tm_module, (void *)de_ctx);
 
         tm_module = TmModuleGetByName(verdict_mod_name);
         if (tm_module == NULL) {
diff --git a/suricata.yaml.in b/suricata.yaml.in
index 18fd315..0942c75 100644
--- a/suricata.yaml.in
+++ b/suricata.yaml.in
@@ -921,3 +921,7 @@ profiling:
 
 coredump:
   max-dump: unlimited
+
+# If set to no, the loading of signatures will be made before the engine
+# is started.
+#delayed-detect: no
-- 
1.7.10.4

