From cddc50cd4e66a874bdfd07c9d27c234e2cd779ad Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 30 Jul 2024 17:14:07 +0100 Subject: [PATCH] [Feature] Allow to set negative group score limit via `min_score` --- src/libmime/scan_result.c | 23 ++++++++++++++++++----- src/libserver/cfg_file.h | 1 + src/libserver/cfg_rcl.cxx | 18 ++++++++++++++++++ src/libserver/cfg_utils.cxx | 2 ++ src/lua/lua_config.c | 2 ++ src/plugins/fuzzy_check.c | 2 ++ src/rspamadm/configdump.c | 5 ++++- 7 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/libmime/scan_result.c b/src/libmime/scan_result.c index f15290b95..bc7e5ccfd 100644 --- a/src/libmime/scan_result.c +++ b/src/libmime/scan_result.c @@ -201,16 +201,29 @@ rspamd_check_group_score(struct rspamd_task *task, double *group_score, double w) { - if (gr != NULL && group_score && gr->max_score > 0.0 && w > 0.0) { - if (*group_score >= gr->max_score && w > 0) { + double group_limit = NAN; + + if (gr != NULL && group_score) { + if ((*group_score + w) >= 0 && !isnan(gr->max_score) && gr->max_score > 0) { + group_limit = gr->max_score; + } + else if ((*group_score + w) < 0 && !isnan(gr->min_score) && gr->min_score < 0) { + group_limit = -gr->min_score; + } + } + + if (gr != NULL && group_limit && !isnan(group_limit)) { + if (fabs(*group_score) >= group_limit && signbit(*group_score) == signbit(w)) { + /* Cannot add more to the group */ msg_info_task("maximum group score %.2f for group %s has been reached," " ignoring symbol %s with weight %.2f", - gr->max_score, + group_limit, gr->name, symbol, w); return NAN; } - else if (*group_score + w > gr->max_score) { - w = gr->max_score - *group_score; + else if (fabs(*group_score + w) > group_limit) { + /* Reduce weight */ + w = signbit(w) ? -group_limit - *group_score : group_limit - *group_score; } } diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h index 1ba1d84ad..fa784f2a2 100644 --- a/src/libserver/cfg_file.h +++ b/src/libserver/cfg_file.h @@ -102,6 +102,7 @@ struct rspamd_symbols_group { char *description; GHashTable *symbols; double max_score; + double min_score; unsigned int flags; }; diff --git a/src/libserver/cfg_rcl.cxx b/src/libserver/cfg_rcl.cxx index 8a479fa6d..9b6e759bb 100644 --- a/src/libserver/cfg_rcl.cxx +++ b/src/libserver/cfg_rcl.cxx @@ -420,6 +420,18 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, return FALSE; } + if (!std::isnan(gr->max_score) && gr->max_score < 0) { + msg_err_config("group %s has negative max_score which is broken, use min_score if required", gr->name); + + return FALSE; + } + if (!std::isnan(gr->min_score) && gr->min_score > 0) { + msg_err_config("group %s has positive min_score which is broken, use max_score if required", gr->name); + + return FALSE; + } + + if (const auto *elt = ucl_object_lookup(obj, "one_shot"); elt != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, @@ -2349,6 +2361,12 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) G_STRUCT_OFFSET(struct rspamd_symbols_group, max_score), 0, "Maximum score that could be reached by this symbols group"); + rspamd_rcl_add_default_handler(sub, + "min_score", + rspamd_rcl_parse_struct_double, + G_STRUCT_OFFSET(struct rspamd_symbols_group, min_score), + 0, + "Maximum negative score that could be reached by this symbols group"); } if (!(skip_sections && g_hash_table_lookup(skip_sections, "worker"))) { diff --git a/src/libserver/cfg_utils.cxx b/src/libserver/cfg_utils.cxx index 1344bc4f9..d8696e72d 100644 --- a/src/libserver/cfg_utils.cxx +++ b/src/libserver/cfg_utils.cxx @@ -1052,6 +1052,8 @@ rspamd_config_new_group(struct rspamd_config *cfg, const char *name) rspamd_mempool_add_destructor(cfg->cfg_pool, (rspamd_mempool_destruct_t) g_hash_table_unref, gr->symbols); gr->name = rspamd_mempool_strdup(cfg->cfg_pool, name); + gr->max_score = NAN; + gr->min_score = NAN; if (strcmp(gr->name, "ungrouped") == 0) { gr->flags |= RSPAMD_SYMBOL_GROUP_UNGROUPED; diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index f9a79eef1..717aa81ce 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -3933,6 +3933,8 @@ lua_config_get_groups(lua_State *L) lua_setfield(L, -2, "description"); lua_pushnumber(L, gr->max_score); lua_setfield(L, -2, "max_score"); + lua_pushnumber(L, gr->min_score); + lua_setfield(L, -2, "min_score"); lua_pushboolean(L, (gr->flags & RSPAMD_SYMBOL_GROUP_PUBLIC) != 0); lua_setfield(L, -2, "is_public"); /* TODO: maybe push symbols as well */ diff --git a/src/plugins/fuzzy_check.c b/src/plugins/fuzzy_check.c index a035eeaae..b92177f1b 100644 --- a/src/plugins/fuzzy_check.c +++ b/src/plugins/fuzzy_check.c @@ -2299,6 +2299,8 @@ fuzzy_insert_result(struct fuzzy_client_session *session, * Otherwise `value` means error code */ + msg_debug_fuzzy_check("got reply with probability %.2f and value %.2f", + (double) rep->v1.prob, (double) rep->v1.value); nval = fuzzy_normalize(rep->v1.value, weight); if (io) { diff --git a/src/rspamadm/configdump.c b/src/rspamadm/configdump.c index 167b4c891..456875cf2 100644 --- a/src/rspamadm/configdump.c +++ b/src/rspamadm/configdump.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 Vsevolod Stakhov + * Copyright 2024 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -444,6 +444,9 @@ rspamadm_configdump(int argc, char **argv, const struct rspamadm_command *cmd) ucl_object_insert_key(gr_ucl, ucl_object_fromdouble(gr->max_score), "max_score", strlen("max_score"), false); + ucl_object_insert_key(gr_ucl, + ucl_object_fromdouble(gr->min_score), + "min_score", strlen("min_score"), false); ucl_object_insert_key(gr_ucl, ucl_object_fromstring(gr->description), "description", strlen("description"), false); -- 2.39.5