]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1022 in SNORT/snort3 from snort_daq_packet_retry to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Mon, 25 Sep 2017 23:38:06 +0000 (19:38 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Mon, 25 Sep 2017 23:38:06 +0000 (19:38 -0400)
Squashed commit of the following:

commit c5eaf9f5a8d381a829df5e159eae3fed26309171
Author: davis mcpherson <davmcphe.cisco.com>
Date:   Thu Aug 10 15:01:28 2017 -0400

    implement snort support for DAQ_VERDICT_RETRY feature

    add reg test inspector to facilitate regression testing, initially for the daq packet retry feature

    add reg test inspector service to facilated regression testing of snort++

    limit check of chp match strings to clear to the ones that may have actually been set during chp processing

15 files changed:
extra/configure.ac
extra/src/daqs/daq_regtest/daq_regtest.c
extra/src/inspectors/CMakeLists.txt
extra/src/inspectors/Makefile.am
extra/src/inspectors/reg_test/CMakeLists.txt [new file with mode: 0644]
extra/src/inspectors/reg_test/Makefile.am [new file with mode: 0644]
extra/src/inspectors/reg_test/reg_test.cc [new file with mode: 0644]
src/main/snort.cc
src/network_inspectors/appid/appid_config.h
src/network_inspectors/appid/appid_http_session.cc
src/network_inspectors/appid/appid_http_session.h
src/packet_io/active.cc
src/packet_io/active.h
src/packet_io/sfdaq.cc
src/packet_io/sfdaq.h

index e0930e05c93b84074f4c70326560d2090abba991..af02d8c4a55412e2d362d35a8de33e3b80e02c33 100644 (file)
@@ -48,6 +48,7 @@ src/daqs/daq_regtest/Makefile \
 src/inspectors/Makefile \
 src/inspectors/data_log/Makefile \
 src/inspectors/dpx/Makefile \
+src/inspectors/reg_test/Makefile \
 src/ips_options/Makefile \
 src/ips_options/find/Makefile \
 src/ips_options/ips_pkt_num/Makefile \
index 637372e46d69a85dbb1e4169f309332d191fa2bc..5898ba144972bfcb60e5a60e48504848a18a4f7f 100644 (file)
 #include "config.h"
 #endif
 
+#include <daq.h>
+#include <daq_api.h>
 #include <stdlib.h>
 #include <string.h>
-#include <pcap.h>
-
-#include "daq.h"
-#include "daq_api.h"
 
 #define DAQ_MOD_VERSION 0
 #define DAQ_NAME "regtest"
@@ -49,32 +47,49 @@ typedef struct
     int daq_config_reads;
     const DAQ_Module_t* module;
     void *handle;
-    struct
-    {
-        int skip;
-        int trace;
-        void* user;
-        DAQ_Analysis_Func_t orig_daq_packet_callback;
-    } packt_tracer_cfg;
+    int skip;
+    int trace;
+    DAQ_PktHdr_t retry_hdr;
+    uint8_t* retry_data;
+    unsigned packets_before_retry;
+    unsigned retry_packet_countdown;
+    void* user;
+    DAQ_Analysis_Func_t wrapped_packet_callback;
 }DAQRegTestContext;
 
+static const DAQ_Verdict verdict_translation_table[MAX_DAQ_VERDICT] = {
+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_PASS */
+    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLOCK */
+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_REPLACE */
+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_WHITELIST */
+    DAQ_VERDICT_BLOCK,      /* DAQ_VERDICT_BLACKLIST */
+    DAQ_VERDICT_PASS,       /* DAQ_VERDICT_IGNORE */
+    DAQ_VERDICT_BLOCK       /* DAQ_VERDICT_RETRY */
+};
+
 // packet tracer configuration from command line daq-var skip and trace
 // --daq-var skip=10 --daq-var trace=5 would trace packets 11 through 15 only
 static void daq_regtest_get_vars(DAQRegTestContext* context, const DAQ_Config_t* cfg)
 {
     DAQ_Dict* entry;
 
-    context->packt_tracer_cfg.skip = 0;
-    context->packt_tracer_cfg.trace = 0;
+    context->skip = 0;
+    context->trace = 0;
+    context->packets_before_retry = 0;
+
     for ( entry = cfg->values; entry; entry = entry->next)
     {
         if ( !strcmp(entry->key, "skip") )
         {
-            context->packt_tracer_cfg.skip = atoi(entry->value);
+            context->skip = atoi(entry->value);
         }
         else if ( !strcmp(entry->key, "trace") )
         {
-            context->packt_tracer_cfg.trace = atoi(entry->value);
+            context->trace = atoi(entry->value);
+        }
+        else if ( !strcmp(entry->key, "packets_before_retry") )
+        {
+            context->packets_before_retry = atoi(entry->value);
         }
     }
 }
@@ -111,7 +126,7 @@ static int daq_regtest_parse_config(DAQRegTestContext *context, DAQRegTestConfig
         return DAQ_ERROR_NOMEM;
     }
     rewind(fh);
-    if ( fgets(config->buf , size, fh) == NULL )
+    if ( fgets(config->buf, size, fh) == NULL )
     {
         if ( errBuf )
             snprintf(errBuf, errMax, "%s: failed to read daq_regtest config file", DAQ_NAME);
@@ -149,6 +164,7 @@ static void daq_regtest_cleanup(DAQRegTestContext* context)
 
     free(context);
 }
+
 //-------------------------------------------------------------------------
 // daq
 //-------------------------------------------------------------------------
@@ -246,33 +262,84 @@ static int daq_regtest_inject (
     return context->module->inject(context->handle, hdr, buf, len, reverse);
 }
 
+static DAQ_Verdict daq_handle_retry_request(DAQRegTestContext* context, const DAQ_PktHdr_t* hdr,
+    const uint8_t* data)
+{
+    // FIXIT-L for current reg test needs or snort only 1 pending retry is required so if we
+    //         get a 2nd request we just let it pass.  future support for >1 pending retries
+    //         can be implemented with a list holding the hdr & data for each retry packet.
+    if ( !context->retry_data )
+    {
+        context->retry_hdr = *hdr;
+        context->retry_data = malloc(hdr->caplen);
+        if ( context->retry_data )
+        {
+            memcpy(context->retry_data, data, hdr->caplen);
+            context->retry_packet_countdown = context->packets_before_retry;
+            return DAQ_VERDICT_BLOCK;
+        }
+    }
+
+    return DAQ_VERDICT_PASS;
+}
+
+static void daq_handle_pending_retry(DAQRegTestContext* context)
+{
+    if ( !context->retry_packet_countdown )
+    {
+        context->retry_hdr.flags |= DAQ_PKT_FLAG_RETRY_PACKET;
+        DAQ_Verdict verdict = context->wrapped_packet_callback(context->user,
+            &context->retry_hdr, context->retry_data);
+
+        if (verdict >= MAX_DAQ_VERDICT)
+            verdict = DAQ_VERDICT_PASS;
+        verdict = verdict_translation_table[verdict];
+        if ( verdict == DAQ_VERDICT_PASS )
+            context->module->inject(context->handle, &context->retry_hdr, context->retry_data,
+                context->retry_hdr.pktlen, 0);
+        free(context->retry_data);
+        context->retry_data = NULL;
+    }
+    else
+        context->retry_packet_countdown--;
+}
+
 //-------------------------------------------------------------------------
 static DAQ_Verdict daq_regtest_packet_callback(void* user, const DAQ_PktHdr_t* hdr,
     const uint8_t* data)
 {
     DAQRegTestContext* context = (DAQRegTestContext*)user;
 
-    if (context->packt_tracer_cfg.skip == 0 && context->packt_tracer_cfg.trace >0)
+    if ( context->skip == 0 && context->trace > 0 )
     {
         DAQ_PktHdr_t* pkthdr = (DAQ_PktHdr_t*)hdr;
         pkthdr->flags |= DAQ_PKT_FLAG_TRACE_ENABLED;
     }
 
-    if (context->packt_tracer_cfg.skip > 0)
-        context->packt_tracer_cfg.skip--;
-    else if (context->packt_tracer_cfg.trace > 0)
-        context->packt_tracer_cfg.trace--;
+    if ( context->skip > 0 )
+        context->skip--;
+    else if ( context->trace > 0 )
+        context->trace--;
 
-    return context->packt_tracer_cfg.orig_daq_packet_callback(context->packt_tracer_cfg.user,
+    if ( context->retry_data )
+        daq_handle_pending_retry(context);
+
+    DAQ_Verdict verdict = context->wrapped_packet_callback(context->user,
         hdr, data);
+    if ( verdict == DAQ_VERDICT_RETRY )
+        verdict = daq_handle_retry_request(context, hdr, data);
+
+    return verdict;
 }
 
 static int daq_regtest_acquire (
     void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t meta, void* user)
 {
     DAQRegTestContext* context = (DAQRegTestContext*)handle;
-    context->packt_tracer_cfg.orig_daq_packet_callback = callback;
-    context->packt_tracer_cfg.user = user;
+    context->wrapped_packet_callback = callback;
+    context->user = user;
+    context->retry_data = NULL;
+
     return context->module->acquire(context->handle, cnt, daq_regtest_packet_callback, meta, handle);
 }
 
@@ -311,7 +378,9 @@ static int daq_regtest_get_snaplen (void* handle)
 static uint32_t daq_regtest_get_capabilities (void* handle)
 {
     DAQRegTestContext* context = (DAQRegTestContext*)handle;
-    return context->module->get_capabilities(context->handle);
+    uint32_t caps = context->module->get_capabilities(context->handle);
+    caps |= DAQ_CAPA_RETRY;
+    return caps;
 }
 
 static int daq_regtest_get_datalink_type(void *handle)
index 147773538d9e127ac27d60977ba08eda6ee9ed66..5eba6ddac14e2f00f78ba4cc7180a296a50dc79d 100644 (file)
@@ -1,2 +1,3 @@
 add_subdirectory ( dpx )
 add_subdirectory ( data_log )
+add_subdirectory ( reg_test )
index d2ce3eb63ceb4406cf9b3aad2747d33be785467e..56a393b04ee336ac4688815f83f85d2e0e552272 100644 (file)
@@ -1,6 +1,7 @@
 SUBDIRS = \
 data_log \
-dpx
+dpx \
+reg_test
 
 AM_CPPFLAGS = @AM_CPPFLAGS@
 AM_CFLAGS= @AM_CFLAGS@
diff --git a/extra/src/inspectors/reg_test/CMakeLists.txt b/extra/src/inspectors/reg_test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9626cdf
--- /dev/null
@@ -0,0 +1,41 @@
+cmake_minimum_required ( VERSION 2.8.11 )
+project ( reg_test CXX )
+
+if ( APPLE )
+    set ( CMAKE_MACOSX_RPATH OFF )
+endif ( APPLE )
+
+include ( FindPkgConfig )
+pkg_search_module ( SNORT3 REQUIRED snort>=3 )
+
+add_library (
+    reg_test MODULE
+    reg_test.cc
+)
+
+if ( APPLE )
+    set_target_properties (
+        reg_test
+        PROPERTIES
+            LINK_FLAGS "-undefined dynamic_lookup"
+    )
+endif ( APPLE )
+
+set_target_properties (
+    reg_test
+    PROPERTIES
+        PREFIX ""
+)
+
+set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
+
+target_include_directories (
+    reg_test PUBLIC
+    ${SNORT3_INCLUDE_DIRS}
+)
+
+install (
+    TARGETS reg_test
+    LIBRARY
+        DESTINATION "lib/${CMAKE_PROJECT_NAME}/inspectors"
+)
diff --git a/extra/src/inspectors/reg_test/Makefile.am b/extra/src/inspectors/reg_test/Makefile.am
new file mode 100644 (file)
index 0000000..50c503c
--- /dev/null
@@ -0,0 +1,8 @@
+reg_testlibdir = $(pkglibdir)/inspectors
+
+AM_CXXFLAGS = @SNORT3_CFLAGS@ -std=c++11
+
+reg_testlib_LTLIBRARIES = reg_test.la
+reg_test_la_CXXFLAGS = $(AM_CXXFLAGS)
+reg_test_la_LDFLAGS  = -module -export-dynamic -avoid-version -shared
+reg_test_la_SOURCES  = reg_test.cc
diff --git a/extra/src/inspectors/reg_test/reg_test.cc b/extra/src/inspectors/reg_test/reg_test.cc
new file mode 100644 (file)
index 0000000..4ccb0f9
--- /dev/null
@@ -0,0 +1,207 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2017-2017 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// rti_service.cc author davis mcpherson <davmcphe@cisco.com>
+
+#include <time.h>
+
+#include "flow/flow.h"
+#include "framework/data_bus.h"
+#include "framework/inspector.h"
+#include "framework/module.h"
+#include "log/messages.h"
+#include "packet_io/active.h"
+#include "pub_sub/http_events.h"
+#include "time/packet_time.h"
+
+static const char* s_name = "reg_test";
+static const char* s_help = "The regression test inspector (rti) is used when special packet handling is required for a reg test";
+
+struct RtiStats
+{
+    PegCount total_packets;
+    PegCount retry_requests;
+    PegCount retry_packets;
+};
+
+const PegInfo rti_pegs[] =
+{
+    { CountType::SUM, "packets", "total packets" },
+    { CountType::SUM, "retry_requests", "total retry packets requested" },
+    { CountType::SUM, "retry_packets", "total retried packets received" },
+    { CountType::END, nullptr, nullptr }
+};
+
+static THREAD_LOCAL RtiStats rti_stats;
+
+//-------------------------------------------------------------------------
+// module stuff
+//-------------------------------------------------------------------------
+
+static const Parameter rti_params[] =
+{
+    { "test_daq_retry", Parameter::PT_BOOL, nullptr, "true",
+        "test daq packet retry feature" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+class RtiServiceModule : public Module
+{
+public:
+    RtiServiceModule() : Module(s_name, s_help, rti_params)
+    { }
+
+    const PegInfo* get_pegs() const override
+    { return rti_pegs; }
+
+    PegCount* get_counts() const override
+    { return (PegCount*)&rti_stats; }
+
+    bool set(const char*, Value& v, SnortConfig*) override;
+
+    bool is_test_daq_retry() { return test_daq_retry; }
+
+public:
+    bool test_daq_retry = true;
+};
+
+bool RtiServiceModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( v.is("test_daq_retry") )
+        test_daq_retry = v.get_bool();
+    else
+        return false;
+
+    return true;
+}
+
+//-------------------------------------------------------------------------
+// inspector stuff
+//-------------------------------------------------------------------------
+
+class RtiService : public Inspector
+{
+public:
+    RtiService(RtiServiceModule* mod);
+
+    void show(SnortConfig*) override;
+    void eval(Packet* p) override;
+    bool configure(SnortConfig*) override
+    { return true; }
+
+private:
+    bool test_daq_retry;
+    void do_daq_packet_retry_test(Packet* p);
+};
+
+RtiService::RtiService(RtiServiceModule* mod)
+{
+    test_daq_retry = mod->is_test_daq_retry();
+    rti_stats.total_packets = 0;
+}
+
+void RtiService::eval(Packet* p)
+{
+    if ( test_daq_retry )
+        do_daq_packet_retry_test(p);
+
+    rti_stats.total_packets++;
+}
+
+void RtiService::show(SnortConfig*)
+{
+    LogMessage("%s config:\n", s_name);
+}
+
+void RtiService::do_daq_packet_retry_test(Packet* p)
+{
+    static bool retry_packet = true;
+    static bool expect_retry_packet = false;
+    if (p->dsize)
+    {
+        if (p->data[0] == 'A')
+        {
+            if (retry_packet)
+            {
+                Active::daq_retry_packet(p);
+                retry_packet = false;
+                expect_retry_packet = true;
+                rti_stats.retry_requests++;
+            }
+            else if (expect_retry_packet)
+            {
+                if ( p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET )
+                {
+                    expect_retry_packet = false;
+                    rti_stats.retry_packets++;
+                }
+            }
+        }
+    }
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new RtiServiceModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static Inspector* rti_ctor(Module* m)
+{ return new RtiService((RtiServiceModule*)m); }
+
+static void rti_dtor(Inspector* p)
+{ delete p; }
+
+static const InspectApi rti_api
+{
+    {
+        PT_INSPECTOR,
+        sizeof(InspectApi),
+        INSAPI_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        s_name,
+        s_help,
+        mod_ctor,
+        mod_dtor
+    },
+    IT_PACKET,
+    (uint16_t)PktType::TCP | (uint16_t)PktType::UDP | (uint16_t)PktType::PDU,
+    nullptr, // buffers
+    s_name,  // service
+    nullptr, // pinit
+    nullptr, // pterm
+    nullptr, // tinit,
+    nullptr, // tterm,
+    rti_ctor,
+    rti_dtor,
+    nullptr, // ssn
+    nullptr  // reset
+};
+
+SO_PUBLIC const BaseApi* snort_plugins[] =
+{
+    &rti_api.base,
+    nullptr
+};
+
index cb8044e4336bf1391619970739fd65b93d10c79f..72331ee3724d6953d0f7d68e4f159b4ee3fdbb12 100644 (file)
@@ -873,7 +873,11 @@ DAQ_Verdict Snort::process_packet(
     }
 
     // process flow verdicts here
-    if ( Active::session_was_blocked() )
+    if ( Active::packet_retry_requested() )
+    {
+        return DAQ_VERDICT_RETRY;
+    }
+    else if ( Active::session_was_blocked() )
     {
         if ( !Active::can_block() )
             return DAQ_VERDICT_PASS;
index 3c92b9391c44608da4ed7d5a5e896f9264cdbcf4..38bfe2af7fdbba501262c1d33ce618ae0bee53a4 100644 (file)
@@ -125,13 +125,10 @@ public:
     NetworkSet* net_list = nullptr;
     std::array<NetworkSet*, MAX_ZONES> net_list_by_zone;
 #endif
-    std::array<AppId, APP_ID_PORT_ARRAY_SIZE> tcp_port_only;     ///< Service IDs for port-only TCP
-                                                                 // services
-    std::array<AppId, APP_ID_PORT_ARRAY_SIZE> udp_port_only;     ///< Service IDs for port-only UDP
-                                                                 // services
-    std::array<AppId, 255> ip_protocol;         ///< Service IDs for non-TCP / UDP protocol
-                                                // services
-    SF_LIST client_app_args;                ///< List of Client App arguments
+    std::array<AppId, APP_ID_PORT_ARRAY_SIZE> tcp_port_only;     // port-only TCP services
+    std::array<AppId, APP_ID_PORT_ARRAY_SIZE> udp_port_only;     // port-only UDP services
+    std::array<AppId, 255> ip_protocol;         // non-TCP / UDP protocol services
+    SF_LIST client_app_args;                    // List of Client App arguments
     // for each potential port, an sflist of PortExclusion structs
     AppIdPortExclusions tcp_port_exclusions_src;
     AppIdPortExclusions udp_port_exclusions_src;
index 8762a4b10fa695d4ca88d2e8a8ec7fccb870a705..f6efee5fe792c0450677c4f1f9d0d8623bb874a2 100644 (file)
@@ -1,5 +1,5 @@
 //--------------------------------------------------------------------------
-// Copyright (C) 2016-2017 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2017-2017 Cisco and/or its affiliates. All rights reserved.
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License Version 2 as published
@@ -76,9 +76,9 @@ AppIdHttpSession::~AppIdHttpSession()
                 snort_free(new_field[i]);
 }
 
-void AppIdHttpSession::free_chp_matches(ChpMatchDescriptor& cmd, unsigned max_matches)
+void AppIdHttpSession::free_chp_matches(ChpMatchDescriptor& cmd, unsigned num_matches)
 {
-    for (unsigned i = 0; i <= max_matches; i++)
+    for (unsigned i = 0; i <= num_matches; i++)
         if ( cmd.chp_matches[i].size() )
             cmd.chp_matches[i].clear();
 }
@@ -277,7 +277,7 @@ void AppIdHttpSession::process_chp_buffers()
             }
         }
 
-        free_chp_matches(cmd, NUMBER_OF_PTYPES-1);
+        free_chp_matches(cmd, MAX_PATTERN_TYPE);
 
         if ( !chp_candidate )
         {
index 6f9ae067aaa8b680046689acb7ffac5bb59ac81e..5af7f1383be6df2c8d6c4949b2947a7baf4e8dbe 100644 (file)
@@ -1,6 +1,5 @@
 //--------------------------------------------------------------------------
-// Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2005-2013 Sourcefire, Inc.
+// Copyright (C) 2017-2017 Cisco and/or its affiliates. All rights reserved.
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License Version 2 as published
index fc4ae9b30ef9624cdfcbdbb8b9abe62051c681d1..0d7b0a78c59d162defdf241d868f1ed9e7a7a5a4 100644 (file)
@@ -413,6 +413,23 @@ void Active::daq_drop_packet(const Packet* p)
     daq_update_status(p);
 }
 
+bool Active::daq_retry_packet(const Packet *p)
+{
+    bool retry_queued = false;
+
+    // FIXIT-M may need to confirm this packet is not a retransmit...2.9.x has a check for that
+    if ( !p->is_rebuilt() && ( active_action == ACT_PASS ) && SFDAQ::can_retry() )
+    {
+        if ( SFDAQ::forwarding_packet(p->pkth) )
+        {
+            active_action = ACT_RETRY;
+            retry_queued = true;
+        }
+    }
+
+    return retry_queued;
+}
+
 void Active::block_session(const Packet* p, bool force)
 {
     update_status(p, force);
index 7571c020df442454417cd09612f0e055f07191bb..89da24e1adb12e4ba7b8e3e7b5dbf794eb0dc80f 100644 (file)
@@ -37,7 +37,7 @@ public:
     { AST_ALLOW, AST_CANT, AST_WOULD, AST_FORCE, AST_MAX };
 
     enum ActiveAction
-    { ACT_PASS, ACT_DROP, ACT_BLOCK, ACT_RESET, ACT_MAX };
+    { ACT_PASS, ACT_DROP, ACT_BLOCK, ACT_RESET, ACT_RETRY, ACT_MAX };
 
 public:
     static bool init(SnortConfig*);
@@ -85,6 +85,7 @@ public:
 
     static void drop_packet(const Packet*, bool force = false);
     static void daq_drop_packet(const Packet*);
+    static bool daq_retry_packet(const Packet *p);
 
     static void block_session(const Packet* p, bool force = false);
     static void reset_session(const Packet* p, bool force = false);
@@ -98,6 +99,9 @@ public:
     static bool packet_was_dropped()
     { return ( active_action >= ACT_DROP ); }
 
+    static bool packet_retry_requested()
+    { return ( active_action == ACT_RETRY ); }
+
     static bool session_was_blocked()
     { return ( active_action >= ACT_BLOCK); }
 
index 6f9956488f0b2221a62f40dd544d545c50b5430e..cc33f440da4574f1daf0127f94dd600b71a432be 100644 (file)
@@ -246,6 +246,11 @@ bool SFDAQ::can_replace()
     return local_instance && local_instance->can_replace();
 }
 
+bool SFDAQ::can_retry()
+{
+    return local_instance && local_instance->can_retry();
+}
+
 int SFDAQ::inject(const DAQ_PktHdr_t* hdr, int rev, const uint8_t* buf, uint32_t len)
 {
     return local_instance->inject(hdr, rev, buf, len);
@@ -422,6 +427,11 @@ bool SFDAQInstance::can_replace()
     return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_REPLACE) != 0;
 }
 
+bool SFDAQInstance::can_retry()
+{
+    return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_RETRY) != 0;
+}
+
 bool SFDAQInstance::can_start_unprivileged()
 {
     return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_UNPRIV_START) != 0;
index b7a63c113ff10a7425101ecf1e98695e581d86bb..af0f31740475c32f64f240d0d5d4defcd4ecdde1 100644 (file)
@@ -55,6 +55,7 @@ public:
     bool can_inject();
     bool can_inject_raw();
     bool can_replace();
+    bool can_retry();
     bool can_start_unprivileged();
     bool can_whitelist();
 
@@ -100,6 +101,7 @@ public:
     static bool can_inject();
     static bool can_inject_raw();
     static bool can_replace();
+    static bool can_retry();
 
     // FIXIT-M X Temporary thread-local instance helpers to be removed when no longer needed
     static void set_local_instance(SFDAQInstance*);