]> source.dussan.org Git - rspamd.git/commitdiff
Add initial version of the whitelist plugin.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 14 Sep 2015 21:12:04 +0000 (22:12 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 14 Sep 2015 21:12:04 +0000 (22:12 +0100)
src/plugins/lua/whitelist.lua [new file with mode: 0644]

diff --git a/src/plugins/lua/whitelist.lua b/src/plugins/lua/whitelist.lua
new file mode 100644 (file)
index 0000000..f28e800
--- /dev/null
@@ -0,0 +1,153 @@
+--[[
+Copyright (c) 2015, Vsevolod Stakhov <vsevolod@highsecure.ru>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+]]--
+
+local rspamd_logger = require "rspamd_logger"
+local ucl = require "ucl"
+require "fun" ()
+
+local options = {
+  dmarc_allow_symbol = 'DMARC_POLICY_ALLOW',
+  spf_allow_symbol = 'R_SPF_ALLOW',
+  dkim_allow_symbol = 'R_DKIM_ALLOW',
+
+  rules = {}
+}
+
+local function whitelist_cb(symbol, rule, task)
+  local from = task:get_from(1)
+  if from and from[1] and from[1]['domain'] then
+    local domain = from[1]['domain']
+    local found = false
+
+    if rule['map'] then
+      if rule['map']:get_key(domain) then
+        found = true
+      end
+    else
+      if rule['domains'][domain] then
+        found = true
+      end
+    end
+
+    if found then
+      if rule['valid_spf'] then
+        -- Check for spf symbol
+        if not task:get_symbol(options['spf_allow_symbol']) then
+          found = false
+          rspamd_logger.debugx(task, "domain %s has been found in whitelist %s" ..
+            "but it doesn't have valid SPF record", domain, symbol)
+        end
+      end
+      if rule['valid_dkim'] then
+        if not task:get_symbol(options['dkim_allow_symbol']) then
+          found = false
+          rspamd_logger.debugx(task, "domain %s has been found in whitelist %s" ..
+              "but it doesn't have valid DKIM", domain, symbol)
+        end
+      end
+      if rule['valid_dmarc'] then
+        if not task:get_symbol(options['dmarc_allow_symbol']) then
+          found = false
+          rspamd_logger.debugx(task, "domain %s has been found in whitelist %s" ..
+              "but it doesn't have valid DMARC", domain, symbol)
+        end
+      end
+    end
+
+    if found then
+      task:insert_result(symbol, 1.0, domain)
+    end
+  end
+
+end
+
+local function gen_whitelist_cb(symbol, rule)
+  return function(task)
+    whitelist_cb(symbol, rule, task)
+  end
+end
+
+local function process_whitelist_map(input)
+  local parser = ucl.parser()
+  local res,err = parser:parse_string(string)
+  if not res then
+    rspamd_logger.warnx(rspamd_config, 'cannot parse settings map: ' .. err)
+  else
+    local obj = parser:get_object()
+
+    options['rules'] = obj
+  end
+end
+
+local configure_whitelist_module = function()
+  local opts =  rspamd_config:get_all_opt('whitelist')
+  if opts then
+    for k,v in pairs(opts) do
+      options[k] = v
+    end
+  end
+
+  if options['rules'] then
+    each(function(symbol, rule)
+      if rule['domains'] then
+        if type(rule['domains']) == 'string' then
+          rule['map'] = rspamd_config:add_hash_map(rule['domains'])
+        elseif type(rule['domains']) == 'table' then
+          -- Transform ['domain1', 'domain2' ...] to indexes:
+          -- {'domain1' = 1, 'domain2' = 1 ...]
+          rule['domains'] = tomap(zip(rule['domains'], ones()))
+        else
+          rspamd_logger.errx(rspamd_config, 'whitelist %s has bad "domains" value',
+            symbol)
+          return
+        end
+
+        local id = rspamd_config:register_symbol(symbol, -1.0,
+          gen_whitelist_cb(symbol, rule))
+
+        if rule['valid_spf'] then
+          rspamd_config:register_dependency(id, options['spf_allow_symbol'])
+        end
+        if rule['valid_dkim'] then
+          rspamd_config:register_dependency(id, options['dkim_allow_symbol'])
+        end
+        if rule['valid_dmarc'] then
+          rspamd_config:register_dependency(id, options['dmarc_allow_symbol'])
+        end
+
+        if rule['score'] then
+          if not rule['group'] then
+            rule['group'] = 'whitelist'
+          end
+          rule['name'] = symbol
+          rspamd_config:set_metric_symbol(rule)
+        end
+      end
+    end, options['rules'])
+  end
+end
+
+configure_whitelist_module()
\ No newline at end of file