Browse Source

[Rework] Completely rewrite DMARC checks logic

tags/1.8.1
Vsevolod Stakhov 5 years ago
parent
commit
a2ea0822d2
1 changed files with 423 additions and 296 deletions
  1. 423
    296
      src/plugins/lua/dmarc.lua

+ 423
- 296
src/plugins/lua/dmarc.lua View File

@@ -195,8 +195,8 @@ local function dmarc_report(task, spf_ok, dkim_ok, disposition,
return res
end

local function dmarc_callback(task)
local function maybe_force_action(disposition)
local function maybe_force_action(task, disposition)
if disposition then
local force_action = dmarc_actions[disposition]
if force_action then
-- Don't do anything if pre-result has been already set
@@ -204,363 +204,489 @@ local function dmarc_callback(task)
task:set_pre_result(force_action, 'Action set by DMARC')
end
end
local from = task:get_from(2)
local hfromdom = ((from or E)[1] or E).domain
local dmarc_domain, spf_domain
local ip_addr = task:get_ip()
local dkim_results = {}
local dmarc_checks = task:get_mempool():get_variable('dmarc_checks', 'int') or 0
end

if dmarc_checks ~= 2 then
rspamd_logger.infox(task, "skip DMARC checks as either SPF or DKIM were not checked");
return
end
--[[
-- Used to check dmarc record, check elements and produce dmarc policy processed
-- result.
-- Returns:
-- false,false - record is garbadge
-- false,error_message - record is invalid
-- true,policy_table - record is valid and parsed
]]
local function dmarc_check_record(task, record, is_tld)
local failed_policy
local result = {
dmarc_policy = 'none'
}

local elts = dmarc_grammar:match(record)
lua_util.debugm(N, task, "got DMARC record: %s, tld_flag=%s, processed=%s",
record, is_tld, elts)

if elts then
local dkim_pol = elts['adkim']
if dkim_pol then
if dkim_pol == 's' then
result.strict_dkim = true
elseif dkim_pol ~= 'r' then
failed_policy = 'adkim tag has invalid value: ' .. dkim_pol
return false,failed_policy
end
end

if ((not check_authed and task:get_user()) or
(not check_local and ip_addr and ip_addr:is_local())) then
rspamd_logger.infox(task, "skip DMARC checks for local networks and authorized users");
return
end
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')
return maybe_force_action('na')
elseif (from or E)[1] then
task:insert_result(dmarc_symbols['na'], 1.0, 'No domain in From header')
return maybe_force_action('na')
local spf_pol = elts['aspf']
if spf_pol then
if spf_pol == 's' then
result.strict_spf = true
elseif spf_pol ~= 'r' then
failed_policy = 'aspf tag has invalid value: ' .. spf_pol
return false,failed_policy
end
end

local policy = elts['p']
if policy then
if (policy == 'reject') then
result.dmarc_policy = 'reject'
elseif (policy == 'quarantine') then
result.dmarc_policy = 'quarantine'
elseif (policy ~= 'none') then
failed_policy = 'p tag has invalid value: ' .. policy
return false,failed_policy
end
end

-- Adjust policy if we are in tld mode
local subdomain_policy = elts['sp']
if elts['sp'] and is_tld then
result.subdomain_policy = elts['sp']

if (subdomain_policy == 'reject') then
result.dmarc_policy = 'reject'
elseif (subdomain_policy == 'quarantine') then
result.dmarc_policy = 'quarantine'
elseif (subdomain_policy == 'none') then
result.dmarc_policy = 'none'
elseif (subdomain_policy ~= 'none') then
failed_policy = 'sp tag has invalid value: ' .. subdomain_policy
return false,failed_policy
end
end
result.pct = elts['pct']
if result.pct then
result.pct = tonumber(result.pct)
end

if elts.rua then
result.rua = elts['rua']
end
else
task:insert_result(dmarc_symbols['na'], 1.0, 'No From header')
return maybe_force_action('na')
return false,false -- Ignore garbadge
end

local function dmarc_report_cb(err)
if not err then
rspamd_logger.infox(task, '<%1> dmarc report saved for %2',
task:get_message_id(), hfromdom)
return true, result
end

local function dmarc_validate_policy(task, policy, hdrfromdom)
local reason = {}

-- Check dkim and spf symbols
local spf_ok = false
local dkim_ok = false
local spf_tmpfail = false
local dkim_tmpfail = false

local spf_domain = ((task:get_from(1) or E)[1] or E).domain

if not spf_domain or spf_domain == '' then
spf_domain = task:get_helo() or ''
end

if task:has_symbol(symbols['spf_allow_symbol']) then
if policy.strict_spf then
if rspamd_util.strequal_caseless(spf_domain, hdrfromdom) then
spf_ok = true
else
table.insert(reason, "SPF not aligned (strict)")
end
else
rspamd_logger.errx(task, '<%1> dmarc report is not saved for %2: %3',
task:get_message_id(), hfromdom, err)
local spf_tld = rspamd_util.get_tld(spf_domain)
if rspamd_util.strequal_caseless(spf_tld, policy.domain) then
spf_ok = true
else
table.insert(reason, "SPF not aligned (relaxed)")
end
end
else
if task:has_symbol(symbols['spf_tempfail_symbol']) then
if policy.strict_spf then
if rspamd_util.strequal_caseless(spf_domain, hdrfromdom) then
spf_tmpfail = true
end
else
local spf_tld = rspamd_util.get_tld(spf_domain)
if rspamd_util.strequal_caseless(spf_tld, policy.domain) then
spf_tmpfail = true
end
end
end

table.insert(reason, "No valid SPF")
end

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
task:insert_result(dmarc_symbols['dnsfail'], 1.0, lookup_domain .. ' : ' .. err)
return maybe_force_action('dnsfail')
elseif err and (err == 'requested record is not found' or err == 'no records with this name') and
lookup_domain == dmarc_domain then
task:insert_result(dmarc_symbols['na'], 1.0, lookup_domain)
return maybe_force_action('na')
end
local opts = ((task:get_symbol('DKIM_TRACE') or E)[1] or E).options
local dkim_results = {
pass = {},
temperror = {},
permerror = {},
fail = {},
}

if not results then
if lookup_domain ~= dmarc_domain then
local resolve_name = '_dmarc.' .. dmarc_domain
task:get_resolver():resolve_txt({
task=task,
name = resolve_name,
callback = dmarc_dns_cb,
forced = true})
return
end

task:insert_result(dmarc_symbols['na'], 1.0, lookup_domain)
return maybe_force_action('na')
end
if opts then
dkim_results.pass = {}
local dkim_violated

local pct
local reason = {}
local strict_spf = false
local strict_dkim = false
local dmarc_policy = 'none'
local found_policy = false
local failed_policy
local rua

for _,r in ipairs(results) do
if failed_policy then break end
local function try()
local elts = dmarc_grammar:match(r)
if not elts then
return
for _,opt in ipairs(opts) do
local check_res = string.sub(opt, -1)
local domain = string.sub(opt, 1, -3)

if check_res == '+' then
table.insert(dkim_results.pass, domain)

if policy.strict_dkim then
if rspamd_util.strequal_caseless(hdrfromdom, domain) then
dkim_ok = true
else
dkim_violated = "DKIM not aligned (strict)"
end
else
if found_policy then
failed_policy = 'Multiple policies defined in DNS'
return
local dkim_tld = rspamd_util.get_tld(domain)

if rspamd_util.strequal_caseless(dkim_tld, policy.domain) then
dkim_ok = true
else
found_policy = true
dkim_violated = "DKIM not aligned (relaxed)"
end
end

if elts then
local dkim_pol = elts['adkim']
if dkim_pol then
if dkim_pol == 's' then
strict_dkim = true
elseif dkim_pol ~= 'r' then
failed_policy = 'adkim tag has invalid value: ' .. dkim_pol
return
elseif check_res == '?' then
-- Check for dkim tempfail
if not dkim_ok then
if policy.strict_dkim then
if rspamd_util.strequal_caseless(hdrfromdom, domain) then
dkim_tmpfail = true
end
end
else
local dkim_tld = rspamd_util.get_tld(domain)

local spf_pol = elts['aspf']
if spf_pol then
if spf_pol == 's' then
strict_spf = true
elseif spf_pol ~= 'r' then
failed_policy = 'aspf tag has invalid value: ' .. spf_pol
return
if rspamd_util.strequal_caseless(dkim_tld, policy.domain) then
dkim_tmpfail = true
end
end
end
table.insert(dkim_results.temperror, domain)
elseif check_res == '-' then
table.insert(dkim_results.fail, domain)
else
table.insert(dkim_results.permerror, domain)
end
end

local policy = elts['p']
if policy then
if (policy == 'reject') then
dmarc_policy = 'reject'
elseif (policy == 'quarantine') then
dmarc_policy = 'quarantine'
elseif (policy ~= 'none') then
failed_policy = 'p tag has invalid value: ' .. policy
return
end
end
if not dkim_ok and dkim_violated then
table.insert(reason, dkim_violated)
end
else
table.insert(reason, "No valid DKIM")
end

local subdomain_policy = elts['sp']
if subdomain_policy and lookup_domain == dmarc_domain then
if (subdomain_policy == 'reject') then
if dmarc_domain ~= hfromdom then
dmarc_policy = 'reject'
end
elseif (subdomain_policy == 'quarantine') then
if dmarc_domain ~= hfromdom then
dmarc_policy = 'quarantine'
end
elseif (subdomain_policy == 'none') then
if dmarc_domain ~= hfromdom then
dmarc_policy = 'none'
end
elseif (subdomain_policy ~= 'none') then
failed_policy = 'sp tag has invalid value: ' .. subdomain_policy
return
end
end
lua_util.debugm(N, task, "validated dmarc policy for %s: %s; dkim_ok=%s, dkim_tempfail=%s, spf_ok=%s, spf_tempfail=%s",
policy.domain, policy.dmarc_policy,
dkim_ok, dkim_tmpfail,
spf_ok, spf_tmpfail)

pct = elts['pct']
if pct then
pct = tonumber(pct)
end
local disposition = 'none'
local sampled_out = false

if not rua then
rua = elts['rua']
end
local function handle_dmarc_failure(what, reason_str)
if not policy.pct or policy.pct == 100 then
task:insert_result(what, 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
disposition = "quarantine"
else
if (math.random(100) > policy.pct) then
if (not no_sampling_domains or
not no_sampling_domains:get_key(policy.domain)) then
task:insert_result(dmarc_symbols['softfail'], 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "sampled_out")
sampled_out = true
else
task:insert_result(what, 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "local_policy")
disposition = what
end
else
task:insert_result(dmarc_symbols[what], 1.0,
policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
disposition = what
end
try()
end

if not found_policy then
if lookup_domain ~= dmarc_domain then
local resolve_name = '_dmarc.' .. dmarc_domain
task:get_resolver():resolve_txt({
task=task,
name = resolve_name,
callback = dmarc_dns_cb,
forced = true})
maybe_force_action(task, disposition)
end

return
if spf_ok or dkim_ok then
--[[
https://tools.ietf.org/html/rfc7489#section-6.6.2
DMARC evaluation can only yield a "pass" result after one of the
underlying authentication mechanisms passes for an aligned
identifier.
]]--
task:insert_result(dmarc_symbols['allow'], 1.0, policy.domain,
policy.dmarc_policy)
else
--[[
https://tools.ietf.org/html/rfc7489#section-6.6.2

If neither passes and one or both of them fail due to a
temporary error, the Receiver evaluating the message is unable to
conclude that the DMARC mechanism had a permanent failure; they
therefore cannot apply the advertised DMARC policy.
]]--
if spf_tmpfail or dkim_tmpfail then
task:insert_result(dmarc_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
local reason_str = table.concat(reason, ',')

if policy.dmarc_policy == 'quarantine' then
handle_dmarc_failure('quarantine', reason_str)
elseif policy.dmarc_policy == 'reject' then
handle_dmarc_failure('reject', reason_str)
else
task:insert_result(dmarc_symbols['na'], 1.0, lookup_domain)
return maybe_force_action('na')
task:insert_result(dmarc_symbols['softfail'], 1.0,
policy.domain .. ' : ' .. reason_str,
policy.dmarc_policy)
end
end
end

local res = 0.5
if failed_policy then
task:insert_result(dmarc_symbols['badpolicy'], res, lookup_domain .. ' : ' .. failed_policy)
return maybe_force_action('badpolicy')
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
rspamd_logger.infox(task, 'DMARC reporting suppressed for %1', policy.domain)
return
end
end

-- Check dkim and spf symbols
local spf_ok = false
local dkim_ok = false
spf_domain = ((task:get_from(1) or E)[1] or E).domain
if not spf_domain or spf_domain == '' then
spf_domain = task:get_helo() or ''
local function dmarc_report_cb(err)
if not err then
rspamd_logger.infox(task, '<%1> dmarc report saved for %2',
task:get_message_id(), hdrfromdom)
else
rspamd_logger.errx(task, '<%1> dmarc report is not saved for %2: %3',
task:get_message_id(), hdrfromdom, err)
end
end

if task:has_symbol(symbols['spf_allow_symbol']) then
if strict_spf and rspamd_util.strequal_caseless(spf_domain, hfromdom) then
spf_ok = true
elseif strict_spf then
table.insert(reason, "SPF not aligned (strict)")
end
if not strict_spf then
local spf_tld = rspamd_util.get_tld(spf_domain)
if rspamd_util.strequal_caseless(spf_tld, dmarc_domain) then
spf_ok = true
else
table.insert(reason, "SPF not aligned (relaxed)")
end
end
local spf_result
if spf_ok then
spf_result = 'pass'
elseif spf_tmpfail then
spf_result = 'temperror'
else
table.insert(reason, "No valid SPF")
end
local das = task:get_symbol(symbols['dkim_allow_symbol'])
if ((das or E)[1] or E).options then
dkim_results.pass = {}
for _,domain in ipairs(das[1]['options']) do
table.insert(dkim_results.pass, domain)
if strict_dkim and rspamd_util.strequal_caseless(hfromdom, domain) then
dkim_ok = true
elseif strict_dkim then
table.insert(reason, "DKIM not aligned (strict)")
end
if not strict_dkim then
local dkim_tld = rspamd_util.get_tld(domain)
if rspamd_util.strequal_caseless(dkim_tld, dmarc_domain) then
dkim_ok = true
else
table.insert(reason, "DKIM not aligned (relaxed)")
end
end
if task:get_symbol(symbols.spf_deny_symbol) then
spf_result = 'fail'
elseif task:get_symbol(symbols.spf_softfail_symbol) then
spf_result = 'softfail'
elseif task:get_symbol(symbols.spf_neutral_symbol) then
spf_result = 'neutral'
elseif task:get_symbol(symbols.spf_permfail_symbol) then
spf_result = 'permerror'
else
spf_result = 'none'
end
else
table.insert(reason, "No valid DKIM")
end

local disposition = 'none'
local sampled_out = false
local spf_tmpfail, dkim_tmpfail

if not (spf_ok or dkim_ok) then
local reason_str = table.concat(reason, ", ")
res = 1.0
spf_tmpfail = task:get_symbol(symbols['spf_tempfail_symbol'])
dkim_tmpfail = task:get_symbol(symbols['dkim_tempfail_symbol'])
if (spf_tmpfail or dkim_tmpfail) then
if ((dkim_tmpfail or E)[1] or E).options then
dkim_results.tempfail = {}
for _,domain in ipairs(dkim_tmpfail[1]['options']) do
table.insert(dkim_results.tempfail, domain)
end
end
task:insert_result(dmarc_symbols['dnsfail'], 1.0, lookup_domain .. ' : ' .. 'SPF/DKIM temp error', dmarc_policy)
return maybe_force_action('dnsfail')
-- Prepare and send redis report element
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)
local report_data = dmarc_report(task,
spf_ok and 'pass' or 'fail',
dkim_ok and 'pass' or 'fail',
disposition,
sampled_out,
hdrfromdom,
spf_domain,
dkim_results,
spf_result)

local idx_key = table.concat({redis_keys.index_prefix, period},
redis_keys.join_char)

if report_data then
rspamd_redis.exec_redis_script(take_report_id,
{task = task, is_write = true},
dmarc_report_cb,
{idx_key, dmarc_domain_key},
{hdrfromdom, report_data})
end
end
end

local function dmarc_callback(task)
local from = task:get_from(2)
local hfromdom = ((from or E)[1] or E).domain
local dmarc_domain
local ip_addr = task:get_ip()
local dmarc_checks = task:get_mempool():get_variable('dmarc_checks', 'int') or 0
local seen_invalid = false

if dmarc_checks ~= 2 then
rspamd_logger.infox(task, "skip DMARC checks as either SPF or DKIM were not checked");
return
end

if ((not check_authed and task:get_user()) or
(not check_local and ip_addr and ip_addr:is_local())) then
rspamd_logger.infox(task, "skip DMARC checks for local networks and authorized users");
return
end

-- Do some initial sanity checks, detect tld domain if different
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')
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')
return maybe_force_action(task,'na')
else
task:insert_result(dmarc_symbols['na'], 1.0, 'No From header')
return maybe_force_action(task,'na')
end


local dns_checks_inflight = 0
local dmarc_domain_policy = {}
local dmarc_tld_policy = {}

local function process_dmarc_policy(policy, is_tld)
lua_util.debugm(N, task, "validate DMARC policy (is_tld=%s): %s",
is_tld, policy)
if policy.err and policy.symbol then
-- In case of fatal errors or final check for tld, we give up and
-- insert result
if is_tld or policy.fatal then
task:insert_result(policy.symbol, 1.0, policy.err)
maybe_force_action(task, policy.disposition)

return true
end
if dmarc_policy == 'quarantine' then
if not pct or pct == 100 then
task:insert_result(dmarc_symbols['quarantine'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy)
disposition = "quarantine"
else
if (math.random(100) > pct) then
if (not no_sampling_domains or not no_sampling_domains:get_key(dmarc_domain)) then
task:insert_result(dmarc_symbols['softfail'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy, "sampled_out")
sampled_out = true
else
task:insert_result(dmarc_symbols['quarantine'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy, "local_policy")
disposition = "quarantine"
end
elseif policy.dmarc_policy then
dmarc_validate_policy(task, policy, hfromdom)

return true -- We have a more specific version, use it
end

return false -- Missing record
end

local function gen_dmarc_cb(lookup_domain, is_tld)
local policy_target = dmarc_domain_policy
if is_tld then
policy_target = dmarc_tld_policy
end

return function (_, _, results, err)
dns_checks_inflight = dns_checks_inflight - 1

if not seen_invalid then
policy_target.domain = lookup_domain

if err then
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']
else
task:insert_result(dmarc_symbols['quarantine'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy)
disposition = "quarantine"
policy_target.err = lookup_domain
policy_target.symbol = dmarc_symbols['na']
end
end
elseif dmarc_policy == 'reject' then
if not pct or pct == 100 then
task:insert_result(dmarc_symbols['reject'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy)
disposition = "reject"
else
if (math.random(100) > pct) then
if (not no_sampling_domains or not no_sampling_domains:get_key(dmarc_domain)) then
task:insert_result(dmarc_symbols['quarantine'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy, "sampled_out")
disposition = "quarantine"
sampled_out = true
local has_valid_policy = false

for _,rec in ipairs(results) do
local ret,results_or_err = dmarc_check_record(task, rec, is_tld)

if not ret then
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.fatal = true
seen_invalid = true
end
else
task:insert_result(dmarc_symbols['reject'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy, "local_policy")
disposition = "reject"
if has_valid_policy then
policy_target.err = lookup_domain .. ' : ' ..
'Multiple policies defined in DNS'
policy_target.symbol = dmarc_symbols['badpolicy']
policy_target.fatal = true
seen_invalid = true
end
has_valid_policy = true

for k,v in pairs(results_or_err) do
policy_target[k] = v
end
end
else
task:insert_result(dmarc_symbols['reject'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy)
disposition = "reject"
end
end
else
task:insert_result(dmarc_symbols['softfail'], res, lookup_domain .. ' : ' .. reason_str, dmarc_policy)
end
else
task:insert_result(dmarc_symbols['allow'], res, lookup_domain, dmarc_policy)
end

if rua and redis_params and dmarc_reporting then

if no_reporting_domains then
if no_reporting_domains:get_key(dmarc_domain) or no_reporting_domains:get_key(rspamd_util.get_tld(dmarc_domain)) then
rspamd_logger.infox(task, 'DMARC reporting suppressed for %1', dmarc_domain)
return maybe_force_action(disposition)
end
end

local spf_result
if spf_ok then
spf_result = 'pass'
elseif spf_tmpfail then
spf_result = 'temperror'
else
if task:get_symbol(symbols.spf_deny_symbol) then
spf_result = 'fail'
elseif task:get_symbol(symbols.spf_softfail_symbol) then
spf_result = 'softfail'
elseif task:get_symbol(symbols.spf_neutral_symbol) then
spf_result = 'neutral'
elseif task:get_symbol(symbols.spf_permfail_symbol) then
spf_result = 'permerror'
else
spf_result = 'none'
end
end
local dkim_deny = ((task:get_symbol(symbols.dkim_deny_symbol) or E)[1] or E).options
if dkim_deny then
dkim_results.fail = {}
for _, domain in ipairs(dkim_deny) do
table.insert(dkim_results.fail, domain)
end
end
local dkim_permerror = ((task:get_symbol(symbols.dkim_permfail_symbol) or E)[1] or E).options
if dkim_permerror then
dkim_results.permerror = {}
for _, domain in ipairs(dkim_permerror) do
table.insert(dkim_results.permerror, domain)
if dns_checks_inflight == 0 then
lua_util.debugm(N, task, "finished DNS queries, validate policies")
-- We have checked both tld and real domain (if different)
if not process_dmarc_policy(dmarc_domain_policy, false) then
-- Try tld policy as well
process_dmarc_policy(dmarc_tld_policy, true)
end
end
-- Prepare and send redis report element
local period = os.date('%Y%m%d', task:get_date({format = 'connect', gmt = true}))
local dmarc_domain_key = table.concat({redis_keys.report_prefix, hfromdom, period}, redis_keys.join_char)
local report_data = dmarc_report(task, spf_ok and 'pass' or 'fail', dkim_ok and 'pass' or 'fail', disposition, sampled_out,
hfromdom, spf_domain, dkim_results, spf_result)
local idx_key = table.concat({redis_keys.index_prefix, period}, redis_keys.join_char)

if report_data then
rspamd_redis.exec_redis_script(take_report_id, {task = task, is_write = true}, dmarc_report_cb,
{idx_key, dmarc_domain_key}, {hfromdom, report_data})
end
end

return maybe_force_action(disposition)

end

-- Do initial request
local resolve_name = '_dmarc.' .. hfromdom

task:get_resolver():resolve_txt({
task=task,
name = resolve_name,
callback = dmarc_dns_cb,
forced = true})
callback = gen_dmarc_cb(hfromdom, false),
forced = true
})
dns_checks_inflight = dns_checks_inflight + 1

if dmarc_domain ~= hfromdom then
resolve_name = '_dmarc.' .. dmarc_domain

task:get_resolver():resolve_txt({
task=task,
name = resolve_name,
callback = gen_dmarc_cb(dmarc_domain, true),
forced = true
})

dns_checks_inflight = dns_checks_inflight + 1
end
end


local function try_opts(where)
local ret = false
local opts = rspamd_config:get_all_opt(where)
@@ -595,6 +721,7 @@ if opts['symbols'] then
end
end

-- XXX: rework this shitty code some day please
if opts['reporting'] == true then
redis_params = rspamd_parse_redis_server('dmarc')
if not redis_params then

Loading…
Cancel
Save