]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4635: packet_capture: support packet capture limit and location
authorNirmala Venkata Subbaiah -X (nirmvenk - XORIANT CORPORATION at Cisco) <nirmvenk@cisco.com>
Wed, 12 Mar 2025 20:42:17 +0000 (20:42 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Wed, 12 Mar 2025 20:42:17 +0000 (20:42 +0000)
Merge in SNORT/snort3 from ~NIRMVENK/snort3:pcap_limit to master

Squashed commit of the following:

commit 397c78f1e44a6e9e6ba976b7387182377739e87f
Author: Nirmala Subbaiah <nirmvenk@cisco.com>
Date:   Mon Feb 24 17:56:54 2025 -0500

    packet_capture: support packet capture limit and location

src/network_inspectors/packet_capture/capture_module.cc
src/network_inspectors/packet_capture/capture_module.h
src/network_inspectors/packet_capture/packet_capture.cc
src/network_inspectors/packet_capture/packet_capture.h

index 36e1bf9c17ca8bf9ef34fed0ac388598278443c3..5555ec67642aedbc31c2dfb37903c75c97a7c028 100644 (file)
 
 #include "capture_module.h"
 
+#include <filesystem>
 #include <lua.hpp>
 
 #include "control/control.h"
 #include "main/analyzer_command.h"
+#include "log/messages.h"
 #include "profiler/profiler.h"
 #include "utils/util.h"
 
@@ -38,6 +40,7 @@ using namespace std;
 
 static int enable(lua_State*);
 static int disable(lua_State*);
+bool is_path_valid(const std::string& path);
 
 static const Parameter s_capture[] =
 {
@@ -55,6 +58,12 @@ static const Parameter s_capture[] =
 
     { "check_inner_pkt", Parameter::PT_BOOL, nullptr, "true",
       "apply filter on inner packet headers" },
+    
+    { "capture_path", Parameter::PT_STRING, nullptr, nullptr,
+      "directory path to capture pcaps" },
+    
+    { "max_packet_count", Parameter::PT_INT, "0:max32", "1000000",
+      "cap the number of packets per thread" },
 
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
@@ -73,6 +82,12 @@ static const Parameter capture_params[] =
     { "check_inner_pkt", Parameter::PT_BOOL, nullptr, "true",
       "apply filter on inner packet headers" },
 
+    { "capture_path", Parameter::PT_STRING, nullptr, nullptr,
+      "directory path to capture pcaps" },
+    
+    { "max_packet_count", Parameter::PT_INT, "0:max32", "1000000",
+      "cap the number of packets per thread" },
+
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -99,7 +114,8 @@ THREAD_LOCAL ProfileStats cap_prof_stats;
 class PacketCaptureDebug : public AnalyzerCommand
 {
 public:
-    PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci);
+    PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci, 
+                       const char* p, const unsigned max);
     bool execute(Analyzer&, void**) override;
     const char* stringify() override { return "PACKET_CAPTURE_DEBUG"; }
 private:
@@ -108,6 +124,8 @@ private:
     int16_t group = -1;
     std::string tenants;
     bool check_inner_pkt = true;
+    std::string capture_path;
+    unsigned max_packet_count = 0;
 };
 
 // -----------------------------------------------------------------------------
@@ -115,14 +133,38 @@ private:
 // -----------------------------------------------------------------------------
 static int enable(lua_State* L)
 {
+    ControlConn* ctrlcon = ControlConn::query_from_lua(L);
+    auto log_response = [ctrlcon](const char* response)
+    {
+      if (ctrlcon)
+        ctrlcon->respond("%s", response);
+      else
+        LogMessage("%s", response);
+    };
+    
+    std::string path = luaL_optstring(L, 5, "");
+    if ( !path.empty() && !is_path_valid(path) )
+    {
+      log_response("== Capture path invalid\n"); 
+      return 0;
+    }
+
+    auto max_limit = luaL_optint(L, 6, 0);
+    if ( max_limit < 0)
+    {
+      log_response("== Max packet count invalid\n"); 
+      return 0;
+    }
     main_broadcast_command(new PacketCaptureDebug(luaL_optstring(L, 1, ""),
-        luaL_optint(L, 2, 0), luaL_optstring(L, 3, ""), luaL_opt(L, lua_toboolean, 4, true)), ControlConn::query_from_lua(L));
+        luaL_optint(L, 2, 0), luaL_optstring(L, 3, ""), luaL_opt(L, lua_toboolean, 4, true), 
+        path.c_str(), max_limit), ctrlcon);
     return 0;
 }
 
 static int disable(lua_State* L)
 {
-    main_broadcast_command(new PacketCaptureDebug(nullptr, -1, nullptr, true), ControlConn::query_from_lua(L));
+    main_broadcast_command(new PacketCaptureDebug(nullptr, -1, nullptr, true, nullptr, 0), 
+        ControlConn::query_from_lua(L));
     return 0;
 }
 
@@ -130,7 +172,8 @@ static int disable(lua_State* L)
 // non-static functions
 // -----------------------------------------------------------------------------
 
-PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci)
+PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci, \
+                                       const char* p, const unsigned max)
 {
     if (f)
     {
@@ -139,13 +182,15 @@ PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const cha
         enable = true;
         tenants = t == nullptr ? "" : t;
         check_inner_pkt = ci;
+        capture_path = p;
+        max_packet_count = max;
     }
 }
 
 bool PacketCaptureDebug::execute(Analyzer&, void**)
 {
     if (enable)
-        packet_capture_enable(filter, group, tenants, check_inner_pkt);
+        packet_capture_enable(filter, group, tenants, check_inner_pkt, capture_path, max_packet_count);
     else
         packet_capture_disable();
 
@@ -176,6 +221,18 @@ bool CaptureModule::set(const char*, Value& v, SnortConfig*)
 
     else if ( v.is("check_inner_pkt") )
         config.check_inner_pkt = v.get_bool();
+    
+    else if ( v.is("capture_path") )
+    {
+        if ( !is_path_valid(v.get_string()) )
+        {
+          return false;
+        }
+        config.capture_path = v.get_string();
+    }
+    
+    else if ( v.is("max_packet_count") )
+        config.max_packet_count = v.get_uint32();
 
     return true;
 }
@@ -195,3 +252,12 @@ const PegInfo* CaptureModule::get_pegs() const
 PegCount* CaptureModule::get_counts() const
 { return (PegCount*)&cap_count_stats; }
 
+bool is_path_valid(const std::string& path)
+{
+  if ( !std::filesystem::exists(path) )
+  {
+    WarningMessage("Cannot create pcap at %s; directory does not exist\n", path.c_str());
+    return false;
+  }
+  return true;
+}
index 1aee45c51ed268b7c6eb474f80fbfff1abd419c0..5f4cdf93a9f27272c27c5d3bcaa692793dd2da0d 100644 (file)
@@ -33,6 +33,8 @@ struct CaptureConfig
     std::string filter;
     std::vector<uint32_t> tenants;
     bool check_inner_pkt;
+    std::string capture_path;
+    unsigned max_packet_count = 0;
 };
 
 struct CaptureStats
index 85f5419596ea682fdcd93361268ca9920d7656e6..0f03265228398f1dd79b483f5a7ccc2c12fbafc3 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "framework/inspector.h"
 #include "log/messages.h"
+#include "main/thread_config.h"
 #include "packet_io/sfdaq.h"
 #include "protocols/packet.h"
 #include "utils/util.h"
@@ -53,6 +54,7 @@ static CaptureConfig config;
 static THREAD_LOCAL pcap_t* pcap = nullptr;
 static THREAD_LOCAL pcap_dumper_t* dumper = nullptr;
 static THREAD_LOCAL struct bpf_program bpf;
+static THREAD_LOCAL unsigned packet_count = 0;
 
 // -----------------------------------------------------------------------------
 // static functions
@@ -118,7 +120,17 @@ static bool bpf_compile_and_validate()
 static bool open_pcap_dumper()
 {
     string fname;
-    get_instance_file(fname, FILE_NAME);
+    if ( config.capture_path.empty() ) 
+        get_instance_file(fname, FILE_NAME);
+    else
+    {
+        auto file_name = std::string(FILE_NAME);
+        if ( ThreadConfig::get_instance_max() > 1 )
+            file_name.insert(file_name.find(".pcap"), 
+                            ("_" + std::to_string(get_instance_id()) + \
+                             "_" + std::to_string(get_relative_instance_number())));
+        fname = config.capture_path + "/" + file_name;
+    }
 
     pcap = pcap_open_dead(get_dlt(), SNAP_LEN);
     dumper = pcap ? pcap_dump_open(pcap, fname.c_str()) : nullptr;
@@ -132,7 +144,8 @@ static bool open_pcap_dumper()
 }
 
 // for unit test
-static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "", const bool ci = true)
+static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "", 
+                                   const bool ci = true, const string& path = "", const unsigned max = 0)
 {
     if ( !config.enabled )
     {
@@ -141,6 +154,8 @@ static void _packet_capture_enable(const string& f, const int16_t g = -1, const
         config.group = g;
         config.check_inner_pkt = ci;
         str_to_int_vector(t, ',', config.tenants);
+        config.capture_path = path;
+        config.max_packet_count = max;
     }
 }
 
@@ -151,6 +166,8 @@ static void _packet_capture_disable()
     config.group = -1;
     config.tenants.clear();
     config.check_inner_pkt = true;
+    config.capture_path.clear();
+    config.max_packet_count = 0;
     LogMessage("Packet capture disabled\n");
 }
 
@@ -158,10 +175,11 @@ static void _packet_capture_disable()
 // non-static functions
 // -----------------------------------------------------------------------------
 
-void packet_capture_enable(const string& f, const int16_t g, const string& t, const bool ci)
+void packet_capture_enable(const string& f, const int16_t g, const string& t, const bool ci, 
+                           const string& p, const unsigned max)
 {
 
-    _packet_capture_enable(f, g, t, ci);
+    _packet_capture_enable(f, g, t, ci, p, max);
 
     if ( !capture_initialized() )
     {
@@ -234,6 +252,8 @@ void PacketCapture::show(const SnortConfig*) const
     {
         ConfigLogger::log_value("filter", config.filter.c_str());
         ConfigLogger::log_value("tenants", int_vector_to_str(config.tenants).c_str());
+        ConfigLogger::log_value("capture_path", config.capture_path.c_str());
+        ConfigLogger::log_value("max_packet_count", config.max_packet_count);
     }
 }
 
@@ -302,6 +322,13 @@ void PacketCapture::eval(Packet* p)
 
 void PacketCapture::write_packet(Packet* p)
 {
+    if ( config.max_packet_count )
+    {
+        if ( packet_count >= config.max_packet_count )
+            return;
+
+        packet_count++;
+    }
     struct pcap_pkthdr pcaphdr;
     pcaphdr.ts = p->pkth->ts;
     pcaphdr.caplen = p->pktlen;
index d145e92d0c91b368f26b7675c985cd7d1569bfeb..9ff3aa404a51a60b8b50559d1b3f6a796c69c0ca 100644 (file)
@@ -23,7 +23,8 @@
 #include <cstdint>
 #include <string>
 
-void packet_capture_enable(const std::string&, const int16_t g = -1, const std::string& t = "", const bool ci = true);
+void packet_capture_enable(const std::string&, const int16_t g = -1, const std::string& t = "", 
+                           const bool ci = true, const std::string& path = "", const unsigned max = 0);
 void packet_capture_disable();
 
 #endif