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;
}
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;
}
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;
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;
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;
}
{
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)
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;
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);
+ }
}
}
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;
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;
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
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;
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);
#include <fstream>
#include <iomanip>
#include <sstream>
+#include <string.h>
#include <sys/stat.h>
#include "log/messages.h"
using namespace snort;
using namespace std;
+#define MAC_STRLEN 17
+
THREAD_LOCAL const Trace* rna_trace = nullptr;
//-------------------------------------------------------------------------
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 }
};
{
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;
}
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*)