]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Project] Add concept of flexible actions
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 13 Jan 2019 14:22:04 +0000 (14:22 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 13 Jan 2019 14:22:04 +0000 (14:22 +0000)
src/controller.c
src/libmime/filter.c
src/libserver/cfg_file.h
src/libserver/cfg_utils.c
src/lua/lua_config.c

index b8eface74469d9acd6d0b00e166b1054ea608ed1..ee7e80e20f48e64a771826e6b5d5992828386091 100644 (file)
@@ -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 ++;
                }
index 94c9ac2231c941abaa3e0a768105eb92023a9b15..2bda47fe76b99c925575e907b3ea82d56eb51e2c 100644 (file)
@@ -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 {
index 6d6ed6f62b3a92fe3bf7f49fe5d539b5f67cd04b..22b15494388fa3b070b87f43deb3ecf26bd4e5a5 100644 (file)
@@ -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
index a15bb9b8ac7a4da47094e471bfecd11bab595f03..170595fb611e8a2c7a604203e3cea787b82d7dd3 100644 (file)
@@ -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);
+}
index 31d4af79b1b3e7806b9dd4a26c21dfaf47814f37..513c2da9375efb9c0b83ea808659ac9657bea530 100644 (file)
@@ -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);
                        }
                }