From 4d32fb1b37d2ff46b4c6e1213a5bc163e3f2e96c Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Fri, 14 Jun 2019 13:23:15 +0100 Subject: [PATCH] [Project] Add preprocessed settings to the config structure --- src/libserver/cfg_file.h | 42 ++++++++++++ src/libserver/cfg_utils.c | 112 ++++++++++++++++++++++++++++++++ src/libserver/protocol.c | 18 ++--- src/libserver/rspamd_symcache.c | 12 ++-- src/libserver/task.c | 4 ++ src/libserver/task.h | 2 +- src/lua/lua_task.c | 4 +- 7 files changed, 177 insertions(+), 17 deletions(-) diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h index b5780a599..dc11d7aab 100644 --- a/src/libserver/cfg_file.h +++ b/src/libserver/cfg_file.h @@ -302,6 +302,15 @@ struct rspamd_config_post_load_script { struct rspamd_lang_detector; +struct rspamd_config_settings_elt { + guint32 id; + const gchar *name; + ucl_object_t *symbols_enabled; + ucl_object_t *symbols_disabled; + struct rspamd_config_settings_elt *prev, *next; + ref_entry_t ref; +}; + /** * Structure that stores all config data */ @@ -458,6 +467,7 @@ struct rspamd_config { gchar *zstd_output_dictionary; /**< path to zstd output dictionary */ ucl_object_t *neighbours; /**< other servers in the cluster */ + struct rspamd_config_settings_elt *setting_ids; /**< preprocessed settings ids */ struct rspamd_lang_detector *lang_det; /**< language detector */ ref_entry_t ref; /**< reference counter */ @@ -715,6 +725,38 @@ gboolean rspamd_config_radix_from_ucl (struct rspamd_config *cfg, struct rspamd_radix_map_helper **target, GError **err); +/** + * Adds new settings id to be preprocessed + * @param cfg + * @param name + * @param symbols_enabled + * @param symbols_disabled + */ +void rspamd_config_register_settings_id (struct rspamd_config *cfg, + const gchar *name, + ucl_object_t *symbols_enabled, + ucl_object_t *symbols_disabled); + +/** + * Finds settings id element and obtain reference count (must be unrefed by callee) + * @param cfg + * @param id + * @return + */ +struct rspamd_config_settings_elt *rspamd_config_find_settings_id_ref ( + struct rspamd_config *cfg, + guint32 id); + +/** + * Finds settings id element and obtain reference count (must be unrefed by callee) + * @param cfg + * @param id + * @return + */ +struct rspamd_config_settings_elt *rspamd_config_find_settings_name_ref ( + struct rspamd_config *cfg, + const gchar *name, gsize namelen); + /** * Returns action object by name * @param cfg diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c index 1c8b2ce5f..e32ca7020 100644 --- a/src/libserver/cfg_utils.c +++ b/src/libserver/cfg_utils.c @@ -2334,3 +2334,115 @@ rspamd_actions_sort (struct rspamd_config *cfg) { HASH_SORT (cfg->actions, rspamd_actions_cmp); } + +static void +rspamd_config_settings_elt_dtor (struct rspamd_config_settings_elt *e) +{ + if (e->symbols_enabled) { + ucl_object_unref (e->symbols_enabled); + } + if (e->symbols_disabled) { + ucl_object_unref (e->symbols_disabled); + } +} + +static inline guint32 +rspamd_config_name_to_id (const gchar *name, gsize namelen) +{ + guint64 h; + + h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, + name, strlen (name), 0x0); + /* Take the lower part of hash as LE number */ + return ((guint32)GUINT64_TO_LE (h)); +} + +struct rspamd_config_settings_elt * +rspamd_config_find_settings_id_ref (struct rspamd_config *cfg, + guint32 id) +{ + struct rspamd_config_settings_elt *cur; + + DL_FOREACH (cfg->setting_ids, cur) { + if (cur->id == id) { + REF_RETAIN (cur); + return cur; + } + } + + return NULL; +} + +struct rspamd_config_settings_elt *rspamd_config_find_settings_name_ref ( + struct rspamd_config *cfg, + const gchar *name, gsize namelen) +{ + guint32 id; + + id = rspamd_config_name_to_id (name, namelen); + + return rspamd_config_find_settings_id_ref (cfg, id); +} + +void +rspamd_config_register_settings_id (struct rspamd_config *cfg, + const gchar *name, + ucl_object_t *symbols_enabled, + ucl_object_t *symbols_disabled) +{ + struct rspamd_config_settings_elt *elt; + guint32 id; + + id = rspamd_config_name_to_id (name, strlen (name)); + elt = rspamd_config_find_settings_id_ref (cfg, id); + + if (elt) { + /* Need to replace */ + struct rspamd_config_settings_elt *nelt; + + DL_DELETE (cfg->setting_ids, elt); + + nelt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*nelt)); + + nelt->id = id; + nelt->name = rspamd_mempool_strdup (cfg->cfg_pool, name); + + if (symbols_enabled) { + nelt->symbols_enabled = ucl_object_ref (symbols_enabled); + } + + if (symbols_disabled) { + nelt->symbols_disabled = ucl_object_ref (symbols_disabled); + } + + REF_INIT_RETAIN (nelt, rspamd_config_settings_elt_dtor); + msg_info_config ("replace settings id %d (%s)", id, name); + DL_APPEND (cfg->setting_ids, nelt); + + /* + * Need to unref old element twice as there are two reference holders: + * 1. Config structure as we call REF_INIT_RETAIN + * 2. rspamd_config_find_settings_id_ref also increases refcount + */ + REF_RELEASE (elt); + REF_RELEASE (elt); + } + else { + elt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*elt)); + + elt->id = id; + elt->name = rspamd_mempool_strdup (cfg->cfg_pool, name); + + if (symbols_enabled) { + elt->symbols_enabled = ucl_object_ref (symbols_enabled); + } + + if (symbols_disabled) { + elt->symbols_disabled = ucl_object_ref (symbols_disabled); + } + + msg_info_config ("register new settings id %d (%s)", id, name); + REF_INIT_RETAIN (elt, rspamd_config_settings_elt_dtor); + DL_APPEND (cfg->setting_ids, elt); + } +} diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c index 7d3ccb27d..5cd0568da 100644 --- a/src/libserver/protocol.c +++ b/src/libserver/protocol.c @@ -483,13 +483,14 @@ rspamd_protocol_handle_headers (struct rspamd_task *task, task->subject = rspamd_mempool_ftokdup (task->task_pool, hv_tok); } IF_HEADER (SETTINGS_ID_HEADER) { - guint64 h; - msg_debug_protocol ("read settings-id header, value: %V", hv); - h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, - hv_tok->begin, hv_tok->len, 0x0); - /* Take the lower part of hash as LE number */ - task->settings_id = (guint32)GUINT64_TO_LE (h); + task->settings_elt = rspamd_config_find_settings_name_ref ( + task->cfg, hv_tok->begin, hv_tok->len); + + if (task->settings_elt == NULL) { + msg_warn_protocol ("unknown settings id: %V", + hv); + } } break; case 'u': @@ -1702,10 +1703,9 @@ rspamd_protocol_write_log_pipe (struct rspamd_task *task) ls = g_malloc0 (sz); /* Handle settings id */ - sid = task->settings_id; - if (sid) { - ls->settings_id = sid; + if (task->settings_elt) { + ls->settings_id = task->settings_elt->id; } else { ls->settings_id = 0; diff --git a/src/libserver/rspamd_symcache.c b/src/libserver/rspamd_symcache.c index 034049005..22f4c3229 100644 --- a/src/libserver/rspamd_symcache.c +++ b/src/libserver/rspamd_symcache.c @@ -1425,24 +1425,26 @@ static gboolean rspamd_symcache_is_item_allowed (struct rspamd_task *task, struct rspamd_symcache_item *item) { - if (task->settings_id != 0) { + if (task->settings_elt != 0) { + guint32 id = task->settings_elt->id; + if (item->forbidden_ids.st[0] != 0 && rspamd_symcache_check_id_list (&item->forbidden_ids, - task->settings_id)) { + id)) { msg_debug_cache_task ("deny execution of %s as it is forbidden for " "settings id %d", item->symbol, - task->settings_id); + id); return FALSE; } if (item->allowed_ids.st[0] != 0 && !rspamd_symcache_check_id_list (&item->allowed_ids, - task->settings_id)) { + id)) { msg_debug_cache_task ("deny execution of %s as it is not listed as allowed for " "settings id %d", item->symbol, - task->settings_id); + id); return FALSE; } } diff --git a/src/libserver/task.c b/src/libserver/task.c index a7c1bc478..16b33294e 100644 --- a/src/libserver/task.c +++ b/src/libserver/task.c @@ -313,6 +313,10 @@ rspamd_task_free (struct rspamd_task *task) ucl_object_unref (task->settings); } + if (task->settings_elt != NULL) { + REF_RELEASE (task->settings_elt); + } + if (task->client_addr) { rspamd_inet_address_free (task->client_addr); } diff --git a/src/libserver/task.h b/src/libserver/task.h index 079e388df..263f06719 100644 --- a/src/libserver/task.h +++ b/src/libserver/task.h @@ -206,7 +206,7 @@ struct rspamd_task { gpointer checkpoint; /**< Opaque checkpoint data */ ucl_object_t *settings; /**< Settings applied to task */ guint32 processed_stages; /**< bits of stages that are processed */ - guint32 settings_id; /**< hashed settings id */ + struct rspamd_config_settings_elt *settings_elt; /**< preprocessed settings id elt */ const gchar *classifier; /**< Classifier to learn (if needed) */ struct rspamd_lang_detector *lang_det; /**< Languages detector */ diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c index 3218a958f..f562d1ca6 100644 --- a/src/lua/lua_task.c +++ b/src/lua/lua_task.c @@ -4872,8 +4872,8 @@ lua_task_get_settings_id (lua_State *L) if (task != NULL) { - if (task->settings_id) { - lua_pushnumber (L, task->settings_id); + if (task->settings_elt) { + lua_pushnumber (L, task->settings_elt->id); } else { lua_pushnil (L); -- 2.39.5