commit 3541f5d: [Project] Rbl: Move config code outside of the plugin

Vsevolod Stakhov vsevolod at highsecure.ru
Tue Oct 20 14:49:07 UTC 2020


Author: Vsevolod Stakhov
Date: 2020-10-20 13:44:49 +0100
URL: https://github.com/rspamd/rspamd/commit/3541f5d1fcde67b9ece721cb0b9474ed8c692754

[Project] Rbl: Move config code outside of the plugin

---
 lualib/plugins/rbl.lua  | 175 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/plugins/lua/rbl.lua | 115 +++++--------------------------
 2 files changed, 190 insertions(+), 100 deletions(-)

diff --git a/lualib/plugins/rbl.lua b/lualib/plugins/rbl.lua
new file mode 100644
index 000000000..12c795e00
--- /dev/null
+++ b/lualib/plugins/rbl.lua
@@ -0,0 +1,175 @@
+--[[
+Copyright (c) 2020, Vsevolod Stakhov <vsevolod at highsecure.ru>
+
+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 ts = require("tableshape").types
+local lua_maps = require "lua_maps"
+local lua_util = require "lua_util"
+
+-- Common RBL plugin definitions
+
+local check_types = {
+    from = {
+      connfilter = true,
+    },
+    received = {},
+    helo = {
+      connfilter = true,
+    },
+    urls = {},
+    content_urls = {},
+    emails = {},
+    replyto = {},
+    dkim = {},
+    rdns = {
+      connfilter = true,
+    },
+    selector = {
+      require_argument = true,
+    },
+}
+
+local default_options = {
+  ['default_enabled'] = true,
+  ['default_ipv4'] = true,
+  ['default_ipv6'] = true,
+  ['default_unknown'] = false,
+  ['default_dkim_domainonly'] = true,
+  ['default_emails_domainonly'] = false,
+  ['default_exclude_private_ips'] = true,
+  ['default_exclude_users'] = false,
+  ['default_exclude_local'] = true,
+  ['default_no_ip'] = false,
+  ['default_dkim_match_from'] = false,
+}
+
+local return_codes_schema = ts.map_of(
+    ts.string / string.upper, -- Symbol name
+    (
+        ts.array_of(ts.string) +
+            (ts.string / function(s)
+              return { s }
+            end) -- List of IP patterns
+    )
+)
+local return_bits_schema = ts.map_of(
+    ts.string / string.upper, -- Symbol name
+    (
+        ts.array_of(ts.number + ts.string / tonumber) +
+            (ts.string / function(s)
+              return { tonumber(s) }
+            end) +
+            (ts.number / function(s)
+              return { s }
+            end)
+    )
+)
+
+local rule_schema_tbl = {
+  content_urls = ts.boolean:is_optional(),
+  disable_monitoring = ts.boolean:is_optional(),
+  disabled = ts.boolean:is_optional(),
+  dkim = ts.boolean:is_optional(),
+  dkim_domainonly = ts.boolean:is_optional(),
+  dkim_match_from = ts.boolean:is_optional(),
+  emails = ts.boolean:is_optional(),
+  emails_delimiter = ts.string:is_optional(),
+  emails_domainonly = ts.boolean:is_optional(),
+  enabled = ts.boolean:is_optional(),
+  exclude_local = ts.boolean:is_optional(),
+  exclude_private_ips = ts.boolean:is_optional(),
+  exclude_users = ts.boolean:is_optional(),
+  from = ts.boolean:is_optional(),
+  hash = ts.one_of{"sha1", "sha256", "sha384", "sha512", "md5", "blake2"}:is_optional(),
+  hash_format = ts.one_of{"hex", "base32", "base64"}:is_optional(),
+  hash_len = (ts.integer + ts.string / tonumber):is_optional(),
+  helo = ts.boolean:is_optional(),
+  ignore_default = ts.boolean:is_optional(), -- alias
+  ignore_defaults = ts.boolean:is_optional(),
+  ignore_whitelist = ts.boolean:is_optional(),
+  ignore_whitelists = ts.boolean:is_optional(), -- alias
+  images = ts.boolean:is_optional(),
+  ipv4 = ts.boolean:is_optional(),
+  ipv6 = ts.boolean:is_optional(),
+  is_whitelist = ts.boolean:is_optional(),
+  local_exclude_ip_map = ts.string:is_optional(),
+  monitored_address = ts.string:is_optional(),
+  no_ip = ts.boolean:is_optional(),
+  process_script = ts.string:is_optional(),
+  rbl = ts.string,
+  rdns = ts.boolean:is_optional(),
+  received = ts.boolean:is_optional(),
+  replyto = ts.boolean:is_optional(),
+  requests_limit = (ts.integer + ts.string / tonumber):is_optional(),
+  resolve_ip = ts.boolean:is_optional(),
+  return_bits = return_bits_schema:is_optional(),
+  return_codes = return_codes_schema:is_optional(),
+  returnbits = return_bits_schema:is_optional(),
+  returncodes = return_codes_schema:is_optional(),
+  selector = ts.one_of{ts.string, ts.table}:is_optional(),
+  symbol = ts.string:is_optional(),
+  symbols_prefixes = ts.map_of(ts.string, ts.string):is_optional(),
+  unknown = ts.boolean:is_optional(),
+  url_compose_map = lua_maps.map_schema:is_optional(),
+  urls = ts.boolean:is_optional(),
+  whitelist = lua_maps.map_schema:is_optional(),
+  whitelist_exception = (
+      ts.array_of(ts.string) + (ts.string / function(s) return {s} end)
+  ):is_optional(),
+  checks = ts.array_of(ts.one_of(lua_util.keys(check_types))):is_optional(),
+}
+
+local function convert_checks(rule)
+  local rspamd_logger = require "rspamd_logger"
+  if rule.checks then
+    local all_connfilter = true
+    for _,check in ipairs(rule.checks) do
+      local check_type = check_types[check]
+      if check_type.require_argument then
+        if not rule[check] then
+          rspamd_logger.errx(rspamd_config, 'rbl rule %s has check %s which requires an argument',
+              rule.symbol, check)
+          return nil
+        else
+          rule[check] = check_type
+        end
+      end
+      if not check_type.connfilter then
+        all_connfilter = false
+      end
+      if not check_type then
+        rspamd_logger.errx(rspamd_config, 'rbl rule %s has invalid check type: %s',
+            rule.symbol, check)
+        return nil
+      end
+    end
+    rule.connfilter = all_connfilter
+  end
+
+  return rule
+end
+
+
+-- Add default boolean flags to the schema
+for def_k,_ in pairs(default_options) do
+  rule_schema_tbl[def_k:sub(#('default_') + 1)] = ts.boolean:is_optional()
+end
+
+return {
+  check_types = check_types,
+  rule_schema = ts.shape(rule_schema_tbl),
+  default_options = default_options,
+  convert_checks = convert_checks,
+}
\ No newline at end of file
diff --git a/src/plugins/lua/rbl.lua b/src/plugins/lua/rbl.lua
index 8c96cff52..7828d74d1 100644
--- a/src/plugins/lua/rbl.lua
+++ b/src/plugins/lua/rbl.lua
@@ -1,5 +1,5 @@
 --[[
-Copyright (c) 2011-2015, Vsevolod Stakhov <vsevolod at highsecure.ru>
+Copyright (c) 2011-2020, Vsevolod Stakhov <vsevolod at highsecure.ru>
 Copyright (c) 2013-2015, Andrew Lewis <nerf at judo.za.org>
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,10 +24,10 @@ local rspamd_logger = require 'rspamd_logger'
 local rspamd_util = require 'rspamd_util'
 local fun = require 'fun'
 local lua_util = require 'lua_util'
-local ts = require("tableshape").types
 local selectors = require "lua_selectors"
 local bit = require 'bit'
 local lua_maps = require "lua_maps"
+local rbl_common = require "plugins/rbl"
 
 -- This plugin implements various types of RBL checks
 -- Documentation can be found here:
@@ -36,6 +36,7 @@ local lua_maps = require "lua_maps"
 local E = {}
 local N = 'rbl'
 
+-- Checks that could be performed by rbl module
 local local_exclusions
 local white_symbols = {}
 local black_symbols = {}
@@ -1114,108 +1115,15 @@ end
 
 -- Plugin defaults should not be changed - override these in config
 -- New defaults should not alter behaviour
-local default_options = {
-  ['default_enabled'] = true,
-  ['default_ipv4'] = true,
-  ['default_ipv6'] = true,
-  ['default_unknown'] = false,
-  ['default_dkim_domainonly'] = true,
-  ['default_emails_domainonly'] = false,
-  ['default_exclude_private_ips'] = true,
-  ['default_exclude_users'] = false,
-  ['default_exclude_local'] = true,
-  ['default_no_ip'] = false,
-  ['default_dkim_match_from'] = false,
-}
 
-opts = lua_util.override_defaults(default_options, opts)
+
+opts = lua_util.override_defaults(rbl_common.default_options, opts)
 
 if(opts['local_exclude_ip_map'] ~= nil) then
   local_exclusions = lua_maps.map_add(N, 'local_exclude_ip_map', 'radix',
     'RBL exclusions map')
 end
 
-local return_codes_schema = ts.map_of(
-    ts.string / string.upper, -- Symbol name
-    (
-        ts.array_of(ts.string) +
-            (ts.string / function(s)
-              return { s }
-            end) -- List of IP patterns
-    )
-)
-local return_bits_schema = ts.map_of(
-    ts.string / string.upper, -- Symbol name
-    (
-        ts.array_of(ts.number + ts.string / tonumber) +
-            (ts.string / function(s)
-              return { tonumber(s) }
-            end) +
-            (ts.number / function(s)
-              return { s }
-            end)
-    )
-)
-
-local rule_schema_tbl = {
-  content_urls = ts.boolean:is_optional(),
-  disable_monitoring = ts.boolean:is_optional(),
-  disabled = ts.boolean:is_optional(),
-  dkim = ts.boolean:is_optional(),
-  dkim_domainonly = ts.boolean:is_optional(),
-  dkim_match_from = ts.boolean:is_optional(),
-  emails = ts.boolean:is_optional(),
-  emails_delimiter = ts.string:is_optional(),
-  emails_domainonly = ts.boolean:is_optional(),
-  enabled = ts.boolean:is_optional(),
-  exclude_local = ts.boolean:is_optional(),
-  exclude_private_ips = ts.boolean:is_optional(),
-  exclude_users = ts.boolean:is_optional(),
-  from = ts.boolean:is_optional(),
-  hash = ts.one_of{"sha1", "sha256", "sha384", "sha512", "md5", "blake2"}:is_optional(),
-  hash_format = ts.one_of{"hex", "base32", "base64"}:is_optional(),
-  hash_len = (ts.integer + ts.string / tonumber):is_optional(),
-  helo = ts.boolean:is_optional(),
-  ignore_default = ts.boolean:is_optional(), -- alias
-  ignore_defaults = ts.boolean:is_optional(),
-  ignore_whitelist = ts.boolean:is_optional(),
-  ignore_whitelists = ts.boolean:is_optional(), -- alias
-  images = ts.boolean:is_optional(),
-  ipv4 = ts.boolean:is_optional(),
-  ipv6 = ts.boolean:is_optional(),
-  is_whitelist = ts.boolean:is_optional(),
-  local_exclude_ip_map = ts.string:is_optional(),
-  monitored_address = ts.string:is_optional(),
-  no_ip = ts.boolean:is_optional(),
-  process_script = ts.string:is_optional(),
-  rbl = ts.string,
-  rdns = ts.boolean:is_optional(),
-  received = ts.boolean:is_optional(),
-  replyto = ts.boolean:is_optional(),
-  requests_limit = (ts.integer + ts.string / tonumber):is_optional(),
-  resolve_ip = ts.boolean:is_optional(),
-  return_bits = return_bits_schema:is_optional(),
-  return_codes = return_codes_schema:is_optional(),
-  returnbits = return_bits_schema:is_optional(),
-  returncodes = return_codes_schema:is_optional(),
-  selector = ts.one_of{ts.string, ts.table}:is_optional(),
-  symbol = ts.string:is_optional(),
-  symbols_prefixes = ts.map_of(ts.string, ts.string):is_optional(),
-  unknown = ts.boolean:is_optional(),
-  url_compose_map = lua_maps.map_schema:is_optional(),
-  urls = ts.boolean:is_optional(),
-  whitelist = lua_maps.map_schema:is_optional(),
-  whitelist_exception = (
-      ts.array_of(ts.string) + (ts.string / function(s) return {s} end)
-  ):is_optional(),
-}
--- Add default boolean flags to the schema
-for def_k,_ in pairs(default_options) do
-  rule_schema_tbl[def_k:sub(#('default_') + 1)] = ts.boolean:is_optional()
-end
-
-local rule_schema = ts.shape(rule_schema_tbl)
-
 for key,rbl in pairs(opts.rbls or opts.rules) do
   if type(rbl) ~= 'table' or rbl.disabled == true or rbl.enabled == false then
     rspamd_logger.infox(rspamd_config, 'disable rbl "%s"', key)
@@ -1229,7 +1137,7 @@ for key,rbl in pairs(opts.rbls or opts.rules) do
     end
     -- Propagate default options from opts to rule
     if not rbl.ignore_defaults then
-      for default_opt_key,_ in pairs(default_options) do
+      for default_opt_key,_ in pairs(rbl_common.default_options) do
         local rbl_opt = default_opt_key:sub(#('default_') + 1)
         if rbl[rbl_opt] == nil then
           rbl[rbl_opt] = opts[default_opt_key]
@@ -1241,15 +1149,22 @@ for key,rbl in pairs(opts.rbls or opts.rules) do
       rbl.requests_limit = rspamd_config:get_dns_max_requests()
     end
 
-    local res,err = rule_schema:transform(rbl)
+    local res,err = rbl_common.rule_schema:transform(rbl)
     if not res then
       rspamd_logger.errx(rspamd_config, 'invalid config for %s: %s, RBL is DISABLED',
           key, err)
     else
+      res = rbl_common.convert_checks(res)
       -- Aliases
       if res.return_codes then res.returncodes = res.return_codes end
       if res.return_bits then res.returnbits = res.return_bits end
-      add_rbl(key, res, opts)
+
+      if not res then
+        rspamd_logger.errx(rspamd_config, 'invalid config for %s: %s, RBL is DISABLED',
+            key, err)
+      else
+        add_rbl(key, res, opts)
+      end
     end
   end -- rbl.enabled
 end


More information about the Commits mailing list