]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] rmilter_headers: authentication-results (#78) 1252/head
authorAndrew Lewis <nerf@judo.za.org>
Mon, 12 Dec 2016 12:08:08 +0000 (14:08 +0200)
committerAndrew Lewis <nerf@judo.za.org>
Mon, 12 Dec 2016 12:08:08 +0000 (14:08 +0200)
src/plugins/lua/rmilter_headers.lua

index 9e2f99ac14c998f6a843263addae966184469880..98a778058a1c20ba41c6057a2ea657f0792f7828 100644 (file)
@@ -38,6 +38,35 @@ local settings = {
       header = 'X-Spam-Status',
       remove = 1,
     },
+    ['authentication-results'] = {
+      header = 'Authentication-Results',
+      remove = 1,
+      spf_symbols = {
+        pass = 'R_SPF_ALLOW',
+        fail = 'R_SPF_FAIL',
+        softfail = 'R_SPF_SOFTFAIL',
+        neutral = 'R_SPF_NEUTRAL',
+        temperror = 'R_SPF_DNSFAIL',
+        none = 'R_SPF_NA',
+        permerror = 'R_SPF_PERMFAIL',
+      },
+      dkim_symbols = {
+        pass = 'R_DKIM_ALLOW',
+        fail = 'R_DKIM_REJECT',
+        temperror = 'R_DKIM_TEMPFAIL',
+        none = 'R_DKIM_NA',
+        permerror = 'R_DKIM_PERMFAIL',
+      },
+      dmarc_symbols = {
+        pass = 'DMARC_POLICY_ALLOW',
+        permerror = 'DMARC_BAD_POLICY',
+        temperror = 'DMARC_DNSFAIL',
+        none = 'DMARC_NA',
+        reject = 'DMARC_POLICY_REJECT',
+        softfail = 'DMARC_POLICY_SOFTFAIL',
+        quarantine = 'DMARC_POLICY_QUARANTINE',
+      },
+    },
   },
 }
 
@@ -112,6 +141,92 @@ routines['x-spam-status'] = function(task, common_meta)
   return nil, add, remove, common
 end
 
+routines['authentication-results'] = function(task, common_meta)
+  local add, remove, auth_results, hdr_parts = {}, {}, {}, {}
+  local common = {symbols = {}}
+  local auth_types = {
+    dkim = settings.routines['authentication-results'].dkim_symbols,
+    dmarc = settings.routines['authentication-results'].dmarc_symbols,
+    spf = settings.routines['authentication-results'].spf_symbols,
+  }
+  if not common_meta.symbols then common_meta.symbols = {} end
+  for auth_type, symbols in pairs(auth_types) do
+    for key, sym in pairs(symbols) do
+      if not (common_meta.symbols[sym] == false) then
+        local s = task:get_symbol(sym)
+        if not s then
+          common_meta.symbols[sym] = false
+          common.symbols[sym] = false
+        else
+          common_meta.symbols[sym] = s
+          common.symbols[sym] = s
+          if not auth_results[auth_type] then
+            auth_results[auth_type] = {key}
+          else
+            table.insert(auth_results[auth_type], key)
+          end
+          if auth_type ~= 'dkim' then
+            break
+          end
+        end
+      end
+    end
+  end
+  if settings.routines['authentication-results'].remove then
+    remove[settings.routines['authentication-results'].header] = settings.routines['authentication-results'].remove
+  end
+  for auth_type, keys in pairs(auth_results) do
+    for _, key in ipairs(keys) do
+      local hdr = ''
+      if auth_type == 'dmarc' and key ~= 'none' then
+        hdr = hdr .. 'dmarc='
+        if key == 'reject' or key == 'quarantine' or key == 'softfail' then
+          hdr = hdr .. 'fail'
+        else
+          hdr = hdr .. key
+        end
+        if key == 'pass' then
+          hdr = hdr .. ' policy=' .. common_meta.symbols[auth_types['dmarc'][key]][1]['options'][2]
+          hdr = hdr .. ' header.from=' .. common_meta.symbols[auth_types['dmarc'][key]][1]['options'][1]
+        elseif key ~= 'none' then
+          local dom, rsn = rspamd_str_split(common_meta.symbols[auth_types['dmarc'][key]][1]['options'][1], ' : ')
+          hdr = hdr .. ' reason="' .. rsn .. '"'
+          hdr = hdr .. ' header.from=' .. dom
+          if key == 'softfail' then
+            hdr = hdr .. ' policy=none'
+          else
+            hdr = hdr .. ' policy=' .. key
+          end
+        end
+        table.insert(hdr_parts, hdr)
+      elseif auth_type == 'dkim' and key ~= 'none' then
+        if common_meta.symbols[auth_types['dkim'][key]][1] then
+          for _, v in ipairs(common_meta.symbols[auth_types['dkim'][key]][1]['options']) do
+            hdr = hdr .. auth_type .. '=' .. key .. ' header.d=' .. v
+            table.insert(hdr_parts, hdr)
+          end
+        end
+      elseif auth_type == 'spf' and key ~= 'none' then
+        hdr = hdr .. auth_type .. '=' .. key
+        local smtp_from = task:get_from('smtp')
+        if smtp_from['addr'] ~= '' and smtp_from['addr'] ~= nil then
+          hdr = hdr .. ' smtp.mailfrom=' .. smtp_from['addr']
+        else
+          local helo = task:get_helo()
+          if helo then
+            hdr = hdr .. ' smtp.helo=' .. task:get_helo()
+          end
+        end
+        table.insert(hdr_parts, hdr)
+      end
+    end
+  end
+  if #hdr_parts > 0 then
+    add[settings.routines['authentication-results'].header] = table.concat(hdr_parts, '; ')
+  end
+  return nil, add, remove, common
+end
+
 local function rmilter_headers(task)
   local common_meta, to_add, to_remove = {}, {}, {}
   for n, f in pairs(active_routines) do
@@ -126,7 +241,13 @@ local function rmilter_headers(task)
         to_remove[k] = v
       end
       for k, v in pairs(common) do
-        common_meta[k] = v
+        if type(v) == 'table' then
+          for sk, sv in pairs(v) do
+            common_meta[k][sk] = sv
+          end
+        else
+          common_meta[k] = v
+        end
       end
     end
   end