From: Juliana Fajardini Date: Tue, 6 Dec 2022 21:29:34 +0000 (-0300) Subject: exceptions: add master switch config option X-Git-Tag: suricata-7.0.0-rc1~82 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d9289014bd8f65c7100e7173f24f5c5ff9de0ac;p=thirdparty%2Fsuricata.git exceptions: add master switch config option This allows all traffic Exception Policies to be set from one configuration point. All exception policy options are available in IPS mode. Bypass, pass and auto (disabled) are also available in iDS mode Exception Policies set up individually will overwrite this setup for the given traffic exception. Task #5219 --- diff --git a/doc/userguide/configuration/exception-policies.rst b/doc/userguide/configuration/exception-policies.rst index 2d49c5e936..cfa81c9bd2 100644 --- a/doc/userguide/configuration/exception-policies.rst +++ b/doc/userguide/configuration/exception-policies.rst @@ -16,6 +16,45 @@ simulate failures or errors and understand Suricata behavior under such conditio Exception Policies ------------------ +.. _master-switch: + +Master Switch +~~~~~~~~~~~~~ + +It is possible to set all configuration policies via what we call "master +switch". This offers a quick way to define what the engine should do in case of +traffic exceptions, while still allowing for the flexibility of indicating a +different behavior for specific exception policies your setup/environment may +have the need to. + +:: + + # In IPS mode, the default is drop-packet/drop-flow. To fallback to old + # behavior (setting each of them individually, or ignoring all), set this + # to ignore. + # All values available for exception policies can be used, and there is one + # extra option: auto - which means drop-packet/drop-flow in IPS mode and + # ignore in IDS mode). + # Exception policy values are: drop-packet, drop-flow, reject, bypass, + # pass-packet, pass-flow, ignore (disable). + exception-policy: auto + +This value will be overwritten by specific exception policies whose settings are +also defined in the yaml file. + +Auto +'''' + +**In IPS mode**, the default behavior for all exception policies is to drop +packets and/or flows. It is possible to disable this default, by setting the +exception policies "master switch" yaml config option to ``ignore``. + +**In IDS mode**, setting auto mode actually means disabling the +``master-swtich``, or ignoring the exception policies. + +Specific settings +~~~~~~~~~~~~~~~~~ + Exception policies are implemented for: .. list-table:: Exception Policy configuration variables diff --git a/doc/userguide/upgrade.rst b/doc/userguide/upgrade.rst index 8c551a2b03..473c8cd488 100644 --- a/doc/userguide/upgrade.rst +++ b/doc/userguide/upgrade.rst @@ -36,6 +36,11 @@ Upgrading 6.0 to 7.0 Major changes ~~~~~~~~~~~~~ - Upgrade of PCRE1 to PCRE2. See :ref:`pcre-update-v1-to-v2` for more details. +- Introducing the :ref:`Exception Policy's Master Switch `. This + allows to setup a single policy for all traffic exceptions. This is a breaking + change for the default behavior in the Exception Policies: in IPS mode, if an + exception policy is not set, it will fall back to the the master switch now, + instead of being ignored. Prevent this by disabling the master switch. Security changes ~~~~~~~~~~~~~~~~ diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index b719397294..66a7eec914 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -156,7 +156,7 @@ struct AppLayerParserState_ { FramesContainer *frames; }; -enum ExceptionPolicy g_applayerparser_error_policy = EXCEPTION_POLICY_IGNORE; +enum ExceptionPolicy g_applayerparser_error_policy = EXCEPTION_POLICY_NOT_SET; static void AppLayerConfg(void) { diff --git a/src/stream-tcp.c b/src/stream-tcp.c index cf914415ee..e2d0e40dc0 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -945,7 +945,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, SCLogDebug("Midstream not enabled, so won't pick up a session"); return 0; } - if (!(stream_config.midstream_policy == EXCEPTION_POLICY_IGNORE || + if (!(stream_config.midstream_policy == EXCEPTION_POLICY_NOT_SET || stream_config.midstream_policy == EXCEPTION_POLICY_PASS_FLOW || stream_config.midstream_policy == EXCEPTION_POLICY_PASS_PACKET)) { SCLogDebug("Midstream policy not permissive, so won't pick up a session"); @@ -1118,7 +1118,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, SCLogDebug("Midstream not enabled, so won't pick up a session"); return 0; } - if (!(stream_config.midstream_policy == EXCEPTION_POLICY_IGNORE || + if (!(stream_config.midstream_policy == EXCEPTION_POLICY_NOT_SET || stream_config.midstream_policy == EXCEPTION_POLICY_PASS_FLOW || stream_config.midstream_policy == EXCEPTION_POLICY_PASS_PACKET)) { SCLogDebug("Midstream policy not permissive, so won't pick up a session"); diff --git a/src/suricata.c b/src/suricata.c index a3e43ab752..49b81d5897 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -125,6 +125,7 @@ #include "util-device.h" #include "util-dpdk.h" #include "util-ebpf.h" +#include "util-exception-policy.h" #include "util-host-os-info.h" #include "util-ioctl.h" #include "util-landlock.h" @@ -2640,6 +2641,8 @@ int PostConfLoadedSetup(SCInstance *suri) MacSetRegisterFlowStorage(); + SetMasterExceptionPolicy(); + LiveDeviceFinalize(); // must be after EBPF extension registration RunModeEngineIsIPS( diff --git a/src/util-exception-policy.c b/src/util-exception-policy.c index 8fb7ace473..1d2f1a637e 100644 --- a/src/util-exception-policy.c +++ b/src/util-exception-policy.c @@ -27,59 +27,101 @@ #include "stream-tcp-reassemble.h" #include "action-globals.h" +enum ExceptionPolicy g_eps_master_switch = EXCEPTION_POLICY_NOT_SET; + +static const char *ExceptionPolicyEnumToString(enum ExceptionPolicy policy) +{ + switch (policy) { + case EXCEPTION_POLICY_NOT_SET: + return "ignore"; + case EXCEPTION_POLICY_REJECT: + return "reject"; + case EXCEPTION_POLICY_BYPASS_FLOW: + return "bypass"; + case EXCEPTION_POLICY_DROP_FLOW: + return "drop-flow"; + case EXCEPTION_POLICY_DROP_PACKET: + return "drop-packet"; + case EXCEPTION_POLICY_PASS_PACKET: + return "pass-packet"; + case EXCEPTION_POLICY_PASS_FLOW: + return "pass-flow"; + } + // TODO we shouldn't reach this, but if we do, better not to leave this as simply null... + return "not set"; +} + +void SetMasterExceptionPolicy(void) +{ + g_eps_master_switch = ExceptionPolicyParse("exception-policy", true); +} + +static enum ExceptionPolicy GetMasterExceptionPolicy(const char *option) +{ + return g_eps_master_switch; +} + 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_REJECT: - SCLogDebug("EXCEPTION_POLICY_REJECT"); - PacketDrop(p, ACTION_REJECT, drop_reason); - /* fall through */ - case EXCEPTION_POLICY_DROP_FLOW: - SCLogDebug("EXCEPTION_POLICY_DROP_FLOW"); - if (p->flow) { - p->flow->flags |= FLOW_ACTION_DROP; - FlowSetNoPayloadInspectionFlag(p->flow); - FlowSetNoPacketInspectionFlag(p->flow); - StreamTcpDisableAppLayer(p->flow); - } - /* fall through */ - case EXCEPTION_POLICY_DROP_PACKET: - SCLogDebug("EXCEPTION_POLICY_DROP_PACKET"); - DecodeSetNoPayloadInspectionFlag(p); - DecodeSetNoPacketInspectionFlag(p); - PacketDrop(p, ACTION_DROP, 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); - break; - } + switch (policy) { + case EXCEPTION_POLICY_NOT_SET: + break; + case EXCEPTION_POLICY_REJECT: + SCLogDebug("EXCEPTION_POLICY_REJECT"); + PacketDrop(p, ACTION_REJECT, drop_reason); + /* fall through */ + case EXCEPTION_POLICY_DROP_FLOW: + SCLogDebug("EXCEPTION_POLICY_DROP_FLOW"); + if (p->flow) { + p->flow->flags |= FLOW_ACTION_DROP; + FlowSetNoPayloadInspectionFlag(p->flow); + FlowSetNoPacketInspectionFlag(p->flow); + StreamTcpDisableAppLayer(p->flow); + } + /* fall through */ + case EXCEPTION_POLICY_DROP_PACKET: + SCLogDebug("EXCEPTION_POLICY_DROP_PACKET"); + DecodeSetNoPayloadInspectionFlag(p); + DecodeSetNoPacketInspectionFlag(p); + PacketDrop(p, ACTION_DROP, 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); + break; } SCLogDebug("end"); } +static enum ExceptionPolicy SetIPSOption( + const char *option, const char *value_str, enum ExceptionPolicy p) +{ + if (!EngineModeIsIPS()) { + SCLogConfig("%s: %s not a valid config in IDS mode. Ignoring it.)", option, value_str); + return EXCEPTION_POLICY_NOT_SET; + } + return p; +} + enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support_flow) { - enum ExceptionPolicy policy = EXCEPTION_POLICY_IGNORE; + enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; 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; + policy = SetIPSOption(option, value_str, EXCEPTION_POLICY_DROP_FLOW); SCLogConfig("%s: %s", option, value_str); } else if (strcmp(value_str, "pass-flow") == 0) { policy = EXCEPTION_POLICY_PASS_FLOW; @@ -88,7 +130,7 @@ enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support policy = EXCEPTION_POLICY_BYPASS_FLOW; SCLogConfig("%s: %s", option, value_str); } else if (strcmp(value_str, "drop-packet") == 0) { - policy = EXCEPTION_POLICY_DROP_PACKET; + policy = SetIPSOption(option, value_str, EXCEPTION_POLICY_DROP_PACKET); SCLogConfig("%s: %s", option, value_str); } else if (strcmp(value_str, "pass-packet") == 0) { policy = EXCEPTION_POLICY_PASS_PACKET; @@ -97,7 +139,10 @@ enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support policy = EXCEPTION_POLICY_REJECT; SCLogConfig("%s: %s", option, value_str); } else if (strcmp(value_str, "ignore") == 0) { // TODO name? - policy = EXCEPTION_POLICY_IGNORE; + policy = EXCEPTION_POLICY_NOT_SET; + SCLogConfig("%s: %s", option, value_str); + } else if (strcmp(value_str, "auto") == 0) { + policy = SetIPSOption(option, value_str, EXCEPTION_POLICY_DROP_FLOW); SCLogConfig("%s: %s", option, value_str); } else { FatalErrorOnInit( @@ -110,12 +155,29 @@ enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support if (policy == EXCEPTION_POLICY_DROP_FLOW || policy == EXCEPTION_POLICY_PASS_FLOW || policy == EXCEPTION_POLICY_BYPASS_FLOW) { SCLogWarning("flow actions not supported for %s, defaulting to \"ignore\"", option); - policy = EXCEPTION_POLICY_IGNORE; + policy = EXCEPTION_POLICY_NOT_SET; } } + } else if (strcmp(option, "exception-policy") == 0) { + /* not enabled, we won't change the master exception policy, + for now */ + SCLogWarning("'exception-policy' master switch not set, so ignoring it." + " This behavior will change in Suricata 8, so please update your" + " config. See ticket #5219 for more details."); + g_eps_master_switch = EXCEPTION_POLICY_NOT_SET; } else { - SCLogConfig("%s: ignore", option); + /* Exception Policy was not defined individually */ + enum ExceptionPolicy master_policy = GetMasterExceptionPolicy(option); + if (master_policy == EXCEPTION_POLICY_NOT_SET) { + SCLogConfig("%s: ignore", option); + } else { + /* If the master switch was set and the Exception Policy option was not + individually set, use the defined master Exception Policy */ + const char *value = ExceptionPolicyEnumToString(master_policy); + SCLogConfig("%s: %s (defined via 'exception-policy' master switch", option, value); + policy = master_policy; + } } return policy; } diff --git a/src/util-exception-policy.h b/src/util-exception-policy.h index b10610ca07..5f2b2e9567 100644 --- a/src/util-exception-policy.h +++ b/src/util-exception-policy.h @@ -25,7 +25,7 @@ #include "decode.h" enum ExceptionPolicy { - EXCEPTION_POLICY_IGNORE = 0, + EXCEPTION_POLICY_NOT_SET = 0, EXCEPTION_POLICY_PASS_PACKET, EXCEPTION_POLICY_PASS_FLOW, EXCEPTION_POLICY_BYPASS_FLOW, @@ -34,10 +34,12 @@ enum ExceptionPolicy { EXCEPTION_POLICY_REJECT, }; +void SetMasterExceptionPolicy(void); void ExceptionPolicyApply( Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason); enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support_flow); +extern enum ExceptionPolicy g_eps_master_switch; #ifdef DEBUG extern uint64_t g_eps_applayer_error_offset_ts; extern uint64_t g_eps_applayer_error_offset_tc; diff --git a/suricata.yaml.in b/suricata.yaml.in index aca16043ed..74a8b60dc0 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1278,6 +1278,19 @@ legacy: # packet. Default is 15 #packet-alert-max: 15 +# Exception Policies +# +# Define a common behavior for all exception policies. +# In IPS mode, the default is drop-packet/drop-flow. To fallback to old +# behavior (setting each of them individually, or ignoring all), set this +# to ignore. +# All values available for exception policies can be used, and there is one +# extra option: auto - which means drop-packet/drop-flow in IPS mode and +# ignore in IDS mode). +# Exception policy values are: drop-packet, drop-flow, reject, bypass, +# pass-packet, pass-flow, ignore (disable). +exception-policy: auto + # IP Reputation #reputation-categories-file: @e_sysconfdir@iprep/categories.txt #default-reputation-path: @e_sysconfdir@iprep