From 392e2946371f5cf4f3f76fbaa11dd8c00515b967 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sun, 28 May 2017 15:24:52 +0100 Subject: [PATCH] [Rework] Move common DKIM functions to a separate lua module --- lualib/dkim_sign_tools.lua | 175 +++++++++++++++++++++++++++++++ src/plugins/lua/arc.lua | 146 +------------------------- src/plugins/lua/dkim_signing.lua | 127 +--------------------- 3 files changed, 183 insertions(+), 265 deletions(-) create mode 100644 lualib/dkim_sign_tools.lua diff --git a/lualib/dkim_sign_tools.lua b/lualib/dkim_sign_tools.lua new file mode 100644 index 000000000..e19d96ce3 --- /dev/null +++ b/lualib/dkim_sign_tools.lua @@ -0,0 +1,175 @@ +--[[ +Copyright (c) 2016, Andrew Lewis +Copyright (c) 2017, Vsevolod Stakhov + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +]]-- + +local exports = {} + +local rspamd_logger = require "rspamd_logger" +local rspamd_util = require "rspamd_util" + +local function prepare_dkim_signing(N, task, settings) + local is_local, is_sign_networks + local auser = task:get_user() + local ip = task:get_from_ip() + + if ip and ip:is_local() then + is_local = true + end + + if settings.auth_only and not auser then + if (settings.sign_networks and settings.sign_networks:get_key(ip)) then + is_sign_networks = true + rspamd_logger.debugm(N, task, 'mail is from address in sign_networks') + elseif settings.sign_local and is_local then + rspamd_logger.debugm(N, task, 'mail is from local address') + else + rspamd_logger.debugm(N, task, 'ignoring unauthenticated mail') + return false,{} + end + end + + local efrom = task:get_from('smtp') + if not settings.allow_envfrom_empty and + #(((efrom or E)[1] or E).addr or '') == 0 then + rspamd_logger.debugm(N, task, 'empty envelope from not allowed') + return false,{} + end + + local hfrom = task:get_from('mime') + if not settings.allow_hdrfrom_multiple and (hfrom or E)[2] then + rspamd_logger.debugm(N, task, 'multiple header from not allowed') + return false,{} + end + + local dkim_domain + local hdom = ((hfrom or E)[1] or E).domain + local edom = ((efrom or E)[1] or E).domain + local udom = string.match(auser or '', '.*@(.*)') + + local function get_dkim_domain(type) + if settings[type] == 'header' then + return hdom + elseif settings[type] == 'envelope' then + return edom + elseif settings[type] == 'auth' then + return udom + end + end + + if hdom then + hdom = hdom:lower() + end + if edom then + edom = edom:lower() + end + if udom then + udom = udom:lower() + end + + if settings.use_domain_sign_networks and is_sign_networks then + dkim_domain = get_dkim_domain('use_domain_sign_networks') + elseif settings.use_domain_local and is_local then + dkim_domain = get_dkim_domain('use_domain_local') + else + dkim_domain = get_dkim_domain('use_domain') + end + + if not dkim_domain then + rspamd_logger.debugm(N, task, 'could not extract dkim domain') + return false,{} + else + rspamd_logger.debugm(N, task, 'use domain(%s) for sugnature: %s', + settings.use_domain, dkim_domain) + end + + if settings.use_esld then + dkim_domain = rspamd_util.get_tld(dkim_domain) + + if settings.use_domain == 'envelope' and hdom then + hdom = rspamd_util.get_tld(hdom) + elseif settings.use_domain == 'header' and edom then + edom = rspamd_util.get_tld(edom) + end + end + if edom and hdom and not settings.allow_hdrfrom_mismatch and hdom ~= edom then + if settings.allow_hdrfrom_mismatch_local and is_local then + rspamd_logger.debugm(N, task, 'domain mismatch allowed for local IP: %1 != %2', hdom, edom) + elseif settings.allow_hdrfrom_mismatch_sign_networks and is_sign_networks then + rspamd_logger.debugm(N, task, 'domain mismatch allowed for sign_networks: %1 != %2', hdom, edom) + else + rspamd_logger.debugm(N, task, 'domain mismatch not allowed: %1 != %2', hdom, edom) + return false,{} + end + end + + if auser and not settings.allow_username_mismatch then + if not udom then + rspamd_logger.debugm(N, task, 'couldnt find domain in username') + return false,{} + end + if settings.use_esld then + udom = rspamd_util.get_tld(udom) + end + if udom ~= dkim_domain then + rspamd_logger.debugm(N, task, 'user domain mismatch') + return false,{} + end + end + + local p = {} + + if settings.domain[dkim_domain] then + p.selector = settings.domain[dkim_domain].selector + p.key = settings.domain[dkim_domain].path + end + + if not (p.key and p.selector) and not + (settings.try_fallback or settings.use_redis or settings.selector_map or settings.path_map) then + rspamd_logger.debugm(N, task, 'dkim unconfigured and fallback disabled') + return false,{} + end + + if not p.key then + if not settings.use_redis then + p.key = settings.path + end + end + + if not p.selector then + p.selector = settings.selector + end + p.domain = dkim_domain + + if settings.selector_map then + local data = settings.selector_map:get_key(dkim_domain) + if data then + p.selector = data + end + end + + if settings.path_map then + local data = settings.path_map:get_key(dkim_domain) + if data then + p.key = data + end + end + + return true,p +end + +exports.prepare_dkim_signing = prepare_dkim_signing + +return exports \ No newline at end of file diff --git a/src/plugins/lua/arc.lua b/src/plugins/lua/arc.lua index f6569680f..e18f0001c 100644 --- a/src/plugins/lua/arc.lua +++ b/src/plugins/lua/arc.lua @@ -16,6 +16,7 @@ limitations under the License. local rspamd_logger = require "rspamd_logger" local lua_util = require "lua_util" +local dkim_sign_tools = require "dkim_sign_tools" local rspamd_util = require "rspamd_util" local rspamd_rsa_privkey = require "rspamd_rsa_privkey" local rspamd_rsa = require "rspamd_rsa" @@ -418,150 +419,11 @@ end local function arc_signing_cb(task) local arc_sigs = task:cache_get('arc-sigs') local arc_seals = task:cache_get('arc-seals') - local is_local, is_sign_networks - local auser = task:get_user() - local ip = task:get_from_ip() - if ip and ip:is_local() then - is_local = true - end - - if settings.auth_only and not auser then - if (settings.sign_networks and settings.sign_networks:get_key(ip)) then - is_sign_networks = true - rspamd_logger.debugm(N, task, 'mail is from address in sign_networks') - elseif settings.sign_local and is_local then - rspamd_logger.debugm(N, task, 'mail is from local address') - else - rspamd_logger.debugm(N, task, 'ignoring unauthenticated mail') - return - end - end - - local efrom = task:get_from('smtp') - if not settings.allow_envfrom_empty and - #(((efrom or E)[1] or E).addr or '') == 0 then - rspamd_logger.debugm(N, task, 'empty envelope from not allowed') - return false - end - - local hfrom = task:get_from('mime') - if not settings.allow_hdrfrom_multiple and (hfrom or E)[2] then - rspamd_logger.debugm(N, task, 'multiple header from not allowed') - return false - end - - local dkim_domain - local hdom = ((hfrom or E)[1] or E).domain - local edom = ((efrom or E)[1] or E).domain - local udom = string.match(auser or '', '.*@(.*)') - - local function get_dkim_domain(type) - if settings[type] == 'header' then - return hdom - elseif settings[type] == 'envelope' then - return edom - elseif settings[type] == 'auth' then - return udom - end - end - - if hdom then - hdom = hdom:lower() - end - if edom then - edom = edom:lower() - end - if udom then - udom = udom:lower() - end - - if settings.use_domain_sign_networks and is_sign_networks then - dkim_domain = get_dkim_domain('use_domain_sign_networks') - elseif settings.use_domain_local and is_local then - dkim_domain = get_dkim_domain('use_domain_local') - else - dkim_domain = get_dkim_domain('use_domain') - end - - if not dkim_domain then - rspamd_logger.debugm(N, task, 'could not extract dkim domain') - return false - else - rspamd_logger.debugm(N, task, 'use domain(%s) for sugnature: %s', - settings.use_domain, dkim_domain) - end - - if settings.use_esld then - dkim_domain = rspamd_util.get_tld(dkim_domain) - - if settings.use_domain == 'envelope' and hdom then - hdom = rspamd_util.get_tld(hdom) - elseif settings.use_domain == 'header' and edom then - edom = rspamd_util.get_tld(edom) - end - end - if edom and hdom and not settings.allow_hdrfrom_mismatch and hdom ~= edom then - if settings.allow_hdrfrom_mismatch_local and is_local then - rspamd_logger.debugm(N, task, 'domain mismatch allowed for local IP: %1 != %2', hdom, edom) - elseif settings.allow_hdrfrom_mismatch_sign_networks and is_sign_networks then - rspamd_logger.debugm(N, task, 'domain mismatch allowed for sign_networks: %1 != %2', hdom, edom) - else - rspamd_logger.debugm(N, task, 'domain mismatch not allowed: %1 != %2', hdom, edom) - return false - end - end - - if auser and not settings.allow_username_mismatch then - if not udom then - rspamd_logger.debugm(N, task, 'couldnt find domain in username') - return false - end - if settings.use_esld then - udom = rspamd_util.get_tld(udom) - end - if udom ~= dkim_domain then - rspamd_logger.debugm(N, task, 'user domain mismatch') - return false - end - end - - local p = {} - - if settings.domain[dkim_domain] then - p.selector = settings.domain[dkim_domain].selector - p.key = settings.domain[dkim_domain].path - end - - if not (p.key and p.selector) and not - (settings.try_fallback or settings.use_redis or settings.selector_map or settings.path_map) then - rspamd_logger.debugm(N, task, 'dkim unconfigured and fallback disabled') - return false - end + local ret,p = dkim_sign_tools.prepare_dkim_signing(N, task, settings) - if not p.key then - if not settings.use_redis then - p.key = settings.path - end - end - - if not p.selector then - p.selector = settings.selector - end - p.domain = dkim_domain - - if settings.selector_map then - local data = settings.selector_map:get_key(dkim_domain) - if data then - p.selector = data - end - end - - if settings.path_map then - local data = settings.path_map:get_key(dkim_domain) - if data then - p.key = data - end + if not ret then + return end p.arc_cv = 'none' diff --git a/src/plugins/lua/dkim_signing.lua b/src/plugins/lua/dkim_signing.lua index 7cd152ba3..ab6cf059e 100644 --- a/src/plugins/lua/dkim_signing.lua +++ b/src/plugins/lua/dkim_signing.lua @@ -16,7 +16,7 @@ limitations under the License. ]]-- local rspamd_logger = require "rspamd_logger" -local rspamd_util = require "rspamd_util" +local dkim_sign_tools = require "dkim_sign_tools" if confighelp then return @@ -60,129 +60,10 @@ local function simple_template(tmpl, keys) end local function dkim_signing_cb(task) - local is_local, is_sign_networks - local auser = task:get_user() - local ip = task:get_from_ip() - if ip and ip:is_local() then - is_local = true - end - if settings.auth_only and not auser then - if (settings.sign_networks and settings.sign_networks:get_key(ip)) then - is_sign_networks = true - rspamd_logger.debugm(N, task, 'mail is from address in sign_networks') - elseif settings.sign_local and is_local then - rspamd_logger.debugm(N, task, 'mail is from local address') - else - rspamd_logger.debugm(N, task, 'ignoring unauthenticated mail') - return - end - end - local efrom = task:get_from('smtp') - if not settings.allow_envfrom_empty and - #(((efrom or E)[1] or E).addr or '') == 0 then - rspamd_logger.debugm(N, task, 'empty envelope from not allowed') - return false - end - local hfrom = task:get_from('mime') - if not settings.allow_hdrfrom_multiple and (hfrom or E)[2] then - rspamd_logger.debugm(N, task, 'multiple header from not allowed') - return false - end - local dkim_domain - local hdom = ((hfrom or E)[1] or E).domain - local edom = ((efrom or E)[1] or E).domain - if hdom then - hdom = hdom:lower() - end - if edom then - edom = edom:lower() - end - if settings.use_domain_sign_networks and is_sign_networks then - if settings.use_domain_sign_networks == 'header' then - dkim_domain = hdom - else - dkim_domain = edom - end - elseif settings.use_domain_local and is_local then - if settings.use_domain_local == 'header' then - dkim_domain = hdom - else - dkim_domain = edom - end - else - if settings.use_domain == 'header' then - dkim_domain = hdom - else - dkim_domain = edom - end - end - if not dkim_domain then - rspamd_logger.debugm(N, task, 'could not extract dkim domain') - return false - end - if settings.use_esld then - dkim_domain = rspamd_util.get_tld(dkim_domain) - if settings.use_domain == 'envelope' and hdom then - hdom = rspamd_util.get_tld(hdom) - elseif settings.use_domain == 'header' and edom then - edom = rspamd_util.get_tld(edom) - end - end - if edom and hdom and not settings.allow_hdrfrom_mismatch and hdom ~= edom then - if settings.allow_hdrfrom_mismatch_local and is_local then - rspamd_logger.debugm(N, task, 'domain mismatch allowed for local IP: %1 != %2', hdom, edom) - elseif settings.allow_hdrfrom_mismatch_sign_networks and is_sign_networks then - rspamd_logger.debugm(N, task, 'domain mismatch allowed for sign_networks: %1 != %2', hdom, edom) - else - rspamd_logger.debugm(N, task, 'domain mismatch not allowed: %1 != %2', hdom, edom) - return false - end - end - if auser and not settings.allow_username_mismatch then - local udom = string.match(auser, '.*@(.*)') - if not udom then - rspamd_logger.debugm(N, task, 'couldnt find domain in username') - return false - end - if settings.use_esld then - udom = rspamd_util.get_tld(udom) - end - if udom ~= dkim_domain then - rspamd_logger.debugm(N, task, 'user domain mismatch') - return false - end - end - local p = {} - if settings.domain[dkim_domain] then - p.selector = settings.domain[dkim_domain].selector - p.key = settings.domain[dkim_domain].path - end - if not (p.key and p.selector) and not - (settings.try_fallback or settings.use_redis or settings.selector_map or settings.path_map) then - rspamd_logger.debugm(N, task, 'dkim unconfigured and fallback disabled') - return false - end - if not p.key then - if not settings.use_redis then - p.key = settings.path - end - end - if not p.selector then - p.selector = settings.selector - end - p.domain = dkim_domain + local ret,p = dkim_sign_tools.prepare_dkim_signing(N, task, settings) - if settings.selector_map then - local data = settings.selector_map:get_key(dkim_domain) - if data then - p.selector = data - end - end - if settings.path_map then - local data = settings.path_map:get_key(dkim_domain) - if data then - p.key = data - end + if not ret then + return end if settings.use_redis then -- 2.39.5