]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Fix couple of issues in FORWARDED rule
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 27 Apr 2017 16:51:11 +0000 (17:51 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 1 May 2017 13:04:37 +0000 (14:04 +0100)
rules/forwarding.lua

index eae803f8160e1c5940d9067569ad20058b0aa436..d145890d2bcd81d771df00a552635f9e7aedd719 100644 (file)
@@ -16,133 +16,145 @@ limitations under the License.
 
 -- Rules to detect forwarding
 
+local fun = require "fun"
+
 rspamd_config.FWD_GOOGLE = {
-    callback = function (task)
-        if not (task:has_from(1) and task:has_recipients(1)) then
-            return false
-        end
-        local envfrom = task:get_from(1)
-        local envrcpts = task:get_recipients(1)
-        -- Forwarding will only be to a single recipient
-        if #envrcpts > 1 then return false end
-        -- Get recipient and compute VERP address
-        local rcpt = envrcpts[1].addr:lower()
-        local verp = rcpt:gsub('@','=')
-        -- Get the user portion of the envfrom
-        local ef_user = envfrom[1].user:lower()
-        -- Check for a match
-        if ef_user:find('+caf_=' .. verp, 1, true) then
-            local _,_,user = ef_user:find('^(.+)+caf_=')
-            if user then
-                user = user .. '@' .. envfrom[1].domain
-                return true, user
-            end
-        end
-        return false
-    end,
-    score = 0.0,
-    description = "Message was forwarded by Google",
-    group = "forwarding"
+  callback = function (task)
+    if not (task:has_from(1) and task:has_recipients(1)) then
+      return false
+    end
+    local envfrom = task:get_from(1)
+    local envrcpts = task:get_recipients(1)
+    -- Forwarding will only be to a single recipient
+    if #envrcpts > 1 then return false end
+    -- Get recipient and compute VERP address
+    local rcpt = envrcpts[1].addr:lower()
+    local verp = rcpt:gsub('@','=')
+    -- Get the user portion of the envfrom
+    local ef_user = envfrom[1].user:lower()
+    -- Check for a match
+    if ef_user:find('+caf_=' .. verp, 1, true) then
+      local _,_,user = ef_user:find('^(.+)+caf_=')
+      if user then
+        user = user .. '@' .. envfrom[1].domain
+        return true, user
+      end
+    end
+    return false
+  end,
+  score = 0.0,
+  description = "Message was forwarded by Google",
+  group = "forwarding"
 }
 
 rspamd_config.FWD_YANDEX = {
-    callback = function (task)
-        if not (task:has_from(1) and task:has_recipients(1)) then
-            return false
-        end
-        local hostname = task:get_hostname()
-        if hostname and hostname:lower():find('%.yandex%.[a-z]+$') then
-            if task:get_header_raw('X-Yandex-Forward') then
-                return true
-            end
-        end
-        return false
-    end,
-    score = 0.0,
-    description = "Message was forwarded by Yandex",
-    group = "forwarding"
+  callback = function (task)
+    if not (task:has_from(1) and task:has_recipients(1)) then
+      return false
+    end
+    local hostname = task:get_hostname()
+    if hostname and hostname:lower():find('%.yandex%.[a-z]+$') then
+      if task:get_header_raw('X-Yandex-Forward') then
+        return true
+      end
+    end
+    return false
+  end,
+  score = 0.0,
+  description = "Message was forwarded by Yandex",
+  group = "forwarding"
 }
 
 rspamd_config.FWD_MAILRU = {
-    callback = function (task)
-        if not (task:has_from(1) and task:has_recipients(1)) then
-            return false
-        end
-        local hostname = task:get_hostname()
-        if hostname and hostname:lower():find('%.mail%.ru$') then
-            if task:get_header_raw('X-MailRu-Forward') then
-                return true
-            end
-        end
-        return false
-    end,
-    score = 0.0,
-    description = "Message was forwarded by Mail.ru",
-    group = "forwarding"
+  callback = function (task)
+    if not (task:has_from(1) and task:has_recipients(1)) then
+      return false
+    end
+    local hostname = task:get_hostname()
+    if hostname and hostname:lower():find('%.mail%.ru$') then
+      if task:get_header_raw('X-MailRu-Forward') then
+        return true
+      end
+    end
+    return false
+  end,
+  score = 0.0,
+  description = "Message was forwarded by Mail.ru",
+  group = "forwarding"
 }
 
 rspamd_config.FWD_SRS = {
-    callback = function (task)
-        if not (task:has_from(1) and task:has_recipients(1)) then
-            return false
-        end
-        local envfrom = task:get_from(1)
-        local envrcpts = task:get_recipients(1)
-        -- Forwarding is only to a single recipient
-        if #envrcpts > 1 then return false end
-        -- Get recipient and compute rewritten SRS address
-        local srs = '=' .. envrcpts[1].domain:lower() ..
-                    '=' .. envrcpts[1].user:lower()
-        if envfrom[1].user:lower():find('^srs[01]=') and
-           envfrom[1].user:lower():find(srs, 1, false)
-        then
-            return true
-        end
-        return false
-    end,
-    score = 0.0,
-    description = "Message was forwarded using SRS",
-    group = "forwarding"
+  callback = function (task)
+    if not (task:has_from(1) and task:has_recipients(1)) then
+      return false
+    end
+    local envfrom = task:get_from(1)
+    local envrcpts = task:get_recipients(1)
+    -- Forwarding is only to a single recipient
+    if #envrcpts > 1 then return false end
+    -- Get recipient and compute rewritten SRS address
+    local srs = '=' .. envrcpts[1].domain:lower() ..
+        '=' .. envrcpts[1].user:lower()
+    if envfrom[1].user:lower():find('^srs[01]=') and
+        envfrom[1].user:lower():find(srs, 1, false)
+    then
+      return true
+    end
+    return false
+  end,
+  score = 0.0,
+  description = "Message was forwarded using SRS",
+  group = "forwarding"
 }
 
 rspamd_config.FORWARDED = {
-    callback = function (task)
-        if not task:has_recipients(1) then return false end
-        local envrcpts = task:get_recipients(1)
-        -- Forwarding will only be for single recipient messages
-        if #envrcpts > 1 then return false end
-        -- Get any other headers we might need
-        local lu = task:get_header('List-Unsubscribe')
-        local to = task:get_recipients(2)
-        local matches = 0
-        -- Retrieve and loop through all Received headers
-        local rcvds = task:get_received_headers()
+  callback = function (task)
+    local function normalize_addr(addr)
+      addr = string.match(addr, '^<?([^<]*)>?$') or addr
+      local cap, _,domain = string.match(addr, '^([^%+][^%+]*)(%+[^@]*)@(.*)$')
+      if cap then
+        addr = string.format('%s@%s', cap, domain)
+      end
+
+      return addr
+    end
+
+    if not task:has_recipients(1) then return false end
+    local envrcpts = task:get_recipients(1)
+    -- Forwarding will only be for single recipient messages
+    if #envrcpts > 1 then return false end
+    -- Get any other headers we might need
+    local lu = task:get_header('List-Unsubscribe')
+    local to = task:get_recipients(2)
+    local matches = 0
+    -- Retrieve and loop through all Received headers
+    local rcvds = task:get_received_headers()
 
-        if rcvds then
-          for _, rcvd in ipairs(rcvds) do
-            local addr = rcvd['for']
-            if addr then
-              matches = matches + 1
-              -- Check that it doesn't match the envrcpt
-              -- TODO: remove any plus addressing?
-              if addr ~= envrcpts[1].addr:lower() then
-                -- Check for mailing-lists as they will have the same signature
-                if matches < 2 and lu and to and to[1].addr:lower() == addr then
-                  return false
-                else
-                  return true, addr
-                end
-              end
-              -- Prevent any other iterations as we only want
-              -- process the first matching Received header
+    if rcvds then
+      for _, rcvd in ipairs(rcvds) do
+        local addr = rcvd['for']
+        if addr then
+          addr = normalize_addr(addr)
+          matches = matches + 1
+          -- Check that it doesn't match the envrcpt
+          if addr ~= envrcpts[1].addr:lower() then
+            -- Check for mailing-lists as they will have the same signature
+            if matches < 2 and lu and to and to[1].addr:lower() == addr then
               return false
+            else
+              return true, 1.0, addr
             end
           end
+          -- Prevent any other iterations as we only want
+          -- process the first matching Received header
+          return false
         end
-        return false
-    end,
-    score = 0.0,
-    description = "Message was forwarded",
-    group = "forwarding"
+      end
+    end
+    return false
+  end,
+  score = 0.0,
+  description = "Message was forwarded",
+  group = "forwarding"
 }