Release history and version notes for Bad IPs
This page tracks all notable changes to Bad IPs. Changes are organized by version with the most recent releases first.
Legend: ✨ Added | 🔄 Changed | 🐛 Fixed | ⚠️ Deprecated | 🔒 Security
escalation_ttl_1 = 600 # comment) were read as literal values, causing numeric operations to fail. Postfix plugin now correctly parses configuration values by placing comments on separate lines.BadIPs::Plugins::Postfix plugin monitors Postfix logs for authentication failures and protocol violations with sophisticated username-based tracking. Detects distributed brute force attacks targeting the same account from multiple IP addresses.$item->{ttl}), allowing plugins to specify different block durations based on attack severity and persistence.20-postfix.conf. Plugin-based approach enables threshold tracking, username-based analysis, and escalating penalties that were not possible with simple pattern matching.central_db_sync and pull_global_blocks worker threads for improved robustness. Extracted common reconnection logic into _attempt_db_reconnect() helper function with interruptible 1-second sleep loops to allow shutdown signal response. Replaced blocking sleep operations with 1-second loop patterns that check shutdown/reload flags, enabling responsive service stops and configuration reloads.$db->test_connection(). Stale connections are immediately detected and cleared ($dbh = undef) to force fresh reconnection on next operation._try_enqueue_with_overflow_handling() helper function with optional non-blocking mode for safely adding IPs when queue depth exceeds 1000 items (prevents nft_blocker thread stall if database outage persists).central_db_sync and pull_global_blocks worker threads. When a database operation fails, the system now attempts to reconnect up to 5 times (configurable) with exponential backoff before requeueing items. This prevents thread death during temporary database outages and ensures graceful degradation - local IP blocking continues uninterrupted even when the central database is temporarily unavailable.db_retry_interval (default: 3 seconds) and db_max_retries (default: 5) parameters allow tuning of reconnection behavior per deployment.nft add set CLI syntax does not support inline comment parameters. Refactored to write persistent configuration file first, then load it with nft -f to create all infrastructure (table, sets, chain, rules) atomically. This approach ensures consistent behavior across all nftables versions.central_db_sync thread to process batches immediately when queue is draining, rather than waiting for timeout.graceful_shutdown_timeout from 300 seconds to 15 seconds. With queue draining fix, typical shutdown now completes in 5-15 seconds vs previous 300+ seconds./etc/sudoers.d/bad_ips with command aliases that used wildcards in arguments (e.g., Cmnd_Alias NFT_BADIPS_ADD = /usr/sbin/nft add element inet badips * *), which sudoers does not support. This caused visudo -c validation to fail with "wildcards are not allowed in command arguments", preventing package configuration and blocking apt dist-upgrade. The sudoers rule has been simplified to use a direct permission grant with wildcards only at the end: badips ALL=(root) NOPASSWD: /usr/sbin/nft add element inet badips *, /usr/sbin/nft flush set inet badips *, ... This syntax is validated successfully and provides the same functionality.urls = url1, url2) were treated as a single concatenated URL instead of separate URLs. The plugin now correctly splits and fetches each URL individually./etc/nftables.d/99-badips.nft so infrastructure survives reboots. Previously only created in-memory rules._add_ips_to_queue() for initial fetched lines, ensuring all historical attacks are blocked on service startup._get_journal_lines() method at line 359 that prevented log monitoring from working. The bug caused shell syntax errors every 2 seconds when unit parameters weren't provided, resulting in "Fetched 0 new relevant log lines" despite dozens of failed SSH attempts. Now correctly falls back to configured journal units when called without explicit parameters.nft -j list ruleset with jq to check what infrastructure already exists before creating anything, preventing duplicates. Running the installer 3 times now results in exactly 6 rules instead of 18.jq to package dependencies for idempotent installer verification logic.systemctl reload nftables.service call from postinst that was wiping out infrastructure created by the installer script. The reload reads config files and has no file to load from, causing it to flush the kernel state created by nft add commands. Infrastructure now persists correctly after package installation.nft add commands that were lost when nftables service reloaded. Changed to write persistent configuration to /etc/nftables.d/99-badips.nft and load with nft -f, ensuring infrastructure survives service reloads and reboots.libfile-slurp-perl to package dependencies required by GeneralLogMonitor plugin.file_paths but accessing via undefined log_pathsplugin_section parameter, causing plugins to fail loading their configuration/etc/nftables.d/99-badips.nft) with dedicated installer script and runtime validation. The systemd service no longer requires the configuration file to exist at startup./usr/local/sbin/bad_ips_installer.sh creates required nftables table, sets, chain, and rules. Idempotent and safe to run multiple times./etc/nftables.d/99-badips.nft wasn't present. Now creates infrastructure automatically during installation and validates it at startup.enqueue_ip callbacks that prevented any IPs from being added to nftables sets. The callbacks were enqueuing list arguments instead of hash references, causing worker threads to crash with "Can't use string as HASH ref" error. This affected both PublicBlocklistPlugins and regular Plugins, preventing all IP blocking from working.nft add element operations for all static sets (never_block, never_block_v6, always_block, always_block_v6). Previously only allowed explicit set names, causing "command not allowed" errors when refreshing static IP lists.[Plugins::GeneralMonitor] to [Plugins:GeneralLogMonitor] (fixed double colon and incorrect name)[Plugins:*] to [PublicBlocklistPlugins:*] (Spamhaus, Feodotracker, Blocklist_de, DNSBL_Info, Malwaredomainlist)table inet badips architecturenft_family_table in template from filter to badips to match actual table created since v3.2.1badips) with limited sudo privileges for enhanced securityff00::/8 (multicast), ::/128 (unspecified), and 2001:db8::/32 (documentation) to default never-block listauto_mode configurationbadips.conf.templatebad_ips_hunter to bad_ips for consistencyCONFIGURATION.md to reflect simplified architecturedatabase.conf now created with 640 permissions instead of 600 to allow badips user read access/usr/local/etc/badips.d/ now properly set to root:badips ownershipbadips.d directory during creationpublic_blocklist_urls - Replaced by [PublicBlocklistPlugins:Name] configuration sectionspublic_blocklist_refresh - Replaced by per-plugin fetch_interval parameterauto_mode settingbadips user instead of rootinet badips table onlydatabase.conf secured with 640 permissionssystemd-journal and adm groups for log access without elevated privileges