]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
exceptions: add master switch config option
authorJuliana Fajardini <jufajardini@oisf.net>
Tue, 6 Dec 2022 21:29:34 +0000 (18:29 -0300)
committerVictor Julien <vjulien@oisf.net>
Tue, 24 Jan 2023 10:08:37 +0000 (11:08 +0100)
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

doc/userguide/configuration/exception-policies.rst
doc/userguide/upgrade.rst
src/app-layer-parser.c
src/stream-tcp.c
src/suricata.c
src/util-exception-policy.c
src/util-exception-policy.h
suricata.yaml.in

index 2d49c5e936d128fb4b9636064a040a7700980aa3..cfa81c9bd2c33873be4ad373f2f75ade06decd36 100644 (file)
@@ -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
index 8c551a2b032960413c5b858e21b005875eda13a8..473c8cd488aac89f0c203b473eb650995cd4f6f7 100644 (file)
@@ -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 <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
 ~~~~~~~~~~~~~~~~
index b719397294ef17029a317f56f47f7239502d10db..66a7eec9149ccc28c515adc58d21ee3d58093431 100644 (file)
@@ -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)
 {
index cf914415eec5ae62e1789ad9d1217720d4e6dec8..e2d0e40dc0f805cfb8d6d28b154f91aec6d2b7b3 100644 (file)
@@ -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");
index a3e43ab7528ff7169d710848f362e3c73c7f9130..49b81d58976e6518dd761c669181a8cd6d72b5b7 100644 (file)
 #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(
index 8fb7ace473fe7a236a824e0ce0fc1de363e4fb8f..1d2f1a637e908930478adc3897f8472bf3c4567b 100644 (file)
 #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;
 }
index b10610ca0757ec65bc59e8af0bf5a095b049df78..5f2b2e956701406e816d8728a6980aca2b17fbbc 100644 (file)
@@ -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;
index aca16043ed86fb14166dd0e5d2274355aa3e9da7..74a8b60dc0ec93adab7d75bdd39940cb7581e401 100644 (file)
@@ -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