mirror of https://github.com/fail2ban/fail2ban
implements the feature of automatic switch `backend = auto` to backend `systemd`, when:
- no files matching `logpath` found for this jail; - no `systemd_if_nologs = false` (`true` by default) is specified for the jail; - option `journalmatch` is set for the jail or its filter (otherwise it'd be too heavy to allow all auto-jails, even if they have never been foreseen for journal); - option `skip_if_nologs` will be ignored if we could switch backend to `systemd`; closes gh-3768pull/3927/merge
parent
5a2fd9b31c
commit
b2352f113e
|
@ -117,12 +117,13 @@ class JailReader(ConfigReader):
|
|||
"logencoding": ["string", None],
|
||||
"logpath": ["string", None],
|
||||
"skip_if_nologs": ["bool", False],
|
||||
"systemd_if_nologs": ["bool", True],
|
||||
"action": ["string", ""]
|
||||
}
|
||||
_configOpts.update(FilterReader._configOpts)
|
||||
|
||||
_ignoreOpts = set(
|
||||
['action', 'filter', 'enabled', 'backend', 'skip_if_nologs'] +
|
||||
['action', 'filter', 'enabled', 'backend', 'skip_if_nologs', 'systemd_if_nologs'] +
|
||||
list(FilterReader._configOpts.keys())
|
||||
)
|
||||
|
||||
|
@ -239,7 +240,7 @@ class JailReader(ConfigReader):
|
|||
return self.__opts
|
||||
return _merge_dicts(self.__opts, self.__filter.getCombined())
|
||||
|
||||
def convert(self, allow_no_files=False):
|
||||
def convert(self, allow_no_files=False, systemd_if_nologs=True):
|
||||
"""Convert read before __opts to the commands stream
|
||||
|
||||
Parameters
|
||||
|
@ -277,14 +278,25 @@ class JailReader(ConfigReader):
|
|||
stream2.append(
|
||||
["set", self.__name, "addlogpath", p, tail])
|
||||
if not found_files:
|
||||
msg = "Have not found any log file for %s jail" % self.__name
|
||||
msg = "Have not found any log file for '%s' jail." % self.__name
|
||||
skip_if_nologs = self.__opts.get('skip_if_nologs', False)
|
||||
if not allow_no_files and not skip_if_nologs:
|
||||
# if auto and we can switch to systemd backend (only possible if jail have journalmatch):
|
||||
if backend.startswith("auto") and systemd_if_nologs and (
|
||||
self.__opts.get('systemd_if_nologs', True) and
|
||||
self.__opts.get('journalmatch', None) is not None
|
||||
):
|
||||
# switch backend to systemd:
|
||||
backend = 'systemd'
|
||||
msg += " Jail will monitor systemd journal."
|
||||
skip_if_nologs = False
|
||||
elif 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,)]]
|
||||
self.__opts['runtime-error'] = msg
|
||||
msg = "Jail '%s' skipped, because of missing log files." % (self.__name,)
|
||||
logSys.warning(msg)
|
||||
stream = [['config-error', msg]]
|
||||
return stream
|
||||
elif opt == "ignoreip":
|
||||
stream.append(["set", self.__name, "addignoreip"] + splitwords(value))
|
||||
|
|
|
@ -88,7 +88,7 @@ class JailsReader(ConfigReader):
|
|||
parse_status |= 2
|
||||
return ((ignoreWrong and parse_status & 1) or not (parse_status & 2))
|
||||
|
||||
def convert(self, allow_no_files=False):
|
||||
def convert(self, allow_no_files=False, systemd_if_nologs=True):
|
||||
"""Convert read before __opts and jails to the commands stream
|
||||
|
||||
Parameters
|
||||
|
@ -101,11 +101,14 @@ class JailsReader(ConfigReader):
|
|||
stream = list()
|
||||
# Convert jails
|
||||
for jail in self.__jails:
|
||||
stream.extend(jail.convert(allow_no_files=allow_no_files))
|
||||
stream.extend(jail.convert(allow_no_files, systemd_if_nologs))
|
||||
# Start jails
|
||||
for jail in self.__jails:
|
||||
if not jail.options.get('config-error'):
|
||||
if not jail.options.get('config-error') and not jail.options.get('runtime-error'):
|
||||
stream.append(["start", jail.getName()])
|
||||
else:
|
||||
# just delete rtm-errors (to check next time if cached)
|
||||
jail.options.pop('runtime-error', None)
|
||||
|
||||
return stream
|
||||
|
||||
|
|
|
@ -719,51 +719,67 @@ class JailsReaderTest(LogCaptureTestCase):
|
|||
jails = JailsReader(basedir=IMPERFECT_CONFIG, share_config=IMPERFECT_CONFIG_SHARE_CFG)
|
||||
self.assertTrue(jails.read())
|
||||
self.assertFalse(jails.getOptions(ignoreWrong=False))
|
||||
self.assertRaises(ValueError, jails.convert)
|
||||
comm_commands = jails.convert(allow_no_files=True)
|
||||
self.maxDiff = None
|
||||
self.assertSortedEqual(comm_commands,
|
||||
[['add', 'emptyaction', 'auto'],
|
||||
['add', 'test-known-interp', 'auto'],
|
||||
['multi-set', 'test-known-interp', 'addfailregex', [
|
||||
'failure test 1 (filter.d/test.conf) <HOST>',
|
||||
'failure test 2 (filter.d/test.local) <HOST>',
|
||||
'failure test 3 (jail.local) <HOST>'
|
||||
]],
|
||||
['start', 'test-known-interp'],
|
||||
['add', 'missinglogfiles', 'auto'],
|
||||
['set', 'missinglogfiles', 'addfailregex', '<IP>'],
|
||||
['config-error', "Jail 'missinglogfiles_skip' skipped, because of missing log files."],
|
||||
['add', 'brokenaction', 'auto'],
|
||||
['set', 'brokenaction', 'addfailregex', '<IP>'],
|
||||
['set', 'brokenaction', 'addaction', 'brokenaction'],
|
||||
['multi-set', 'brokenaction', 'action', 'brokenaction', [
|
||||
['actionban', 'hit with big stick <ip>'],
|
||||
['actname', 'brokenaction'],
|
||||
['name', 'brokenaction']
|
||||
]],
|
||||
['add', 'parse_to_end_of_jail.conf', 'auto'],
|
||||
['set', 'parse_to_end_of_jail.conf', 'addfailregex', '<IP>'],
|
||||
['set', 'tz_correct', 'addfailregex', '<IP>'],
|
||||
['set', 'tz_correct', 'logtimezone', 'UTC+0200'],
|
||||
['start', 'emptyaction'],
|
||||
['start', 'missinglogfiles'],
|
||||
['start', 'brokenaction'],
|
||||
['start', 'parse_to_end_of_jail.conf'],
|
||||
['add', 'tz_correct', 'auto'],
|
||||
['start', 'tz_correct'],
|
||||
['config-error',
|
||||
"Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo': unexpected option syntax"],
|
||||
['config-error',
|
||||
"Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test': unexpected option syntax"],
|
||||
['config-error',
|
||||
"Jail 'missingaction' skipped, because of wrong configuration: Unable to read action 'noactionfileforthisaction'"],
|
||||
['config-error',
|
||||
"Jail 'missingbitsjail' skipped, because of wrong configuration: Unable to read the filter 'catchallthebadies'"],
|
||||
])
|
||||
self.assertRaises(ValueError, lambda: jails.convert(systemd_if_nologs=False))
|
||||
self.assertLogged("Errors in jail 'missingbitsjail'.")
|
||||
self.assertNotLogged("Skipping...")
|
||||
# check with allow no files (just to cover other jail problems), but without switch to systemd:
|
||||
self.pruneLog('[test-phase] allow no files, no switch to systemd ...')
|
||||
comm_commands = jails.convert(allow_no_files=True, systemd_if_nologs=False)
|
||||
self.maxDiff = None
|
||||
def _checkStream(comm_commands, backend='auto'):
|
||||
self.assertSortedEqual(comm_commands,
|
||||
[['add', 'emptyaction', 'auto'],
|
||||
['add', 'test-known-interp', 'auto'],
|
||||
['multi-set', 'test-known-interp', 'addfailregex', [
|
||||
'failure test 1 (filter.d/test.conf) <HOST>',
|
||||
'failure test 2 (filter.d/test.local) <HOST>',
|
||||
'failure test 3 (jail.local) <HOST>'
|
||||
]],
|
||||
['start', 'test-known-interp'],
|
||||
['add', 'missinglogfiles', backend], # can switch backend because have journalmatch
|
||||
['set', 'missinglogfiles', 'addfailregex', '<IP>'],
|
||||
['set', 'missinglogfiles', 'addjournalmatch', '_COMM=test'],
|
||||
['config-error', "Jail 'missinglogfiles_skip' skipped, because of missing log files."],
|
||||
['add', 'brokenaction', 'auto'],
|
||||
['set', 'brokenaction', 'addfailregex', '<IP>'],
|
||||
['set', 'brokenaction', 'addaction', 'brokenaction'],
|
||||
['multi-set', 'brokenaction', 'action', 'brokenaction', [
|
||||
['actionban', 'hit with big stick <ip>'],
|
||||
['actname', 'brokenaction'],
|
||||
['name', 'brokenaction']
|
||||
]],
|
||||
['add', 'parse_to_end_of_jail.conf', 'auto'],
|
||||
['set', 'parse_to_end_of_jail.conf', 'addfailregex', '<IP>'],
|
||||
['set', 'tz_correct', 'addfailregex', '<IP>'],
|
||||
['set', 'tz_correct', 'logtimezone', 'UTC+0200'],
|
||||
['start', 'emptyaction'],
|
||||
['start', 'missinglogfiles'],
|
||||
['start', 'brokenaction'],
|
||||
['start', 'parse_to_end_of_jail.conf'],
|
||||
['add', 'tz_correct', 'auto'],
|
||||
['start', 'tz_correct'],
|
||||
['config-error',
|
||||
"Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo': unexpected option syntax"],
|
||||
['config-error',
|
||||
"Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test': unexpected option syntax"],
|
||||
['config-error',
|
||||
"Jail 'missingaction' skipped, because of wrong configuration: Unable to read action 'noactionfileforthisaction'"],
|
||||
['config-error',
|
||||
"Jail 'missingbitsjail' skipped, because of wrong configuration: Unable to read the filter 'catchallthebadies'"],
|
||||
])
|
||||
_checkStream(comm_commands, backend='auto')
|
||||
self.assertNotLogged("Have not found any log file for 'missinglogfiles' jail. Jail will monitor systemd journal.")
|
||||
self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction")
|
||||
self.assertLogged("Jail 'missinglogfiles_skip' skipped, because of missing log files.")
|
||||
# switch backend auto to systemd if no files found, note that jail "missinglogfiles_skip" will be skipped yet,
|
||||
# because for this jail configured skip_if_nologs = true, all other jails shall switch to systemd with warning
|
||||
self.pruneLog('[test-phase] auto -> systemd')
|
||||
comm_commands = jails.convert(allow_no_files=True)
|
||||
_checkStream(comm_commands, backend='systemd')
|
||||
self.assertNotLogged("Errors in jail 'missingbitsjail'.")
|
||||
self.assertLogged("Have not found any log file for 'missinglogfiles' jail. Jail will monitor systemd journal.")
|
||||
self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction")
|
||||
self.assertLogged("Jail 'missinglogfiles_skip' skipped, because of missing log files.")
|
||||
|
||||
def testReadStockActionConf(self):
|
||||
unittest.F2B.SkipIfCfgMissing(stock=True)
|
||||
|
|
|
@ -21,6 +21,7 @@ failregex = %(known/failregex)s
|
|||
|
||||
[missinglogfiles]
|
||||
enabled = true
|
||||
journalmatch = _COMM=test ;# allow to switch to systemd (by backend = `auto` and no logs found)
|
||||
logpath = /weapons/of/mass/destruction
|
||||
|
||||
[missinglogfiles_skip]
|
||||
|
|
Loading…
Reference in New Issue