From: Vsevolod Stakhov Date: Mon, 14 Jan 2019 09:47:05 +0000 (+0000) Subject: [Project] More steps to flexible actions X-Git-Tag: 1.9.0~331 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=96986ba7f75858395a35c87305427b16eca96547;p=rspamd.git [Project] More steps to flexible actions --- 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);