exceptions: initial exception-policy implementation

Adds a framework for setting exception policies. These would be called
when the engine reaches some kind of exception condition, like hitting
a memcap or some traffic processing error.

The policy gives control over what should happen next: drop the packet,
drop the packet and flow, bypass, etc.

Implements the policy for:

    stream: If stream session or reassembly memcaps are hit call the
    memcap policy on the packet and flow.

    flow: Apply policy when memcap is reached and no flow could be
    freed up.

    defrag: Apply policy when no tracker could be picked up.

    app-layer: Apply ppolicy if a parser reaches an error state.

All options default to 'ignore', which means the default behavior
is unchanged.

Adds commandline options: add simulation options for exceptions. These
are only exposed if compiled with `--enable-debug`.

Ticket: #5214.
Ticket: #5215.
Ticket: #5216.
Ticket: #5218.
Ticket: #5194.
(cherry picked from commit 8580499ded)
pull/7544/head
Victor Julien 4 years ago
parent 3a55873eb8
commit 660484404f

@ -483,6 +483,7 @@ util-device.c util-device.h \
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 \

@ -169,6 +169,13 @@ struct AppLayerParserState_ {
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)
{
@ -1281,6 +1288,24 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow
/* 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,
@ -1614,6 +1639,8 @@ void AppLayerParserRegisterProtocolParsers(void)
{
SCEnter();
AppLayerConfg();
RegisterHTPParsers();
RegisterSSLParsers();
RegisterDCERPCParsers();

@ -40,14 +40,13 @@
#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
@ -292,6 +291,8 @@ static int TCPProtoDetectTriggerOpposingSide(ThreadVars *tv,
return ret;
}
extern enum ExceptionPolicy g_applayerparser_error_policy;
/** \todo data const
* \retval int -1 error
* \retval int 0 ok
@ -402,8 +403,7 @@ static int TCPProtoDetect(ThreadVars *tv,
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
@ -439,8 +439,7 @@ static int TCPProtoDetect(ThreadVars *tv,
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
@ -468,7 +467,7 @@ static int TCPProtoDetect(ThreadVars *tv,
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);
}
@ -520,8 +519,7 @@ static int TCPProtoDetect(ThreadVars *tv,
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
@ -553,7 +551,7 @@ static int TCPProtoDetect(ThreadVars *tv,
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;
@ -579,6 +577,12 @@ static int TCPProtoDetect(ThreadVars *tv,
}
}
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.
@ -640,6 +644,10 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
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;
}
@ -719,6 +727,10 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
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);
}
}
}
@ -807,6 +819,10 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow *
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);
}

@ -181,6 +181,7 @@ void DefragInitConfig(char quiet)
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;
@ -472,6 +473,14 @@ static inline int DefragTrackerCompare(DefragTracker *t, Packet *p)
*/
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 */
@ -491,6 +500,7 @@ static DefragTracker *DefragTrackerGetNew(Packet *p)
dt = DefragTrackerGetUsedDefragTracker();
if (dt == NULL) {
ExceptionPolicyApply(p, defrag_config.memcap_policy, PKT_DROP_REASON_DEFRAG_MEMCAP);
return NULL;
}
@ -499,6 +509,7 @@ static DefragTracker *DefragTrackerGetNew(Packet *p)
/* 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;
}

@ -72,6 +72,7 @@ typedef struct DefragConfig_ {
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

@ -62,6 +62,8 @@
#include "util-unittest.h"
#endif
#include "util-validate.h"
#define DEFAULT_DEFRAG_HASH_SIZE 0xffff
#define DEFAULT_DEFRAG_POOL_SIZE 0xffff
@ -620,8 +622,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker,
}
}
else {
/* Abort - should not happen. */
SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid address family, aborting.");
DEBUG_VALIDATE_BUG_ON(1);
return NULL;
}

@ -49,6 +49,7 @@
#include "output.h"
#include "output-flow.h"
#include "stream-tcp.h"
#include "util-exception-policy.h"
extern TcpStreamCnf stream_config;
@ -526,6 +527,11 @@ static inline Flow *FlowSpareSync(ThreadVars *tv, FlowLookupStruct *fls,
return f;
}
static inline void NoFlowHandleIPS(Packet *p)
{
ExceptionPolicyApply(p, flow_config.memcap_policy, PKT_DROP_REASON_FLOW_MEMCAP);
}
/**
* \brief Get a new flow
*
@ -537,10 +543,14 @@ static inline Flow *FlowSpareSync(ThreadVars *tv, FlowLookupStruct *fls,
*
* \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;
}
@ -561,6 +571,7 @@ static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, const Packet *p)
f = FlowGetUsedFlow(tv, fls->dtv, &p->ts);
if (f == NULL) {
NoFlowHandleIPS(p);
return NULL;
}
#ifdef UNITTESTS
@ -585,6 +596,7 @@ static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, const Packet *p)
#ifdef UNITTESTS
}
#endif
NoFlowHandleIPS(p);
return NULL;
}
@ -600,9 +612,8 @@ static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, const Packet *p)
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) {
@ -724,8 +735,7 @@ static inline void FromHashLockCMP(Flow *f)
*
* \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;

@ -77,8 +77,7 @@ typedef struct FlowBucket_ {
/* 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);

@ -589,6 +589,9 @@ void FlowInitConfig(char quiet)
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);

@ -28,6 +28,7 @@
typedef struct FlowStorageId FlowStorageId;
#include "decode.h"
#include "util-exception-policy.h"
#include "util-var.h"
#include "util-atomic.h"
#include "util-device.h"
@ -299,6 +300,8 @@ typedef struct FlowCnf_
uint32_t emerg_timeout_est;
uint32_t emergency_recovery;
enum ExceptionPolicy memcap_policy;
SC_ATOMIC_DECLARE(uint64_t, memcap);
} FlowConfig;

@ -27,6 +27,7 @@
#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;
@ -59,7 +60,13 @@ void CleanupPcapFileFileVars(PcapFileFileVars *pfv)
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();

@ -66,6 +66,7 @@
#include "util-profiling.h"
#include "util-validate.h"
#include "util-exception-policy.h"
#ifdef DEBUG
static SCMutex segment_pool_memuse_mutex;
@ -73,6 +74,10 @@ static uint64_t segment_pool_memuse = 0;
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;
@ -145,6 +150,13 @@ uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
*/
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)
@ -1888,6 +1900,9 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_
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);
}

@ -74,6 +74,7 @@
#include "util-validate.h"
#include "util-runmodes.h"
#include "util-random.h"
#include "util-exception-policy.h"
#include "source-pcap-file.h"
@ -107,7 +108,9 @@ static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *);
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;
@ -468,6 +471,11 @@ void StreamTcpInitConfig(char quiet)
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",
@ -700,11 +708,18 @@ static TcpSession *StreamTcpNewSession (Packet *p, int id)
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;
}
@ -5223,6 +5238,9 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq)
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;

@ -1,4 +1,4 @@
/* 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
@ -64,6 +64,9 @@ typedef struct TcpStreamCnf_ {
bool streaming_log_api;
enum ExceptionPolicy ssn_memcap_policy;
enum ExceptionPolicy reassembly_memcap_policy;
StreamingBufferConfig sbcnf;
} TcpStreamCnf;

@ -86,6 +86,7 @@
#include "source-pcap.h"
#include "source-pcap-file.h"
#include "source-pcap-file-helper.h"
#include "source-pfring.h"
@ -176,6 +177,8 @@
#include "util-plugin.h"
#include "util-exception-policy.h"
#include "rust.h"
/*
@ -1293,6 +1296,14 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri)
#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
@ -1662,6 +1673,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri)
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':

@ -0,0 +1,185 @@
/* 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

@ -0,0 +1,50 @@
/* 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
Loading…
Cancel
Save