From: Vsevolod Stakhov Date: Mon, 14 Sep 2015 21:12:04 +0000 (+0100) Subject: Add initial version of the whitelist plugin. X-Git-Tag: 1.0.0~42 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e9a993987839de1f012419c8f4c1211a5fa21477;p=rspamd.git Add initial version of the whitelist plugin. --- diff --git a/src/plugins/lua/whitelist.lua b/src/plugins/lua/whitelist.lua new file mode 100644 index 000000000..f28e80018 --- /dev/null +++ b/src/plugins/lua/whitelist.lua @@ -0,0 +1,153 @@ +--[[ +Copyright (c) 2015, Vsevolod Stakhov +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