From e9c1446f0afc281546dc356943358ff33491378e Mon Sep 17 00:00:00 2001 From: Andrew Lewis Date: Wed, 11 Feb 2015 15:43:26 +0200 Subject: [PATCH] Update RBL module: fix indentation; collapse loops; avoid calling for un-needed information; allow disabling RBLs for authenticated users --- conf/modules.conf | 1 + doc/markdown/modules/rbl.md | 6 +- src/plugins/lua/rbl.lua | 326 ++++++++++++++++++++++-------------- 3 files changed, 207 insertions(+), 126 deletions(-) diff --git a/conf/modules.conf b/conf/modules.conf index 719b86793..a72eb1818 100644 --- a/conf/modules.conf +++ b/conf/modules.conf @@ -86,6 +86,7 @@ rbl { default_from = true; default_received = false; + default_user = false; rbls { diff --git a/doc/markdown/modules/rbl.md b/doc/markdown/modules/rbl.md index 84bb91478..3bcbf839b 100644 --- a/doc/markdown/modules/rbl.md +++ b/doc/markdown/modules/rbl.md @@ -19,7 +19,7 @@ rbl { The default settings define the ways in which the RBLs are used unless overridden in an RBL-specific subsection. -Defaults may be set for the following parameters (default values used if these are not set are shown in brackets): +Defaults may be set for the following parameters (default values used if these are not set are shown in brackets - note that these may be redefined in the default config): - default_ipv4 (true) @@ -49,6 +49,10 @@ Use this RBL to test parameters sent for HELO/EHLO at SMTP time. If set to false, do not yield a result unless the response received from the RBL is defined in its related returncodes {} subsection, else return the default symbol for the RBL. +- deault_user (true) + +If set to false, do not use this RBL if the message sender is authenticated. + RBL-specific subsection is structured as follows: ~~~nginx diff --git a/src/plugins/lua/rbl.lua b/src/plugins/lua/rbl.lua index 5b6165d80..9258c1e86 100644 --- a/src/plugins/lua/rbl.lua +++ b/src/plugins/lua/rbl.lua @@ -3,159 +3,235 @@ local rbls = {} local rspamd_logger = require "rspamd_logger" local function ip_to_rbl(ip, rbl) - return table.concat(ip:inversed_str_octets(), ".") .. '.' .. rbl + return table.concat(ip:inversed_str_octets(), ".") .. '.' .. rbl end local function rbl_cb (task) - local function rbl_dns_cb(resolver, to_resolve, results, err, key) - if results then - local thisrbl = nil - for k,r in pairs(rbls) do - if k == key then - thisrbl = r - break - end - end - if thisrbl ~= nil then - if thisrbl['returncodes'] == nil then - if thisrbl['symbol'] ~= nil then - task:insert_result(thisrbl['symbol'], 1) - end - else - for _,result in pairs(results) do - local ipstr = result:to_string() - local foundrc = false - for s,i in pairs(thisrbl['returncodes']) do - if type(i) == 'string' then - if string.find(ipstr, "^" .. i .. "$") then - foundrc = true - task:insert_result(s, 1) - break - end - elseif type(i) == 'table' then - for _,v in pairs(i) do - if string.find(ipstr, "^" .. v .. "$") then - foundrc = true - task:insert_result(s, 1) - break - end - end - end - end - if not foundrc then - if thisrbl['unknown'] and thisrbl['symbol'] then - task:insert_result(thisrbl['symbol'], 1) - else - rspamd_logger.err('RBL ' .. thisrbl['rbl'] .. ' returned unknown result ' .. ipstr) - end - end - end - end - end - end - task:inc_dns_req() - end + local function rbl_dns_cb(resolver, to_resolve, results, err, key) + if results then + local thisrbl = nil + for k,r in pairs(rbls) do + if k == key then + thisrbl = r + break + end + end + if thisrbl ~= nil then + if thisrbl['returncodes'] == nil then + if thisrbl['symbol'] ~= nil then + task:insert_result(thisrbl['symbol'], 1) + end + else + for _,result in pairs(results) do + local ipstr = result:to_string() + local foundrc = false + for s,i in pairs(thisrbl['returncodes']) do + if type(i) == 'string' then + if string.find(ipstr, "^" .. i .. "$") then + foundrc = true + task:insert_result(s, 1) + break + end + elseif type(i) == 'table' then + for _,v in pairs(i) do + if string.find(ipstr, "^" .. v .. "$") then + foundrc = true + task:insert_result(s, 1) + break + end + end + end + end + if not foundrc then + if thisrbl['unknown'] and thisrbl['symbol'] then + task:insert_result(thisrbl['symbol'], 1) + else + rspamd_logger.err('RBL ' .. thisrbl['rbl'] .. + ' returned unknown result ' .. ipstr) + end + end + end + end + end + end + task:inc_dns_req() + end - local helo = task:get_helo() - if helo and string.sub(helo,1,1) ~= '[' then - for k,rbl in pairs(rbls) do - if rbl['helo'] then - task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), helo .. '.' .. rbl['rbl'], rbl_dns_cb, k) - end - end - end - local sender_dns = task:get_hostname() - if sender_dns ~= nil and sender_dns ~= 'unknown' then - for k,rbl in pairs(rbls) do - if rbl['rdns'] then - task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), sender_dns .. '.' .. rbl['rbl'], rbl_dns_cb, k) - end - end - end - local rip = task:get_from_ip() - if rip and (rip:to_string() ~= '0.0.0.0') then - for k,rbl in pairs(rbls) do - if (rip:get_version() == 6 and rbl['ipv6'] and rbl['from']) or - (rip:get_version() == 4 and rbl['ipv4'] and rbl['from']) then - task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), - ip_to_rbl(rip, rbl['rbl']), rbl_dns_cb, k) - end - end - end - local recvh = task:get_received_headers() - for _,rh in ipairs(recvh) do - if rh['real_ip'] and rh['real_ip']:to_string() ~= '0.0.0.0' then - for k,rbl in pairs(rbls) do - if (rh['real_ip']:get_version() == 6 and rbl['ipv6'] and rbl['received']) or - (rh['real_ip']:get_version() == 4 and rbl['ipv4'] and rbl['received']) then - task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), - ip_to_rbl(rh['real_ip'], rbl['rbl']), rbl_dns_cb, k) - end - end - end - end + local havegot = {} + local notgot = {} + local function check_user() + if not havegot['user'] and not notgot['user'] then + havegot['user'] = task:get_user() + if havegot['user'] == nil then + notgot['user'] = true + end + end + if havegot['user'] ~= nil then + return true + end + return false + end + + for k,rbl in pairs(rbls) do + + if rbl['helo'] then + (function() + if notgot['helo'] then + return + end + if not havegot['helo'] then + havegot['helo'] = task:get_helo() + if havegot['helo'] == nil or string.sub(havegot['helo'],1,1) == '[' then + notgot['helo'] = true + return + end + end + if rbl['user'] == false and check_user() == true then + return + end + task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), + havegot['helo'] .. '.' .. rbl['rbl'], rbl_dns_cb, k) + end)() + end + + if rbl['rdns'] then + (function() + if notgot['rdns'] then + return + end + if not havegot['rdns'] then + havegot['rdns'] = task:get_hostname() + if havegot['rdns'] == nil or havegot['rdns'] == 'unknown' then + notgot['rdns'] = true + return + end + end + if rbl['user'] == false and check_user() == true then + return + end + task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), + havegot['rdns'] .. '.' .. rbl['rbl'], rbl_dns_cb, k) + end)() + end + + if rbl['from'] then + (function() + if notgot['from'] then + return + end + if not havegot['from'] then + havegot['from'] = task:get_from_ip() + if havegot['from'] == nil then + notgot['from'] = true + return + end + end + if (havegot['from']:get_version() == 6 and rbl['ipv6']) or + (havegot['from']:get_version() == 4 and rbl['ipv4']) then + if rbl['user'] == false and check_user() == true then + return + end + task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), + ip_to_rbl(havegot['from'], rbl['rbl']), rbl_dns_cb, k) + end + end)() + end + + if rbl['received'] then + (function() + if notgot['received'] then + return + end + if not havegot['received'] then + havegot['received'] = task:get_received_headers() + if havegot['received'] == nil then + notgot['received'] = true + return + end + end + if rbl['user'] == false and check_user() == true then + return + end + for _,rh in ipairs(havegot['received']) do + if rh['real_ip'] and rh['real_ip']:to_string() ~= '0.0.0.0' then + for k,rbl in pairs(rbls) do + if (rh['real_ip']:get_version() == 6 and rbl['ipv6']) or + (rh['real_ip']:get_version() == 4 and rbl['ipv4']) then + task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), + ip_to_rbl(rh['real_ip'], rbl['rbl']), rbl_dns_cb, k) + end + end + end + end + end)() + end + end end -- Registration if type(rspamd_config.get_api_version) ~= 'nil' then - if rspamd_config:get_api_version() >= 1 then - rspamd_config:register_module_option('rbl', 'rbls', 'map') - rspamd_config:register_module_option('rbl', 'default_ipv4', 'string') - rspamd_config:register_module_option('rbl', 'default_ipv6', 'string') - rspamd_config:register_module_option('rbl', 'default_received', 'string') - rspamd_config:register_module_option('rbl', 'default_from', 'string') - rspamd_config:register_module_option('rbl', 'default_rdns', 'string') - rspamd_config:register_module_option('rbl', 'default_helo', 'string') - rspamd_config:register_module_option('rbl', 'default_unknown', 'string') - end + if rspamd_config:get_api_version() >= 1 then + rspamd_config:register_module_option('rbl', 'rbls', 'map') + rspamd_config:register_module_option('rbl', 'default_ipv4', 'string') + rspamd_config:register_module_option('rbl', 'default_ipv6', 'string') + rspamd_config:register_module_option('rbl', 'default_received', 'string') + rspamd_config:register_module_option('rbl', 'default_from', 'string') + rspamd_config:register_module_option('rbl', 'default_rdns', 'string') + rspamd_config:register_module_option('rbl', 'default_helo', 'string') + rspamd_config:register_module_option('rbl', 'default_unknown', 'string') + rspamd_config:register_module_option('rbl', 'default_user', 'string') + end end -- Configuration local opts = rspamd_config:get_all_opt('rbl') if not opts or type(opts) ~= 'table' then - return + return end if(opts['default_ipv4'] == nil) then - opts['default_ipv4'] = true + opts['default_ipv4'] = true end if(opts['default_ipv6'] == nil) then - opts['default_ipv6'] = false + opts['default_ipv6'] = false end if(opts['default_received'] == nil) then - opts['default_received'] = true + opts['default_received'] = true end if(opts['default_from'] == nil) then - opts['default_from'] = false + opts['default_from'] = false end if(opts['default_unknown'] == nil) then - opts['default_unknown'] = false + opts['default_unknown'] = false end if(opts['default_rdns'] == nil) then - opts['default_rdns'] = false + opts['default_rdns'] = false end if(opts['default_helo'] == nil) then - opts['default_helo'] = false + opts['default_helo'] = false +end +if(opts['default_user'] == nil) then + opts['default_user'] = true end for key,rbl in pairs(opts['rbls']) do - local o = { "ipv4", "ipv6", "from", "received", "unknown", "rdns", "helo" } - for i=1,table.maxn(o) do - if(rbl[o[i]] == nil) then - rbl[o[i]] = opts['default_' .. o[i]] - end - end - if type(rbl['returncodes']) == 'table' then - for s,_ in pairs(rbl['returncodes']) do - if type(rspamd_config.get_api_version) ~= 'nil' then - rspamd_config:register_virtual_symbol(s, 1) - end - end - end - if not rbl['symbol'] and type(rbl['returncodes']) ~= 'nil' and not rbl['unknown'] then - rbl['symbol'] = key - end - if type(rspamd_config.get_api_version) ~= 'nil' and rbl['symbol'] then - rspamd_config:register_virtual_symbol(rbl['symbol'], 1) - end - rbls[key] = rbl + local o = { "ipv4", "ipv6", "from", "received", "unknown", "rdns", "helo", "user" } + for i=1,table.maxn(o) do + if(rbl[o[i]] == nil) then + rbl[o[i]] = opts['default_' .. o[i]] + end + end + if type(rbl['returncodes']) == 'table' then + for s,_ in pairs(rbl['returncodes']) do + if type(rspamd_config.get_api_version) ~= 'nil' then + rspamd_config:register_virtual_symbol(s, 1) + end + end + end + if not rbl['symbol'] and type(rbl['returncodes']) ~= 'nil' and not rbl['unknown'] then + rbl['symbol'] = key + end + if type(rspamd_config.get_api_version) ~= 'nil' and rbl['symbol'] then + rspamd_config:register_virtual_symbol(rbl['symbol'], 1) + end + rbls[key] = rbl end rspamd_config:register_callback_symbol_priority('RBL', 1.0, 0, rbl_cb) -- 2.39.5