diff options
author | Vsevolod Stakhov <vsevolod@rspamd.com> | 2025-07-13 15:28:09 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rspamd.com> | 2025-07-13 15:28:09 +0100 |
commit | 3e216519f0de812425d3ffffd92bf98a0ce63b62 (patch) | |
tree | 3f07fc0089d23bb316edde8d4a8249a39a57cb20 | |
parent | 2d99b3c630b0ebb47205ca0e8d16e4e4ca75b61b (diff) | |
download | rspamd-3e216519f0de812425d3ffffd92bf98a0ce63b62.tar.gz rspamd-3e216519f0de812425d3ffffd92bf98a0ce63b62.zip |
[Fix] Fix DL lists initialisations
-rw-r--r-- | src/libserver/re_cache.c | 13 | ||||
-rw-r--r-- | src/plugins/lua/multimap.lua | 155 |
2 files changed, 93 insertions, 75 deletions
diff --git a/src/libserver/re_cache.c b/src/libserver/re_cache.c index 5313e157a..7c5e14616 100644 --- a/src/libserver/re_cache.c +++ b/src/libserver/re_cache.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 Vsevolod Stakhov + * Copyright 2025 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -324,7 +324,8 @@ rspamd_re_cache_new(void) cache->nre = 0; cache->re = g_ptr_array_new_full(256, rspamd_re_cache_elt_dtor); cache->selectors = kh_init(lua_selectors_hash); - cache->next = cache->prev = NULL; + cache->next = NULL; + cache->prev = cache; cache->scope = NULL; /* Default scope */ cache->flags = RSPAMD_RE_CACHE_FLAG_LOADED; /* Default scope is always loaded */ #ifdef WITH_HYPERSCAN @@ -659,6 +660,9 @@ rspamd_re_cache_runtime_new_single(struct rspamd_re_cache *cache) #ifdef WITH_HYPERSCAN rt->has_hs = cache->hyperscan_loaded; #endif + /* Initialize the doubly-linked list pointers */ + rt->next = NULL; + rt->prev = NULL; return rt; } @@ -689,6 +693,9 @@ rspamd_re_cache_runtime_new(struct rspamd_re_cache *cache) } else { rt_head = rt; + /* For doubly-linked list, first element's prev should point to itself */ + rt_head->prev = rt_head; + rt_head->next = NULL; } } } @@ -2657,7 +2664,7 @@ rspamd_re_cache_is_valid_hyperscan_file(struct rspamd_re_cache *cache, len = strlen(path); - if (len < sizeof(rspamd_cryptobox_HASHBYTES + 3)) { + if (len < (rspamd_cryptobox_HASHBYTES + 3)) { if (!silent) { msg_err_re_cache("cannot open hyperscan cache file %s: too short filename", path); diff --git a/src/plugins/lua/multimap.lua b/src/plugins/lua/multimap.lua index 97d68f36b..336a65d0e 100644 --- a/src/plugins/lua/multimap.lua +++ b/src/plugins/lua/multimap.lua @@ -62,8 +62,8 @@ local function parse_multimap_value(parse_rule, p_ret) (digit ^ 1) -- Matches: 55.97, -90.8, .9 - number.decimal = (number.integer * -- Integer - (number.fractional ^ -1)) + -- Fractional + number.decimal = (number.integer * -- Integer + (number.fractional ^ -1)) + -- Fractional (lpeg.S("+-") * number.fractional) -- Completely fractional number local sym_start = lpeg.R("az", "AZ") + lpeg.S("_") @@ -98,7 +98,7 @@ local function parse_multimap_value(parse_rule, p_ret) else if p_ret ~= '' then rspamd_logger.infox(rspamd_config, '%s: cannot parse string "%s"', - parse_rule.symbol, p_ret) + parse_rule.symbol, p_ret) end return true, nil, 1.0, {} @@ -113,7 +113,9 @@ end -- SpamAssassin-like line processing functions local function split_sa_line(str) local result = {} - if not str then return result end + if not str then + return result + end for token in string.gmatch(str, '%S+') do table.insert(result, token) @@ -193,7 +195,7 @@ local function create_sa_atom_function(atom_name, re, rule_type, rule_data) end end -local function process_sa_line(rule, line, map) +local function process_sa_line(rule, line) line = lua_util.str_trim(line) if string.len(line) == 0 or string.sub(line, 1, 1) == '#' then @@ -249,7 +251,7 @@ local function process_sa_line(rule, line, map) } lua_util.debugm(N, rspamd_config, 'added SA header atom: %s for header %s (scope: %s)', - atom_name, header_name, scope_name) + atom_name, header_name, scope_name) end end elseif words[1] == 'body' then @@ -501,8 +503,8 @@ create_sa_meta_callback = function(meta_rule) if not (already_processed and already_processed[result_name or 'default']) then local expression = rspamd_expression.create(meta_rule.expression, - parse_sa_atom, - rspamd_config:get_mempool()) + parse_sa_atom, + rspamd_config:get_mempool()) if not expression then rspamd_logger.errx(rspamd_config, 'Cannot parse SA meta expression: %s', meta_rule.expression) return @@ -515,7 +517,7 @@ create_sa_meta_callback = function(meta_rule) if res > 0 then local score = sa_scores[meta_rule.symbol] or 1.0 task:insert_result_named(cur_res, meta_rule.symbol, score, - fun.totable(fun.filter(exclude_sym_filter, trace))) + fun.totable(fun.filter(exclude_sym_filter, trace))) end if not cached[meta_rule.symbol] then @@ -584,7 +586,7 @@ local function finalize_sa_rules() end lua_util.debugm(N, rspamd_config, 'registered SA meta symbol: %s (score: %s)', - meta_name, score) + meta_name, score) end -- Mark orphaned symbols - symbols that were previously available but no longer in current rules @@ -1058,19 +1060,19 @@ local function multimap_query_redis(key, task, value, callback) local function redis_map_cb(err, data) lua_util.debugm(N, task, 'got reply from Redis when trying to get key %s: err=%s, data=%s', - key, err, data) + key, err, data) if not err and type(data) ~= 'userdata' then callback(data) end end return rspamd_redis_make_request(task, - redis_params, -- connect params - key, -- hash key - false, -- is write - redis_map_cb, --callback - cmd, -- command - srch -- arguments + redis_params, -- connect params + key, -- hash key + false, -- is write + redis_map_cb, --callback + cmd, -- command + srch -- arguments ) end @@ -1082,9 +1084,9 @@ local function multimap_callback(task, rule) local function get_key_callback(ret, err_or_data, err_code) lua_util.debugm(N, task, 'got return "%s" (err code = %s) for multimap %s', - err_or_data, - err_code, - rule.symbol) + err_or_data, + err_code, + rule.symbol) if ret then if type(err_or_data) == 'table' then @@ -1096,12 +1098,12 @@ local function multimap_callback(task, rule) end elseif err_code ~= 404 then rspamd_logger.infox(task, "map %s: get key returned error %s: %s", - rule.symbol, err_code, err_or_data) + rule.symbol, err_code, err_or_data) end end lua_util.debugm(N, task, 'check value %s for multimap %s', value, - rule.symbol) + rule.symbol) local ret = false @@ -1140,8 +1142,8 @@ local function multimap_callback(task, rule) if rule.symbols_set then if not rule.symbols_set[symbol] then rspamd_logger.infox(task, 'symbol %s is not registered for map %s, ' .. - 'replace it with just %s', - symbol, rule.symbol, rule.symbol) + 'replace it with just %s', + symbol, rule.symbol, rule.symbol) symbol = rule.symbol end elseif rule.disable_multisymbol then @@ -1211,7 +1213,7 @@ local function multimap_callback(task, rule) if fn then local filtered_value = fn(task, r.filter, value, r) lua_util.debugm(N, task, 'apply filter %s for rule %s: %s -> %s', - r.filter, r.symbol, value, filtered_value) + r.filter, r.symbol, value, filtered_value) value = filtered_value end end @@ -1358,12 +1360,12 @@ local function multimap_callback(task, rule) if not res or res == 0 then lua_util.debugm(N, task, 'condition is false for %s', - rule.symbol) + rule.symbol) return else lua_util.debugm(N, task, 'condition is true for %s: %s', - rule.symbol, - trace) + rule.symbol, + trace) end end @@ -1380,18 +1382,18 @@ local function multimap_callback(task, rule) local to_resolve = ip_to_rbl(ip, rule['map']) local function dns_cb(_, _, results, err) lua_util.debugm(N, rspamd_config, - 'resolve() finished: results=%1, err=%2, to_resolve=%3', - results, err, to_resolve) + 'resolve() finished: results=%1, err=%2, to_resolve=%3', + results, err, to_resolve) if err and (err ~= 'requested record is not found' and - err ~= 'no records with this name') then + err ~= 'no records with this name') then rspamd_logger.errx(task, 'error looking up %s: %s', to_resolve, results) elseif results then task:insert_result(rule['symbol'], 1, rule['map']) if rule.action then task:set_pre_result(rule['action'], - 'Matched map: ' .. rule['symbol'], N) + 'Matched map: ' .. rule['symbol'], N) end end end @@ -1557,7 +1559,7 @@ local function multimap_callback(task, rule) if ext then local fake_fname = string.format('detected.%s', ext) lua_util.debugm(N, task, 'detected filename %s', - fake_fname) + fake_fname) match_filename(rule, fake_fname) end end @@ -1630,7 +1632,7 @@ local function multimap_callback(task, rule) if ret and ret ~= 0 then for n, t in pairs(trace) do insert_results(t.value, string.format("%s=%s", - n, t.matched)) + n, t.matched)) end end end, @@ -1666,7 +1668,7 @@ local function multimap_on_load_gen(rule) if r and symbol and not known_symbols[symbol] then lua_util.debugm(N, rspamd_config, "%s: adding new symbol %s (score = %s), triggered by %s", - rule.symbol, symbol, score, key) + rule.symbol, symbol, score, key) rspamd_config:register_symbol { name = symbol, parent = rule.callback_id, @@ -1692,22 +1694,22 @@ local function add_multimap_rule(key, newrule) if rule['regexp'] then if rule['multi'] then rule.map_obj = lua_maps.map_add_from_ucl(rule.map, 'regexp_multi', - rule.description) + rule.description) else rule.map_obj = lua_maps.map_add_from_ucl(rule.map, 'regexp', - rule.description) + rule.description) end elseif rule['glob'] then if rule['multi'] then rule.map_obj = lua_maps.map_add_from_ucl(rule.map, 'glob_multi', - rule.description) + rule.description) else rule.map_obj = lua_maps.map_add_from_ucl(rule.map, 'glob', - rule.description) + rule.description) end else rule.map_obj = lua_maps.map_add_from_ucl(rule.map, 'hash', - rule.description) + rule.description) end end @@ -1748,7 +1750,7 @@ local function add_multimap_rule(key, newrule) end if not newrule['description'] then newrule['description'] = string.format('multimap, type %s: %s', newrule['type'], - newrule['symbol']) + newrule['symbol']) end if newrule['type'] == 'mempool' and not newrule['variable'] then rspamd_logger.errx(rspamd_config, 'mempool map requires variable') @@ -1760,11 +1762,11 @@ local function add_multimap_rule(key, newrule) return nil else local selector = lua_selectors.create_selector_closure( - rspamd_config, newrule['selector'], newrule['delimiter'] or "") + rspamd_config, newrule['selector'], newrule['delimiter'] or "") if not selector then rspamd_logger.errx(rspamd_config, 'selector map has invalid selector: "%s", symbol: %s', - newrule['selector'], newrule['symbol']) + newrule['selector'], newrule['symbol']) return nil end @@ -1775,7 +1777,7 @@ local function add_multimap_rule(key, newrule) string.find(newrule['map'], '^redis://.*$') then if not redis_params then rspamd_logger.infox(rspamd_config, 'no redis servers are specified, ' .. - 'cannot add redis map %s: %s', newrule['symbol'], newrule['map']) + 'cannot add redis map %s: %s', newrule['symbol'], newrule['map']) return nil end @@ -1788,17 +1790,17 @@ local function add_multimap_rule(key, newrule) string.find(newrule['map'], '^redis%+selector://.*$') then if not redis_params then rspamd_logger.infox(rspamd_config, 'no redis servers are specified, ' .. - 'cannot add redis map %s: %s', newrule['symbol'], newrule['map']) + 'cannot add redis map %s: %s', newrule['symbol'], newrule['map']) return nil end local selector_str = string.match(newrule['map'], '^redis%+selector://(.*)$') local selector = lua_selectors.create_selector_closure( - rspamd_config, selector_str, newrule['delimiter'] or "") + rspamd_config, selector_str, newrule['delimiter'] or "") if not selector then rspamd_logger.errx(rspamd_config, 'redis selector map has invalid selector: "%s", symbol: %s', - selector_str, newrule['symbol']) + selector_str, newrule['symbol']) return nil end @@ -1807,12 +1809,12 @@ local function add_multimap_rule(key, newrule) elseif newrule.type == 'combined' then local lua_maps_expressions = require "lua_maps_expressions" newrule.combined = lua_maps_expressions.create(rspamd_config, - { - rules = newrule.rules, - expression = newrule.expression, - description = newrule.description, - on_load = newrule.dynamic_symbols and multimap_on_load_gen(newrule) or nil, - }, N, 'Combined map for ' .. newrule.symbol) + { + rules = newrule.rules, + expression = newrule.expression, + description = newrule.description, + on_load = newrule.dynamic_symbols and multimap_on_load_gen(newrule) or nil, + }, N, 'Combined map for ' .. newrule.symbol) if not newrule.combined then rspamd_logger.errx(rspamd_config, 'cannot add combined map for %s', newrule.symbol) else @@ -1851,17 +1853,23 @@ local function add_multimap_rule(key, newrule) type = "callback", url = map_ucl.url or map_ucl.urls or map_ucl, description = newrule.description or 'SA-style multimap: ' .. newrule.symbol, - callback = function(line, map) + callback = function(pseudo_key, pseudo_value) + -- We have values being parsed as kv pairs, but they are not, so we concat them and use as a line + local line = pseudo_key .. ' ' .. pseudo_value + -- Add debug logging to see if callback is called + lua_util.debugm(N, rspamd_config, 'regexp_rules callback called for line: %s', line) + -- Mark scope as unloaded on first line if not first_line_processed then first_line_processed = true + lua_util.debugm(N, rspamd_config, 'processing first line of regexp_rules map %s', newrule.symbol) -- Mark all existing symbols for this scope as loading for symbol, state_info in pairs(regexp_rules_symbol_states) do if state_info.rule_name == newrule.symbol then state_info.state = 'loading' lua_util.debugm(N, rspamd_config, 'marked regexp_rules symbol %s as loading for scope %s reload', - symbol, scope_name) + symbol, scope_name) end end @@ -1877,7 +1885,7 @@ local function add_multimap_rule(key, newrule) sa_atoms[symbol] = nil sa_meta_rules[symbol] = nil lua_util.debugm(N, rspamd_config, 'cleared regexp_rules symbol %s for scope %s reload', - symbol, scope_name) + symbol, scope_name) end -- The scope will be created by process_sa_line when first regexp is added @@ -1885,15 +1893,17 @@ local function add_multimap_rule(key, newrule) rspamd_config:set_regexp_scope_loaded(scope_name, false) lua_util.debugm(N, rspamd_config, 'marked regexp scope %s as unloaded during processing', scope_name) end - process_sa_line(newrule, line, map) + process_sa_line(newrule, line) end, - by_line = true, -- Process line by line + by_line = true, -- Process line by line opaque_data = false, -- Use plain strings }) -- Add on_load callback to mark scope as loaded when map processing is complete if newrule.map_obj then newrule.map_obj:on_load(function() + lua_util.debugm(N, rspamd_config, 'regexp_rules map %s loaded successfully', newrule.symbol) + -- Mark all atoms for this scope as available (if they're still loading) for symbol, state_info in pairs(regexp_rules_symbol_states) do if state_info.rule_name == newrule.symbol then @@ -1921,7 +1931,8 @@ local function add_multimap_rule(key, newrule) -- Trigger hyperscan compilation for this updated scope newrule.map_obj:trigger_hyperscan_compilation() - lua_util.debugm(N, rspamd_config, 'triggered hyperscan compilation for scope %s after map loading', scope_name) + lua_util.debugm(N, rspamd_config, 'triggered hyperscan compilation for scope %s after map loading', + scope_name) else lua_util.debugm(N, rspamd_config, 'regexp scope %s not created (empty map)', scope_name) end @@ -1932,21 +1943,21 @@ local function add_multimap_rule(key, newrule) -- Mark this rule as using SA functionality newrule.uses_sa = true lua_util.debugm(N, rspamd_config, 'created regexp_rules map %s with scope: %s', - newrule.symbol, scope_name) + newrule.symbol, scope_name) ret = true else rspamd_logger.warnx(rspamd_config, 'Cannot add SA-style rule: map doesn\'t exists: %s', - newrule['map']) + newrule['map']) end else if newrule['type'] == 'ip' then newrule.map_obj = lua_maps.map_add_from_ucl(newrule.map, 'radix', - newrule.description) + newrule.description) if newrule.map_obj then ret = true else rspamd_logger.warnx(rspamd_config, 'Cannot add rule: map doesn\'t exists: %s', - newrule['map']) + newrule['map']) end elseif newrule['type'] == 'received' then if type(newrule['flags']) == 'table' and newrule['flags'][1] then @@ -1962,12 +1973,12 @@ local function add_multimap_rule(key, newrule) local filter = newrule['filter'] or 'real_ip' if filter == 'real_ip' or filter == 'from_ip' then newrule.map_obj = lua_maps.map_add_from_ucl(newrule.map, 'radix', - newrule.description) + newrule.description) if newrule.map_obj then ret = true else rspamd_logger.warnx(rspamd_config, 'Cannot add rule: map doesn\'t exists: %s', - newrule['map']) + newrule['map']) end else multimap_load_kv_map(newrule) @@ -1976,13 +1987,13 @@ local function add_multimap_rule(key, newrule) ret = true else rspamd_logger.warnx(rspamd_config, 'Cannot add rule: map doesn\'t exists: %s', - newrule['map']) + newrule['map']) end end elseif known_generic_types[newrule.type] then if newrule.filter == 'ip_addr' then newrule.map_obj = lua_maps.map_add_from_ucl(newrule.map, 'radix', - newrule.description) + newrule.description) elseif not newrule.combined then multimap_load_kv_map(newrule) end @@ -1991,13 +2002,13 @@ local function add_multimap_rule(key, newrule) ret = true else rspamd_logger.warnx(rspamd_config, 'Cannot add rule: map doesn\'t exists: %s', - newrule['map']) + newrule['map']) end elseif newrule['type'] == 'dnsbl' then ret = true else rspamd_logger.errx(rspamd_config, 'cannot add rule %s: invalid type %s', - key, newrule['type']) + key, newrule['type']) end end @@ -2034,13 +2045,13 @@ local function add_multimap_rule(key, newrule) end local expression = rspamd_expression.create(newrule['require_symbols'], - { parse_atom, process_atom }, rspamd_config:get_mempool()) + { parse_atom, process_atom }, rspamd_config:get_mempool()) if expression then newrule['expression'] = expression fun.each(function(v) lua_util.debugm(N, rspamd_config, 'add dependency %s -> %s', - newrule['symbol'], v) + newrule['symbol'], v) rspamd_config:register_dependency(newrule['symbol'], v) end, atoms) end @@ -2062,7 +2073,7 @@ if opts and type(opts) == 'table' then rspamd_logger.errx(rspamd_config, 'cannot add rule: "' .. k .. '"') else rspamd_logger.infox(rspamd_config, 'added multimap rule: %s (%s)', - k, rule.type) + k, rule.type) table.insert(rules, rule) end end |