summaryrefslogtreecommitdiffstats
path: root/src/util-action.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util-action.c')
-rw-r--r--src/util-action.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/util-action.c b/src/util-action.c
new file mode 100644
index 0000000..1b24bc5
--- /dev/null
+++ b/src/util-action.c
@@ -0,0 +1,440 @@
+/* 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
+ * 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
+ *
+ * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
+ */
+
+#include "suricata-common.h"
+
+#include "action-globals.h"
+#include "conf.h"
+#include "conf-yaml-loader.h"
+
+#include "detect.h"
+#include "detect-engine.h"
+#include "detect-engine-sigorder.h"
+
+#include "util-unittest.h"
+#include "util-action.h"
+#include "util-unittest-helper.h"
+#include "util-debug.h"
+
+/* Default order: */
+uint8_t action_order_sigs[4] = {ACTION_PASS, ACTION_DROP, ACTION_REJECT, ACTION_ALERT};
+/* This order can be changed from config */
+
+/**
+ * \brief Return the priority associated to an action (to order sigs
+ * as specified at config)
+ * action_order_sigs has this priority by index val
+ * so action_order_sigs[0] has to be inspected first.
+ * This function is called from detect-engine-sigorder
+ * \param action can be one of ACTION_PASS, ACTION_DROP,
+ * ACTION_REJECT or ACTION_ALERT
+ * \retval uint8_t the priority (order of this actions)
+ */
+uint8_t ActionOrderVal(uint8_t action)
+{
+ /* reject_both and reject_dst have the same prio as reject */
+ if( (action & ACTION_REJECT) ||
+ (action & ACTION_REJECT_BOTH) ||
+ (action & ACTION_REJECT_DST)) {
+ action = ACTION_REJECT;
+ }
+ uint8_t i = 0;
+ for (; i < 4; i++) {
+ if (action_order_sigs[i] == action)
+ return i;
+ }
+ /* Unknown action, set just a low prio (high val) */
+ return 10;
+}
+
+/**
+ * \brief Return the ACTION_* bit from their ascii value
+ * \param action can be one of "pass", "drop",
+ * "reject" or "alert"
+ * \retval uint8_t can be one of ACTION_PASS, ACTION_DROP,
+ * ACTION_REJECT or ACTION_ALERT
+ */
+static uint8_t ActionAsciiToFlag(const char *action)
+{
+ if (strcmp(action,"pass") == 0)
+ return ACTION_PASS;
+ if (strcmp(action,"drop") == 0)
+ return ACTION_DROP;
+ if (strcmp(action,"reject") == 0)
+ return ACTION_REJECT;
+ if (strcmp(action,"alert") == 0)
+ return ACTION_ALERT;
+
+ return 0;
+}
+
+/**
+ * \brief Load the action order from config. If none is provided,
+ * it will be default to ACTION_PASS, ACTION_DROP,
+ * ACTION_REJECT, ACTION_ALERT (pass has the highest prio)
+ *
+ * \retval 0 on success; -1 on fatal error;
+ */
+int ActionInitConfig(void)
+{
+ uint8_t actions_used = 0;
+ uint8_t action_flag = 0;
+ uint8_t actions_config[4] = {0, 0, 0, 0};
+ int order = 0;
+
+ ConfNode *action_order;
+ ConfNode *action = NULL;
+
+ /* Let's load the order of actions from the general config */
+ action_order = ConfGetNode("action-order");
+ if (action_order == NULL) {
+ /* No configuration, use defaults. */
+ return 0;
+ }
+ else {
+ TAILQ_FOREACH(action, &action_order->head, next) {
+ SCLogDebug("Loading action order : %s", action->val);
+ action_flag = ActionAsciiToFlag(action->val);
+ if (action_flag == 0) {
+ SCLogError("action-order, invalid action: \"%s\". Please, use"
+ " \"pass\",\"drop\",\"alert\",\"reject\". You have"
+ " to specify all of them, without quotes and without"
+ " capital letters",
+ action->val);
+ goto error;
+ }
+
+ if (actions_used & action_flag) {
+ SCLogError("action-order, action already set: \"%s\". Please,"
+ " use \"pass\",\"drop\",\"alert\",\"reject\". You"
+ " have to specify all of them, without quotes and"
+ " without capital letters",
+ action->val);
+ goto error;
+ }
+
+ if (order >= 4) {
+ SCLogError("action-order, you have already specified all the "
+ "possible actions plus \"%s\". Please, use \"pass\","
+ "\"drop\",\"alert\",\"reject\". You have to specify"
+ " all of them, without quotes and without capital"
+ " letters",
+ action->val);
+ goto error;
+ }
+ actions_used |= action_flag;
+ actions_config[order++] = action_flag;
+ }
+ }
+ if (order < 4) {
+ SCLogError("action-order, the config didn't specify all of the "
+ "actions. Please, use \"pass\",\"drop\",\"alert\","
+ "\"reject\". You have to specify all of them, without"
+ " quotes and without capital letters");
+ goto error;
+ }
+
+ /* Now, it's a valid config. Override the default preset */
+ for (order = 0; order < 4; order++) {
+ action_order_sigs[order] = actions_config[order];
+ }
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+#ifdef UNITTESTS
+
+/**
+ * \test Check that we invalidate duplicated actions
+ * (It should default to pass, drop, reject, alert)
+ */
+static int UtilActionTest01(void)
+{
+ char config[] = "\
+%YAML 1.1\n\
+---\n\
+action-order:\n\
+ - alert\n\
+ - drop\n\
+ - reject\n\
+ - alert\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ ActionInitConfig();
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
+ ConfRestoreContextBackup();
+
+ /* Restore default values */
+ action_order_sigs[0] = ACTION_PASS;
+ action_order_sigs[1] = ACTION_DROP;
+ action_order_sigs[2] = ACTION_REJECT;
+ action_order_sigs[3] = ACTION_ALERT;
+ PASS;
+}
+
+/**
+ * \test Check that we invalidate with unknown keywords
+ * (It should default to pass, drop, reject, alert)
+ */
+static int UtilActionTest02(void)
+{
+ char config[] = "\
+%YAML 1.1\n\
+---\n\
+action-order:\n\
+ - alert\n\
+ - drop\n\
+ - reject\n\
+ - ftw\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ ActionInitConfig();
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
+ ConfRestoreContextBackup();
+
+ /* Restore default values */
+ action_order_sigs[0] = ACTION_PASS;
+ action_order_sigs[1] = ACTION_DROP;
+ action_order_sigs[2] = ACTION_REJECT;
+ action_order_sigs[3] = ACTION_ALERT;
+ PASS;
+}
+
+/**
+ * \test Check that we invalidate if any action is missing
+ * (It should default to pass, drop, reject, alert)
+ */
+static int UtilActionTest03(void)
+{
+ char config[] = "\
+%YAML 1.1\n\
+---\n\
+action-order:\n\
+ - alert\n\
+ - drop\n\
+ - reject\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ ActionInitConfig();
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
+ ConfRestoreContextBackup();
+
+ /* Restore default values */
+ action_order_sigs[0] = ACTION_PASS;
+ action_order_sigs[1] = ACTION_DROP;
+ action_order_sigs[2] = ACTION_REJECT;
+ action_order_sigs[3] = ACTION_ALERT;
+ PASS;
+}
+
+/**
+ * \test Check that we invalidate if any action is missing
+ * (It should default to pass, drop, reject, alert)
+ */
+static int UtilActionTest04(void)
+{
+ char config[] = "\
+%YAML 1.1\n\
+---\n\
+action-order:\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ ActionInitConfig();
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
+ ConfRestoreContextBackup();
+
+ /* Restore default values */
+ action_order_sigs[0] = ACTION_PASS;
+ action_order_sigs[1] = ACTION_DROP;
+ action_order_sigs[2] = ACTION_REJECT;
+ action_order_sigs[3] = ACTION_ALERT;
+ PASS;
+}
+
+/**
+ * \test Check that we invalidate with unknown keywords
+ * and/or more than the expected
+ * (It should default to pass, drop, reject, alert)
+ */
+static int UtilActionTest05(void)
+{
+ char config[] = "\
+%YAML 1.1\n\
+---\n\
+action-order:\n\
+ - alert\n\
+ - drop\n\
+ - reject\n\
+ - pass\n\
+ - whatever\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ ActionInitConfig();
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
+ ConfRestoreContextBackup();
+
+ /* Restore default values */
+ action_order_sigs[0] = ACTION_PASS;
+ action_order_sigs[1] = ACTION_DROP;
+ action_order_sigs[2] = ACTION_REJECT;
+ action_order_sigs[3] = ACTION_ALERT;
+ PASS;
+}
+
+/**
+ * \test Check that we load a valid config
+ */
+static int UtilActionTest06(void)
+{
+ char config[] = "\
+%YAML 1.1\n\
+---\n\
+action-order:\n\
+ - alert\n\
+ - drop\n\
+ - reject\n\
+ - pass\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ ActionInitConfig();
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_ALERT);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_PASS);
+ ConfRestoreContextBackup();
+
+ /* Restore default values */
+ action_order_sigs[0] = ACTION_PASS;
+ action_order_sigs[1] = ACTION_DROP;
+ action_order_sigs[2] = ACTION_REJECT;
+ action_order_sigs[3] = ACTION_ALERT;
+ PASS;
+}
+
+/**
+ * \test Check that we load a valid config
+ */
+static int UtilActionTest07(void)
+{
+ char config[] = "\
+%YAML 1.1\n\
+---\n\
+action-order:\n\
+ - pass\n\
+ - alert\n\
+ - drop\n\
+ - reject\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ ActionInitConfig();
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_ALERT);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_REJECT);
+ ConfRestoreContextBackup();
+
+ /* Restore default values */
+ action_order_sigs[0] = ACTION_PASS;
+ action_order_sigs[1] = ACTION_DROP;
+ action_order_sigs[2] = ACTION_REJECT;
+ action_order_sigs[3] = ACTION_ALERT;
+ PASS;
+}
+
+/**
+ * \test Check that the expected defaults are loaded if the
+ * action-order configuration is not present.
+ */
+static int UtilActionTest08(void)
+{
+ char config[] = "%YAML 1.1\n"
+ "---\n";
+
+ ConfCreateContextBackup();
+ ConfInit();
+ ConfYamlLoadString(config, strlen(config));
+
+ FAIL_IF_NOT(ActionInitConfig() == 0);
+ FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
+ FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
+ FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
+ FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
+
+ ConfRestoreContextBackup();
+ PASS;
+}
+
+/* Register unittests */
+void UtilActionRegisterTests(void)
+{
+ /* Generic tests */
+ UtRegisterTest("UtilActionTest01", UtilActionTest01);
+ UtRegisterTest("UtilActionTest02", UtilActionTest02);
+ UtRegisterTest("UtilActionTest02", UtilActionTest02);
+ UtRegisterTest("UtilActionTest03", UtilActionTest03);
+ UtRegisterTest("UtilActionTest04", UtilActionTest04);
+ UtRegisterTest("UtilActionTest05", UtilActionTest05);
+ UtRegisterTest("UtilActionTest06", UtilActionTest06);
+ UtRegisterTest("UtilActionTest07", UtilActionTest07);
+ UtRegisterTest("UtilActionTest08", UtilActionTest08);
+}
+#endif