aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libmime/scan_result.c48
-rw-r--r--src/libserver/cfg_file.h1
-rw-r--r--src/libserver/cfg_rcl.cxx18
-rw-r--r--src/libserver/cfg_utils.cxx2
-rw-r--r--src/libserver/milter.c8
-rw-r--r--src/libserver/protocol.c19
-rw-r--r--src/libserver/protocol_internal.h1
-rw-r--r--src/lua/lua_config.c2
-rw-r--r--src/lua/lua_redis.c23
-rw-r--r--src/plugins/fuzzy_check.c2
-rw-r--r--src/plugins/lua/once_received.lua103
-rw-r--r--src/rspamadm/configdump.c5
-rw-r--r--src/rspamd_proxy.c10
13 files changed, 133 insertions, 109 deletions
diff --git a/src/libmime/scan_result.c b/src/libmime/scan_result.c
index f15290b95..894ae4f9e 100644
--- a/src/libmime/scan_result.c
+++ b/src/libmime/scan_result.c
@@ -201,16 +201,34 @@ 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 */
+ double new_w = signbit(w) ? -group_limit - *group_score : group_limit - *group_score;
+ msg_info_task("maximum group score %.2f for group %s has been reached,"
+ " reduce weight of symbol %s from %.2f to %.2f",
+ group_limit,
+ gr->name, symbol, w, new_w);
+ w = new_w;
}
}
@@ -393,15 +411,7 @@ insert_metric_result(struct rspamd_task *task,
}
else if (gr_score) {
*gr_score += cur_diff;
-
- if (cur_diff < diff) {
- /* Reduce */
- msg_debug_metric(
- "group limit %.2f is reached for %s when inserting symbol %s;"
- " reduce score %.2f - %.2f",
- *gr_score, gr->name, symbol, diff, cur_diff);
- diff = cur_diff;
- }
+ diff = cur_diff;
}
}
}
@@ -461,15 +471,7 @@ insert_metric_result(struct rspamd_task *task,
}
else if (gr_score) {
*gr_score += cur_score;
-
- if (cur_score < final_score) {
- /* Reduce */
- msg_debug_metric(
- "group limit %.2f is reached for %s when inserting symbol %s;"
- " reduce score %.2f - %.2f",
- *gr_score, gr->name, symbol, final_score, cur_score);
- final_score = cur_score;
- }
+ final_score = cur_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/libserver/milter.c b/src/libserver/milter.c
index f35278a0e..94b0d6cc1 100644
--- a/src/libserver/milter.c
+++ b/src/libserver/milter.c
@@ -1465,10 +1465,16 @@ rspamd_milter_macro_http(struct rspamd_milter_session *session,
return;
}
+ /*
+ * When we get a queue-id we try to pass it to the backend, where possible
+ * We also need that for logging consistency
+ */
IF_MACRO("{i}")
{
rspamd_http_message_add_header_len(msg, QUEUE_ID_HEADER,
found->begin, found->len);
+ rspamd_http_message_add_header_len(msg, LOG_TAG_HEADER,
+ found->begin, found->len);
}
else
{
@@ -1476,6 +1482,8 @@ rspamd_milter_macro_http(struct rspamd_milter_session *session,
{
rspamd_http_message_add_header_len(msg, QUEUE_ID_HEADER,
found->begin, found->len);
+ rspamd_http_message_add_header_len(msg, LOG_TAG_HEADER,
+ found->begin, found->len);
}
}
diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c
index db83b0bfb..ee2192913 100644
--- a/src/libserver/protocol.c
+++ b/src/libserver/protocol.c
@@ -660,9 +660,9 @@ rspamd_protocol_handle_headers(struct rspamd_task *task,
IF_HEADER(USER_HEADER)
{
/*
- * We must ignore User header in case of spamc, as SA has
- * different meaning of this header
- */
+ * We must ignore User header in case of spamc, as SA has
+ * different meaning of this header
+ */
msg_debug_protocol("read user header, value: %T", hv_tok);
if (!RSPAMD_TASK_IS_SPAMC(task)) {
task->auth_user = rspamd_mempool_ftokdup(task->task_pool,
@@ -708,6 +708,15 @@ rspamd_protocol_handle_headers(struct rspamd_task *task,
task->flags |= RSPAMD_TASK_FLAG_NO_LOG;
}
}
+ IF_HEADER(LOG_TAG_HEADER)
+ {
+ msg_debug_protocol("read log-tag header, value: %T", hv_tok);
+ /* Ensure that a tag is valid */
+ if (rspamd_fast_utf8_validate(hv_tok->begin, hv_tok->len) == 0) {
+ memcpy(task->task_pool->tag.uid, hv_tok->begin,
+ MIN(hv_tok->len, sizeof(task->task_pool->tag.uid)));
+ }
+ }
break;
case 'm':
case 'M':
@@ -752,9 +761,9 @@ rspamd_protocol_handle_headers(struct rspamd_task *task,
default:
msg_debug_protocol("generic header: %T", hn_tok);
break;
- }
+ }
- rspamd_task_add_request_header (task, hn_tok, hv_tok);
+ rspamd_task_add_request_header (task, hn_tok, hv_tok);
}
}); /* End of kh_foreach_value */
diff --git a/src/libserver/protocol_internal.h b/src/libserver/protocol_internal.h
index 7a70ccef0..e55e54851 100644
--- a/src/libserver/protocol_internal.h
+++ b/src/libserver/protocol_internal.h
@@ -78,6 +78,7 @@ extern "C" {
#define HOSTNAME_HEADER "Hostname"
#define DELIVER_TO_HEADER "Deliver-To"
#define NO_LOG_HEADER "Log"
+#define LOG_TAG_HEADER "Log-Tag"
#define MLEN_HEADER "Message-Length"
#define USER_AGENT_HEADER "User-Agent"
#define MTA_TAG_HEADER "MTA-Tag"
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/lua/lua_redis.c b/src/lua/lua_redis.c
index f95abb577..d20c496ed 100644
--- a/src/lua/lua_redis.c
+++ b/src/lua/lua_redis.c
@@ -104,7 +104,7 @@ struct lua_redis_userdata {
char *server;
char log_tag[RSPAMD_LOG_ID_LEN + 1];
struct lua_redis_request_specific_userdata *specific;
- double timeout;
+ ev_tstamp timeout;
uint16_t port;
uint16_t terminated;
};
@@ -280,16 +280,23 @@ lua_redis_fin(void *arg)
* @param code
* @param ud
*/
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 5)))
+#endif
static void
lua_redis_push_error(const char *err,
struct lua_redis_ctx *ctx,
struct lua_redis_request_specific_userdata *sp_ud,
- gboolean connected)
+ gboolean connected,
+ ...)
{
struct lua_redis_userdata *ud = sp_ud->c;
struct lua_callback_state cbs;
lua_State *L;
+ va_list ap;
+ va_start(ap, connected);
+
if (!(sp_ud->flags & (LUA_REDIS_SPECIFIC_REPLIED | LUA_REDIS_SPECIFIC_FINISHED))) {
if (sp_ud->cbref != -1) {
@@ -302,7 +309,7 @@ lua_redis_push_error(const char *err,
lua_rawgeti(cbs.L, LUA_REGISTRYINDEX, sp_ud->cbref);
/* String of error */
- lua_pushstring(cbs.L, err);
+ lua_pushvfstring(cbs.L, err, ap);
/* Data is nil */
lua_pushnil(cbs.L);
@@ -331,6 +338,8 @@ lua_redis_push_error(const char *err,
lua_redis_fin(sp_ud);
}
}
+
+ va_end(ap);
}
static void
@@ -479,7 +488,7 @@ lua_redis_callback(redisAsyncContext *c, gpointer r, gpointer priv)
lua_redis_push_data(reply, ctx, sp_ud);
}
else {
- lua_redis_push_error(reply->str, ctx, sp_ud, TRUE);
+ lua_redis_push_error("%s", ctx, sp_ud, TRUE, reply->str);
}
}
else {
@@ -488,10 +497,10 @@ lua_redis_callback(redisAsyncContext *c, gpointer r, gpointer priv)
}
else {
if (c->err == REDIS_ERR_IO) {
- lua_redis_push_error(strerror(errno), ctx, sp_ud, TRUE);
+ lua_redis_push_error("%s", ctx, sp_ud, TRUE, strerror(errno));
}
else {
- lua_redis_push_error(c->errstr, ctx, sp_ud, TRUE);
+ lua_redis_push_error("%s", ctx, sp_ud, TRUE, c->errstr);
}
}
}
@@ -750,7 +759,7 @@ lua_redis_timeout(EV_P_ ev_timer *w, int revents)
REDIS_RETAIN(ctx);
msg_debug_lua_redis("timeout while querying redis server: %p, redis: %p", sp_ud,
sp_ud->c->ctx);
- lua_redis_push_error("timeout while connecting the server", ctx, sp_ud, TRUE);
+ lua_redis_push_error("timeout while connecting the server (%.2f sec)", ctx, sp_ud, TRUE, ud->timeout);
if (sp_ud->c->ctx) {
ac = sp_ud->c->ctx;
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/plugins/lua/once_received.lua b/src/plugins/lua/once_received.lua
index 2a5552ab9..5c5ff7986 100644
--- a/src/plugins/lua/once_received.lua
+++ b/src/plugins/lua/once_received.lua
@@ -19,10 +19,7 @@ if confighelp then
end
-- 0 or 1 received: = spam
-
local symbol = 'ONCE_RECEIVED'
-local symbol_rdns = 'RDNS_NONE'
-local symbol_rdns_dnsfail = 'RDNS_DNSFAIL'
local symbol_mx = 'DIRECT_TO_MX'
-- Symbol for strict checks
local symbol_strict = nil
@@ -47,54 +44,6 @@ local function check_quantity_received (task)
return not h['flags']['artificial']
end, recvh))
- local function recv_dns_cb(_, to_resolve, results, err)
- if err and (err ~= 'requested record is not found' and err ~= 'no records with this name') then
- rspamd_logger.errx(task, 'error looking up %s: %s', to_resolve, err)
- task:insert_result(symbol_rdns_dnsfail, 1.0)
- end
-
- if not results then
- if nreceived <= 1 then
- task:insert_result(symbol, 1)
- -- Avoid strict symbol inserting as the remaining symbols have already
- -- quote a significant weight, so a message could be rejected by just
- -- this property.
- --task:insert_result(symbol_strict, 1)
- -- Check for MUAs
- local ua = task:get_header('User-Agent')
- local xm = task:get_header('X-Mailer')
- if (ua or xm) then
- task:insert_result(symbol_mx, 1, (ua or xm))
- end
- end
- task:insert_result(symbol_rdns, 1)
- else
- rspamd_logger.infox(task, 'source hostname has not been passed to Rspamd from MTA, ' ..
- 'but we could resolve source IP address PTR %s as "%s"',
- to_resolve, results[1])
- task:set_hostname(results[1])
-
- if good_hosts then
- for _, gh in ipairs(good_hosts) do
- if string.find(results[1], gh) then
- return
- end
- end
- end
-
- if nreceived <= 1 then
- task:insert_result(symbol, 1)
- for _, h in ipairs(bad_hosts) do
- if string.find(results[1], h) then
-
- task:insert_result(symbol_strict, 1, h)
- return
- end
- end
- end
- end
- end
-
local task_ip = task:get_ip()
if ((not check_authed and task:get_user()) or
@@ -110,13 +59,39 @@ local function check_quantity_received (task)
local hn = task:get_hostname()
-- Here we don't care about received
- if (not hn) and task_ip and task_ip:is_valid() then
- task:get_resolver():resolve_ptr({ task = task,
- name = task_ip:to_string(),
- callback = recv_dns_cb,
- forced = true
- })
+ if not hn then
+ if nreceived <= 1 then
+ task:insert_result(symbol, 1)
+ -- Avoid strict symbol inserting as the remaining symbols have already
+ -- quote a significant weight, so a message could be rejected by just
+ -- this property.
+ --task:insert_result(symbol_strict, 1)
+ -- Check for MUAs
+ local ua = task:get_header('User-Agent')
+ local xm = task:get_header('X-Mailer')
+ if (ua or xm) then
+ task:insert_result(symbol_mx, 1, (ua or xm))
+ end
+ end
return
+ else
+ if good_hosts then
+ for _, gh in ipairs(good_hosts) do
+ if string.find(hn, gh) then
+ return
+ end
+ end
+ end
+
+ if nreceived <= 1 then
+ task:insert_result(symbol, 1)
+ for _, h in ipairs(bad_hosts) do
+ if string.find(hn, h) then
+ task:insert_result(symbol_strict, 1, h)
+ break
+ end
+ end
+ end
end
if nreceived <= 1 then
@@ -181,10 +156,6 @@ if opts then
for n, v in pairs(opts) do
if n == 'symbol_strict' then
symbol_strict = v
- elseif n == 'symbol_rdns' then
- symbol_rdns = v
- elseif n == 'symbol_rdns_dnsfail' then
- symbol_rdns_dnsfail = v
elseif n == 'bad_host' then
if type(v) == 'string' then
bad_hosts[1] = v
@@ -207,16 +178,6 @@ if opts then
end
rspamd_config:register_symbol({
- name = symbol_rdns,
- type = 'virtual',
- parent = id
- })
- rspamd_config:register_symbol({
- name = symbol_rdns_dnsfail,
- type = 'virtual',
- parent = id
- })
- rspamd_config:register_symbol({
name = symbol_strict,
type = 'virtual',
parent = id
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.
@@ -445,6 +445,9 @@ rspamadm_configdump(int argc, char **argv, const struct rspamadm_command *cmd)
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);
diff --git a/src/rspamd_proxy.c b/src/rspamd_proxy.c
index 4f08e81b9..6c8869e22 100644
--- a/src/rspamd_proxy.c
+++ b/src/rspamd_proxy.c
@@ -1398,7 +1398,8 @@ proxy_backend_mirror_finish_handler(struct rspamd_http_connection *conn,
bk_conn->err = "cannot parse ucl";
}
- msg_info_session("finished mirror connection to %s", bk_conn->name);
+ msg_info_session("finished mirror connection to %s; HTTP code: %d",
+ bk_conn->name, msg->code);
rspamd_upstream_ok(bk_conn->up);
proxy_backend_close_connection(bk_conn);
@@ -2203,6 +2204,8 @@ proxy_client_finish_handler(struct rspamd_http_connection *conn,
rspamd_http_message_remove_header(msg, "Keep-Alive");
rspamd_http_message_remove_header(msg, "Connection");
rspamd_http_message_remove_header(msg, "Key");
+ rspamd_http_message_add_header_len(msg, LOG_TAG_HEADER, session->pool->tag.uid,
+ sizeof(session->pool->tag.uid));
proxy_open_mirror_connections(session);
rspamd_http_connection_reset(session->client_conn);
@@ -2210,7 +2213,10 @@ proxy_client_finish_handler(struct rspamd_http_connection *conn,
proxy_send_master_message(session);
}
else {
- msg_info_session("finished master connection");
+ msg_info_session("finished master connection to %s; HTTP code: %d",
+ rspamd_inet_address_to_string_pretty(
+ rspamd_upstream_addr_cur(session->master_conn->up)),
+ msg->code);
proxy_backend_close_connection(session->master_conn);
REF_RELEASE(session);
}