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)
{
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;
}
{
public:
FlowCache(const FlowCacheConfig&);
- ~FlowCache();
+ virtual ~FlowCache();
FlowCache(const FlowCache&) = delete;
FlowCache& operator=(const FlowCache&) = delete;
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;
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;
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
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);