From: Mike Stepanek (mstepane) Date: Tue, 10 Sep 2019 16:31:19 +0000 (-0400) Subject: Merge pull request #1733 in SNORT/snort3 from ~SMINUT/snort3:rna_update_timeout to... X-Git-Tag: 3.0.0-261~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=367708c5be5227b791aa9c170ac327a01b89593e;p=thirdparty%2Fsnort3.git Merge pull request #1733 in SNORT/snort3 from ~SMINUT/snort3:rna_update_timeout to master Squashed commit of the following: commit e082dd186ee53898cb90b31d7b426cd277afd2f1 Author: Silviu Minut Date: Thu Sep 5 12:41:00 2019 -0400 rna: generate an RNA_EVENT_CHANGE when a host is seen after the last log event and the current time is past the update timeout. rna: lock when returning last_seen and last_event in host tracker and add peg counts for RnaIdleEventHandler. rna: pass cond_var to the rna log functions, as per snort 2. rna: make generation of a CHANGE_HOST_UPDATE event from idle, configurable. rna: change RnaLoggerEvent::cond_var from time_t to void* because SfUnified2LoggerRNA::rna_serialize() already takes a void* as cond_var. rna: pass host tracker IP address rather than NULL when calling generate_change_host_update from idle. rna: supress unused variable message in RnaIdleEventHandle::handle(). rna: address reviewers' comments. --- diff --git a/src/host_tracker/host_tracker.cc b/src/host_tracker/host_tracker.cc index 28f5c8fb7..6a3bc8a09 100644 --- a/src/host_tracker/host_tracker.cc +++ b/src/host_tracker/host_tracker.cc @@ -40,6 +40,12 @@ void HostTracker::update_last_seen() last_seen = (uint32_t) packet_time(); } +void HostTracker::update_last_event(uint32_t time) +{ + std::lock_guard 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) ) diff --git a/src/host_tracker/host_tracker.h b/src/host_tracker/host_tracker.h index ac2bce1ce..ff46f9adc 100644 --- a/src/host_tracker/host_tracker.h +++ b/src/host_tracker/host_tracker.h @@ -78,9 +78,24 @@ class SO_PUBLIC HostTracker { 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 lck(host_tracker_lock); + return last_seen; + } + + void update_last_event(uint32_t time = 0); + uint32_t get_last_event() const + { + std::lock_guard 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); @@ -99,9 +114,10 @@ public: 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 macs; std::vector services; diff --git a/src/network_inspectors/rna/rna_config.h b/src/network_inspectors/rna/rna_config.h index 791b4f5b3..c8a672332 100644 --- a/src/network_inspectors/rna/rna_config.h +++ b/src/network_inspectors/rna/rna_config.h @@ -28,6 +28,7 @@ struct RnaModuleConfig 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 @@ -39,7 +40,7 @@ struct RnaConfig uint16_t max_host_services = 100; uint16_t max_host_service_info = 16; bool enable_banner_grab = 0; + bool log_when_idle = 0; }; #endif - diff --git a/src/network_inspectors/rna/rna_event_handler.cc b/src/network_inspectors/rna/rna_event_handler.cc index 012a37947..75724cccd 100644 --- a/src/network_inspectors/rna/rna_event_handler.cc +++ b/src/network_inspectors/rna/rna_event_handler.cc @@ -88,3 +88,11 @@ void RnaUdpNewFlowEventHandler::handle(DataEvent& event, Flow*) ++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(); +} diff --git a/src/network_inspectors/rna/rna_event_handler.h b/src/network_inspectors/rna/rna_event_handler.h index cc6adbb29..1d809aed5 100644 --- a/src/network_inspectors/rna/rna_event_handler.h +++ b/src/network_inspectors/rna/rna_event_handler.h @@ -108,4 +108,13 @@ private: 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 diff --git a/src/network_inspectors/rna/rna_inspector.cc b/src/network_inspectors/rna/rna_inspector.cc index bbfc69780..4315f7a97 100644 --- a/src/network_inspectors/rna/rna_inspector.cc +++ b/src/network_inspectors/rna/rna_inspector.cc @@ -53,10 +53,11 @@ RnaInspector::RnaInspector(RnaModule* mod) { 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() @@ -80,6 +81,8 @@ bool RnaInspector::configure(SnortConfig*) 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; } diff --git a/src/network_inspectors/rna/rna_logger.cc b/src/network_inspectors/rna/rna_logger.cc index ccc0cd7c2..bd1708ddb 100644 --- a/src/network_inspectors/rna/rna_logger.cc +++ b/src/network_inspectors/rna/rna_logger.cc @@ -27,6 +27,7 @@ #include "managers/event_manager.h" #include "protocols/packet.h" +#include "rna_logger_common.h" #ifdef UNIT_TEST #include "catch/snort_catch.h" @@ -34,8 +35,9 @@ 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; @@ -46,6 +48,13 @@ bool RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, const RnaT 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(p), "RNA", &rle); return true; } diff --git a/src/network_inspectors/rna/rna_logger.h b/src/network_inspectors/rna/rna_logger.h index 24091e2bf..0b72de6af 100644 --- a/src/network_inspectors/rna/rna_logger.h +++ b/src/network_inspectors/rna/rna_logger.h @@ -40,14 +40,16 @@ struct RnaLoggerEvent : public Event 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; diff --git a/src/network_inspectors/rna/rna_logger_common.h b/src/network_inspectors/rna/rna_logger_common.h index bcdf273d2..1f256c1a7 100644 --- a/src/network_inspectors/rna/rna_logger_common.h +++ b/src/network_inspectors/rna/rna_logger_common.h @@ -24,4 +24,7 @@ #define RNA_EVENT_NEW 1000 #define NEW_HOST 1 +#define RNA_EVENT_CHANGE 1001 + #define CHANGE_HOST_UPDATE 15 + #endif diff --git a/src/network_inspectors/rna/rna_module.cc b/src/network_inspectors/rna/rna_module.cc index 708dd6de4..d954d76cb 100644 --- a/src/network_inspectors/rna/rna_module.cc +++ b/src/network_inspectors/rna/rna_module.cc @@ -56,6 +56,9 @@ static const Parameter rna_params[] = { "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 } }; @@ -71,6 +74,7 @@ static const PegInfo rna_pegs[] = { 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}, }; @@ -107,6 +111,8 @@ bool RnaModule::set(const char*, Value& v, SnortConfig*) 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; diff --git a/src/network_inspectors/rna/rna_module.h b/src/network_inspectors/rna/rna_module.h index 15f4157ef..b835670b3 100644 --- a/src/network_inspectors/rna/rna_module.h +++ b/src/network_inspectors/rna/rna_module.h @@ -41,6 +41,7 @@ struct RnaStats PegCount tcp_syn_ack; PegCount tcp_midstream; PegCount other_packets; + PegCount change_host_update; }; extern THREAD_LOCAL RnaStats rna_stats; @@ -68,4 +69,3 @@ private: }; #endif - diff --git a/src/network_inspectors/rna/rna_pnd.cc b/src/network_inspectors/rna/rna_pnd.cc index f4130bf84..ed818d6d5 100644 --- a/src/network_inspectors/rna/rna_pnd.cc +++ b/src/network_inspectors/rna/rna_pnd.cc @@ -153,8 +153,39 @@ void RnaPnd::discover_network(const Packet* p, u_int8_t ttl) 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 diff --git a/src/network_inspectors/rna/rna_pnd.h b/src/network_inspectors/rna/rna_pnd.h index e798554a3..5abe5d6b1 100644 --- a/src/network_inspectors/rna/rna_pnd.h +++ b/src/network_inspectors/rna/rna_pnd.h @@ -23,6 +23,7 @@ #include "helpers/discovery_filter.h" #include "rna_logger.h" +#include "sfip/sf_ip.h" namespace snort { @@ -37,8 +38,9 @@ enum class TcpPacketType 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); @@ -46,6 +48,13 @@ public: 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); @@ -57,6 +66,7 @@ private: RnaLogger logger; DiscoveryFilter filter; + time_t update_timeout; }; #endif