]> 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>
Sat, 29 Jul 2023 06:00:12 +0000 (08:00 +0200)
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

(cherry picked from commit 0d9289014bd8f65c7100e7173f24f5c5ff9de0ac)

doc/userguide/configuration/exception-policies.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 2d394d0df9cdd45e9eaa2c2976b212605a3038bf..201a7a3ecb339391028b982be73f21289f75235e 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 473ce277d3a4709360a24dd06ae12cfb0bd5f7d2..34594c97808db3ff094907e1ddb7d90e58d08454 100644 (file)
@@ -169,7 +169,7 @@ struct AppLayerParserState_ {
     AppLayerDecoderEvents *decoder_events;
 };
 
-enum ExceptionPolicy g_applayerparser_error_policy = EXCEPTION_POLICY_IGNORE;
+enum ExceptionPolicy g_applayerparser_error_policy = EXCEPTION_POLICY_NOT_SET;
 
 static void AppLayerConfg(void)
 {
index dc6d8f1e20cb20b65924c556a7de37f8869e407e..d736edef2a094ec02370ab9a06d5b55a55954110 100644 (file)
@@ -481,11 +481,11 @@ void StreamTcpInitConfig(char quiet)
     SCLogConfig("memcap-policy: %u/%u", stream_config.ssn_memcap_policy,
             stream_config.reassembly_memcap_policy);
     stream_config.midstream_policy = ExceptionPolicyParse("stream.midstream-policy", true);
-    if (stream_config.midstream && stream_config.midstream_policy != EXCEPTION_POLICY_IGNORE) {
+    if (stream_config.midstream && stream_config.midstream_policy != EXCEPTION_POLICY_NOT_SET) {
         SCLogWarning(SC_WARN_COMPATIBILITY,
                 "stream.midstream_policy setting conflicting with stream.midstream enabled. "
                 "Ignoring stream.midstream_policy.");
-        stream_config.midstream_policy = EXCEPTION_POLICY_IGNORE;
+        stream_config.midstream_policy = EXCEPTION_POLICY_NOT_SET;
     }
 
     if (!quiet) {
@@ -961,7 +961,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");
@@ -1132,7 +1132,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 fac1ccdda88890338c2282df98ca9e64e743d328..6ebf24ba293fcda8316af05772677028abe4d092 100644 (file)
@@ -2607,6 +2607,8 @@ int PostConfLoadedSetup(SCInstance *suri)
         EngineModeSetIDS();
     }
 
+    SetMasterExceptionPolicy();
+
     AppLayerSetup();
 
     /* Suricata will use this umask if provided. By default it will use the
index a1ead767787db8a76acfd913acf47369c9c39d17..65fd5f4cec591289356328d4942aed1ff23db90e 100644 (file)
 #include "util-misc.h"
 #include "stream-tcp-reassemble.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);
-                PacketSetActionOnCurrentPkt(p, ACTION_PASS);
-                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");
 }
@@ -85,7 +116,7 @@ static enum ExceptionPolicy PickPacketAction(const char *option, enum ExceptionP
         case EXCEPTION_POLICY_BYPASS_FLOW:
             SCLogWarning(SC_ERR_INVALID_VALUE,
                     "flow actions not supported for %s, defaulting to \"ignore\"", option);
-            return EXCEPTION_POLICY_IGNORE;
+            return EXCEPTION_POLICY_NOT_SET;
         /* add all cases, to make sure new cases not handle will raise
          * errors */
         case EXCEPTION_POLICY_DROP_PACKET:
@@ -94,19 +125,29 @@ static enum ExceptionPolicy PickPacketAction(const char *option, enum ExceptionP
             break;
         case EXCEPTION_POLICY_REJECT:
             break;
-        case EXCEPTION_POLICY_IGNORE:
+        case EXCEPTION_POLICY_NOT_SET:
             break;
     }
     return p;
 }
 
+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;
@@ -115,7 +156,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;
@@ -124,7 +165,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(SC_ERR_INVALID_ARGUMENT,
@@ -137,8 +181,25 @@ enum ExceptionPolicy ExceptionPolicyParse(const char *option, const bool support
             policy = PickPacketAction(option, policy);
         }
 
+    } else if (strcmp(option, "exception-policy") == 0) {
+        /* not enabled, we won't change the master exception policy,
+             for now */
+        SCLogInfo("'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 0a3b78d9f7e63cfdfa3d3936c51f6c648df70b38..96e22c67503c28cdd5b47e7e141317daee5275a3 100644 (file)
@@ -23,7 +23,7 @@
 #define __UTIL_EXCEPTION_POLICY_H__
 
 enum ExceptionPolicy {
-    EXCEPTION_POLICY_IGNORE = 0,
+    EXCEPTION_POLICY_NOT_SET = 0,
     EXCEPTION_POLICY_PASS_PACKET,
     EXCEPTION_POLICY_PASS_FLOW,
     EXCEPTION_POLICY_BYPASS_FLOW,
@@ -32,10 +32,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 081378fb8dcc310c9cd94f0b86322192fe1d4ce8..eb985c260e9397e2ce98f6af3f3aefa84b73589c 100644 (file)
@@ -1129,6 +1129,18 @@ legacy:
 # packet. Default is 15
 #packet-alert-max: 15
 
+# Exception Policies
+#
+# Define a common behavior for all exception policies.
+# Default is ignore.
+# All values available for exception policies can be used, and there is one
+# extra option: auto - which means ignore (in Suricata 7.0 this changes to drop
+# in IPS mode).
+#
+# Exception policy values are: drop-packet, drop-flow, reject, bypass,
+# pass-packet, pass-flow, auto or ignore (disable).
+exception-policy: auto
+
 # IP Reputation
 #reputation-categories-file: @e_sysconfdir@iprep/categories.txt
 #default-reputation-path: @e_sysconfdir@iprep