]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Replace builtin_suspicious TLDs with map-based configuration
authorVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 28 Jan 2026 08:56:28 +0000 (08:56 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 28 Jan 2026 08:56:28 +0000 (08:56 +0000)
Convert hardcoded suspicious TLDs list to a proper map file following
rspamd's standard map loading pattern with fallback support.

Changes:
- Add conf/maps.d/suspicious_tlds.inc with default TLDs (.tk, .ml, .ga, .cf, .gq)
- Update url_suspect.conf to use fallback+file:// pattern for user overrides
- Update url_suspect.lua to load TLDs via rspamd_map_add_from_ucl()

Users can now:
- Override entirely: create local.d/maps.d/suspicious_tlds.inc
- Extend defaults: create local.d/maps.d/suspicious_tlds.inc.local
- Disable: set suspicious_tlds_map = null in local.d/url_suspect.conf

Supersedes #5864 - the map-based approach inherently handles nil/missing
config gracefully, making the type check unnecessary.

conf/maps.d/suspicious_tlds.inc [new file with mode: 0644]
conf/modules.d/url_suspect.conf
src/plugins/lua/url_suspect.lua

diff --git a/conf/maps.d/suspicious_tlds.inc b/conf/maps.d/suspicious_tlds.inc
new file mode 100644 (file)
index 0000000..04126b6
--- /dev/null
@@ -0,0 +1,11 @@
+# Suspicious TLDs - used by url_suspect plugin
+# Format: one TLD per line (with or without leading dot)
+# Users can override this file in local.d/maps.d/ or use map_add_from_ucl syntax
+# to combine with additional TLDs
+
+# Known free/abused TLDs often used in phishing and spam
+.tk
+.ml
+.ga
+.cf
+.gq
index 721b551751c0e431d776c38ea81e60fe11b3532a..87d37ee58df1ddc1282b25f43c7f85a80dd5df9e 100644 (file)
@@ -51,12 +51,14 @@ url_suspect {
     tld {
       enabled = true;
 
-      # Built-in suspicious TLDs
-      builtin_suspicious = [".tk", ".ml", ".ga", ".cf", ".gq"];
-
-      # OPTIONAL: Custom TLD map
-      # To enable, add in local.d/url_suspect.conf:
-      # tld_map = "$LOCAL_CONFDIR/local.d/maps/url_suspect_tlds.map";
+      # Suspicious TLDs map
+      # User can override in local.d/maps.d/suspicious_tlds.inc
+      # or add local additions in local.d/maps.d/suspicious_tlds.inc.local
+      suspicious_tlds_map = [
+        "$LOCAL_CONFDIR/local.d/maps.d/suspicious_tlds.inc.local",
+        "$LOCAL_CONFDIR/local.d/maps.d/suspicious_tlds.inc",
+        "fallback+file://${CONFDIR}/maps.d/suspicious_tlds.inc"
+      ];
     }
 
     # Unicode and encoding analysis
index 9d1a33f3a6d555c022402e4693a86826ce2c869b..e1c0003e0800e75e6d59e7da644e0f3d789e67b8 100644 (file)
@@ -79,8 +79,8 @@ local settings = {
       allow_private_ranges = true
     },
     tld = {
-      enabled = true,
-      builtin_suspicious = { ".tk", ".ml", ".ga", ".cf", ".gq" }
+      enabled = true
+      -- suspicious_tlds_map loaded from config (default: $CONFDIR/maps.d/suspicious_tlds.inc)
     },
     unicode = {
       enabled = true,
@@ -407,23 +407,17 @@ function checks.tld_analysis(task, url, cfg)
     return findings
   end
 
-  -- Check built-in suspicious TLDs (5 TLDs, O(n) is fine)
-  for _, suspicious_tld in ipairs(cfg.builtin_suspicious) do
-    if tld == suspicious_tld or tld:sub(-#suspicious_tld) == suspicious_tld then
+  -- Check suspicious TLDs map
+  if maps.suspicious_tlds then
+    -- Check both with and without leading dot for flexibility
+    local tld_with_dot = tld:sub(1, 1) == '.' and tld or ('.' .. tld)
+    local tld_without_dot = tld:sub(1, 1) == '.' and tld:sub(2) or tld
+    if maps.suspicious_tlds:get_key(tld_with_dot) or maps.suspicious_tlds:get_key(tld_without_dot) then
       lua_util.debugm(N, task, "URL uses suspicious TLD: %s", tld)
       table.insert(findings, {
         symbol = symbols.suspicious_tld,
         options = { tld }
       })
-      break
-    end
-  end
-
-  -- Optional: check TLD map if configured
-  if maps.suspicious_tlds then
-    if maps.suspicious_tlds:get_key(tld) then
-      lua_util.debugm(N, task, "URL TLD in suspicious map: %s", tld)
-      -- Already handled by built-in check, or could add extra penalty
     end
   end
 
@@ -695,9 +689,12 @@ local function init_maps(cfg)
         cfg.checks.numeric_ip.range_map, 'radix', 'url_suspect_ip_ranges')
   end
 
-  if cfg.checks.tld.tld_map then
-    maps.suspicious_tlds = lua_maps.map_add_from_ucl(
-        cfg.checks.tld.tld_map, 'set', 'url_suspect_tlds')
+  if cfg.checks.tld.suspicious_tlds_map then
+    maps.suspicious_tlds = lua_maps.rspamd_map_add_from_ucl(
+        cfg.checks.tld.suspicious_tlds_map, 'set', 'url_suspect_suspicious_tlds')
+    if not maps.suspicious_tlds then
+      rspamd_logger.warnx(rspamd_config, 'failed to load suspicious_tlds_map, TLD check will be disabled')
+    end
   end
 
   if cfg.checks.structure.port_map then