--- /dev/null
+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',
+}
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
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)
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()
+local logger = require "rspamd_logger"
-- This function parses redis server definition using either
-- specific server string for this module or global
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)
return {0}
end
-local function meta_attachments_function(task)
-end
-
local metafunctions = {
{
cb = meta_size_function,
end
return total
-end
\ No newline at end of file
+end
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"
yield_result(task, rule, data)
end
else
+ rspamd_logger.errx(task, 'Got error checking cache: %1', err)
fn()
end
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',
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,
local rspamd_logger = require "rspamd_logger"
local rspamd_regexp = require "rspamd_regexp"
-local rspamd_redis = require "rspamd_redis"
local options = {
provider_type = 'rspamd',
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
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,
'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'])
})
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
'EXPIRE', -- command
{key, tostring(options.expire)} -- arguments
)
+ if not ret then
+ upstream:fail()
+ end
end
end
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
-- 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
-- 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 = {}
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'])
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
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
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
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
]]--
local rspamd_logger = require "rspamd_logger"
-local rspamd_redis = require 'rspamd_redis'
local redis_params
local ucl = require "ucl"
local fun = require "fun"
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
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
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
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
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
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
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)
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 = {}
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 = {}
-- 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
-- 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'
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
}
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)
return true,false
end
-
- return false,false
end
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
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'])
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
elseif err then
rspamd_logger.errx(task, 'got error while getting greylisting keys: %1', err)
upstream:fail()
+ return
end
+ upstream:ok()
end
local ret, _
)
if not ret then
rspamd_logger.errx(task, 'cannot make redis request to check results')
+ upstream:fail()
end
end
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
{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'])
})
'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
{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())
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
--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,
}
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 = {
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)
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
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
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)
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
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
-- 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
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)
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)
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
'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'])
-- 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])
end
end
- local function create_get_command(ip, asn, country, ipnet)
+ local function create_get_command()
local cmd = 'HMGET'
local args = {options['hash']}
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
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
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
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
-- Module for checking mail list headers
local symbol = 'MAILLIST'
-local rspamd_logger = require "rspamd_logger"
-- EZMLM
-- Mailing-List: .*run by ezmlm
-- Precedence: bulk
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
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
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())
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
'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({
end
end
-local function graphite_config(opts)
+local function graphite_config()
load_defaults({
host = 'localhost',
port = 2003,
data = {
metrics_str,
},
- callback = (function (err, data)
+ callback = (function (err)
if err then
logger.errx('Push failed: %1', err)
return
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')
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,
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)
end
if not stamp then
logger.debug('No state found - pushing stats immediately')
- push_metrics(worker)
+ push_metrics()
schedule_regular_push()
return
end
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
]]--
-- This plugin implements mime types checks for mail messages
-local rspamd_logger = require "rspamd_logger"
-local rspamd_regexp = require "rspamd_regexp"
local settings = {
file = '',
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"
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,
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
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
url = apply_url_filter,
filename = apply_filename_filter,
mempool = apply_regexp_filter,
+ hostname = apply_hostname_filter,
--content = apply_content_filter, -- Content filters are special :(
}
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 = {}
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
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
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, ' ..
end
local function match_content(r)
- local data = {}
+ local data
if r['filter'] then
data = apply_content_filter(task, r['filter'], r)
data = {task:get_content()}
end
- for i,v in ipairs(data) do
+ for _,v in ipairs(data) do
match_rule(r, v)
end
end
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'])
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
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
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
-- 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"
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
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
'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
'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
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,
port = 25
})
- if not ret then
+ if not t_ret then
mxes[name].checked = true
end
end
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()
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
)
if not ret then
+ upstream:fail()
local r = task:get_resolver()
r:resolve('mx', {
name = mx_domain,
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
return
end
- local recvh = task:get_received_headers()
if recvh and #recvh <= 1 then
local ret = true
local r = recvh[1]
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
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,
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
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
local found_path = false
local found_query = false
local data = nil
- local d
if elt then
local path = url:get_path()
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 = {
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
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
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
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"
end,
},
['to'] = {
- ['get_value'] = function(task)
+ ['get_value'] = function()
return '%s' -- 'to' is special
end,
},
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()
'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
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
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]
atime - ctime)
bucket = 1
ctime = ntime
- atime = ntime
else
if bucket > 0 then
bucket = bucket - rate * (ntime - atime) + 1;
'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
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
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)))
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')
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'
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
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
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
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()
-- 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)
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']
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
end
end
end,
- fun.filter(function(k, rbl)
+ fun.filter(function(_, rbl)
if rbl['received'] then return true end
return false
end, enabled_rbls))
['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'},
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]
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
-- Default port for redis upstreams
local redis_params
-local whitelisted_ip
local settings = {
action = nil,
expire = 86400, -- 1 day by default
}
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)
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
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
local function process_rules(obj)
fun.each(function(key, code)
- local f = loadstring(code)
+ local f = load(code)
if f then
f()
else
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)
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
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)
-- https://rspamd.com/doc/configuration/settings.html
local rspamd_logger = require "rspamd_logger"
-local rspamd_redis = require 'rspamd_redis'
local redis_params
local settings = {}
task:set_settings(parser:get_object())
return true
+ else
+ rspamd_logger.errx(task, 'Parse error: %s', err)
end
end
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
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
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
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
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
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)
-- 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
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",
'GET', -- command
{key} -- arguments
)
+ if not ret then
+ rspamd_logger.errx(task, 'Redis GET failed: %s', ret)
+ end
end
end
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',
-- Internal variables
local rules = {}
local atoms = {}
-local metas = {}
local scores = {}
local scores_added = {}
local external_deps = {}
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)
-- 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,
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
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
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
end
end
- nparam['header'] = h
+ nparam['header'] = hh
table.insert(hdr_params, nparam)
end
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']))
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))
},
{
'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
},
{
'check_relays_unparseable',
- function(task, remain)
+ function(task)
local rh_mime = task:get_header_full('Received')
local rh_parsed = task:get_received_headers()
{
'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
},
{
'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
},
{
'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
},
{
'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
},
{
'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
},
{
'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
},
}
- 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)
local substitutions = {
{'^exists:',
function(task) -- filter
- local hdrs_check = {}
+ local hdrs_check
if arg == 'MESSAGEID' then
hdrs_check = {
'Message-ID',
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
},
}
- for k,s in ipairs(substitutions) do
+ for _,s in ipairs(substitutions) do
if string.find(line, s[1]) then
return s[2]
end
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,
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({
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)
-- 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
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
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
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
end
atoms[k] = f
end,
- fun.filter(function(k, r)
+ fun.filter(function(_, r)
return r['type'] == 'header' and r['header']
end,
rules))
end
atoms[k] = f
end,
- fun.filter(function(k, r)
+ fun.filter(function(_, r)
return r['type'] == 'function' and r['function']
end,
rules))
end
atoms[k] = f
end,
- fun.filter(function(k, r)
+ fun.filter(function(_, r)
return r['type'] == 'part'
end, rules))
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))
end
atoms[k] = f
end,
- fun.filter(function(k, r)
+ fun.filter(function(_, r)
return r['type'] == 'uri'
end,
rules))
end
end
end,
- fun.filter(function(k, r)
+ fun.filter(function(_, r)
return r['type'] == 'meta'
end,
rules))
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)
end
end
end,
- fun.filter(function(k, r)
+ fun.filter(function(_, r)
return r['type'] == 'meta'
end,
rules))
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, ' ..
end
end
end,
- fun.filter(function(k, r)
+ fun.filter(function(_, r)
return r['type'] == 'meta'
end,
rules))
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)
-- 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)
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',
local rspamd_logger = require "rspamd_logger"
local rspamd_util = require "rspamd_util"
-local ucl = require "ucl"
local fun = require "fun"
local options = {
return false,0.0
end
- local from = task:get_from(1)
local found = false
local mult = 1.0
local spf_violated = false
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