LruCacheSharedMemcap(const LruCacheSharedMemcap& arg) = delete;
LruCacheSharedMemcap& operator=(const LruCacheSharedMemcap& arg) = delete;
- LruCacheSharedMemcap(const size_t initial_size) : LruCacheShared<Key, Value, Hash, Eq>(initial_size) {}
+ LruCacheSharedMemcap(const size_t initial_size) : LruCacheShared<Key, Value, Hash, Eq>(initial_size),
+ valid_id(invalid_id+1) {}
size_t mem_size() override
{
return false;
}
+ bool is_valid(size_t id) const
+ {
+ return id == valid_id;
+ }
+
+ void invalidate()
+ {
+ valid_id++;
+ }
+
+ size_t get_valid_id() const { return valid_id; }
+
+ static constexpr size_t invalid_id = 0;
+
template <class T>
friend class HostCacheAllocIp;
current_size -= mem_chunk;
}
+ std::atomic<size_t> valid_id;
+
std::mutex reload_mutex;
friend class TEST_host_cache_module_misc_Test; // for unit test
};
const uint8_t snort::zero_mac[MAC_SIZE] = {0, 0, 0, 0, 0, 0};
+
+HostTracker::HostTracker() : hops(-1)
+{
+ last_seen = nat_count_start = (uint32_t) packet_time();
+ last_event = -1;
+ visibility = host_cache.get_valid_id();
+}
+
void HostTracker::update_last_seen()
{
lock_guard<mutex> lck(host_tracker_lock);
return available;
}
- if ( max_services == 0 or num_visible_services < max_services )
+ if ( max_services == 0 or num_visible_services < max_services )
{
services.emplace_back(port, proto, appid, false, 1, lseen);
return &services.back();
bool HostTracker::set_visibility(bool v)
{
+ // get_valid_id may use its own lock, so get this outside our lock
+ size_t container_id = host_cache.get_valid_id();
+
std::lock_guard<std::mutex> lck(host_tracker_lock);
- bool old_visibility = visibility;
+ size_t old_visibility = visibility;
- visibility = v;
+ visibility = v ? container_id : HostCacheIp::invalid_id;
- if ( visibility == false )
+ if (visibility == HostCacheIp::invalid_id)
{
for (auto& proto : network_protos)
proto.second = false;
for (auto& info : s.info)
info.visibility = false;
s.user[0] = '\0';
- set_payload_visibility_no_lock(s.payloads, v, s.num_visible_payloads);
+ set_payload_visibility_no_lock(s.payloads, false, s.num_visible_payloads);
}
num_visible_services = 0;
for ( auto& c : clients )
{
c.visibility = false;
- set_payload_visibility_no_lock(c.payloads, v, c.num_visible_payloads);
+ set_payload_visibility_no_lock(c.payloads, false, c.num_visible_payloads);
}
num_visible_clients = 0;
ua_fps.clear();
}
- return old_visibility;
+ return old_visibility == visibility;
+}
+
+bool HostTracker::is_visible() const
+{
+ std::lock_guard<std::mutex> lck(host_tracker_lock);
+ return visibility == host_cache.get_valid_id();
}
+
bool HostTracker::set_network_proto_visibility(uint16_t proto, bool v)
{
std::lock_guard<std::mutex> lck(host_tracker_lock);
HostApplicationInfo(const char *ver, const char *ven);
char vendor[INFO_SIZE] = { '\0' };
char version[INFO_SIZE] = { '\0' };
- bool visibility = true;
friend class HostTracker;
+private:
+ bool visibility = true;
+
};
typedef HostCacheAllocIp<HostApplicationInfo> HostAppInfoAllocator;
typedef std::pair<uint16_t, bool> NetProto_t;
typedef std::pair<uint8_t, bool> XProto_t;
- HostTracker() : hops(-1)
- {
- last_seen = nat_count_start = (uint32_t) packet_time();
- last_event = -1;
- }
+ HostTracker();
void update_last_seen();
uint32_t get_last_seen() const
bool set_visibility(bool v = true);
- bool is_visible() const
- {
- std::lock_guard<std::mutex> lck(host_tracker_lock);
- return visibility;
- }
+ bool is_visible() const;
// the control delete commands do not actually remove objects from
// the host tracker, but just mark them as invisible, until rediscovered.
uint32_t nat_count = 0;
uint32_t nat_count_start; // the time nat counting starts for this host
- bool visibility = true;
+ size_t visibility;
uint32_t num_visible_services = 0;
uint32_t num_visible_clients = 0;
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);
-
+
HostApplication* find_and_add_service_no_lock(Port, IpProtocol, uint32_t lseen,
bool& is_new, AppId, uint16_t max_services = 0);
set ( RNA_SOURCES
${RNA_INCLUDES}
+ data_purge_cmd.cc
+ data_purge_cmd.h
rna_app_discovery.cc
rna_app_discovery.h
rna_event_handler.cc
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// data_purge_cmd.cc author Silviu Minut <sminut@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "data_purge_cmd.h"
+
+#include "managers/inspector_manager.h"
+
+#include "rna_inspector.h"
+#include "rna_name.h"
+#include "rna_pnd.h"
+
+using namespace snort;
+
+DataPurgeAC::~DataPurgeAC()
+{
+ auto rna_ins = (RnaInspector*) InspectorManager::get_inspector(RNA_NAME, true);
+ RnaPnd* pnd = rna_ins->get_pnd();
+ delete pnd->host_cache_mac_ptr;
+ pnd->host_cache_mac_ptr = host_cache_mac;
+ set_host_cache_mac(host_cache_mac);
+}
+
+bool DataPurgeAC::execute(Analyzer&, void**)
+{
+ set_host_cache_mac(host_cache_mac);
+ return true;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// data_purge_cmd.h author Silviu Minut <sminut@cisco.com>
+
+#ifndef DATA_PURGE_CMD_H
+#define DATA_PURGE_CMD_H
+
+#include "main/analyzer_command.h"
+
+#include "rna_mac_cache.h"
+
+class DataPurgeAC : public snort::AnalyzerCommand
+{
+public:
+
+ DataPurgeAC(HostCacheMac* hcm) : host_cache_mac(hcm) { }
+ ~DataPurgeAC() override;
+
+ bool execute(Analyzer&, void**) override;
+
+ const char* stringify() override { return "DATA_PURGE"; }
+
+private:
+ HostCacheMac* host_cache_mac;
+};
+
+#endif
const auto& src_ip = p->ptrs.ip_api.get_src();
auto ht = host_cache.find(*src_ip);
- if ( !ht )
+ if ( !ht || !ht->is_visible() )
return; // should not happen as rna would get new flow event before appid event
const uint8_t* src_mac;
if ( p->packet_flags & PKT_FROM_SERVER )
{
auto cht = host_cache.find(p->flow->client_ip);
- if ( cht )
+ if ( cht && cht->is_visible() )
discover_client(p, cht, (const struct in6_addr*) &p->flow->client_ip,
layer::get_eth_layer(p)->ether_dst, conf, logger, version, client,
service);
if ( p->is_from_client() )
{
htp = host_cache.find(ip);
- if ( !htp )
+ if ( !htp || !htp->is_visible() )
return false;
if ( layer::get_eth_layer(p) )
bool new_client_payload = false;
auto client_ht = host_cache.find(p->flow->client_ip);
- if (!client_ht)
+ if (!client_ht || !client_ht->is_visible())
return;
HostClient hc(client, nullptr, service);
if ( p->is_from_client() )
{
htp = host_cache.find(ip);
- if ( !htp )
+ if ( !htp || !htp->is_visible() )
return;
if ( layer::get_eth_layer(p) )
// tinit is not called during reload, so pass processor pointers to threads via reload tuner
if ( Snort::is_reloading() && InspectorManager::get_inspector(RNA_NAME, true) )
- sc->register_reload_resource_tuner(new FpProcReloadTuner(*mod_conf));
+ sc->register_reload_resource_tuner(new FpProcReloadTuner(*mod_conf, pnd->host_cache_mac_ptr));
return true;
}
set_tcp_fp_processor(mod_conf->tcp_processor);
set_ua_fp_processor(mod_conf->ua_processor);
set_udp_fp_processor(mod_conf->udp_processor);
+ set_host_cache_mac(pnd->host_cache_mac_ptr);
}
void RnaInspector::tterm()
snort::UdpFpProcessor*&);
void set_fp_processor(snort::TcpFpProcessor*, snort::UaFpProcessor*, snort::UdpFpProcessor*);
+ RnaPnd* get_pnd() const { return pnd; }
+
private:
void load_rna_conf();
RnaModuleConfig* mod_conf = nullptr;
using namespace snort;
using namespace std;
-HostCacheMac host_cache_mac(MAC_CACHE_INITIAL_SIZE);
-
bool HostTrackerMac::add_network_proto(const uint16_t type)
{
lock_guard<mutex> lck(host_tracker_mac_lock);
TEST_CASE("RNA Mac Cache", "[rna_mac_cache]")
{
uint8_t a_mac[6] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6};
+ HostCacheMac mac_cache(MAC_CACHE_INITIAL_SIZE);
SECTION("HostCacheMac: store, retrieve")
{
bool new_host_mac = false;
- auto a_ptr = host_cache_mac.find_else_create(a, &new_host_mac);
+ auto a_ptr = mac_cache.find_else_create(a, &new_host_mac);
CHECK(new_host_mac == true);
CHECK(a_ptr != nullptr);
new_host_mac = false;
- auto b_ptr = host_cache_mac.find_else_create(b, &new_host_mac);
+ auto b_ptr = mac_cache.find_else_create(b, &new_host_mac);
CHECK(new_host_mac == true);
CHECK(b_ptr != nullptr);
new_host_mac = false;
- auto c_ptr = host_cache_mac.find_else_create(c, &new_host_mac);
+ auto c_ptr = mac_cache.find_else_create(c, &new_host_mac);
CHECK(new_host_mac == true);
CHECK(c_ptr != nullptr);
// Try to add one of the previous macs again
new_host_mac = false;
- auto test_ptr = host_cache_mac.find_else_create(test, &new_host_mac);
+ auto test_ptr = mac_cache.find_else_create(test, &new_host_mac);
CHECK(new_host_mac == false);
CHECK(test_ptr != nullptr);
// Verify macs in cache in LRU order, where test mac (i.e., b) is the most recent
- const auto&& lru_data = host_cache_mac.get_all_data();
+ const auto&& lru_data = mac_cache.get_all_data();
CHECK(lru_data.size() == 3);
CHECK(lru_data[2].first == a);
CHECK(lru_data[1].first == c);
SECTION("HostCacheMac: VLAN Tag Details")
{
MacKey a(a_mac);
- auto a_ptr = host_cache_mac.find_else_create(a, nullptr);
+ auto a_ptr = mac_cache.find_else_create(a, nullptr);
a_ptr->update_vlan(12345, 54321);
uint8_t cfi, priority;
};
typedef LruCacheSharedMemcap<MacKey, HostTrackerMac, HashMac> HostCacheMac;
-extern HostCacheMac host_cache_mac;
+
+extern HostCacheMac* get_host_cache_mac();
template <class T>
HostCacheAllocMac<T>::HostCacheAllocMac()
{
- lru = &host_cache_mac;
+ lru = get_host_cache_mac();
}
#endif
#include <string.h>
#include <sys/stat.h>
+#include "host_tracker/host_cache.h"
#include "log/messages.h"
#include "lua/lua.h"
+#include "main/request.h"
#include "main/snort_config.h"
+#include "managers/inspector_manager.h"
#include "managers/module_manager.h"
#include "utils/util.h"
+#include "data_purge_cmd.h"
#include "rna_fingerprint_tcp.h"
#include "rna_fingerprint_ua.h"
#include "rna_fingerprint_udp.h"
#include "rna_mac_cache.h"
+#include "rna_pnd.h"
#ifdef UNIT_TEST
#include "catch/snort_catch.h"
return ss.str();
}
+static int purge_data(lua_State* L)
+{
+ RnaModule* mod = (RnaModule*) ModuleManager::get_module(RNA_NAME);
+ if ( mod )
+ {
+ HostCacheMac* mac_cache = new HostCacheMac(MAC_CACHE_INITIAL_SIZE);
+ main_broadcast_command(new DataPurgeAC(mac_cache), (L != nullptr));
+
+ host_cache.invalidate();
+
+ auto& request = get_dispatched_request();
+ request.respond("data purge done\n", false, true);
+ LogMessage("data purge done\n");
+ }
+
+ return 0;
+}
+
bool FpProcReloadTuner::tinit()
{
set_tcp_fp_processor(mod_conf.tcp_processor);
set_ua_fp_processor(mod_conf.ua_processor);
set_udp_fp_processor(mod_conf.udp_processor);
+ set_host_cache_mac(host_cache_mac_ptr);
return false; // no work to do after this
}
return 0;
MacKey search_mk(mac);
- bool success = host_cache_mac.remove((const uint8_t*) &search_mk);
+ HostCacheMac* mac_cache = get_host_cache_mac();
+ assert(mac_cache);
+
+ bool success = mac_cache->remove((const uint8_t*) &search_mk);
if (!success)
{
return 0;
MacKey search_mk(mac);
- auto htm = host_cache_mac.find((const uint8_t*) &search_mk);
+ HostCacheMac* mac_cache = get_host_cache_mac();
+ assert(mac_cache);
+
+ auto htm = mac_cache->find((const uint8_t*) &search_mk);
if (!htm)
{
"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"},
+ { "purge_data", purge_data, nullptr,
+ "purge all host cache and mac cache data"},
{ nullptr, nullptr, nullptr, nullptr }
};
}
string str;
- const auto&& lru_data = host_cache_mac.get_all_data();
- out_stream << "Current mac cache size: " << host_cache_mac.mem_size() << " bytes, "
+ HostCacheMac* host_cache_mac = get_host_cache_mac();
+ assert(host_cache_mac);
+ const auto&& lru_data = host_cache_mac->get_all_data();
+ out_stream << "Current mac cache size: " << host_cache_mac->mem_size() << " bytes, "
<< lru_data.size() << " trackers" << endl << endl;
for ( const auto& elem : lru_data )
{
#include "rna_config.h"
#include "rna_fingerprint.h"
+#include "rna_mac_cache.h"
#include "rna_name.h"
struct RnaStats
class FpProcReloadTuner : public snort::ReloadResourceTuner
{
public:
- explicit FpProcReloadTuner(RnaModuleConfig& mod_conf) : mod_conf(mod_conf) { }
+ explicit FpProcReloadTuner(RnaModuleConfig& mod_conf, HostCacheMac* ptr = nullptr)
+ : mod_conf(mod_conf), host_cache_mac_ptr(ptr) { }
~FpProcReloadTuner() override = default;
bool tinit() override;
private:
RnaModuleConfig& mod_conf;
+ HostCacheMac* host_cache_mac_ptr = nullptr;
};
class RnaModule : public snort::Module
#define RNA_NAT_COUNT_THRESHOLD 10
#define RNA_NAT_TIMEOUT_THRESHOLD 10 // timeout in seconds
+static THREAD_LOCAL HostCacheMac* local_mac_cache_ptr = nullptr;
+
+HostCacheMac* get_host_cache_mac()
+{
+ return local_mac_cache_ptr;
+}
+
+void set_host_cache_mac(HostCacheMac* mac_host)
+{
+ local_mac_cache_ptr = mac_host;
+}
+
+HostCacheIp::Data RnaPnd::find_or_create_host_tracker(const SfIp& ip, bool& new_host)
+{
+ auto ht = host_cache.find_else_create(ip, &new_host);
+
+ // If it's a new host, it's automatically visible, so we don't do anything.
+ // If it's not a new host, we're rediscovering it, so make it visible.
+ // Also if it was not new (we had it in the cache) and it went from
+ // not visible to visible, then it's as good as new.
+ if (!new_host and !ht->set_visibility(true))
+ new_host = true;
+
+ return ht;
+}
+
+RnaPnd::RnaPnd(const bool en, const std::string& cp, RnaConfig* rc) :
+ logger(RnaLogger(en)), filter(DiscoveryFilter(cp)), conf(rc)
+{
+ update_timeout = (rc ? rc->update_timeout : 0);
+ host_cache_mac_ptr = new HostCacheMac(MAC_CACHE_INITIAL_SIZE);
+ set_host_cache_mac(host_cache_mac_ptr);
+}
+
+RnaPnd::~RnaPnd()
+{
+ delete host_cache_mac_ptr;
+ host_cache_mac_ptr = nullptr;
+ set_host_cache_mac(nullptr);
+}
+
void RnaPnd::analyze_appid_changes(DataEvent& event)
{
RnaAppDiscovery::process(static_cast<AppidEvent*>(&event), filter, conf, logger);
const auto& src_ip = p->ptrs.ip_api.get_src();
const auto& src_ip_ptr = (const struct in6_addr*) src_ip->get_ip6_ptr();
- auto ht = host_cache.find_else_create(*src_ip, &new_host);
-
- // If it's a new host, it's automatically visible, so we don't do anything.
- // If it's not a new host, we're rediscovering it, so make it visible.
- // Also if it was not new (we had it in the cache) and it went from
- // not visible to visible, then it's as good as new.
- if (!new_host and !ht->set_visibility(true))
- new_host = true;
+ auto ht = find_or_create_host_tracker(*src_ip, new_host);
uint32_t last_seen = ht->get_last_seen();
if ( !new_host )
bool new_host = false;
bool new_mac = false;
const auto& src_ip = p->ptrs.ip_api.get_src();
- auto ht = host_cache.find_else_create(*src_ip, &new_host);
+ auto ht = find_or_create_host_tracker(*src_ip, new_host);
if (!new_host)
ht->update_last_seen();
MacKey mk(src_mac);
- auto hm_ptr = host_cache_mac.find_else_create(mk, &new_mac);
+ auto hm_ptr = local_mac_cache_ptr->find_else_create(mk, &new_mac);
if (new_mac)
{
ht->add_mac(mk.mac_addr, p->ptrs.ip_api.ttl(), 0);
SfIp router_ip = {(void*)&router, AF_INET};
bool new_host = false;
bool new_mac = false;
- auto ht = host_cache.find_else_create(leased_ip, &new_host);
+ auto ht = find_or_create_host_tracker(leased_ip, new_host);
if (!new_host)
ht->update_last_seen();
MacKey mk(src_mac);
- auto hm_ptr = host_cache_mac.find_else_create(mk, &new_mac);
+ auto hm_ptr = local_mac_cache_ptr->find_else_create(mk, &new_mac);
if (new_mac)
{
ht->add_mac(mk.mac_addr, p->ptrs.ip_api.ttl(), 0);
return;
auto hosts = host_cache.get_all_data();
- auto mac_hosts = host_cache_mac.get_all_data();
+ auto mac_hosts = local_mac_cache_ptr->get_all_data();
auto sec = time(nullptr);
for ( auto & h : hosts )
bool new_host_mac = false;
MacKey mk(layer::get_eth_layer(p)->ether_src);
- auto hm_ptr = host_cache_mac.find_else_create(mk, &new_host_mac);
+ auto hm_ptr = local_mac_cache_ptr->find_else_create(mk, &new_host_mac);
if ( new_host_mac )
{
bool new_host = false;
bool new_host_mac = false;
- auto ht = host_cache.find_else_create(spa, &new_host);
- auto hm_ptr = host_cache_mac.find_else_create(mk, &new_host_mac);
+ auto ht = find_or_create_host_tracker(spa, new_host);
+
+ auto hm_ptr = local_mac_cache_ptr->find_else_create(mk, &new_host_mac);
if ( !new_host_mac )
hm_ptr->update_last_seen(p->pkth->ts.tv_sec);
bool new_host_mac = false;
MacKey mk(layer::get_eth_layer(p)->ether_src);
- auto hm_ptr = host_cache_mac.find_else_create(mk, &new_host_mac);
+ auto hm_ptr = local_mac_cache_ptr->find_else_create(mk, &new_host_mac);
if ( new_host_mac )
{
{
public:
- RnaPnd(const bool en, const std::string& cp, RnaConfig* rc = nullptr) :
- logger(RnaLogger(en)), filter(DiscoveryFilter(cp)), conf(rc)
- { update_timeout = (rc ? rc->update_timeout : 0); }
+ RnaPnd(const bool en, const std::string& cp, RnaConfig* rc = nullptr);
+ ~RnaPnd();
void analyze_appid_changes(snort::DataEvent&);
void analyze_flow_icmp(const snort::Packet*);
// generate change event for all hosts in the ip cache
void generate_change_host_update();
+ static HostCacheIp::Data find_or_create_host_tracker(const snort::SfIp&, bool&);
+
+ HostCacheMac* host_cache_mac_ptr = nullptr;
+
private:
// generate change event for single host
void generate_change_host_update(RnaTracker*, const snort::Packet*,
time_t update_timeout;
};
+HostCacheMac* get_host_cache_mac();
+void set_host_cache_mac(HostCacheMac* mac_host);
+
#endif
add_cpputest( rna_module_test
SOURCES
../../../framework/parameter.cc
+ ../../../host_tracker/host_cache.cc
../rna_fingerprint.cc
$<TARGET_OBJECTS:catch_tests>
LIBS
#ifndef RNA_MODULE_MOCK_H
#define RNA_MODULE_MOCK_H
+#include "main/request.h"
+
#include "../rna_mac_cache.cc"
THREAD_LOCAL RnaStats rna_stats;
} // end of namespace snort
+static Request mock_request;
+void Request::respond(const char*, bool, bool) { }
+Request& get_dispatched_request() { return mock_request; }
+
+HostCacheMac* get_host_cache_mac() { return nullptr; }
+
+DataPurgeAC::~DataPurgeAC() { }
+bool DataPurgeAC::execute(Analyzer&, void**) { return true;}
+
+void snort::main_broadcast_command(AnalyzerCommand*, bool) { }
+void set_host_cache_mac(HostCacheMac*) { }
+
+
#endif