]> source.dussan.org Git - rspamd.git/commitdiff
Improve and fix multimap plugin
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 28 Jan 2016 14:51:08 +0000 (14:51 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 28 Jan 2016 14:51:08 +0000 (14:51 +0000)
- 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

index d821902eaa91a56a7426d556787fbffaf0d29d15..5a8bbeea923b33e1afbc6cd9d5212389a47125f5 100644 (file)
@@ -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)