From 7a260afe3968cf3c1c2444910a1a6fab79741c43 Mon Sep 17 00:00:00 2001 From: Ruakij Date: Mon, 26 Oct 2026 19:52:14 +0000 Subject: [PATCH] crowdsec_range_bouncer: skip range decisions wider than /8 (IPv4) or /16 (IPv6) and log each skip --- .../templates/crowdsec-range-bouncer.py.j2 | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crowdsec_range_bouncer/templates/crowdsec-range-bouncer.py.j2 b/crowdsec_range_bouncer/templates/crowdsec-range-bouncer.py.j2 index 7cd3053..f0fbf3b 100644 --- a/crowdsec_range_bouncer/templates/crowdsec-range-bouncer.py.j2 +++ b/crowdsec_range_bouncer/templates/crowdsec-range-bouncer.py.j2 @@ -20,6 +20,8 @@ STATE_DIR = os.environ.get("STATE_DIRECTORY", "/var/lib/crowdsec-range-bouncer") HASH_FILE = os.path.join(STATE_DIR, "last.sha256") NFT = "/usr/sbin/nft" TABLE = "crowdsec_ranges" +# A prefix this wide is a poisoned decision, not a bad network. +MIN_DECISION_PREFIXLEN = {4: 8, 6: 16} def fetch_ranges(lapi_url, api_key): @@ -35,11 +37,16 @@ def fetch_ranges(lapi_url, api_key): return [] if not isinstance(decisions, list): raise ValueError("unexpected LAPI answer: %s" % type(decisions).__name__) - return [ - ipaddress.ip_network(d["value"], strict=False) - for d in decisions - if d["type"] == "ban" and d["scope"].lower() == "range" - ] + networks = [] + for d in decisions: + if d["type"] != "ban" or d["scope"].lower() != "range": + continue + network = ipaddress.ip_network(d["value"], strict=False) + if network.prefixlen < MIN_DECISION_PREFIXLEN[network.version]: + print("skipping suspiciously wide range decision %s" % network) + continue + networks.append(network) + return networks def collapse(networks, version):