@@ -0,0 +1,36 @@ | |||
codes = true | |||
std = 'min' | |||
exclude_files = { | |||
'/**/src/plugins/lua/fann_classifier.lua', | |||
'/**/src/plugins/lua/fann_scores.lua', | |||
'/**/src/plugins/lua/fann_redis.lua', | |||
} | |||
globals = { | |||
'classifiers', | |||
'config', | |||
'rspamd_config', | |||
'rspamd_count_metatokens', | |||
'rspamd_gen_metatokens', | |||
'rspamd_parse_redis_server', | |||
'rspamd_paths', | |||
'rspamd_plugins', | |||
'rspamd_redis_make_request', | |||
'rspamd_str_split', | |||
'rspamd_version', | |||
} | |||
ignore = { | |||
} | |||
files['/**/rules/regexp/headers.lua'].globals = { | |||
'check_header_delimiter_empty', | |||
'check_header_delimiter_tab', | |||
'kmail_msgid', | |||
} | |||
files['/**/src/plugins/lua/spamassassin.lua'].globals = { | |||
'ffi', | |||
'jit', | |||
} |
@@ -182,7 +182,7 @@ rspamd_config.R_WHITE_ON_WHITE = { | |||
normal_len = p:get_length() | |||
local hc = p:get_html() -- we get HTML context | |||
hc:foreach_tag({'font', 'span', 'div', 'p'}, function(tag, _) | |||
hc:foreach_tag({'font', 'span', 'div', 'p'}, function(tag) | |||
local bl = tag:get_extra() | |||
if bl then | |||
if bl['bgcolor'] and bl['color'] and bl['visible'] then |
@@ -51,7 +51,7 @@ end | |||
rspamd_config.SUBJ_ALL_CAPS = { | |||
callback = function(task) | |||
local caps_test = function(sbj, _) | |||
local caps_test = function(sbj) | |||
return util.is_uppercase(sbj) | |||
end | |||
return test_subject(task, caps_test, 1.0/40.0) |
@@ -67,7 +67,7 @@ local function get_specific_statfiles(classifier, task) | |||
end | |||
end | |||
classifiers['bayes'] = function(classifier, task, is_learn, _) | |||
classifiers['bayes'] = function(classifier, task, is_learn) | |||
-- Subfunction for detection of message's language | |||
local detect_language = function() | |||
local parts = task:get_text_parts() |
@@ -1,3 +1,4 @@ | |||
local logger = require "rspamd_logger" | |||
-- This function parses redis server definition using either | |||
-- specific server string for this module or global | |||
@@ -6,7 +7,6 @@ function rspamd_parse_redis_server(module_name) | |||
local default_port = 6379 | |||
local default_timeout = 1.0 | |||
local logger = require "rspamd_logger" | |||
local upstream_list = require "rspamd_upstream_list" | |||
local function try_load_redis_servers(options) | |||
@@ -313,9 +313,6 @@ local function meta_urls_function(task) | |||
return {0} | |||
end | |||
local function meta_attachments_function(task) | |||
end | |||
local metafunctions = { | |||
{ | |||
cb = meta_size_function, | |||
@@ -380,4 +377,4 @@ function rspamd_count_metatokens() | |||
end | |||
return total | |||
end | |||
end |
@@ -16,7 +16,6 @@ limitations under the License. | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_util = require "rspamd_util" | |||
local rspamd_redis = require "rspamd_redis" | |||
local rspamd_regexp = require "rspamd_regexp" | |||
local tcp = require "rspamd_tcp" | |||
local upstream_list = require "rspamd_upstream_list" | |||
@@ -191,6 +190,7 @@ local function check_av_cache(task, rule, fn) | |||
yield_result(task, rule, data) | |||
end | |||
else | |||
rspamd_logger.errx(task, 'Got error checking cache: %1', err) | |||
fn() | |||
end | |||
end | |||
@@ -219,7 +219,7 @@ end | |||
local function save_av_cache(task, rule, to_save) | |||
local key = task:get_digest() | |||
local function redis_set_cb(err, data) | |||
local function redis_set_cb(err) | |||
-- Do nothing | |||
if err then | |||
rspamd_logger.errx(task, 'failed to save virus cache for %s -> "%s": %s', | |||
@@ -506,7 +506,7 @@ if opts and type(opts) == 'table' then | |||
if not cb then | |||
rspamd_logger.errx(rspamd_config, 'cannot add rule: "' .. k .. '"') | |||
else | |||
local id = rspamd_config:register_symbol({ | |||
rspamd_config:register_symbol({ | |||
type = 'normal', | |||
name = m['symbol'], | |||
callback = cb, |
@@ -17,7 +17,6 @@ limitations under the License. | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_regexp = require "rspamd_regexp" | |||
local rspamd_redis = require "rspamd_redis" | |||
local options = { | |||
provider_type = 'rspamd', | |||
@@ -56,7 +55,10 @@ local function asn_check(task) | |||
local asn_check_func = {} | |||
function asn_check_func.rspamd(ip) | |||
local function rspamd_dns_cb(resolver, to_resolve, results, err, key) | |||
local function rspamd_dns_cb(_, _, results, dns_err) | |||
if dns_err then | |||
rspamd_logger.errx(task, 'error querying dns: %s', dns_err) | |||
end | |||
if not (results and results[1]) then return end | |||
local parts = rspamd_re:split(results[1]) | |||
-- "15169 | 8.8.8.0/24 | US | arin |" for 8.8.8.8 | |||
@@ -65,12 +67,13 @@ local function asn_check(task) | |||
if redis_params then | |||
local redis_key = options.key_prefix .. ip:to_string() | |||
local ret,conn,upstream | |||
local function redis_asn_set_cb(err, data) | |||
if not err then | |||
local function redis_asn_set_cb(redis_err) | |||
if not redis_err then | |||
upstream:ok() | |||
else | |||
rspamd_logger.infox(task, 'got error %s when setting asn record on server %s', | |||
err, upstream:get_addr()) | |||
redis_err, upstream:get_addr()) | |||
upstream:fail() | |||
end | |||
end | |||
ret,conn,upstream = rspamd_redis_make_request(task, | |||
@@ -81,7 +84,7 @@ local function asn_check(task) | |||
'HMSET', -- command | |||
{redis_key, "asn", parts[1], "net", parts[2], "country", parts[3]} -- arguments | |||
) | |||
if conn then | |||
if ret then | |||
conn:add_cmd('EXPIRE', { | |||
redis_key, tostring(options['expire']) | |||
}) | |||
@@ -107,10 +110,14 @@ local function asn_check(task) | |||
else | |||
asn_set(data[1], data[2], data[3]) | |||
-- Refresh key | |||
local function redis_asn_expire_cb(err, data) | |||
local function redis_asn_expire_cb(redis_err) | |||
if redis_err then | |||
rspamd_logger.errx(task, 'Error setting expire: %s', | |||
redis_err) | |||
end | |||
end | |||
local ret,_,_ = rspamd_redis_make_request(task, | |||
local ret,_,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
key, -- hash key | |||
true, -- is write | |||
@@ -118,6 +125,9 @@ local function asn_check(task) | |||
'EXPIRE', -- command | |||
{key, tostring(options.expire)} -- arguments | |||
) | |||
if not ret then | |||
upstream:fail() | |||
end | |||
end | |||
end | |||
@@ -70,21 +70,17 @@ local function check_dcc (task) | |||
if header then | |||
local _,_,info = header:find("; (.-)$") | |||
if (result == 'A') then | |||
-- Accept | |||
elseif (result == 'G') then | |||
-- Greylist | |||
elseif (result == 'R') then | |||
if (result == 'R') then | |||
-- Reject | |||
task:insert_result(symbol_bulk, 1.0, info) | |||
elseif (result == 'S') then | |||
-- Accept for some recipients only | |||
elseif (result == 'T') then | |||
-- Temporary failure | |||
logger.warnx(task, 'DCC returned a temporary failure result') | |||
else | |||
-- Unknown result | |||
logger.warnx(task, 'DCC result error: %1', result); | |||
if result ~= 'A' and result ~= 'G' and result ~= 'S' then | |||
-- Unknown result | |||
logger.warnx(task, 'DCC result error: %1', result); | |||
end | |||
end | |||
end | |||
end |
@@ -17,10 +17,7 @@ limitations under the License. | |||
-- Dmarc policy filter | |||
local rspamd_regexp = require "rspamd_regexp" | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_redis = require "rspamd_redis" | |||
local upstream_list = require "rspamd_upstream_list" | |||
local rspamd_util = require "rspamd_util" | |||
local check_local = false | |||
local check_authed = false | |||
@@ -52,7 +49,6 @@ local dmarc_symbols = { | |||
-- Default port for redis upstreams | |||
local redis_params = nil | |||
local dmarc_redis_key_prefix = "dmarc_" | |||
local dmarc_domain = nil | |||
local dmarc_reporting = false | |||
local dmarc_actions = {} | |||
@@ -108,7 +104,7 @@ local function dmarc_callback(task) | |||
return maybe_force_action('na') | |||
end | |||
local function dmarc_report_cb(err, data) | |||
local function dmarc_report_cb(err) | |||
if not err then | |||
rspamd_logger.infox(task, '<%1> dmarc report saved for %2', | |||
task:get_message_id(), from[1]['domain']) | |||
@@ -118,7 +114,7 @@ local function dmarc_callback(task) | |||
end | |||
end | |||
local function dmarc_dns_cb(resolver, to_resolve, results, err, key) | |||
local function dmarc_dns_cb(_, to_resolve, results, err) | |||
local lookup_domain = string.sub(to_resolve, 8) | |||
if err and (err ~= 'requested record is not found' and err ~= 'no records with this name') then | |||
@@ -281,7 +277,7 @@ local function dmarc_callback(task) | |||
end | |||
local das = task:get_symbol(symbols['dkim_allow_symbol']) | |||
if das and das[1] and das[1]['options'] then | |||
for i,dkim_domain in ipairs(das[1]['options']) do | |||
for _,dkim_domain in ipairs(das[1]['options']) do | |||
if strict_dkim and rspamd_util.strequal_caseless(from[1]['domain'], dkim_domain) then | |||
dkim_ok = true | |||
elseif strict_dkim then | |||
@@ -367,7 +363,7 @@ if opts and type(opts) ~= 'table' then | |||
end | |||
end | |||
local opts = rspamd_config:get_all_opt('dmarc') | |||
opts = rspamd_config:get_all_opt('dmarc') | |||
if not opts or type(opts) ~= 'table' then | |||
return | |||
end | |||
@@ -397,9 +393,9 @@ if opts['key_prefix'] then | |||
end | |||
-- Check spf and dkim sections for changed symbols | |||
local function check_mopt(var, opts, name) | |||
if opts[name] then | |||
symbols['var'] = tostring(opts[name]) | |||
local function check_mopt(var, m_opts, name) | |||
if m_opts[name] then | |||
symbols[var] = tostring(m_opts[name]) | |||
end | |||
end | |||
@@ -15,7 +15,6 @@ limitations under the License. | |||
]]-- | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_redis = require 'rspamd_redis' | |||
local redis_params | |||
local ucl = require "ucl" | |||
local fun = require "fun" | |||
@@ -92,7 +91,7 @@ local function redis_make_request(ev_base, cfg, key, is_write, callback, command | |||
return ret,conn,addr | |||
end | |||
local function apply_dynamic_actions(cfg, acts) | |||
local function apply_dynamic_actions(_, acts) | |||
fun.each(function(k, v) | |||
if type(v) == 'table' then | |||
v['name'] = k | |||
@@ -117,7 +116,7 @@ local function apply_dynamic_actions(cfg, acts) | |||
end, acts)) | |||
end | |||
local function apply_dynamic_scores(cfg, sc) | |||
local function apply_dynamic_scores(_, sc) | |||
fun.each(function(k, v) | |||
if type(v) == 'table' then | |||
v['name'] = k | |||
@@ -154,13 +153,13 @@ local function apply_dynamic_conf(cfg, data) | |||
end | |||
if data['symbols_enabled'] then | |||
fun.each(function(i, v) | |||
fun.each(function(_, v) | |||
cfg:enable_symbol(v) | |||
end, data['symbols_enabled']) | |||
end | |||
if data['symbols_disabled'] then | |||
fun.each(function(i, v) | |||
fun.each(function(_, v) | |||
cfg:disable_symbol(v) | |||
end, data['symbols_disabled']) | |||
end | |||
@@ -177,7 +176,7 @@ local function update_dynamic_conf(cfg, ev_base, recv) | |||
cur_settings.updates.actions = {} | |||
end | |||
end | |||
local function redis_data_set_cb(err, data) | |||
local function redis_data_set_cb(err) | |||
if err then | |||
rspamd_logger.errx(cfg, "cannot save dynamic conf to redis: %s", err) | |||
else | |||
@@ -195,7 +194,7 @@ local function update_dynamic_conf(cfg, ev_base, recv) | |||
fun.each(function(k, v) | |||
cur_settings.data.scores[k] = v | |||
end, | |||
fun.filter(function(k,v) | |||
fun.filter(function(k) | |||
if cur_settings.updates.symbols[k] then | |||
return false | |||
end | |||
@@ -209,7 +208,7 @@ local function update_dynamic_conf(cfg, ev_base, recv) | |||
fun.each(function(k, v) | |||
cur_settings.data.actions[k] = v | |||
end, | |||
fun.filter(function(k,v) | |||
fun.filter(function(k) | |||
if cur_settings.updates.actions[k] then | |||
return false | |||
end | |||
@@ -223,10 +222,12 @@ local function update_dynamic_conf(cfg, ev_base, recv) | |||
end | |||
local function check_dynamic_conf(cfg, ev_base) | |||
local function redis_load_cb(err, data) | |||
if data and type(data) == 'string' then | |||
local function redis_load_cb(redis_err, data) | |||
if redis_err then | |||
rspamd_logger.errx(cfg, "cannot read dynamic conf from redis: %s", redis_err) | |||
elseif data and type(data) == 'string' then | |||
local parser = ucl.parser() | |||
local res,err = parser:parse_string(data) | |||
local _,err = parser:parse_string(data) | |||
if err then | |||
rspamd_logger.errx(cfg, "cannot load dynamic conf from redis: %s", err) | |||
@@ -278,17 +279,17 @@ if section then | |||
settings[k] = v | |||
end | |||
rspamd_config:add_on_load(function(cfg, ev_base) | |||
rspamd_config:add_on_load(function(_, ev_base) | |||
rspamd_config:add_periodic(ev_base, 0.0, | |||
function(cfg, ev_base) | |||
check_dynamic_conf(cfg, ev_base) | |||
function(cfg, _ev_base) | |||
check_dynamic_conf(cfg, _ev_base) | |||
return settings.redis_watch_interval | |||
end, true) | |||
end) | |||
end | |||
-- Updates part | |||
local function add_dynamic_symbol(cfg, sym, score) | |||
local function add_dynamic_symbol(_, sym, score) | |||
local add = false | |||
if not cur_settings.data then | |||
cur_settings.data = {} | |||
@@ -318,7 +319,7 @@ local function add_dynamic_symbol(cfg, sym, score) | |||
return add | |||
end | |||
local function add_dynamic_action(cfg, act, score) | |||
local function add_dynamic_action(_, act, score) | |||
local add = false | |||
if not cur_settings.data then | |||
cur_settings.data = {} |
@@ -24,15 +24,17 @@ local logger = require "rspamd_logger" | |||
-- Check rule for a single email | |||
local function check_email_rule(task, rule, addr) | |||
local function emails_dns_cb(resolver, to_resolve, results, err) | |||
if results then | |||
local function emails_dns_cb(_, to_resolve, results, err) | |||
if err then | |||
logger.errx(task, 'Error querying DNS: %1', err) | |||
elseif results then | |||
logger.infox(task, '<%1> email: [%2] resolved for symbol: %3', | |||
task:get_message_id(), to_resolve, rule['symbol']) | |||
task:insert_result(rule['symbol'], 1) | |||
end | |||
end | |||
if rule['dnsbl'] then | |||
local to_resolve = '' | |||
local to_resolve | |||
if rule['domain_only'] then | |||
to_resolve = string.format('%s.%s', addr:get_host(), rule['dnsbl']) | |||
else |
@@ -17,7 +17,6 @@ limitations under the License. | |||
-- Plugin for comparing smtp dialog recipients and sender with recipients and sender | |||
-- in mime headers | |||
local logger = require "rspamd_logger" | |||
local symbol_rcpt = 'FORGED_RECIPIENTS' | |||
local symbol_sender = 'FORGED_SENDER' | |||
@@ -25,7 +24,7 @@ local function check_forged_headers(task) | |||
local auser = task:get_user() | |||
local smtp_rcpt = task:get_recipients(1) | |||
local smtp_from = task:get_from(1) | |||
local res = false | |||
local res | |||
local score = 1.0 | |||
if not smtp_rcpt then return end |
@@ -53,11 +53,8 @@ local settings = { | |||
} | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_redis = require "rspamd_redis" | |||
local upstream_list = require "rspamd_upstream_list" | |||
local rspamd_util = require "rspamd_util" | |||
local fun = require "fun" | |||
local rspamd_cryptobox = require "rspamd_cryptobox" | |||
local hash = require "rspamd_cryptobox_hash" | |||
local function data_key(task) | |||
@@ -144,8 +141,6 @@ local function check_time(task, tm, type) | |||
return true,false | |||
end | |||
return false,false | |||
end | |||
local function greylist_check(task) | |||
@@ -168,21 +163,11 @@ local function greylist_check(task) | |||
local hash_key = body_key .. meta_key | |||
local upstream | |||
local function redis_set_cb(err, data) | |||
if not err then | |||
upstream:ok() | |||
else | |||
rspamd_logger.errx(task, 'got error %s when setting greylisting record on server %s', | |||
err, upstream:get_addr()) | |||
end | |||
end | |||
local function redis_get_cb(err, data) | |||
local ret_body = false | |||
local greylisted_body = false | |||
local ret_meta = false | |||
local greylisted_meta = false | |||
local greylist_type | |||
if data then | |||
if data[1] and type(data[1]) ~= 'userdata' then | |||
@@ -205,8 +190,6 @@ local function greylist_check(task) | |||
end | |||
end | |||
upstream:ok() | |||
if not ret_body and not ret_meta then | |||
local end_time = rspamd_util.time_to_string(rspamd_util.get_time() | |||
+ settings['timeout']) | |||
@@ -216,11 +199,10 @@ local function greylist_check(task) | |||
settings['timeout']) | |||
rspamd_logger.infox(task, 'greylisted until "%s" using %s key', | |||
end_time, type) | |||
task:insert_result(settings['symbol'], 0.0, 'greylisted', end_time, | |||
greylist_type) | |||
task:insert_result(settings['symbol'], 0.0, 'greylisted', end_time) | |||
if settings.message_func then | |||
task:set_pre_result('soft reject', | |||
settings.message_func(task, end_time, greylist_type)) | |||
settings.message_func(task, end_time)) | |||
else | |||
task:set_pre_result('soft reject', settings['message']) | |||
end | |||
@@ -228,7 +210,9 @@ local function greylist_check(task) | |||
elseif err then | |||
rspamd_logger.errx(task, 'got error while getting greylisting keys: %1', err) | |||
upstream:fail() | |||
return | |||
end | |||
upstream:ok() | |||
end | |||
local ret, _ | |||
@@ -242,6 +226,7 @@ local function greylist_check(task) | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'cannot make redis request to check results') | |||
upstream:fail() | |||
end | |||
end | |||
@@ -284,12 +269,13 @@ local function greylist_set(task) | |||
local upstream, ret, conn | |||
local hash_key = body_key .. meta_key | |||
local function redis_set_cb(err, data) | |||
local function redis_set_cb(err) | |||
if not err then | |||
upstream:ok() | |||
else | |||
rspamd_logger.errx(task, 'got error %s when setting greylisting record on server %s', | |||
err, upstream:get_addr()) | |||
upstream:fail() | |||
end | |||
end | |||
@@ -313,7 +299,7 @@ local function greylist_set(task) | |||
{body_key, tostring(settings['expire'])} -- arguments | |||
) | |||
-- Update greylisting record expire | |||
if conn then | |||
if ret then | |||
conn:add_cmd('EXPIRE', { | |||
meta_key, tostring(settings['expire']) | |||
}) | |||
@@ -329,7 +315,6 @@ local function greylist_set(task) | |||
'new record') | |||
task:set_pre_result(settings['action'], settings['message']) | |||
-- Create new record | |||
local ret, conn | |||
ret,conn,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
hash_key, -- hash key | |||
@@ -339,12 +324,10 @@ local function greylist_set(task) | |||
{body_key, tostring(settings['expire']), t} -- arguments | |||
) | |||
if conn then | |||
if ret then | |||
conn:add_cmd('SETEX', { | |||
meta_key, tostring(settings['expire']), t | |||
}) | |||
local end_time = rspamd_util.time_to_string(rspamd_util.get_time() | |||
+ settings['timeout']) | |||
else | |||
rspamd_logger.infox(task, 'got error while connecting to redis: %s', | |||
upstream:get_addr()) | |||
@@ -380,7 +363,7 @@ end | |||
local opts = rspamd_config:get_all_opt('greylist') | |||
if opts then | |||
if opts['message_func'] then | |||
settings.message_func = assert(loadstring(opts['message_func']))() | |||
settings.message_func = assert(load(opts['message_func']))() | |||
end | |||
for k,v in pairs(opts) do | |||
if k ~= 'message_func' then |
@@ -22,7 +22,6 @@ limitations under the License. | |||
--local dumper = require 'pl.pretty'.dump | |||
local rspamd_regexp = require "rspamd_regexp" | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamc_local_helo = "rspamc.local" | |||
local checks_hellohost = { | |||
['[.-]gprs[.-]'] = 5, ['gprs[.-][0-9]'] = 5, ['[0-9][.-]?gprs'] = 5, | |||
@@ -69,30 +68,30 @@ local checks_hello = { | |||
} | |||
local checks_hello_badip = { | |||
['^0\\.'] = 5, | |||
['^::1$'] = 5, --loopback ipv4, ipv6 | |||
['^127\\.'] = 5, | |||
['^10\\.'] = 5, | |||
['^192\\.168\\.'] = 5, --local ipv4 | |||
['^172\\.1[6-9]\\.'] = 5, | |||
['^172\\.2[0-9]\\.'] = 5, | |||
['^172\\.3[01]\\.'] = 5, --local ipv4 | |||
['^169\\.254\\.'] = 5, --chanel ipv4 | |||
['^192\\.0\\.0\\.'] = 5, --IETF Protocol | |||
['^192\\.88\\.99\\.'] = 5, --RFC3068 | |||
['^100.6[4-9]\\.'] = 5, | |||
['^100.[7-9]\\d\\.'] = 5, | |||
['^100.1[01]\\d\\.'] = 5, | |||
['^100.12[0-7]\\d\\.'] = 5, --RFC6598 | |||
['^\\d\\.\\d\\.\\d\\.255$'] = 5, --multicast ipv4 | |||
['^192\\.0\\.2\\.'] = 5, | |||
['^198\\.51\\.100\\.'] = 5, | |||
['^203\\.0\\.113\\.'] = 5, --sample | |||
['^fe[89ab][0-9a-f]::'] = 5, | |||
['^fe[cdf][0-9a-f]:'] = 5, --local ipv6 (fe80:: - febf::, fec0:: - feff::) | |||
['^2001:db8::'] = 5, --reserved RFC 3849 for ipv6 | |||
['^fc00::'] = 5, | |||
['^ffxx::'] = 5 --unicast, multicast ipv6 | |||
['^0\\.'] = 1, | |||
['^::1$'] = 1, --loopback ipv4, ipv6 | |||
['^127\\.'] = 1, | |||
['^10\\.'] = 1, | |||
['^192\\.168\\.'] = 1, --local ipv4 | |||
['^172\\.1[6-9]\\.'] = 1, | |||
['^172\\.2[0-9]\\.'] = 1, | |||
['^172\\.3[01]\\.'] = 1, --local ipv4 | |||
['^169\\.254\\.'] = 1, --chanel ipv4 | |||
['^192\\.0\\.0\\.'] = 1, --IETF Protocol | |||
['^192\\.88\\.99\\.'] = 1, --RFC3068 | |||
['^100.6[4-9]\\.'] = 1, | |||
['^100.[7-9]\\d\\.'] = 1, | |||
['^100.1[01]\\d\\.'] = 1, | |||
['^100.12[0-7]\\d\\.'] = 1, --RFC6598 | |||
['^\\d\\.\\d\\.\\d\\.255$'] = 1, --multicast ipv4 | |||
['^192\\.0\\.2\\.'] = 1, | |||
['^198\\.51\\.100\\.'] = 1, | |||
['^203\\.0\\.113\\.'] = 1, --sample | |||
['^fe[89ab][0-9a-f]::'] = 1, | |||
['^fe[cdf][0-9a-f]:'] = 1, --local ipv6 (fe80:: - febf::, fec0:: - feff::) | |||
['^2001:db8::'] = 1, --reserved RFC 3849 for ipv6 | |||
['^fc00::'] = 1, | |||
['^ffxx::'] = 1 --unicast, multicast ipv6 | |||
} | |||
local checks_hello_bareip = { | |||
@@ -143,7 +142,7 @@ local function check_host(task, host, symbol_suffix, eq_ip, eq_host) | |||
local failed_address = 0 | |||
local resolved_address = {} | |||
local function check_host_cb_mx(resolver, to_resolve, results, err) | |||
local function check_host_cb_mx(_, _, results) | |||
task:inc_dns_req() | |||
if not results then | |||
task:insert_result('HFILTER_' .. symbol_suffix .. '_NORES_A_OR_MX', 1.0) | |||
@@ -152,10 +151,10 @@ local function check_host(task, host, symbol_suffix, eq_ip, eq_host) | |||
if mx['name'] then | |||
local failed_mx_address = 0 | |||
-- Capture failed_mx_address | |||
local function check_host_cb_mx_a(resolver, to_resolve, results, err) | |||
local function check_host_cb_mx_a(_, _, mx_results) | |||
task:inc_dns_req() | |||
if not results then | |||
if not mx_results then | |||
failed_mx_address = failed_mx_address + 1 | |||
end | |||
@@ -178,7 +177,7 @@ local function check_host(task, host, symbol_suffix, eq_ip, eq_host) | |||
end | |||
end | |||
end | |||
local function check_host_cb_a(resolver, to_resolve, results, err) | |||
local function check_host_cb_a(_, _, results) | |||
task:inc_dns_req() | |||
if not results then | |||
@@ -259,7 +258,7 @@ local function hfilter(task) | |||
local hc = html_text_part:get_html() | |||
if hc then | |||
local url_len = 0 | |||
hc:foreach_tag('a', function(tag, len) | |||
hc:foreach_tag('a', function(_, len) | |||
url_len = url_len + len | |||
return false | |||
end) | |||
@@ -322,7 +321,7 @@ local function hfilter(task) | |||
local find_badip = false | |||
for regexp,weight in pairs(checks_hello_badip) do | |||
if check_regexp(helo, regexp) then | |||
task:insert_result('HFILTER_HELO_BADIP', 1.0) | |||
task:insert_result('HFILTER_HELO_BADIP', weight) | |||
find_badip = true | |||
break | |||
end | |||
@@ -494,7 +493,7 @@ if opts and type(opts) ~= 'table' then | |||
end | |||
end | |||
local opts = rspamd_config:get_all_opt('hfilter') | |||
opts = rspamd_config:get_all_opt('hfilter') | |||
if opts then | |||
for k,v in pairs(opts) do | |||
config[k] = v |
@@ -16,17 +16,15 @@ limitations under the License. | |||
-- IP score is a module that set ip score of specific ip, asn, country | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_redis = require "rspamd_redis" | |||
local upstream_list = require "rspamd_upstream_list" | |||
local rspamd_regexp = require "rspamd_regexp" | |||
local rspamd_util = require "rspamd_util" | |||
local _ = require "fun" | |||
-- Default settings | |||
local redis_params = nil | |||
local whitelist = nil | |||
local asn_cc_whitelist = nil | |||
local check_authed = false | |||
local check_local = false | |||
local options = { | |||
actions = { -- how each action is treated in scoring | |||
@@ -105,20 +103,23 @@ local ip_score_set = function(task) | |||
return old_score + score, new_total | |||
end | |||
local score_set_cb = function(err, data) | |||
local score_set_cb = function(err) | |||
if err then | |||
rspamd_logger.infox(task, 'got error while IP score changing: %1', err) | |||
end | |||
end | |||
local ip = task:get_from_ip() | |||
if task:get_user() or (ip and ip:is_local()) then | |||
if not check_authed and task:get_user() then | |||
return | |||
end | |||
local action = task:get_metric_action(options['metric']) | |||
if not ip or not ip:is_valid() then | |||
return | |||
end | |||
if not check_local and ip:is_local() then | |||
return | |||
end | |||
local pool = task:get_mempool() | |||
local asn, country, ipnet = ip_score_get_task_vars(task) | |||
@@ -145,7 +146,6 @@ local ip_score_set = function(task) | |||
score = score_mult * rspamd_util.tanh (2.718281 * (score/options['score_divisor'])) | |||
local hkey = ip_score_hash_key(asn, country, ipnet, ip) | |||
local upstream,ret | |||
asn_score,total_asn = new_score_set(score, asn_score, total_asn) | |||
country_score,total_country = new_score_set(score, country_score, total_country) | |||
@@ -157,7 +157,7 @@ local ip_score_set = function(task) | |||
options['ipnet_prefix'] .. ipnet, string.format('%f|%d', ipnet_score, total_ipnet), | |||
ip:to_string(), string.format('%f|%d', ip_score, total_ip)} | |||
ret,_,upstream = rspamd_redis_make_request(task, | |||
local ret,_,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
hkey, -- hash key | |||
true, -- is write | |||
@@ -165,6 +165,11 @@ local ip_score_set = function(task) | |||
'HMSET', -- command | |||
redis_args -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Redis HMSET failed on %s', upstream:get_addr()) | |||
upstream:fail() | |||
return | |||
end | |||
-- Now insert final result | |||
asn_score = normalize_score(asn_score, total_asn, options['scores']['asn']) | |||
@@ -209,8 +214,13 @@ end | |||
-- Check score for ip in keystorage | |||
local ip_score_check = function(task) | |||
local asn, country, ipnet = ip_score_get_task_vars(task) | |||
local ip = task:get_from_ip() | |||
local ip_score_redis_cb = function(err, data) | |||
if err then | |||
rspamd_logger.errx(task, 'Redis error: %s', err) | |||
-- XXX: upstreams | |||
end | |||
local function calculate_score(score) | |||
local parts = asn_re:split(score) | |||
local rep = tonumber(parts[1]) | |||
@@ -248,7 +258,7 @@ local ip_score_check = function(task) | |||
end | |||
end | |||
local function create_get_command(ip, asn, country, ipnet) | |||
local function create_get_command() | |||
local cmd = 'HMGET' | |||
local args = {options['hash']} | |||
@@ -277,7 +287,6 @@ local ip_score_check = function(task) | |||
return cmd, args | |||
end | |||
local ip = task:get_from_ip() | |||
if task:get_user() or (ip and ip:is_local()) then | |||
rspamd_logger.infox(task, "skip IP Score for local networks and authorized users") | |||
return | |||
@@ -300,7 +309,7 @@ local ip_score_check = function(task) | |||
end | |||
end | |||
local cmd, args = create_get_command(ip, asn, country, ipnet) | |||
local cmd, args = create_get_command() | |||
local ret,_,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
@@ -310,6 +319,10 @@ local ip_score_check = function(task) | |||
cmd, -- command | |||
args -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Call to redis at %s failed', upstream:get_addr()) | |||
upstream:fail() | |||
end | |||
end | |||
end | |||
@@ -321,6 +334,9 @@ local configure_ip_score_module = function() | |||
if type(opts['check_authed']) == 'boolean' then | |||
check_authed = opts['check_authed'] | |||
end | |||
if type(opts['check_local']) == 'boolean' then | |||
check_local = opts['check_local'] | |||
end | |||
end | |||
opts = rspamd_config:get_all_opt('ip_score') | |||
if not opts then return end |
@@ -17,7 +17,6 @@ limitations under the License. | |||
-- Module for checking mail list headers | |||
local symbol = 'MAILLIST' | |||
local rspamd_logger = require "rspamd_logger" | |||
-- EZMLM | |||
-- Mailing-List: .*run by ezmlm | |||
-- Precedence: bulk | |||
@@ -219,7 +218,7 @@ local function check_ml_majordomo(task) | |||
return false | |||
end | |||
local header = task:get_header('Precedence') | |||
header = task:get_header('Precedence') | |||
if not header or (header ~= 'list' and header ~= 'bulk') then | |||
return false | |||
end |
@@ -46,18 +46,18 @@ if url then | |||
rspamd_http = require "rspamd_http" | |||
end | |||
if opts['select'] then | |||
settings.select = assert(loadstring(opts['select']))() | |||
settings.select = assert(load(opts['select']))() | |||
end | |||
if opts['format'] then | |||
settings.format = assert(loadstring(opts['format']))() | |||
settings.format = assert(load(opts['format']))() | |||
end | |||
if opts['mime_type'] then | |||
settings['mime_type'] = opts['mime_type'] | |||
end | |||
local function metadata_exporter(task) | |||
local ret,conn,upstream | |||
local function http_callback(err, code, body, headers) | |||
local _,ret,upstream | |||
local function http_callback(err, code) | |||
if err then | |||
rspamd_logger.errx(task, 'got error %s in http callback', err) | |||
end | |||
@@ -65,7 +65,7 @@ local function metadata_exporter(task) | |||
rspamd_logger.errx(task, 'got unexpected http status: %s', code) | |||
end | |||
end | |||
local function redis_set_cb(err, data) | |||
local function redis_set_cb(err) | |||
if err then | |||
rspamd_logger.errx(task, 'got error %s when publishing record on server %s', | |||
err, upstream:get_addr()) | |||
@@ -84,7 +84,7 @@ local function metadata_exporter(task) | |||
return | |||
end | |||
if channel then | |||
ret,conn,upstream = rspamd_redis_make_request(task, | |||
ret,_,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
nil, -- hash key | |||
true, -- is write | |||
@@ -92,6 +92,10 @@ local function metadata_exporter(task) | |||
'PUBLISH', -- command | |||
{channel, data} -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Redis PUBLISH failed') | |||
upstream:fail() | |||
end | |||
end | |||
if url then | |||
rspamd_http.request({ |
@@ -85,7 +85,7 @@ local function load_defaults(defaults) | |||
end | |||
end | |||
local function graphite_config(opts) | |||
local function graphite_config() | |||
load_defaults({ | |||
host = 'localhost', | |||
port = 2003, | |||
@@ -124,7 +124,7 @@ local function graphite_push(kwargs) | |||
data = { | |||
metrics_str, | |||
}, | |||
callback = (function (err, data) | |||
callback = (function (err) | |||
if err then | |||
logger.errx('Push failed: %1', err) | |||
return | |||
@@ -150,16 +150,16 @@ local function configure_metric_exporter() | |||
for k, v in pairs(opts) do | |||
settings[k] = v | |||
end | |||
return backends[opts['backend']]['configure'](opts) | |||
return backends[opts['backend']]['configure']() | |||
end | |||
if not configure_metric_exporter() then return end | |||
rspamd_config:add_on_load(function (cfg, ev_base, worker) | |||
rspamd_config:add_on_load(function (_, ev_base, worker) | |||
-- Exit unless we're the first 'normal' worker | |||
if not (worker:get_name() == 'normal' and worker:get_index() == 0) then return end | |||
-- Persist mempool variable to statefile on shutdown | |||
rspamd_config:register_finish_script(function (task) | |||
rspamd_config:register_finish_script(function () | |||
local stamp = pool:get_variable(VAR_NAME, 'double') | |||
if not stamp then | |||
logger.warn('No last metric exporter push to persist to disk') | |||
@@ -176,7 +176,7 @@ rspamd_config:add_on_load(function (cfg, ev_base, worker) | |||
end | |||
end) | |||
-- Push metrics to backend | |||
local function push_metrics(worker, time) | |||
local function push_metrics(time) | |||
logger.infox('Pushing metrics to %s backend', settings['backend']) | |||
local args = { | |||
ev_base = ev_base, | |||
@@ -189,15 +189,15 @@ rspamd_config:add_on_load(function (cfg, ev_base, worker) | |||
end | |||
-- Push metrics at regular intervals | |||
local function schedule_regular_push() | |||
rspamd_config:add_periodic(ev_base, settings['interval'], function (cfg, ev_base) | |||
push_metrics(worker) | |||
rspamd_config:add_periodic(ev_base, settings['interval'], function () | |||
push_metrics() | |||
return true | |||
end) | |||
end | |||
-- Push metrics to backend and reschedule check | |||
local function schedule_intermediate_push(when) | |||
rspamd_config:add_periodic(ev_base, when, function (cfg, ev_base) | |||
push_metrics(worker) | |||
rspamd_config:add_periodic(ev_base, when, function () | |||
push_metrics() | |||
schedule_regular_push() | |||
return false | |||
end) | |||
@@ -215,7 +215,7 @@ rspamd_config:add_on_load(function (cfg, ev_base, worker) | |||
end | |||
if not stamp then | |||
logger.debug('No state found - pushing stats immediately') | |||
push_metrics(worker) | |||
push_metrics() | |||
schedule_regular_push() | |||
return | |||
end | |||
@@ -223,7 +223,7 @@ rspamd_config:add_on_load(function (cfg, ev_base, worker) | |||
local delta = stamp - time + settings['interval'] | |||
if delta <= 0 then | |||
logger.debug('Last push is too old - pushing stats immediately') | |||
push_metrics(worker, time) | |||
push_metrics(time) | |||
schedule_regular_push() | |||
return | |||
end |
@@ -15,8 +15,6 @@ limitations under the License. | |||
]]-- | |||
-- This plugin implements mime types checks for mail messages | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_regexp = require "rspamd_regexp" | |||
local settings = { | |||
file = '', |
@@ -22,7 +22,6 @@ local cdb = require "rspamd_cdb" | |||
local util = require "rspamd_util" | |||
local regexp = require "rspamd_regexp" | |||
local rspamd_expression = require "rspamd_expression" | |||
local rspamd_redis = require "rspamd_redis" | |||
local redis_params | |||
local fun = require "fun" | |||
@@ -54,7 +53,7 @@ local value_types = { | |||
get_value = function(val) return val end, | |||
}, | |||
content = { | |||
get_value = function(val) return nil end, | |||
get_value = function() return nil end, | |||
}, | |||
hostname = { | |||
get_value = function(val) return val end, | |||
@@ -267,7 +266,7 @@ local function apply_regexp_filter(task, filter, fn, r) | |||
return fn | |||
end | |||
local function apply_content_filter(task, filter, r) | |||
local function apply_content_filter(task, filter) | |||
if filter == 'body' then | |||
return {task:get_rawbody()} | |||
elseif filter == 'full' then | |||
@@ -276,19 +275,19 @@ local function apply_content_filter(task, filter, r) | |||
return {task:get_raw_headers()} | |||
elseif filter == 'text' then | |||
local ret = {} | |||
for i,p in ipairs(task:get_text_parts()) do | |||
for _,p in ipairs(task:get_text_parts()) do | |||
table.insert(ret, p:get_content()) | |||
end | |||
return ret | |||
elseif filter == 'rawtext' then | |||
local ret = {} | |||
for i,p in ipairs(task:get_text_parts()) do | |||
for _,p in ipairs(task:get_text_parts()) do | |||
table.insert(ret, p:get_raw_content()) | |||
end | |||
return ret | |||
elseif filter == 'oneline' then | |||
local ret = {} | |||
for i,p in ipairs(task:get_text_parts()) do | |||
for _,p in ipairs(task:get_text_parts()) do | |||
table.insert(ret, p:get_content_oneline()) | |||
end | |||
return ret | |||
@@ -306,6 +305,7 @@ local multimap_filters = { | |||
url = apply_url_filter, | |||
filename = apply_filename_filter, | |||
mempool = apply_regexp_filter, | |||
hostname = apply_hostname_filter, | |||
--content = apply_content_filter, -- Content filters are special :( | |||
} | |||
@@ -359,8 +359,8 @@ local function multimap_callback(task, rule) | |||
end | |||
-- Parse result in form: <symbol>:<score>|<symbol>|<score> | |||
local function parse_ret(rule, ret) | |||
if ret and type(ret) == 'string' then | |||
local function parse_ret(parse_rule, p_ret) | |||
if p_ret and type(p_ret) == 'string' then | |||
local lpeg = require "lpeg" | |||
local number = {} | |||
@@ -388,7 +388,7 @@ local function multimap_callback(task, rule) | |||
local symscore_cap = (symbol_cap * lpeg.P(":") * score_cap) | |||
local grammar = symscore_cap + symbol_cap + score_cap | |||
local parser = lpeg.Ct(grammar) | |||
local tbl = parser:match(ret) | |||
local tbl = parser:match(p_ret) | |||
if tbl then | |||
local sym = nil | |||
@@ -403,15 +403,15 @@ local function multimap_callback(task, rule) | |||
return true,sym,score | |||
else | |||
if ret ~= '' then | |||
if p_ret ~= '' then | |||
rspamd_logger.infox(task, '%s: cannot parse string "%s"', | |||
rule.symbol, ret) | |||
parse_rule.symbol, p_ret) | |||
end | |||
return true,nil,1.0 | |||
end | |||
elseif type(ret) == 'boolean' then | |||
return ret,nil,0.0 | |||
elseif type(p_ret) == 'boolean' then | |||
return p_ret,nil,0.0 | |||
end | |||
return false,nil,0.0 | |||
@@ -421,7 +421,7 @@ local function multimap_callback(task, rule) | |||
local function match_rule(r, value) | |||
local function rule_callback(result) | |||
if result then | |||
local res,symbol,score = parse_ret(r, result) | |||
local _,symbol,score = parse_ret(r, result) | |||
if symbol and r['symbols_set'] then | |||
if not r['symbols_set'][symbol] then | |||
rspamd_logger.infox(task, 'symbol %s is not registered for map %s, ' .. | |||
@@ -495,7 +495,7 @@ local function multimap_callback(task, rule) | |||
end | |||
local function match_content(r) | |||
local data = {} | |||
local data | |||
if r['filter'] then | |||
data = apply_content_filter(task, r['filter'], r) | |||
@@ -503,7 +503,7 @@ local function multimap_callback(task, rule) | |||
data = {task:get_content()} | |||
end | |||
for i,v in ipairs(data) do | |||
for _,v in ipairs(data) do | |||
match_rule(r, v) | |||
end | |||
end | |||
@@ -527,7 +527,10 @@ local function multimap_callback(task, rule) | |||
if rt == 'ip' then | |||
match_rule(rule, ip) | |||
else | |||
local cb = function (resolver, to_resolve, results, err, rbl) | |||
local cb = function (_, _, results, err) | |||
if err then | |||
rspamd_logger.errx(task, 'DNS lookup failed: %s', err) | |||
end | |||
if results then | |||
task:insert_result(rule['symbol'], 1, rule['map']) | |||
@@ -558,18 +561,18 @@ local function multimap_callback(task, rule) | |||
end | |||
elseif rt == 'url' then | |||
if task:has_urls() then | |||
local urls = task:get_urls() | |||
for i,url in ipairs(urls) do | |||
local msg_urls = task:get_urls() | |||
for _,url in ipairs(msg_urls) do | |||
match_url(rule, url) | |||
end | |||
end | |||
elseif rt == 'filename' then | |||
local parts = task:get_parts() | |||
for i,p in ipairs(parts) do | |||
for _,p in ipairs(parts) do | |||
if p:is_archive() then | |||
local fnames = p:get_archive():get_files() | |||
for ii,fn in ipairs(fnames) do | |||
for _,fn in ipairs(fnames) do | |||
match_filename(rule, fn) | |||
end | |||
end | |||
@@ -635,7 +638,6 @@ local function add_multimap_rule(key, newrule) | |||
end | |||
-- Check cdb flag | |||
if string.find(newrule['map'], '^cdb://.*$') then | |||
local test = cdb.create(newrule['map']) | |||
newrule['cdb'] = cdb.create(newrule['map']) | |||
if newrule['cdb'] then | |||
ret = true | |||
@@ -747,10 +749,10 @@ local function add_multimap_rule(key, newrule) | |||
end | |||
local function process_atom(atom, task) | |||
local ret = task:has_symbol(atom) | |||
rspamd_logger.debugx('check for symbol %s: %s', atom, ret) | |||
local f_ret = task:has_symbol(atom) | |||
rspamd_logger.debugx('check for symbol %s: %s', atom, f_ret) | |||
if ret then | |||
if f_ret then | |||
return 1 | |||
end | |||
@@ -17,7 +17,6 @@ limitations under the License. | |||
-- MX check plugin | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_tcp = require "rspamd_tcp" | |||
local rspamd_redis = require "rspamd_redis" | |||
local rspamd_util = require "rspamd_util" | |||
local fun = require "fun" | |||
@@ -56,15 +55,19 @@ local function mx_check(task) | |||
end | |||
local valid = false | |||
local ret,_,upstream | |||
local function check_results(mxes) | |||
if fun.all(function(k, elt) return elt.checked end, mxes) then | |||
if fun.all(function(_, elt) return elt.checked end, mxes) then | |||
-- Save cache | |||
local key = settings.key_prefix .. mx_domain | |||
local function redis_cache_cb(err, data) | |||
local function redis_cache_cb(err) | |||
if err ~= nil then | |||
rspamd_logger.errx(task, 'redis_cache_cb received error: %1', err) | |||
upstream:fail() | |||
return | |||
else | |||
upstream:ok() | |||
end | |||
end | |||
if not valid then | |||
@@ -78,7 +81,7 @@ local function mx_check(task) | |||
else | |||
task:insert_result(settings.symbol_bad_mx, 1.0) | |||
end | |||
local ret,_,_ = rspamd_redis_make_request(task, | |||
ret,_,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
key, -- hash key | |||
false, -- is write | |||
@@ -86,13 +89,17 @@ local function mx_check(task) | |||
'SETEX', -- command | |||
{key, tostring(settings.expire_novalid), '0'} -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Redis SETEX failed') | |||
upstream:fail() | |||
end | |||
else | |||
local valid_mx = {} | |||
fun.each(function(k, mx) | |||
fun.each(function(k) | |||
table.insert(valid_mx, k) | |||
end, fun.filter(function (k, elt) return elt.working end, mxes)) | |||
end, fun.filter(function (_, elt) return elt.working end, mxes)) | |||
task:insert_result(settings.symbol_good_mx, 1.0, valid_mx) | |||
local ret,_,_ = rspamd_redis_make_request(task, | |||
ret,_,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
key, -- hash key | |||
false, -- is write | |||
@@ -100,16 +107,20 @@ local function mx_check(task) | |||
'SETEX', -- command | |||
{key, tostring(settings.expire), table.concat(valid_mx, ';')} -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Redis SETEX failed') | |||
upstream:fail() | |||
end | |||
end | |||
end | |||
end | |||
local function gen_mx_a_callback(name, mxes) | |||
return function(resolver, to_resolve, results, err, _, authenticated) | |||
return function(_, _, results, err) | |||
mxes[name].ips = results | |||
local function io_cb(err, data, conn) | |||
if err then | |||
local function io_cb(io_err) | |||
if io_err then | |||
mxes[name].checked = true | |||
else | |||
mxes[name].checked = true | |||
@@ -135,7 +146,7 @@ local function mx_check(task) | |||
else | |||
-- Try to open TCP connection to port 25 | |||
for _,res in ipairs(results) do | |||
local ret = rspamd_tcp.new({ | |||
local t_ret = rspamd_tcp.new({ | |||
task = task, | |||
host = res:to_string(), | |||
callback = io_cb, | |||
@@ -144,7 +155,7 @@ local function mx_check(task) | |||
port = 25 | |||
}) | |||
if not ret then | |||
if not t_ret then | |||
mxes[name].checked = true | |||
end | |||
end | |||
@@ -153,7 +164,7 @@ local function mx_check(task) | |||
end | |||
end | |||
local function mx_callback(resolver, to_resolve, results, err, _, authenticated) | |||
local function mx_callback(_, _, results, err) | |||
local mxes = {} | |||
if err or not results then | |||
local r = task:get_resolver() | |||
@@ -219,7 +230,7 @@ local function mx_check(task) | |||
end | |||
local key = settings.key_prefix .. mx_domain | |||
local ret,_,_ = rspamd_redis_make_request(task, | |||
ret,_,upstream = rspamd_redis_make_request(task, | |||
redis_params, -- connect params | |||
key, -- hash key | |||
false, -- is write | |||
@@ -229,6 +240,7 @@ local function mx_check(task) | |||
) | |||
if not ret then | |||
upstream:fail() | |||
local r = task:get_resolver() | |||
r:resolve('mx', { | |||
name = mx_domain, |
@@ -30,7 +30,10 @@ local check_authed = false | |||
local function check_quantity_received (task) | |||
local recvh = task:get_received_headers() | |||
local function recv_dns_cb(resolver, to_resolve, results, err) | |||
local function recv_dns_cb(_, to_resolve, results, err) | |||
if err then | |||
rspamd_logger.errx(task, 'DNS lookup error: %s', err) | |||
end | |||
task:inc_dns_req() | |||
if not results then | |||
@@ -85,7 +88,6 @@ local function check_quantity_received (task) | |||
return | |||
end | |||
local recvh = task:get_received_headers() | |||
if recvh and #recvh <= 1 then | |||
local ret = true | |||
local r = recvh[1] | |||
@@ -94,13 +96,12 @@ local function check_quantity_received (task) | |||
return | |||
end | |||
local hn = nil | |||
if r['real_hostname'] then | |||
hn = string.lower(r['real_hostname']) | |||
local rhn = string.lower(r['real_hostname']) | |||
-- Check for good hostname | |||
if hn and good_hosts then | |||
if rhn and good_hosts then | |||
for _,gh in ipairs(good_hosts) do | |||
if string.find(hn, gh) then | |||
if string.find(rhn, gh) then | |||
ret = false | |||
break | |||
end | |||
@@ -148,10 +149,10 @@ if opts and type(opts) ~= 'table' then | |||
end | |||
end | |||
-- Configuration | |||
local opts = rspamd_config:get_all_opt('once_received') | |||
opts = rspamd_config:get_all_opt('once_received') | |||
if opts then | |||
if opts['symbol'] then | |||
local symbol = opts['symbol'] | |||
symbol = opts['symbol'] | |||
local id = rspamd_config:register_symbol({ | |||
name = symbol, |
@@ -26,7 +26,6 @@ local redirector_domains = {} | |||
local openphish_map = 'https://www.openphish.com/feed.txt' | |||
local phishtank_map = 'http://data.phishtank.com/data/online-valid.json' | |||
-- Not enabled by default as their feed is quite large | |||
local phishtank_enabled = false | |||
local openphish_premium = false | |||
local openphish_hash | |||
local phishtank_hash | |||
@@ -41,7 +40,7 @@ if not (opts and type(opts) == 'table') then | |||
end | |||
local function phishing_cb(task) | |||
local function check_phishing_map(map, url, symbol) | |||
local function check_phishing_map(map, url, phish_symbol) | |||
local host = url:get_host() | |||
if host then | |||
@@ -49,7 +48,6 @@ local function phishing_cb(task) | |||
local found_path = false | |||
local found_query = false | |||
local data = nil | |||
local d | |||
if elt then | |||
local path = url:get_path() | |||
@@ -69,14 +67,17 @@ local function phishing_cb(task) | |||
end | |||
end | |||
else | |||
if not d['path'] then | |||
found_path = true | |||
found_query = true | |||
for _,d in ipairs(elt) do | |||
if not d['path'] then | |||
found_path = true | |||
found_query = true | |||
break | |||
end | |||
end | |||
end | |||
if found_path then | |||
local args = nil | |||
local args | |||
if type(data) == 'table' then | |||
args = { | |||
@@ -92,15 +93,15 @@ local function phishing_cb(task) | |||
if found_query then | |||
-- Query + path match | |||
task:insert_result(symbol, 1.0, args) | |||
task:insert_result(phish_symbol, 1.0, args) | |||
else | |||
-- Host + path match | |||
task:insert_result(symbol, 0.3, args) | |||
task:insert_result(phish_symbol, 0.3, args) | |||
end | |||
else | |||
if url:is_phished() then | |||
-- Only host matches | |||
task:insert_result(symbol, 0.1, host) | |||
task:insert_result(phish_symbol, 0.1, host) | |||
end | |||
end | |||
end | |||
@@ -138,7 +139,7 @@ local function phishing_cb(task) | |||
end | |||
rspamd_logger.debugx(task, "distance: %1 -> %2: %3", tld, ptld, dist) | |||
local function found_in_map(map, url, weight) | |||
local function found_in_map(map) | |||
if #map > 0 then | |||
for _,rule in ipairs(map) do | |||
for _,dn in ipairs({url:get_tld(), url:get_host()}) do | |||
@@ -151,7 +152,7 @@ local function phishing_cb(task) | |||
end | |||
end | |||
if not found_in_map(redirector_domains, url, weight) then | |||
if not found_in_map(redirector_domains) then | |||
if not found_in_map(strict_domains, purl, 1.0) then | |||
if domains then | |||
if domains:get_key(ptld) then |
@@ -36,13 +36,11 @@ local ip_score_lower_bound = 10 | |||
local ip_score_ham_multiplier = 1.1 | |||
local ip_score_spam_divisor = 1.1 | |||
local message_func = function(task, limit_type, bucket, threshold) | |||
local message_func = function(_, limit_type) | |||
return string.format('Ratelimit "%s" exceeded', limit_type) | |||
end | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_redis = require "rspamd_redis" | |||
local upstream_list = require "rspamd_upstream_list" | |||
local rspamd_util = require "rspamd_util" | |||
local fun = require "fun" | |||
@@ -152,7 +150,7 @@ local keywords = { | |||
end, | |||
}, | |||
['to'] = { | |||
['get_value'] = function(task) | |||
['get_value'] = function() | |||
return '%s' -- 'to' is special | |||
end, | |||
}, | |||
@@ -215,6 +213,8 @@ local function check_limits(task, args) | |||
if err then | |||
rspamd_logger.infox(task, 'got error while getting limit: %1', err) | |||
upstream:fail() | |||
else | |||
upstream:ok() | |||
end | |||
if not data then return end | |||
local ntime = rspamd_util.get_time() | |||
@@ -307,6 +307,10 @@ local function check_limits(task, args) | |||
'mget', -- command | |||
fun.totable(fun.map(function(l) return l[2] end, args)) -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Redis MGET failed on %s', upstream:get_addr()) | |||
upstream:fail() | |||
end | |||
end | |||
--- Set specific limit inside redis | |||
@@ -314,7 +318,7 @@ local function set_limits(task, args) | |||
local key = fun.foldl(function(acc, k) return acc .. k[2] end, '', args) | |||
local ret, upstream | |||
local function rate_set_cb(err, data) | |||
local function rate_set_cb(err) | |||
if not err then | |||
upstream:ok() | |||
else | |||
@@ -333,7 +337,6 @@ local function set_limits(task, args) | |||
fun.each(function(elt, limit) | |||
local bucket = elt[2] | |||
local rate = limit[1][2] | |||
local threshold = limit[1][1] | |||
local atime = elt[1] | |||
local ctime = elt[3] | |||
@@ -342,7 +345,6 @@ local function set_limits(task, args) | |||
atime - ctime) | |||
bucket = 1 | |||
ctime = ntime | |||
atime = ntime | |||
else | |||
if bucket > 0 then | |||
bucket = bucket - rate * (ntime - atime) + 1; | |||
@@ -391,6 +393,10 @@ local function set_limits(task, args) | |||
'mget', -- command | |||
fun.totable(fun.map(function(l) return l[2] end, args)) -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Redis MGET failed on %s', upstream:get_addr()) | |||
upstream:fail() | |||
end | |||
end | |||
--- Check or update ratelimit | |||
@@ -428,7 +434,7 @@ local function rate_test_set(task, func) | |||
end | |||
local rate_key | |||
for k, v in pairs(settings) do | |||
for k in pairs(settings) do | |||
rate_key = dynamic_rate_key(task, k) | |||
if rate_key then | |||
if type(rate_key) == 'table' then | |||
@@ -517,9 +523,9 @@ if opts then | |||
end, opts['dynamic_rates']) | |||
end | |||
local enabled_limits = fun.totable(fun.map(function(t, lim) | |||
local enabled_limits = fun.totable(fun.map(function(t) | |||
return t | |||
end, fun.filter(function(t, lim) | |||
end, fun.filter(function(_, lim) | |||
return type(lim) == 'string' or | |||
(type(lim) == 'table' and type(lim[1]) == 'number' and lim[1] > 0) | |||
end, settings))) | |||
@@ -573,7 +579,7 @@ if opts then | |||
end | |||
if opts['message_func'] then | |||
message_func = assert(loadstring(opts['message_func']))() | |||
message_func = assert(load(opts['message_func']))() | |||
end | |||
redis_params = rspamd_parse_redis_server('ratelimit') |
@@ -23,7 +23,6 @@ local rbls = {} | |||
local local_exclusions = nil | |||
local rspamd_logger = require 'rspamd_logger' | |||
local rspamd_ip = require 'rspamd_ip' | |||
local rspamd_util = require 'rspamd_util' | |||
local fun = require 'fun' | |||
@@ -62,7 +61,10 @@ end | |||
local function rbl_cb (task) | |||
local function gen_rbl_callback(rule) | |||
return function (resolver, to_resolve, results, err) | |||
return function (_, to_resolve, results, err) | |||
if err then | |||
rspamd_logger.errx(task, 'DNS lookup error: %s', err) | |||
end | |||
if not results then return end | |||
for _,rbl in ipairs(rule.rbls) do | |||
@@ -72,7 +74,7 @@ local function rbl_cb (task) | |||
end | |||
for _,result in pairs(results) do | |||
local ipstr = result:to_string() | |||
local foundrc, s | |||
local foundrc | |||
for s,i in pairs(rbl['returncodes']) do | |||
if type(i) == 'string' then | |||
if string.find(ipstr, '^' .. i .. '$') then | |||
@@ -126,7 +128,7 @@ local function rbl_cb (task) | |||
local havegot = {} | |||
local notgot = {} | |||
local alive_rbls = fun.filter(function(k, rbl) | |||
local alive_rbls = fun.filter(function(_, rbl) | |||
if not rbl.monitored:alive() then | |||
return false | |||
end | |||
@@ -135,7 +137,7 @@ local function rbl_cb (task) | |||
end, rbls) | |||
-- Now exclude rbls, that are disabled by configuration | |||
local enabled_rbls = fun.filter(function(k, rbl) | |||
local enabled_rbls = fun.filter(function(_, rbl) | |||
if rbl['exclude_users'] then | |||
if not havegot['user'] and not notgot['user'] then | |||
havegot['user'] = task:get_user() | |||
@@ -260,17 +262,17 @@ local function rbl_cb (task) | |||
-- Now we iterate over enabled rbls and fill params | |||
-- Helo RBLs | |||
fun.each(function(k, rbl) | |||
fun.each(function(_, rbl) | |||
local to_resolve = havegot['helo'] .. '.' .. rbl['rbl'] | |||
gen_rbl_rule(to_resolve, rbl) | |||
end, | |||
fun.filter(function(k, rbl) | |||
fun.filter(function(_, rbl) | |||
if rbl['helo'] then return true end | |||
return false | |||
end, enabled_rbls)) | |||
-- DKIM RBLs | |||
fun.each(function(k, rbl) | |||
fun.each(function(_, rbl) | |||
for _, d in ipairs(havegot['dkim']) do | |||
if rbl['dkim_domainonly'] then | |||
d = rspamd_util.get_tld(d) | |||
@@ -279,13 +281,13 @@ local function rbl_cb (task) | |||
gen_rbl_rule(to_resolve, rbl) | |||
end | |||
end, | |||
fun.filter(function(k, rbl) | |||
fun.filter(function(_, rbl) | |||
if rbl['dkim'] then return true end | |||
return false | |||
end, enabled_rbls)) | |||
-- Emails RBLs | |||
fun.each(function(k, rbl) | |||
fun.each(function(_, rbl) | |||
if rbl['emails'] == 'domain_only' then | |||
for domain, _ in pairs(havegot['emails']) do | |||
local to_resolve = domain .. '.' .. rbl['rbl'] | |||
@@ -298,36 +300,36 @@ local function rbl_cb (task) | |||
end | |||
end | |||
end, | |||
fun.filter(function(k, rbl) | |||
fun.filter(function(_, rbl) | |||
if rbl['emails'] then return true end | |||
return false | |||
end, enabled_rbls)) | |||
-- RDNS lists | |||
fun.each(function(k, rbl) | |||
fun.each(function(_, rbl) | |||
local to_resolve = havegot['rdns'] .. '.' .. rbl['rbl'] | |||
gen_rbl_rule(to_resolve, rbl) | |||
end, | |||
fun.filter(function(k, rbl) | |||
fun.filter(function(_, rbl) | |||
if rbl['rdns'] then return true end | |||
return false | |||
end, enabled_rbls)) | |||
-- From lists | |||
fun.each(function(k, rbl) | |||
fun.each(function(_, rbl) | |||
if (havegot['from']:get_version() == 6 and rbl['ipv6']) or | |||
(havegot['from']:get_version() == 4 and rbl['ipv4']) then | |||
local to_resolve = ip_to_rbl(havegot['from'], rbl['rbl']) | |||
gen_rbl_rule(to_resolve, rbl) | |||
end | |||
end, | |||
fun.filter(function(k, rbl) | |||
fun.filter(function(_, rbl) | |||
if rbl['from'] then return true end | |||
return false | |||
end, enabled_rbls)) | |||
-- Received lists | |||
fun.each(function(k, rbl) | |||
fun.each(function(_, rbl) | |||
for _,rh in ipairs(havegot['received']) do | |||
if rh['real_ip'] and rh['real_ip']:is_valid() then | |||
if ((rh['real_ip']:get_version() == 6 and rbl['ipv6']) or | |||
@@ -344,7 +346,7 @@ local function rbl_cb (task) | |||
end | |||
end | |||
end, | |||
fun.filter(function(k, rbl) | |||
fun.filter(function(_, rbl) | |||
if rbl['received'] then return true end | |||
return false | |||
end, enabled_rbls)) | |||
@@ -403,7 +405,6 @@ local default_defaults = { | |||
['default_dkim'] = {[1] = false, [2] = 'dkim'}, | |||
['default_dkim_domainonly'] = {[1] = true, [2] = 'dkim_domainonly'}, | |||
['default_emails'] = {[1] = false, [2] = 'emails'}, | |||
['default_exclude_users'] = {[1] = false, [2] = 'exclude_users'}, | |||
['default_exclude_private_ips'] = {[1] = true, [2] = 'exclude_private_ips'}, | |||
['default_exclude_users'] = {[1] = false, [2] = 'exclude_users'}, | |||
['default_exclude_local'] = {[1] = true, [2] = 'exclude_local'}, | |||
@@ -433,7 +434,6 @@ local id = rspamd_config:register_symbol({ | |||
for key,rbl in pairs(opts['rbls']) do | |||
(function() | |||
if rbl['disabled'] then return end | |||
local s | |||
for default, default_v in pairs(default_defaults) do | |||
if(rbl[default_v[2]] == nil) then | |||
rbl[default_v[2]] = opts[default] | |||
@@ -501,7 +501,7 @@ for key,rbl in pairs(opts['rbls']) do | |||
elseif type(rbl['whitelist_exception']) == 'table' then | |||
local foundException = false | |||
for _, e in pairs(rbl['whitelist_exception']) do | |||
if e == s then | |||
if e == rbl['symbol'] then | |||
foundException = true | |||
break | |||
end |
@@ -19,7 +19,6 @@ limitations under the License. | |||
-- Default port for redis upstreams | |||
local redis_params | |||
local whitelisted_ip | |||
local settings = { | |||
action = nil, | |||
expire = 86400, -- 1 day by default | |||
@@ -29,8 +28,6 @@ local settings = { | |||
} | |||
local rspamd_logger = require 'rspamd_logger' | |||
local rspamd_redis = require 'rspamd_redis' | |||
local upstream_list = require 'rspamd_upstream_list' | |||
local hash = require 'rspamd_cryptobox_hash' | |||
local function make_key(goop) | |||
@@ -83,7 +80,7 @@ local function replies_check(task) | |||
end | |||
local function replies_set(task) | |||
local function redis_set_cb(err, data) | |||
local function redis_set_cb(err) | |||
if err ~=nil then | |||
rspamd_logger.errx('redis_set_cb received error: %1', err) | |||
end |
@@ -19,7 +19,6 @@ limitations under the License. | |||
local ucl = require "ucl" | |||
local fun = require "fun" | |||
local rspamd_logger = require "rspamd_logger" | |||
local updates_priority = 2 | |||
local rspamd_config = rspamd_config | |||
local hash = require "rspamd_cryptobox_hash" | |||
local rspamd_version = rspamd_version | |||
@@ -47,7 +46,7 @@ end | |||
local function process_rules(obj) | |||
fun.each(function(key, code) | |||
local f = loadstring(code) | |||
local f = load(code) | |||
if f then | |||
f() | |||
else | |||
@@ -81,10 +80,9 @@ local function check_version(obj) | |||
return ret | |||
end | |||
local function gen_callback(map) | |||
local function gen_callback() | |||
return function(data) | |||
local ucl = require "ucl" | |||
local parser = ucl.parser() | |||
local res,err = parser:parse_string(data) | |||
@@ -97,12 +95,6 @@ local function gen_callback(map) | |||
if check_version(obj) then | |||
local priority = updates_priority | |||
if obj['priority'] then | |||
priority = obj['priority'] | |||
end | |||
if obj['symbols'] then | |||
process_symbols(obj['symbols']) | |||
end | |||
@@ -127,9 +119,7 @@ local section = rspamd_config:get_all_opt("rspamd_update") | |||
if section then | |||
local trusted_key | |||
fun.each(function(k, elt) | |||
if k == 'priority' then | |||
updates_priority = tonumber(elt) | |||
elseif k == 'key' then | |||
if k == 'key' then | |||
trusted_key = elt | |||
else | |||
local map = rspamd_config:add_map(elt, "rspamd updates map", nil) |
@@ -19,7 +19,6 @@ limitations under the License. | |||
-- https://rspamd.com/doc/configuration/settings.html | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_redis = require 'rspamd_redis' | |||
local redis_params | |||
local settings = {} | |||
@@ -43,6 +42,8 @@ local function check_query_settings(task) | |||
task:set_settings(parser:get_object()) | |||
return true | |||
else | |||
rspamd_logger.errx(task, 'Parse error: %s', err) | |||
end | |||
end | |||
@@ -136,7 +137,7 @@ local function check_settings(task) | |||
return false | |||
end | |||
local function check_specific_setting(name, rule, ip, client_ip, from, rcpt, | |||
local function check_specific_setting(_, rule, ip, client_ip, from, rcpt, | |||
user, auth_user) | |||
local res = false | |||
@@ -254,13 +255,12 @@ local function check_settings(task) | |||
local user = {} | |||
if uname then | |||
user[1] = {} | |||
for localpart, domainpart in string.gmatch(uname, "(.+)@(.+)") do | |||
local localpart, domainpart = string.gmatch(uname, "(.+)@(.+)")() | |||
if localpart then | |||
user[1]["user"] = localpart | |||
user[1]["domain"] = domainpart | |||
user[1]["addr"] = uname | |||
break | |||
end | |||
if not user[1]["addr"] then | |||
else | |||
user[1]["user"] = uname | |||
user[1]["addr"] = uname | |||
end | |||
@@ -324,7 +324,7 @@ local function process_settings_table(tbl) | |||
local out = {} | |||
if type(ip) == "table" then | |||
for i,v in ipairs(ip) do | |||
for _,v in ipairs(ip) do | |||
table.insert(out, process_ip(v)) | |||
end | |||
elseif type(ip) == "string" then | |||
@@ -363,7 +363,7 @@ local function process_settings_table(tbl) | |||
local function process_addr(addr) | |||
local out = {} | |||
if type(addr) == "table" then | |||
for i,v in ipairs(addr) do | |||
for _,v in ipairs(addr) do | |||
table.insert(out, process_addr(v)) | |||
end | |||
elseif type(addr) == "string" then | |||
@@ -399,8 +399,8 @@ local function process_settings_table(tbl) | |||
return out | |||
end | |||
local check_table = function(elt, out) | |||
if type(elt) == 'string' then | |||
local check_table = function(chk_elt, out) | |||
if type(chk_elt) == 'string' then | |||
return {out} | |||
end | |||
@@ -480,7 +480,7 @@ local function process_settings_table(tbl) | |||
max_pri = 0 | |||
local nrules = 0 | |||
settings_ids = {} | |||
for k,v in pairs(settings) do settings[k]={} end | |||
for k in pairs(settings) do settings[k]={} end | |||
-- fill new settings by priority | |||
fun.for_each(function(k, v) | |||
local pri = get_priority(v) | |||
@@ -507,7 +507,6 @@ end | |||
-- Parse settings map from the ucl line | |||
local function process_settings_map(string) | |||
local ucl = require "ucl" | |||
local parser = ucl.parser() | |||
local res,err = parser:parse_string(string) | |||
if not res then | |||
@@ -530,12 +529,11 @@ local function gen_redis_callback(handler, id) | |||
local function redis_settings_cb(err, data) | |||
if not err and type(data) == 'string' then | |||
local ucl = require "ucl" | |||
local parser = ucl.parser() | |||
local res,err = parser:parse_string(data) | |||
local res,ucl_err = parser:parse_string(data) | |||
if not res then | |||
rspamd_logger.warnx(rspamd_config, 'cannot parse settings from redis: %s', | |||
err) | |||
ucl_err) | |||
else | |||
local obj = parser:get_object() | |||
rspamd_logger.infox(task, "<%1> apply settings according to redis rule %2", | |||
@@ -558,6 +556,9 @@ local function gen_redis_callback(handler, id) | |||
'GET', -- command | |||
{key} -- arguments | |||
) | |||
if not ret then | |||
rspamd_logger.errx(task, 'Redis GET failed: %s', ret) | |||
end | |||
end | |||
end | |||
@@ -570,7 +571,7 @@ if redis_section then | |||
local handlers = redis_section.handlers | |||
for _,h in ipairs(handlers) do | |||
local chunk,err = loadstring(h) | |||
local chunk,err = load(h) | |||
if not chunk then | |||
rspamd_logger.errx(rspamd_config, 'Cannot load handler from string: %s', |
@@ -83,7 +83,6 @@ local symbols_replacements = { | |||
-- Internal variables | |||
local rules = {} | |||
local atoms = {} | |||
local metas = {} | |||
local scores = {} | |||
local scores_added = {} | |||
local external_deps = {} | |||
@@ -171,7 +170,7 @@ local function process_regexp_opt(re, task, re_type, header, strong) | |||
if not strong then | |||
strong = 0 | |||
else | |||
string = 1 | |||
strong = 1 | |||
end | |||
local iret = ffi.C.rspamd_re_cache_process_ffi (task, re, itype, header, strong) | |||
@@ -196,14 +195,12 @@ local function handle_header_def(hline, cur_rule) | |||
-- Check if an re is an ordinary re | |||
local ordinary = true | |||
for i,h in ipairs(hdrs) do | |||
for _,h in ipairs(hdrs) do | |||
if h == 'ALL' or h == 'ALL:raw' then | |||
ordinary = false | |||
cur_rule['type'] = 'function' | |||
-- Pack closure | |||
local re = cur_rule['re'] | |||
local not_f = cur_rule['not'] | |||
local sym = cur_rule['symbol'] | |||
-- Rule to match all headers | |||
rspamd_config:register_regexp({ | |||
re = re, | |||
@@ -235,7 +232,7 @@ local function handle_header_def(hline, cur_rule) | |||
local addr_parsed = util.parse_addr(str) | |||
local ret = {} | |||
if addr_parsed then | |||
for i,elt in ipairs(addr_parsed) do | |||
for _,elt in ipairs(addr_parsed) do | |||
if elt['addr'] then | |||
table.insert(ret, elt['addr']) | |||
end | |||
@@ -249,7 +246,7 @@ local function handle_header_def(hline, cur_rule) | |||
local addr_parsed = util.parse_addr(str) | |||
local ret = {} | |||
if addr_parsed then | |||
for i,elt in ipairs(addr_parsed) do | |||
for _,elt in ipairs(addr_parsed) do | |||
if elt['name'] then | |||
table.insert(ret, elt['name']) | |||
end | |||
@@ -269,7 +266,7 @@ local function handle_header_def(hline, cur_rule) | |||
end, fun.tail(args)) | |||
local function split_hdr_param(param, headers) | |||
for i,h in ipairs(headers) do | |||
for _,hh in ipairs(headers) do | |||
local nparam = {} | |||
for k,v in pairs(param) do | |||
if k ~= 'header' then | |||
@@ -277,7 +274,7 @@ local function handle_header_def(hline, cur_rule) | |||
end | |||
end | |||
nparam['header'] = h | |||
nparam['header'] = hh | |||
table.insert(hdr_params, nparam) | |||
end | |||
end | |||
@@ -319,7 +316,7 @@ end | |||
local function gen_eval_rule(arg) | |||
local eval_funcs = { | |||
{'check_freemail_from', function(task, remain) | |||
{'check_freemail_from', function(task) | |||
local from = task:get_from('mime') | |||
if from and from[1] then | |||
return freemail_search(string.lower(from[1]['addr'])) | |||
@@ -327,26 +324,26 @@ local function gen_eval_rule(arg) | |||
return 0 | |||
end}, | |||
{'check_freemail_replyto', | |||
function(task, remain) | |||
function(task) | |||
return freemail_search(task:get_header('Reply-To')) | |||
end | |||
}, | |||
{'check_freemail_header', | |||
function(task, remain) | |||
-- Remain here contains one or two args: header and regexp to match | |||
local arg = string.match(remain, "^%(%s*['\"]([^%s]+)['\"]%s*%)$") | |||
local larg = string.match(remain, "^%(%s*['\"]([^%s]+)['\"]%s*%)$") | |||
local re = nil | |||
if not arg then | |||
arg, re = string.match(remain, "^%(%s*['\"]([^%s]+)['\"]%s*,%s*['\"]([^%s]+)['\"]%s*%)$") | |||
if not larg then | |||
larg, re = string.match(remain, "^%(%s*['\"]([^%s]+)['\"]%s*,%s*['\"]([^%s]+)['\"]%s*%)$") | |||
end | |||
if arg then | |||
if larg then | |||
local h | |||
if arg == 'EnvelopeFrom' then | |||
if larg == 'EnvelopeFrom' then | |||
h = task:get_from('smtp') | |||
if h then h = h[1]['addr'] end | |||
else | |||
h = task:get_header(arg) | |||
h = task:get_header(larg) | |||
end | |||
if h then | |||
local hdr_freemail = freemail_search(string.lower(h)) | |||
@@ -372,7 +369,7 @@ local function gen_eval_rule(arg) | |||
}, | |||
{ | |||
'check_for_missing_to_header', | |||
function (task, remain) | |||
function (task) | |||
local th = task:get_recipients('mime') | |||
if not th or #th == 0 then | |||
return 1 | |||
@@ -383,7 +380,7 @@ local function gen_eval_rule(arg) | |||
}, | |||
{ | |||
'check_relays_unparseable', | |||
function(task, remain) | |||
function(task) | |||
local rh_mime = task:get_header_full('Received') | |||
local rh_parsed = task:get_received_headers() | |||
@@ -433,13 +430,13 @@ local function gen_eval_rule(arg) | |||
{ | |||
'check_for_mime', | |||
function(task, remain) | |||
local arg = string.match(remain, "^%(%s*['\"]([^%s]+)['\"]%s*%)$") | |||
local larg = string.match(remain, "^%(%s*['\"]([^%s]+)['\"]%s*%)$") | |||
if arg then | |||
if arg == 'mime_attachment' then | |||
if larg then | |||
if larg == 'mime_attachment' then | |||
local parts = task:get_parts() | |||
if parts then | |||
for i,p in ipairs(parts) do | |||
for _,p in ipairs(parts) do | |||
if p:get_filename() then | |||
return 1 | |||
end | |||
@@ -455,7 +452,7 @@ local function gen_eval_rule(arg) | |||
}, | |||
{ | |||
'check_from_in_blacklist', | |||
function(task, remain) | |||
function(task) | |||
local from = task:get_from('mime') | |||
if from and from[1] and from[1]['addr'] then | |||
if sa_lists['from_blacklist'][string.lower(from[1]['addr'])] then | |||
@@ -468,7 +465,7 @@ local function gen_eval_rule(arg) | |||
}, | |||
{ | |||
'check_from_in_whitelist', | |||
function(task, remain) | |||
function(task) | |||
local from = task:get_from('mime') | |||
if from and from[1] and from[1]['addr'] then | |||
if sa_lists['from_whitelist'][string.lower(from[1]['addr'])] then | |||
@@ -481,7 +478,7 @@ local function gen_eval_rule(arg) | |||
}, | |||
{ | |||
'check_from_in_default_whitelist', | |||
function(task, remain) | |||
function(task) | |||
local from = task:get_from('mime') | |||
if from and from[1] and from[1]['addr'] then | |||
if sa_lists['from_def_whitelist'][string.lower(from[1]['addr'])] then | |||
@@ -494,10 +491,10 @@ local function gen_eval_rule(arg) | |||
}, | |||
{ | |||
'check_to_in_blacklist', | |||
function(task, remain) | |||
function(task) | |||
local rcpt = task:get_recipients('mime') | |||
if rcpt then | |||
for i,r in ipairs(rcpt) do | |||
for _,r in ipairs(rcpt) do | |||
if sa_lists['to_blacklist'][string.lower(r['addr'])] then | |||
return 1 | |||
end | |||
@@ -509,10 +506,10 @@ local function gen_eval_rule(arg) | |||
}, | |||
{ | |||
'check_to_in_whitelist', | |||
function(task, remain) | |||
function(task) | |||
local rcpt = task:get_recipients('mime') | |||
if rcpt then | |||
for i,r in ipairs(rcpt) do | |||
for _,r in ipairs(rcpt) do | |||
if sa_lists['to_whitelist'][string.lower(r['addr'])] then | |||
return 1 | |||
end | |||
@@ -524,7 +521,7 @@ local function gen_eval_rule(arg) | |||
}, | |||
} | |||
for k,f in ipairs(eval_funcs) do | |||
for _,f in ipairs(eval_funcs) do | |||
local pat = string.format('^%s', f[1]) | |||
local first,last = string.find(arg, pat) | |||
@@ -548,7 +545,7 @@ local function maybe_parse_sa_function(line) | |||
local substitutions = { | |||
{'^exists:', | |||
function(task) -- filter | |||
local hdrs_check = {} | |||
local hdrs_check | |||
if arg == 'MESSAGEID' then | |||
hdrs_check = { | |||
'Message-ID', | |||
@@ -561,7 +558,7 @@ local function maybe_parse_sa_function(line) | |||
hdrs_check = {arg} | |||
end | |||
for i,h in ipairs(hdrs_check) do | |||
for _,h in ipairs(hdrs_check) do | |||
if task:get_header(h) then | |||
return 1 | |||
end | |||
@@ -589,7 +586,7 @@ local function maybe_parse_sa_function(line) | |||
}, | |||
} | |||
for k,s in ipairs(substitutions) do | |||
for _,s in ipairs(substitutions) do | |||
if string.find(line, s[1]) then | |||
return s[2] | |||
end | |||
@@ -723,8 +720,6 @@ local function process_sa_conf(f) | |||
end | |||
end | |||
local slash = string.find(l, '/') | |||
-- Skip comments | |||
local words = fun.totable(fun.take_while( | |||
function(w) return string.sub(w, 1, 1) ~= '#' end, | |||
@@ -777,7 +772,7 @@ local function process_sa_conf(f) | |||
valid_rule = true | |||
cur_rule['re']:set_max_hits(1) | |||
if cur_rule['header'] and cur_rule['ordinary'] then | |||
for i,h in ipairs(cur_rule['header']) do | |||
for _,h in ipairs(cur_rule['header']) do | |||
if type(h) == 'string' then | |||
if cur_rule['mime'] then | |||
rspamd_config:register_regexp({ | |||
@@ -1102,14 +1097,14 @@ local function apply_replacements(str) | |||
end | |||
local function replace_all_tags(s) | |||
local str, matches | |||
str = s | |||
local sstr, _ | |||
sstr = s | |||
fun.each(function(n, t) | |||
str,matches = string.gsub(str, string.format("<%s>", n), | |||
sstr,_ = string.gsub(sstr, string.format("<%s>", n), | |||
string.format("%s%s%s", pre, t, post)) | |||
end, replace['tags']) | |||
return str | |||
return sstr | |||
end | |||
local s = replace_all_tags(str) | |||
@@ -1264,20 +1259,19 @@ local function post_process() | |||
-- Slow path | |||
fun.each(function(h) | |||
local headers = {} | |||
local hname = h['header'] | |||
local hdr | |||
if h['mime'] then | |||
local parts = task:get_parts() | |||
for i, p in ipairs(parts) do | |||
for _, p in ipairs(parts) do | |||
local m_hdr = p:get_header_full(hname, h['strong']) | |||
if m_hdr then | |||
if not hdr then | |||
hdr = {} | |||
end | |||
for k, mh in ipairs(m_hdr) do | |||
for _, mh in ipairs(m_hdr) do | |||
table.insert(hdr, mh) | |||
end | |||
end | |||
@@ -1287,7 +1281,7 @@ local function post_process() | |||
end | |||
if hdr then | |||
for n, rh in ipairs(hdr) do | |||
for _, rh in ipairs(hdr) do | |||
-- Subject for optimization | |||
local str | |||
if h['raw'] then | |||
@@ -1305,7 +1299,7 @@ local function post_process() | |||
if type(str) == 'string' then | |||
table.insert(check, str) | |||
else | |||
for ii, c in ipairs(str) do | |||
for _, c in ipairs(str) do | |||
table.insert(check, c) | |||
end | |||
end | |||
@@ -1321,7 +1315,7 @@ local function post_process() | |||
end | |||
local ret = 0 | |||
for i, c in ipairs(check) do | |||
for _, c in ipairs(check) do | |||
local match = sa_regexp_match(c, r['re'], raw, r) | |||
if (match > 0 and not r['not']) or (match == 0 and r['not']) then | |||
ret = 1 | |||
@@ -1338,7 +1332,7 @@ local function post_process() | |||
end | |||
atoms[k] = f | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'header' and r['header'] | |||
end, | |||
rules)) | |||
@@ -1360,7 +1354,7 @@ local function post_process() | |||
end | |||
atoms[k] = f | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'function' and r['function'] | |||
end, | |||
rules)) | |||
@@ -1386,7 +1380,7 @@ local function post_process() | |||
end | |||
atoms[k] = f | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'part' | |||
end, rules)) | |||
@@ -1411,7 +1405,7 @@ local function post_process() | |||
end | |||
atoms[k] = f | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'sabody' or r['type'] == 'message' or r['type'] == 'sarawbody' | |||
end, rules)) | |||
@@ -1433,7 +1427,7 @@ local function post_process() | |||
end | |||
atoms[k] = f | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'uri' | |||
end, | |||
rules)) | |||
@@ -1484,7 +1478,7 @@ local function post_process() | |||
end | |||
end | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'meta' | |||
end, | |||
rules)) | |||
@@ -1495,9 +1489,9 @@ local function post_process() | |||
if r['expression'] then | |||
local expr_atoms = r['expression']:atoms() | |||
for i,a in ipairs(expr_atoms) do | |||
for _,a in ipairs(expr_atoms) do | |||
if not atoms[a] then | |||
local rspamd_symbol, replaced_symbol = replace_symbol(a) | |||
local rspamd_symbol = replace_symbol(a) | |||
rspamd_logger.debugx('atom %1 is a direct foreign dependency, ' .. | |||
'register dependency for %2 on %3', | |||
a, k, rspamd_symbol) | |||
@@ -1511,7 +1505,7 @@ local function post_process() | |||
end | |||
end | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'meta' | |||
end, | |||
rules)) | |||
@@ -1520,7 +1514,7 @@ local function post_process() | |||
fun.each(function(k, r) | |||
if r['expression'] then | |||
local expr_atoms = r['expression']:atoms() | |||
for i,a in ipairs(expr_atoms) do | |||
for _,a in ipairs(expr_atoms) do | |||
if type(external_deps[a]) == 'table' then | |||
for _,dep in ipairs(external_deps[a]) do | |||
rspamd_logger.debugx('atom %1 holds a foreign dependency, ' .. | |||
@@ -1539,7 +1533,7 @@ local function post_process() | |||
end | |||
end | |||
end, | |||
fun.filter(function(k, r) | |||
fun.filter(function(_, r) | |||
return r['type'] == 'meta' | |||
end, | |||
rules)) | |||
@@ -1572,15 +1566,15 @@ if type(section) == "table" then | |||
elseif k == 'match_limit' and type(fn) == 'number' then | |||
match_limit = fn | |||
elseif k == 'pcre_only' and type(fn) == 'table' then | |||
for i,s in ipairs(fn) do | |||
for _,s in ipairs(fn) do | |||
pcre_only_regexps[s] = 1 | |||
end | |||
else | |||
if type(fn) == 'table' then | |||
for k, elt in ipairs(fn) do | |||
for _, elt in ipairs(fn) do | |||
local files = util.glob(elt) | |||
for i,matched in ipairs(files) do | |||
for _,matched in ipairs(files) do | |||
local f = io.open(matched, "r") | |||
if f then | |||
process_sa_conf(f) | |||
@@ -1594,7 +1588,7 @@ if type(section) == "table" then | |||
-- assume string | |||
local files = util.glob(fn) | |||
for i,matched in ipairs(files) do | |||
for _,matched in ipairs(files) do | |||
local f = io.open(matched, "r") | |||
if f then | |||
process_sa_conf(f) |
@@ -160,7 +160,7 @@ if opts then | |||
end | |||
if id ~= -1 then | |||
for sym, opt in pairs(opts) do | |||
for sym in pairs(opts) do | |||
rspamd_config:register_symbol({ | |||
name = sym, | |||
type = 'virtual', |
@@ -16,7 +16,6 @@ limitations under the License. | |||
local rspamd_logger = require "rspamd_logger" | |||
local rspamd_util = require "rspamd_util" | |||
local ucl = require "ucl" | |||
local fun = require "fun" | |||
local options = { | |||
@@ -55,7 +54,6 @@ local function whitelist_cb(symbol, rule, task) | |||
return false,0.0 | |||
end | |||
local from = task:get_from(1) | |||
local found = false | |||
local mult = 1.0 | |||
local spf_violated = false | |||
@@ -170,18 +168,6 @@ local function gen_whitelist_cb(symbol, rule) | |||
end | |||
end | |||
local function process_whitelist_map(input) | |||
local parser = ucl.parser() | |||
local res,err = parser:parse_string(string) | |||
if not res then | |||
rspamd_logger.warnx(rspamd_config, 'cannot parse settings map: ' .. err) | |||
else | |||
local obj = parser:get_object() | |||
options['rules'] = obj | |||
end | |||
end | |||
local configure_whitelist_module = function() | |||
local opts = rspamd_config:get_all_opt('whitelist') | |||
if opts then |