]> source.dussan.org Git - rspamd.git/commitdiff
[Project] More steps to flexible actions
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 14 Jan 2019 09:47:05 +0000 (09:47 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 14 Jan 2019 09:47:05 +0000 (09:47 +0000)
src/libserver/cfg_file.h
src/libserver/cfg_utils.c
src/lua/lua_config.c

index 22b15494388fa3b070b87f43deb3ecf26bd4e5a5..3a809458506ba1603d9a3fc2e1bf5f6fdee7df91 100644 (file)
@@ -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, \
index 170595fb611e8a2c7a604203e3cea787b82d7dd3..5e3193cba9786140cb689a8dfee917bd48ae82eb 100644 (file)
@@ -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,
index 513c2da9375efb9c0b83ea808659ac9657bea530..0b9811272fe1c634a97dd113aa06c3f392f01445 100644 (file)
@@ -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);