]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
multi-tenant: introduce device selector
authorVictor Julien <victor@inliniac.net>
Wed, 31 May 2017 07:33:16 +0000 (09:33 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 7 Aug 2018 09:10:17 +0000 (11:10 +0200)
Add device to tenant mapping support:

  mappings:
  - device: ens5f0
    tenant-id: 1
  - device: ens5f1
    tenant-id: 23

Implemented by assigning the tenant id to the 'livedev', which means
it's only supported for capture methods that use the livedev API.

It's also currently not supported for IPS. In a case like 'eth0 -> eth1'
it's unclear which tenant should be used for the return traffic in a
flow, where the incoming device is 'eth1'.

src/detect-engine.c
src/detect-engine.h
src/detect.h
src/util-device.c
src/util-device.h

index c5fa7e5e3f880402c8fcd62320041b7aa62ebb29..029736c9719027fa93af9c45c45e5c610cdd976e 100644 (file)
@@ -73,7 +73,7 @@
 #include "util-magic.h"
 #include "util-signal.h"
 #include "util-spm.h"
-
+#include "util-device.h"
 #include "util-var-name.h"
 
 #include "tm-threads.h"
@@ -98,6 +98,7 @@ static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER,
 static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len);
 static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len);
 static void TenantIdFree(void *d);
+static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p);
 static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p);
 static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p);
 
@@ -2168,6 +2169,10 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread
             det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
             SCLogDebug("TENANT_SELECTOR_VLAN");
             break;
+        case TENANT_SELECTOR_LIVEDEV:
+            det_ctx->TenantGetId = DetectEngineTentantGetIdFromLivedev;
+            SCLogDebug("TENANT_SELECTOR_LIVEDEV");
+            break;
         case TENANT_SELECTOR_DIRECT:
             det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
             SCLogDebug("TENANT_SELECTOR_DIRECT");
@@ -2932,6 +2937,122 @@ int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int r
     return 0;
 }
 
+static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node,
+        bool failure_fatal)
+{
+    ConfNode *mapping_node = NULL;
+
+    int mapping_cnt = 0;
+    if (mappings_root_node != NULL) {
+        TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
+            ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
+            if (tenant_id_node == NULL)
+                goto bad_mapping;
+            ConfNode *device_node = ConfNodeLookupChild(mapping_node, "device");
+            if (device_node == NULL)
+                goto bad_mapping;
+
+            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;
+            }
+
+            const char *dev = device_node->val;
+            LiveDevice *ld = LiveGetDevice(dev);
+            if (ld == NULL) {
+                SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s not found", dev);
+                goto bad_mapping;
+            }
+
+            if (ld->tenant_id_set) {
+                SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s already mapped to tenant-id %u",
+                        dev, ld->tenant_id);
+                goto bad_mapping;
+            }
+
+            ld->tenant_id = tenant_id;
+            ld->tenant_id_set = true;
+
+            if (DetectEngineTentantRegisterLivedev(tenant_id, ld->id) != 0) {
+                goto error;
+            }
+
+            SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
+            mapping_cnt++;
+            continue;
+
+        bad_mapping:
+            if (failure_fatal)
+                goto error;
+        }
+    }
+    SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
+    return mapping_cnt;
+
+error:
+    return 0;
+}
+
+static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node,
+        bool failure_fatal)
+{
+    ConfNode *mapping_node = NULL;
+
+    int mapping_cnt = 0;
+    if (mappings_root_node != NULL) {
+        TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
+            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 (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 (vlan_id == 0 || vlan_id >= 4095) {
+                SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id  "
+                        "of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
+                goto bad_mapping;
+            }
+
+            if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
+                goto error;
+            }
+            SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
+            mapping_cnt++;
+            continue;
+
+        bad_mapping:
+            if (failure_fatal)
+                goto error;
+        }
+    }
+    return mapping_cnt;
+
+error:
+    return 0;
+}
+
 /**
  *  \brief setup multi-detect / multi-tenancy
  *
@@ -2977,6 +3098,15 @@ int DetectEngineMultiTenantSetup(void)
 
             } else if (strcmp(handler, "direct") == 0) {
                 tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
+            } else if (strcmp(handler, "device") == 0) {
+                tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
+                if (EngineModeIsIPS()) {
+                    SCLogWarning(SC_ERR_MT_NO_MAPPING,
+                            "multi-tenant 'device' mode not supported for IPS");
+                    SCMutexUnlock(&master->lock);
+                    goto error;
+                }
+
             } else {
                 SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s "
                                                  "multi-detect.selector", handler);
@@ -2989,63 +3119,31 @@ int DetectEngineMultiTenantSetup(void)
 
         /* traffic -- tenant mappings */
         ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
-        ConfNode *mapping_node = NULL;
-
-        int mapping_cnt = 0;
-        if (mappings_root_node != NULL) {
-            TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
-                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 (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 (vlan_id == 0 || vlan_id >= 4095) {
-                    SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id  "
-                            "of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
-                    goto bad_mapping;
-                }
-
-                if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
-                    goto error;
+        if (tenant_selector == TENANT_SELECTOR_VLAN) {
+            int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(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
+                 * depending on failure_fatal */
+
+                if (unix_socket) {
+                    SCLogNotice("no tenant traffic mappings defined, "
+                            "tenants won't be used until mappings are added");
+                } else {
+                    if (failure_fatal) {
+                        SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
+                        goto error;
+                    } else {
+                        SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
+                    }
                 }
-                SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
-                mapping_cnt++;
-                continue;
-
-            bad_mapping:
-                if (failure_fatal)
-                    goto error;
             }
-        }
-
-        if (tenant_selector == TENANT_SELECTOR_VLAN && mapping_cnt == 0) {
-            /* no mappings are valid when we're in unix socket mode,
-             * they can be added on the fly. Otherwise warn/error
-             * depending on failure_fatal */
-
-            if (unix_socket) {
-                SCLogNotice("no tenant traffic mappings defined, "
-                        "tenants won't be used until mappings are added");
-            } else {
+        } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
+            int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
+                    failure_fatal);
+            if (mapping_cnt == 0) {
                 if (failure_fatal) {
                     SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
                     goto error;
@@ -3141,6 +3239,18 @@ static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet
     return 0;
 }
 
+static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p)
+{
+    const DetectEngineThreadCtx *det_ctx = ctx;
+    const LiveDevice *ld = p->livedev;
+
+    if (ld == NULL || det_ctx == NULL)
+        return 0;
+
+    SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
+    return ld->tenant_id;
+}
+
 static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector,
                                            uint32_t tenant_id, uint32_t traffic_id)
 {
@@ -3218,6 +3328,11 @@ static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelector
     return -1;
 }
 
+int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id)
+{
+    return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
+}
+
 int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
 {
     return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
index 39e033ad2e8488bfa5765aa0e5e43d5c89add6d7..cfcc05788581eab7cdb8fb2cea1a1848d4cd521a 100644 (file)
@@ -102,6 +102,7 @@ int DetectEngineReloadIsIdle(void);
 int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml);
 int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt);
 
+int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id);
 int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id);
 int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id);
 int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id);
index 11ad5dae89d514634c3bc0a27f1af021a3b7217f..a8048f89e2200d119af0967008b653cd7e9ae54d 100644 (file)
@@ -1325,6 +1325,7 @@ 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 */
 };
 
 typedef struct DetectEngineTenantMapping_ {
index e6ba99fe999829739e5c09dff5e7ba65036b9025..551a398963f1e99e8cd532d5e79f94933bacf82a 100644 (file)
@@ -133,6 +133,7 @@ int LiveRegisterDevice(const char *dev)
     SC_ATOMIC_INIT(pd->drop);
     SC_ATOMIC_INIT(pd->invalid_checksums);
     pd->ignore_checksum = 0;
+    pd->id = LiveGetDeviceCount();
     TAILQ_INSERT_TAIL(&live_devices, pd, next);
 
     SCLogDebug("Device \"%s\" registered and created.", dev);
index 2bdd00d33c44282545270754981845bf32f74ac7..d14825b1b4379a16faa9f2f4a633166c13e97ce2 100644 (file)
@@ -40,13 +40,18 @@ int LiveGetOffload(void);
 typedef struct LiveDevice_ {
     char *dev;  /**< the device (e.g. "eth0") */
     char dev_short[MAX_DEVNAME + 1];
+    bool tenant_id_set;
+
     int ignore_checksum;
+    int id;
+
     SC_ATOMIC_DECLARE(uint64_t, pkts);
     SC_ATOMIC_DECLARE(uint64_t, drop);
     SC_ATOMIC_DECLARE(uint64_t, bypassed);
     SC_ATOMIC_DECLARE(uint64_t, invalid_checksums);
     TAILQ_ENTRY(LiveDevice_) next;
 
+    uint32_t tenant_id;     /**< tenant id in multi-tenancy */
     uint32_t offload_orig;  /**< original offload settings to restore @exit */
 } LiveDevice;