commit b75b02a: [Rework] Reorganize dmarc plugin and remove unsupported reporting code
Vsevolod Stakhov
vsevolod at highsecure.ru
Thu Jul 29 14:56:05 UTC 2021
Author: Vsevolod Stakhov
Date: 2021-07-29 15:54:25 +0100
URL: https://github.com/rspamd/rspamd/commit/b75b02a67bad7cba5635ec93123814d91baf1f53 (HEAD -> master)
[Rework] Reorganize dmarc plugin and remove unsupported reporting code
---
src/plugins/lua/dmarc.lua | 894 ++++++----------------------------------------
1 file changed, 113 insertions(+), 781 deletions(-)
diff --git a/src/plugins/lua/dmarc.lua b/src/plugins/lua/dmarc.lua
index ef2c89881..e38ab822b 100644
--- a/src/plugins/lua/dmarc.lua
+++ b/src/plugins/lua/dmarc.lua
@@ -18,135 +18,58 @@ limitations under the License.
-- Dmarc policy filter
local rspamd_logger = require "rspamd_logger"
-local mempool = require "rspamd_mempool"
-local rspamd_url = require "rspamd_url"
local rspamd_util = require "rspamd_util"
local rspamd_redis = require "lua_redis"
local lua_util = require "lua_util"
-local auth_and_local_conf
if confighelp then
return
end
local N = 'dmarc'
-local no_sampling_domains
-local no_reporting_domains
-local statefile = string.format('%s/%s', rspamd_paths['DBDIR'], 'dmarc_reports_last_sent')
-local VAR_NAME = 'dmarc_reports_last_sent'
-local INTERVAL = 86400
-local pool
-
-local report_settings = {
- helo = 'rspamd',
- hscan_count = 1000,
- smtp = '127.0.0.1',
- smtp_port = 25,
- retries = 2,
- from_name = 'Rspamd',
- msgid_from = 'rspamd',
-}
-
-local report_template = [[From: "{= from_name =}" <{= from_addr =}>
-To: {= rcpt =}
-{%+ if is_string(bcc) %}Bcc: {= bcc =}{%- endif %}
-Subject: Report Domain: {= reporting_domain =}
- Submitter: {= submitter =}
- Report-ID: {= report_id =}
-Date: {= report_date =}
-MIME-Version: 1.0
-Message-ID: <{= message_id =}>
-Content-Type: multipart/mixed;
- boundary="----=_NextPart_000_024E_01CC9B0A.AFE54C00"
-
-This is a multipart message in MIME format.
-
-------=_NextPart_000_024E_01CC9B0A.AFE54C00
-Content-Type: text/plain; charset="us-ascii"
-Content-Transfer-Encoding: 7bit
-
-This is an aggregate report from {= submitter =}.
-
-Report domain: {= reporting_domain =}
-Submitter: {= submitter =}
-Report ID: {= report_id =}
-
-------=_NextPart_000_024E_01CC9B0A.AFE54C00
-Content-Type: application/gzip
-Content-Transfer-Encoding: base64
-Content-Disposition: attachment;
- filename="{= submitter =}!{= reporting_domain =}!{= report_start =}!{= report_end =}.xml.gz"
-
-]]
-local report_footer = [[
-
-------=_NextPart_000_024E_01CC9B0A.AFE54C00--]]
-
-local symbols = {
- spf_allow_symbol = 'R_SPF_ALLOW',
- spf_deny_symbol = 'R_SPF_FAIL',
- spf_softfail_symbol = 'R_SPF_SOFTFAIL',
- spf_neutral_symbol = 'R_SPF_NEUTRAL',
- spf_tempfail_symbol = 'R_SPF_DNSFAIL',
- spf_permfail_symbol = 'R_SPF_PERMFAIL',
- spf_na_symbol = 'R_SPF_NA',
-
- dkim_allow_symbol = 'R_DKIM_ALLOW',
- dkim_deny_symbol = 'R_DKIM_REJECT',
- dkim_tempfail_symbol = 'R_DKIM_TEMPFAIL',
- dkim_na_symbol = 'R_DKIM_NA',
- dkim_permfail_symbol = 'R_DKIM_PERMFAIL',
-}
-local dmarc_symbols = {
- allow = 'DMARC_POLICY_ALLOW',
- badpolicy = 'DMARC_BAD_POLICY',
- dnsfail = 'DMARC_DNSFAIL',
- na = 'DMARC_NA',
- reject = 'DMARC_POLICY_REJECT',
- softfail = 'DMARC_POLICY_SOFTFAIL',
- quarantine = 'DMARC_POLICY_QUARANTINE',
+local settings = {
+ auth_and_local_conf = false,
+ symbols = {
+ spf_allow_symbol = 'R_SPF_ALLOW',
+ spf_deny_symbol = 'R_SPF_FAIL',
+ spf_softfail_symbol = 'R_SPF_SOFTFAIL',
+ spf_neutral_symbol = 'R_SPF_NEUTRAL',
+ spf_tempfail_symbol = 'R_SPF_DNSFAIL',
+ spf_permfail_symbol = 'R_SPF_PERMFAIL',
+ spf_na_symbol = 'R_SPF_NA',
+
+ dkim_allow_symbol = 'R_DKIM_ALLOW',
+ dkim_deny_symbol = 'R_DKIM_REJECT',
+ dkim_tempfail_symbol = 'R_DKIM_TEMPFAIL',
+ dkim_na_symbol = 'R_DKIM_NA',
+ dkim_permfail_symbol = 'R_DKIM_PERMFAIL',
+
+ -- DMARC symbols
+ allow = 'DMARC_POLICY_ALLOW',
+ badpolicy = 'DMARC_BAD_POLICY',
+ dnsfail = 'DMARC_DNSFAIL',
+ na = 'DMARC_NA',
+ reject = 'DMARC_POLICY_REJECT',
+ softfail = 'DMARC_POLICY_SOFTFAIL',
+ quarantine = 'DMARC_POLICY_QUARANTINE',
+ },
+ no_sampling_domains = nil,
+ no_reporting_domains = nil,
+ reporting = {
+ redis_keys = {
+ index_prefix = 'dmarc_idx',
+ report_prefix = 'dmarc',
+ join_char = ';',
+ },
+ enabled = false,
+ max_entries = 1000,
+ only_domains = nil,
+ },
+ actions = {},
}
-local redis_keys = {
- index_prefix = 'dmarc_idx',
- report_prefix = 'dmarc',
- join_char = ';',
-}
-
-local function gen_xml_grammar()
- local lpeg = require 'lpeg'
- local lt = lpeg.P('<') / '<'
- local gt = lpeg.P('>') / '>'
- local amp = lpeg.P('&') / '&'
- local quot = lpeg.P('"') / '"'
- local apos = lpeg.P("'") / '''
- local special = lt + gt + amp + quot + apos
- local grammar = lpeg.Cs((special + 1)^0)
- return grammar
-end
-
-local xml_grammar = gen_xml_grammar()
-
-local function escape_xml(input)
- if type(input) == 'string' or type(input) == 'userdata' then
- return xml_grammar:match(input)
- else
- input = tostring(input)
-
- if input then
- return xml_grammar:match(input)
- end
- end
-
- return ''
-end
-
--- Default port for redis upstreams
local redis_params = nil
--- 2 days
-local dmarc_reporting = false
-local dmarc_actions = {}
local E = {}
@@ -162,17 +85,6 @@ redis.call('HINCRBY', report_key, report, 1)
redis.call('EXPIRE', report_key, 172800)
]]
--- return the timezone offset in seconds, as it was on the time given by ts
--- Eric Feliksik
-local function get_timezone_offset(ts)
- local utcdate = os.date("!*t", ts)
- local localdate = os.date("*t", ts)
- localdate.isdst = false -- this is the trick
- return os.difftime(os.time(localdate), os.time(utcdate))
-end
-
-local tz_offset = get_timezone_offset(os.time())
-
local function gen_dmarc_grammar()
local lpeg = require "lpeg"
lpeg.locale(lpeg)
@@ -207,6 +119,8 @@ local function dmarc_key_value_case(elts)
return result
end
+
+-- Returns a key used to be inserted into dmarc report sample
local function dmarc_report(task, spf_ok, dkim_ok, disposition,
sampled_out, hfromdom, spfdom, dres, spf_result)
local ip = task:get_from_ip()
@@ -230,7 +144,7 @@ end
local function maybe_force_action(task, disposition)
if disposition then
- local force_action = dmarc_actions[disposition]
+ local force_action = settings.actions[disposition]
if force_action then
-- Set least action
task:set_pre_result(force_action, 'Action set by DMARC', N, nil, nil, 'least')
@@ -337,7 +251,7 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
spf_domain = task:get_helo() or ''
end
- if task:has_symbol(symbols['spf_allow_symbol']) then
+ if task:has_symbol(settings.symbols['spf_allow_symbol']) then
if policy.strict_spf then
if rspamd_util.strequal_caseless(spf_domain, hdrfromdom) then
spf_ok = true
@@ -353,7 +267,7 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
end
end
else
- if task:has_symbol(symbols['spf_tempfail_symbol']) then
+ if task:has_symbol(settings.symbols['spf_tempfail_symbol']) then
if policy.strict_spf then
if rspamd_util.strequal_caseless(spf_domain, hdrfromdom) then
spf_tmpfail = true
@@ -446,14 +360,14 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
local function handle_dmarc_failure(what, reason_str)
if not policy.pct or policy.pct == 100 then
- task:insert_result(dmarc_symbols[what], 1.0,
+ task:insert_result(settings.symbols[what], 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
disposition = what
else
local coin = math.random(100)
if (coin > policy.pct) then
- if (not no_sampling_domains or
- not no_sampling_domains:get_key(policy.domain)) then
+ if (not settings.no_sampling_domains or
+ not settings.no_sampling_domains:get_key(policy.domain)) then
if what == 'reject' then
disposition = 'quarantine'
@@ -461,19 +375,19 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
disposition = 'softfail'
end
- task:insert_result(dmarc_symbols[disposition], 1.0,
+ task:insert_result(settings.symbols[disposition], 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "sampled_out")
sampled_out = true
lua_util.debugm(N, task,
'changed dmarc policy from %s to %s, sampled out: %s < %s',
what, disposition, coin, policy.pct)
else
- task:insert_result(dmarc_symbols[what], 1.0,
+ task:insert_result(settings.symbols[what], 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "local_policy")
disposition = what
end
else
- task:insert_result(dmarc_symbols[what], 1.0,
+ task:insert_result(settings.symbols[what], 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
disposition = what
end
@@ -489,7 +403,7 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
underlying authentication mechanisms passes for an aligned
identifier.
]]--
- task:insert_result(dmarc_symbols['allow'], 1.0, policy.domain,
+ task:insert_result(settings.symbols['allow'], 1.0, policy.domain,
policy.dmarc_policy)
else
--[[
@@ -501,7 +415,7 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
therefore cannot apply the advertised DMARC policy.
]]--
if spf_tmpfail or dkim_tmpfail then
- task:insert_result(dmarc_symbols['dnsfail'], 1.0, policy.domain..
+ task:insert_result(settings.symbols['dnsfail'], 1.0, policy.domain..
' : ' .. 'SPF/DKIM temp error', policy.dmarc_policy)
else
-- We can now check the failed policy and maybe send report data elt
@@ -512,17 +426,17 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
elseif policy.dmarc_policy == 'reject' then
handle_dmarc_failure('reject', reason_str)
else
- task:insert_result(dmarc_symbols['softfail'], 1.0,
+ task:insert_result(settings.symbols['softfail'], 1.0,
policy.domain .. ' : ' .. reason_str,
policy.dmarc_policy)
end
end
end
- if policy.rua and redis_params and dmarc_reporting then
- if no_reporting_domains then
- if no_reporting_domains:get_key(policy.domain) or
- no_reporting_domains:get_key(rspamd_util.get_tld(policy.domain)) then
+ if policy.rua and redis_params and settings.reporting.enabled then
+ if settings.no_reporting_domains then
+ if settings.no_reporting_domains:get_key(policy.domain) or
+ settings.no_reporting_domains:get_key(rspamd_util.get_tld(policy.domain)) then
rspamd_logger.infox(task, 'DMARC reporting suppressed for %1', policy.domain)
return
end
@@ -544,13 +458,13 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
elseif spf_tmpfail then
spf_result = 'temperror'
else
- if task:has_symbol(symbols.spf_deny_symbol) then
+ if task:has_symbol(settings.symbols.spf_deny_symbol) then
spf_result = 'fail'
- elseif task:has_symbol(symbols.spf_softfail_symbol) then
+ elseif task:has_symbol(settings.symbols.spf_softfail_symbol) then
spf_result = 'softfail'
- elseif task:has_symbol(symbols.spf_neutral_symbol) then
+ elseif task:has_symbol(settings.symbols.spf_neutral_symbol) then
spf_result = 'neutral'
- elseif task:has_symbol(symbols.spf_permfail_symbol) then
+ elseif task:has_symbol(settings.symbols.spf_permfail_symbol) then
spf_result = 'permerror'
else
spf_result = 'none'
@@ -561,7 +475,8 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
local period = os.date('!%Y%m%d',
task:get_date({format = 'connect', gmt = true}))
local dmarc_domain_key = table.concat(
- {redis_keys.report_prefix, hdrfromdom, period}, redis_keys.join_char)
+ {settings.reporting.redis_keys.report_prefix, hdrfromdom, period},
+ settings.reporting.redis_keys.join_char)
local report_data = dmarc_report(task,
spf_ok and 'pass' or 'fail',
dkim_ok and 'pass' or 'fail',
@@ -572,8 +487,8 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
dkim_results,
spf_result)
- local idx_key = table.concat({redis_keys.index_prefix, period},
- redis_keys.join_char)
+ local idx_key = table.concat({settings.redis_keys.index_prefix, period},
+ settings.redis_keys.join_char)
if report_data then
rspamd_redis.exec_redis_script(take_report_id,
@@ -598,7 +513,7 @@ local function dmarc_callback(task)
return
end
- if lua_util.is_skip_local_or_authed(task, auth_and_local_conf, ip_addr) then
+ if lua_util.is_skip_local_or_authed(task, settings.auth_and_local_conf, ip_addr) then
rspamd_logger.infox(task, "skip DMARC checks for local networks and authorized users")
return
end
@@ -607,13 +522,13 @@ local function dmarc_callback(task)
if hfromdom and hfromdom ~= '' and not (from or E)[2] then
dmarc_domain = rspamd_util.get_tld(hfromdom)
elseif (from or E)[2] then
- task:insert_result(dmarc_symbols['na'], 1.0, 'Duplicate From header')
+ task:insert_result(settings.symbols['na'], 1.0, 'Duplicate From header')
return maybe_force_action(task, 'na')
elseif (from or E)[1] then
- task:insert_result(dmarc_symbols['na'], 1.0, 'No domain in From header')
+ task:insert_result(settings.symbols['na'], 1.0, 'No domain in From header')
return maybe_force_action(task,'na')
else
- task:insert_result(dmarc_symbols['na'], 1.0, 'No From header')
+ task:insert_result(settings.symbols['na'], 1.0, 'No From header')
return maybe_force_action(task,'na')
end
@@ -659,10 +574,10 @@ local function dmarc_callback(task)
if (err ~= 'requested record is not found' and
err ~= 'no records with this name') then
policy_target.err = lookup_domain .. ' : ' .. err
- policy_target.symbol = dmarc_symbols['dnsfail']
+ policy_target.symbol = settings.symbols['dnsfail']
else
policy_target.err = lookup_domain
- policy_target.symbol = dmarc_symbols['na']
+ policy_target.symbol = settings.symbols['na']
end
else
local has_valid_policy = false
@@ -674,7 +589,7 @@ local function dmarc_callback(task)
if results_or_err then
-- We have a fatal parsing error, give up
policy_target.err = lookup_domain .. ' : ' .. results_or_err
- policy_target.symbol = dmarc_symbols['badpolicy']
+ policy_target.symbol = settings.symbols['badpolicy']
policy_target.fatal = true
seen_invalid = true
end
@@ -682,7 +597,7 @@ local function dmarc_callback(task)
if has_valid_policy then
policy_target.err = lookup_domain .. ' : ' ..
'Multiple policies defined in DNS'
- policy_target.symbol = dmarc_symbols['badpolicy']
+ policy_target.symbol = settings.symbols['badpolicy']
policy_target.fatal = true
seen_invalid = true
end
@@ -696,7 +611,7 @@ local function dmarc_callback(task)
if not has_valid_policy and not seen_invalid then
policy_target.err = lookup_domain .. ':' .. ' no valid DMARC record'
- policy_target.symbol = dmarc_symbols['na']
+ policy_target.symbol = settings.symbols['na']
end
end
end
@@ -740,622 +655,41 @@ end
local opts = rspamd_config:get_all_opt('dmarc')
-if not opts or type(opts) ~= 'table' then
- return
-end
+settings = lua_util.override_defaults(settings, opts)
-auth_and_local_conf = lua_util.config_check_local_or_authed(rspamd_config, N,
+settings.auth_and_local_conf = lua_util.config_check_local_or_authed(rspamd_config, N,
false, false)
-no_sampling_domains = rspamd_map_add(N, 'no_sampling_domains', 'map', 'Domains not to apply DMARC sampling to')
-no_reporting_domains = rspamd_map_add(N, 'no_reporting_domains', 'map', 'Domains not to apply DMARC reporting to')
+local lua_maps = require "lua_maps"
+lua_maps.fill_config_maps(N, settings, {
+ no_sampling_domains = {
+ optional = true,
+ type = 'map',
+ description = 'Domains not to apply DMARC sampling to'
+ },
+ no_reporting_domains = {
+ optional = true,
+ type = 'map',
+ description = 'Domains not to apply DMARC reporting to'
+ },
+})
-if opts['symbols'] then
- for k,_ in pairs(dmarc_symbols) do
- if opts['symbols'][k] then
- dmarc_symbols[k] = opts['symbols'][k]
- end
- end
-end
--- Reporting related code --
-
----
---- Converts a reporting entry to an XML format
---- @param data data table
---- @return string with an XML representation
-local function entry_to_xml(data)
- local buf = {
- table.concat({
- '<record><row><source_ip>', data.ip, '</source_ip><count>',
- data.count, '</count><policy_evaluated><disposition>',
- data.disposition, '</disposition><dkim>', data.dkim_disposition,
- '</dkim><spf>', data.spf_disposition, '</spf>'
- }),
- }
- if data.override ~= '' then
- table.insert(buf, string.format('<reason><type>%s</type></reason>', data.override))
- end
- table.insert(buf, table.concat({
- '</policy_evaluated></row><identifiers><header_from>', data.header_from,
- '</header_from></identifiers>',
- }))
- table.insert(buf, '<auth_results>')
- if data.dkim_results[1] then
- for _, d in ipairs(data.dkim_results) do
- table.insert(buf, table.concat({
- '<dkim><domain>', d.domain, '</domain><result>',
- d.result, '</result></dkim>',
- }))
- end
- end
- table.insert(buf, table.concat({
- '<spf><domain>', data.spf_domain, '</domain><result>',
- data.spf_result, '</result></spf></auth_results></record>',
- }))
- return table.concat(buf)
-end
-
-if opts['reporting'] == true then
+if settings.reporting == true then
+ rspamd_logger.errx(rspamd_config, 'old style dmarc reporting is NO LONGER supported, please read the documentation')
+elseif settings.reporting.enabled then
redis_params = rspamd_parse_redis_server('dmarc')
if not redis_params then
rspamd_logger.errx(rspamd_config, 'cannot parse servers parameter')
- elseif not opts['send_reports'] then
- dmarc_reporting = true
- take_report_id = rspamd_redis.add_redis_script(take_report_script, redis_params)
else
- dmarc_reporting = true
- if type(opts['report_settings']) == 'table' then
- for k, v in pairs(opts['report_settings']) do
- report_settings[k] = v
- end
- end
- for _, e in ipairs({'email', 'domain', 'org_name'}) do
- if not report_settings[e] then
- rspamd_logger.errx(rspamd_config, 'Missing required setting: report_settings.%s', e)
- return
- end
- end
take_report_id = rspamd_redis.add_redis_script(take_report_script, redis_params)
- rspamd_config:add_on_load(function(cfg, ev_base, worker)
- if not worker:is_primary_controller() then return end
-
- pool = mempool.create()
-
- rspamd_config:register_finish_script(function ()
- local stamp = pool:get_variable(VAR_NAME, 'double')
- if not stamp then
- rspamd_logger.warnx(rspamd_config, 'No last DMARC report information to persist to disk')
- return
- end
- local f, err = io.open(statefile, 'w')
- if err then
- rspamd_logger.errx(rspamd_config, 'Unable to write statefile to disk: %s', err)
- return
- end
- assert(f:write(pool:get_variable(VAR_NAME, 'double')))
- assert(f:close())
- pool:destroy()
- end)
-
- local get_reporting_domain, reporting_domain, report_start,
- report_end, report_id, want_period, report_key
- local reporting_addrs = {}
- local bcc_addrs = {}
- local domain_policy = {}
- local to_verify = {}
- local cursor = 0
- local function dmarc_report_xml()
- local entries = {}
- report_id = string.format('%s.%d.%d',
- reporting_domain, report_start, report_end)
- lua_util.debugm(N, rspamd_config, 'new report: %s', report_id)
- local actions = {
- push = function(t)
- local data = t[1]
- local split = rspamd_str_split(data, ',')
- local row = {
- ip = split[1],
- spf_disposition = split[2],
- dkim_disposition = split[3],
- disposition = split[4],
- override = split[5],
- header_from = split[6],
- dkim_results = {},
- spf_domain = split[11],
- spf_result = split[12],
- count = t[2],
- }
- if split[7] and split[7] ~= '' then
- local tmp = rspamd_str_split(split[7], '|')
- for _, d in ipairs(tmp) do
- table.insert(row.dkim_results, {domain = d, result = 'pass'})
- end
- end
- if split[8] and split[8] ~= '' then
- local tmp = rspamd_str_split(split[8], '|')
- for _, d in ipairs(tmp) do
- table.insert(row.dkim_results, {domain = d, result = 'fail'})
- end
- end
- if split[9] and split[9] ~= '' then
- local tmp = rspamd_str_split(split[9], '|')
- for _, d in ipairs(tmp) do
- table.insert(row.dkim_results, {domain = d, result = 'temperror'})
- end
- end
- if split[10] and split[10] ~= '' then
- local tmp = lua_util.str_split(split[10], '|')
- for _, d in ipairs(tmp) do
- table.insert(row.dkim_results,
- {domain = d, result = 'permerror'})
- end
- end
- table.insert(entries, row)
- end,
- -- TODO: please rework this shit
- header = function()
- return table.concat({
- '<?xml version="1.0" encoding="utf-8"?><feedback><report_metadata><org_name>',
- escape_xml(report_settings.org_name), '</org_name><email>',
- escape_xml(report_settings.email), '</email><report_id>',
- report_id, '</report_id><date_range><begin>', report_start,
- '</begin><end>', report_end, '</end></date_range></report_metadata><policy_published><domain>',
- reporting_domain, '</domain><adkim>', escape_xml(domain_policy.adkim), '</adkim><aspf>',
- escape_xml(domain_policy.aspf), '</aspf><p>', escape_xml(domain_policy.p),
- '</p><sp>', escape_xml(domain_policy.sp), '</sp><pct>',
- escape_xml(domain_policy.pct),
- '</pct></policy_published>'
- })
- end,
- footer = function()
- return [[</feedback>]]
- end,
- entries = function()
- local buf = {}
- for _, e in pairs(entries) do
- table.insert(buf, entry_to_xml(e))
- end
- return table.concat(buf, '')
- end,
- }
- return function(action, p)
- local f = actions[action]
- if not f then error('invalid action: ' .. action) end
- return f(p)
- end
- end
-
-
- local function send_report_via_email(xmlf, retry)
- if not retry then retry = 0 end
-
- local function sendmail_cb(ret, err)
- if not ret then
- rspamd_logger.errx(rspamd_config, "Couldn't send mail for %s: %s", err)
- if retry >= report_settings.retries then
- rspamd_logger.errx(rspamd_config, "Couldn't send mail for %s: retries exceeded", reporting_domain)
- return get_reporting_domain()
- else
- send_report_via_email(xmlf, retry + 1)
- end
- else
- get_reporting_domain()
- end
- end
-
- -- Format message
- local list_rcpt = lua_util.keys(reporting_addrs)
-
- local encoded = rspamd_util.encode_base64(rspamd_util.gzip_compress(
- table.concat(
- {xmlf('header'),
- xmlf('entries'),
- xmlf('footer')})), 73)
- local addr_string = table.concat(list_rcpt, ', ')
-
- local bcc_addrs_keys = lua_util.keys(bcc_addrs)
- local bcc_string
- if #bcc_addrs_keys > 0 then
- bcc_string = table.concat(bcc_addrs_keys, ', ')
- end
-
- local rhead = lua_util.jinja_template(report_template,
- {
- from_name = report_settings.from_name,
- from_addr = report_settings.email,
- rcpt = addr_string,
- bcc = bcc_string,
- reporting_domain = reporting_domain,
- submitter = report_settings.domain,
- report_id = report_id,
- report_date = rspamd_util.time_to_string(rspamd_util.get_time()),
- message_id = rspamd_util.random_hex(16) .. '@' .. report_settings.msgid_from,
- report_start = report_start,
- report_end = report_end
- }, true)
- local message = {
- (rhead:gsub("\n", "\r\n")),
- encoded,
- (report_footer:gsub("\n", "\r\n"))
- }
-
- local lua_smtp = require "lua_smtp"
- lua_smtp.sendmail({
- ev_base = ev_base,
- config = rspamd_config,
- host = report_settings.smtp,
- port = report_settings.smtp_port,
- resolver = rspamd_config:get_resolver(),
- from = report_settings.email,
*** OUTPUT TRUNCATED, 499 LINES SKIPPED ***
More information about the Commits
mailing list