commit 60107a1: [Project] Add concept of flexible actions

Vsevolod Stakhov vsevolod at highsecure.ru
Mon Jan 14 18:00:04 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-01-13 14:22:04 +0000
URL: https://github.com/rspamd/rspamd/commit/60107a1f7d79df078c8528618c026858092d2d46

[Project] Add concept of flexible actions

---
 src/controller.c          |  6 ++--
 src/libmime/filter.c      |  2 +-
 src/libserver/cfg_file.h  | 40 +++++++++++++++++-----
 src/libserver/cfg_utils.c | 87 +++++++++++++++++++++++++++++++++++++++--------
 src/lua/lua_config.c      |  8 ++---
 5 files changed, 111 insertions(+), 32 deletions(-)

diff --git a/src/controller.c b/src/controller.c
index b8eface74..ee7e80e20 100644
--- a/src/controller.c
+++ b/src/controller.c
@@ -882,7 +882,7 @@ rspamd_controller_handle_actions (struct rspamd_http_connection_entry *conn_ent,
 				ucl_object_fromstring (rspamd_action_to_str (
 						act->action)), "action", 0, false);
 		ucl_object_insert_key (obj, ucl_object_fromdouble (
-				act->score), "value", 0, false);
+				act->threshold), "value", 0, false);
 		ucl_array_append (top, obj);
 	}
 
@@ -2238,8 +2238,8 @@ rspamd_controller_handle_saveactions (
 			score = ucl_object_todouble (cur);
 		}
 
-		if ((isnan (session->cfg->actions[act].score) != isnan (score)) ||
-				(session->cfg->actions[act].score != score)) {
+		if ((isnan (session->cfg->actions[act].threshold) != isnan (score)) ||
+				(session->cfg->actions[act].threshold != score)) {
 			add_dynamic_action (ctx->cfg, DEFAULT_METRIC, act, score);
 			added ++;
 		}
diff --git a/src/libmime/filter.c b/src/libmime/filter.c
index 94c9ac223..2bda47fe7 100644
--- a/src/libmime/filter.c
+++ b/src/libmime/filter.c
@@ -71,7 +71,7 @@ rspamd_create_metric_result (struct rspamd_task *task)
 
 	if (task->cfg) {
 		for (i = 0; i < METRIC_ACTION_MAX; i++) {
-			metric_res->actions_limits[i] = task->cfg->actions[i].score;
+			metric_res->actions_limits[i] = task->cfg->actions[i].threshold;
 		}
 	}
 	else {
diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h
index 6d6ed6f62..22b154943 100644
--- a/src/libserver/cfg_file.h
+++ b/src/libserver/cfg_file.h
@@ -29,6 +29,7 @@
 #include "libutil/radix.h"
 #include "monitored.h"
 #include "redis_pool.h"
+#include "contrib/uthash/uthash.h"
 
 #define DEFAULT_BIND_PORT 11333
 #define DEFAULT_CONTROL_PORT 11334
@@ -115,7 +116,7 @@ struct rspamd_symbols_group {
 #define RSPAMD_SYMBOL_FLAG_UNGROUPPED (1 << 3)
 
 /**
- * Symbol definition
+ * Symbol config definition
  */
 struct rspamd_symbol {
 	gchar *name;
@@ -258,6 +259,9 @@ struct rspamd_log_format {
 	struct rspamd_log_format *prev, *next;
 };
 
+/**
+ * Standard actions
+ */
 enum rspamd_action_type {
 	METRIC_ACTION_REJECT = 0,
 	METRIC_ACTION_SOFT_REJECT,
@@ -265,13 +269,28 @@ enum rspamd_action_type {
 	METRIC_ACTION_ADD_HEADER,
 	METRIC_ACTION_GREYLIST,
 	METRIC_ACTION_NOACTION,
-	METRIC_ACTION_MAX
+	METRIC_ACTION_MAX,
+	METRIC_ACTION_CUSTOM = 999,
+};
+
+enum rspamd_action_flags {
+	RSPAMD_ACTION_NORMAL = 0,
+	RSPAMD_ACTION_NO_THRESHOLD = (1u << 0),
+	RSPAMD_ACTION_THRESHOLD_ONLY = (1u << 1),
+	RSPAMD_ACTION_HAM = (1u << 2),
 };
 
+/**
+ * Action config definition
+ */
 struct rspamd_action {
 	enum rspamd_action_type action;
-	gdouble score;
+	enum rspamd_action_flags flags;
 	guint priority;
+	gint lua_handler_ref; /* If special handling is needed */
+	gdouble threshold;
+	gchar *name;
+	UT_hash_handle hh; /* Index by name */
 };
 
 struct rspamd_config_post_load_script {
@@ -300,8 +319,8 @@ struct rspamd_config {
 	gdouble grow_factor;                            /**< grow factor for metric							*/
 	GHashTable *symbols;                            /**< weights of symbols in metric					*/
 	const gchar *subject;                           /**< subject rewrite string							*/
-	GHashTable * groups; 		                    /**< groups of symbols								*/
-	struct rspamd_action actions[METRIC_ACTION_MAX]; /**< all actions of the metric						*/
+	GHashTable * groups;                            /**< groups of symbols								*/
+	struct rspamd_action *actions;                  /**< all actions of the metric						*/
 
 	gboolean raw_mode;                              /**< work in raw mode instead of utf one				*/
 	gboolean one_shot_mode;                         /**< rules add only one symbol							*/
@@ -626,14 +645,12 @@ gboolean rspamd_config_add_symbol_group (struct rspamd_config *cfg,
  * @param cfg config file
  * @param metric metric name (or NULL for default metric)
  * @param action_name symbolic name of action
- * @param score score limit
- * @param priority priority for action
+ * @param obj data to set for action
  * @return TRUE if symbol has been inserted or FALSE if action already exists with higher priority
  */
 gboolean rspamd_config_set_action_score (struct rspamd_config *cfg,
 		const gchar *action_name,
-		gdouble score,
-		guint priority);
+		const ucl_object_t *obj);
 
 /**
  * Checks if a specified C or lua module is enabled or disabled in the config.
@@ -662,6 +679,11 @@ gboolean rspamd_action_from_str (const gchar *data, gint *result);
 const gchar * rspamd_action_to_str (enum rspamd_action_type action);
 const gchar * rspamd_action_to_str_alt (enum rspamd_action_type action);
 
+/*
+ * Resort all actions (needed to operate with thresholds)
+ */
+void rspamd_actions_sort (struct rspamd_config *cfg);
+
 /**
  * Parse radix tree or radix map from ucl object
  * @param cfg configuration object
diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c
index a15bb9b8a..170595fb6 100644
--- a/src/libserver/cfg_utils.c
+++ b/src/libserver/cfg_utils.c
@@ -133,6 +133,29 @@ rspamd_config_new (enum rspamd_config_init_flags flags)
 	/* 16 sockets per DNS server */
 	cfg->dns_io_per_server = 16;
 
+	/* Add all internal actions to keep compatibility */
+	for (int i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i ++) {
+		struct rspamd_action *action;
+
+		action = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*action));
+		action->threshold = NAN;
+		action->name = rspamd_mempool_strdup (cfg->cfg_pool,
+				rspamd_action_to_str (i));
+		action->action = i;
+
+		if (i == METRIC_ACTION_SOFT_REJECT) {
+			action->flags |= RSPAMD_ACTION_NO_THRESHOLD;
+		}
+		else if (i == METRIC_ACTION_GREYLIST) {
+			action->flags |= RSPAMD_ACTION_THRESHOLD_ONLY;
+		}
+		else if (i == METRIC_ACTION_NOACTION) {
+			action->flags |= RSPAMD_ACTION_HAM;
+		}
+
+		HASH_ADD_STR (cfg->actions, name, action);
+	}
+
 	/* Disable timeout */
 	cfg->task_timeout = DEFAULT_TASK_TIMEOUT;
 
@@ -265,6 +288,8 @@ rspamd_config_free (struct rspamd_config *cfg)
 		rspamd_monitored_ctx_destroy (cfg->monitored_ctx);
 	}
 
+	HASH_CLEAR (hh, cfg->actions);
+
 	rspamd_mempool_delete (cfg->cfg_pool);
 
 	if (cfg->checksum) {
@@ -828,17 +853,17 @@ rspamd_config_post_load (struct rspamd_config *cfg,
 		struct rspamd_worker_conf *wcf;
 
 		for (i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i ++) {
-			if (!isnan (prev_score) && !isnan (cfg->actions[i].score)) {
-				if (prev_score <= isnan (cfg->actions[i].score)) {
+			if (!isnan (prev_score) && !isnan (cfg->actions[i].threshold)) {
+				if (prev_score <= isnan (cfg->actions[i].threshold)) {
 					msg_warn_config ("incorrect metrics scores: action %s"
 							" has lower score: %.2f than action %s: %.2f",
 							rspamd_action_to_str (prev_act), prev_score,
-							rspamd_action_to_str (i), cfg->actions[i].score);
+							rspamd_action_to_str (i), cfg->actions[i].threshold);
 					ret = FALSE;
 				}
 			}
 
-			if (!isnan (cfg->actions[i].score)) {
+			if (!isnan (cfg->actions[i].threshold)) {
 				prev_score = cfg->actions[i].score;
 				prev_act = i;
 			}
@@ -1890,25 +1915,26 @@ rspamd_config_is_module_enabled (struct rspamd_config *cfg,
 gboolean
 rspamd_config_set_action_score (struct rspamd_config *cfg,
 		const gchar *action_name,
-		gdouble score,
-		guint priority)
+		const ucl_object_t *obj)
 {
 	struct rspamd_action *act;
-	gint act_num;
+	const ucl_object_t *elt;
 
 	g_assert (cfg != NULL);
 	g_assert (action_name != NULL);
 
-	if (!rspamd_action_from_str (action_name, &act_num)) {
-		msg_err_config ("invalid action name: %s", action_name);
-		return FALSE;
-	}
-
-	g_assert (act_num >= METRIC_ACTION_REJECT && act_num < METRIC_ACTION_MAX);
+	HASH_FIND_STR (cfg->actions, action_name, act);
 
+	if (act) {
+		/* Existing element */
+	}
+	else {
+		/* Add new element */
+		act = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*act));
+	}
 	act = &cfg->actions[act_num];
 
-	if (isnan (act->score)) {
+	if (isnan (act->threshold)) {
 		act->score = score;
 		act->priority = priority;
 	}
@@ -1928,7 +1954,7 @@ rspamd_config_set_action_score (struct rspamd_config *cfg,
 					action_name,
 					act->priority,
 					priority,
-					act->score,
+					act->threshold,
 					score);
 
 			act->score = score;
@@ -2119,3 +2145,34 @@ rspamd_action_to_str_alt (enum rspamd_action_type action)
 
 	return "unknown action";
 }
+
+static int
+rspamd_actions_cmp (const struct rspamd_action *a1, const struct rspamd_action *a2)
+{
+	if (!isnan (a1->threshold) && !isnan (a2->threshold)) {
+		if (a1->threshold < a2->threshold) {
+			return -1;
+		}
+		else if (a1->threshold > a2->threshold) {
+			return 1;
+		}
+
+		return 0;
+	}
+
+	if (isnan (a1->threshold) && isnan (a2->threshold)) {
+		return 0;
+	}
+	else if (isnan (a1->threshold)) {
+		return 1;
+	}
+	else {
+		return -1;
+	}
+}
+
+void
+rspamd_actions_sort (struct rspamd_config *cfg)
+{
+	HASH_SORT (cfg->actions, rspamd_actions_cmp);
+}
diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c
index 31d4af79b..513c2da93 100644
--- a/src/lua/lua_config.c
+++ b/src/lua/lua_config.c
@@ -2170,8 +2170,8 @@ lua_config_get_metric_action (lua_State * L)
 
 	if (cfg && act_name) {
 		if (rspamd_action_from_str (act_name, &act)) {
-			if (!isnan (cfg->actions[act].score)) {
-				lua_pushnumber (L, cfg->actions[act].score);
+			if (!isnan (cfg->actions[act].threshold)) {
+				lua_pushnumber (L, cfg->actions[act].threshold);
 			}
 			else {
 				lua_pushnil (L);
@@ -2199,9 +2199,9 @@ lua_config_get_all_actions (lua_State * L)
 		lua_newtable (L);
 
 		for (act = METRIC_ACTION_REJECT; act < METRIC_ACTION_MAX; act ++) {
-			if (!isnan (cfg->actions[act].score)) {
+			if (!isnan (cfg->actions[act].threshold)) {
 				lua_pushstring (L, rspamd_action_to_str (act));
-				lua_pushnumber (L, cfg->actions[act].score);
+				lua_pushnumber (L, cfg->actions[act].threshold);
 				lua_settable (L, -3);
 			}
 		}


More information about the Commits mailing list