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 \
#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"
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);
}
}
}
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);
free(context);
}
+
//-------------------------------------------------------------------------
// daq
//-------------------------------------------------------------------------
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);
}
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)
add_subdirectory ( dpx )
add_subdirectory ( data_log )
+add_subdirectory ( reg_test )
SUBDIRS = \
data_log \
-dpx
+dpx \
+reg_test
AM_CPPFLAGS = @AM_CPPFLAGS@
AM_CFLAGS= @AM_CFLAGS@
--- /dev/null
+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"
+)
--- /dev/null
+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
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+};
+
}
// 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;
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;
//--------------------------------------------------------------------------
-// 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
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();
}
}
}
- free_chp_matches(cmd, NUMBER_OF_PTYPES-1);
+ free_chp_matches(cmd, MAX_PATTERN_TYPE);
if ( !chp_candidate )
{
//--------------------------------------------------------------------------
-// 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
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);
{ 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*);
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);
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); }
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);
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;
bool can_inject();
bool can_inject_raw();
bool can_replace();
+ bool can_retry();
bool can_start_unprivileged();
bool can_whitelist();
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*);