diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index f5a7aa7f0b..3ab97b99cc 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -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: diff --git a/src/detect-engine.c b/src/detect-engine.c index adb3d5908e..48afc52b6a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -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); diff --git a/src/detect-engine.h b/src/detect-engine.h index b89260d613..928f788766 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -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 *); diff --git a/src/detect.h b/src/detect.h index 223b6d31a4..05c31d65d6 100644 --- a/src/detect.h +++ b/src/detect.h @@ -560,6 +560,8 @@ typedef struct DetectEngineCtx_ { uint8_t flags; int failure_fatal; + int tenant_id; + Signature *sig_list; uint32_t sig_cnt; diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index bc7f24cc70..2e9a6c0f41 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -41,6 +41,10 @@ #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. */ diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index 578469ec24..b844c890a6 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -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__ */ diff --git a/src/unix-manager.c b/src/unix-manager.c index 6228c6a5eb..8bea8c4834 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -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) {