From: Wei Wang (weiwa) Date: Fri, 17 Jan 2025 23:10:55 +0000 (+0000) Subject: Pull request #4564: pcap: Filter Geneve encapsulated packets using inner headers X-Git-Tag: 3.6.2.0~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=04d70424b7812208cfc35839020f24ffc6821dc4;p=thirdparty%2Fsnort3.git Pull request #4564: pcap: Filter Geneve encapsulated packets using inner headers Merge in SNORT/snort3 from ~WEIWA/snort3:weiwa-master-pcap-inner-pkt-filter to master Squashed commit of the following: commit beb09752e94427d25e5e0e548f32a03e87400a47 Author: Wei Wang Date: Fri Jan 17 00:49:23 2025 +0530 pcap: Filter Geneve encapsulated packets using inner headers --- diff --git a/src/network_inspectors/packet_capture/capture_module.cc b/src/network_inspectors/packet_capture/capture_module.cc index 06a0634a5..1fe0ce55e 100644 --- a/src/network_inspectors/packet_capture/capture_module.cc +++ b/src/network_inspectors/packet_capture/capture_module.cc @@ -53,6 +53,9 @@ static const Parameter s_capture[] = { "tenants", Parameter::PT_STRING, nullptr, nullptr, "comma-separated tenants filter to use for packet capturing" }, + { "check_inner_pkt", Parameter::PT_BOOL, nullptr, "true", + "apply filter on inner packet headers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -67,6 +70,9 @@ static const Parameter capture_params[] = { "tenants", Parameter::PT_STRING, nullptr, nullptr, "comma-separated tenants filter to use for packet capturing" }, + { "check_inner_pkt", Parameter::PT_BOOL, nullptr, "true", + "apply filter on inner packet headers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -93,7 +99,7 @@ THREAD_LOCAL ProfileStats cap_prof_stats; class PacketCaptureDebug : public AnalyzerCommand { public: - PacketCaptureDebug(const char* f, const int16_t g, const char* t); + PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci); bool execute(Analyzer&, void**) override; const char* stringify() override { return "PACKET_CAPTURE_DEBUG"; } private: @@ -101,6 +107,7 @@ private: std::string filter; int16_t group = -1; std::string tenants; + bool check_inner_pkt = true; }; // ----------------------------------------------------------------------------- @@ -109,13 +116,13 @@ private: static int enable(lua_State* L) { main_broadcast_command(new PacketCaptureDebug(luaL_optstring(L, 1, ""), - luaL_optint(L, 2, 0), luaL_optstring(L, 3, "")), ControlConn::query_from_lua(L)); + luaL_optint(L, 2, 0), luaL_optstring(L, 3, ""), luaL_opt(L, lua_toboolean, 4, true)), ControlConn::query_from_lua(L)); return 0; } static int disable(lua_State* L) { - main_broadcast_command(new PacketCaptureDebug(nullptr, -1, nullptr), ControlConn::query_from_lua(L)); + main_broadcast_command(new PacketCaptureDebug(nullptr, -1, nullptr, true), ControlConn::query_from_lua(L)); return 0; } @@ -123,7 +130,7 @@ static int disable(lua_State* L) // non-static functions // ----------------------------------------------------------------------------- -PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const char* t) +PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci) { if (f) { @@ -131,13 +138,14 @@ PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const cha group = g; enable = true; tenants = t == nullptr ? "" : t; + check_inner_pkt = ci; } } bool PacketCaptureDebug::execute(Analyzer&, void**) { if (enable) - packet_capture_enable(filter, group, tenants); + packet_capture_enable(filter, group, tenants, check_inner_pkt); else packet_capture_disable(); @@ -166,6 +174,9 @@ bool CaptureModule::set(const char*, Value& v, SnortConfig*) else if ( v.is("tenants") ) str_to_int_vector(v.get_string(), ',', config.tenants); + else if ( v.is("check_inner_pkt") ) + config.check_inner_pkt = v.get_bool(); + return true; } diff --git a/src/network_inspectors/packet_capture/capture_module.h b/src/network_inspectors/packet_capture/capture_module.h index 431824b75..7a01e9628 100644 --- a/src/network_inspectors/packet_capture/capture_module.h +++ b/src/network_inspectors/packet_capture/capture_module.h @@ -32,6 +32,7 @@ struct CaptureConfig int16_t group; std::string filter; std::vector tenants; + bool check_inner_pkt; }; struct CaptureStats diff --git a/src/network_inspectors/packet_capture/packet_capture.cc b/src/network_inspectors/packet_capture/packet_capture.cc index ca9197e70..b093ce729 100644 --- a/src/network_inspectors/packet_capture/packet_capture.cc +++ b/src/network_inspectors/packet_capture/packet_capture.cc @@ -132,13 +132,14 @@ static bool open_pcap_dumper() } // for unit test -static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "") +static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "", const bool ci = true) { if ( !config.enabled ) { config.filter = f; config.enabled = true; config.group = g; + config.check_inner_pkt = ci; str_to_int_vector(t, ',', config.tenants); } } @@ -149,6 +150,7 @@ static void _packet_capture_disable() config.enabled = false; config.group = -1; config.tenants.clear(); + config.check_inner_pkt = true; LogMessage("Packet capture disabled\n"); } @@ -156,10 +158,10 @@ static void _packet_capture_disable() // non-static functions // ----------------------------------------------------------------------------- -void packet_capture_enable(const string& f, const int16_t g, const string& t) +void packet_capture_enable(const string& f, const int16_t g, const string& t, const bool ci) { - _packet_capture_enable(f, g, t); + _packet_capture_enable(f, g, t, ci); if ( !capture_initialized() ) { @@ -263,8 +265,30 @@ void PacketCapture::eval(Packet* p) } } - if ( !bpf.bf_insns || bpf_filter(bpf.bf_insns, p->pkt, - p->pktlen, p->pkth->pktlen) ) + bool matched_filter = false; + if (!bpf.bf_insns) + { + matched_filter = true; + } + else + { + const uint8_t* filter_pkt = p->pkt; + uint32_t filter_pkt_len = p->pktlen; + uint32_t filter_pkth_len = p->pkth->pktlen; + if (config.check_inner_pkt) + { + uint16_t inner_offset = p->get_inner_pkt_offset(); + if (inner_offset > 0 && inner_offset < filter_pkt_len && inner_offset < filter_pkth_len) + { + filter_pkt += inner_offset; + filter_pkt_len -= inner_offset; + filter_pkth_len -= inner_offset; + } + } + matched_filter = bpf_filter(bpf.bf_insns, filter_pkt, filter_pkt_len, filter_pkth_len); + } + + if (matched_filter) { write_packet(p); cap_count_stats.matched++; diff --git a/src/network_inspectors/packet_capture/packet_capture.h b/src/network_inspectors/packet_capture/packet_capture.h index 33f4f053e..4a14ec259 100644 --- a/src/network_inspectors/packet_capture/packet_capture.h +++ b/src/network_inspectors/packet_capture/packet_capture.h @@ -23,7 +23,7 @@ #include #include -void packet_capture_enable(const std::string&, const int16_t g = -1, const std::string& t = ""); +void packet_capture_enable(const std::string&, const int16_t g = -1, const std::string& t = "", const bool ci = true); void packet_capture_disable(); #endif diff --git a/src/protocols/packet.cc b/src/protocols/packet.cc index e0785230a..c74bfb46d 100644 --- a/src/protocols/packet.cc +++ b/src/protocols/packet.cc @@ -284,6 +284,28 @@ std::vector Packet::get_geneve_options(bool inner) return {}; } +uint16_t Packet::get_inner_pkt_offset() const +{ + uint16_t offset = 0; + if (num_layers > 0 && proto_bits & PROTO_BIT__GENEVE) + { + for (int i = num_layers-1; i >= 0; i--) + { + if (layers[i].prot_id == ProtocolId::GENEVE) + { + offset = layers[i].start - layers[0].start + layers[i].length; + break; + } + } + } + // TODO: Add support for other encapsulation types + + if (offset >= pktlen) + return 0; + + return offset; +} + bool Packet::is_from_application_client() const { if (flow) diff --git a/src/protocols/packet.h b/src/protocols/packet.h index de46a25d9..03705e872 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -354,6 +354,16 @@ struct SO_PUBLIC Packet uint32_t get_flow_geneve_vni() const; std::vector get_geneve_options(bool inner) const; + /* + * Get the offset of the inner packet if the packet is encapsulated in an outer packet + * like a Geneve packet, or 0 otherwise. Note this MUST be called when this packet's + * "layers" field is fully populated. + * @return the first byte index of the inner packet - the actual customer traffic + * packet - in this packet's "pkt" field if it is encapsulated, or 0 if it + * is not encapsulated. + */ + uint16_t get_inner_pkt_offset() const; + int16_t get_ingress_group() const { if (is_inter_group_flow())