]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2565 in SNORT/snort3 from ~MMATIRKO/snort3:delete_mac to master
authorMasud Hasan (mashasan) <mashasan@cisco.com>
Mon, 2 Nov 2020 16:30:39 +0000 (16:30 +0000)
committerMasud Hasan (mashasan) <mashasan@cisco.com>
Mon, 2 Nov 2020 16:30:39 +0000 (16:30 +0000)
Squashed commit of the following:

commit 584d6d7e0b4c65d3bc3ae3decad2f943645e3a17
Author: Michael Matirko <mmatirko@cisco.com>
Date:   Wed Oct 21 13:34:48 2020 -0400

    rna: add command to delete MAC hosts and protos

src/host_tracker/host_tracker.cc
src/host_tracker/host_tracker.h
src/network_inspectors/rna/rna_mac_cache.h
src/network_inspectors/rna/rna_module.cc
src/network_inspectors/rna/test/rna_module_mock.h

index 2e9e9d97a31160ffbf5eb87b114f171fc806704d..10ba176a9b161074b1b7223309b36e644ed5d0ac 100644 (file)
@@ -97,13 +97,40 @@ bool HostTracker::add_mac(const uint8_t* mac, uint8_t ttl, uint8_t primary)
     if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
         return false;
 
+    HostMac_t* invisible_swap_candidate = nullptr;
     lock_guard<mutex> lck(host_tracker_lock);
 
-    for ( const auto& hm : macs )
-        if ( !memcmp(mac, hm.mac, MAC_SIZE) )
-            return false;
+    for ( auto& hm_t : macs )
+    {
+        if ( !memcmp(mac, hm_t.mac, MAC_SIZE) )
+        {
+            if ( hm_t.visibility )
+            {
+                return false;
+            }
+
+            hm_t.visibility = true;
+            num_visible_macs++;
+            return true;
+        }
+
+        if (!invisible_swap_candidate and !hm_t.visibility)
+            invisible_swap_candidate = &hm_t;
+    }
+
+    if (invisible_swap_candidate)
+    {
+        memcpy(invisible_swap_candidate->mac, mac, MAC_SIZE);
+        invisible_swap_candidate->ttl = ttl;
+        invisible_swap_candidate->primary = primary;
+        invisible_swap_candidate->visibility = true;
+        num_visible_macs++;
+        return true;
+    }
 
     macs.emplace_back(ttl, mac, primary, last_seen);
+    num_visible_macs++;
+
     return true;
 }
 
@@ -130,7 +157,10 @@ bool HostTracker::get_hostmac(const uint8_t* mac, HostMac& hm)
     for ( auto& ahm : macs )
         if ( !memcmp(mac, ahm.mac, MAC_SIZE) )
         {
-            hm = ahm;
+            if (!ahm.visibility)
+                return false;
+
+            hm = static_cast<HostMac>(ahm);
             return true;
         }
 
@@ -140,11 +170,12 @@ bool HostTracker::get_hostmac(const uint8_t* mac, HostMac& hm)
 const uint8_t* HostTracker::get_last_seen_mac()
 {
     lock_guard<mutex> lck(host_tracker_lock);
-    const HostMac* max_hm = nullptr;
+    const HostMac_t* max_hm = nullptr;
 
     for ( const auto& hm : macs )
-        if ( !max_hm or max_hm->last_seen < hm.last_seen)
-            max_hm = &hm;
+        if ( !max_hm or max_hm->last_seen < hm.last_seen )
+            if (hm.visibility)
+                max_hm = &hm;
 
     if ( max_hm )
         return max_hm->mac;
@@ -162,7 +193,7 @@ bool HostTracker::update_mac_ttl(const uint8_t* mac, uint8_t new_ttl)
     for ( auto& hm : macs )
         if ( !memcmp(mac, hm.mac, MAC_SIZE) )
         {
-            if (hm.ttl < new_ttl)
+            if (hm.ttl < new_ttl and hm.visibility)
             {
                 hm.ttl = new_ttl;
                 return true;
@@ -179,13 +210,16 @@ bool HostTracker::make_primary(const uint8_t* mac)
     if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
         return false;
 
-    HostMac* hm = nullptr;
+    HostMac_t* hm = nullptr;
 
     lock_guard<mutex> lck(host_tracker_lock);
 
     for ( auto& hm_iter : macs )
         if ( !memcmp(mac, hm_iter.mac, MAC_SIZE) )
         {
+            if ( !hm_iter.visibility )
+                return false;
+
             hm = &hm_iter;
             break;
         }
@@ -207,22 +241,22 @@ HostMac* HostTracker::get_max_ttl_hostmac()
 {
     lock_guard<mutex> lck(host_tracker_lock);
 
-    HostMac* max_ttl_hm = nullptr;
+    HostMac_t* max_ttl_hm = nullptr;
     uint8_t max_ttl = 0;
 
     for ( auto& hm : macs )
     {
-        if (hm.primary)
-            return &hm;
+        if ( hm.primary and hm.visibility )
+            return static_cast<HostMac*> (&hm);
 
-        if ( hm.ttl > max_ttl )
+        if ( hm.ttl > max_ttl and hm.visibility )
         {
             max_ttl = hm.ttl;
             max_ttl_hm = &hm;
         }
     }
 
-    return max_ttl_hm;
+    return static_cast<HostMac*>(max_ttl_hm);
 }
 
 void HostTracker::update_vlan(uint16_t vth_pri_cfi_vlan, uint16_t vth_proto)
@@ -668,6 +702,11 @@ bool HostTracker::set_visibility(bool v)
         for (auto& proto : xport_protos)
             proto.second = false;
 
+        for (auto& mac_t : macs)
+            mac_t.visibility = false;
+
+        num_visible_macs = 0;
+
         for (auto& s : services)
         {
             s.visibility = false;
@@ -906,13 +945,16 @@ void HostTracker::stringify(string& str)
 
     if ( !macs.empty() )
     {
-        str += "\nmacs size: " + to_string(macs.size());
+        str += "\nmacs size: " + to_string(num_visible_macs);
         for ( const auto& m : macs )
         {
-            str += "\n    mac: " + to_mac_string(m.mac)
-                + ", ttl: " + to_string(m.ttl)
-                + ", primary: " + to_string(m.primary)
-                + ", time: " + to_time_string(m.last_seen);
+            if ( m.visibility )
+            {
+                str += "\n    mac: " + to_mac_string(m.mac)
+                    + ", ttl: " + to_string(m.ttl)
+                    + ", primary: " + to_string(m.primary)
+                    + ", time: " + to_time_string(m.last_seen);
+            }
         }
     }
 
index 819b2bdc8b88c6c286ec6511984be1df1a77f808..98d0d03917df7a20765f457b971f70da8537295c 100644 (file)
@@ -163,10 +163,28 @@ enum HostType : std::uint32_t
     HOST_TYPE_LB
 };
 
+class HostMac_t : public HostMac
+{
+public:
+    HostMac_t(uint8_t p_ttl, const uint8_t* p_mac, uint8_t p_primary, uint32_t p_last_seen)
+        : HostMac(p_ttl, p_mac, p_primary, p_last_seen) {}
+
+    HostMac_t& operator=(const HostMac_t& hm)
+    {
+        ttl = hm.ttl;
+        primary = hm.primary;
+        last_seen = hm.last_seen;
+        visibility = hm.visibility;
+        memcpy(mac, hm.mac, MAC_SIZE);
+        return *this;
+    }
+
+    bool visibility = true;
+};
+
 #define MIN_BOOT_TIME    10
 #define MIN_TTL_DIFF     16
 
-typedef HostCacheAllocIp<HostMac> HostMacAllocator;
 typedef HostCacheAllocIp<HostApplication> HostAppAllocator;
 typedef HostCacheAllocIp<HostClient> HostClientAllocator;
 typedef HostCacheAllocIp<DeviceFingerprint> HostDeviceFpAllocator;
@@ -371,7 +389,9 @@ private:
     uint8_t hops;                 // hops from the snort inspector, e.g., zero for ARP
     uint32_t last_seen;           // the last time this host was seen
     uint32_t last_event;          // the last time an event was generated
-    std::list<HostMac, HostMacAllocator> macs; // list guarantees iterator validity on insertion
+
+    // list guarantees iterator validity on insertion
+    std::list<HostMac_t, HostCacheAllocIp<HostMac_t>> macs;
     std::vector<NetProto_t, HostCacheAllocIp<NetProto_t>> network_protos;
     std::vector<XProto_t, HostCacheAllocIp<XProto_t>> xport_protos;
     std::vector<HostApplication, HostAppAllocator> services;
@@ -384,12 +404,20 @@ private:
     HostType host_type = HOST_TYPE_HOST;
     uint8_t ip_ttl = 0;
     uint32_t nat_count = 0;
-    uint32_t nat_count_start;     // the time nat counting start for this host
+    uint32_t nat_count_start;     // the time nat counting starts for this host
 
     bool visibility = true;
 
     uint32_t num_visible_services = 0;
     uint32_t num_visible_clients = 0;
+    uint32_t num_visible_macs = 0;
+
+    // These three do not lock independently; they are used by payload discovery and called
+    // from add_payload(HostApplication&, Port, IpProtocol, AppId, AppId, size_t); where the
+    // lock is actually obtained
+    bool add_payload_no_lock(const AppId, HostApplication*, size_t);
+    HostApplication* find_service_no_lock(Port, IpProtocol, AppId);
+    void update_ha_no_lock(HostApplication& dst, HostApplication& src);
 
     // Hide / delete the constructor from the outside world. We don't want to
     // have zombie host trackers, i.e. host tracker objects that live outside
@@ -404,13 +432,6 @@ private:
     template<class Key, class Value, class Hash>
     friend class LruCacheShared;
 
-    // These two do not lock independently; they are used by payload discovery and called
-    // from add_payload(HostApplication&, Port, IpProtocol, AppId, AppId, size_t); where the
-    // lock is actually obtained
-    bool add_payload_no_lock(const AppId, HostApplication*, size_t);
-    HostApplication* find_service_no_lock(Port, IpProtocol, AppId);
-    void update_ha_no_lock(HostApplication& dst, HostApplication& src);
-
     // ... and some unit tests. See Utest.h and UtestMacros.h in cpputest.
     friend class TEST_host_tracker_add_find_service_test_Test;
     friend class TEST_host_tracker_stringify_Test;
index 0007c1e7b2459f0d9441b4df108efb34e43804c8..90d6ded603753914bf71cab4b6aa1f1061ee41a2 100644 (file)
@@ -75,6 +75,22 @@ public:
         return last_event;
     }
 
+    bool delete_proto(uint16_t proto)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_mac_lock);
+
+        for (auto it = network_protos.begin(); it != network_protos.end(); ++it)
+        {
+            if (*it == proto)
+            {
+                network_protos.erase(it);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     void update_last_seen()
     {
         std::lock_guard<std::mutex> lck(host_tracker_mac_lock);
index 4ff3cbb885431d9739a4ed8dc2f49612f92bbbb9..0387ada9c0f009fef82f1a3fb9189ff1a2d9acb6 100644 (file)
@@ -28,6 +28,7 @@
 #include <fstream>
 #include <iomanip>
 #include <sstream>
+#include <string.h>
 #include <sys/stat.h>
 
 #include "log/messages.h"
@@ -47,6 +48,8 @@
 using namespace snort;
 using namespace std;
 
+#define MAC_STRLEN 17
+
 THREAD_LOCAL const Trace* rna_trace = nullptr;
 
 //-------------------------------------------------------------------------
@@ -82,10 +85,153 @@ bool FpProcReloadTuner::tinit()
     return false;  // no work to do after this
 }
 
+static bool get_mac_from_args(lua_State* L, uint8_t* mac_addr)
+{
+    const char* lua_in = luaL_optstring(L, 1, nullptr);
+
+    size_t input_len = strlen(lua_in);
+    if ( input_len != MAC_STRLEN)
+    {
+        LogMessage("Improperly formatted MAC address, use format aa:bb:cc:dd:ee:ff\n");
+        return false;
+    }
+
+    string in(lua_in);
+    istringstream tokinizer(in);
+    stringstream hex_parser;
+    string tok;
+    int idx = 0;
+
+    // Need to use uint16_t, otherwise stringstream sees uint_8 (char*)
+    // and converts the string to a char* (not what was intended)
+    uint16_t tmp_byte = 0;
+
+    while (getline(tokinizer, tok, ':'))
+    {
+        hex_parser << hex << tok;
+        hex_parser >> tmp_byte;
+        mac_addr[idx++] = (uint8_t) tmp_byte;
+
+           if ( hex_parser.fail() or tok.size() != 2 )
+           {
+               LogMessage("Improperly formatted MAC address, use format "
+                "aa:bb:cc:dd:ee:ff\n");
+               return false;
+           }
+
+        hex_parser.str(string());
+        hex_parser.clear();
+    }
+
+       if ( idx != MAC_SIZE )
+    {
+        LogMessage("Improperly formatted MAC address, use format aa:bb:cc:dd:ee:ff\n");
+        return false;
+    }
+
+    return true;
+
+}
+
+static int delete_mac_host(lua_State* L)
+{
+    RnaModule* mod = (RnaModule*) ModuleManager::get_module(RNA_NAME);
+    if ( mod )
+    {
+        uint8_t mac[MAC_SIZE] = {0};
+
+           const char* lua_in = luaL_optstring(L, 1, nullptr);
+
+           if ( lua_in == nullptr )
+           {
+               LogMessage("Usage: rna.delete_mac_host(mac)\n");
+               return 0;
+           }
+
+        bool valid_mac = get_mac_from_args(L, mac);
+        if (!valid_mac)
+            return 0;
+
+        MacKey search_mk(mac);
+        bool success = host_cache_mac.remove((const uint8_t*) &search_mk);
+
+        if (!success)
+        {
+            LogMessage("MAC not found in cache\n");
+            return 0;
+        }
+
+        LogMessage("rna.delete_mac_host completed successfully\n");
+    }
+    return 0;
+}
+
+static int delete_mac_host_proto(lua_State* L)
+{
+    RnaModule* mod = (RnaModule*) ModuleManager::get_module(RNA_NAME);
+    if ( mod )
+    {
+        uint8_t mac[MAC_SIZE] = {0};
+
+           const char* lua_in = luaL_optstring(L, 1, nullptr);
+
+           if ( lua_in == nullptr )
+           {
+               LogMessage("Usage: rna.delete_mac_host_proto(mac, proto)\n");
+               return 0;
+           }
+
+        bool valid_mac = get_mac_from_args(L, mac);
+        if (!valid_mac)
+            return 0;
+
+        MacKey search_mk(mac);
+        auto htm = host_cache_mac.find((const uint8_t*) &search_mk);
+
+        if (!htm)
+        {
+            LogMessage("MAC not found in cache\n");
+            return 0;
+        }
+
+        uint16_t proto = luaL_optnumber(L, 2, 0);
+        bool success = false;
+        if (proto != 0)
+            success = htm->delete_proto(proto);
+
+        if (success)
+            LogMessage("rna.delete_mac_host_proto completed successfully\n");
+        else
+            LogMessage("rna.delete_mac_host_proto failed to delete protocol\n");
+
+    }
+    return 0;
+}
+
+
+static const Parameter mac_delete_params[] =
+{
+    { "mac", Parameter::PT_STRING, nullptr, nullptr, "MAC address to delete, "
+        "format aa:bb:cc:dd:ee:ff"},
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const Parameter mac_delete_proto_params[] =
+{
+    { "mac", Parameter::PT_STRING, nullptr, nullptr, "MAC address with associated protocol, "
+        "format: aa:bb:cc:dd:ee:ff"},
+    { "proto", Parameter::PT_INT, nullptr, nullptr, "protocol to delete from MAC host, "
+        "format: Ethertype, in decimal" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
 static const Command rna_cmds[] =
 {
-    { "dump_macs", dump_mac_cache, nullptr,
-      "dump rna's internal MAC trackers" },
+    { "dump_macs", dump_mac_cache, nullptr, "dump rna's internal MAC trackers" },
+    { "delete_mac_host", delete_mac_host, mac_delete_params,
+        "delete a MAC from rna's MAC cache"},
+    { "delete_mac_host_proto", delete_mac_host_proto, mac_delete_proto_params,
+        "delete a protocol associated with a MAC host"},
     { nullptr, nullptr, nullptr, nullptr }
 };
 
@@ -386,7 +532,7 @@ bool RnaModule::log_mac_cache(const char* outfile)
     {
         str = "MAC: ";
         str += format_dump_mac(elem.first.mac_addr);
-        str += "\n Key: " +  to_string(hash_mac(elem.first.mac_addr));
+        str += "\n Key: " + to_string(hash_mac(elem.first.mac_addr));
         elem.second->stringify(str);
         out_stream << str << endl << endl;
     }
index 06001ab260f6b3c764fbea9502f5aca0d52cb16f..a80c4c1afc945e4b073d0a78862b627251b8f116 100644 (file)
@@ -28,6 +28,11 @@ THREAD_LOCAL ProfileStats rna_perf_stats;
 
 const char* luaL_optlstring(lua_State*, int, const char*, size_t*) { return nullptr; }
 
+extern "C"
+{
+    lua_Number luaL_optnumber(lua_State*, int, lua_Number) { return 0; }
+}
+
 namespace snort
 {
 Module* ModuleManager::get_module(const char*)