From: Steven Baigal (sbaigal) Date: Thu, 15 Sep 2022 14:57:53 +0000 (+0000) Subject: Pull request #3585: netflow: evaluate all matching netflow rules, not just the first... X-Git-Tag: 3.1.42.0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b3869c99a04d1d2b1e40bea23d6cbd922dfddbf;p=thirdparty%2Fsnort3.git Pull request #3585: netflow: evaluate all matching netflow rules, not just the first match Merge in SNORT/snort3 from ~MMATIRKO/snort3:nf_rule_eval to master Squashed commit of the following: commit b600d2774896b5e35232dff280d995626fae0599 Author: Michael Matirko Date: Wed Sep 7 17:09:21 2022 -0400 netflow: evaluate all matching netflow rules, not just the first match --- diff --git a/src/network_inspectors/rna/rna_pnd.cc b/src/network_inspectors/rna/rna_pnd.cc index 02b23e081..31d622af6 100644 --- a/src/network_inspectors/rna/rna_pnd.cc +++ b/src/network_inspectors/rna/rna_pnd.cc @@ -203,13 +203,9 @@ void RnaPnd::analyze_netflow_host(NetFlowEvent* nfe) const auto& src_ip = nfe->get_record()->initiator_ip; const auto& src_ip_ptr = (const struct in6_addr*) src_ip.get_ip6_ptr(); - auto ht = find_or_create_host_tracker(src_ip, new_host); - - if ( !new_host ) - ht->update_last_seen(); - - const uint8_t src_mac[6] = {0}; - + // This case must be handled first before adding the host to the + // host cache. Otherwise, new rules evals with create_host = true + // will fail since the host will already exist. if (!nfe->get_create_host() and !nfe->get_create_service()) { uint32_t service = nfe->get_service_id(); @@ -218,6 +214,13 @@ void RnaPnd::analyze_netflow_host(NetFlowEvent* nfe) return; } + auto ht = find_or_create_host_tracker(src_ip, new_host); + + if ( !new_host ) + ht->update_last_seen(); + + const uint8_t src_mac[6] = {0}; + if ( new_host ) { if ( nfe->get_create_host() ) diff --git a/src/service_inspectors/netflow/netflow.cc b/src/service_inspectors/netflow/netflow.cc index 8977f88e2..eea7c9bcf 100644 --- a/src/service_inspectors/netflow/netflow.cc +++ b/src/service_inspectors/netflow/netflow.cc @@ -81,9 +81,11 @@ static std::unordered_map* tcp_srv_map = nullptr; // ----------------------------------------------------------------------------- // static functions // ----------------------------------------------------------------------------- -static const NetFlowRule* filter_record(const NetFlowRules* rules, const int zone, +static std::vector filter_record(const NetFlowRules* rules, const int zone, const SfIp* src, const SfIp* dst) { + std::vector match_vec; + const SfIp* addr[2] = {src, dst}; for( auto const & address : addr ) @@ -91,7 +93,7 @@ static const NetFlowRule* filter_record(const NetFlowRules* rules, const int zon for( auto const& rule : rules->exclude ) { if ( rule.filter_match(address, zone) ) - return nullptr; + return match_vec; } } @@ -100,10 +102,11 @@ static const NetFlowRule* filter_record(const NetFlowRules* rules, const int zon for( auto const& rule : rules->include ) { if ( rule.filter_match(address, zone) ) - return &rule; + match_vec.emplace_back(&rule); } } - return nullptr; + + return match_vec; } static void publish_netflow_event(const Packet* p, const NetFlowRule* match, NetFlowSessionRecord& record) @@ -505,8 +508,8 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, } // filter based on configuration - const NetFlowRule* match = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip); - if ( !match ) + std::vector match_vec = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip); + if ( !match_vec.size() ) { records--; continue; @@ -526,8 +529,20 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, } record.netflow_initiator_ip.set(p->ptrs.ip_api.get_src()->get_ip6_ptr(), AF_INET6); - publish_netflow_event(p, match, record); + bool alerted_conn = false; + bool alerted_host = false; + + for (const NetFlowRule* nr: match_vec) + { + if ((!alerted_conn and !nr->create_host) or (!alerted_host and nr->create_host) ) + publish_netflow_event(p, nr, record); + + if (nr->create_host or nr->create_service) + alerted_host = true; + else + alerted_conn = true; + } } if ( netflow_cache->add(record.initiator_ip, record, true) ) @@ -678,8 +693,8 @@ static bool decode_netflow_v5(const unsigned char* data, uint16_t size, if ( record.next_hop_ip.set(&precord->next_hop_addr, AF_INET) != SFIP_SUCCESS ) return false; - const NetFlowRule* match = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip); - if ( !match ) + std::vector match_vec = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip); + if ( !match_vec.size() ) continue; record.initiator_port = ntohs(precord->src_port); @@ -705,7 +720,20 @@ static bool decode_netflow_v5(const unsigned char* data, uint16_t size, ++netflow_stats.unique_flows; record.netflow_initiator_ip.set(p->ptrs.ip_api.get_src()->get_ip6_ptr(), AF_INET6); - publish_netflow_event(p, match, record); + + bool alerted_conn = false; + bool alerted_host = false; + + for (const NetFlowRule* nr: match_vec) + { + if ( (!alerted_conn and !nr->create_host) or (!alerted_host and nr->create_host) ) + publish_netflow_event(p, nr, record); + + if (nr->create_host or nr->create_service) + alerted_host = true; + else + alerted_conn = true; + } } return true; }