From 8dc6f30cdd855c41b80ebdde3fe2bc91cc94e594 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 15 Jan 2020 19:22:53 +0100 Subject: [PATCH] closes #2596: fixed supplying of backend-related `logtype` to the jail filter - don't merge it (provide as init parameter if not set in definition section), init parameters don't affect config-cache (better implementation as in #2387 and it covered now with new test) --- MANIFEST | 2 ++ fail2ban/client/configreader.py | 8 +++-- fail2ban/client/fail2banregex.py | 7 ++--- fail2ban/client/filterreader.py | 8 +++++ fail2ban/client/jailreader.py | 7 ++--- fail2ban/tests/clientreadertestcase.py | 17 +++++++++- .../tests/config/filter.d/checklogtype.conf | 31 +++++++++++++++++++ .../config/filter.d/checklogtype_test.conf | 12 +++++++ fail2ban/tests/config/jail.conf | 25 +++++++++++++++ 9 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 fail2ban/tests/config/filter.d/checklogtype.conf create mode 100644 fail2ban/tests/config/filter.d/checklogtype_test.conf --- a/MANIFEST +++ b/MANIFEST @@ -227,6 +227,8 @@ fail2ban/tests/clientreadertestcase.py fail2ban/tests/config/action.d/action.conf fail2ban/tests/config/action.d/brokenaction.conf fail2ban/tests/config/fail2ban.conf +fail2ban/tests/config/filter.d/checklogtype.conf +fail2ban/tests/config/filter.d/checklogtype_test.conf fail2ban/tests/config/filter.d/simple.conf fail2ban/tests/config/filter.d/test.conf fail2ban/tests/config/filter.d/test.local --- a/fail2ban/client/configreader.py +++ b/fail2ban/client/configreader.py @@ -120,6 +120,10 @@ class ConfigReader(): except AttributeError: return False + def has_option(self, sec, opt, withDefault=True): + return self._cfg.has_option(sec, opt) if withDefault \ + else opt in self._cfg._sections.get(sec, {}) + def merge_defaults(self, d): self._cfg.get_defaults().update(d) @@ -261,8 +265,8 @@ class ConfigReaderUnshared(SafeConfigPar logSys.warning("'%s' not defined in '%s'. Using default one: %r" % (optname, sec, optvalue)) values[optname] = optvalue - elif logSys.getEffectiveLevel() <= logLevel: - logSys.log(logLevel, "Non essential option '%s' not defined in '%s'.", optname, sec) + # elif logSys.getEffectiveLevel() <= logLevel: + # logSys.log(logLevel, "Non essential option '%s' not defined in '%s'.", optname, sec) except ValueError: logSys.warning("Wrong value for '" + optname + "' in '" + sec + "'. Using default one: '" + repr(optvalue) + "'") --- a/fail2ban/client/fail2banregex.py +++ b/fail2ban/client/fail2banregex.py @@ -372,11 +372,8 @@ class Fail2banRegex(object): if not ret: output( "ERROR: failed to load filter %s" % value ) return False - # overwrite default logtype (considering that the filter could specify this too in Definition/Init sections): - if not fltOpt.get('logtype'): - reader.merge_defaults({ - 'logtype': ['file','journal'][int(self._backend.startswith("systemd"))] - }) + # set backend-related options (logtype): + reader.applyAutoOptions(self._backend) # get, interpolate and convert options: reader.getOptions(None) # show real options if expected: --- a/fail2ban/client/filterreader.py +++ b/fail2ban/client/filterreader.py @@ -53,6 +53,14 @@ class FilterReader(DefinitionInitConfigR def getFile(self): return self.__file + def applyAutoOptions(self, backend): + # set init option to backend-related logtype, considering + # that the filter settings may be overwritten in its local: + if (not self._initOpts.get('logtype') and + not self.has_option('Definition', 'logtype', False) + ): + self._initOpts['logtype'] = ['file','journal'][int(backend.startswith("systemd"))] + def convert(self): stream = list() opts = self.getCombined() --- a/fail2ban/client/jailreader.py +++ b/fail2ban/client/jailreader.py @@ -149,11 +149,8 @@ class JailReader(ConfigReader): ret = self.__filter.read() if not ret: raise JailDefError("Unable to read the filter %r" % filterName) - if not filterOpt.get('logtype'): - # overwrite default logtype backend-related (considering that the filter settings may be overwritten): - self.__filter.merge_defaults({ - 'logtype': ['file','journal'][int(self.__opts.get('backend', '').startswith("systemd"))] - }) + # set backend-related options (logtype): + self.__filter.applyAutoOptions(self.__opts.get('backend', '')) # merge options from filter as 'known/...' (all options unfiltered): self.__filter.getOptions(self.__opts, all=True) ConfigReader.merge_section(self, self.__name, self.__filter.getCombined(), 'known/') --- a/fail2ban/tests/clientreadertestcase.py +++ b/fail2ban/tests/clientreadertestcase.py @@ -328,7 +328,22 @@ class JailReaderTest(LogCaptureTestCase) self.assertFalse(len(o) > 2 and o[2].endswith('regex')) i += 1 if i > usednsidx: break - + + def testLogTypeOfBackendInJail(self): + unittest.F2B.SkipIfCfgMissing(stock=True); # expected include of common.conf + # test twice to check cache works peoperly: + for i in (1, 2): + # backend-related, overwritten in definition, specified in init parameters: + for prefline in ('JRNL', 'FILE', 'TEST', 'INIT'): + jail = JailReader('checklogtype_'+prefline.lower(), basedir=IMPERFECT_CONFIG, + share_config=IMPERFECT_CONFIG_SHARE_CFG, force_enable=True) + self.assertTrue(jail.read()) + self.assertTrue(jail.getOptions()) + stream = jail.convert() + # 'JRNL' for systemd, 'FILE' for file backend, 'TEST' for custom logtype (overwrite it): + self.assertEqual([['set', jail.getName(), 'addfailregex', '^%s failure from $' % prefline]], + [o for o in stream if len(o) > 2 and o[2] == 'addfailregex']) + def testSplitOption(self): # Simple example option = "mail-whois[name=SSH]" --- /dev/null +++ b/fail2ban/tests/config/filter.d/checklogtype.conf @@ -0,0 +1,31 @@ +# Fail2Ban configuration file +# + +[INCLUDES] + +# Read common prefixes (logtype is set in default section) +before = ../../../../config/filter.d/common.conf + +[Definition] + +_daemon = test + +failregex = ^/__prefix_line> failure from $ +ignoreregex = + +# following sections define prefix line considering logtype: + +# backend-related (retrieved from backend, overwrite default): +[lt_file] +__prefix_line = FILE + +[lt_journal] +__prefix_line = JRNL + +# specified in definition section of filter (see filter checklogtype_test.conf): +[lt_test] +__prefix_line = TEST + +# specified in init parameter of jail (see ../jail.conf, jail checklogtype_init): +[lt_init] +__prefix_line = INIT --- /dev/null +++ b/fail2ban/tests/config/filter.d/checklogtype_test.conf @@ -0,0 +1,12 @@ +# Fail2Ban configuration file +# + +[INCLUDES] + +# Read common prefixes (logtype is set in default section) +before = checklogtype.conf + +[Definition] + +# overwrite logtype in definition (no backend anymore): +logtype = test \ No newline at end of file --- a/fail2ban/tests/config/jail.conf +++ b/fail2ban/tests/config/jail.conf @@ -74,3 +74,28 @@ journalmatch = _COMM=test maxlines = 2 usedns = no enabled = false + +[checklogtype_jrnl] +filter = checklogtype +backend = systemd +action = action +enabled = false + +[checklogtype_file] +filter = checklogtype +backend = polling +logpath = README.md +action = action +enabled = false + +[checklogtype_test] +filter = checklogtype_test +backend = systemd +action = action +enabled = false + +[checklogtype_init] +filter = checklogtype_test[logtype=init] +backend = systemd +action = action +enabled = false