commit 96986ba: [Project] More steps to flexible actions

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


Author: Vsevolod Stakhov
Date: 2019-01-14 09:47:05 +0000
URL: https://github.com/rspamd/rspamd/commit/96986ba7f75858395a35c87305427b16eca96547

[Project] More steps to flexible actions

---
 src/libserver/cfg_file.h  |  13 ++++-
 src/libserver/cfg_utils.c | 135 ++++++++++++++++++++++++++++++++++++----------
 src/lua/lua_config.c      |  43 ++++++++++++---
 3 files changed, 152 insertions(+), 39 deletions(-)

diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h
index 22b154943..3a8094585 100644
--- a/src/libserver/cfg_file.h
+++ b/src/libserver/cfg_file.h
@@ -29,7 +29,6 @@
 #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
@@ -280,6 +279,7 @@ enum rspamd_action_flags {
 	RSPAMD_ACTION_HAM = (1u << 2),
 };
 
+struct UT_hash_handle;
 /**
  * Action config definition
  */
@@ -290,7 +290,7 @@ struct rspamd_action {
 	gint lua_handler_ref; /* If special handling is needed */
 	gdouble threshold;
 	gchar *name;
-	UT_hash_handle hh; /* Index by name */
+	struct UT_hash_handle hh; /* Index by name */
 };
 
 struct rspamd_config_post_load_script {
@@ -699,6 +699,15 @@ gboolean rspamd_config_radix_from_ucl (struct rspamd_config *cfg,
 		struct rspamd_radix_map_helper **target,
 		GError **err);
 
+/**
+ * Returns action object by name
+ * @param cfg
+ * @param name
+ * @return
+ */
+struct rspamd_action * rspamd_config_get_action (struct rspamd_config *cfg,
+												 const gchar *name);
+
 #define msg_err_config(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
         cfg->cfg_pool->tag.tagname, cfg->checksum, \
         G_STRFUNC, \
diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c
index 170595fb6..5e3193cba 100644
--- a/src/libserver/cfg_utils.c
+++ b/src/libserver/cfg_utils.c
@@ -17,6 +17,8 @@
 
 #include "cfg_file.h"
 #include "rspamd.h"
+#include "../../contrib/mumhash/mum.h"
+#define HASH_CASELESS
 #include "uthash_strcase.h"
 #include "filter.h"
 #include "lua/lua_common.h"
@@ -1038,12 +1040,6 @@ rspamd_config_init_metric (struct rspamd_config *cfg)
 	cfg->symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
 	cfg->groups = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
 
-	for (i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i++) {
-		cfg->actions[i].score = NAN;
-		cfg->actions[i].action = i;
-		cfg->actions[i].priority = 0;
-	}
-
 	cfg->subject = SPAM_SUBJECT;
 	rspamd_mempool_add_destructor (cfg->cfg_pool,
 			(rspamd_mempool_destruct_t) g_hash_table_unref,
@@ -1912,6 +1908,72 @@ rspamd_config_is_module_enabled (struct rspamd_config *cfg,
 	return TRUE;
 }
 
+static gboolean
+rspamd_config_action_from_ucl (struct rspamd_config *cfg,
+							   struct rspamd_action *act,
+							   const ucl_object_t *obj,
+							   guint priority)
+{
+	const ucl_object_t *elt;
+	gdouble threshold = NAN;
+	guint flags = 0, std_act;
+
+	elt = ucl_object_lookup_any (obj, "score", "threshold", NULL);
+
+	if (elt) {
+		threshold = ucl_object_todouble (elt);
+	}
+
+	elt = ucl_object_lookup_any (obj, "flags");
+
+	if (elt && ucl_object_type (elt) == UCL_ARRAY) {
+		const ucl_object_t *cur;
+		ucl_object_iter_t it = NULL;
+
+		while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
+			if (ucl_object_type (cur) == UCL_STRING) {
+				const gchar *fl_str = ucl_object_tostring (cur);
+
+				if (g_ascii_strcasecmp (fl_str, "no_threshold") == 0) {
+					flags |= RSPAMD_ACTION_NO_THRESHOLD;
+				}
+				else if (g_ascii_strcasecmp (fl_str, "threshold_only") == 0) {
+					flags |= RSPAMD_ACTION_THRESHOLD_ONLY;
+				}
+				else if (g_ascii_strcasecmp (fl_str, "ham") == 0) {
+					flags |= RSPAMD_ACTION_HAM;
+				}
+				else {
+					msg_warn_config ("unknown action flag: %s", fl_str);
+				}
+			}
+		}
+	}
+
+	/* TODO: add lua references support */
+
+	if (isnan (threshold) && !(flags & RSPAMD_ACTION_NO_THRESHOLD)) {
+		msg_err_config ("action %s has no threshold being set and it is not"
+				  " a no threshold action", act->name);
+
+		return FALSE;
+	}
+
+	act->threshold = threshold;
+	act->flags = flags;
+
+	if (rspamd_action_from_str (act->name, &std_act)) {
+		act->action = std_act;
+	}
+	else {
+		act->action = METRIC_ACTION_CUSTOM;
+	}
+
+	rspamd_actions_sort (cfg);
+
+	return TRUE;
+}
+
 gboolean
 rspamd_config_set_action_score (struct rspamd_config *cfg,
 		const gchar *action_name,
@@ -1919,52 +1981,67 @@ rspamd_config_set_action_score (struct rspamd_config *cfg,
 {
 	struct rspamd_action *act;
 	const ucl_object_t *elt;
+	guint priority = ucl_object_get_priority (obj);
 
 	g_assert (cfg != NULL);
 	g_assert (action_name != NULL);
 
+	elt = ucl_object_lookup (obj, "priority");
+
+	if (elt) {
+		priority = ucl_object_toint (elt);
+	}
+
 	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->threshold)) {
-		act->score = score;
-		act->priority = priority;
-	}
-	else {
-		if (act->priority > priority) {
+		if (act->priority <= priority) {
+			/* We can replace data */
 			msg_info_config ("action %s has been already registered with "
-					"priority %ud, do not override (new priority: %ud)",
+							 "priority %ud, override it with new priority: %ud, "
+							 "old score: %.2f, new score: %.2f",
 					action_name,
 					act->priority,
-					priority);
-			return FALSE;
+					priority,
+					act->threshold,
+					ucl_object_todouble (
+							ucl_object_lookup_any (obj, "score", "threshold", NULL)));
+			return rspamd_config_action_from_ucl (cfg, act, obj, priority);
 		}
 		else {
 			msg_info_config ("action %s has been already registered with "
-					"priority %ud, override it with new priority: %ud, "
-					"old score: %.2f, new score: %.2f",
+							 "priority %ud, do not override (new priority: %ud)",
 					action_name,
 					act->priority,
-					priority,
-					act->threshold,
-					score);
+					priority);
+		}
+	}
+	else {
+		/* Add new element */
+		act = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*act));
+		act->name = rspamd_mempool_strdup (cfg->cfg_pool, action_name);
 
-			act->score = score;
-			act->priority = priority;
+		if (rspamd_config_action_from_ucl (cfg, act, obj, priority)) {
+			HASH_ADD_STR (cfg->actions, name, act);
+		}
+		else {
+			return FALSE;
 		}
 	}
 
 	return TRUE;
 }
 
+struct rspamd_action *
+rspamd_config_get_action (struct rspamd_config *cfg, const gchar *name)
+{
+	struct rspamd_action *res = NULL;
+
+	HASH_FIND_STR (cfg->actions, name, res);
+
+	return res;
+}
 
 gboolean
 rspamd_config_radix_from_ucl (struct rspamd_config *cfg,
diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c
index 513c2da93..0b9811272 100644
--- a/src/lua/lua_config.c
+++ b/src/lua/lua_config.c
@@ -2127,9 +2127,10 @@ lua_config_set_metric_action (lua_State * L)
 	LUA_TRACE_POINT;
 	struct rspamd_config *cfg = lua_check_config (L, 1);
 	const gchar *name = NULL;
-	double weight;
+	double threshold = NAN;
 	GError *err = NULL;
 	gdouble priority = 0.0;
+	ucl_object_t *obj_tbl = NULL;
 
 	if (cfg) {
 
@@ -2137,7 +2138,7 @@ lua_config_set_metric_action (lua_State * L)
 			if (!rspamd_lua_parse_table_arguments (L, 2, &err,
 					"*action=S;score=N;"
 					"priority=N",
-					&name, &weight,
+					&name, &threshold,
 					&priority)) {
 				msg_err_config ("bad arguments: %e", err);
 				g_error_free (err);
@@ -2145,12 +2146,36 @@ lua_config_set_metric_action (lua_State * L)
 				return 0;
 			}
 		}
+		else if (lua_type (L, 2) == LUA_TSTRING && lua_type (L, 3) == LUA_TTABLE) {
+			name = lua_tostring (L, 2);
+			obj_tbl = ucl_object_lua_import (L, 3);
+
+			if (obj_tbl) {
+				if (name) {
+					rspamd_config_set_action_score (cfg, name, obj_tbl);
+					ucl_object_unref (obj_tbl);
+				}
+				else {
+					ucl_object_unref (obj_tbl);
+					return luaL_error (L, "invalid first argument, action name expected");
+				}
+			}
+			else {
+				return luaL_error (L, "invalid second argument, table expected");
+			}
+		}
 		else {
 			return luaL_error (L, "invalid arguments, table expected");
 		}
 
-		if (name != NULL && weight != 0) {
-			rspamd_config_set_action_score (cfg, name, weight, (guint)priority);
+		if (name != NULL && !isnan (threshold) && threshold != 0) {
+			obj_tbl = ucl_object_typed_new (UCL_OBJECT);
+			ucl_object_insert_key (obj_tbl, ucl_object_fromdouble (threshold),
+					"score", 0, false);
+			ucl_object_insert_key (obj_tbl, ucl_object_fromdouble (priority),
+					"priority", 0, false);
+			rspamd_config_set_action_score (cfg, name, obj_tbl);
+			ucl_object_unref (obj_tbl);
 		}
 	}
 	else {
@@ -2166,12 +2191,14 @@ lua_config_get_metric_action (lua_State * L)
 	LUA_TRACE_POINT;
 	struct rspamd_config *cfg = lua_check_config (L, 1);
 	const gchar *act_name = luaL_checkstring (L, 2);
-	gint act = 0;
+	struct rspamd_action *act;
 
 	if (cfg && act_name) {
-		if (rspamd_action_from_str (act_name, &act)) {
-			if (!isnan (cfg->actions[act].threshold)) {
-				lua_pushnumber (L, cfg->actions[act].threshold);
+		act = rspamd_config_get_action (cfg, act_name);
+
+		if (act) {
+			if (!isnan (act->threshold)) {
+				lua_pushnumber (L, act->threshold);
 			}
 			else {
 				lua_pushnil (L);


More information about the Commits mailing list