From 6d0833e5ab01b0bde51b4219eb027d2ba75c1a01 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 28 Jan 2016 14:51:08 +0000 Subject: [PATCH] Improve and fix multimap plugin - Restore 'header' maps - Add filters for headers - Add 'email:addr', 'email:user', 'email:domain' and 'email:name' filters - Add generic regexp filters --- src/plugins/lua/multimap.lua | 99 ++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/src/plugins/lua/multimap.lua b/src/plugins/lua/multimap.lua index d821902ea..5a8bbeea9 100644 --- a/src/plugins/lua/multimap.lua +++ b/src/plugins/lua/multimap.lua @@ -29,6 +29,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. local rules = {} local rspamd_logger = require "rspamd_logger" local cdb = require "rspamd_cdb" +local util = require "rspamd_util" +local regexp = require "rspamd_regexp" local _ = require "fun" --local dumper = require 'pl.pretty'.dump @@ -37,9 +39,63 @@ local function ip_to_rbl(ip, rbl) end local function check_multimap(task) + -- Applies specific filter for input + local function apply_filter(filter, input, rule) + if filter == 'email:addr' or filter == 'email' then + local addr = util.parse_mail_address(input) + if addr and addr[1] then + return addr[1]['addr'] + end + elseif filter == 'email:user' then + local addr = util.parse_mail_address(input) + if addr and addr[1] then + return addr[1]['user'] + end + elseif filter == 'email:domain' then + local addr = util.parse_mail_address(input) + if addr and addr[1] then + return addr[1]['domain'] + end + elseif filter == 'email:name' then + local addr = util.parse_mail_address(input) + if addr and addr[1] then + return addr[1]['name'] + end + else + -- regexp case + if not rule['regexp'] then + local type,pat = string.match(filter, '(regexp:)(.+)') + if type and pat then + rule['regexp'] = regexp.create(pat) + end + end + + if not rule['regexp'] then + rspamd_logger.errx(task, 'bad search filter: %s', filter) + else + local results = rule['regexp']:search(input) + if results then + return results[1] + end + end + end + + return input + end + + -- Match a single value for against a single rule local function match_rule(r, value) local ret = false + + if r['filter'] then + value = apply_filter(r['filter'], value, r) + end + + if not value then + return false + end + if r['cdb'] then local srch = value if r['type'] == 'ip' then @@ -56,7 +112,7 @@ local function check_multimap(task) if ret then task:insert_result(r['symbol'], 1) end - + return ret end @@ -65,13 +121,13 @@ local function check_multimap(task) local ret = false if ls then if fields then - _.each(function(e) + _.each(function(e) local match = e[fields[1]] if match then if fields[2] then match = fields[2](match) end - ret = match_rule(r, match) + ret = match_rule(r, match) end end, ls) else @@ -81,10 +137,10 @@ local function check_multimap(task) return ret end - + local function match_addr(r, addr) local ret = match_list(r, addr, {'addr'}) - + if not ret then -- Try domain ret = match_list(r, addr, {'domain', function(d) return '@' .. d end}) @@ -93,9 +149,10 @@ local function check_multimap(task) -- Try user ret = match_list(r, addr, {'user', function(d) return d .. '@' end}) end - + return ret end + -- IP rules local ip = task:get_from_ip() if ip:is_valid() then @@ -106,13 +163,13 @@ local function check_multimap(task) -- Header rules _.each(function(r) local hv = task:get_header_full(r['header']) - match_list(r, hv, 'decoded') + match_list(r, hv, {'decoded'}) end, _.filter(function(r) return r['type'] == 'header' end, rules)) -- Rcpt rules - local rcpts = task:get_recipients() - if rcpts then + if task:has_recipients() then + local rcpts = task:get_recipients() _.each(function(r) match_addr(r, rcpts) end, @@ -120,12 +177,14 @@ local function check_multimap(task) end -- From rules - local from = task:get_from() - if from then - _.each(function(r) - match_addr(r, from) - end, - _.filter(function(r) return r['type'] == 'from' end, rules)) + if task:has_from() then + local from = task:get_from() + if from then + _.each(function(r) + match_addr(r, from) + end, + _.filter(function(r) return r['type'] == 'from' end, rules)) + end end -- RBL rules @@ -136,7 +195,7 @@ local function check_multimap(task) task:insert_result(r['symbol'], 1, r['map']) end end - + task:get_resolver():resolve_a({task = task, name = ip_to_rbl(ip, r['map']), callback = cb, @@ -148,13 +207,13 @@ end local function add_multimap_rule(key, newrule) if not newrule['map'] then - rspamd_logger.errx(rspamd_config, 'incomplete rule') + rspamd_logger.errx(rspamd_config, 'incomplete rule, missing map') return nil end if not newrule['symbol'] and key then newrule['symbol'] = key elseif not newrule['symbol'] then - rspamd_logger.errx(rspamd_config, 'incomplete rule') + rspamd_logger.errx(rspamd_config, 'incomplete rule, missing symbol') return nil end -- Check cdb flag @@ -186,7 +245,7 @@ local function add_multimap_rule(key, newrule) newrule['map']) end elseif newrule['type'] == 'dnsbl' then - return newrule + return newrule end end return nil @@ -209,7 +268,7 @@ if opts and type(opts) == 'table' then end -- add fake symbol to check all maps inside a single callback if type(rspamd_config.get_api_version) ~= 'nil' then - local id = rspamd_config:register_callback_symbol_priority(1.0, -1, + local id = rspamd_config:register_callback_symbol_priority(1.0, -1, check_multimap) for i,rule in ipairs(rules) do rspamd_config:register_virtual_symbol(rule['symbol'], 1.0, id) -- 2.39.5