From 78af48862f49ffa283a4844d798e418db64a8b89 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 23 Aug 2024 12:16:08 +0200 Subject: [PATCH 1/2] new jail option `skip_if_nologs` to ignore jail if no `logpath` matches found, fail2ban continue to start with warnings/errors, thus other jails become running; closes gh-2756 --- ChangeLog | 2 ++ fail2ban/client/jailreader.py | 13 +++++++++++-- fail2ban/tests/clientreadertestcase.py | 12 ++++++++++-- fail2ban/tests/config/jail.conf | 5 +++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index c8344d81..f32047d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,8 @@ ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition several log messages will be tagged with as originating from a process named "sshd-session" rather than "sshd" (gh-3782) ### New Features and Enhancements +* new jail option `skip_if_nologs` to ignore jail if no `logpath` matches found, fail2ban continue to start with warnings/errors, + thus other jails become running (gh-2756) * `action.d/*-ipset.conf`: - parameter `ipsettype` to set type of ipset, e. g. hash:ip, hash:net, etc (gh-3760) * `action.d/firewallcmd-rich-*.conf` - fixed incorrect quoting, disabling port variable expansion diff --git a/fail2ban/client/jailreader.py b/fail2ban/client/jailreader.py index e7242bfd..d3fa703f 100644 --- a/fail2ban/client/jailreader.py +++ b/fail2ban/client/jailreader.py @@ -116,11 +116,15 @@ class JailReader(ConfigReader): "logtimezone": ["string", None], "logencoding": ["string", None], "logpath": ["string", None], + "skip_if_nologs": ["bool", False], "action": ["string", ""] } _configOpts.update(FilterReader._configOpts) - _ignoreOpts = set(['action', 'filter', 'enabled', 'backend'] + list(FilterReader._configOpts.keys())) + _ignoreOpts = set( + ['action', 'filter', 'enabled', 'backend', 'skip_if_nologs'] + + list(FilterReader._configOpts.keys()) + ) def getOptions(self, addOpts=None): @@ -274,9 +278,14 @@ class JailReader(ConfigReader): ["set", self.__name, "addlogpath", p, tail]) if not found_files: msg = "Have not found any log file for %s jail" % self.__name - if not allow_no_files: + skip_if_nologs = self.__opts.get('skip_if_nologs', False) + if not allow_no_files and not skip_if_nologs: raise ValueError(msg) logSys.warning(msg) + if skip_if_nologs: + self.__opts['config-error'] = msg + stream = [['config-error', "Jail '%s' skipped, because of missing log files." % (self.__name,)]] + return stream elif opt == "ignoreip": stream.append(["set", self.__name, "addignoreip"] + splitwords(value)) elif opt not in JailReader._ignoreOpts: diff --git a/fail2ban/tests/clientreadertestcase.py b/fail2ban/tests/clientreadertestcase.py index 0388fd3d..02627978 100644 --- a/fail2ban/tests/clientreadertestcase.py +++ b/fail2ban/tests/clientreadertestcase.py @@ -733,6 +733,7 @@ class JailsReaderTest(LogCaptureTestCase): ['start', 'test-known-interp'], ['add', 'missinglogfiles', 'auto'], ['set', 'missinglogfiles', 'addfailregex', ''], + ['config-error', "Jail 'missinglogfiles_skip' skipped, because of missing log files."], ['add', 'brokenaction', 'auto'], ['set', 'brokenaction', 'addfailregex', ''], ['set', 'brokenaction', 'addaction', 'brokenaction'], @@ -1022,6 +1023,11 @@ filter = testfilter1 self.assertRaisesRegex(ValueError, r"Have not found any log file for .* jail", self._testLogPath, backend='polling') + def testLogPathSkipJailIfNoLogs(self): + s = self._testLogPath(backend='polling', skip_if_nologs=True) + self.assertLogged('Have not found any log file for') + self.assertEqual(s, [['config-error', "Jail 'testjail1' skipped, because of missing log files."]]) + def testLogPathSystemdBackend(self): try: # pragma: systemd no cover from ..server.filtersystemd import FilterSystemd @@ -1031,7 +1037,7 @@ filter = testfilter1 self._testLogPath(backend='systemd[journalflags=2]') @with_tmpdir - def _testLogPath(self, basedir, backend): + def _testLogPath(self, basedir, backend, skip_if_nologs=False): jailfd = open(os.path.join(basedir, "jail.conf"), 'w') jailfd.write(""" [testjail1] @@ -1043,8 +1049,10 @@ action = filter = failregex = test """ % (backend, basedir)) + if skip_if_nologs: + jailfd.write("skip_if_nologs = true\n") jailfd.close() jails = JailsReader(basedir=basedir) self.assertTrue(jails.read()) self.assertTrue(jails.getOptions()) - jails.convert() + return jails.convert() diff --git a/fail2ban/tests/config/jail.conf b/fail2ban/tests/config/jail.conf index b1a1707b..2a2a111b 100644 --- a/fail2ban/tests/config/jail.conf +++ b/fail2ban/tests/config/jail.conf @@ -23,6 +23,11 @@ failregex = %(known/failregex)s enabled = true logpath = /weapons/of/mass/destruction +[missinglogfiles_skip] +enabled = true +skip_if_nologs = true +logpath = /weapons/of/mass/destruction + [brokenactiondef] enabled = true action = joho[foo From 2950e41186e38e80303ad180df9b7fc090551197 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 23 Aug 2024 15:22:00 +0200 Subject: [PATCH 2/2] man/jail.conf.5: docu for skip_if_nologs --- man/jail.conf.5 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/man/jail.conf.5 b/man/jail.conf.5 index 363e996b..6998da1f 100644 --- a/man/jail.conf.5 +++ b/man/jail.conf.5 @@ -197,6 +197,9 @@ Optional space separated option 'tail' can be added to the end of the path to ca Ensure syslog or the program that generates the log file isn't configured to compress repeated log messages to "\fI*last message repeated 5 time*s\fR" otherwise it will fail to detect. This is called \fIRepeatedMsgReduction\fR in rsyslog and should be \fIOff\fR. .TP +.B skip_if_nologs +if no logpath matches found, skip the jail by start of fail2ban if \fIskip_if_nologs\fR set to true, otherwise (default: false) start of fail2ban will fail with an error "Have not found any log file". +.TP .B logencoding encoding of log files used for decoding. Default value of "auto" uses current system locale. .TP