]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Rework IP processing/checking in settings
authorDmitry Petrov <dpetrov67@gmail.com>
Tue, 4 Mar 2025 18:12:21 +0000 (13:12 -0500)
committerDmitry Petrov <dpetrov67@gmail.com>
Tue, 4 Mar 2025 18:12:21 +0000 (13:12 -0500)
 * Avoid misleading "cannot parse ip" logging by checking for "map:" prefix early
 * Do not use tables for maps or IPs without mask
 * Normalize IPs by applying mask during processing
 * Add error logging for wrong IP mask
 * Simplify check_ip_settings() based on changes in process_ip_condition()

src/plugins/lua/settings.lua

index 69d31d30179603b96fb38dd99cdec0d7124cdd5b..2c9d5b2f987133ae36cb0410fa39d6244b6caccf 100644 (file)
@@ -248,17 +248,13 @@ local function check_string_setting(expected, str)
 end
 
 local function check_ip_setting(expected, ip)
-  if not expected[2] then
-    if lua_maps.rspamd_maybe_check_map(expected[1], ip:to_string()) then
+  if type(expected) == "string" then
+    if lua_maps.rspamd_maybe_check_map(expected, ip:to_string()) then
       return true
     end
   else
-    if expected[2] ~= 0 then
-      local nip = ip:apply_mask(expected[2])
-      if nip and nip:to_string() == expected[1] then
-        return true
-      end
-    elseif ip:to_string() == expected[1] then
+    local nip = ip:apply_mask(expected[2])
+    if nip and nip:to_string() == expected[1] then
       return true
     end
   end
@@ -465,43 +461,48 @@ end
 
 -- Process IP address: converted to a table {ip, mask}
 local function process_ip_condition(ip)
-  local out = {}
-
   if type(ip) == "table" then
+    local out = {}
     for _, v in ipairs(ip) do
+      -- should we check/abort on nil here?
       table.insert(out, process_ip_condition(v))
     end
-  elseif type(ip) == "string" then
-    local slash = string.find(ip, '/')
-
-    if not slash then
-      -- Just a plain IP address
-      local res = rspamd_ip.from_string(ip)
+    return out
+  end
 
-      if res:is_valid() then
-        out[1] = res:to_string()
-        out[2] = 0
-      else
-        -- It can still be a map
-        out[1] = ip
-      end
-    else
-      local res = rspamd_ip.from_string(string.sub(ip, 1, slash - 1))
-      local mask = tonumber(string.sub(ip, slash + 1))
+  if type(ip) == "string" then
+    if string.sub(ip, 1, 4) == "map:" then
+      -- It is a map, don't apply any extra logic
+      return ip
+    end
 
-      if res:is_valid() then
-        out[1] = res:to_string()
-        out[2] = mask
-      else
-        rspamd_logger.errx(rspamd_config, "bad IP address: " .. ip)
+    local mask
+    local slash = string.find(ip, '/')
+    if slash then
+      mask = string.sub(ip, slash + 1)
+      ip = string.sub(ip, 1, slash - 1)
+    end
+
+    local res = rspamd_ip.from_string(ip)
+    if res:is_valid() then
+      if mask then
+        local mask_num = tonumber(mask)
+        if mask_num then
+          -- normalize IP
+          res = res:apply_mask(mask_num)
+          if res then
+            return { res:to_string(), mask_num }
+          end 
+        end
+        rspamd_logger.errx(rspamd_config, "bad IP mask: " .. mask)
         return nil
       end
+      return ip
     end
-  else
-    return nil
   end
 
-  return out
+  rspamd_logger.errx(rspamd_config, "bad IP address: " .. ip)
+  return nil
 end
 
 -- Process email like condition, converted to a table with fields: