From e96db4fa97d9c434f5785c070538d3e5f82c505f Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Fri, 4 Aug 2023 11:04:37 -0400 Subject: [PATCH 1/2] doc/mt: Document vlan-tuple selector Issue: 6237 The VLAN tuple selector uses a tuple of values to select a tenant. - [ vlan-outermost, vlan-innermost] The tuple can contain as many VLAN values as supported by Suricata - currently 3. Each of these can accept a wild-card value (0). The tenant is selected by matching packet VLAN values with the selector values. --- doc/userguide/configuration/multi-tenant.rst | 108 +++++++++++++++++-- 1 file changed, 100 insertions(+), 8 deletions(-) diff --git a/doc/userguide/configuration/multi-tenant.rst b/doc/userguide/configuration/multi-tenant.rst index 1058468a2f2f..cad779a20f74 100644 --- a/doc/userguide/configuration/multi-tenant.rst +++ b/doc/userguide/configuration/multi-tenant.rst @@ -18,7 +18,7 @@ Add a new section in the main ("master") Suricata configuration file -- ``surica Settings: * `enabled`: yes/no -> is multi-tenancy support enabled -* `selector`: direct (for unix socket pcap processing, see below), VLAN or device +* `selector`: direct (for unix socket pcap processing, see below), vlan, vlan-tuple or device * `loaders`: number of `loader` threads, for parallel tenant loading at startup * `tenants`: list of tenants * `config-path`: path from where the tenant yamls are loaded @@ -27,15 +27,30 @@ Settings: * yaml: separate yaml file with the tenant specific settings * `mappings`: + * tenant id: tenant to associate with the VLAN id or device + +Tenant mappings depend on the type of selector used: + +* `vlan` or `device` * VLAN id or device: The outermost VLAN is used to match. - * tenant id: tenant to associate with the VLAN id or device + +* `vlan-tuple` + + * VLAN tuple: Specify the VLAN identifiers -- outermost to innermost, e.g., `[3000, 1]` will match when the + outermost VLAN id is 3000 and the innermost VLAN id is 1. The special value of `0` means "any VLAN in that position" will match. + Note that there must the same number of layers of VLAN encapsulation as there are values in the tuple. + + + * `[0, 302]` will match any packet with an innermost VLAN id of `302` on packets that are QinQ.. + * `[3000, 0]` will match any packet with an outermost VLAN id of `3000` on packets that are QinQ.. + * `[3000, 1000, 40]` will match any packet with 3-VLAN identifiers of outermost `3000`, middle `1000` and innermost `40`. :: multi-detect: enabled: yes - #selector: direct # direct or vlan + #selector: direct # direct or vlan, vlan-tuple selector: vlan loaders: 3 @@ -55,6 +70,33 @@ Settings: - vlan-id: 1112 tenant-id: 3 + +This example uses the VLAN tuple selector for packets encapsulated with two VLAN ids: + +:: + + multi-detect: + enabled: yes + selector: vlan-tuple + loaders: 3 + + tenants: + - id: 1 + yaml: tenant-1.yaml + - id: 2 + yaml: tenant-2.yaml + - id: 3 + yaml: tenant-3.yaml + + mappings: + - vlan-tuple: [1000, 1] + tenant-id: 1 + - vlan-tuple: [2000, 1] + tenant-id: 2 + - vlan-tuple: [1112, 1] + tenant-id: 3 + + The tenant-1.yaml, tenant-2.yaml, tenant-3.yaml each contain a partial configuration: @@ -97,8 +139,11 @@ configuration: vlan-id ~~~~~~~ -Assign tenants to VLAN ids. Suricata matches the outermost VLAN id with this value. -Multiple VLANs can have the same tenant id. VLAN id values must be between 1 and 4094. +Assign tenants to VLAN ids. Suricata matches the outermost VLAN id with this value with +the selector ``vlan`` (default); the selector ``vlan-tuple`` should be used if QinQ is deployed and requires both +the inner and outer VLAN id values to match to determine the tenant. +Multiple VLANs can have the same tenant id. VLAN id values must be between 1 and 4094 with the ``vlan`` selector. +A wildcard value of ``00`` can be used with the ``vlan-tuple`` selector. Example of VLAN mapping:: @@ -114,6 +159,26 @@ The mappings can also be modified over the unix socket, see below. Note: can only be used if ``vlan.use-for-tracking`` is enabled. +vlan-tuple +~~~~~~~~~~ + +The ``vlan-tuple`` tag can only used with the ``vlan-tuple`` selector. The value will be used +to match with the innermost VLAN. Values of ``0`` will match any VLAN value. + +Example of VLAN mapping:: + + mappings: + - vlan-tuple: [1000, 0] + tenant-id: 1 + - vlan-tuple: [2000, 3000] + tenant-id: 2 + - vlan-tuple: [1112, 3112] + tenant-id: 3 + +The mappings can also be modified over the unix socket, see below. + +Note: can only be used if ``vlan.use-for-tracking`` is enabled. + device ~~~~~~ @@ -195,26 +260,53 @@ Live traffic mode Multi-tenancy supports both VLAN and devices with live traffic. -In the master configuration yaml file, specify ``device`` or ``vlan`` for the ``selector`` setting. +In the master configuration yaml file, specify ``device``, ``vlan`` or ``vlan-tuple`` for the ``selector`` setting. Registration ~~~~~~~~~~~~ Tenants can be mapped to vlan ids. -``register-tenant-handler vlan `` + +Examples using the ``vlan`` selector: + +:: + + register-tenant-handler vlan :: register-tenant-handler 1 vlan 1000 -``unregister-tenant-handler vlan `` +:: + + unregister-tenant-handler vlan :: unregister-tenant-handler 4 vlan 1111 unregister-tenant-handler 1 vlan 1000 + +Examples using the ``vlan-tuple`` selector: + +:: + + register-tenant-handler vlan-tuple + +:: + + register-tenant-handler 1 vlan-tuple 1000 + +:: + + unregister-tenant-handler vlan-tuple + +:: + + unregister-tenant-handler 4 vlan-tuple 1111 1 + unregister-tenant-handler 1 vlan-tuple 1000 2 + The registration of tenant and tenant handlers can be done on a running engine. From 54a8b2d5e8b362d42ea0145b848f7789845edc43 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Fri, 4 Aug 2023 11:05:11 -0400 Subject: [PATCH 2/2] detect/mt: Add support for vlan-tuple selector Issue: 6237 --- python/suricata/sc/specs.py | 10 ++ src/detect-engine.c | 230 +++++++++++++++++++++++++++--------- src/detect-engine.h | 4 + src/detect.h | 22 ++-- src/runmode-unix-socket.c | 84 +++++++++++-- 5 files changed, 280 insertions(+), 70 deletions(-) diff --git a/python/suricata/sc/specs.py b/python/suricata/sc/specs.py index c7e045873303..de5f6b7f00b3 100644 --- a/python/suricata/sc/specs.py +++ b/python/suricata/sc/specs.py @@ -73,6 +73,11 @@ "type": int, "required": 0, }, + { + "name": "hargs_extra", + "type": int, + "required": 0, + }, ], "register-tenant-handler": [ { @@ -89,6 +94,11 @@ "type": int, "required": 0, }, + { + "name": "hargs_extra", + "type": int, + "required": 0, + }, ], "unregister-tenant": [ { diff --git a/src/detect-engine.c b/src/detect-engine.c index d8f9f1880e56..732e5df63480 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation +/* Copyright (C) 2007-2023 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -101,6 +101,7 @@ static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len static void TenantIdFree(void *d); static uint32_t DetectEngineTenantGetIdFromLivedev(const void *ctx, const Packet *p); static uint32_t DetectEngineTenantGetIdFromVlanId(const void *ctx, const Packet *p); +static uint32_t DetectEngineTenantGetIdFromVlanIdTuple(const void *ctx, const Packet *p); static uint32_t DetectEngineTenantGetIdFromPcap(const void *ctx, const Packet *p); static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; @@ -3179,6 +3180,10 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread det_ctx->TenantGetId = DetectEngineTenantGetIdFromVlanId; SCLogDebug("TENANT_SELECTOR_VLAN"); break; + case TENANT_SELECTOR_VLAN_TUPLE: + det_ctx->TenantGetId = DetectEngineTenantGetIdFromVlanIdTuple; + SCLogDebug("TENANT_SELECTOR_VLAN_TUPLE"); + break; case TENANT_SELECTOR_LIVEDEV: det_ctx->TenantGetId = DetectEngineTenantGetIdFromLivedev; SCLogDebug("TENANT_SELECTOR_LIVEDEV"); @@ -4152,8 +4157,8 @@ static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappi return 0; } -static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node, - bool failure_fatal) +static int DetectEngineMultiTenantSetupLoadVlanMappings(enum DetectEngineTenantSelectors selector, + const ConfNode *mappings_root_node, bool failure_fatal) { ConfNode *mapping_node = NULL; @@ -4163,9 +4168,6 @@ static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings 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; uint32_t tenant_id = 0; if (StringParseUint32(&tenant_id, 10, (uint16_t)strlen(tenant_id_node->val), @@ -4176,25 +4178,67 @@ static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings goto bad_mapping; } - uint16_t vlan_id = 0; - if (StringParseUint16( - &vlan_id, 10, (uint16_t)strlen(vlan_id_node->val), vlan_id_node->val) < 0) { - SCLogError("vlan-id " - "of %s is invalid", - vlan_id_node->val); - goto bad_mapping; - } - if (vlan_id == 0 || vlan_id >= 4095) { - SCLogError("vlan-id " - "of %s is invalid. Valid range 1-4094.", - vlan_id_node->val); - goto bad_mapping; - } + if (selector == TENANT_SELECTOR_VLAN) { + ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id"); + if (vlan_id_node == NULL) + goto bad_mapping; + + uint16_t vlan_id = 0; + if (StringParseU16RangeCheck(&vlan_id, 10, (uint16_t)strlen(vlan_id_node->val), + vlan_id_node->val, 1, 4094) < 0) { + SCLogError("vlan-id " + "of %s is invalid; must be %d-4094", + vlan_id_node->val, 1); + goto bad_mapping; + } + if (DetectEngineTenantRegisterVlanId(tenant_id, vlan_id) != 0) { + goto error; + } + SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id); + } else if (selector == TENANT_SELECTOR_VLAN_TUPLE) { + + ConfNode *vlan_tuple = ConfNodeLookupChild(mapping_node, "vlan-tuple"); + ConfNode *field; + int16_t idx = 0; + uint16_t vlan_id = 0; + TrafficId traffic_id = { 0 }; + TAILQ_FOREACH (field, &vlan_tuple->head, next) { + /* "0" is a wild card value (matches any vlan) so permit it */ + if (StringParseU16RangeCheck(&vlan_id, 10, (uint16_t)strlen(field->val), + field->val, 0, 4094) < 0) { + SCLogError("vlan value %s is invalid; must be 0-4094", field->val); + goto bad_mapping; + } + traffic_id.vlan.tuple[idx++] = vlan_id; + } + traffic_id.vlan.count = idx; + + /* Reject if all vlan ids have wildcard values */ + bool all_wildcard = true; + for (int i = 0; i < traffic_id.vlan.count; i++) { + if (traffic_id.vlan.tuple[i] != 0) { + all_wildcard = false; + break; + } + } - if (DetectEngineTenantRegisterVlanId(tenant_id, vlan_id) != 0) { - goto error; + if (all_wildcard) { + SCLogError("Cannot use wild-card values for all vlan ids"); + goto error; + } + + if (traffic_id.vlan.tuple[1] == 0) { + SCLogNotice("tenant id: %d, Since the inner VLAN id value is the wildcard " + "value (0); suggest the use of " + "the selector \"vlan\" instead.", + tenant_id); + } + + if (DetectEngineTenantRegisterVlanIdTuple(tenant_id, traffic_id) != 0) + goto error; + SCLogNotice("vlan-tuple %u:%u connected to tenant-id %u", traffic_id.vlan.tuple[0], + traffic_id.vlan.tuple[1], tenant_id); } - SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id); mapping_cnt++; continue; @@ -4238,17 +4282,20 @@ int DetectEngineMultiTenantSetup(const bool unix_socket) if (ConfGet("multi-detect.selector", &handler) == 1) { SCLogConfig("multi-tenant selector type %s", handler); - if (strcmp(handler, "vlan") == 0) { - tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN; + if (strcmp(handler, "vlan") == 0 || strcmp(handler, "vlan-tuple") == 0) { + if (strcmp(handler, "vlan") == 0) + tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN; + else + tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN_TUPLE; int vlanbool = 0; if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) { SCLogError("vlan tracking is disabled, " - "can't use multi-detect selector 'vlan'"); + "can't use multi-detect selector '%s'", + handler); SCMutexUnlock(&master->lock); goto error; } - } else if (strcmp(handler, "direct") == 0) { tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT; } else if (strcmp(handler, "device") == 0) { @@ -4273,12 +4320,13 @@ int DetectEngineMultiTenantSetup(const bool unix_socket) /* traffic -- tenant mappings */ ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings"); - if (tenant_selector == TENANT_SELECTOR_VLAN) { - int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node, - failure_fatal); + if (tenant_selector == TENANT_SELECTOR_VLAN || + tenant_selector == TENANT_SELECTOR_VLAN_TUPLE) { + int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings( + tenant_selector, mappings_root_node, failure_fatal); if (mapping_cnt == 0) { - /* no mappings are valid when we're in unix socket mode, - * they can be added on the fly. Otherwise warn/error + /* no mappings are valid only when in unix socket mode, + * as they can be added on the fly. Otherwise warn/error * depending on failure_fatal */ if (unix_socket) { @@ -4385,23 +4433,64 @@ int DetectEngineMultiTenantSetup(const bool unix_socket) static uint32_t DetectEngineTenantGetIdFromVlanId(const void *ctx, const Packet *p) { + if (p->vlan_idx == 0) + return 0; + const DetectEngineThreadCtx *det_ctx = ctx; - uint32_t x = 0; - uint32_t vlan_id = 0; + if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0) + return 0; + /* not very efficient, but for now we're targeting only limited amounts. + * Can use hash/tree approach later. */ + for (uint32_t x = 0; x < det_ctx->tenant_array_size; x++) { + if (det_ctx->tenant_array[x].traffic_id.vlan.count != p->vlan_idx) + continue; + if (det_ctx->tenant_array[x].traffic_id.vlan.tuple[0] == p->vlan_id[0]) + return det_ctx->tenant_array[x].tenant_id; + } + + return 0; +} + +/* Match if the configured vlan match is a wildcard or the vlan ids match */ +#define VLAN_TUPLE_MATCH(tenant_val, traffic_val) ((tenant_val == 0) || (tenant_val == traffic_val)) + +#define TRAFFIC_ID_VLAN_TUPLE_MATCH(tenant_val, traffic_id) \ + ({ \ + bool match = false; \ + if (tenant_val.vlan.count == traffic_id.vlan.count) { \ + match = true; \ + for (int i = 0; i < tenant_val.vlan.count; i++) { \ + if (tenant_val.vlan.tuple[i] != traffic_id.vlan.tuple[i]) { \ + match = false; \ + break; \ + } \ + } \ + } \ + match; \ + }) +static uint32_t DetectEngineTenantGetIdFromVlanIdTuple(const void *ctx, const Packet *p) +{ if (p->vlan_idx == 0) return 0; - vlan_id = p->vlan_id[0]; - + const DetectEngineThreadCtx *det_ctx = ctx; if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0) return 0; + TrafficId traffic_id = { + .vlan.count = p->vlan_idx, .vlan.tuple[0] = p->vlan_id[0], .vlan.tuple[1] = p->vlan_id[1] + }; + /* not very efficient, but for now we're targeting only limited amounts. * Can use hash/tree approach later. */ - for (x = 0; x < det_ctx->tenant_array_size; x++) { - if (det_ctx->tenant_array[x].traffic_id == vlan_id) + for (uint32_t x = 0; x < det_ctx->tenant_array_size; x++) { + if (det_ctx->tenant_array[x].traffic_id.vlan.count != p->vlan_idx) + continue; + + if (TRAFFIC_ID_VLAN_TUPLE_MATCH(det_ctx->tenant_array[x].traffic_id, traffic_id)) { return det_ctx->tenant_array[x].tenant_id; + } } return 0; @@ -4420,7 +4509,7 @@ static uint32_t DetectEngineTenantGetIdFromLivedev(const void *ctx, const Packet } static int DetectEngineTenantRegisterSelector( - enum DetectEngineTenantSelectors selector, uint32_t tenant_id, uint32_t traffic_id) + enum DetectEngineTenantSelectors selector, uint32_t tenant_id, TrafficId traffic_id) { DetectEngineMasterCtx *master = &g_master_de_ctx; SCMutexLock(&master->lock); @@ -4433,10 +4522,18 @@ static int DetectEngineTenantRegisterSelector( DetectEngineTenantMapping *m = master->tenant_mapping_list; while (m) { - if (m->traffic_id == traffic_id) { - SCLogInfo("traffic id already registered"); - SCMutexUnlock(&master->lock); - return -1; + if (selector == TENANT_SELECTOR_VLAN_TUPLE) { + if (TRAFFIC_ID_VLAN_TUPLE_MATCH(m->traffic_id, traffic_id)) { + SCLogInfo("traffic id already registered"); + SCMutexUnlock(&master->lock); + return -1; + } + } else { + if (m->traffic_id.id == traffic_id.id) { + SCLogInfo("traffic id already registered"); + SCMutexUnlock(&master->lock); + return -1; + } } m = m->next; } @@ -4455,13 +4552,24 @@ static int DetectEngineTenantRegisterSelector( master->tenant_selector = selector; - SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id); + if (sc_log_global_log_level >= SC_LOG_DEBUG) { + if (selector == TENANT_SELECTOR_VLAN) { + SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, + traffic_id.vlan.tuple[0]); + } else if (selector == TENANT_SELECTOR_VLAN_TUPLE) { + SCLogDebug("tenant handler %u %u [%u, %u, %u] registered", selector, tenant_id, + traffic_id.vlan.tuple[0], traffic_id.vlan.tuple[1], traffic_id.vlan.tuple[2]); + } else { + SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id.id); + } + } + SCMutexUnlock(&master->lock); return 0; } static int DetectEngineTenantUnregisterSelector( - enum DetectEngineTenantSelectors selector, uint32_t tenant_id, uint32_t traffic_id) + enum DetectEngineTenantSelectors selector, uint32_t tenant_id, TrafficId traffic_id) { DetectEngineMasterCtx *master = &g_master_de_ctx; SCMutexLock(&master->lock); @@ -4474,9 +4582,7 @@ static int DetectEngineTenantUnregisterSelector( DetectEngineTenantMapping *prev = NULL; DetectEngineTenantMapping *map = master->tenant_mapping_list; while (map) { - if (map->traffic_id == traffic_id && - map->tenant_id == tenant_id) - { + if (map->traffic_id.id == traffic_id.id && map->tenant_id == tenant_id) { if (prev != NULL) prev->next = map->next; else @@ -4484,7 +4590,7 @@ static int DetectEngineTenantUnregisterSelector( map->next = NULL; SCFree(map); - SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id); + SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id.id); SCMutexUnlock(&master->lock); return 0; } @@ -4498,30 +4604,44 @@ static int DetectEngineTenantUnregisterSelector( int DetectEngineTenantRegisterLivedev(uint32_t tenant_id, int device_id) { - return DetectEngineTenantRegisterSelector( - TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id); + TrafficId traffic_id = { .id = device_id }; + return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_LIVEDEV, tenant_id, traffic_id); } int DetectEngineTenantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id) { - return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); + TrafficId traffic_id = { .vlan.tuple[0] = vlan_id, .vlan.count = 1 }; + return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, traffic_id); } int DetectEngineTenantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id) { - return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); + TrafficId traffic_id = { .vlan.tuple[0] = vlan_id, .vlan.count = 1 }; + return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, traffic_id); +} + +int DetectEngineTenantRegisterVlanIdTuple(uint32_t tenant_id, TrafficId traffic_id) +{ + return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_VLAN_TUPLE, tenant_id, traffic_id); +} + +int DetectEngineTenantUnregisterVlanIdTuple(uint32_t tenant_id, TrafficId traffic_id) +{ + return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_VLAN_TUPLE, tenant_id, traffic_id); } int DetectEngineTenantRegisterPcapFile(uint32_t tenant_id) { + TrafficId traffic_id = { .id = 0 }; SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id); - return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); + return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, traffic_id); } int DetectEngineTenantUnregisterPcapFile(uint32_t tenant_id) { + TrafficId traffic_id = { .id = 0 }; SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id); - return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); + return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, traffic_id); } static uint32_t DetectEngineTenantGetIdFromPcap(const void *ctx, const Packet *p) diff --git a/src/detect-engine.h b/src/detect-engine.h index a1732b16a993..7054a5f4e440 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -133,8 +133,12 @@ int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int r int DetectEngineReloadTenantsBlocking(const int reload_cnt); int DetectEngineTenantRegisterLivedev(uint32_t tenant_id, int device_id); +int DetectEngineTenantRegisterVlanIdInner(uint32_t tenant_id, uint16_t vlan_id); +int DetectEngineTenantUnregisterVlanIdInner(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTenantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id); int DetectEngineTenantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id); +int DetectEngineTenantRegisterVlanIdTuple(uint32_t tenant_id, TrafficId traffic_id); +int DetectEngineTenantUnregisterVlanIdTuple(uint32_t tenant_id, TrafficId traffic_id); int DetectEngineTenantRegisterPcapFile(uint32_t tenant_id); int DetectEngineTenantUnregisterPcapFile(uint32_t tenant_id); diff --git a/src/detect.h b/src/detect.h index 04dd49a65a75..75619d95ad78 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1496,19 +1496,27 @@ typedef struct SigGroupHead_ { /** strict parsing is enabled */ #define SIGMATCH_STRICT_PARSING BIT_U16(11) -enum DetectEngineTenantSelectors -{ - TENANT_SELECTOR_UNKNOWN = 0, /**< not set */ - TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */ - TENANT_SELECTOR_VLAN, /**< map vlan to tenant id */ - TENANT_SELECTOR_LIVEDEV, /**< map livedev to tenant id */ +enum DetectEngineTenantSelectors { + TENANT_SELECTOR_UNKNOWN = 0, /**< not set */ + TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */ + TENANT_SELECTOR_VLAN, /**< map vlan to tenant id */ + TENANT_SELECTOR_LIVEDEV, /**< map livedev to tenant id */ + TENANT_SELECTOR_VLAN_TUPLE, /**< map vlan tuple to tenant id */ }; +typedef union _traffic_id { + uint32_t id; + struct TrafficIdVlan_ { + uint16_t tuple[VLAN_MAX_LAYERS]; + uint16_t count; + } vlan; +} TrafficId; + typedef struct DetectEngineTenantMapping_ { uint32_t tenant_id; /* traffic id that maps to the tenant id */ - uint32_t traffic_id; + TrafficId traffic_id; struct DetectEngineTenantMapping_ *next; } DetectEngineTenantMapping; diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index e695cb8dfbd6..e26ab936eef7 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -881,22 +881,56 @@ TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data) traffic_id = json_integer_value(hargs); } + /* 3.5 (vlan-tuple only) Get optional hargs_extra (vlan-id-inner) */ + int traffic_id_inner = -1; + if (0 == strcmp(htype, "vlan-tuple")) { + hargs = json_object_get(cmd, "hargs_extra"); + if (hargs != NULL) { + if (!json_is_integer(hargs)) { + SCLogInfo("error: hargs_extra not a number"); + json_object_set_new(answer, "message", json_string("hargs_extra not a number")); + return TM_ECODE_FAILED; + } + traffic_id_inner = json_integer_value(hargs); + } + } + /* 4 add to system */ int r = -1; if (strcmp(htype, "pcap") == 0) { r = DetectEngineTenantRegisterPcapFile(tenant_id); - } else if (strcmp(htype, "vlan") == 0) { + } else if (strcmp(htype, "vlan") == 0 || strcmp(htype, "vlan-tuple") == 0) { if (traffic_id < 0) { json_object_set_new(answer, "message", json_string("vlan requires argument")); return TM_ECODE_FAILED; } - if (traffic_id > USHRT_MAX) { + if (traffic_id > 4094) { json_object_set_new(answer, "message", json_string("vlan argument out of range")); return TM_ECODE_FAILED; } + if (strcmp(htype, "vlan-tuple") == 0) { + if (traffic_id_inner < 0) { + json_object_set_new(answer, "message", json_string("vlan-tuple requires argument")); + return TM_ECODE_FAILED; + } + if (traffic_id_inner > 4094) { + json_object_set_new( + answer, "message", json_string("vlan-tuple argument out of range")); + return TM_ECODE_FAILED; + } + } - SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id); - r = DetectEngineTenantRegisterVlanId(tenant_id, (uint16_t)traffic_id); + if (strcmp(htype, "vlan") == 0) { + SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id); + r = DetectEngineTenantRegisterVlanId(tenant_id, (uint16_t)traffic_id); + } else { + SCLogInfo("VLAN-tuple handler: id %u:%u maps to tenant %u", (uint32_t)traffic_id, + (uint32_t)traffic_id_inner, tenant_id); + TrafficId traffic_tuple = { .vlan.count = 2, + .vlan.tuple[0] = (uint16_t)traffic_id, + .vlan.tuple[1] = (uint16_t)traffic_id_inner }; + r = DetectEngineTenantRegisterVlanIdTuple(tenant_id, traffic_tuple); + } } if (r != 0) { json_object_set_new(answer, "message", json_string("handler setup failure")); @@ -961,23 +995,57 @@ TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *dat } traffic_id = json_integer_value(hargs); } + /* 3.5 Get optional hargs_extra (only with vlan-tuple) */ + int traffic_id_inner = -1; + if (0 == strcmp(htype, "vlan-tuple")) { + hargs = json_object_get(cmd, "hargs_extra"); + if (hargs != NULL) { + if (!json_is_integer(hargs)) { + SCLogInfo("error: hargs_extra not a number"); + json_object_set_new(answer, "message", json_string("hargs not a number")); + return TM_ECODE_FAILED; + } + traffic_id_inner = json_integer_value(hargs); + } + } /* 4 add to system */ int r = -1; if (strcmp(htype, "pcap") == 0) { r = DetectEngineTenantUnregisterPcapFile(tenant_id); - } else if (strcmp(htype, "vlan") == 0) { + } else if (strcmp(htype, "vlan") == 0 || strcmp(htype, "vlan-tuple") == 0) { if (traffic_id < 0) { json_object_set_new(answer, "message", json_string("vlan requires argument")); return TM_ECODE_FAILED; } - if (traffic_id > USHRT_MAX) { + if (traffic_id > 4094) { json_object_set_new(answer, "message", json_string("vlan argument out of range")); return TM_ECODE_FAILED; } + if (strcmp(htype, "vlan-tuple") == 0) { + if (traffic_id_inner < 0) { + json_object_set_new(answer, "message", json_string("vlan-tuple requires argument")); + return TM_ECODE_FAILED; + } + if (traffic_id_inner > 4094) { + json_object_set_new( + answer, "message", json_string("vlan-tuple argument out of range")); + return TM_ECODE_FAILED; + } + } - SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, tenant_id); - r = DetectEngineTenantUnregisterVlanId(tenant_id, (uint16_t)traffic_id); + if (strcmp(htype, "vlan") == 0) { + SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, + tenant_id); + r = DetectEngineTenantUnregisterVlanId(tenant_id, (uint16_t)traffic_id); + } else { + SCLogInfo("VLAN handler: removing mapping of %u:%u to tenant %u", (uint32_t)traffic_id, + (uint32_t)traffic_id_inner, tenant_id); + TrafficId traffic_tuple = { .vlan.count = 2, + .vlan.tuple[0] = (uint16_t)traffic_id, + .vlan.tuple[1] = (uint16_t)traffic_id_inner }; + r = DetectEngineTenantUnregisterVlanIdTuple(tenant_id, traffic_tuple); + } } if (r != 0) { json_object_set_new(answer, "message", json_string("handler unregister failure"));