]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
live rule support added
authorAnoop Saldanha <poonaatsoc@gmail.com>
Fri, 22 Jun 2012 15:38:26 +0000 (21:08 +0530)
committerVictor Julien <victor@inliniac.net>
Tue, 26 Jun 2012 07:36:10 +0000 (09:36 +0200)
To reload ruleset during engine runtime, send the USR2 signal to the engine, and the ruleset would be reloaded from the same yaml file supplied at engine startup

13 files changed:
src/counters.c
src/detect-engine-state.c
src/detect-engine-state.h
src/detect-engine.c
src/detect-engine.h
src/detect.c
src/detect.h
src/flow-manager.c
src/flow.h
src/suricata.c
src/suricata.h
src/tm-modules.h
src/tm-threads.c

index cf4f9f3e9ecf464e9fc0608445e96a6204806241..53e9c9caceb976b63db83bab13839cae1b0e73e9 100644 (file)
@@ -433,6 +433,12 @@ static void SCPerfReleaseOPCtx()
  */
 static void *SCPerfMgmtThread(void *arg)
 {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv_local = (ThreadVars *)arg;
     uint8_t run = 1;
     struct timespec cond_time;
@@ -487,6 +493,12 @@ static void *SCPerfMgmtThread(void *arg)
  */
 static void *SCPerfWakeupThread(void *arg)
 {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv_local = (ThreadVars *)arg;
     uint8_t run = 1;
     ThreadVars *tv = NULL;
index 3cdf0d744403a5f0b0d58f125a3c20592acaa13e..3e714d720b26d2b1030c62cc299b96f57dec6cfc 100644 (file)
@@ -366,7 +366,7 @@ void DeStateStoreFileNoMatch(DetectEngineState *de_state, uint8_t direction,
  *  \retval 1 has state
  *  \retval 0 has no state
  */
-int DeStateFlowHasState(Flow *f, uint8_t flags, uint16_t alversion) {
+int DeStateFlowHasState(DetectEngineCtx *de_ctx, Flow *f, uint8_t flags, uint16_t alversion) {
     SCEnter();
 
     int r = 0;
@@ -679,7 +679,15 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
      * the last SigMatch that didn't match */
     if (f->de_state == NULL) {
         f->de_state = DetectEngineStateAlloc();
+        f->de_state->de_ctx_id = de_ctx->id;
+    } else {
+        if (f->de_state->de_ctx_id != de_ctx->id) {
+            DetectEngineStateReset(f->de_state);
+            f->de_state = DetectEngineStateAlloc();
+            f->de_state->de_ctx_id = de_ctx->id;
+        }
     }
+
     if (f->de_state != NULL) {
         /* \todo shift to an array to transfer these match values*/
         DeStateSignatureAppend(f->de_state, s, sm, match_flags);
@@ -727,6 +735,13 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete
     if (f->de_state == NULL || f->de_state->cnt == 0)
         goto end;
 
+    if (f->de_state->de_ctx_id != de_ctx->id) {
+        DetectEngineStateReset(f->de_state);
+        f->de_state = NULL;
+        SCMutexUnlock(&f->de_state_m);
+        SCReturnInt(0);
+    }
+
     DeStateResetFileInspection(f, alproto, alstate);
 
     /* loop through the stores */
index ad717be3eefeefb1938403454a3affb4125fe047..1602dc1ad19aca9ea996b5ec6d693d03c9179040 100644 (file)
@@ -125,6 +125,10 @@ typedef struct DetectEngineState_ {
                                      *   cannot match in to client direction. */
     uint16_t toserver_filestore_cnt;/**< number of sigs with filestore that
                                      *   cannot match in to server direction. */
+
+    /* the de_ctx id that the state belongs to */
+    uint32_t de_ctx_id;
+
     uint16_t flags;
 } DetectEngineState;
 
@@ -137,7 +141,7 @@ void DetectEngineStateReset(DetectEngineState *state);
 DetectEngineState *DetectEngineStateAlloc(void);
 void DetectEngineStateFree(DetectEngineState *);
 
-int DeStateFlowHasState(Flow *, uint8_t, uint16_t);
+int DeStateFlowHasState(DetectEngineCtx *, Flow *, uint8_t, uint16_t);
 
 int DeStateDetectStartDetection(ThreadVars *, DetectEngineCtx *,
         DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *,
index 46cea5db2872a17494a772a81e14c157bd0e69ba..669294ea61e69e19c736149af61c09996fa4eff4 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "suricata-common.h"
+#include "suricata.h"
 #include "debug.h"
 #include "detect.h"
 #include "flow.h"
 //#include "util-mpm.h"
 #include "util-classification-config.h"
 #include "util-reference-config.h"
+#include "util-threshold-config.h"
 #include "util-error.h"
 #include "util-hash.h"
 #include "util-byte.h"
 #include "util-debug.h"
 #include "util-unittest.h"
+#include "util-action.h"
+#include "util-magic.h"
 
 #include "util-var-name.h"
 
 
 #define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000
 
+static uint32_t detect_engine_ctx_id = 0;
+
+static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *, void *, void **);
+
 static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *);
 
+static void *DetectEngineLiveRuleSwap(void *arg)
+{
+    SCEnter();
+
+    SCLogInfo("===== Starting live rule swap triggered by user signal USR2 =====");
+
+    ThreadVars *tv_local = (ThreadVars *)arg;
+
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
+    ConfDeInit();
+    ConfInit();
+
+    /* re-load the yaml file */
+    if (conf_filename != NULL) {
+        if (ConfYamlLoadFile(conf_filename) != 0) {
+            /* Error already displayed. */
+            exit(EXIT_FAILURE);
+        }
+
+        ConfNode *file;
+        ConfNode *includes = ConfGetNode("include");
+        if (includes != NULL) {
+            TAILQ_FOREACH(file, &includes->head, next) {
+                char *ifile = ConfLoadCompleteIncludePath(file->val);
+                SCLogInfo("Live Rule Swap: Including: %s", ifile);
+
+                if (ConfYamlLoadFile(ifile) != 0) {
+                    /* Error already displayed. */
+                    exit(EXIT_FAILURE);
+                }
+            }
+        }
+    } /* if (conf_filename != NULL) */
+
+#if 0
+    ConfDump();
+#endif
+
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+
+    SCClassConfLoadClassficationConfigFile(de_ctx);
+    SCRConfLoadReferenceConfigFile(de_ctx);
+
+    if (ActionInitConfig() < 0) {
+        exit(EXIT_FAILURE);
+    }
+
+    //if (MagicInit() != 0)
+    //    exit(EXIT_FAILURE);
+
+    if (SigLoadSignatures(de_ctx, NULL, FALSE) < 0) {
+        SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
+        if (de_ctx->failure_fatal)
+            exit(EXIT_FAILURE);
+    }
+
+    SCThresholdConfInitContext(de_ctx, NULL);
+
+
+    /* start the process of swapping detect threads ctxs */
+
+    SCMutexLock(&tv_root_lock);
+
+    int no_of_detect_tvs = 0;
+    ThreadVars *tv = tv_root[TVT_PPT];
+    while (tv) {
+        /* obtain the slots for this TV */
+        TmSlot *slots = tv->tm_slots;
+        while (slots != NULL) {
+            TmModule *tm = TmModuleGetById(slots->tm_id);
+
+            if (suricata_ctl_flags != 0) {
+                TmThreadsSetFlag(tv_local, THV_CLOSED);
+
+                SCLogInfo("===== Live rule swap premature exit, since "
+                          "suricta_ctl_flags != 0 =====");
+
+                SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2EngineShutdown);
+
+                pthread_exit(NULL);
+            }
+
+            if (!(tm->flags & TM_FLAG_DETECT_TM)) {
+                slots = slots->slot_next;
+                continue;
+            }
+
+            no_of_detect_tvs++;
+
+            slots = slots->slot_next;
+        }
+
+        tv = tv->next;
+    }
+
+    DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs];
+    DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs];
+
+    /* all receive threads are part of packet processing threads */
+    tv = tv_root[TVT_PPT];
+    int i = 0;
+    while (tv) {
+        /* obtain the slots for this TV */
+        TmSlot *slots = tv->tm_slots;
+        while (slots != NULL) {
+            TmModule *tm = TmModuleGetById(slots->tm_id);
+
+            if (!(tm->flags & TM_FLAG_DETECT_TM)) {
+                slots = slots->slot_next;
+                continue;
+            }
+
+            old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data);
+
+            DetectEngineThreadCtx *det_ctx = NULL;
+            DetectEngineThreadCtxInitForLiveRuleSwap(tv, (void *)de_ctx,
+                                                     (void **)&det_ctx);
+            SCLogDebug("live rule swap done with new det_ctx - %p and de_ctx "
+                       "- %p\n", det_ctx, de_ctx);
+
+            new_det_ctx[i] = det_ctx;
+            i++;
+
+            if (suricata_ctl_flags != 0) {
+                TmThreadsSetFlag(tv_local, THV_CLOSED);
+
+                SCLogInfo("===== Live rule swap premature exit between "
+                          "swapping det_ctxs, since "
+                          "suricta_ctl_flags != 0 =====");
+
+                SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2EngineShutdown);
+
+                pthread_exit(NULL);
+            }
+
+
+            SC_ATOMIC_CAS(&slots->slot_data, SC_ATOMIC_GET(slots->slot_data),
+                          det_ctx);
+            SCLogDebug("swapping new det_ctx with older one");
+
+            slots = slots->slot_next;
+        }
+
+        tv = tv->next;
+    }
+
+    SCMutexUnlock(&tv_root_lock);
+
+    SCLogInfo("Live rule swap has swapped %d old det_ctx's with new ones, "
+              "along with the new de_ctx", no_of_detect_tvs);
+
+    for (i = 0; i < no_of_detect_tvs; i++) {
+        while (new_det_ctx[i]->so_far_used_by_detect != 1) {
+            SCLogDebug("new_det_ctx - %p used by detect", new_det_ctx[i]);
+            if (suricata_ctl_flags != 0) {
+                TmThreadsSetFlag(tv_local, THV_CLOSED);
+
+                SCLogInfo("===== Live rule swap done, but premature exit at "
+                          "de-init phase, since suricta_ctl_flags != 0 =====");
+
+                SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2EngineShutdown);
+
+                pthread_exit(NULL);
+            }
+
+            usleep(1000);
+        }
+    }
+
+    DetectEngineCtx *old_de_ctx = old_det_ctx[0]->de_ctx;
+    for (i = 0; i < no_of_detect_tvs; i++) {
+        SCLogDebug("Freeing old_det_ctx - %p used by detect",
+                   old_det_ctx[i]);
+        if (suricata_ctl_flags != 0) {
+            TmThreadsSetFlag(tv_local, THV_CLOSED);
+
+            SCLogInfo("===== Live rule swap done, but premature exit at "
+                      "de-init phase, since suricta_ctl_flags != 0 =====");
+
+            SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2EngineShutdown);
+
+            pthread_exit(NULL);
+        }
+
+
+        DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]);
+    }
+    DetectEngineCtxFree(old_de_ctx);
+
+    SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2);
+
+    TmThreadsSetFlag(tv_local, THV_CLOSED);
+
+    SCLogInfo("===== Live rule swap DONE =====");
+
+    pthread_exit(NULL);
+}
+
+void DetectEngineSpawnLiveRuleSwapMgmtThread(void)
+{
+    SCEnter();
+
+    SCLogDebug("Spawning mgmt thread for live rule swap");
+
+    ThreadVars *tv = TmThreadCreateMgmtThread("DetectEngineLiveRuleSwap",
+                                              DetectEngineLiveRuleSwap, 0);
+    if (tv == NULL) {
+        SCLogError(SC_ERR_THREAD_CREATE, "Live rule swap thread spawn failed");
+        exit(EXIT_FAILURE);
+    }
+    if (TmThreadSpawn(tv) != 0) {
+        SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for "
+                   "DetectEngineLiveRuleSwap");
+        exit(EXIT_FAILURE);
+    }
+
+    SCReturn;
+}
+
 DetectEngineCtx *DetectEngineCtxInit(void) {
     DetectEngineCtx *de_ctx;
 
@@ -133,6 +365,8 @@ DetectEngineCtx *DetectEngineCtxInit(void) {
         goto error;
     }
 
+    de_ctx->id = detect_engine_ctx_id++;
+
     return de_ctx;
 error:
     return NULL;
@@ -168,6 +402,8 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) {
     SCClassConfDeInitContext(de_ctx);
     SCRConfDeInitContext(de_ctx);
 
+    SigGroupCleanup(de_ctx);
+
     SCFree(de_ctx);
     //DetectAddressGroupPrintMemory();
     //DetectSigGroupPrintMemory();
@@ -453,7 +689,79 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) {
     /* this detection engine context belongs to this thread instance */
     det_ctx->tv = tv;
 
-    det_ctx->bj_values = SCMalloc(sizeof(*det_ctx->bj_values) * de_ctx->byte_extract_max_local_id);
+    det_ctx->bj_values = SCMalloc(sizeof(*det_ctx->bj_values) *
+                                  (de_ctx->byte_extract_max_local_id + 1));
+    if (det_ctx->bj_values == NULL) {
+        return TM_ECODE_FAILED;
+    }
+
+    *data = (void *)det_ctx;
+
+    return TM_ECODE_OK;
+}
+
+static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *initdata, void **data)
+{
+    DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata;
+    if (de_ctx == NULL)
+        return TM_ECODE_FAILED;
+
+    DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx));
+    if (det_ctx == NULL)
+        return TM_ECODE_FAILED;
+    memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
+
+    det_ctx->de_ctx = de_ctx;
+
+    /** \todo we still depend on the global mpm_ctx here
+     *
+     * Initialize the thread pattern match ctx with the max size
+     * of the content and uricontent id's so our match lookup
+     * table is always big enough
+     */
+    PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx));
+    PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx));
+    PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher, DetectUricontentMaxId(de_ctx));
+
+    //PmqSetup(&det_ctx->pmq, DetectEngineGetMaxSigId(de_ctx), DetectContentMaxId(de_ctx));
+    PmqSetup(&det_ctx->pmq, 0, DetectContentMaxId(de_ctx));
+    int i;
+    for (i = 0; i < 256; i++) {
+        PmqSetup(&det_ctx->smsg_pmq[i], 0, DetectContentMaxId(de_ctx));
+    }
+
+    /* IP-ONLY */
+    DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx);
+
+    /* DeState */
+    if (de_ctx->sig_array_len > 0) {
+        det_ctx->de_state_sig_array_len = de_ctx->sig_array_len;
+        det_ctx->de_state_sig_array = SCMalloc(det_ctx->de_state_sig_array_len * sizeof(uint8_t));
+        if (det_ctx->de_state_sig_array == NULL) {
+            return TM_ECODE_FAILED;
+        }
+        memset(det_ctx->de_state_sig_array, 0,
+               det_ctx->de_state_sig_array_len * sizeof(uint8_t));
+
+        det_ctx->match_array_len = de_ctx->sig_array_len;
+        det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *));
+        if (det_ctx->match_array == NULL) {
+            return TM_ECODE_FAILED;
+        }
+        memset(det_ctx->match_array, 0,
+               det_ctx->match_array_len * sizeof(Signature *));
+    }
+
+    /** alert counter setup */
+    det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv,
+                                                      SC_PERF_TYPE_UINT64, "NULL");
+    //tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx);
+    //SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->sc_perf_pctx);
+
+    /* this detection engine context belongs to this thread instance */
+    det_ctx->tv = tv;
+
+    det_ctx->bj_values = SCMalloc(sizeof(*det_ctx->bj_values) * (de_ctx->byte_extract_max_local_id + 1));
     if (det_ctx->bj_values == NULL) {
         return TM_ECODE_FAILED;
     }
index 42c4bb8e09c52d9381eb072fa5b4ec3c6cc8dd8b..e04f6a5a6ee941a55cf62e4a30db780e5dd85a1c 100644 (file)
@@ -28,6 +28,7 @@
 #include "tm-threads.h"
 
 /* prototypes */
+void DetectEngineSpawnLiveRuleSwapMgmtThread(void);
 DetectEngineCtx *DetectEngineCtxInit(void);
 void DetectEngineCtxFree(DetectEngineCtx *);
 
index fbd597a344f51850f7f6c270139accceba276149..e50e2b0cb3cc5e2829e7a44033e65194d029cec3 100644 (file)
@@ -208,6 +208,7 @@ void TmModuleDetectRegister (void) {
     tmm_modules[TMM_DETECT].ThreadDeinit = DetectThreadDeinit;
     tmm_modules[TMM_DETECT].RegisterTests = SigRegisterTests;
     tmm_modules[TMM_DETECT].cap_flags = 0;
+    tmm_modules[TMM_DETECT].flags = TM_FLAG_DETECT_TM;
 
     PacketAlertTagInit();
 }
@@ -1338,11 +1339,19 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
             if (IP_GET_IPPROTO(p) == p->flow->proto) { /* filter out icmp */
                 PACKET_PROFILING_DETECT_START(p, PROF_DETECT_GETSGH);
                 if (p->flowflags & FLOW_PKT_TOSERVER && p->flow->flags & FLOW_SGH_TOSERVER) {
-                    det_ctx->sgh = p->flow->sgh_toserver;
-                    sms_runflags |= SMS_USE_FLOW_SGH;
+                    if (p->flow->sgh_toserver_de_ctx_id != de_ctx->id) {
+                        p->flow->flags &= ~FLOW_SGH_TOSERVER;
+                    } else {
+                        det_ctx->sgh = p->flow->sgh_toserver;
+                        sms_runflags |= SMS_USE_FLOW_SGH;
+                    }
                 } else if (p->flowflags & FLOW_PKT_TOCLIENT && p->flow->flags & FLOW_SGH_TOCLIENT) {
-                    det_ctx->sgh = p->flow->sgh_toclient;
-                    sms_runflags |= SMS_USE_FLOW_SGH;
+                    if (p->flow->sgh_toclient_de_ctx_id != de_ctx->id) {
+                        p->flow->flags &= ~FLOW_SGH_TOCLIENT;
+                    } else {
+                        det_ctx->sgh = p->flow->sgh_toclient;
+                        sms_runflags |= SMS_USE_FLOW_SGH;
+                    }
                 }
                 PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH);
 
@@ -1479,7 +1488,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
         memset(det_ctx->de_state_sig_array, 0x00, det_ctx->de_state_sig_array_len);
 
         /* if applicable, continue stateful detection */
-        int state = DeStateFlowHasState(p->flow, flags, alversion);
+        int state = DeStateFlowHasState(de_ctx, p->flow, flags, alversion);
         if (state == 1) {
             DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p->flow,
                     flags, alstate, alproto, alversion);
@@ -1767,6 +1776,7 @@ end:
             if (p->flowflags & FLOW_PKT_TOSERVER && !(p->flow->flags & FLOW_SGH_TOSERVER)) {
                 /* first time we see this toserver sgh, store it */
                 p->flow->sgh_toserver = det_ctx->sgh;
+                p->flow->sgh_toserver_de_ctx_id = de_ctx->id;
                 p->flow->flags |= FLOW_SGH_TOSERVER;
 
                 /* see if this sgh requires us to consider file storing */
@@ -1783,6 +1793,7 @@ end:
                 }
             } else if (p->flowflags & FLOW_PKT_TOCLIENT && !(p->flow->flags & FLOW_SGH_TOCLIENT)) {
                 p->flow->sgh_toclient = det_ctx->sgh;
+                p->flow->sgh_toclient_de_ctx_id = de_ctx->id;
                 p->flow->flags |= FLOW_SGH_TOCLIENT;
 
                 if (p->flow->sgh_toclient == NULL || p->flow->sgh_toclient->filestore_cnt == 0) {
@@ -1842,6 +1853,12 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue
         goto error;
     }
 
+    if (det_ctx->so_far_used_by_detect == 0) {
+        det_ctx->so_far_used_by_detect = 1;
+        SCLogDebug("Detect Engine using new det_ctx - %p and de_ctx - %p",
+                  det_ctx, de_ctx);
+    }
+
     /* see if the packet matches one or more of the sigs */
     int r = SigMatchSignatures(tv,de_ctx,det_ctx,p);
     if (r >= 0) {
index eb425947c3db137f1aed9378f720cd96ec4544c5..53635ecc7578e72924900363ed23ba877619bae8 100644 (file)
@@ -659,6 +659,9 @@ typedef struct DetectEngineCtx_ {
     /* the max local id used amongst all sigs */
     int32_t byte_extract_max_local_id;
 
+    /* id used by every detect engine ctx instance */
+    uint32_t id;
+
     /** sgh for signatures that match against invalid packets. In those cases
      *  we can't lookup by proto, address, port as we don't have these */
     struct SigGroupHead_ *decoder_event_sgh;
@@ -733,6 +736,8 @@ typedef struct DetectionEngineThreadCtx_ {
     /** ID of the transaction currently being inspected. */
     uint16_t tx_id;
 
+    uint16_t so_far_used_by_detect;
+
     /* holds the current recursion depth on content inspection */
     int inspection_recursion_counter;
 
index 0e3dbe2d50ee7ada1d84fd81be608eda55659afb..36dd467db4004b1599a12df7cb1e71cf9a4a4fd9 100644 (file)
@@ -371,6 +371,12 @@ next:
  */
 void *FlowManagerThread(void *td)
 {
+    /* block usr1.  usr1 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *th_v = (ThreadVars *)td;
     struct timeval ts;
     uint32_t established_cnt = 0, new_cnt = 0, closing_cnt = 0;
index 45a32edf574090e7a9f4d044d1a2923f3f3086d1..46b4c8101dcf2750dac0925f26bd606434402f0a 100644 (file)
@@ -327,9 +327,11 @@ typedef struct Flow_
     /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag
      *  has been set. */
     struct SigGroupHead_ *sgh_toclient;
+    uint32_t sgh_toclient_de_ctx_id;
     /** toserver sgh for this flow. Only use when FLOW_SGH_TOSERVER flow flag
      *  has been set. */
     struct SigGroupHead_ *sgh_toserver;
+    uint32_t sgh_toserver_de_ctx_id;
 
     /** List of tags of this flow (from "tag" keyword of type "session") */
     void *tag_list;
index d4e270c333db71c0b15a0c35dcf81f917b2bb61e..f29161e36a2310b1aca7e147b75295197ce7eebc 100644 (file)
@@ -222,6 +222,8 @@ intmax_t max_pending_packets;
 /** set caps or not */
 int sc_set_caps;
 
+char *conf_filename = NULL;
+
 int RunmodeIsUnittests(void) {
     if (run_mode == RUNMODE_UNITTEST)
         return 1;
@@ -237,6 +239,41 @@ static void SignalHandlerSigterm(/*@unused@*/ int sig) {
     sigterm_count = 1;
     suricata_ctl_flags |= SURICATA_KILL;
 }
+
+void SignalHandlerSigusr2EngineShutdown(int sig)
+{
+    SCLogInfo("Live rule swap no longer possible.  Engine in shutdown mode.");
+
+    return;
+}
+
+static void SignalHandlerSigusr2Idle(int sig)
+{
+    if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) {
+        SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode");
+        return;
+    }
+
+    SCLogInfo("Hang on buddy!  Ruleset load in progress.  New ruleset load "
+              "allowed after current is done");
+
+    return;
+}
+
+void SignalHandlerSigusr2(int sig)
+{
+    if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) {
+        SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode");
+        return;
+    }
+
+    SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle);
+
+    DetectEngineSpawnLiveRuleSwapMgmtThread();
+
+    return;
+}
+
 #if 0
 static void SignalHandlerSighup(/*@unused@*/ int sig) {
     sighup_count = 1;
@@ -258,8 +295,7 @@ uint8_t print_mem_flag = 1;
 #endif
 #endif
 
-static void
-SignalHandlerSetup(int sig, void (*handler)())
+void SignalHandlerSetup(int sig, void (*handler)())
 {
 #if defined (OS_WIN32)
        signal(sig, handler);
@@ -630,7 +666,6 @@ int main(int argc, char **argv)
     char *sig_file = NULL;
     int sig_file_exclusive = FALSE;
     int conf_test = 0;
-    char *conf_filename = NULL;
     char *pid_filename = NULL;
 #ifdef UNITTESTS
     char *regex_arg = NULL;
@@ -1435,6 +1470,8 @@ int main(int argc, char **argv)
 
     AppLayerHtpNeedFileInspection();
 
+    SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle);
+
 #ifdef UNITTESTS
 
     if (run_mode == RUNMODE_UNITTEST) {
@@ -1671,6 +1708,10 @@ int main(int argc, char **argv)
         exit(EXIT_SUCCESS);
     }
 
+    /* registering singal handlers we use.  We register usr2 here, so that one
+     * can't call it during the first sig load phase */
+    SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2);
+
 #ifdef PROFILING
     SCProfilingInitRuleCounters(de_ctx);
 #endif /* PROFILING */
@@ -1838,6 +1879,8 @@ int main(int argc, char **argv)
         usleep(10* 1000);
     }
 
+    SignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2EngineShutdown);
+
     /* Update the engine stage/status flag */
     SC_ATOMIC_CAS(&engine_stage, SURICATA_RUNTIME, SURICATA_DEINIT);
 
@@ -1887,7 +1930,10 @@ int main(int argc, char **argv)
         }
     }
 #endif
+    /* updated by AS.  Don't clean up de_ctx.  Necessiated by live rule swap */
+#if 0
     SigGroupCleanup(de_ctx);
+#endif
 #ifdef __SC_CUDA_SUPPORT__
     if (PatternMatchDefaultMatcher() == MPM_B2G_CUDA) {
         /* pop the cuda context we just pushed before the call to SigGroupCleanup() */
@@ -1902,11 +1948,17 @@ int main(int argc, char **argv)
 
     AppLayerHtpPrintStats();
 
+    /* updated by AS.  Don't clean up de_ctx.  Necessiated by live rule swap */
+#if 0
     SigCleanSignatures(de_ctx);
+#endif
     if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) {
         MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx);
     }
+    /* updated by AS.  Don't clean up de_ctx.  Necessiated by live rule swap */
+#if 0
     DetectEngineCtxFree(de_ctx);
+#endif
     AlpProtoDestroy();
 
     TagDestroyCtx();
index 673e863732b3eeef0365960c8ab39605023e463a..c100a6fc47c517894f524cd09c7c43034f0724ad 100644 (file)
@@ -125,6 +125,8 @@ extern uint8_t suricata_ctl_flags;
 /* uppercase to lowercase conversion lookup table */
 uint8_t g_u8_lowercasetable[256];
 
+extern char *conf_filename;
+
 /* marco to do the actual lookup */
 //#define u8_tolower(c) g_u8_lowercasetable[(c)]
 // these 2 are slower:
@@ -138,6 +140,11 @@ uint8_t g_u8_lowercasetable[256];
 void EngineStop(void);
 void EngineKill(void);
 
+/* live rule swap required this to be made static */
+void SignalHandlerSetup(int, void (*handler)());
+void SignalHandlerSigusr2(int);
+void SignalHandlerSigusr2EngineShutdown(int);
+
 int RunmodeIsUnittests(void);
 
 #endif /* __SURICATA_H__ */
index b547ab3b57eb01bd1c810e39a65df16dd9d7368d..3e35f708628983d915ca65fc14f0b738c4cfaafa 100644 (file)
@@ -30,6 +30,7 @@
 /* thread flags */
 #define TM_FLAG_RECEIVE_TM      0x01
 #define TM_FLAG_DECODE_TM       0x02
+#define TM_FLAG_DETECT_TM       0x04
 
 typedef struct TmModule_ {
     char *name;
index fdf65b46ad9a0bb73fc4e68746365d5080c016e6..3864e88d5ddd12251c888b06fc69ddac21660ea5 100644 (file)
@@ -121,6 +121,12 @@ void TmThreadsUnsetFlag(ThreadVars *tv, uint8_t flag)
 /* 1 slot functions */
 void *TmThreadsSlot1NoIn(void *td)
 {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv = (ThreadVars *)td;
     TmSlot *s = (TmSlot *)tv->tm_slots;
     char run = 1;
@@ -213,6 +219,12 @@ void *TmThreadsSlot1NoIn(void *td)
 
 void *TmThreadsSlot1NoOut(void *td)
 {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv = (ThreadVars *)td;
     TmSlot *s = (TmSlot *)tv->tm_slots;
     Packet *p = NULL;
@@ -288,6 +300,12 @@ void *TmThreadsSlot1NoOut(void *td)
 
 void *TmThreadsSlot1NoInOut(void *td)
 {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv = (ThreadVars *)td;
     TmSlot *s = (TmSlot *)tv->tm_slots;
     char run = 1;
@@ -358,6 +376,12 @@ void *TmThreadsSlot1NoInOut(void *td)
 
 void *TmThreadsSlot1(void *td)
 {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv = (ThreadVars *)td;
     TmSlot *s = (TmSlot *)tv->tm_slots;
     Packet *p = NULL;
@@ -558,6 +582,12 @@ TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p,
  */
 
 void *TmThreadsSlotPktAcqLoop(void *td) {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv = (ThreadVars *)td;
     TmSlot *s = tv->tm_slots;
     char run = 1;
@@ -645,6 +675,12 @@ void *TmThreadsSlotPktAcqLoop(void *td) {
  */
 void *TmThreadsSlotVar(void *td)
 {
+    /* block usr2.  usr2 to be handled by the main thread only */
+    sigset_t x;
+    sigemptyset(&x);
+    sigaddset(&x, SIGUSR2);
+    sigprocmask(SIG_BLOCK, &x, NULL);
+
     ThreadVars *tv = (ThreadVars *)td;
     TmSlot *s = (TmSlot *)tv->tm_slots;
     Packet *p = NULL;