last_seen = (uint32_t) packet_time();
}
+void HostTracker::update_last_event(uint32_t time)
+{
+ std::lock_guard<std::mutex> lck(host_tracker_lock);
+ last_event = time ? time : last_seen;
+}
+
bool HostTracker::add_mac(const u_int8_t* mac, u_int8_t ttl, u_int8_t primary)
{
if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
{
public:
HostTracker() : hops(-1)
- { last_seen = (uint32_t) packet_time(); }
+ {
+ last_seen = (uint32_t) packet_time();
+ last_event = -1;
+ }
void update_last_seen();
+ uint32_t get_last_seen() const
+ {
+ std::lock_guard<std::mutex> lck(host_tracker_lock);
+ return last_seen;
+ }
+
+ void update_last_event(uint32_t time = 0);
+ uint32_t get_last_event() const
+ {
+ std::lock_guard<std::mutex> lck(host_tracker_lock);
+ return last_event;
+ }
// Returns true if a new mac entry is added, false otherwise
bool add_mac(const u_int8_t* mac, u_int8_t ttl, u_int8_t primary);
void stringify(std::string& str);
private:
- std::mutex host_tracker_lock; // ensure that updates to a shared object are safe
+ mutable std::mutex host_tracker_lock; // ensure that updates to a shared object are safe
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;
std::vector<HostApplication, HostAppAllocator> services;
std::string fingerprint_dir;
std::string custom_fingerprint_dir;
bool enable_logger;
+ bool log_when_idle;
};
// Give default values so that RNA can work even if rna_conf_path is not provided
uint16_t max_host_services = 100;
uint16_t max_host_service_info = 16;
bool enable_banner_grab = 0;
+ bool log_when_idle = 0;
};
#endif
-
++rna_stats.udp_new;
pnd.analyze_flow_udp(event.get_packet());
}
+
+void RnaIdleEventHandler::handle(DataEvent& event, Flow*)
+{
+ UNUSED(event);
+ Profile profile(rna_perf_stats);
+ ++rna_stats.change_host_update;
+ pnd.generate_change_host_update();
+}
RnaPnd& pnd;
};
+class RnaIdleEventHandler : public snort::DataHandler
+{
+public:
+ RnaIdleEventHandler(RnaPnd& nd) : DataHandler(RNA_NAME), pnd(nd) { }
+ void handle(snort::DataEvent&, snort::Flow*) override;
+private:
+ RnaPnd& pnd;
+};
+
#endif
{
mod_conf = mod->get_config();
load_rna_conf();
+ time_t update_timeout = rna_conf ? rna_conf->update_timeout : 0;
if ( mod_conf )
- pnd = new RnaPnd(mod_conf->enable_logger, mod_conf->rna_conf_path);
+ pnd = new RnaPnd(mod_conf->enable_logger, mod_conf->rna_conf_path, update_timeout);
else
- pnd = new RnaPnd(false, "");
+ pnd = new RnaPnd(false, "", update_timeout);
}
RnaInspector::~RnaInspector()
DataBus::subscribe( STREAM_TCP_SYN_EVENT, new RnaTcpSynEventHandler(*pnd) );
DataBus::subscribe( STREAM_TCP_SYN_ACK_EVENT, new RnaTcpSynAckEventHandler(*pnd) );
DataBus::subscribe( STREAM_TCP_MIDSTREAM_EVENT, new RnaTcpMidstreamEventHandler(*pnd) );
+ if (rna_conf && rna_conf->log_when_idle)
+ DataBus::subscribe( THREAD_IDLE_EVENT, new RnaIdleEventHandler(*pnd) );
return true;
}
#include "managers/event_manager.h"
#include "protocols/packet.h"
+#include "rna_logger_common.h"
#ifdef UNIT_TEST
#include "catch/snort_catch.h"
using namespace snort;
-bool RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, const RnaTracker* ht,
- const struct in6_addr* src_ip, const u_int8_t* src_mac)
+bool RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const u_int8_t* src_mac, uint32_t event_time,
+ void* cond_var)
{
if ( !enabled )
return false;
else
rle.ip = nullptr;
+ if (ht)
+ {
+ (*ht)->update_last_event(event_time);
+ if (type == RNA_EVENT_CHANGE && subtype == CHANGE_HOST_UPDATE)
+ rle.cond_var = cond_var;
+ }
+
EventManager::call_loggers(nullptr, const_cast<Packet*>(p), "RNA", &rle);
return true;
}
const RnaTracker* ht;
const u_int8_t* mac;
const struct in6_addr* ip;
+ void* cond_var = nullptr;
};
class RnaLogger
{
public:
RnaLogger(const bool enable) : enabled(enable) { }
- bool log(uint16_t type, uint16_t subtype, const snort::Packet* p, const RnaTracker* ht,
- const struct in6_addr* src_ip, const u_int8_t* src_mac);
+ bool log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const u_int8_t* src_mac,
+ uint32_t event_time = 0, void* cond_var = nullptr);
private:
const bool enabled;
#define RNA_EVENT_NEW 1000
#define NEW_HOST 1
+#define RNA_EVENT_CHANGE 1001
+ #define CHANGE_HOST_UPDATE 15
+
#endif
{ "enable_logger", Parameter::PT_BOOL, nullptr, "true",
"enable or disable writing discovery events into logger" },
+ { "log_when_idle", Parameter::PT_BOOL, nullptr, "false",
+ "enable host update logging when snort is idle" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
{ CountType::SUM, "tcp_syn_ack", "count of TCP SYN-ACK packets received" },
{ CountType::SUM, "tcp_midstream", "count of TCP midstream packets received" },
{ CountType::SUM, "other_packets", "count of packets received without session tracking" },
+ { CountType::SUM, "change_host_update", "count number of change host update events" },
{ CountType::END, nullptr, nullptr},
};
mod_conf->custom_fingerprint_dir = std::string(v.get_string());
else if (v.is("enable_logger"))
mod_conf->enable_logger = v.get_bool();
+ else if (v.is("log_when_idle"))
+ mod_conf->log_when_idle = v.get_bool();
else
return false;
PegCount tcp_syn_ack;
PegCount tcp_midstream;
PegCount other_packets;
+ PegCount change_host_update;
};
extern THREAD_LOCAL RnaStats rna_stats;
};
#endif
-
ht->add_mac(src_mac, ttl, 0);
if ( new_host )
+ {
logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht,
(const struct in6_addr*) src_ip->get_ip6_ptr(), src_mac);
+ }
+ else if ( update_timeout )
+ generate_change_host_update(&ht, p, src_ip, src_mac, packet_time());
+
+}
+
+void RnaPnd::generate_change_host_update(RnaTracker* ht, const snort::Packet* p,
+ const SfIp* src_ip, const uint8_t* src_mac, time_t sec)
+{
+ if ( !ht || !update_timeout)
+ return;
+
+ uint32_t last_seen = (*ht)->get_last_seen();
+ uint32_t last_event = (*ht)->get_last_event();
+ time_t timestamp = sec - update_timeout;
+ if ( last_seen > last_event && (time_t) last_event + update_timeout <= sec )
+ logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_UPDATE, p, ht,
+ (const struct in6_addr*) src_ip->get_ip6_ptr(), src_mac, last_seen, (void*) ×tamp);
+ // FIXIT-M: deal with host service hits.
+}
+
+void RnaPnd::generate_change_host_update()
+{
+ if ( !update_timeout )
+ return;
+
+ auto hosts = host_cache.get_all_data();
+ auto sec = time(nullptr);
+ for ( auto & h : hosts )
+ generate_change_host_update(&h.second, nullptr, &h.first, nullptr, sec);
}
#ifdef UNIT_TEST
#include "helpers/discovery_filter.h"
#include "rna_logger.h"
+#include "sfip/sf_ip.h"
namespace snort
{
class RnaPnd
{
public:
- RnaPnd(const bool en, const std::string& conf)
- : logger(RnaLogger(en)), filter(DiscoveryFilter(conf)) { }
+
+ RnaPnd(const bool en, const std::string& conf, time_t ut = 0)
+ : logger(RnaLogger(en)), filter(DiscoveryFilter(conf)), update_timeout(ut) { }
void analyze_flow_icmp(const snort::Packet* p);
void analyze_flow_ip(const snort::Packet* p);
void analyze_flow_tcp(const snort::Packet* p, TcpPacketType type);
void analyze_flow_udp(const snort::Packet* p);
+ // generate change event for single host
+ void generate_change_host_update(RnaTracker* ht, const snort::Packet* p,
+ const snort::SfIp* src_ip, const uint8_t* src_mac, time_t sec);
+
+ // generate change event for all hosts in the ip cache
+ void generate_change_host_update();
+
private:
// General rna utilities not associated with flow
void discover_network_icmp(const snort::Packet* p);
RnaLogger logger;
DiscoveryFilter filter;
+ time_t update_timeout;
};
#endif