diff options
-rw-r--r-- | conf/modules.conf | 2 | ||||
-rw-r--r-- | doc/markdown/modules/rbl.md | 10 | ||||
-rw-r--r-- | src/lua/lua_config.c | 57 | ||||
-rw-r--r-- | src/plugins/lua/rbl.lua | 60 |
4 files changed, 90 insertions, 39 deletions
diff --git a/conf/modules.conf b/conf/modules.conf index 2f291de79..1a4185c97 100644 --- a/conf/modules.conf +++ b/conf/modules.conf @@ -89,6 +89,8 @@ rbl { default_exclude_users = true; default_exclude_private_ips = true; + private_ips = "127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 169.254.0.0/16 172.16.0.0/12 100.64.0.0/10 fc00::/7 fe80::/10 fec0::/10 ::1"; + rbls { spamhaus { diff --git a/doc/markdown/modules/rbl.md b/doc/markdown/modules/rbl.md index 8748f4617..bff67e31d 100644 --- a/doc/markdown/modules/rbl.md +++ b/doc/markdown/modules/rbl.md @@ -55,7 +55,11 @@ If set to true, do not use this RBL if the message sender is authenticated. - default_exclude_private_ips (false) -If set to true, from/received RBL checks will ignore private IP address space. +If true & private_ips is set appropriately, from/received RBL checks will ignore private IP address space. + +- default_exclude_local (true) + +If true, and local_exclude_ip_map has been set - exclude specified addresses/subnets from received/from RBL checks. Other parameters which can be set here are: @@ -63,6 +67,10 @@ Other parameters which can be set here are: Can be set to a URL of a list of IPv4/IPv6 addresses & subnets not to be processed by from/received RBL checks. +- private_ips + +Should be set to a space/comma/semicolon-delimited list of addresses & subnets to be considered private by exclude_private_ips checks. + RBL-specific subsection is structured as follows: ~~~nginx diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index 089a4b1bd..4fdf4a236 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -109,6 +109,24 @@ end */ LUA_FUNCTION_DEF (config, add_radix_map); /*** + * @method rspamd_config:radix_from_config(mname, optname) + * Creates new static map of IP/mask addresses from config. + * @param {string} mname name of module + * @param {string} optname option to get + * @return {radix} radix tree object + * @example +local ip_map = rspamd_config:radix_from_config ('mymodule', 'ips') +... +local function foo(task) + local ip = task:get_from_ip() + if ip_map:get_key(ip) then + return true + end + return false +end + */ +LUA_FUNCTION_DEF (config, radix_from_config); +/*** * @method rspamd_config:add_hash_map(mapline[, description]) * Creates new dynamic map string objects. * @param {string} mapline URL for a map @@ -298,6 +316,7 @@ static const struct luaL_reg configlib_m[] = { LUA_INTERFACE_DEF (config, get_all_opt), LUA_INTERFACE_DEF (config, register_function), LUA_INTERFACE_DEF (config, add_radix_map), + LUA_INTERFACE_DEF (config, radix_from_config), LUA_INTERFACE_DEF (config, add_hash_map), LUA_INTERFACE_DEF (config, add_kv_map), LUA_INTERFACE_DEF (config, add_map), @@ -755,6 +774,44 @@ lua_config_add_radix_map (lua_State *L) } static gint +lua_config_radix_from_config (lua_State *L) +{ + struct rspamd_config *cfg = lua_check_config (L); + const gchar *mname, *optname; + const ucl_object_t *obj; + radix_compressed_t **r, ***ud; + + if (!cfg) { + lua_pushnil (L); + return 1; + } + + mname = luaL_checkstring (L, 2); + optname = luaL_checkstring (L, 3); + + if (mname && optname) { + obj = rspamd_config_get_module_opt (cfg, mname, optname); + if (obj) { + r = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (radix_compressed_t *)); + *r = radix_create_compressed (); + radix_add_generic_iplist (ucl_obj_tostring (obj), r); + ud = lua_newuserdata (L, sizeof (radix_compressed_t *)); + *ud = r; + rspamd_lua_setclass (L, "rspamd{radix}", -1); + return 1; + } else { + msg_warn ("Couldnt find config option [%s][%s]", mname, optname); + lua_pushnil (L); + return 1; + } + } else { + msg_warn ("Couldnt find config option"); + lua_pushnil (L); + return 1; + } +} + +static gint lua_config_add_hash_map (lua_State *L) { struct rspamd_config *cfg = lua_check_config (L); diff --git a/src/plugins/lua/rbl.lua b/src/plugins/lua/rbl.lua index 6fa7d25cc..82955f13c 100644 --- a/src/plugins/lua/rbl.lua +++ b/src/plugins/lua/rbl.lua @@ -31,6 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. local rbls = {} local local_exclusions = nil +local private_ips = nil local rspamd_logger = require "rspamd_logger" local rspamd_ip = require "rspamd_ip" @@ -48,39 +49,9 @@ local function validate_dns(lstr, rstr) return true end -local private_ranges_v4 = { - {[1] = rspamd_ip.from_string("127.0.0.0"), [2] = 8}, - {[1] = rspamd_ip.from_string("10.0.0.0"), [2] = 8}, - {[1] = rspamd_ip.from_string("192.168.0.0"), [2] = 16}, - {[1] = rspamd_ip.from_string("169.254.0.0"), [2] = 16}, - {[1] = rspamd_ip.from_string("172.16.0.0"), [2] = 12}, - {[1] = rspamd_ip.from_string("100.64.0.0"), [2] = 10}, -} - -local private_ranges_v6 = { - {[1] = rspamd_ip.from_string("fc00::"), [2] = 7}, - {[1] = rspamd_ip.from_string("fe80::"), [2] = 10}, - {[1] = rspamd_ip.from_string("fec0::"), [2] = 10}, -} - -local ipv6_loopback = rspamd_ip.from_string("::1") - local function is_private_ip(rip) - if rip:get_version() == 4 then - for _, r in pairs(private_ranges_v4) do - if r[1] == rip:apply_mask(r[2]) then - return true - end - end - elseif rip:get_version() == 6 then - if rip == ipv6_loopback then - return true - end - for _, r in pairs(private_ranges_v6) do - if r[1] == rip:apply_mask(r[2]) then - return true - end - end + if private_ips and private_ips:get_key(rip) then + return true end return false end @@ -207,13 +178,15 @@ local function rbl_cb (task) end if not havegot['from'] then havegot['from'] = task:get_from_ip() - if not havegot['from']:is_valid() or - (rbl['exclude_private_ips'] and is_private_ip(havegot['from'])) - or is_excluded_ip(havegot['from']) then + if not havegot['from']:is_valid() then notgot['from'] = true return end end + if (rbl['exclude_private_ips'] and is_private_ip(havegot['from'])) + or (is_excluded_ip(havegot['from']) and rbl['exclude_local']) then + return + end if (havegot['from']:get_version() == 6 and rbl['ipv6']) or (havegot['from']:get_version() == 4 and rbl['ipv4']) then task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), @@ -239,7 +212,8 @@ local function rbl_cb (task) if ((rh['real_ip']:get_version() == 6 and rbl['ipv6']) or (rh['real_ip']:get_version() == 4 and rbl['ipv4'])) and ((rbl['exclude_private_ips'] and not is_private_ip(rh['real_ip'])) or - not rbl['exclude_private_ips']) and not is_excluded_ip(rh['real_ip']) then + not rbl['exclude_private_ips']) and ((rbl['exclude_local_ips'] and + not is_excluded_ip(rh['real_ip'])) or not rbl['exclude_local_ips']) then task:get_resolver():resolve_a(task:get_session(), task:get_mempool(), ip_to_rbl(rh['real_ip'], rbl['rbl']), rbl_dns_cb, k) end @@ -265,6 +239,8 @@ if type(rspamd_config.get_api_version) ~= 'nil' then rspamd_config:register_module_option('rbl', 'default_exclude_users', 'string') rspamd_config:register_module_option('rbl', 'default_exclude_private_ips', 'string') rspamd_config:register_module_option('rbl', 'local_exclude_ip_map', 'string') + rspamd_config:register_module_option('rbl', 'default_exclude_local', 'string') + rspamd_config:register_module_option('rbl', 'private_ips', 'string') end end @@ -300,13 +276,21 @@ end if(opts['default_exclude_private_ips'] == nil) then opts['default_exclude_private_ips'] = false end - +if(opts['default_exclude_local'] == nil) then + opts['default_exclude_local'] = true +end if(opts['local_exclude_ip_map'] ~= nil) then local_exclusions = rspamd_config:add_radix_map(opts['local_exclude_ip_map']) end +if(opts['private_ips'] ~= nil) then + private_ips = rspamd_config:radix_from_config('rbl', 'private_ips') +end for key,rbl in pairs(opts['rbls']) do - local o = { "ipv4", "ipv6", "from", "received", "unknown", "rdns", "helo", "exclude_users", "exclude_private_ips" } + local o = { + "ipv4", "ipv6", "from", "received", "unknown", "rdns", "helo", "exclude_users", + "exclude_private_ips", "exclude_local" + } for i=1,table.maxn(o) do if(rbl[o[i]] == nil) then rbl[o[i]] = opts['default_' .. o[i]] |