From 7e081148fdf4fa81c7973037c07236e804296272 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 20 Aug 2019 16:26:22 +0100 Subject: [PATCH] [Feature] Implement settings id propagation between deps --- src/libserver/rspamd_symcache.c | 213 ++++++++++++++++++++++++-------- src/libserver/rspamd_symcache.h | 3 +- src/lua/lua_config.c | 3 +- src/plugins/surbl.c | 4 +- 4 files changed, 166 insertions(+), 57 deletions(-) diff --git a/src/libserver/rspamd_symcache.c b/src/libserver/rspamd_symcache.c index 054c6af5f..900a1894c 100644 --- a/src/libserver/rspamd_symcache.c +++ b/src/libserver/rspamd_symcache.c @@ -193,9 +193,10 @@ struct rspamd_symcache_dynamic_item { struct cache_dependency { - struct rspamd_symcache_item *item; - gchar *sym; - gint id; + struct rspamd_symcache_item *item; /* Real dependency */ + gchar *sym; /* Symbolic dep name */ + gint id; /* Real from */ + gint vid; /* Virtual from */ }; struct delayed_cache_dependency { @@ -533,12 +534,139 @@ rspamd_symcache_resort (struct rspamd_symcache *cache) cache->items_by_order = ord; } +static void +rspamd_symcache_propagate_dep (struct rspamd_symcache *cache, + struct rspamd_symcache_item *it, + struct rspamd_symcache_item *dit) +{ + const guint *ids; + guint nids = 0; + + ids = rspamd_symcache_get_allowed_settings_ids (cache, dit->symbol, &nids); + + /* TODO: merge? */ + if (nids > 0) { + msg_info_cache ("propagate allowed ids from %s to %s", + dit->symbol, it->symbol); + + rspamd_symcache_set_allowed_settings_ids (cache, it->symbol, ids, + nids); + } + + ids = rspamd_symcache_get_forbidden_settings_ids (cache, dit->symbol, &nids); + + if (nids > 0) { + msg_info_cache ("propagate forbidden ids from %s to %s", + dit->symbol, it->symbol); + + rspamd_symcache_set_forbidden_settings_ids (cache, it->symbol, ids, + nids); + } +} + +static void +rspamd_symcache_process_dep (struct rspamd_symcache *cache, + struct rspamd_symcache_item *it, + struct cache_dependency *dep) +{ + struct rspamd_symcache_item *dit = NULL, *vdit = NULL; + struct cache_dependency *rdep; + + if (dep->id >= 0) { + dit = rspamd_symcache_find_filter (cache, dep->sym, true); + } + + if (dep->vid >= 0) { + /* Case of the virtual symbol that depends on another (maybe virtual) symbol */ + vdit = rspamd_symcache_find_filter (cache, dep->sym, false); + } + else { + vdit = dit; + } + + if (dit != NULL) { + if (!dit->is_filter) { + /* + * Check sanity: + * - filters -> prefilter dependency is OK and always satisfied + * - postfilter -> (filter, prefilter) dep is ok + * - idempotent -> (any) dep is OK + * + * Otherwise, emit error + * However, even if everything is fine this dep is useless ¯\_(ツ)_/¯ + */ + gboolean ok_dep = FALSE; + + if (it->is_filter) { + if (dit->type & SYMBOL_TYPE_PREFILTER) { + ok_dep = TRUE; + } + } + else if (it->type & SYMBOL_TYPE_POSTFILTER) { + if (dit->type & SYMBOL_TYPE_PREFILTER) { + ok_dep = TRUE; + } + } + else if (it->type & SYMBOL_TYPE_IDEMPOTENT) { + if (dit->type & (SYMBOL_TYPE_PREFILTER|SYMBOL_TYPE_POSTFILTER)) { + ok_dep = TRUE; + } + } + else if (it->type & SYMBOL_TYPE_PREFILTER) { + if (it->priority < dit->priority) { + /* Also OK */ + ok_dep = TRUE; + } + } + + if (!ok_dep) { + msg_err_cache ("cannot add dependency from %s on %s: invalid symbol types", + dep->sym, dit->symbol); + + return; + } + } + else { + if (dit->id == it->id) { + msg_err_cache ("cannot add dependency on self: %s -> %s " + "(resolved to %s)", + it->symbol, dep->sym, dit->symbol); + } else { + rdep = rspamd_mempool_alloc (cache->static_pool, + sizeof (*rdep)); + + rdep->sym = dep->sym; + rdep->item = it; + rdep->id = it->id; + g_assert (dit->rdeps != NULL); + g_ptr_array_add (dit->rdeps, rdep); + dep->item = dit; + dep->id = dit->id; + + msg_debug_cache ("add dependency from %d on %d", it->id, + dit->id); + } + } + } + else if (dep->id >= 0) { + msg_err_cache ("cannot find dependency on symbol %s for symbol %s", + dep->sym, it->symbol); + + return; + } + + if (vdit) { + /* Use virtual symbol to propagate deps */ + rspamd_symcache_propagate_dep (cache, it, vdit); + } +} + /* Sort items in logical order */ static void rspamd_symcache_post_init (struct rspamd_symcache *cache) { - struct rspamd_symcache_item *it, *dit; - struct cache_dependency *dep, *rdep; + struct rspamd_symcache_item *it, *vit; + struct cache_dependency *dep; struct delayed_cache_dependency *ddep; struct delayed_cache_condition *dcond; GList *cur; @@ -548,6 +676,7 @@ rspamd_symcache_post_init (struct rspamd_symcache *cache) while (cur) { ddep = cur->data; + vit = rspamd_symcache_find_filter (cache, ddep->from, false); it = rspamd_symcache_find_filter (cache, ddep->from, true); if (it == NULL) { @@ -555,9 +684,9 @@ rspamd_symcache_post_init (struct rspamd_symcache *cache) "%s is missing", ddep->from, ddep->to, ddep->from); } else { - msg_debug_cache ("delayed between %s(%d) -> %s", ddep->from, - it->id, ddep->to); - rspamd_symcache_add_dependency (cache, it->id, ddep->to); + msg_debug_cache ("delayed between %s(%d:%d) -> %s", ddep->from, + it->id, vit->id, ddep->to); + rspamd_symcache_add_dependency (cache, it->id, ddep->to, vit->id); } cur = g_list_next (cur); @@ -585,40 +714,7 @@ rspamd_symcache_post_init (struct rspamd_symcache *cache) PTR_ARRAY_FOREACH (cache->items_by_id, i, it) { PTR_ARRAY_FOREACH (it->deps, j, dep) { - dit = rspamd_symcache_find_filter (cache, dep->sym, true); - - if (dit != NULL) { - if (!dit->is_filter) { - msg_err_cache ("cannot depend on non filter symbol " - "(%s wants to add dependency on %s)", - dep->sym, dit->symbol); - } - else { - if (dit->id == i) { - msg_err_cache ("cannot add dependency on self: %s -> %s " - "(resolved to %s)", - it->symbol, dep->sym, dit->symbol); - } else { - rdep = rspamd_mempool_alloc (cache->static_pool, - sizeof (*rdep)); - - rdep->sym = dep->sym; - rdep->item = it; - rdep->id = i; - g_assert (dit->rdeps != NULL); - g_ptr_array_add (dit->rdeps, rdep); - dep->item = dit; - dep->id = dit->id; - - msg_debug_cache ("add dependency from %d on %d", it->id, - dit->id); - } - } - } - else { - msg_err_cache ("cannot find dependency on symbol %s for symbol %s", - dep->sym, it->symbol); - } + rspamd_symcache_process_dep (cache, it, dep); } if (it->deps) { @@ -1083,15 +1179,12 @@ rspamd_symcache_add_symbol (struct rspamd_symcache *cache, cache->used_items, item->id); } - if (item->is_filter) { - /* Only plain filters can have deps and rdeps */ - item->deps = g_ptr_array_new (); - item->rdeps = g_ptr_array_new (); - rspamd_mempool_add_destructor (cache->static_pool, - rspamd_ptr_array_free_hard, item->deps); - rspamd_mempool_add_destructor (cache->static_pool, - rspamd_ptr_array_free_hard, item->rdeps); - } + item->deps = g_ptr_array_new (); + item->rdeps = g_ptr_array_new (); + rspamd_mempool_add_destructor (cache->static_pool, + rspamd_ptr_array_free_hard, item->deps); + rspamd_mempool_add_destructor (cache->static_pool, + rspamd_ptr_array_free_hard, item->rdeps); if (name != NULL) { g_hash_table_insert (cache->items_by_symbol, item->symbol, item); @@ -2384,9 +2477,10 @@ rspamd_symcache_inc_frequency (struct rspamd_symcache *cache, void rspamd_symcache_add_dependency (struct rspamd_symcache *cache, - gint id_from, const gchar *to) + gint id_from, const gchar *to, + gint virtual_id_from) { - struct rspamd_symcache_item *source; + struct rspamd_symcache_item *source, *vsource; struct cache_dependency *dep; g_assert (id_from >= 0 && id_from < (gint)cache->items_by_id->len); @@ -2397,7 +2491,20 @@ rspamd_symcache_add_dependency (struct rspamd_symcache *cache, dep->sym = rspamd_mempool_strdup (cache->static_pool, to); /* Will be filled later */ dep->item = NULL; + dep->vid = -1; g_ptr_array_add (source->deps, dep); + + if (id_from != virtual_id_from) { + /* We need that for settings id propagation */ + vsource = g_ptr_array_index (cache->items_by_id, virtual_id_from); + dep = rspamd_mempool_alloc (cache->static_pool, sizeof (*dep)); + dep->vid = id_from; + dep->id = -1; + dep->sym = rspamd_mempool_strdup (cache->static_pool, to); + /* Will be filled later */ + dep->item = NULL; + g_ptr_array_add (vsource->deps, dep); + } } void diff --git a/src/libserver/rspamd_symcache.h b/src/libserver/rspamd_symcache.h index ce2f3f7bf..6542e76ce 100644 --- a/src/libserver/rspamd_symcache.h +++ b/src/libserver/rspamd_symcache.h @@ -224,7 +224,8 @@ void rspamd_symcache_inc_frequency (struct rspamd_symcache *cache, * @param to destination name */ void rspamd_symcache_add_dependency (struct rspamd_symcache *cache, - gint id_from, const gchar *to); + gint id_from, const gchar *to, + gint virtual_id_from); /** * Add delayed dependency that is resolved on cache post-load routine diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index aea0c8436..9b8c084c0 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -2206,7 +2206,8 @@ lua_config_register_dependency (lua_State * L) if (child_id > 0 && parent != NULL) { - rspamd_symcache_add_dependency (cfg->cache, child_id, parent); + rspamd_symcache_add_dependency (cfg->cache, child_id, parent, + child_id); } } else { diff --git a/src/plugins/surbl.c b/src/plugins/surbl.c index 860f4b5e5..7da36f483 100644 --- a/src/plugins/surbl.c +++ b/src/plugins/surbl.c @@ -868,7 +868,7 @@ surbl_module_parse_rule (const ucl_object_t* value, struct rspamd_config* cfg) 1, 1); rspamd_symcache_add_dependency (cfg->cache, cb_id, - SURBL_REDIRECTOR_CALLBACK); + SURBL_REDIRECTOR_CALLBACK, cb_id); /* Failure symbol */ g_string_append (sym, "_FAIL"); rspamd_symcache_add_symbol (cfg->cache, sym->str, @@ -1205,7 +1205,7 @@ surbl_module_config (struct rspamd_config *cfg) if (cur_suffix->options & SURBL_OPTION_CHECKDKIM) { rspamd_symcache_add_dependency (cfg->cache, - cur_suffix->callback_id, "DKIM_TRACE"); + cur_suffix->callback_id, "DKIM_TRACE", cur_suffix->callback_id); } cur_opt = g_list_next (cur_opt); -- 2.39.5