From: Michael Altizer (mialtize) Date: Thu, 10 May 2018 16:29:31 +0000 (-0400) Subject: Merge pull request #1219 in SNORT/snort3 from add_capture_support to master X-Git-Tag: 3.0.0-245~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c2193132af10b57b3b81c66552a7e06676ff9fd4;p=thirdparty%2Fsnort3.git Merge pull request #1219 in SNORT/snort3 from add_capture_support to master Squashed commit of the following: commit a5e4304b0fa51fb13d40af0f802ee8059d529edd Author: shaslad Date: Thu May 3 22:12:04 2018 -0400 packet_capture: adding analyzer command to initialize dump file --- diff --git a/src/main.cc b/src/main.cc index 266d89513..aba39f06f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -241,9 +241,23 @@ static Pig* get_lazy_pig(unsigned max) // main commands //------------------------------------------------------------------------- -void snort::main_broadcast_command(AnalyzerCommand* ac) +static AnalyzerCommand* get_command(AnalyzerCommand* ac, bool from_shell) +{ +#ifndef SHELL + UNUSED(from_shell); +#else + if ( from_shell ) + return ( new ACShellCmd(current_fd, ac) ); + else +#endif + return ac; +} + +void snort::main_broadcast_command(AnalyzerCommand* ac, bool from_shell) { unsigned dispatched = 0; + + ac = get_command(ac, from_shell); for (unsigned idx = 0; idx < max_pigs; ++idx) { @@ -255,23 +269,11 @@ void snort::main_broadcast_command(AnalyzerCommand* ac) orphan_commands.push(ac); } -static AnalyzerCommand* get_command(AnalyzerCommand* ac, bool from_shell) -{ -#ifndef SHELL - UNUSED(from_shell); -#else - if ( from_shell ) - return ( new ACShellCmd(current_fd, ac) ); - else -#endif - return ac; -} - int main_dump_stats(lua_State* L) { bool from_shell = ( L != nullptr ); current_request->respond("== dumping stats\n", from_shell); - main_broadcast_command(get_command(new ACGetStats(), from_shell)); + main_broadcast_command(new ACGetStats(), from_shell); return 0; } @@ -279,7 +281,7 @@ int main_rotate_stats(lua_State* L) { bool from_shell = ( L != nullptr ); current_request->respond("== rotating stats\n", from_shell); - main_broadcast_command(get_command(new ACRotate(), from_shell)); + main_broadcast_command(new ACRotate(), from_shell); return 0; } @@ -321,7 +323,7 @@ int main_reload_config(lua_State* L) bool from_shell = ( L != nullptr ); current_request->respond(".. swapping configuration\n", from_shell); - main_broadcast_command(get_command(new ACSwap(new Swapper(old, sc, old_tc, tc)), from_shell)); + main_broadcast_command(new ACSwap(new Swapper(old, sc, old_tc, tc)), from_shell); return 0; } @@ -362,7 +364,7 @@ int main_reload_policy(lua_State* L) bool from_shell = ( L != nullptr ); current_request->respond(".. swapping policy\n", from_shell); - main_broadcast_command(get_command(new ACSwap(new Swapper(old, sc)), from_shell)); + main_broadcast_command(new ACSwap(new Swapper(old, sc)), from_shell); return 0; } @@ -371,7 +373,7 @@ int main_reload_daq(lua_State* L) { bool from_shell = ( L != nullptr ); current_request->respond(".. reloading daq module\n", from_shell); - main_broadcast_command(get_command(new ACDAQSwap(), from_shell)); + main_broadcast_command(new ACDAQSwap(), from_shell); proc_stats.daq_reloads++; return 0; @@ -409,7 +411,7 @@ int main_reload_hosts(lua_State* L) bool from_shell = ( L != nullptr ); current_request->respond(".. swapping hosts table\n", from_shell); - main_broadcast_command(get_command(new ACSwap(new Swapper(old, tc)), from_shell)); + main_broadcast_command(new ACSwap(new Swapper(old, tc)), from_shell); return 0; } @@ -450,7 +452,7 @@ int main_delete_inspector(lua_State* L) bool from_shell = ( L != nullptr ); current_request->respond(".. deleted inspector\n", from_shell); - main_broadcast_command(get_command(new ACSwap(new Swapper(old, sc)), from_shell)); + main_broadcast_command(new ACSwap(new Swapper(old, sc)), from_shell); return 0; } @@ -472,7 +474,7 @@ int main_pause(lua_State* L) { bool from_shell = ( L != nullptr ); current_request->respond("== pausing\n", from_shell); - main_broadcast_command(get_command(new ACPause(), from_shell)); + main_broadcast_command(new ACPause(), from_shell); paused = true; return 0; } @@ -481,7 +483,7 @@ int main_resume(lua_State* L) { bool from_shell = ( L != nullptr ); current_request->respond("== resuming\n", from_shell); - main_broadcast_command(get_command(new ACResume(), from_shell)); + main_broadcast_command(new ACResume(), from_shell); paused = false; return 0; } @@ -505,7 +507,7 @@ int main_quit(lua_State* L) { bool from_shell = ( L != nullptr ); current_request->respond("== stopping\n", from_shell); - main_broadcast_command(get_command(new ACStop(), from_shell)); + main_broadcast_command(new ACStop(), from_shell); exit_requested = true; return 0; } diff --git a/src/main/analyzer_command.h b/src/main/analyzer_command.h index 72ad0d301..a069291b2 100644 --- a/src/main/analyzer_command.h +++ b/src/main/analyzer_command.h @@ -113,7 +113,7 @@ public: namespace snort { -SO_PUBLIC void main_broadcast_command(AnalyzerCommand* ac); // From main.cc +SO_PUBLIC void main_broadcast_command(AnalyzerCommand* ac, bool from_shell = false); // From main.cc } #endif diff --git a/src/main/request.h b/src/main/request.h index eb8fa9539..61e048ba2 100644 --- a/src/main/request.h +++ b/src/main/request.h @@ -41,6 +41,6 @@ private: int fd; char read_buf[1024]; size_t bytes_read; - const char* queued_response; + const char* queued_response = nullptr; }; #endif diff --git a/src/network_inspectors/appid/appid_module.cc b/src/network_inspectors/appid/appid_module.cc index c20d2a99c..4b65ac647 100644 --- a/src/network_inspectors/appid/appid_module.cc +++ b/src/network_inspectors/appid/appid_module.cc @@ -146,14 +146,14 @@ static int enable_debug(lua_State* L) constraints.sport = sport; constraints.dport = dport; - main_broadcast_command(new AcAppIdDebug(&constraints)); + main_broadcast_command(new AcAppIdDebug(&constraints), true); return 0; } static int disable_debug(lua_State*) { - main_broadcast_command(new AcAppIdDebug(nullptr)); + main_broadcast_command(new AcAppIdDebug(nullptr), true); return 0; } diff --git a/src/network_inspectors/packet_capture/capture_module.cc b/src/network_inspectors/packet_capture/capture_module.cc index 8b2f8db7d..660351c73 100644 --- a/src/network_inspectors/packet_capture/capture_module.cc +++ b/src/network_inspectors/packet_capture/capture_module.cc @@ -26,6 +26,7 @@ #include +#include "main/analyzer_command.h" #include "profiler/profiler.h" #include "packet_capture.h" @@ -36,13 +37,6 @@ using namespace std; static int enable(lua_State*); static int disable(lua_State*); -const PegInfo cap_names[] = -{ - { CountType::SUM, "processed", "packets processed against filter" }, - { CountType::SUM, "captured", "packets matching dumped after matching filter" }, - { CountType::END, nullptr, nullptr } -}; - static const Parameter s_capture[] = { { "enable", Parameter::PT_BOOL, nullptr, "false", @@ -61,21 +55,66 @@ static const Command cap_cmds[] = { nullptr, nullptr, nullptr, nullptr } }; +static const PegInfo cap_names[] = +{ + { CountType::SUM, "processed", "packets processed against filter" }, + { CountType::SUM, "captured", "packets matching dumped after matching filter" }, + { CountType::END, nullptr, nullptr } +}; + THREAD_LOCAL CaptureStats cap_count_stats; THREAD_LOCAL ProfileStats cap_prof_stats; +//------------------------------------------------------------------------- +// class stuff +//------------------------------------------------------------------------- +class PacketCaptureDebug : public AnalyzerCommand +{ +public: + PacketCaptureDebug(const char* f); + void execute(Analyzer&) override; + const char* stringify() override { return "PACKET_CAPTURE_DEBUG"; } +private: + bool enable = false; + std::string filter; +}; + +// ----------------------------------------------------------------------------- +// static functions +// ----------------------------------------------------------------------------- static int enable(lua_State* L) { - packet_capture_enable(lua_tostring(L, 1)); + main_broadcast_command(new PacketCaptureDebug(lua_tostring(L, 1)), true); return 0; } static int disable(lua_State*) { - packet_capture_disable(); + main_broadcast_command(new PacketCaptureDebug(nullptr), true); return 0; } +// ----------------------------------------------------------------------------- +// non-static functions +// ----------------------------------------------------------------------------- + +PacketCaptureDebug::PacketCaptureDebug(const char* f) +{ + if (f) + { + filter = f; + enable = true; + } +} + +void PacketCaptureDebug::execute(Analyzer&) +{ + if (enable) + packet_capture_enable(filter); + else + packet_capture_disable(); +} + CaptureModule::CaptureModule() : Module(CAPTURE_NAME, CAPTURE_HELP, s_capture) { config.enabled = false; } diff --git a/src/network_inspectors/packet_capture/packet_capture.cc b/src/network_inspectors/packet_capture/packet_capture.cc index 866f873a5..3bfa85085 100644 --- a/src/network_inspectors/packet_capture/packet_capture.cc +++ b/src/network_inspectors/packet_capture/packet_capture.cc @@ -42,32 +42,122 @@ using namespace std; #define FILE_NAME "packet_capture.pcap" #define SNAP_LEN 65535 +// ----------------------------------------------------------------------------- +// static variables +// ----------------------------------------------------------------------------- + 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 functions +// ----------------------------------------------------------------------------- + static inline bool capture_initialized() { return dumper != nullptr; } -void packet_capture_enable(const string& f) +static void _capture_term() +{ + if ( dumper ) + { + pcap_dump_close(dumper); + dumper = nullptr; + } + if ( pcap ) + { + free(pcap); + pcap = nullptr; + } + pcap_freecode(&bpf); +} + +static bool bpf_compile_and_validate() +{ + // FIXIT-M This BPF compilation is not threadsafe and should be handled by the main thread + // and this call should use DLT from DAQ rather then hard coding DLT_EN10MB + if ( pcap_compile_nopcap(SNAP_LEN, DLT_EN10MB, &bpf, + config.filter.c_str(), 1, 0) >= 0 ) + { + if (bpf_validate(bpf.bf_insns, bpf.bf_len)) + return true; + else + WarningMessage("Unable to validate BPF filter\n"); + } + else + WarningMessage("Unable to compile BPF filter\n"); + return false; +} + +static bool open_pcap_dumper() +{ + string fname; + get_instance_file(fname, FILE_NAME); + + pcap = pcap_open_dead(DLT_EN10MB, SNAP_LEN); + dumper = pcap ? pcap_dump_open(pcap, fname.c_str()) : nullptr; + + if (dumper) + return true; + else + WarningMessage("Could not initialize dump file\n"); + + return false; +} + +// for unit test +static void _packet_capture_enable(const string& f) { if ( !config.enabled ) { config.filter = f; config.enabled = true; } - else - WarningMessage("Conflicting packet capture already in progress.\n"); } -void packet_capture_disable() +// for unit test +static void _packet_capture_disable() { config.enabled = false; LogMessage("Packet capture disabled\n"); } +// ----------------------------------------------------------------------------- +// non-static functions +// ----------------------------------------------------------------------------- + +void packet_capture_enable(const string& f) +{ + + _packet_capture_enable(f); + + if ( !capture_initialized() ) + { + if (bpf_compile_and_validate()) + { + if (open_pcap_dumper()) + { + LogMessage("Packet capture enabled\n"); + return; + } + } + else + { + WarningMessage("Failed to enable Packet capture\n"); + packet_capture_disable(); + } + } +} + +void packet_capture_disable() +{ + _packet_capture_disable(); + if ( capture_initialized() ) + _capture_term(); +} + //------------------------------------------------------------------------- // class stuff //------------------------------------------------------------------------- @@ -77,25 +167,41 @@ class PacketCapture : public Inspector public: PacketCapture(CaptureModule*); + // non-static functions void eval(Packet*) override; void tterm() override { capture_term(); } protected: virtual bool capture_init(); virtual void capture_term(); - virtual pcap_dumper_t* open_dump(pcap_t*, const char*); virtual void write_packet(Packet* p); }; PacketCapture::PacketCapture(CaptureModule* m) { m->get_config(config); } +void PacketCapture::capture_term() { _capture_term(); } + +bool PacketCapture::capture_init() +{ + if (bpf_compile_and_validate()) + { + if (open_pcap_dumper()) + { + LogMessage("Packet capture enabled\n"); + return true; + } + } + packet_capture_disable(); + return false; +} + void PacketCapture::eval(Packet* p) { if ( config.enabled ) { if ( !capture_initialized() ) - if ( !capture_init() ) + if ( !capture_init() ) return; if ( !bpf.bf_insns || bpf_filter(bpf.bf_insns, p->pkt, @@ -111,53 +217,6 @@ void PacketCapture::eval(Packet* p) capture_term(); } -bool PacketCapture::capture_init() -{ - if ( pcap_compile_nopcap(SNAP_LEN, DLT_EN10MB, &bpf, - config.filter.c_str(), 1, 0) >= 0 ) - { - if ( bpf_validate(bpf.bf_insns, bpf.bf_len) ) - { - string fname; - get_instance_file(fname, FILE_NAME); - - pcap = pcap_open_dead(DLT_EN10MB, SNAP_LEN); - dumper = open_dump(pcap, fname.c_str()); - - if ( dumper ) - return true; - else - WarningMessage("Could not initialize dump file\n"); - } - else - WarningMessage("Unable to validate BPF filter\n"); - } - else - WarningMessage("Unable to compile BPF filter\n"); - - packet_capture_disable(); - capture_term(); - return false; -} - -pcap_dumper_t* PacketCapture::open_dump(pcap_t* pcap, const char* fname) -{ return pcap_dump_open(pcap, fname); } - -void PacketCapture::capture_term() -{ - if ( dumper ) - { - pcap_dump_close(dumper); - dumper = nullptr; - } - if ( pcap ) - { - free(pcap); - pcap = nullptr; - } - pcap_freecode(&bpf); -} - void PacketCapture::write_packet(Packet* p) { //DAQ_PktHdr_t is compatible with pcap_pkthdr @@ -219,6 +278,10 @@ const BaseApi* nin_packet_capture[] = nullptr }; +// -------------------------------------------------------------------------- +// unit tests +// -------------------------------------------------------------------------- + #ifdef UNIT_TEST static Packet* init_null_packet() { @@ -242,15 +305,24 @@ public: MockPacketCapture(CaptureModule* m) : PacketCapture(m) {} protected: - pcap_dumper_t* open_dump(pcap_t*, const char*) override - { return (pcap_dumper_t*)1; } - void write_packet(Packet* p) override { pcap.push_back(p); write_packet_called = true; } + bool capture_init() override + { + if (bpf_compile_and_validate()) + { + dumper = (pcap_dumper_t*)1; + return true; + } + _packet_capture_disable(); + capture_term(); + return false; + } + void capture_term() override { dumper = nullptr; @@ -271,12 +343,12 @@ TEST_CASE("toggle", "[PacketCapture]") CHECK ( !cap.write_packet_called ); cap.write_packet_called = false; - packet_capture_enable(""); + _packet_capture_enable(""); cap.eval(null_packet); CHECK ( cap.write_packet_called ); cap.write_packet_called = false; - packet_capture_disable(); + _packet_capture_disable(); cap.eval(null_packet); CHECK ( !cap.write_packet_called ); } @@ -296,13 +368,13 @@ TEST_CASE("lazy init", "[PacketCapture]") pc_dtor(real_cap); MockPacketCapture cap(mod); - packet_capture_enable(""); + _packet_capture_enable(""); CHECK ( (capture_initialized() == false) ); cap.eval(null_packet); CHECK ( (capture_initialized() == true) ); - packet_capture_disable(); + _packet_capture_disable(); CHECK ( (capture_initialized() == true) ); cap.eval(null_packet); @@ -328,13 +400,13 @@ TEST_CASE("blank filter", "[PacketCapture]") CaptureModule mod; MockPacketCapture cap(&mod); - packet_capture_enable(""); + _packet_capture_enable(""); cap.eval(&p); REQUIRE ( cap.pcap.size() ); CHECK ( cap.pcap[0] == &p ); - packet_capture_disable(); + _packet_capture_disable(); cap.eval(null_packet); } @@ -345,11 +417,11 @@ TEST_CASE("bad filter", "[PacketCapture]") CaptureModule mod; MockPacketCapture cap(&mod); - packet_capture_enable("this is garbage"); + _packet_capture_enable("this is garbage"); cap.eval(null_packet); CHECK ( (capture_initialized() == false) ); - packet_capture_enable( + _packet_capture_enable( "port 0 " "port 1 " "port 2 " @@ -413,8 +485,8 @@ TEST_CASE("bpf filter", "[PacketCapture]") cap_count_stats.checked = 0; cap_count_stats.matched = 0; - packet_capture_enable("ip host 10.82.240.82"); - packet_capture_enable(""); //Test double-enable guard + _packet_capture_enable("ip host 10.82.240.82"); + _packet_capture_enable(""); //Test double-enable guard cap.write_packet_called = false; cap.eval(&p_match); @@ -436,7 +508,7 @@ TEST_CASE("bpf filter", "[PacketCapture]") CHECK ( cap.pcap[0] == &p_match ); CHECK ( cap.pcap[1] == &p_match ); - packet_capture_disable(); + _packet_capture_disable(); cap.eval(null_packet); } #endif diff --git a/src/network_inspectors/packet_tracer/packet_tracer_module.cc b/src/network_inspectors/packet_tracer/packet_tracer_module.cc index 74bb97eda..28db49bc2 100644 --- a/src/network_inspectors/packet_tracer/packet_tracer_module.cc +++ b/src/network_inspectors/packet_tracer/packet_tracer_module.cc @@ -137,21 +137,19 @@ static int enable(lua_State* L) constraints.sport = sport; constraints.dport = dport; - main_broadcast_command(new PacketTracerDebug(&constraints)); + main_broadcast_command(new PacketTracerDebug(&constraints), true); return 0; } static int disable(lua_State*) { - main_broadcast_command(new PacketTracerDebug(nullptr)); + main_broadcast_command(new PacketTracerDebug(nullptr), true); return 0; } PacketTracerModule::PacketTracerModule() : Module(PACKET_TRACER_NAME, PACKET_TRACER_HELP, s_params) -{ -} - +{} bool PacketTracerModule::set(const char *, Value &v, SnortConfig*) {