]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3585: netflow: evaluate all matching netflow rules, not just the first...
authorSteven Baigal (sbaigal) <sbaigal@cisco.com>
Thu, 15 Sep 2022 14:57:53 +0000 (14:57 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Thu, 15 Sep 2022 14:57:53 +0000 (14:57 +0000)
Merge in SNORT/snort3 from ~MMATIRKO/snort3:nf_rule_eval to master

Squashed commit of the following:

commit b600d2774896b5e35232dff280d995626fae0599
Author: Michael Matirko <mmatirko@cisco.com>
Date:   Wed Sep 7 17:09:21 2022 -0400

    netflow: evaluate all matching netflow rules, not just the first match

src/network_inspectors/rna/rna_pnd.cc
src/service_inspectors/netflow/netflow.cc

index 02b23e081b786d680a59a70a1bbc0567624d3c97..31d622af61b1bf46fd1fae1fa427dc6626368d1b 100644 (file)
@@ -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() )
index 8977f88e28f85a51b7e4cd840e97a39b34e9081c..eea7c9bcfa16eaacdd83080945cc22aca13010ad 100644 (file)
@@ -81,9 +81,11 @@ static std::unordered_map<int, int>* tcp_srv_map = nullptr;
 // -----------------------------------------------------------------------------
 // static functions
 // -----------------------------------------------------------------------------
-static const NetFlowRule* filter_record(const NetFlowRules* rules, const int zone,
+static std::vector<const NetFlowRule*> filter_record(const NetFlowRules* rules, const int zone,
     const SfIp* src, const SfIp* dst)
 {
+    std::vector<const NetFlowRule*> 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<const NetFlowRule*> 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<const NetFlowRule*> 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;
 }