]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4564: pcap: Filter Geneve encapsulated packets using inner headers
authorWei Wang (weiwa) <weiwa@cisco.com>
Fri, 17 Jan 2025 23:10:55 +0000 (23:10 +0000)
committerSteve Chew (stechew) <stechew@cisco.com>
Fri, 17 Jan 2025 23:10:55 +0000 (23:10 +0000)
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 <weiwa@cisco.com>
Date:   Fri Jan 17 00:49:23 2025 +0530

    pcap: Filter Geneve encapsulated packets using inner headers

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
src/protocols/packet.cc
src/protocols/packet.h

index 06a0634a55155ea21333b4fa0a7291961163dde3..1fe0ce55e447afdd923ac4314e04d6223894ea3a 100644 (file)
@@ -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;
 }
 
index 431824b753caa6654ca876809fee952d03f21bc6..7a01e9628753a794249c4e04f52079621dd33ae5 100644 (file)
@@ -32,6 +32,7 @@ struct CaptureConfig
     int16_t group;
     std::string filter;
     std::vector<uint32_t> tenants;
+    bool check_inner_pkt;
 };
 
 struct CaptureStats
index ca9197e70e50edb749eea494d4486af0333690c2..b093ce729723d77a97f7b0835f16ba0aa1cc3930 100644 (file)
@@ -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++;
index 33f4f053e0c87b30f797da212ce2c71f59a1b8b4..4a14ec2596355b731cfb057f4e1ed094d154228f 100644 (file)
@@ -23,7 +23,7 @@
 #include <cstdint>
 #include <string>
 
-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
index e0785230a57835ede4ff773333b146c7b049be19..c74bfb46dd4b101573e8fe27fee29a10e3998d0e 100644 (file)
@@ -284,6 +284,28 @@ std::vector<snort::geneve::GeneveOptData> 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)
index de46a25d96c9502166b9982d556c1ebd507d87a0..03705e8725aae90746e24ba6c1986ff5a0fcf1b0 100644 (file)
@@ -354,6 +354,16 @@ struct SO_PUBLIC Packet
     uint32_t get_flow_geneve_vni() const;
     std::vector<snort::geneve::GeneveOptData> 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())