util-ebpf.c util-ebpf.h \
util-enum.c util-enum.h \
util-error.c util-error.h \
+util-exception-policy.c util-exception-policy.h \
util-file.c util-file.h \
util-file-decompression.c util-file-decompression.h \
util-file-swf-decompression.c util-file-swf-decompression.h \
AppLayerDecoderEvents *decoder_events;
};
+enum ExceptionPolicy g_applayerparser_error_policy = EXCEPTION_POLICY_IGNORE;
+
+static void AppLayerConfg(void)
+{
+ g_applayerparser_error_policy = ExceptionPolicyParse("app-layer.error-policy", true);
+}
+
#ifdef UNITTESTS
void UTHAppLayerParserStateGetIds(void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min)
{
/* invoke the recursive parser, but only on data. We may get empty msgs on EOF */
if (input_len > 0 || (flags & STREAM_EOF)) {
+#ifdef DEBUG
+ uint64_t offset = 0;
+ if (f->proto == IPPROTO_TCP && f->protoctx != NULL) {
+ TcpSession *ssn = f->protoctx;
+ TcpStream *stream = (flags & STREAM_TOSERVER) ? &ssn->client : &ssn->server;
+ offset = STREAM_APP_PROGRESS(stream);
+ }
+ if (((flags & STREAM_TOSERVER) && offset >= g_eps_applayer_error_offset_ts)) {
+ SCLogNotice("putting parser %s into an error state from toserver offset %" PRIu64,
+ AppProtoToString(alproto), g_eps_applayer_error_offset_ts);
+ goto error;
+ }
+ if (((flags & STREAM_TOCLIENT) && offset >= g_eps_applayer_error_offset_tc)) {
+ SCLogNotice("putting parser %s into an error state from toclient offset %" PRIu64,
+ AppProtoToString(alproto), g_eps_applayer_error_offset_tc);
+ goto error;
+ }
+#endif
/* invoke the parser */
AppLayerResult res = p->Parser[direction](f, alstate, pstate,
input, input_len,
{
SCEnter();
+ AppLayerConfg();
+
RegisterHTPParsers();
RegisterSSLParsers();
RegisterDCERPCParsers();
#include "flow-util.h"
#include "flow-private.h"
#include "ippair.h"
-
#include "util-debug.h"
#include "util-print.h"
#include "util-profiling.h"
#include "util-validate.h"
#include "decode-events.h"
-
#include "app-layer-htp-mem.h"
+#include "util-exception-policy.h"
/**
* \brief This is for the app layer in general and it contains per thread
return ret;
}
+extern enum ExceptionPolicy g_applayerparser_error_policy;
+
/** \todo data const
* \retval int -1 error
* \retval int 0 ok
if (TCPProtoDetectTriggerOpposingSide(tv, ra_ctx,
p, ssn, *stream) != 0)
{
- DisableAppLayer(tv, f, p);
- SCReturnInt(-1);
+ goto detect_error;
}
if (FlowChangeProto(f)) {
/* We have the first data which requested a protocol change from P1 to P2
if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) {
AppLayerDecoderEventsSetEventRaw(&p->app_layer_events,
APPLAYER_WRONG_DIRECTION_FIRST_DATA);
- DisableAppLayer(tv, f, p);
- SCReturnInt(-1);
+ goto detect_error;
}
/* This can happen if the current direction is not the
* right direction, and the data from the other(also
flags, data, data_len);
PACKET_PROFILING_APP_END(app_tctx, f->alproto);
if (r < 0) {
- SCReturnInt(-1);
+ goto parser_error;
} else if (r == 0) {
StreamTcpUpdateAppLayerProgress(ssn, direction, data_len);
}
if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) &&
(first_data_dir) && !(first_data_dir & flags))
{
- DisableAppLayer(tv, f, p);
- SCReturnInt(-1);
+ goto detect_error;
}
/* if protocol detection is marked done for our direction we
SCLogDebug("packet %"PRIu64": pd done(us %u them %u), parser called (r==%d), APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION set",
p->pcap_cnt, *alproto, *alproto_otherdir, r);
if (r < 0) {
- SCReturnInt(-1);
+ goto parser_error;
}
}
*alproto = ALPROTO_FAILED;
}
}
SCReturnInt(0);
+parser_error:
+ ExceptionPolicyApply(p, g_applayerparser_error_policy, PKT_DROP_REASON_APPLAYER_ERROR);
+ SCReturnInt(-1);
+detect_error:
+ DisableAppLayer(tv, f, p);
+ SCReturnInt(-2);
}
/** \brief handle TCP data for the app-layer.
PACKET_PROFILING_APP_END(app_tctx, f->alproto);
/* ignore parser result for gap */
StreamTcpUpdateAppLayerProgress(ssn, direction, data_len);
+ if (r < 0) {
+ ExceptionPolicyApply(p, g_applayerparser_error_policy, PKT_DROP_REASON_APPLAYER_ERROR);
+ SCReturnInt(-1);
+ }
goto end;
}
PACKET_PROFILING_APP_END(app_tctx, f->alproto);
if (r == 0) {
StreamTcpUpdateAppLayerProgress(ssn, direction, data_len);
+ } else if (r < 0) {
+ ExceptionPolicyApply(
+ p, g_applayerparser_error_policy, PKT_DROP_REASON_APPLAYER_ERROR);
+ SCReturnInt(-1);
}
}
}
PACKET_PROFILING_APP_END(tctx, f->alproto);
PACKET_PROFILING_APP_STORE(tctx, p);
}
+ if (r < 0) {
+ ExceptionPolicyApply(p, g_applayerparser_error_policy, PKT_DROP_REASON_APPLAYER_ERROR);
+ SCReturnInt(-1);
+ }
SCReturnInt(r);
}
defrag_config.hash_size = DEFRAG_DEFAULT_HASHSIZE;
defrag_config.prealloc = DEFRAG_DEFAULT_PREALLOC;
SC_ATOMIC_SET(defrag_config.memcap, DEFRAG_DEFAULT_MEMCAP);
+ defrag_config.memcap_policy = ExceptionPolicyParse("defrag.memcap-policy", false);
/* Check if we have memcap and hash_size defined at config */
const char *conf_val;
*/
static DefragTracker *DefragTrackerGetNew(Packet *p)
{
+#ifdef DEBUG
+ if (g_eps_defrag_memcap != UINT64_MAX && g_eps_defrag_memcap == p->pcap_cnt) {
+ SCLogNotice("simulating memcap hit for packet %" PRIu64, p->pcap_cnt);
+ ExceptionPolicyApply(p, defrag_config.memcap_policy, PKT_DROP_REASON_DEFRAG_MEMCAP);
+ return NULL;
+ }
+#endif
+
DefragTracker *dt = NULL;
/* get a tracker from the spare queue */
dt = DefragTrackerGetUsedDefragTracker();
if (dt == NULL) {
+ ExceptionPolicyApply(p, defrag_config.memcap_policy, PKT_DROP_REASON_DEFRAG_MEMCAP);
return NULL;
}
/* now see if we can alloc a new tracker */
dt = DefragTrackerAlloc();
if (dt == NULL) {
+ ExceptionPolicyApply(p, defrag_config.memcap_policy, PKT_DROP_REASON_DEFRAG_MEMCAP);
return NULL;
}
uint32_t hash_rand;
uint32_t hash_size;
uint32_t prealloc;
+ enum ExceptionPolicy memcap_policy;
} DefragConfig;
/** \brief check if a memory alloc would fit in the memcap
#include "util-unittest.h"
#endif
+#include "util-validate.h"
+
#define DEFAULT_DEFRAG_HASH_SIZE 0xffff
#define DEFAULT_DEFRAG_POOL_SIZE 0xffff
}
}
else {
- /* Abort - should not happen. */
- SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid address family, aborting.");
+ DEBUG_VALIDATE_BUG_ON(1);
return NULL;
}
#include "output.h"
#include "output-flow.h"
#include "stream-tcp.h"
+#include "util-exception-policy.h"
extern TcpStreamCnf stream_config;
return f;
}
+static inline void NoFlowHandleIPS(Packet *p)
+{
+ ExceptionPolicyApply(p, flow_config.memcap_policy, PKT_DROP_REASON_FLOW_MEMCAP);
+}
+
/**
* \brief Get a new flow
*
*
* \retval f *LOCKED* flow on succes, NULL on error.
*/
-static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, const Packet *p)
+static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, Packet *p)
{
const bool emerg = ((SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0);
-
+#ifdef DEBUG
+ if (g_eps_flow_memcap != UINT64_MAX && g_eps_flow_memcap == p->pcap_cnt) {
+ return NULL;
+ }
+#endif
if (FlowCreateCheck(p, emerg) == 0) {
return NULL;
}
f = FlowGetUsedFlow(tv, fls->dtv, &p->ts);
if (f == NULL) {
+ NoFlowHandleIPS(p);
return NULL;
}
#ifdef UNITTESTS
#ifdef UNITTESTS
}
#endif
+ NoFlowHandleIPS(p);
return NULL;
}
return f;
}
-static Flow *TcpReuseReplace(ThreadVars *tv, FlowLookupStruct *fls,
- FlowBucket *fb, Flow *old_f,
- const uint32_t hash, const Packet *p)
+static Flow *TcpReuseReplace(ThreadVars *tv, FlowLookupStruct *fls, FlowBucket *fb, Flow *old_f,
+ const uint32_t hash, Packet *p)
{
#ifdef UNITTESTS
if (tv != NULL && fls->dtv != NULL) {
*
* \retval f *LOCKED* flow or NULL
*/
-Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls,
- const Packet *p, Flow **dest)
+Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls, Packet *p, Flow **dest)
{
Flow *f = NULL;
/* prototypes */
-Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *tctx,
- const Packet *, Flow **);
+Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *tctx, Packet *, Flow **);
Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash);
Flow *FlowGetExistingFlowFromHash(FlowKey * key, uint32_t hash);
flow_config.prealloc = configval;
}
}
+
+ flow_config.memcap_policy = ExceptionPolicyParse("flow.memcap-policy", false);
+
SCLogDebug("Flow config from suricata.yaml: memcap: %"PRIu64", hash-size: "
"%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(flow_config.memcap),
flow_config.hash_size, flow_config.prealloc);
typedef struct FlowStorageId FlowStorageId;
#include "decode.h"
+#include "util-exception-policy.h"
#include "util-var.h"
#include "util-atomic.h"
#include "util-device.h"
uint32_t emerg_timeout_est;
uint32_t emergency_recovery;
+ enum ExceptionPolicy memcap_policy;
+
SC_ATOMIC_DECLARE(uint64_t, memcap);
} FlowConfig;
#include "util-checksum.h"
#include "util-profiling.h"
#include "source-pcap-file.h"
+#include "util-exception-policy.h"
extern int max_pending_packets;
extern PcapFileGlobalVars pcap_g;
void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt)
{
SCEnter();
-
+#ifdef DEBUG
+ if (unlikely((pcap_g.cnt + 1ULL) == g_eps_pcap_packet_loss)) {
+ SCLogNotice("skipping packet %" PRIu64, g_eps_pcap_packet_loss);
+ pcap_g.cnt++;
+ SCReturn;
+ }
+#endif
PcapFileFileVars *ptv = (PcapFileFileVars *)user;
Packet *p = PacketGetFromQueueOrAlloc();
#include "util-profiling.h"
#include "util-validate.h"
+#include "util-exception-policy.h"
#ifdef DEBUG
static SCMutex segment_pool_memuse_mutex;
static uint64_t segment_pool_memcnt = 0;
#endif
+#ifdef DEBUG
+thread_local uint64_t t_pcapcnt = UINT64_MAX;
+#endif
+
static PoolThread *segment_thread_pool = NULL;
/* init only, protect initializing and growing pool */
static SCMutex segment_thread_pool_mutex = SCMUTEX_INITIALIZER;
*/
int StreamTcpReassembleCheckMemcap(uint64_t size)
{
+#ifdef DEBUG
+ if (unlikely((g_eps_stream_reassembly_memcap != UINT64_MAX &&
+ g_eps_stream_reassembly_memcap == t_pcapcnt))) {
+ SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt);
+ return 0;
+ }
+#endif
uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.reassembly_memcap);
if (memcapcopy == 0 ||
(uint64_t)((uint64_t)size + SC_ATOMIC_GET(ra_memuse)) <= memcapcopy)
if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
+ /* failure can only be because of memcap hit, so see if this should lead to a drop */
+ ExceptionPolicyApply(
+ p, stream_config.reassembly_memcap_policy, PKT_DROP_REASON_STREAM_MEMCAP);
SCReturnInt(-1);
}
#include "util-validate.h"
#include "util-runmodes.h"
#include "util-random.h"
+#include "util-exception-policy.h"
#include "source-pcap-file.h"
static int StreamTcpStateDispatch(ThreadVars *tv, Packet *p,
StreamTcpThread *stt, TcpSession *ssn, PacketQueueNoLock *pq,
uint8_t state);
-
+#ifdef DEBUG
+extern thread_local uint64_t t_pcapcnt;
+#endif
extern int g_detect_disabled;
static PoolThread *ssn_pool = NULL;
stream_config.flags |= STREAMTCP_INIT_FLAG_INLINE;
}
}
+ stream_config.ssn_memcap_policy = ExceptionPolicyParse("stream.memcap-policy", true);
+ stream_config.reassembly_memcap_policy =
+ ExceptionPolicyParse("stream.reassembly.memcap-policy", true);
+ SCLogConfig("memcap-policy: %u/%u", stream_config.ssn_memcap_policy,
+ stream_config.reassembly_memcap_policy);
if (!quiet) {
SCLogConfig("stream.\"inline\": %s",
if (p->flow->protoctx != NULL)
ssn_pool_cnt++;
SCMutexUnlock(&ssn_pool_mutex);
-#endif
+ if (unlikely((g_eps_stream_ssn_memcap != UINT64_MAX &&
+ g_eps_stream_ssn_memcap == t_pcapcnt))) {
+ SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt);
+ ExceptionPolicyApply(p, stream_config.ssn_memcap_policy, PKT_DROP_REASON_STREAM_MEMCAP);
+ return NULL;
+ }
+#endif
ssn = (TcpSession *)p->flow->protoctx;
if (ssn == NULL) {
SCLogDebug("ssn_pool is empty");
+ ExceptionPolicyApply(p, stream_config.ssn_memcap_policy, PKT_DROP_REASON_STREAM_MEMCAP);
return NULL;
}
StreamTcpThread *stt = (StreamTcpThread *)data;
SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
+#ifdef DEBUG
+ t_pcapcnt = p->pcap_cnt;
+#endif
if (!(PKT_IS_TCP(p))) {
return TM_ECODE_OK;
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2022 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
bool streaming_log_api;
+ enum ExceptionPolicy ssn_memcap_policy;
+ enum ExceptionPolicy reassembly_memcap_policy;
+
StreamingBufferConfig sbcnf;
} TcpStreamCnf;
#include "source-pcap.h"
#include "source-pcap-file.h"
+#include "source-pcap-file-helper.h"
#include "source-pfring.h"
#include "util-plugin.h"
+#include "util-exception-policy.h"
+
#include "rust.h"
/*
#ifdef HAVE_NFLOG
{"nflog", optional_argument, 0, 0},
#endif
+ {"simulate-packet-flow-memcap", required_argument, 0, 0},
+ {"simulate-applayer-error-at-offset-ts", required_argument, 0, 0},
+ {"simulate-applayer-error-at-offset-tc", required_argument, 0, 0},
+ {"simulate-packet-loss", required_argument, 0, 0},
+ {"simulate-packet-tcp-reassembly-memcap", required_argument, 0, 0},
+ {"simulate-packet-tcp-ssn-memcap", required_argument, 0, 0},
+ {"simulate-packet-defrag-memcap", required_argument, 0, 0},
+
{NULL, 0, NULL, 0}
};
// clang-format on
if (suri->strict_rule_parsing_string == NULL) {
FatalError(SC_ERR_MEM_ALLOC, "failed to duplicate 'strict' string");
}
+ } else {
+ int r = ExceptionSimulationCommandlineParser(
+ (long_opts[option_index]).name, optarg);
+ if (r < 0)
+ return TM_ECODE_FAILED;
}
break;
case 'c':
--- /dev/null
+/* Copyright (C) 2022 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ */
+
+#include "suricata-common.h"
+#include "util-exception-policy.h"
+#include "util-misc.h"
+
+void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
+{
+ SCLogDebug("start: pcap_cnt %" PRIu64 ", policy %u", p->pcap_cnt, policy);
+ if (EngineModeIsIPS()) {
+ switch (policy) {
+ case EXCEPTION_POLICY_IGNORE:
+ break;
+ case EXCEPTION_POLICY_DROP_FLOW:
+ SCLogDebug("EXCEPTION_POLICY_DROP_FLOW");
+ if (p->flow) {
+ p->flow->flags |= FLOW_ACTION_DROP;
+ }
+ /* fall through */
+ case EXCEPTION_POLICY_DROP_PACKET:
+ SCLogDebug("EXCEPTION_POLICY_DROP_PACKET");
+ DecodeSetNoPayloadInspectionFlag(p);
+ DecodeSetNoPacketInspectionFlag(p);
+ PacketDrop(p, drop_reason);
+ break;
+ case EXCEPTION_POLICY_BYPASS_FLOW:
+ PacketBypassCallback(p);
+ /* fall through */
+ case EXCEPTION_POLICY_PASS_FLOW:
+ SCLogDebug("EXCEPTION_POLICY_PASS_FLOW");
+ if (p->flow) {
+ p->flow->flags |= FLOW_ACTION_PASS;
+ FlowSetNoPacketInspectionFlag(p->flow); // TODO util func
+ }
+ /* fall through */
+ case EXCEPTION_POLICY_PASS_PACKET:
+ SCLogDebug("EXCEPTION_POLICY_PASS_PACKET");
+ DecodeSetNoPayloadInspectionFlag(p);
+ DecodeSetNoPacketInspectionFlag(p);
+ PACKET_PASS(p);
+ break;
+ }
+ }
+ SCLogDebug("end");
+}
+
+enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support_flow)
+{
+ enum ExceptionPolicy policy = EXCEPTION_POLICY_IGNORE;
+ const char *value_str = NULL;
+ if ((ConfGet(option, &value_str)) == 1 && value_str != NULL) {
+ if (strcmp(value_str, "drop-flow") == 0) {
+ policy = EXCEPTION_POLICY_DROP_FLOW;
+ SCLogConfig("%s: %s", option, value_str);
+ } else if (strcmp(value_str, "pass-flow") == 0) {
+ policy = EXCEPTION_POLICY_PASS_FLOW;
+ SCLogConfig("%s: %s", option, value_str);
+ } else if (strcmp(value_str, "bypass") == 0) {
+ policy = EXCEPTION_POLICY_BYPASS_FLOW;
+ SCLogConfig("%s: %s", option, value_str);
+ } else if (strcmp(value_str, "drop-packet") == 0) {
+ policy = EXCEPTION_POLICY_DROP_PACKET;
+ SCLogConfig("%s: %s", option, value_str);
+ } else if (strcmp(value_str, "pass-packet") == 0) {
+ policy = EXCEPTION_POLICY_PASS_PACKET;
+ SCLogConfig("%s: %s", option, value_str);
+ } else if (strcmp(value_str, "ignore") == 0) { // TODO name?
+ policy = EXCEPTION_POLICY_IGNORE;
+ SCLogConfig("%s: %s", option, value_str);
+ } else {
+ SCLogConfig("%s: ignore", option);
+ }
+
+ if (!support_flow) {
+ if (policy == EXCEPTION_POLICY_DROP_FLOW || policy == EXCEPTION_POLICY_PASS_FLOW ||
+ policy == EXCEPTION_POLICY_BYPASS_FLOW) {
+ SCLogWarning(SC_WARN_COMPATIBILITY,
+ "flow actions not supported for %s, defaulting to \"ignore\"", option);
+ policy = EXCEPTION_POLICY_IGNORE;
+ }
+ }
+
+ } else {
+ SCLogConfig("%s: ignore", option);
+ }
+ return policy;
+}
+
+#ifndef DEBUG
+
+int ExceptionSimulationCommandlineParser(const char *name, const char *arg)
+{
+ return 0;
+}
+
+#else
+
+/* exception policy simulation (eps) handling */
+
+uint64_t g_eps_applayer_error_offset_ts = UINT64_MAX;
+uint64_t g_eps_applayer_error_offset_tc = UINT64_MAX;
+uint64_t g_eps_pcap_packet_loss = UINT64_MAX;
+uint64_t g_eps_stream_ssn_memcap = UINT64_MAX;
+uint64_t g_eps_stream_reassembly_memcap = UINT64_MAX;
+uint64_t g_eps_flow_memcap = UINT64_MAX;
+uint64_t g_eps_defrag_memcap = UINT64_MAX;
+
+/* 1: parsed, 0: not for us, -1: error */
+int ExceptionSimulationCommandlineParser(const char *name, const char *arg)
+{
+ if (strcmp(name, "simulate-applayer-error-at-offset-ts") == 0) {
+ BUG_ON(arg == NULL);
+ uint64_t offset = 0;
+ if (ParseSizeStringU64(arg, &offset) < 0) {
+ return -1;
+ }
+ g_eps_applayer_error_offset_ts = offset;
+ } else if (strcmp(name, "simulate-applayer-error-at-offset-tc") == 0) {
+ BUG_ON(arg == NULL);
+ uint64_t offset = 0;
+ if (ParseSizeStringU64(arg, &offset) < 0) {
+ return TM_ECODE_FAILED;
+ }
+ g_eps_applayer_error_offset_tc = offset;
+ } else if (strcmp(name, "simulate-packet-loss") == 0) {
+ BUG_ON(arg == NULL);
+ uint64_t pkt_num = 0;
+ if (ParseSizeStringU64(arg, &pkt_num) < 0) {
+ return TM_ECODE_FAILED;
+ }
+ g_eps_pcap_packet_loss = pkt_num;
+ } else if (strcmp(name, "simulate-packet-tcp-reassembly-memcap") == 0) {
+ BUG_ON(arg == NULL);
+ uint64_t pkt_num = 0;
+ if (ParseSizeStringU64(arg, &pkt_num) < 0) {
+ return TM_ECODE_FAILED;
+ }
+ g_eps_stream_reassembly_memcap = pkt_num;
+ } else if (strcmp(name, "simulate-packet-tcp-ssn-memcap") == 0) {
+ BUG_ON(arg == NULL);
+ uint64_t pkt_num = 0;
+ if (ParseSizeStringU64(arg, &pkt_num) < 0) {
+ return TM_ECODE_FAILED;
+ }
+ g_eps_stream_ssn_memcap = pkt_num;
+ } else if (strcmp(name, "simulate-packet-flow-memcap") == 0) {
+ BUG_ON(arg == NULL);
+ uint64_t pkt_num = 0;
+ if (ParseSizeStringU64(arg, &pkt_num) < 0) {
+ return TM_ECODE_FAILED;
+ }
+ g_eps_flow_memcap = pkt_num;
+ } else if (strcmp(name, "simulate-packet-defrag-memcap") == 0) {
+ BUG_ON(arg == NULL);
+ uint64_t pkt_num = 0;
+ if (ParseSizeStringU64(arg, &pkt_num) < 0) {
+ return TM_ECODE_FAILED;
+ }
+ g_eps_defrag_memcap = pkt_num;
+ } else {
+ // not for us
+ return 0;
+ }
+ return 1;
+}
+#endif
--- /dev/null
+/* Copyright (C) 2022 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ */
+
+#ifndef __UTIL_EXCEPTION_POLICY_H__
+#define __UTIL_EXCEPTION_POLICY_H__
+
+enum ExceptionPolicy {
+ EXCEPTION_POLICY_IGNORE = 0,
+ EXCEPTION_POLICY_PASS_PACKET,
+ EXCEPTION_POLICY_PASS_FLOW,
+ EXCEPTION_POLICY_BYPASS_FLOW,
+ EXCEPTION_POLICY_DROP_PACKET,
+ EXCEPTION_POLICY_DROP_FLOW,
+};
+
+void ExceptionPolicyApply(
+ Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason);
+enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support_flow);
+
+#ifdef DEBUG
+extern uint64_t g_eps_applayer_error_offset_ts;
+extern uint64_t g_eps_applayer_error_offset_tc;
+extern uint64_t g_eps_pcap_packet_loss;
+extern uint64_t g_eps_stream_ssn_memcap;
+extern uint64_t g_eps_stream_reassembly_memcap;
+extern uint64_t g_eps_flow_memcap;
+extern uint64_t g_eps_defrag_memcap;
+#endif
+
+int ExceptionSimulationCommandlineParser(const char *name, const char *arg);
+
+#endif