]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
multi-detect: (un)register-tenant unix socket commands
authorVictor Julien <victor@inliniac.net>
Mon, 12 Jan 2015 18:00:16 +0000 (19:00 +0100)
committerVictor Julien <victor@inliniac.net>
Thu, 23 Jul 2015 17:36:14 +0000 (19:36 +0200)
Make available to live mode and unix socket mode.

register-tenant:
    Loads a new YAML, does basic validation.
    Loads a new detection engine
    Loads rules
    Add new de_ctx to master store and stores tenant id in the de_ctx so
        we can look it up by tenant id later.

unregister-tenant:
    Gets the de_ctx, moves it to the freelist
    Removes config

Introduce DetectEngineGetByTenantId, which gets a reference to the
detect engine by tenant id.

scripts/suricatasc/src/suricatasc.py
src/detect-engine.c
src/detect-engine.h
src/detect.h
src/runmode-unix-socket.c
src/runmode-unix-socket.h
src/unix-manager.c

index f5a7aa7f0b7a9fa9a38bbf9289c1e3ed39e8ea50..3ab97b99cc638de7884f7e05821598e742006a9c 100644 (file)
@@ -80,7 +80,7 @@ class SuricataCompleter:
 
 class SuricataSC:
     def __init__(self, sck_path, verbose=False):
-        self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat']
+        self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant']
         self.sck_path = sck_path
         self.verbose = verbose
 
@@ -206,6 +206,27 @@ class SuricataSC:
                 else:
                     arguments = {}
                     arguments["variable"] = variable
+            elif "unregister-tenant" in command:
+                try:
+                    [cmd, tenantid] = command.split(' ', 1)
+                except:
+                    raise SuricataCommandException("Unable to split command '%s'" % (command))
+                if cmd != "unregister-tenant":
+                    raise SuricataCommandException("Invalid command '%s'" % (command))
+                else:
+                    arguments = {}
+                    arguments["id"] = int(tenantid)
+            elif "register-tenant" in command:
+                try:
+                    [cmd, tenantid, filename] = command.split(' ', 2)
+                except:
+                    raise SuricataCommandException("Arguments to command '%s' is missing" % (command))
+                if cmd != "register-tenant":
+                    raise SuricataCommandException("Invalid command '%s'" % (command))
+                else:
+                    arguments = {}
+                    arguments["id"] = int(tenantid)
+                    arguments["filename"] = filename
             else:
                 cmd = command
         else:
index adb3d5908e9e357e789210e0dff2d69d61bbed0c..48afc52b6a703c58baf5af5ffed3d8ce8ebf783f 100644 (file)
@@ -1640,6 +1640,30 @@ DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx)
     return de_ctx;
 }
 
+DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id)
+{
+    DetectEngineMasterCtx *master = &g_master_de_ctx;
+    SCMutexLock(&master->lock);
+
+    if (master->list == NULL) {
+        SCMutexUnlock(&master->lock);
+        return NULL;
+    }
+
+    DetectEngineCtx *de_ctx = master->list;
+    while (de_ctx) {
+        if (de_ctx->tenant_id == tenant_id) {
+            de_ctx->ref_cnt++;
+            break;
+        }
+
+        de_ctx = de_ctx->next;
+    }
+
+    SCMutexUnlock(&master->lock);
+    return de_ctx;
+}
+
 void DetectEngineDeReference(DetectEngineCtx **de_ctx)
 {
     BUG_ON((*de_ctx)->ref_cnt == 0);
index b89260d613e5bdb904d466d8734961e82170d262..928f7887669e6314b8d6058ad9251120debaa6f3 100644 (file)
@@ -70,6 +70,7 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type);
 
 int DetectEngineAddToMaster(DetectEngineCtx *de_ctx);
 DetectEngineCtx *DetectEngineGetCurrent(void);
+DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id);
 void DetectEnginePruneFreeList(void);
 int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx);
 DetectEngineCtx *DetectEngineReference(DetectEngineCtx *);
index 223b6d31a47fd52a72d5ea4c76ffc7c37ee0b04e..05c31d65d6c28433ba4c4552981613820de9dc39 100644 (file)
@@ -560,6 +560,8 @@ typedef struct DetectEngineCtx_ {
     uint8_t flags;
     int failure_fatal;
 
+    int tenant_id;
+
     Signature *sig_list;
     uint32_t sig_cnt;
 
index bc7f24cc70dc69f5a7d340dc248a7c3f4fae4d13..2e9a6c0f4174d9d4828db19a6fe77c433f2f66b7 100644 (file)
 
 #include "util-profiling.h"
 
+#include "conf-yaml-loader.h"
+
+#include "detect-engine.h"
+
 static const char *default_mode = NULL;
 
 int unix_socket_mode_is_running = 0;
@@ -397,6 +401,134 @@ void UnixSocketPcapFile(TmEcode tm)
 #endif
 }
 
+#ifdef BUILD_UNIX_SOCKET
+/**
+ * \brief Command to add a tenant
+ *
+ * \param cmd the content of command Arguments as a json_t object
+ * \param answer the json_t object that has to be used to answer
+ * \param data pointer to data defining the context here a PcapCommand::
+ */
+TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data)
+{
+    const char *filename;
+#ifdef OS_WIN32
+    struct _stat st;
+#else
+    struct stat st;
+#endif /* OS_WIN32 */
+
+    /* 1 get tenant id */
+    json_t *jarg = json_object_get(cmd, "id");
+    if (!json_is_integer(jarg)) {
+        json_object_set_new(answer, "message", json_string("id is not an integer"));
+        return TM_ECODE_FAILED;
+    }
+    int tenant_id = json_integer_value(jarg);
+
+    /* 2 get tenant yaml */
+    jarg = json_object_get(cmd, "filename");
+    if (!json_is_string(jarg)) {
+        json_object_set_new(answer, "message", json_string("command is not a string"));
+        return TM_ECODE_FAILED;
+    }
+    filename = json_string_value(jarg);
+#ifdef OS_WIN32
+    if(_stat(filename, &st) != 0) {
+#else
+    if(stat(filename, &st) != 0) {
+#endif /* OS_WIN32 */
+        json_object_set_new(answer, "message", json_string("file does not exist"));
+        return TM_ECODE_FAILED;
+    }
+
+    SCLogDebug("add-tenant: %d %s", tenant_id, filename);
+
+    /* 3 register it in the system */
+
+    /* 3A yaml parsing */
+    char prefix[64];
+    snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
+
+    if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
+        json_object_set_new(answer, "message", json_string("YAML loading failed, ConfYamlLoadFileWithPrefix failed"));
+        return TM_ECODE_FAILED;
+    }
+
+    ConfNode *node = ConfGetNode(prefix);
+    if (node == NULL) {
+        json_object_set_new(answer, "message", json_string("YAML loading failed, node == NULL"));
+        return TM_ECODE_FAILED;
+    }
+#if 0
+    ConfDump();
+#endif
+
+    /* 3B setup the de_ctx */
+    DetectEngineCtx *de_ctx = DetectEngineCtxInitWithPrefix(prefix);
+    if (de_ctx == NULL) {
+        json_object_set_new(answer, "message", json_string("detect engine failed to load"));
+        return TM_ECODE_FAILED;
+    }
+    SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix);
+
+    de_ctx->tenant_id = tenant_id;
+
+    SigLoadSignatures(de_ctx, NULL, 0);
+
+    DetectEngineAddToMaster(de_ctx);
+
+    /* 3C for each thread, replace det_ctx */
+
+    json_object_set_new(answer, "message", json_string("work in progress"));
+    return TM_ECODE_OK;
+}
+
+/**
+ * \brief Command to remove a tenant
+ *
+ * \param cmd the content of command Arguments as a json_t object
+ * \param answer the json_t object that has to be used to answer
+ * \param data pointer to data defining the context here a PcapCommand::
+ */
+TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data)
+{
+    /* 1 get tenant id */
+    json_t *jarg = json_object_get(cmd, "id");
+    if (!json_is_integer(jarg)) {
+        SCLogInfo("error: command is not a string");
+        json_object_set_new(answer, "message", json_string("id is not an integer"));
+        return TM_ECODE_FAILED;
+    }
+    int tenant_id = json_integer_value(jarg);
+
+    SCLogInfo("remove-tenant: %d TODO", tenant_id);
+
+    /* 2 remove it from the system */
+    char prefix[64];
+    snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
+
+    DetectEngineCtx *de_ctx = DetectEngineGetByTenantId(tenant_id);
+    if (de_ctx == NULL) {
+        json_object_set_new(answer, "message", json_string("tenant detect engine not found"));
+        return TM_ECODE_FAILED;
+    }
+
+    /* move to free list */
+    DetectEngineMoveToFreeList(de_ctx);
+    DetectEngineDeReference(&de_ctx);
+
+    /* update the threads */
+    /** TODO */
+
+    /* walk free list, freeing the removed de_ctx */
+    DetectEnginePruneFreeList();
+
+    json_object_set_new(answer, "message", json_string("work in progress"));
+    return TM_ECODE_OK;
+}
+#endif /* BUILD_UNIX_SOCKET */
+
 /**
  * \brief Single thread version of the Pcap file processing.
  */
index 578469ec242d9fb9e27fda3b102afbb6ceaacc4c..b844c890a60a7b63b3c233a614fabe75e2162541 100644 (file)
@@ -31,4 +31,9 @@ int RunModeUnixSocketIsActive(void);
 
 void UnixSocketPcapFile(TmEcode tm);
 
+#ifdef BUILD_UNIX_SOCKET
+TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data);
+TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data);
+#endif
+
 #endif /* __RUNMODE_UNIX_SOCKET_H__ */
index 6228c6a5eb4d2e8e7b69f2c334580ee9b1143a2b..8bea8c48348b7ddff5c60c93330812afecf3e70b 100644 (file)
@@ -899,6 +899,9 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data)
     UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS);
     UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0);
     UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0);
+    UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS);
+    UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS);
+
 
     TmThreadsSetFlag(th_v, THV_INIT_DONE);
     while (1) {