From 742c28c489170f067728f063fbd9d4b64f46ab2e Mon Sep 17 00:00:00 2001 From: "Nirmala Venkata Subbaiah -X (nirmvenk - XORIANT CORPORATION at Cisco)" Date: Wed, 12 Mar 2025 20:42:17 +0000 Subject: [PATCH] Pull request #4635: packet_capture: support packet capture limit and location Merge in SNORT/snort3 from ~NIRMVENK/snort3:pcap_limit to master Squashed commit of the following: commit 397c78f1e44a6e9e6ba976b7387182377739e87f Author: Nirmala Subbaiah Date: Mon Feb 24 17:56:54 2025 -0500 packet_capture: support packet capture limit and location --- .../packet_capture/capture_module.cc | 76 +++++++++++++++++-- .../packet_capture/capture_module.h | 2 + .../packet_capture/packet_capture.cc | 35 ++++++++- .../packet_capture/packet_capture.h | 3 +- 4 files changed, 106 insertions(+), 10 deletions(-) diff --git a/src/network_inspectors/packet_capture/capture_module.cc b/src/network_inspectors/packet_capture/capture_module.cc index 36e1bf9c1..5555ec676 100644 --- a/src/network_inspectors/packet_capture/capture_module.cc +++ b/src/network_inspectors/packet_capture/capture_module.cc @@ -24,10 +24,12 @@ #include "capture_module.h" +#include #include #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; +} diff --git a/src/network_inspectors/packet_capture/capture_module.h b/src/network_inspectors/packet_capture/capture_module.h index 1aee45c51..5f4cdf93a 100644 --- a/src/network_inspectors/packet_capture/capture_module.h +++ b/src/network_inspectors/packet_capture/capture_module.h @@ -33,6 +33,8 @@ struct CaptureConfig std::string filter; std::vector tenants; bool check_inner_pkt; + std::string capture_path; + unsigned max_packet_count = 0; }; struct CaptureStats diff --git a/src/network_inspectors/packet_capture/packet_capture.cc b/src/network_inspectors/packet_capture/packet_capture.cc index 85f541959..0f0326522 100644 --- a/src/network_inspectors/packet_capture/packet_capture.cc +++ b/src/network_inspectors/packet_capture/packet_capture.cc @@ -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; diff --git a/src/network_inspectors/packet_capture/packet_capture.h b/src/network_inspectors/packet_capture/packet_capture.h index d145e92d0..9ff3aa404 100644 --- a/src/network_inspectors/packet_capture/packet_capture.h +++ b/src/network_inspectors/packet_capture/packet_capture.h @@ -23,7 +23,8 @@ #include #include -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 -- 2.47.3