From: Masud Hasan (mashasan) Date: Mon, 2 Nov 2020 16:30:39 +0000 (+0000) Subject: Merge pull request #2565 in SNORT/snort3 from ~MMATIRKO/snort3:delete_mac to master X-Git-Tag: 3.0.3-5~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4456e15abf296b354427527c412827e6a5043899;p=thirdparty%2Fsnort3.git Merge pull request #2565 in SNORT/snort3 from ~MMATIRKO/snort3:delete_mac to master Squashed commit of the following: commit 584d6d7e0b4c65d3bc3ae3decad2f943645e3a17 Author: Michael Matirko Date: Wed Oct 21 13:34:48 2020 -0400 rna: add command to delete MAC hosts and protos --- diff --git a/src/host_tracker/host_tracker.cc b/src/host_tracker/host_tracker.cc index 2e9e9d97a..10ba176a9 100644 --- a/src/host_tracker/host_tracker.cc +++ b/src/host_tracker/host_tracker.cc @@ -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 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(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 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 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 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 (&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(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); + } } } diff --git a/src/host_tracker/host_tracker.h b/src/host_tracker/host_tracker.h index 819b2bdc8..98d0d0391 100644 --- a/src/host_tracker/host_tracker.h +++ b/src/host_tracker/host_tracker.h @@ -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 HostMacAllocator; typedef HostCacheAllocIp HostAppAllocator; typedef HostCacheAllocIp HostClientAllocator; typedef HostCacheAllocIp 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 macs; // list guarantees iterator validity on insertion + + // list guarantees iterator validity on insertion + std::list> macs; std::vector> network_protos; std::vector> xport_protos; std::vector 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 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; diff --git a/src/network_inspectors/rna/rna_mac_cache.h b/src/network_inspectors/rna/rna_mac_cache.h index 0007c1e7b..90d6ded60 100644 --- a/src/network_inspectors/rna/rna_mac_cache.h +++ b/src/network_inspectors/rna/rna_mac_cache.h @@ -75,6 +75,22 @@ public: return last_event; } + bool delete_proto(uint16_t proto) + { + std::lock_guard 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 lck(host_tracker_mac_lock); diff --git a/src/network_inspectors/rna/rna_module.cc b/src/network_inspectors/rna/rna_module.cc index 4ff3cbb88..0387ada9c 100644 --- a/src/network_inspectors/rna/rna_module.cc +++ b/src/network_inspectors/rna/rna_module.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #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; } diff --git a/src/network_inspectors/rna/test/rna_module_mock.h b/src/network_inspectors/rna/test/rna_module_mock.h index 06001ab26..a80c4c1af 100644 --- a/src/network_inspectors/rna/test/rna_module_mock.h +++ b/src/network_inspectors/rna/test/rna_module_mock.h @@ -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*)