diff --git a/src/detect-engine.c b/src/detect-engine.c index 1634f15cd2..163874c9d9 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1676,13 +1676,84 @@ int DetectEngineMultiTenantEnabled(void) return (master->multi_tenant_enabled); } +/** \brief load a tenant from a yaml file + * + * \param tenant_id the tenant id by which the config is known + * \param filename full path of a yaml file + * + * \retval 0 ok + * \retval -1 failed + */ +int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename) +{ + DetectEngineCtx *de_ctx = NULL; + char prefix[64]; + + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + +#ifdef OS_WIN32 + struct _stat st; + if(_stat(filename, &st) != 0) { +#else + struct stat st; + if(stat(filename, &st) != 0) { +#endif /* OS_WIN32 */ + SCLogError(SC_ERR_FOPEN, "failed to stat file %s", filename); + goto error; + } + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); + goto error; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); + goto error; + } + + de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + goto error; + } + SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix); + + de_ctx->tenant_id = tenant_id; + + if (SigLoadSignatures(de_ctx, NULL, 0) < 0) { + SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); + goto error; + } + + DetectEngineAddToMaster(de_ctx); + + return 0; + +error: + return -1; +} + +/** + * \brief setup multi-detect / multi-tenancy + * + * See if MT is enabled. If so, setup the selector, tenants and mappings. + * Tenants and mappings are optional, and can also dynamically be added + * and removed from the unix socket. + */ void DetectEngineMultiTenantSetup(void) { DetectEngineMasterCtx *master = &g_master_de_ctx; - SCMutexLock(&master->lock); + + int failure_fatal = 0; + (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal); + int enabled = 0; (void)ConfGetBool("multi-detect.enabled", &enabled); if (enabled == 1) { + SCMutexLock(&master->lock); master->multi_tenant_enabled = 1; char *handler = NULL; @@ -1696,14 +1767,110 @@ void DetectEngineMultiTenantSetup(void) } else { SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s " "multi-detect.selector", handler); - goto end; + SCMutexUnlock(&master->lock); + goto error; } } + SCMutexUnlock(&master->lock); SCLogInfo("multi-detect is enabled (multi tenancy). Selector: %s", handler); + + /* traffic -- tenant mappings */ + ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings"); + ConfNode *mapping_node = NULL; + + if (mappings_root_node != NULL) { + TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) { + if (strcmp(mapping_node->val, "vlan") == 0) { + ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id"); + if (tenant_id_node == NULL) + goto bad_mapping; + ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id"); + if (vlan_id_node == NULL) + goto bad_mapping; + + SCLogInfo("vlan %s %s", tenant_id_node->val, vlan_id_node->val); + + uint32_t tenant_id = 0; + if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val), + tenant_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id " + "of %s is invalid", tenant_id_node->val); + goto bad_mapping; + } + + uint16_t vlan_id = 0; + if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val), + vlan_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " + "of %s is invalid", vlan_id_node->val); + goto bad_mapping; + } + + if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { + goto error; + } + } else { + SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.mappings expects a list of 'vlan's. Not %s", mapping_node->val); + goto bad_mapping; + } + continue; + + bad_mapping: + if (failure_fatal) + goto error; + } + } + + /* tenants */ + ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants"); + ConfNode *tenant_node = NULL; + + if (tenants_root_node != NULL) { + TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) { + if (strcmp(tenant_node->val, "tenant") != 0) { + SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.tenants expects a list of 'tenant's. Not %s", tenant_node->val); + goto bad_tenant; + } + ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id"); + if (id_node == NULL) + goto bad_tenant; + ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml"); + if (yaml_node == NULL) + goto bad_tenant; + + uint32_t tenant_id = 0; + if (ByteExtractStringUint32(&tenant_id, 10, strlen(id_node->val), + id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant_id " + "of %s is invalid", id_node->val); + goto bad_tenant; + } + SCLogInfo("tenant id: %u, %s", tenant_id, yaml_node->val); + + if (DetectEngineMultiTenantLoadTenant(tenant_id, yaml_node->val) != 0) { + /* error logged already */ + goto bad_tenant; + } + continue; + + bad_tenant: + if (failure_fatal) + goto error; + } + } + if (DetectEngineMTApply() < 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + goto error; + } + + } else { + SCLogDebug("multi-detect not enabled (multi tenancy)"); } - SCLogDebug("multi-detect not enabled (multi tenancy)"); -end: - SCMutexUnlock(&master->lock); +error: + return; } uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p)