Blob Blame History Raw
From 8dc6f30cdd855c41b80ebdde3fe2bc91cc94e594 Mon Sep 17 00:00:00 2001
From: sebres <serg.brester@sebres.de>
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 <HOST>$' % 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 = ^<lt_<logtype>/__prefix_line> failure from <HOST>$
+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