]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4429: stream: fix to dump all flows
authorARUNKUMAR KAYAMBU -X (akayambu - XORIANT CORPORATION at Cisco) <akayambu@cisco.com>
Tue, 10 Sep 2024 14:13:00 +0000 (14:13 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Tue, 10 Sep 2024 14:13:00 +0000 (14:13 +0000)
Merge in SNORT/snort3 from ~AKAYAMBU/snort3:dump_all_flows to master

Squashed commit of the following:

commit 5bdf40420c947eeb8490cab14a0632feded8905c
Author: Arunkumar Kayambu <akayambu@cisco.com>
Date:   Tue Aug 20 12:21:14 2024 -0400

    stream: fix to dump all flows

src/flow/flow_cache.cc
src/flow/flow_cache.h
src/flow/test/flow_cache_test.cc
src/flow/test/flow_control_test.cc

index 8283acb43a32f598c97ac0f7cf8b04ef67c23421..b00b949ba13bc24ab978d154e88c5e0ecec32c9a 100644 (file)
@@ -886,39 +886,39 @@ bool FlowCache::dump_flows(std::fstream& stream, unsigned count, const FilterFlo
     struct timeval now;
     packet_gettimeofday(&now);
     unsigned i;
+    bool has_more_flows = false;
+    Flow* walk_flow = nullptr;
 
     for(uint8_t proto_id = to_utype(PktType::NONE)+1; proto_id <= to_utype(PktType::ICMP); proto_id++)
     {
         if (first)
         {
-            Flow* walk_flow = static_cast<Flow*>(hash_table->get_walk_user_data(proto_id));
+            walk_flow = static_cast<Flow*>(hash_table->get_walk_user_data(proto_id));
             if (!walk_flow)
             {
                 //Return only if all the protocol caches are processed.
                 if (proto_id < to_utype(PktType::ICMP))
                     continue;
-
-                return true;
+                return !has_more_flows;
             }
             walk_flow->dump_code = code;
             bool matched_filter = filter_flows(*walk_flow, ffc);
             if (matched_filter)
                 output_flow(stream, *walk_flow, now);
             i = 1;
-
         }
         else
             i = 0;
         while (i < count)
         {
-            Flow* walk_flow = static_cast<Flow*>(hash_table->get_next_walk_user_data(proto_id));
+            walk_flow = static_cast<Flow*>(hash_table->get_next_walk_user_data(proto_id));
 
             if (!walk_flow )
             {
                 //Return only if all the protocol caches are processed.
                 if (proto_id < to_utype(PktType::ICMP))
                     break;
-                return true;
+                return !has_more_flows;
             }
             if (walk_flow->dump_code != code)
             {
@@ -933,6 +933,8 @@ bool FlowCache::dump_flows(std::fstream& stream, unsigned count, const FilterFlo
                 LogMessage("dump_flows skipping already dumped flow\n");
 #endif
         }
+        if(walk_flow) // we have output 'count' flows, but the protocol cache still has more flows
+            has_more_flows = true;
     }
     return false;
 }
index f45f32cc209fc61ab3e1e31766986fe32b06e915..7756a16afcb1717e50ffdf457d7e0fbe0dafdd8b 100644 (file)
@@ -81,7 +81,7 @@ class FlowCache
 {
 public:
     FlowCache(const FlowCacheConfig&);
-    ~FlowCache();
+    virtual ~FlowCache();
 
     FlowCache(const FlowCache&) = delete;
     FlowCache& operator=(const FlowCache&) = delete;
@@ -134,6 +134,9 @@ public:
     const FlowCacheConfig& get_flow_cache_config() const
     { return config; }
 
+    virtual bool filter_flows(const snort::Flow&, const FilterFlowCriteria&) const;
+    virtual void output_flow(std::fstream&, const snort::Flow&, const struct timeval&) const;
+
     unsigned get_flows_allocated() const;
 
     size_t uni_flows_size() const;
@@ -150,8 +153,6 @@ private:
     unsigned delete_active_flows(unsigned mode, unsigned num_to_delete, unsigned &deleted);
     static std::string timeout_to_str(time_t);
     bool is_ip_match(const snort::SfIp& flow_ip, const snort::SfIp& filter_ip, const snort::SfIp& subnet) const;
-    bool filter_flows(const snort::Flow&, const FilterFlowCriteria&) const;
-    void output_flow(std::fstream&, const snort::Flow&, const struct timeval&) const;
 
 private:
     uint8_t timeout_idx;
index 4ebbd223f7b88f748266e98181251e87a42031a3..2341b5d3216083fe24633310bf43fbfa95a664f6 100644 (file)
@@ -131,6 +131,15 @@ int ExpectCache::add_flow(const Packet*, PktType, IpProtocol, const SfIp*, uint1
 unsigned int get_random_seed()
 { return 3193; }
 
+class DummyCache : public FlowCache
+{
+    public:
+        DummyCache(const FlowCacheConfig& cfg) : FlowCache(cfg) {}
+        ~DummyCache() = default;
+        void output_flow(std::fstream& stream, const Flow& flow, const struct timeval& now) const override { (void)stream, (void)flow, (void)now; };
+        bool filter_flows(const Flow& flow, const FilterFlowCriteria& ffc) const override { (void)flow; (void)ffc; return true; };
+};
+
 TEST_GROUP(flow_prune) { };
 
 // No flows in the flow cache, pruning should not happen
@@ -384,6 +393,105 @@ TEST(flow_prune, prune_counts)
     CHECK_EQUAL(3, stats.get_proto_prune_count(PruneReason::IDLE_PROTOCOL_TIMEOUT, PktType::IP));
 }
 
+TEST_GROUP(dump_flows) { };
+
+TEST(dump_flows, dump_flows_with_all_empty_caches)
+{
+    FlowCacheConfig fcg;
+    FilterFlowCriteria ffc;
+    std::fstream dump_stream;
+    DummyCache *cache = new DummyCache(fcg);
+    CHECK(cache->dump_flows(dump_stream, 100, ffc, true, 1 ) == true);
+    CHECK(cache->get_flows_allocated() == 0);
+    delete cache;
+}
+
+TEST(dump_flows, dump_flows_with_one_tcp_flow)
+{
+    FlowCacheConfig fcg;
+    fcg.max_flows = 5;
+    FilterFlowCriteria ffc;
+    std::fstream dump_stream;
+    DummyCache *cache = new DummyCache(fcg);
+
+    FlowKey flow_key;
+    flow_key.port_l = 1;
+    flow_key.pkt_type = PktType::TCP;
+    cache->allocate(&flow_key);
+    CHECK(cache->dump_flows(dump_stream, 100, ffc, true, 1 ) == true);
+    CHECK (cache->get_count() == 1);
+
+    cache->purge();
+    CHECK(cache->get_flows_allocated() == 0);
+    delete cache;
+}
+
+TEST(dump_flows, dump_flows_with_102_tcp_flows)
+{
+    FlowCacheConfig fcg;
+    fcg.max_flows = 500;
+    FilterFlowCriteria ffc;
+    std::fstream dump_stream;
+    DummyCache *cache = new DummyCache(fcg);
+    int port = 1;
+
+    for ( unsigned i = 0; i < 102; i++ )
+    {
+        FlowKey flow_key;
+        flow_key.port_l = port++;
+        flow_key.pkt_type = PktType::TCP;
+        cache->allocate(&flow_key);
+    }
+    CHECK (cache->get_count() == 102);
+    //since we only dump 100 flows at a time. The first call will return false
+    //second time when it is called , it dumps the remaining 2 flows and returns true
+    CHECK(cache->dump_flows(dump_stream, 100, ffc, true, 1 ) == false);
+    CHECK(cache->dump_flows(dump_stream, 100, ffc, false, 1 ) == true);
+
+    cache->purge();
+    CHECK(cache->get_flows_allocated() == 0);
+    CHECK (cache->get_count() == 0);
+    delete cache;
+}
+
+TEST(dump_flows, dump_flows_with_102_tcp_flows_and_202_udp_flows)
+{
+    FlowCacheConfig fcg;
+    fcg.max_flows = 500;
+    FilterFlowCriteria ffc;
+    std::fstream dump_stream;
+    DummyCache *cache = new DummyCache(fcg);
+    int port = 1;
+
+    for ( unsigned i = 0; i < 102; i++ )
+    {
+        FlowKey flow_key;
+        flow_key.port_l = port++;
+        flow_key.pkt_type = PktType::TCP;
+        cache->allocate(&flow_key);
+    }
+
+    for ( unsigned i = 0; i < 202; i++ )
+    {
+        FlowKey flow_key;
+        flow_key.port_l = port++;
+        flow_key.pkt_type = PktType::UDP;
+        cache->allocate(&flow_key);
+    }
+
+    CHECK (cache->get_count() == 304);
+    //since we only dump 100 flows at a time. The first 2 calls will return false
+    //third time when it is called , it dumps the remaining 2 UDP flows and returns true
+    CHECK(cache->dump_flows(dump_stream, 100, ffc, true, 1 ) == false);
+    CHECK(cache->dump_flows(dump_stream, 100, ffc, false, 1 ) == false);
+    CHECK(cache->dump_flows(dump_stream, 100, ffc, false, 1 ) == true);
+
+    cache->purge();
+    CHECK(cache->get_flows_allocated() == 0);
+    CHECK (cache->get_count() == 0);
+    delete cache;
+}
+
 int main(int argc, char** argv)
 {
     return CommandLineTestRunner::RunAllTests(argc, argv);
index a0037668d1ca2d1ac8f9692d9c63df2191e7f73d..234001d244d1e1b83c6ce35abfad5ba29d83588b 100644 (file)
@@ -75,6 +75,8 @@ void Flow::init(PktType) { }
 const SnortConfig* SnortConfig::get_conf() { return nullptr; }
 void FlowCache::unlink_uni(Flow*) { }
 bool FlowCache::dump_flows(std::fstream&, unsigned, const FilterFlowCriteria&, bool, uint8_t) const { return false; }
+void FlowCache::output_flow(std::fstream&, const Flow&, const struct timeval& ) const { }
+bool FlowCache::filter_flows(const Flow&, const FilterFlowCriteria&) const { return true; };
 void Flow::set_client_initiate(Packet*) { }
 void Flow::set_direction(Packet*) { }
 void Flow::set_mpls_layer_per_dir(Packet*) { }