From f127e6e6f0b7f107cfbc807954e0625797f22094 Mon Sep 17 00:00:00 2001 From: sebres Date: Sat, 1 Aug 2026 15:51:26 +0200 Subject: [PATCH 01/42] `action.d\nftables.conf`: allows protocol `all` for multi- and allports type; see https://github.com/fail2ban/fail2ban/discussions/4211#discussioncomment-17863040 --- config/action.d/nftables.conf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config/action.d/nftables.conf b/config/action.d/nftables.conf index 94ff9cdf..ef3dbedc 100644 --- a/config/action.d/nftables.conf +++ b/config/action.d/nftables.conf @@ -35,7 +35,11 @@ type = multiport rule_match-custom = rule_match-allports = meta l4proto \{ \} rule_match-multiport = $proto dport \{ $(echo '' | sed s/:/-/g) \} +rule_match-allprotos-custom = +rule_match-allprotos-allports = +rule_match-allprotos-multiport = th dport \{ $(echo '' | sed s/:/-/g) \} match = > +match_allprotos = > # Option: rule_stat # Notes.: statement for nftables filter rule. @@ -43,6 +47,7 @@ match = > # Values: nftables statement # rule_stat = %(match)s saddr @ +rule_stat_allprotos = %(match_allprotos)s saddr @ # optional iterator over protocol's: _nft_for_proto-custom-iter = @@ -56,9 +61,13 @@ _nft_list = -a list chain _nft_get_handle_id = sed -nE 's/.*@\s+.*\s+\#\s*(handle\s+[0-9]+)$/\1/p' _nft_add_set = add set
\{ type \; \} + if [ '' != "all" ]; then <_nft_for_proto--iter> add rule
%(rule_stat)s <_nft_for_proto--done> + else + add rule
%(rule_stat_allprotos)s + fi _nft_del_set = { %(_nft_list)s | %(_nft_get_handle_id)s; } | while read -r hdl; do delete rule
$hdl; done delete set
From 27552eb190b0f757e37758927c3123004b5f5517 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 14 Aug 2026 12:15:44 +0200 Subject: [PATCH 02/42] domino-smtp: added test cases illustrating GHSA-33wh-ccjc-p397 - hang injecting user name --- fail2ban/tests/files/logs/domino-smtp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fail2ban/tests/files/logs/domino-smtp b/fail2ban/tests/files/logs/domino-smtp index 957d593f..d9b7cc0c 100644 --- a/fail2ban/tests/files/logs/domino-smtp +++ b/fail2ban/tests/files/logs/domino-smtp @@ -7,6 +7,11 @@ # failJSON: { "time": "2016-11-07T22:21:20", "match": true , "host": "1.2.3.4" } 2016-11-07 22:21:20 smtp: postmaster [1.2.3.4] authentication failure using internet password +# failJSON: { "time": "2016-11-07T22:21:22", "match": true , "host": "192.0.2.5", "desc": "GHSA-33wh-ccjc-p397, positive case (match, no hangs)" } +2016-11-07 22:21:22 smtp: A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A 192.0.2.5 authentication failure using internet password +# failJSON: { "match": false, "desc": "GHSA-33wh-ccjc-p397, negative case (bypass, no hangs)" } +2016-11-07 22:21:23 smtp: A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A 192.0.2.5 + # failJSON: { "time": "2018-09-19T17:25:50", "match": true , "host": "192.0.2.1", "desc":"different log-format" } 2018-09-19 17:25:50 SMTP Server [0D14:0027-1334] Authentication failed for user Bad Hacker ; connecting host [192.0.2.1] # failJSON: { "time": "2018-09-19T17:25:52", "match": true , "host": "192.0.2.2", "desc":"gh-2228, rejected for policy reasons" } From 189da87824f90efc833b36253cd220dbb002b80d Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 14 Aug 2026 12:20:27 +0200 Subject: [PATCH 03/42] `filter.d/domino-smtp.conf`: fixes GHSA-33wh-ccjc-p397 - improve vulnerable RE so it'd not cause hangs --- config/filter.d/domino-smtp.conf | 11 ++++------- fail2ban/tests/files/logs/domino-smtp | 3 +++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/filter.d/domino-smtp.conf b/config/filter.d/domino-smtp.conf index 638cd7c5..2bac9f1c 100644 --- a/config/filter.d/domino-smtp.conf +++ b/config/filter.d/domino-smtp.conf @@ -23,10 +23,7 @@ [Definition] # Option: failregex -# Notes.: regex to match the password failure messages in the logfile. The -# host must be matched by a group named "host". The tag "" can -# be used for standard IP/hostname matching and is only an alias for -# (?:::f{4,6}:)?(?P\S+) +# Notes.: regex to match the password failure messages in the logfile. # Values: TEXT # # Sample log entries (used different time formats and an extra sample with process info in front of date) @@ -37,9 +34,9 @@ __prefix = (?:\[[^\]]+\])?\s* __opt_data = (?::|\s+\[[^\]]+\]) -failregex = ^%(__prefix)sSMTP Server%(__opt_data)s Authentication failed for user .*? \; connecting host \[?\]?$ - ^%(__prefix)ssmtp: (?:[^\[]+ )*\[?\]? authentication failure using internet password\s*$ - ^%(__prefix)sSMTP Server%(__opt_data)s Connection from \[?\]? rejected for policy reasons\. +failregex = ^%(__prefix)sSMTP Server%(__opt_data)s Authentication failed for user .*? \; connecting host \[?\]?$ + ^%(__prefix)ssmtp: (?:(?:[^\[ ]+ )*[^\[ ]+ )?\[?\]? authentication failure using internet password\s*$ + ^%(__prefix)sSMTP Server%(__opt_data)s Connection from \[?\]? rejected for policy reasons\. # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. diff --git a/fail2ban/tests/files/logs/domino-smtp b/fail2ban/tests/files/logs/domino-smtp index d9b7cc0c..0e87c52f 100644 --- a/fail2ban/tests/files/logs/domino-smtp +++ b/fail2ban/tests/files/logs/domino-smtp @@ -7,6 +7,9 @@ # failJSON: { "time": "2016-11-07T22:21:20", "match": true , "host": "1.2.3.4" } 2016-11-07 22:21:20 smtp: postmaster [1.2.3.4] authentication failure using internet password +# failJSON: { "time": "2016-11-07T22:21:21", "match": true , "host": "192.0.2.4", "user": "user with space in name" } +2016-11-07 22:21:21 smtp: user with space in name [192.0.2.4] authentication failure using internet password + # failJSON: { "time": "2016-11-07T22:21:22", "match": true , "host": "192.0.2.5", "desc": "GHSA-33wh-ccjc-p397, positive case (match, no hangs)" } 2016-11-07 22:21:22 smtp: A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A 192.0.2.5 authentication failure using internet password # failJSON: { "match": false, "desc": "GHSA-33wh-ccjc-p397, negative case (bypass, no hangs)" } From 2b46485c7adea3826978488b1bc2045265dbb2ba Mon Sep 17 00:00:00 2001 From: VXNCXNX Date: Fri, 14 Aug 2026 16:02:39 +0000 Subject: [PATCH 04/42] filter.d/postfix: catch "hostname ... does not resolve to address" in aggressive mode Postfix logs this warning when a client's reverse DNS does not resolve back to its address. Bots trip it constantly, but so does a legitimate sender with broken rDNS, so it only belongs in aggressive mode. Regex as given by sebres in gh-4078 and confirmed working by the reporter. Closes gh-4078 --- config/filter.d/postfix.conf | 1 + fail2ban/tests/files/logs/postfix | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/config/filter.d/postfix.conf b/config/filter.d/postfix.conf index 305e2ded..0c7f34b0 100644 --- a/config/filter.d/postfix.conf +++ b/config/filter.d/postfix.conf @@ -59,6 +59,7 @@ mdad-extra = mdpr-aggressive = (?:%(mdpr-auth)s|%(mdpr-normal)s|%(mdpr-ddos)s) mdre-aggressive = %(mdre-auth2)s %(mdre-normal)s + ^hostname \S+ does not resolve to address mdad-aggressive = %(mdad-ddos)s mdpr-errors = too many errors after \S+ diff --git a/fail2ban/tests/files/logs/postfix b/fail2ban/tests/files/logs/postfix index 30a4df24..75093f16 100644 --- a/fail2ban/tests/files/logs/postfix +++ b/fail2ban/tests/files/logs/postfix @@ -198,3 +198,7 @@ Sep 19 12:10:58 hostname postfix/smtpd[14059]: warning: Message delivery request # filterOptions: [{}, {"mode": "ddos"}, {"mode": "aggressive"}] # failJSON: { "match": false, "desc": "don't affect lawful data (sporadical connection aborts within DATA-phase, see gh-1813 for discussion)" } Feb 18 09:50:05 xxx postfix/smtpd[42]: lost connection after DATA from good-host.example.com[192.0.2.10] + +# filterOptions: [{"mode": "aggressive"}] +# failJSON: { "match": true , "host": "192.0.2.44", "desc": "hostname does not resolve to address, aggressive only (gh-4078)" } +Aug 14 10:00:01 mail postfix/smtpd[1234]: warning: hostname bad.example.com does not resolve to address 192.0.2.44: Name or service not known From 3a133f8aa43dc4806336697e19c3ae176d6d4dac Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 14 Aug 2026 23:32:19 +0200 Subject: [PATCH 05/42] `filter.d/dovecot.conf`: amend to GHSA-33wh-ccjc-p397 - improve vulnerable RE part to avoid catastrophic backtracking; added more (artificial) tests covering that (shall no hang) --- config/filter.d/dovecot.conf | 2 +- fail2ban/tests/files/logs/dovecot | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config/filter.d/dovecot.conf b/config/filter.d/dovecot.conf index 0a0d73e6..4a3b3ee7 100644 --- a/config/filter.d/dovecot.conf +++ b/config/filter.d/dovecot.conf @@ -15,7 +15,7 @@ _auth_driver = [a-z\-]+ _auth_worker = (?:dovecot: )?auth(?:-worker)? _auth_worker_info = (?:%(_auth_driver)s: )?(?:conn \w+:auth(?:-worker)? \([^\)]+\): auth(?:-worker)?<\d+>: )? -_bypass_reject_reason = (?:: (?:\w+\([^\):]*\) \w+|[^\(]+))* +_bypass_reject_reason = (?::(?: [^\( ]*|\([^\(]*\))*)? prefregex = ^%(__prefix_line)s(?:%(_auth_worker)s(?:\((?:\S*,(?:,\S*)?|[^\)]+)\))?(?:<[^>]+>)?: )?(?:%(__pam_auth)s(?:\(dovecot:auth\))?: |(?:pop3|imap|managesieve|submission)-login: )?(?:request \[\d+\]: )?(?:Info: )?%(_auth_worker_info)s.+$ diff --git a/fail2ban/tests/files/logs/dovecot b/fail2ban/tests/files/logs/dovecot index 07cbd654..da4e2006 100644 --- a/fail2ban/tests/files/logs/dovecot +++ b/fail2ban/tests/files/logs/dovecot @@ -144,6 +144,11 @@ Aug 30 00:10:57 auth(info@example.com,192.0.2.110,sasl:login): # failJSON: { "time": "2004-08-30T00:11:05", "match": true , "host": "192.0.2.110", "desc": "closed after 3 attempts (password mismatch), gh-4196" } Aug 30 00:11:05 imap-login: Info: Login aborted: Connection closed (auth failed, 3 attempts in 16 secs) (auth_failed): user=, method=PLAIN, rip=192.0.2.110, lip=0.0.0.0, TLS, session= +# failJSON: { "time": "2004-08-31T16:06:05", "match": true , "host": "192.0.2.111", "desc": "GHSA-33wh-ccjc-p397, positive case (match, no hangs)" } +Aug 31 16:06:05 s166-62-100-187 dovecot: imap-login: Disconnected: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: (reason: some unknown reason) (tried to use disallowed test auth): user=<>, rip=192.0.2.111 +# failJSON: { "match": false , "desc": "GHSA-33wh-ccjc-p397, negative case (bypass, no hangs)" } +Aug 31 16:06:06 s166-62-100-187 dovecot: imap-login: Disconnected: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: a: test no match + # --------------------------------------- # Test-cases of aggressive mode: # --------------------------------------- From d97eac50b9c098f1ea64302ed2cf92cad96638a1 Mon Sep 17 00:00:00 2001 From: VXNCXNX Date: Sat, 15 Aug 2026 06:37:47 +0000 Subject: [PATCH 06/42] filter.d/postfix: move the new sample into the existing aggressive section review feedback from sebres, the file already has a filterOptions aggressive section, so the sample belongs there rather than in a second one at the end. --- fail2ban/tests/files/logs/postfix | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fail2ban/tests/files/logs/postfix b/fail2ban/tests/files/logs/postfix index 75093f16..0075b91c 100644 --- a/fail2ban/tests/files/logs/postfix +++ b/fail2ban/tests/files/logs/postfix @@ -154,6 +154,9 @@ Jan 14 16:18:16 xxx postfix/smtpd[14933]: warning: host[192.0.2.5]: SASL CRAM-MD # failJSON: { "time": "2004-11-04T09:11:01", "match": true , "host": "192.0.2.152", "user": "admin", "desc": "reason unavailable" } Nov 4 09:11:01 mail postfix/smtpd[1234]: warning: unknown[192.0.2.152]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=admin +# failJSON: { "match": true , "host": "192.0.2.44", "desc": "hostname does not resolve to address, aggressive only (gh-4078)" } +Aug 14 10:00:01 mail postfix/smtpd[1234]: warning: hostname bad.example.com does not resolve to address 192.0.2.44: Name or service not known + # --------------------------------------- # Test-cases of postfix DDOS mode: # --------------------------------------- @@ -198,7 +201,3 @@ Sep 19 12:10:58 hostname postfix/smtpd[14059]: warning: Message delivery request # filterOptions: [{}, {"mode": "ddos"}, {"mode": "aggressive"}] # failJSON: { "match": false, "desc": "don't affect lawful data (sporadical connection aborts within DATA-phase, see gh-1813 for discussion)" } Feb 18 09:50:05 xxx postfix/smtpd[42]: lost connection after DATA from good-host.example.com[192.0.2.10] - -# filterOptions: [{"mode": "aggressive"}] -# failJSON: { "match": true , "host": "192.0.2.44", "desc": "hostname does not resolve to address, aggressive only (gh-4078)" } -Aug 14 10:00:01 mail postfix/smtpd[1234]: warning: hostname bad.example.com does not resolve to address 192.0.2.44: Name or service not known From d5d81242cf40a586e4c7564f965a9d51b496e791 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Sat, 15 Aug 2026 19:06:17 +0900 Subject: [PATCH 07/42] Add support for systemd socket activation --- ChangeLog | 1 + fail2ban/server/asyncserver.py | 61 +++++++++++++++++++++----------- fail2ban/tests/sockettestcase.py | 35 ++++++++++++++++++ 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 216ffe88..83dff08b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -83,6 +83,7 @@ ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition * `filter.d/froxlor-auth.conf` - updated the regex to the new logging situation for froxlor and changed logpath in jail.conf (gh-4075). ### New Features and Enhancements +* `fail2ban-server` supports `systemd` socket activation (`sd_listen_fds(3)`); optional `fail2ban.socket` unit provided * backend `systemd` extended with new parameter `rotated` (default `false`, as prevention against "too many open files"), that allows to monitor only actual journals and ignore now a lot of rotated files by default; so can drastically reduce amount of used file descriptors, normally to 1 or 2 descriptors per jail (gh-3391) diff --git a/fail2ban/server/asyncserver.py b/fail2ban/server/asyncserver.py index 62d6cce5..557ab19f 100644 --- a/fail2ban/server/asyncserver.py +++ b/fail2ban/server/asyncserver.py @@ -236,35 +236,54 @@ class AsyncServer(asyncore.dispatcher): # Creates an instance of the handler class to handle the # request/response on the incoming connection. RequestHandler(conn, self.__transmitter) - + + def setup_socket(self, sock, force): + nfds = os.environ.get("LISTEN_FDS") + if nfds and os.environ.get("LISTEN_PID") == str(os.getpid()): + # systemd socket activation (sd_listen_fds(3)): reuse an inherited, + # already bound and listening socket instead of creating our own. + names = os.environ.get("LISTEN_FDNAMES", "").split(":") + idx = names.index("fail2ban") if "fail2ban" in names else 0 + idx = min(idx, int(nfds) - 1) + os.environ.pop("LISTEN_PID", None) + os.environ.pop("LISTEN_FDS", None) + os.environ.pop("LISTEN_FDNAMES", None) + logSys.info("Using socket activation, inherited socket %r", sock) + self.set_socket(socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, fileno=3 + idx)) + self.socket.setblocking(False) + self.accepting = True + else: + # Remove socket + if os.path.exists(sock): + logSys.error("Fail2ban seems to be already running") + if force: + logSys.warning("Forcing execution of the server") + self._remove_sock() + else: + raise AsyncServerException("Server already running") + # Creates the socket. + self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.set_reuse_addr() + try: + self.bind(sock) + except Exception: # pragma: no cover + raise AsyncServerException("Unable to bind socket %s" % self.__sock) + self.listen(1) + # Sets the init flag. + self.__init = True + AsyncServer.__markCloseOnExec(self.socket) + ## # Starts the communication server. # # @param sock: socket file. # @param force: remove the socket file if exists. - + def start(self, sock, force, timeout=None, use_poll=False): self.__worker = threading.current_thread() self.__sock = sock - # Remove socket - if os.path.exists(sock): - logSys.error("Fail2ban seems to be already running") - if force: - logSys.warning("Forcing execution of the server") - self._remove_sock() - else: - raise AsyncServerException("Server already running") - # Creates the socket. - self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.set_reuse_addr() - try: - self.bind(sock) - except Exception: # pragma: no cover - raise AsyncServerException("Unable to bind socket %s" % self.__sock) - AsyncServer.__markCloseOnExec(self.socket) - self.listen(1) - # Sets the init flag. - self.__init = self.__loop = self.__active = True + self.setup_socket(sock, force) + self.__loop = self.__active = True # Execute on start event (server ready): if self.onstart: self.onstart() diff --git a/fail2ban/tests/sockettestcase.py b/fail2ban/tests/sockettestcase.py index 5c674620..57fa10d7 100644 --- a/fail2ban/tests/sockettestcase.py +++ b/fail2ban/tests/sockettestcase.py @@ -25,6 +25,7 @@ __copyright__ = "Copyright (c) 2013 Steven Hiscocks" __license__ = "GPL" import os +import socket import sys import tempfile import threading @@ -34,6 +35,7 @@ import unittest from .utils import LogCaptureTestCase from .. import protocol +from ..server import asyncserver from ..server.asyncserver import asyncore, RequestHandler, loop, AsyncServer, AsyncServerException from ..server.utils import Utils from ..client.csocket import CSocket @@ -203,6 +205,39 @@ class Socket(LogCaptureTestCase): self.assertLogged("Server connection was closed: test errors in poll", "Too many errors - stop logging connection errors", all=True) + def testSocketActivation(self): + # Simulate a socket already bound/listening, handed to us as an + # inherited fd (systemd socket activation, sd_listen_fds(3)): + presock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + presock.bind(self.sock_name) + presock.listen(5) + # dup to a fresh fd first (presock.fileno() might already be 3): + fd = os.dup(presock.fileno()) + presock.close() + os.dup2(fd, 3) + os.close(fd) + + self.addCleanup(os.environ.pop, "LISTEN_PID", None) + self.addCleanup(os.environ.pop, "LISTEN_FDS", None) + self.addCleanup(lambda: os.path.exists(self.sock_name) and os.remove(self.sock_name)) + os.environ["LISTEN_PID"] = str(os.getpid()) + os.environ["LISTEN_FDS"] = "1" + + serverThread = self._createServerThread() + # consumed once picked up, so forked actions don't misinterpret them: + self.assertNotIn("LISTEN_PID", os.environ) + self.assertNotIn("LISTEN_FDS", os.environ) + + client = Utils.wait_for(self._serverSocket, 2) + testMessage = ["A", "test", "message"] + self.assertEqual(client.send(testMessage), testMessage) + + self.server.stop() + self._stopServerThread() + self.assertFalse(serverThread.is_alive()) + # socket file is owned by the service manager, must not be removed: + self.assertTrue(os.path.exists(self.sock_name)) + def testSocketForce(self): open(self.sock_name, 'w').close() # Create sock file # Try to start without force From ef15ac46a88468878e24cda420672b6b3cfd57e5 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Sat, 15 Aug 2026 19:07:44 +0900 Subject: [PATCH 08/42] Add `fail2ban.socket` unit --- files/fail2ban.socket.in | 12 ++++++++++++ setup.py | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 files/fail2ban.socket.in diff --git a/files/fail2ban.socket.in b/files/fail2ban.socket.in new file mode 100644 index 00000000..2333f84f --- /dev/null +++ b/files/fail2ban.socket.in @@ -0,0 +1,12 @@ +[Unit] +Description=Fail2Ban Socket +Documentation=man:fail2ban(1) + +[Socket] +ListenStream=%t/fail2ban/fail2ban.sock +FileDescriptorName=fail2ban +SocketMode=0600 +RuntimeDirectory=fail2ban + +[Install] +WantedBy=sockets.target diff --git a/setup.py b/setup.py index b2c0e5c9..ee8f392d 100755 --- a/setup.py +++ b/setup.py @@ -80,7 +80,7 @@ class install_scripts_f2b(install_scripts): except: # pragma: no cover print('WARNING: Cannot find root-base option, check the bin-path to fail2ban-scripts in "fail2ban.service" and "fail2ban-openrc.init".') - scripts = ['fail2ban.service', 'fail2ban-openrc.init'] + scripts = ['fail2ban.service', 'fail2ban.socket', 'fail2ban-openrc.init'] for script in scripts: print(('Creating %s/%s (from %s.in): @BINDIR@ -> %s' % (buildroot, script, script, install_dir))) with open(os.path.join(source_dir, 'files/%s.in' % script), 'r') as fn: @@ -294,5 +294,6 @@ if sys.argv[1] == "install": print("They are in \"/etc/fail2ban/\".") print("") print("You can also install systemd service-unit file from \"build/fail2ban.service\"") + print("(optionally paired with \"build/fail2ban.socket\" to enable socket activation)") print("resp. corresponding init script from \"files/*-initd\".") print("") From 6afc0745913d34de560fd6b3ecbd0d5fc016ef84 Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Sat, 15 Aug 2026 12:33:16 +0200 Subject: [PATCH 09/42] Update ChangeLog with new aggressive mode matching Extended modes 'aggressive' to match hostname resolution errors. --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 216ffe88..4b22a58e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -65,6 +65,7 @@ ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition - add optional `NOQUEUE:` prefix to ddos regex (gh-4072) - internal parameter `_pref` is renamed to `_cmd`, `_pref` matches now optional prefix like `NOQUEUE: ` etc - modes `ddos` and `aggressive` extended to match `rate limit exceeded` for connection or message delivery request rates (gh-3265, gh-4073) + - modes `aggressive` extended to match `hostname does not resolve to address` (gh-4218, gh-4078) * `filter.d/dropbear.conf`: - recognizes extra pid/timestamp if logged into stdout/journal, added `journalmatch` (gh-3597) - failregex extended to match different format of "Exit before auth" message (gh-3791) From fbfeecd0b1c40be58fa0cc83e121df9a4a6791e9 Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Sat, 15 Aug 2026 13:10:02 +0200 Subject: [PATCH 10/42] CI: update Python version to 3.15.0-rc.1 in workflow --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ee6305c4..6312790c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8, 3.9, '3.10', '3.11', '3.12', '3.13', '3.14', '3.15.0-alpha.5', pypy3.11] + python-version: [3.8, 3.9, '3.10', '3.11', '3.12', '3.13', '3.14', '3.15.0-rc.1', pypy3.11] fail-fast: false # Steps represent a sequence of tasks that will be executed as part of the job steps: From 5684996a940f8b1b86111eaa4f3d2f295a7c03f9 Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Sat, 15 Aug 2026 13:14:33 +0200 Subject: [PATCH 11/42] CI: update checkout action version to v7 try to silence deprecation warning (Node.js 20) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6312790c..63e5e3c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,7 +27,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v5 From 153751d40ccd228fab285ff611c87c69f76fa9aa Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Sat, 15 Aug 2026 13:18:30 +0200 Subject: [PATCH 12/42] CI: upgrade Python setup action to version 7 try to silence deprecation warning (Node.js 20) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 63e5e3c2..77c85ec2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v7 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} From a2694a1ec1f73551232d04f1987b37f9f501969f Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Sat, 15 Aug 2026 13:25:05 +0200 Subject: [PATCH 13/42] update ChangeLog with recent fixes Fix catastrophic backtracking in REs for domino-smtp and dovecot filters. --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 216ffe88..77b0c467 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,7 @@ ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition to use it as before set `mode = more` for exim jail, but be aware of the consequences. ### Fixes +* fixes catastrophic backtracking explosion for REs in domino-smtp and dovecot filters (GHSA-33wh-ccjc-p397, gh-4221) * fixes `systemd` bug with missing journal descriptor after rotation by reopening of journal if it is recognized as not alive (gh-3929) * improve threaded clean-up of all filters, new thread functions `afterStop` (to force clean-up after stop) and `done`, invoking `afterStop` once * ensure journal-reader is always closed (additional prevention against leaks and "too many open files"), thereby avoid sporadic segfault From f0fe7a57ff1b82f90c14dc76d3aa7fd2a0ead30c Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Sat, 15 Aug 2026 13:33:10 +0200 Subject: [PATCH 14/42] CI: update actions/checkout from v3 to v7 silence deprecation warning (Node.js 20) --- .github/workflows/codespell.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 7373affc..16877239 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -17,6 +17,6 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v7 - name: Codespell uses: codespell-project/actions-codespell@v2 From f60978618a101427b06924fc932b44350fec2b63 Mon Sep 17 00:00:00 2001 From: sebres Date: Sat, 15 Aug 2026 14:22:54 +0200 Subject: [PATCH 15/42] release 1.1.1 -- triple-one-win --- ChangeLog | 2 +- MANIFEST | 12 +++++++++++- fail2ban/version.py | 2 +- man/fail2ban-client.1 | 18 +++++++++++------- man/fail2ban-python.1 | 22 +++++++++++++--------- man/fail2ban-regex.1 | 2 +- man/fail2ban-server.1 | 4 ++-- man/fail2ban-testcases.1 | 2 +- 8 files changed, 41 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index ff1374d8..044c061d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,7 +7,7 @@ Fail2Ban: Changelog =================== -ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition +ver. 1.1.1 (2026/08/15) - triple-one-win ----------- ### Compatibility diff --git a/MANIFEST b/MANIFEST index 972a2b48..5fbd4e10 100644 --- a/MANIFEST +++ b/MANIFEST @@ -11,6 +11,7 @@ config/action.d/bsd-ipfw.conf config/action.d/cloudflare.conf config/action.d/cloudflare-token.conf config/action.d/complain.conf +config/action.d/csf.conf config/action.d/dshield.conf config/action.d/dummy.conf config/action.d/firewallcmd-allports.conf @@ -129,6 +130,7 @@ config/filter.d/nginx-http-auth.conf config/filter.d/nginx-limit-req.conf config/filter.d/nsd.conf config/filter.d/openhab.conf +config/filter.d/openvpn.conf config/filter.d/openwebmail.conf config/filter.d/oracleims.conf config/filter.d/pam-generic.conf @@ -138,6 +140,7 @@ config/filter.d/php-url-fopen.conf config/filter.d/portsentry.conf config/filter.d/postfix.conf config/filter.d/proftpd.conf +config/filter.d/proxmox.conf config/filter.d/pure-ftpd.conf config/filter.d/qmail.conf config/filter.d/recidive.conf @@ -162,10 +165,12 @@ config/filter.d/suhosin.conf config/filter.d/tine20.conf config/filter.d/traefik-auth.conf config/filter.d/uwimap-auth.conf +config/filter.d/vaultwarden.conf config/filter.d/vsftpd.conf config/filter.d/webmin-auth.conf config/filter.d/wuftpd.conf config/filter.d/xinetd-fail.conf +config/filter.d/xrdp.conf config/filter.d/znc-adminlog.conf config/filter.d/zoneminder.conf config/jail.conf @@ -340,6 +345,7 @@ fail2ban/tests/files/logs/nginx-http-auth fail2ban/tests/files/logs/nginx-limit-req fail2ban/tests/files/logs/nsd fail2ban/tests/files/logs/openhab +fail2ban/tests/files/logs/openvpn fail2ban/tests/files/logs/openwebmail fail2ban/tests/files/logs/oracleims fail2ban/tests/files/logs/pam-generic @@ -349,6 +355,7 @@ fail2ban/tests/files/logs/php-url-fopen fail2ban/tests/files/logs/portsentry fail2ban/tests/files/logs/postfix fail2ban/tests/files/logs/proftpd +fail2ban/tests/files/logs/proxmox fail2ban/tests/files/logs/pure-ftpd fail2ban/tests/files/logs/qmail fail2ban/tests/files/logs/recidive @@ -373,10 +380,12 @@ fail2ban/tests/files/logs/suhosin fail2ban/tests/files/logs/tine20 fail2ban/tests/files/logs/traefik-auth fail2ban/tests/files/logs/uwimap-auth +fail2ban/tests/files/logs/vaultwarden fail2ban/tests/files/logs/vsftpd fail2ban/tests/files/logs/webmin-auth fail2ban/tests/files/logs/wuftpd fail2ban/tests/files/logs/xinetd-fail +fail2ban/tests/files/logs/xrdp fail2ban/tests/files/logs/znc-adminlog fail2ban/tests/files/logs/zoneminder fail2ban/tests/files/logs/zzz-generic-example @@ -390,6 +399,7 @@ fail2ban/tests/files/testcase-journal.log fail2ban/tests/files/testcase-multiline.log fail2ban/tests/files/testcase-usedns.log fail2ban/tests/files/testcase-wrong-char.log +fail2ban/tests/files/test-ign-ips-file fail2ban/tests/files/zzz-sshd-obsolete-multiline.log fail2ban/tests/filtertestcase.py fail2ban/tests/__init__.py @@ -410,7 +420,7 @@ files/fail2ban-logrotate files/fail2ban-openrc.conf files/fail2ban-openrc.init.in files/fail2ban.service.in -files/fail2ban-tmpfiles.conf +files/fail2ban.socket.in files/fail2ban.upstart files/gen_badbots files/ipmasq-ZZZzzz_fail2ban.rul diff --git a/fail2ban/version.py b/fail2ban/version.py index 34dff834..bf49505a 100644 --- a/fail2ban/version.py +++ b/fail2ban/version.py @@ -24,7 +24,7 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko, Steven Hiscocks, Daniel Black" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2005-2016 Yaroslav Halchenko, 2013-2014 Steven Hiscocks, Daniel Black" __license__ = "GPL-v2+" -version = "1.1.1.dev1" +version = "1.1.1" def normVersion(): """ Returns fail2ban version in normalized machine-readable format""" diff --git a/man/fail2ban-client.1 b/man/fail2ban-client.1 index 9d270933..0a99b1c1 100644 --- a/man/fail2ban-client.1 +++ b/man/fail2ban-client.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-CLIENT "1" "April 2024" "Fail2Ban v1.1.1.dev1" "User Commands" +.TH FAIL2BAN-CLIENT "1" "August 2026" "Fail2Ban v1.1.1" "User Commands" .SH NAME fail2ban-client \- configure and control the server .SH SYNOPSIS .B fail2ban-client [\fI\,OPTIONS\/\fR] \fI\,\/\fR .SH DESCRIPTION -Fail2Ban v1.1.1.dev1 reads log file that contains password failure report +Fail2Ban v1.1.1 reads log file that contains password failure report and bans the corresponding IP addresses using firewall rules. .SH OPTIONS .TP @@ -125,8 +125,10 @@ server .TP \fBstatus \fB\-\-all\fR [FLAVOR]\fR gets the current status of all -jails, with optional output style [FLAVOR]. -Flavors: 'basic' (default), 'cymru', 'short', 'stats'. +jails, with optional output style +[FLAVOR]. Flavors: 'basic' +(default), 'cymru', 'short', +\&'stats' .TP \fBstat[istic]s\fR gets the current statistics of all @@ -214,9 +216,11 @@ stops the jail . The jail is removed .TP \fBstatus [FLAVOR]\fR -gets the current status of all -jails, with optional output style [FLAVOR]. -Flavors: 'basic' (default), 'cymru', 'short', 'stats'. +gets the current status of , +with optional output style +[FLAVOR]. Flavors: 'basic' +(default), 'cymru', 'short', +\&'stats' .IP JAIL CONFIGURATION .TP diff --git a/man/fail2ban-python.1 b/man/fail2ban-python.1 index e673d7a0..c865cd26 100644 --- a/man/fail2ban-python.1 +++ b/man/fail2ban-python.1 @@ -1,13 +1,13 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-PYTHON "1" "April 2024" "fail2ban-python 1.1.1.1" "User Commands" +.TH FAIL2BAN-PYTHON "1" "August 2026" "fail2ban-python 1.1.1" "User Commands" .SH NAME fail2ban-python \- a helper for Fail2Ban to assure that the same Python is used .SH DESCRIPTION usage: fail2ban\-python [option] ... [\-c cmd | \fB\-m\fR mod | file | \fB\-]\fR [arg] ... Options (and corresponding environment variables): -\fB\-b\fR : issue warnings about str(bytes_instance), str(bytearray_instance) +\fB\-b\fR : issue warnings about converting bytes/bytearray to str and comparing .IP -and comparing bytes/bytearray with str. (\fB\-bb\fR: issue errors) +bytes/bytearray with str or bytes with int. (\fB\-bb\fR: issue errors) .PP \fB\-B\fR : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x \fB\-c\fR cmd : program passed in as string (terminates option list) @@ -21,7 +21,7 @@ debug builds); also PYTHONDEBUG=x .IP if stdin does not appear to be a terminal; also PYTHONINSPECT=x .PP -\fB\-I\fR : isolate Python from the user's environment (implies \fB\-E\fR and \fB\-s\fR) +\fB\-I\fR : isolate Python from the user's environment (implies \fB\-E\fR, \fB\-P\fR and \fB\-s\fR) \fB\-m\fR mod : run library module as a script (terminates option list) \fB\-O\fR : remove assert and __debug__\-dependent statements; add .opt\-1 before .IP @@ -31,9 +31,12 @@ if stdin does not appear to be a terminal; also PYTHONINSPECT=x .IP \&.pyc extension .PP -\fB\-P\fR : don't prepend a potentially unsafe path to sys.path +\fB\-P\fR : don't prepend a potentially unsafe path to sys.path; also +.IP +PYTHONSAFEPATH +.PP \fB\-q\fR : don't print version and copyright messages on interactive startup -\fB\-s\fR : don't add user site directory to sys.path; also PYTHONNOUSERSITE +\fB\-s\fR : don't add user site directory to sys.path; also PYTHONNOUSERSITE=x \fB\-S\fR : don't imply 'import site' on initialization \fB\-u\fR : force the stdout and stderr streams to be unbuffered; .IP @@ -57,9 +60,10 @@ also PYTHONWARNINGS=arg .IP control how Python invalidates hash\-based .pyc files .PP -\fB\-\-help\-env\fR : print help about Python environment variables and exit -\fB\-\-help\-xoptions\fR : print help about implementation\-specific \fB\-X\fR options and exit -\fB\-\-help\-all\fR : print complete help information and exit +\fB\-\-help\-env\fR: print help about Python environment variables and exit +\fB\-\-help\-xoptions\fR: print help about implementation\-specific \fB\-X\fR options and exit +\fB\-\-help\-all\fR: print complete help information and exit +.PP Arguments: file : program read from script file \- : program read from stdin (default; interactive mode if a tty) diff --git a/man/fail2ban-regex.1 b/man/fail2ban-regex.1 index d1a7626f..a5afc76c 100644 --- a/man/fail2ban-regex.1 +++ b/man/fail2ban-regex.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-REGEX "1" "June 2025" "fail2ban-regex 1.1.1.dev1" "User Commands" +.TH FAIL2BAN-REGEX "1" "August 2026" "fail2ban-regex 1.1.1" "User Commands" .SH NAME fail2ban-regex \- test Fail2ban "failregex" option .SH SYNOPSIS diff --git a/man/fail2ban-server.1 b/man/fail2ban-server.1 index df85419b..7d506d39 100644 --- a/man/fail2ban-server.1 +++ b/man/fail2ban-server.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-SERVER "1" "April 2024" "Fail2Ban v1.1.1.dev1" "User Commands" +.TH FAIL2BAN-SERVER "1" "August 2026" "Fail2Ban v1.1.1" "User Commands" .SH NAME fail2ban-server \- start the server .SH SYNOPSIS .B fail2ban-server [\fI\,OPTIONS\/\fR] .SH DESCRIPTION -Fail2Ban v1.1.1.dev1 reads log file that contains password failure report +Fail2Ban v1.1.1 reads log file that contains password failure report and bans the corresponding IP addresses using firewall rules. .SH OPTIONS .TP diff --git a/man/fail2ban-testcases.1 b/man/fail2ban-testcases.1 index 8d8dcf6e..acbcfde4 100644 --- a/man/fail2ban-testcases.1 +++ b/man/fail2ban-testcases.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-TESTCASES "1" "April 2024" "fail2ban-testcases 1.1.1.dev1" "User Commands" +.TH FAIL2BAN-TESTCASES "1" "August 2026" "fail2ban-testcases 1.1.1" "User Commands" .SH NAME fail2ban-testcases \- run Fail2Ban unit-tests .SH SYNOPSIS From 3a7a6ac4150fefd15a95b44bd2bda213bbc76c2f Mon Sep 17 00:00:00 2001 From: sebres Date: Sat, 15 Aug 2026 17:48:38 +0200 Subject: [PATCH 16/42] version bump (back to .dev) --- ChangeLog | 8 ++++++++ fail2ban/version.py | 2 +- man/fail2ban-client.1 | 4 ++-- man/fail2ban-python.1 | 2 +- man/fail2ban-regex.1 | 2 +- man/fail2ban-server.1 | 4 ++-- man/fail2ban-testcases.1 | 2 +- 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 044c061d..aabe064e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,14 @@ Fail2Ban: Changelog =================== +ver. 1.1.2-dev-1 (20??/??/??) - development nightly edition +----------- + +### Fixes + +### New Features and Enhancements + + ver. 1.1.1 (2026/08/15) - triple-one-win ----------- diff --git a/fail2ban/version.py b/fail2ban/version.py index bf49505a..f570d0bc 100644 --- a/fail2ban/version.py +++ b/fail2ban/version.py @@ -24,7 +24,7 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko, Steven Hiscocks, Daniel Black" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2005-2016 Yaroslav Halchenko, 2013-2014 Steven Hiscocks, Daniel Black" __license__ = "GPL-v2+" -version = "1.1.1" +version = "1.1.2.dev1" def normVersion(): """ Returns fail2ban version in normalized machine-readable format""" diff --git a/man/fail2ban-client.1 b/man/fail2ban-client.1 index 0a99b1c1..5cf9c4fb 100644 --- a/man/fail2ban-client.1 +++ b/man/fail2ban-client.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-CLIENT "1" "August 2026" "Fail2Ban v1.1.1" "User Commands" +.TH FAIL2BAN-CLIENT "1" "August 2026" "Fail2Ban v1.1.2.dev1" "User Commands" .SH NAME fail2ban-client \- configure and control the server .SH SYNOPSIS .B fail2ban-client [\fI\,OPTIONS\/\fR] \fI\,\/\fR .SH DESCRIPTION -Fail2Ban v1.1.1 reads log file that contains password failure report +Fail2Ban v1.1.2.dev1 reads log file that contains password failure report and bans the corresponding IP addresses using firewall rules. .SH OPTIONS .TP diff --git a/man/fail2ban-python.1 b/man/fail2ban-python.1 index c865cd26..d1dff5b1 100644 --- a/man/fail2ban-python.1 +++ b/man/fail2ban-python.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-PYTHON "1" "August 2026" "fail2ban-python 1.1.1" "User Commands" +.TH FAIL2BAN-PYTHON "1" "August 2026" "fail2ban-python 1.1.2.1" "User Commands" .SH NAME fail2ban-python \- a helper for Fail2Ban to assure that the same Python is used .SH DESCRIPTION diff --git a/man/fail2ban-regex.1 b/man/fail2ban-regex.1 index a5afc76c..6b879e3f 100644 --- a/man/fail2ban-regex.1 +++ b/man/fail2ban-regex.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-REGEX "1" "August 2026" "fail2ban-regex 1.1.1" "User Commands" +.TH FAIL2BAN-REGEX "1" "August 2026" "fail2ban-regex 1.1.2.dev1" "User Commands" .SH NAME fail2ban-regex \- test Fail2ban "failregex" option .SH SYNOPSIS diff --git a/man/fail2ban-server.1 b/man/fail2ban-server.1 index 7d506d39..af824fd7 100644 --- a/man/fail2ban-server.1 +++ b/man/fail2ban-server.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-SERVER "1" "August 2026" "Fail2Ban v1.1.1" "User Commands" +.TH FAIL2BAN-SERVER "1" "August 2026" "Fail2Ban v1.1.2.dev1" "User Commands" .SH NAME fail2ban-server \- start the server .SH SYNOPSIS .B fail2ban-server [\fI\,OPTIONS\/\fR] .SH DESCRIPTION -Fail2Ban v1.1.1 reads log file that contains password failure report +Fail2Ban v1.1.2.dev1 reads log file that contains password failure report and bans the corresponding IP addresses using firewall rules. .SH OPTIONS .TP diff --git a/man/fail2ban-testcases.1 b/man/fail2ban-testcases.1 index acbcfde4..c2ad982d 100644 --- a/man/fail2ban-testcases.1 +++ b/man/fail2ban-testcases.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH FAIL2BAN-TESTCASES "1" "August 2026" "fail2ban-testcases 1.1.1" "User Commands" +.TH FAIL2BAN-TESTCASES "1" "August 2026" "fail2ban-testcases 1.1.2.dev1" "User Commands" .SH NAME fail2ban-testcases \- run Fail2Ban unit-tests .SH SYNOPSIS From 83a66db41d6fcbc02dcceb3bbb68c7f7fe8556d9 Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Sat, 15 Aug 2026 21:58:59 +0200 Subject: [PATCH 17/42] Readme: version bump - v1.1.2.dev1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d5a5959..d6da5e71 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ / _|__ _(_) |_ ) |__ __ _ _ _ | _/ _` | | |/ /| '_ \/ _` | ' \ |_| \__,_|_|_/___|_.__/\__,_|_||_| - v1.1.0.dev1 20??/??/?? + v1.1.2.dev1 20??/??/?? ## Fail2Ban: ban hosts that cause multiple authentication errors From 203202cdb46ee1d6d0b39e1cd62221203d3982a9 Mon Sep 17 00:00:00 2001 From: VXNCXNX Date: Sun, 16 Aug 2026 08:40:42 +0000 Subject: [PATCH 18/42] filter.d/nginx-botsearch: support the journal log format The error-log regex hardcoded the file-format prefix, so lines carrying a systemd journal prefix were missed. Use __prefix_line from nginx-error-common.conf, as the other nginx error-log filters already do. Closes gh-3732 --- ChangeLog | 1 + config/filter.d/nginx-botsearch.conf | 3 ++- fail2ban/tests/files/logs/nginx-botsearch | 10 +++++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index aabe064e..0cdc676e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,7 @@ ver. 1.1.2-dev-1 (20??/??/??) - development nightly edition ----------- ### Fixes +* `filter.d/nginx-botsearch.conf` - error-log regex extended with support of journal format (gh-3732) ### New Features and Enhancements diff --git a/config/filter.d/nginx-botsearch.conf b/config/filter.d/nginx-botsearch.conf index 2bd23072..4cff8ad2 100644 --- a/config/filter.d/nginx-botsearch.conf +++ b/config/filter.d/nginx-botsearch.conf @@ -5,11 +5,12 @@ # Load regexes for filtering before = botsearch-common.conf + nginx-error-common.conf [Definition] failregex = ^ \- \S+ \[\] \"(GET|POST|HEAD) \/ \S+\" 404 .+$ - ^ \[error\] \d+#\d+: \*\d+ (\S+ )?\"\S+\" (failed|is not found) \(2\: No such file or directory\), client\: \, server\: \S*\, request: \"(GET|POST|HEAD) \/ \S+\"\, .*?$ + ^%(__prefix_line)s(\S+ )?\"\S+\" (failed|is not found) \(2\: No such file or directory\), client\: \, server\: \S*\, request: \"(GET|POST|HEAD) \/ \S+\"\, .*?$ ignoreregex = diff --git a/fail2ban/tests/files/logs/nginx-botsearch b/fail2ban/tests/files/logs/nginx-botsearch index c694fa3b..a739dc84 100644 --- a/fail2ban/tests/files/logs/nginx-botsearch +++ b/fail2ban/tests/files/logs/nginx-botsearch @@ -32,4 +32,12 @@ 2015/01/21 10:58:10 [error] 2833#0: *16336 open() "/var/www/site/cgi-bin/php4" failed (2: No such file or directory), client: 5.7.9.2, server: localhost, request: "HEAD /cgi-bin/php4 HTTP/1.1", host: "1.2.3.4" # failJSON: { "time": "2015-01-21T15:02:27", "match": true , "host": "5.7.9.2" } -2015/01/21 15:02:27 [error] 2833#0: *16813 "/var/www/site/roundcube/" is not found (2: No such file or directory), client: 5.7.9.2, server: localhost, request: "GET /roundcube/ HTTP/1.1", host: "1.2.3.4" \ No newline at end of file +2015/01/21 15:02:27 [error] 2833#0: *16813 "/var/www/site/roundcube/" is not found (2: No such file or directory), client: 5.7.9.2, server: localhost, request: "GET /roundcube/ HTTP/1.1", host: "1.2.3.4" + +# filterOptions: [{"logtype": "journal"}] + +# failJSON: { "match": true, "host": "5.7.9.2", "desc": "systemd journal message, gh-3732" } +host nginx[2833]: 2015/01/21 10:56:10 [error] 2833#0: *16336 open() "/var/www/site/cgi-bin/php4" failed (2: No such file or directory), client: 5.7.9.2, server: localhost, request: "GET /cgi-bin/php4 HTTP/1.1", host: "1.2.3.4" + +# failJSON: { "match": true, "host": "5.7.9.2", "desc": "systemd journal message, is not found variant, gh-3732" } +host nginx[2833]: 2015/01/21 15:02:27 [error] 2833#0: *16813 "/var/www/site/roundcube/" is not found (2: No such file or directory), client: 5.7.9.2, server: localhost, request: "GET /roundcube/ HTTP/1.1", host: "1.2.3.4" From 382b904e093dfb93b89adb834d66535c90844940 Mon Sep 17 00:00:00 2001 From: VXNCXNX Date: Fri, 14 Aug 2026 15:58:46 +0000 Subject: [PATCH 19/42] filter.d/apache-noscript: match a cgi-bin directory with no script name AH02811 lines can name the CGI directory itself rather than a script inside it: stderr from /srv/http/cgi-bin: script not found or unable to stat The script pattern required 'cgi-bin/', so a path ending in 'cgi-bin:' never matched. Use a word boundary instead. Closes gh-4040 --- fail2ban/tests/files/logs/apache-noscript | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fail2ban/tests/files/logs/apache-noscript b/fail2ban/tests/files/logs/apache-noscript index 0478cac9..cd48216c 100644 --- a/fail2ban/tests/files/logs/apache-noscript +++ b/fail2ban/tests/files/logs/apache-noscript @@ -26,3 +26,6 @@ # failJSON: { "time": "2024-12-18T23:58:03", "match": true , "host": "192.0.2.74", "desc": "script not found, changed log-format with stderr from (gh-3900)" } [Wed Dec 18 23:58:03.148113 2024] [cgi:error] [pid 16720:tid 1878] [client 192.0.2.74:35092] AH02811: stderr from /usr/lib/cgi-bin/luci: script not found or unable to stat + +# failJSON: { "time": "2025-07-30T16:43:26", "match": true , "host": "192.0.2.5", "desc": "stderr from a cgi-bin directory, no script name and no trailing slash (gh-4040)" } +[Wed Jul 30 16:43:26.968908 2025] [cgi:error] [pid 147397:tid 147442] [client 192.0.2.5:33570] AH02811: stderr from /srv/http/cgi-bin: script not found or unable to stat From a511f9e3eb02c57b1e23e1b1a5ae59eff7c1a99b Mon Sep 17 00:00:00 2001 From: VXNCXNX Date: Sat, 15 Aug 2026 16:30:55 +0200 Subject: [PATCH 20/42] filter.d/apache-noscript: no trailing slash for cgi-bin pattern + word boundary after `