LruCacheShared(const size_t initial_size) :
max_size(initial_size), current_size(0) { }
+ virtual ~LruCacheShared() = default;
+
using Data = std::shared_ptr<Value>;
using ValueType = Value;
bool remove(const Key& key, Data& data);
const PegInfo* get_pegs() const
- {
- return lru_cache_shared_peg_names;
- }
+ { return lru_cache_shared_peg_names; }
PegCount* get_counts()
- {
- return (PegCount*)&stats;
- }
+ { return (PegCount*)&stats; }
void lock()
- {
- cache_mutex.lock();
- }
+ { cache_mutex.lock(); }
void unlock()
- {
- cache_mutex.unlock();
- }
+ { cache_mutex.unlock(); }
protected:
- using LruList = std::list<std::pair<Key, Data> >;
+ using LruList = std::list<std::pair<Key, Data>>;
using LruListIter = typename LruList::iterator;
- using LruMap = std::unordered_map<Key, LruListIter, Hash>;
+ using LruMap = std::unordered_map<Key, LruListIter, Hash>;
using LruMapIter = typename LruMap::iterator;
static constexpr size_t mem_chunk = sizeof(Data) + sizeof(Value);
// Create a Hash Table with smaller entries
GHash* t = new GHash(-10, 0, false, nullptr);
- CHECK(t != nullptr);
-
// Add Nodes to the Hash Table
for (i=0; i<num; i++)
{
assert(!athread);
LogMessage("++ [%u] %s\n", idx, analyzer->get_source());
- Swapper* ps = new Swapper(SnortConfig::get_main_conf(), HostAttributes::get_host_attributes_table());
+ Swapper* ps = new Swapper(SnortConfig::get_main_conf());
athread = new std::thread(std::ref(*analyzer), ps, ++run_num);
}
}
if ( !sc->attribute_hosts_file.empty() )
- HostAttributes::load_hosts_file(sc, sc->attribute_hosts_file.c_str());
+ {
+ if ( !HostAttributesManager::load_hosts_file(sc, sc->attribute_hosts_file.c_str()) )
+ current_request->respond("== reload failed - host attributes file failed to load\n");
+ }
- HostAttributesTable* old_tc = HostAttributes::get_host_attributes_table();
- HostAttributesTable* tc = HostAttributes::activate();
+ int32_t num_hosts = HostAttributesManager::get_num_host_entries();
+ if ( num_hosts >= 0 )
+ LogMessage( "host attribute table: %d hosts loaded\n", num_hosts);
+ else
+ LogMessage("No host attribute table loaded\n");
PluginManager::reload_so_plugins_cleanup(sc);
SnortConfig::set_conf(sc);
bool from_shell = ( L != nullptr );
current_request->respond(".. swapping configuration\n", from_shell);
- main_broadcast_command(new ACSwap(new Swapper(old, sc, old_tc, tc), current_request, from_shell), from_shell);
+ main_broadcast_command(new ACSwap(new Swapper(old, sc), current_request, from_shell), from_shell);
return 0;
}
return 0;
}
- proc_stats.attribute_table_overflow = 0;
- HostAttributes::load_hosts_file(SnortConfig::get_main_conf(), fname);
-
- HostAttributesTable* old = HostAttributes::get_host_attributes_table();
- HostAttributesTable* tc = HostAttributes::activate();
-
- if ( !tc )
+ if ( !HostAttributesManager::load_hosts_file(SnortConfig::get_main_conf(), fname) )
{
current_request->respond("== reload failed\n");
return 0;
}
proc_stats.attribute_table_reloads++;
- LogMessage(STDu64 " hosts loaded\n", proc_stats.attribute_table_hosts);
+ int32_t num_hosts = HostAttributesManager::get_num_host_entries();
+ assert( num_hosts >= 0 );
+ LogMessage( "host attribute table: %d hosts loaded\n", num_hosts);
bool from_shell = ( L != nullptr );
current_request->respond(".. swapping hosts table\n", from_shell);
- main_broadcast_command(new ACSwap(new Swapper(old, tc), current_request, from_shell), from_shell);
+ main_broadcast_command(new ACHostAttributesSwap(current_request, from_shell), from_shell);
return 0;
}
#include "pub_sub/finalize_packet_event.h"
#include "side_channel/side_channel.h"
#include "stream/stream.h"
+#include "target_based/host_attributes.h"
#include "time/packet_time.h"
#include "trace/trace_api.h"
#include "utils/stats.h"
HighAvailabilityManager::thread_init(); // must be before InspectorManager::thread_init();
InspectorManager::thread_init(sc);
PacketTracer::thread_init();
+ HostAttributesManager::initialize();
// in case there are HA messages waiting, process them first
HighAvailabilityManager::process_receive();
#include "framework/module.h"
#include "log/messages.h"
#include "managers/module_manager.h"
+#include "target_based/host_attributes.h"
#include "utils/stats.h"
#include "analyzer.h"
sc->clear_reload_resource_tuner_list();
}
delete ps;
+ HostAttributesManager::swap_cleanup();
+
Swapper::set_reload_in_progress(false);
LogMessage("== reload complete\n");
request->respond("== reload complete\n", from_shell, true);
}
+ACHostAttributesSwap::ACHostAttributesSwap(Request* req, bool from_shell)
+ : request(req), from_shell(from_shell)
+{
+ assert(Swapper::get_reload_in_progress() == false);
+ Swapper::set_reload_in_progress(true);
+}
+
+bool ACHostAttributesSwap::execute(Analyzer&, void**)
+{
+ HostAttributesManager::initialize();
+ return true;
+}
+
+ACHostAttributesSwap::~ACHostAttributesSwap()
+{
+ HostAttributesManager::swap_cleanup();
+ Swapper::set_reload_in_progress(false);
+ LogMessage("== reload host attributes complete\n");
+ request->respond("== reload host attributes complete\n", from_shell, true);
+}
+
bool ACDAQSwap::execute(Analyzer& analyzer, void**)
{
analyzer.reload_daq();
bool from_shell;
};
+class ACHostAttributesSwap : public snort::AnalyzerCommand
+{
+public:
+ ACHostAttributesSwap(Request* req, bool from_shell);
+ bool execute(Analyzer&, void**) override;
+ const char* stringify() override { return "HOST_ATTRIBUTES_SWAP"; }
+ ~ACHostAttributesSwap() override;
+
+private:
+ Request* request;
+ bool from_shell;
+};
+
class ACDAQSwap : public snort::AnalyzerCommand
{
public:
// hosts module
//-------------------------------------------------------------------------
+class HostAttributesReloadTuner : public snort::ReloadResourceTuner
+{
+public:
+ HostAttributesReloadTuner() = default;
+
+ bool tinit() override
+ {
+ HostAttributesManager::initialize();
+ return true;
+ }
+
+ bool tune_packet_context() override
+ { return true; }
+
+ bool tune_idle_context() override
+ { return true; }
+};
+
static const Parameter service_params[] =
{
{ "name", Parameter::PT_STRING, nullptr, nullptr,
{
public:
HostsModule() : Module("hosts", hosts_help, hosts_params, true)
- { app = nullptr; host = nullptr; }
- ~HostsModule() override { assert(!host && !app); }
+ { host = nullptr; }
+
+ ~HostsModule() override
+ { assert(!host); }
bool set(const char*, Value&, SnortConfig*) override;
bool begin(const char*, int, SnortConfig*) override;
bool end(const char*, int, SnortConfig*) override;
+ const PegInfo* get_pegs() const override
+ { return HostAttributesManager::get_pegs(); }
+
+ PegCount* get_counts() const override
+ { return HostAttributesManager::get_peg_counts(); }
+
Usage get_usage() const override
{ return GLOBAL; }
private:
- ApplicationEntry* app;
- HostAttributeEntry* host;
+ HostServiceDescriptor service;
+ HostAttributesEntry host;
+ HostAttributesReloadTuner hart;
};
bool HostsModule::set(const char*, Value& v, SnortConfig* sc)
{
if ( host and v.is("ip") )
- v.get_addr(host->ipAddr);
+ {
+ SfIp addr;
+ v.get_addr(addr);
+ host->set_ip_addr(addr);
+ }
else if ( host and v.is("frag_policy") )
- host->hostInfo.fragPolicy = v.get_uint8() + 1;
+ host->set_frag_policy(v.get_uint8() + 1);
else if ( host and v.is("tcp_policy") )
- host->hostInfo.streamPolicy = v.get_uint8();
+ host->set_stream_policy(v.get_uint8());
- else if ( app and v.is("name") )
- app->snort_protocol_id = sc->proto_ref->add(v.get_string());
+ else if ( v.is("name") )
+ service.snort_protocol_id = sc->proto_ref->add(v.get_string());
- else if ( app and v.is("proto") )
- app->ipproto = sc->proto_ref->add(v.get_string());
+ else if ( v.is("proto") )
+ service.ipproto = sc->proto_ref->add(v.get_string());
- else if ( app and v.is("port") )
- app->port = v.get_uint16();
+ else if ( v.is("port") )
+ service.port = v.get_uint16();
else
return false;
bool HostsModule::begin(const char* fqn, int idx, SnortConfig*)
{
if ( idx && !strcmp(fqn, "hosts.services") )
- app = new ApplicationEntry;
+ service.reset();
else if ( idx && !strcmp(fqn, "hosts") )
- host = new HostAttributeEntry;
+ host.reset(new HostAttributesDescriptor);
return true;
}
{
if ( idx && !strcmp(fqn, "hosts.services") )
{
- host->add_service(app);
- app = nullptr;
+ bool updated = false;
+ host->update_service(service.port, service.ipproto, service.snort_protocol_id, updated);
+ service.reset();
}
else if ( idx && !strcmp(fqn, "hosts") )
{
- if ( !HostAttributes::add_host(host, sc) )
- delete host;
+ if ( !HostAttributesManager::add_host(host, sc) )
+ host.reset();
host = nullptr;
}
+ else if ( !idx && !strcmp(fqn, "hosts"))
+ {
+ if ( HostAttributesManager::activate() )
+ {
+ if ( Snort::is_reloading() )
+ sc->register_reload_resource_tuner(hart);
+ }
+ }
return true;
}
sc->setup();
if ( !sc->attribute_hosts_file.empty() )
- HostAttributes::load_hosts_file(sc, sc->attribute_hosts_file.c_str());
+ {
+ if ( !HostAttributesManager::load_hosts_file(sc, sc->attribute_hosts_file.c_str()) )
+ ParseError("host attributes file failed to load\n");
+ }
// Must be after CodecManager::instantiate()
if ( !InspectorManager::configure(sc) )
if ((offload_search_api != nullptr) and (offload_search_api != search_api))
MpseManager::activate_search_engine(offload_search_api, sc);
- HostAttributes::activate();
-
#ifdef PIGLET
if ( !Piglet::piglet_mode() )
#endif
term_signals();
IpsManager::global_term(sc);
- HostAttributes::cleanup();
+ HostAttributesManager::term();
#ifdef PIGLET
if ( !Piglet::piglet_mode() )
#include "swapper.h"
-#include "target_based/host_attributes.h"
-
#include "analyzer.h"
#include "snort.h"
#include "snort_config.h"
bool Swapper::reload_in_progress = false;
-Swapper::Swapper(SnortConfig* s, HostAttributesTable* t)
+Swapper::Swapper(SnortConfig* s)
{
old_conf = nullptr;
new_conf = s;
-
- old_attribs = nullptr;
- new_attribs = t;
}
Swapper::Swapper(const SnortConfig* sold, SnortConfig* snew)
{
old_conf = sold;
new_conf = snew;
-
- old_attribs = nullptr;
- new_attribs = nullptr;
-}
-
-Swapper::Swapper(
- const SnortConfig* sold, SnortConfig* snew,
- HostAttributesTable* told, HostAttributesTable* tnew)
-{
- old_conf = sold;
- new_conf = snew;
-
- old_attribs = told;
- new_attribs = tnew;
}
-Swapper::Swapper(HostAttributesTable* told, HostAttributesTable* tnew)
+Swapper::Swapper()
{
old_conf = nullptr;
new_conf = nullptr;
-
- old_attribs = told;
- new_attribs = tnew;
}
Swapper::~Swapper()
{
if ( old_conf )
delete old_conf;
-
- if ( old_attribs )
- delete old_attribs;
}
void Swapper::apply(Analyzer& analyzer)
if ( reload )
analyzer.reinit(new_conf);
}
-
- if ( new_attribs )
- HostAttributes::set_host_attributes_table(new_attribs);
}
}
class Analyzer;
-struct HostAttributesTable;
class Swapper
{
public:
- Swapper(snort::SnortConfig*, HostAttributesTable*);
+ Swapper(snort::SnortConfig*);
Swapper(const snort::SnortConfig* sold, snort::SnortConfig* snew);
-
- Swapper(const snort::SnortConfig* sold, snort::SnortConfig* snew,
- HostAttributesTable*, HostAttributesTable*);
-
- Swapper(HostAttributesTable*, HostAttributesTable*);
+ Swapper();
~Swapper();
void apply(Analyzer&);
const snort::SnortConfig* old_conf;
snort::SnortConfig* new_conf;
- HostAttributesTable* old_attribs;
- HostAttributesTable* new_attribs;
-
static bool reload_in_progress;
};
#include "protocols/packet_manager.h"
#include "side_channel/side_channel.h"
#include "stream/stream.h"
+#include "target_based/host_attributes.h"
#include "time/packet_time.h"
#include "trace/trace_api.h"
#include "utils/dnet_header.h"
eth_t* eth_open(const char*) { return nullptr; }
eth_t* eth_close(eth_t*) { return nullptr; }
ssize_t eth_send(eth_t*, const void*, size_t) { return -1; }
+void HostAttributesManager::initialize() { }
namespace snort
{
if (tmp_snort_protocol_id != snort_protocol_id)
{
snort_protocol_id = tmp_snort_protocol_id;
- p->flow->ssn_state.snort_protocol_id = tmp_snort_protocol_id;
+ Stream::set_snort_protocol_id(p->flow, tmp_snort_protocol_id);
}
}
flow->clouseau = nullptr;
}
-static void set_service(Flow* flow, const HostAttributeEntry* host)
+static void set_service(Flow* flow, const HostAttributesEntry host)
{
Stream::set_snort_protocol_id(flow, host, FROM_SERVER);
}
bool update(Binding*);
bool apply_action(Flow*);
- void apply_session(Flow*, const HostAttributeEntry*);
- void apply_service(Flow*, const HostAttributeEntry*);
+ void apply_session(Flow*, const HostAttributesEntry);
+ void apply_service(Flow*, const HostAttributesEntry);
void apply_assistant(Flow*, const char*);
};
return true;
}
-void Stuff::apply_session(Flow* flow, const HostAttributeEntry* host)
+void Stuff::apply_session(Flow* flow, const HostAttributesEntry host)
{
if ( server )
{
{
case PktType::IP:
set_session(flow, INS_IP);
- flow->ssn_policy = host ? host->hostInfo.fragPolicy : 0;
+ flow->ssn_policy = host ? host->get_frag_policy() : 0;
break;
case PktType::ICMP:
case PktType::TCP:
set_session(flow, INS_TCP);
- flow->ssn_policy = host ? host->hostInfo.streamPolicy : 0;
+ flow->ssn_policy = host ? host->get_stream_policy() : 0;
break;
case PktType::UDP:
}
}
-void Stuff::apply_service(Flow* flow, const HostAttributeEntry* host)
+void Stuff::apply_service(Flow* flow, const HostAttributesEntry host)
{
if ( data )
flow->set_data(data);
if ( !stuff.apply_action(flow) )
return;
- const HostAttributeEntry* host = HostAttributes::find_host(&flow->server_ip);
+ const HostAttributesEntry host = HostAttributesManager::find_host(flow->server_ip);
// setup session
stuff.apply_session(flow, host);
}
void Stream::set_snort_protocol_id(
- Flow* flow, const HostAttributeEntry* host_entry, int /*direction*/)
+ Flow* flow, const HostAttributesEntry& host, int /*direction*/)
{
SnortProtocolId snort_protocol_id;
- if (!flow || !host_entry)
+ if (!flow )
return;
/* Cool, its already set! */
set_ip_protocol(flow);
}
- snort_protocol_id = host_entry->get_snort_protocol_id
+ snort_protocol_id = host->get_snort_protocol_id
(flow->ssn_state.ipprotocol, flow->server_port);
#if 0
return flow->ssn_state.snort_protocol_id;
if (flow->ssn_state.ipprotocol == 0)
- {
set_ip_protocol(flow);
- }
- if ( HostAttributeEntry* host_entry = HostAttributes::find_host(&flow->server_ip) )
+ if ( HostAttributesEntry host = HostAttributesManager::find_host(flow->server_ip) )
{
- set_snort_protocol_id(flow, host_entry, FROM_SERVER);
+ set_snort_protocol_id(flow, host, FROM_SERVER);
if (flow->ssn_state.snort_protocol_id != UNKNOWN_PROTOCOL_ID)
return flow->ssn_state.snort_protocol_id;
}
- if ( HostAttributeEntry* host_entry = HostAttributes::find_host(&flow->client_ip) )
+ if ( HostAttributesEntry host = HostAttributesManager::find_host(flow->client_ip) )
{
- set_snort_protocol_id(flow, host_entry, FROM_CLIENT);
+ set_snort_protocol_id(flow, host, FROM_CLIENT);
if (flow->ssn_state.snort_protocol_id != UNKNOWN_PROTOCOL_ID)
return flow->ssn_state.snort_protocol_id;
if ( !flow->is_proxied() )
{
- HostAttributes::update_service
- (&flow->server_ip, flow->server_port, flow->ssn_state.ipprotocol, id);
+ HostAttributesManager::update_service
+ (flow->server_ip, flow->server_port, flow->ssn_state.ipprotocol, id);
}
+
return id;
}
// provides a common flow management interface
+#include <memory>
+
#include "flow/flow.h"
-struct HostAttributeEntry;
+class HostAttributesDescriptor;
+typedef std::shared_ptr<HostAttributesDescriptor> HostAttributesEntry;
namespace snort
{
static void populate_flow_key(Packet*, FlowKey*);
static void set_snort_protocol_id(
- Flow*, const HostAttributeEntry*, int direction);
+ Flow*, const HostAttributesEntry&, int direction);
static bool is_midstream(Flow* flow)
{ return ((flow->ssn_state.session_flags & SSNFLAG_MIDSTREAM) != 0); }
{
TcpStreamTracker* listener = tsd.get_listener();
- pkt_action_mask |= listener->normalizer.handle_paws(tsd);
-
if ( tsd.is_policy_inline() )
if ( tsd.get_tcph()->is_ack() && !listener->is_ack_valid(tsd.get_ack()) )
pkt_action_mask |= ACTION_BAD_PKT;
+ if ( !tsd.is_meta_ack_packet() )
+ pkt_action_mask |= listener->normalizer.handle_paws(tsd);
+
return ( pkt_action_mask & ACTION_BAD_PKT ) ? false : true;
}
WHEN("SYN is sent")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
client_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_SENT_EVENT);
tsh->eval(*tsd, *client_tracker);
THEN("Event should be TCP_SYN_SENT_EVENT")
SECTION("SYN is received")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
server_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_RECV_EVENT);
tsh->eval(*tsd, *server_tracker);
CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
SECTION("syn_ack_sent")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
client_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT);
tsh->eval(*tsd, *client_tracker);
CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
SECTION("syn_ack_recv")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
server_tracker->set_tcp_event(TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT);
tsh->eval(*tsd, *server_tracker);
CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
SECTION("ack_sent")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
client_tracker->set_tcp_event(TcpStreamTracker::TCP_ACK_SENT_EVENT);
tsh->eval(*tsd, *client_tracker);
CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
SECTION("ack_recv")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
server_tracker->set_tcp_event(TcpStreamTracker::TCP_ACK_RECV_EVENT);
tsh->eval(*tsd, *server_tracker);
CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
SECTION("data_seg_sent")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
client_tracker->set_tcp_event(TcpStreamTracker::TCP_DATA_SEG_SENT_EVENT);
tsh->eval(*tsd, *client_tracker);
CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
SECTION("data_seg_recv")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
server_tracker->set_tcp_event(TcpStreamTracker::TCP_DATA_SEG_RECV_EVENT);
tsh->eval(*tsd, *server_tracker);
CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
SECTION("fin_sent")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
client_tracker->set_tcp_event(TcpStreamTracker::TCP_FIN_SENT_EVENT);
tsh->eval(*tsd, *client_tracker);
CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
SECTION("fin_recv")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
server_tracker->set_tcp_event(TcpStreamTracker::TCP_FIN_RECV_EVENT);
tsh->eval(*tsd, *server_tracker);
CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
SECTION("rst_sent")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
client_tracker->set_tcp_event(TcpStreamTracker::TCP_RST_SENT_EVENT);
tsh->eval(*tsd, *client_tracker);
CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
SECTION("rst_recv")
{
TcpSegmentDescriptor* tsd = new TcpSegmentDescriptor(flow, pkt, tel);
- REQUIRE( ( tsd != nullptr ) );
server_tracker->set_tcp_event(TcpStreamTracker::TCP_RST_RECV_EVENT);
tsh->eval(*tsd, *server_tracker);
CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// host_attributes.cc Author: davis mcpherson
+// host_attributes.cc author davis mcpherson <davmcphe@cisco.com>
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "host_attributes.h"
-#include "log/messages.h"
+#include "hash/lru_cache_shared.h"
#include "main/shell.h"
#include "main/snort_config.h"
-#include "protocols/packet.h"
-#include "sfrt/sfrt.h"
-#include "utils/stats.h"
-#include "utils/util.h"
+#include "main/thread.h"
using namespace snort;
-static THREAD_LOCAL HostAttributesTable* curr_cfg = nullptr;
-static HostAttributesTable* next_cfg = nullptr;
-
-void HostAttributesTable::free_host_entry(void* host)
-{ delete (HostAttributeEntry*)host; }
-
-HostAttributesTable::HostAttributesTable(uint32_t max_hosts)
- : max_hosts(max_hosts)
+static const PegInfo host_attribute_pegs[] =
{
- // Add 1 to max for table purposes
- // We use max_hosts to limit memcap, assume 16k per entry costs
- // FIXIT-M 16k per host is no longer true
- host_table = sfrt_new(DIR_8x16, IPv6, max_hosts + 1, (max_hosts >> 6) + 1);
-}
-
-HostAttributesTable::~HostAttributesTable()
+ { CountType::MAX, "total_hosts", "maximum number of entries in the host attribute table" },
+ { CountType::SUM, "hosts_pruned", "number of LRU hosts pruned due to configured resource limits" },
+ { CountType::SUM, "dynamic_host_adds", "number of host additions after initial host file load" },
+ { CountType::SUM, "dynamic_service_adds", "number of service additions after initial host file load" },
+ { CountType::SUM, "dynamic_service_updates", "number of service updates after initial host file load" },
+ { CountType::SUM, "service_list_overflows", "number of service additions that failed due to configured resource limits" },
+ { CountType::END, nullptr, nullptr }
+};
+
+template<typename Key, typename Value, typename Hash>
+class HostLruSharedCache : public LruCacheShared<Key, Value, Hash>
{
- sfrt_cleanup(host_table, HostAttributesTable::free_host_entry);
- sfrt_free(host_table);
-}
+public:
+ HostLruSharedCache(const size_t initial_size) : LruCacheShared<Key, Value, Hash>(initial_size)
+ { }
+};
-bool HostAttributesTable::add_host(HostAttributeEntry* host)
-{
- SfCidr* ipAddr = &host->ipAddr;
- int ret = sfrt_insert(ipAddr, (unsigned char)ipAddr->get_bits(), host,
- RT_FAVOR_SPECIFIC, host_table);
+typedef HostLruSharedCache<snort::SfIp, HostAttributesDescriptor, HostAttributesCacheKey> HostAttributesSharedCache;
- if ( ret == RT_SUCCESS )
- {
- ++num_hosts;
- return true;
- }
+static THREAD_LOCAL HostAttributesSharedCache* active_cache = nullptr;
+static HostAttributesSharedCache* swap_cache = nullptr;
+static HostAttributesSharedCache* next_cache = nullptr;
+static HostAttributesSharedCache* old_cache = nullptr;
+static THREAD_LOCAL HostAttributeStats host_attribute_stats;
+
+bool HostAttributesDescriptor::update_service
+ (uint16_t port, uint16_t protocol, SnortProtocolId snort_protocol_id, bool& updated)
+{
+ std::lock_guard<std::mutex> lck(host_attributes_lock);
- if ( ret == RT_POLICY_TABLE_EXCEEDED )
+ for ( auto& s : services)
{
- if ( !sfat_insufficient_space_logged )
+ if ( s.ipproto == protocol && (uint16_t)s.port == port )
{
- ParseWarning(WARN_HOSTS, "Attribute table insertion failed: %d Insufficient "
- "space in attribute table, only configured to store %u hosts\n",
- ret, max_hosts);
- sfat_insufficient_space_logged = true;
+ s.snort_protocol_id = snort_protocol_id;
+ updated = true;
+ return true;
}
-
- proc_stats.attribute_table_overflow++;
}
- else if ( !sfat_grammar_error_printed )
+
+ // service not found, add it
+ if ( services.size() < SnortConfig::get_conf()->get_max_services_per_host() )
{
- ParseWarning(WARN_HOSTS, "Attribute table insertion failed: %d '%s'\n",
- ret, rt_error_messages[ret]);
- sfat_grammar_error_printed = true;
+ updated = false;
+ services.emplace_back(HostServiceDescriptor(port, protocol, snort_protocol_id));
+ return true;
}
return false;
}
-HostAttributeEntry* HostAttributesTable::get_host(SfIp* ipAddr)
+SnortProtocolId HostAttributesDescriptor::get_snort_protocol_id(int ipprotocol, uint16_t port) const
{
- HostAttributeEntry* host = (HostAttributeEntry*)sfrt_lookup(ipAddr, host_table);
- if ( !host && !is_host_attribute_table_full() )
+ std::lock_guard<std::mutex> lck(host_attributes_lock);
+
+ for ( auto& s : services )
{
- host = new HostAttributeEntry;
- host->ipAddr.set(*ipAddr);
- if ( !curr_cfg->add_host(host) )
- {
- delete host;
- host = nullptr;
- }
+ if ( (s.ipproto == ipprotocol) && (s.port == port) )
+ return s.snort_protocol_id;
}
- return host;
-}
-
-HostAttributeEntry* HostAttributesTable::find_host(const SfIp* ipAddr)
-{ return (HostAttributeEntry*)sfrt_lookup(ipAddr, host_table); }
-
-HostAttributeEntry::~HostAttributeEntry()
-{
- for ( auto app : services )
- delete app;
+ return UNKNOWN_PROTOCOL_ID;
}
-void HostAttributeEntry::add_service(ApplicationEntry* app)
-{ services.push_back(app); }
-
-void HostAttributeEntry::update_service
- (HostAttributeEntry* host, uint16_t port, uint16_t protocol, SnortProtocolId snort_protocol_id)
+bool HostAttributesManager::load_hosts_file(snort::SnortConfig* sc, const char* fname)
{
- unsigned service_count = 0;
-
- for ( auto app : services)
- {
- if ( app->ipproto == protocol && (uint16_t)app->port == port )
- {
- app->snort_protocol_id = snort_protocol_id;
- return;
- }
-
- service_count++;
- }
+ delete next_cache;
+ next_cache = new HostAttributesSharedCache(sc->max_attribute_hosts);
- // application service not found, add it
- if ( service_count >= SnortConfig::get_conf()->get_max_services_per_host() )
- return;
+ Shell sh(fname);
+ if ( sh.configure(sc, false, true) )
+ return true;
- ApplicationEntry* app = new ApplicationEntry(port, protocol, snort_protocol_id);
- host->add_service(app);
+ // loading of host file failed...
+ delete next_cache;
+ next_cache = nullptr;
+ return false;
}
-SnortProtocolId HostAttributeEntry::get_snort_protocol_id(int ipprotocol, uint16_t port) const
+bool HostAttributesManager::add_host(HostAttributesEntry host, snort::SnortConfig* sc)
{
- for ( auto app : services )
- {
- if ( (app->ipproto == ipprotocol) && (app->port == port) )
- return app->snort_protocol_id;
- }
+ if ( !next_cache )
+ next_cache = new HostAttributesSharedCache(sc->max_attribute_hosts);
- return 0;
+ return next_cache->find_else_insert(host->get_ip_addr(), host, true);
}
-void HostAttributes::load_hosts_file(SnortConfig* sc, const char* fname)
+bool HostAttributesManager::activate()
{
- delete next_cfg;
- next_cfg = new HostAttributesTable(sc->max_attribute_hosts);
-
- Shell sh(fname);
+ old_cache = active_cache;
+ active_cache = next_cache;
+ swap_cache = next_cache;
+ next_cache = nullptr;
- if ( !sh.configure(sc, false, true) )
- {
- delete next_cfg;
- next_cfg = nullptr;
- }
+ return ( active_cache != old_cache ) ? true : false;
}
-HostAttributesTable* HostAttributes::activate()
-{
- curr_cfg = next_cfg;
- next_cfg = nullptr;
+void HostAttributesManager::initialize()
+{ active_cache = swap_cache; }
- if ( curr_cfg )
- proc_stats.attribute_table_hosts = curr_cfg->get_num_hosts();
- else
- proc_stats.attribute_table_hosts = 0;
+void HostAttributesManager::swap_cleanup()
+{ delete old_cache; }
- return curr_cfg;
-}
+void HostAttributesManager::term()
+{ delete active_cache; }
-void HostAttributes::set_host_attributes_table(HostAttributesTable* p)
-{ curr_cfg = p; }
+HostAttributesEntry HostAttributesManager::find_host(const snort::SfIp& host_ip)
+{
+ if ( active_cache )
+ return active_cache->find(host_ip);
-HostAttributesTable* HostAttributes::get_host_attributes_table()
-{ return curr_cfg; }
+ return nullptr;
+}
-bool HostAttributes::add_host(HostAttributeEntry* host, snort::SnortConfig* sc)
+void HostAttributesManager::update_service(const snort::SfIp& host_ip, uint16_t port, uint16_t protocol, SnortProtocolId snort_protocol_id)
{
- if ( !next_cfg )
- next_cfg = new HostAttributesTable(sc->max_attribute_hosts);
-
- return next_cfg->add_host(host);
+ if ( active_cache )
+ {
+ bool created = false;
+ HostAttributesEntry host = active_cache->find_else_create(host_ip, &created);
+ if ( host )
+ {
+ if ( created )
+ {
+ host->set_ip_addr(host_ip);
+ host_attribute_stats.dynamic_host_adds++;
+ }
+
+ bool updated = false;
+ if ( host->update_service(port, protocol, snort_protocol_id, updated) )
+ {
+ if ( updated )
+ host_attribute_stats.dynamic_service_updates++;
+ else
+ host_attribute_stats.dynamic_service_adds++;
+ }
+ else
+ host_attribute_stats.service_list_overflows++;
+ }
+ }
}
-HostAttributeEntry* HostAttributes::find_host(const SfIp* ipAddr)
+int32_t HostAttributesManager::get_num_host_entries()
{
- if ( !curr_cfg )
- return nullptr;
+ if ( active_cache )
+ return active_cache->size();
- return curr_cfg->find_host(ipAddr);
+ return -1;
}
-void HostAttributes::update_service(SfIp* ipAddr, uint16_t port, uint16_t protocol, SnortProtocolId snort_protocol_id)
+const PegInfo* HostAttributesManager::get_pegs()
+{ return (const PegInfo*)&host_attribute_pegs; }
+
+PegCount* HostAttributesManager::get_peg_counts()
{
- if ( curr_cfg )
+ if ( active_cache )
{
- HostAttributeEntry* host = curr_cfg->get_host(ipAddr);
- if ( host )
- host->update_service(host, port, protocol, snort_protocol_id);
+ LruCacheSharedStats* cache_stats = (LruCacheSharedStats*) active_cache->get_counts();
+ host_attribute_stats.hosts_pruned = cache_stats->alloc_prunes;
+ host_attribute_stats.total_hosts = active_cache->size();
}
+
+ return (PegCount*)&host_attribute_stats;
}
-void HostAttributes::cleanup()
-{ delete curr_cfg; }
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// host_attributes.h author davis mcpherson
+// host_attributes.h author davis mcpherson <davmcphe@cisco.com>
#ifndef HOST_ATTRIBUTES_H
#define HOST_ATTRIBUTES_H
// Provides attribute table initialization, lookup, swap, and releasing.
+#include <functional>
+#include <memory>
+#include <mutex>
#include <vector>
-#include "sfip/sf_cidr.h"
-#include "sfrt/sfrt.h"
+#include "framework/counts.h"
+#include "sfip/sf_ip.h"
#include "target_based/snort_protocols.h"
-struct ApplicationEntry
+namespace snort
+{
+struct SnortConfig;
+}
+
+struct HostAttributeStats
+{
+ PegCount total_hosts = 0;
+ PegCount hosts_pruned = 0;
+ PegCount dynamic_host_adds = 0;
+ PegCount dynamic_service_adds = 0;
+ PegCount dynamic_service_updates = 0;
+ PegCount service_list_overflows = 0;
+};
+
+class HostServiceDescriptor
{
- ApplicationEntry() = default;
- ApplicationEntry(uint16_t port, uint16_t protocol, SnortProtocolId spi)
+public:
+ HostServiceDescriptor() = default;
+ HostServiceDescriptor(uint16_t port, uint16_t protocol, SnortProtocolId spi)
: port(port), ipproto(protocol), snort_protocol_id(spi)
{ }
- ~ApplicationEntry() = default;
+
+ ~HostServiceDescriptor() = default;
+
+ void reset()
+ {
+ port = 0;
+ ipproto = 0;
+ snort_protocol_id = UNKNOWN_PROTOCOL_ID;
+ }
uint16_t port = 0;
uint16_t ipproto = 0;
- SnortProtocolId snort_protocol_id = 0;
+ SnortProtocolId snort_protocol_id = UNKNOWN_PROTOCOL_ID;
};
-struct HostInfo
+struct HostPolicyDescriptor
{
uint8_t streamPolicy = 0;
uint8_t fragPolicy = 0;
};
-struct HostAttributeEntry
+class HostAttributesDescriptor
{
- HostAttributeEntry() = default;
- ~HostAttributeEntry();
+public:
+ HostAttributesDescriptor() = default;
+ ~HostAttributesDescriptor() = default;
- void add_service(ApplicationEntry*);
- void update_service(HostAttributeEntry*, uint16_t port, uint16_t protocol, SnortProtocolId);
+ bool update_service(uint16_t port, uint16_t protocol, SnortProtocolId, bool& updated);
SnortProtocolId get_snort_protocol_id(int ipprotocol, uint16_t port) const;
- snort::SfCidr ipAddr;
- HostInfo hostInfo;
- std::vector<ApplicationEntry*> services;
-};
-
-#define DEFAULT_MAX_ATTRIBUTE_HOSTS 10000
-#define DEFAULT_MAX_ATTRIBUTE_SERVICES_PER_HOST 100
-#define DEFAULT_MAX_METADATA_SERVICES 9
+ const snort::SfIp& get_ip_addr() const
+ { return ip_address; }
-namespace snort
-{
-struct SfIp;
-struct SnortConfig;
-}
+ void set_ip_addr(const snort::SfIp& host_ip_addr)
+ {
+ std::lock_guard<std::mutex> lck(host_attributes_lock);
+ ip_address = host_ip_addr;
+ }
-struct HostAttributesTable
-{
- HostAttributesTable(uint32_t max_hosts);
- ~HostAttributesTable();
+ uint8_t get_frag_policy() const
+ { return policies.fragPolicy; }
- bool add_host(HostAttributeEntry*);
- HostAttributeEntry* get_host(snort::SfIp*);
- HostAttributeEntry* find_host(const snort::SfIp*);
- void add_service(HostAttributeEntry*, ApplicationEntry*);
+ void set_frag_policy(const uint8_t frag_policy)
+ {
+ std::lock_guard<std::mutex> lck(host_attributes_lock);
+ policies.fragPolicy = frag_policy;
+ }
- bool is_host_attribute_table_full()
- { return num_hosts >= max_hosts; }
+ uint8_t get_stream_policy() const
+ { return policies.streamPolicy; }
- uint32_t get_num_hosts () const
- { return num_hosts; }
+ void set_stream_policy(uint8_t stream_policy)
+ {
+ std::lock_guard<std::mutex> lck(host_attributes_lock);
+ policies.streamPolicy = stream_policy;
+ }
private:
- table_t* host_table;
- uint32_t max_hosts;
- uint32_t num_hosts = 0;
+ mutable std::mutex host_attributes_lock; // ensure updates to this shared object are safe
+ snort::SfIp ip_address;
+ HostPolicyDescriptor policies;
+ std::vector<HostServiceDescriptor> services;
+};
- bool sfat_grammar_error_printed = false;
- bool sfat_insufficient_space_logged = false;
+typedef std::shared_ptr<HostAttributesDescriptor> HostAttributesEntry;
- static void free_host_entry(void* host);
+#define DEFAULT_MAX_ATTRIBUTE_HOSTS 10000
+#define DEFAULT_MAX_ATTRIBUTE_SERVICES_PER_HOST 100
+#define DEFAULT_MAX_METADATA_SERVICES 9
+
+// Create a hash key from an IP address stored in a SfIp object.
+struct HostAttributesCacheKey
+{
+ size_t operator()(const snort::SfIp& ip) const
+ {
+ const uint64_t* ip64 = (const uint64_t*) ip.get_ip6_ptr();
+ return std::hash<uint64_t>() (ip64[0]) ^
+ std::hash<uint64_t>() (ip64[1]);
+ }
};
-class HostAttributes
+class HostAttributesManager
{
public:
- static void load_hosts_file(snort::SnortConfig*, const char* fname);
- static HostAttributesTable* activate();
- static HostAttributesTable* get_host_attributes_table();
- static void set_host_attributes_table(HostAttributesTable*);
- static bool add_host(HostAttributeEntry*, snort::SnortConfig*);
- static HostAttributeEntry* find_host(const snort::SfIp* ipAddr);
- static void update_service(snort::SfIp*, uint16_t port, uint16_t protocol, uint16_t id);
- static void cleanup();
+ static bool load_hosts_file(snort::SnortConfig*, const char* fname);
+ static bool activate();
+ static void initialize();
+ static void swap_cleanup();
+ static void term();
+
+ static bool add_host(HostAttributesEntry, snort::SnortConfig*);
+ static HostAttributesEntry find_host(const snort::SfIp&);
+ static void update_service(const snort::SfIp&, uint16_t port, uint16_t protocol, SnortProtocolId);
+ static int32_t get_num_host_entries();
+ static const PegInfo* get_pegs();
+ static PegCount* get_peg_counts();
};
-
#endif
-
using namespace std;
SnortProtocolId ProtocolReference::get_count()
-{
- return protocol_number;
-}
+{ return protocol_number; }
const char* ProtocolReference::get_name(SnortProtocolId id)
{
SnortProtocolId ProtocolReference::add(const char* protocol)
{
- if (!protocol)
+ if ( !protocol )
return UNKNOWN_PROTOCOL_ID;
auto protocol_ref = ref_table.find(protocol);
if ( protocol_ref != ref_table.end() )
- {
return protocol_ref->second;
- }
SnortProtocolId snort_protocol_id = protocol_number++;
id_map.emplace_back(protocol);
{
auto protocol_ref = ref_table.find(protocol);
if ( protocol_ref != ref_table.end() )
- {
return protocol_ref->second;
- }
return UNKNOWN_PROTOCOL_ID;
}
void ProtocolReference::init(ProtocolReference* old_proto_ref)
{
- if(!old_proto_ref)
+ if ( !old_proto_ref )
{
bool ok = ( add("unknown") == UNKNOWN_PROTOCOL_ID );
ok = ( add("ip") == SNORT_PROTO_IP ) and ok;
}
else
{
- // Copy old ProtocolReference ID/name pairs to new ProtocolReference
for(SnortProtocolId id = 0; id < old_proto_ref->get_count(); id++)
- {
add(old_proto_ref->get_name(id));
- }
}
}
ProtocolReference::ProtocolReference()
-{
- init(nullptr);
-}
+{ init(nullptr); }
ProtocolReference::ProtocolReference(ProtocolReference* old_proto_ref)
-{
- init(old_proto_ref);
-}
+{ init(old_proto_ref); }
ProtocolReference::~ProtocolReference()
-{
- ref_table.clear();
-}
+{ ref_table.clear(); }
{ CountType::SUM, "inspector_deletions", "number of times inspectors were deleted" },
{ CountType::SUM, "daq_reloads", "number of times daq configuration was reloaded" },
{ CountType::SUM, "attribute_table_reloads", "number of times hosts attribute table was reloaded" },
- { CountType::SUM, "attribute_table_hosts", "number of hosts added to the attribute table" },
- { CountType::SUM, "attribute_table_overflow", "number of host additions that failed due to attribute table full" },
{ CountType::END, nullptr, nullptr }
};
LogLabel("Summary Statistics");
show_stats((PegCount*)&proc_stats, proc_names, array_size(proc_names)-1, "process");
-
}
//-------------------------------------------------------------------------
PegCount inspector_deletions;
PegCount daq_reloads;
PegCount attribute_table_reloads;
- PegCount attribute_table_hosts;
- PegCount attribute_table_overflow;
};
extern ProcessCount proc_stats;