mirror of https://github.com/fail2ban/fail2ban
Merge pull request #1619 from sebres/_0.10/skip-wrong-jails
commit
95dd76b7dd
|
@ -55,6 +55,8 @@ TODO: implementing of options resp. other tasks from PR #1346
|
||||||
banned in this jail, if option `--unban` specified
|
banned in this jail, if option `--unban` specified
|
||||||
- `unban --all` - unbans all IP addresses (in all jails and database)
|
- `unban --all` - unbans all IP addresses (in all jails and database)
|
||||||
- `unban <IP> ... <IP>` - unbans \<IP\> (in all jails and database) (see gh-1388)
|
- `unban <IP> ... <IP>` - unbans \<IP\> (in all jails and database) (see gh-1388)
|
||||||
|
- introduced new option `-t` or `--test` to test configuration resp. start server only
|
||||||
|
if configuration is clean (fails by wrong configured jails if option `-t` specified)
|
||||||
* New command action parameter `actionrepair` - command executed in order to restore
|
* New command action parameter `actionrepair` - command executed in order to restore
|
||||||
sane environment in error case of `actioncheck`.
|
sane environment in error case of `actioncheck`.
|
||||||
|
|
||||||
|
@ -119,6 +121,10 @@ fail2ban-client set loglevel INFO
|
||||||
- new replacement for `<ADDR>` in opposition to `<HOST>`, for separate
|
- new replacement for `<ADDR>` in opposition to `<HOST>`, for separate
|
||||||
usage of 2 address groups only (regardless of `usedns`), `ip4` and `ip6`
|
usage of 2 address groups only (regardless of `usedns`), `ip4` and `ip6`
|
||||||
together, without host (dns)
|
together, without host (dns)
|
||||||
|
* Misconfigured jails don't prevent fail2ban from starting, server starts
|
||||||
|
nevertheless, as long as one jail was successful configured (gh-1619)
|
||||||
|
Message about wrong jail configuration logged in client log (stdout, systemd
|
||||||
|
journal etc.) and in server log with error level
|
||||||
* fail2ban-testcases:
|
* fail2ban-testcases:
|
||||||
- `assertLogged` extended with parameter wait (to wait up to specified timeout,
|
- `assertLogged` extended with parameter wait (to wait up to specified timeout,
|
||||||
before we throw assert exception) + test cases rewritten using that
|
before we throw assert exception) + test cases rewritten using that
|
||||||
|
|
|
@ -72,9 +72,9 @@ class Configurator:
|
||||||
def getEarlyOptions(self):
|
def getEarlyOptions(self):
|
||||||
return self.__fail2ban.getEarlyOptions()
|
return self.__fail2ban.getEarlyOptions()
|
||||||
|
|
||||||
def getOptions(self, jail=None, updateMainOpt=None):
|
def getOptions(self, jail=None, updateMainOpt=None, ignoreWrong=True):
|
||||||
self.__fail2ban.getOptions(updateMainOpt)
|
self.__fail2ban.getOptions(updateMainOpt)
|
||||||
return self.__jails.getOptions(jail)
|
return self.__jails.getOptions(jail, ignoreWrong=ignoreWrong)
|
||||||
|
|
||||||
def convertToProtocol(self):
|
def convertToProtocol(self):
|
||||||
self.__streams["general"] = self.__fail2ban.convert()
|
self.__streams["general"] = self.__fail2ban.convert()
|
||||||
|
|
|
@ -125,7 +125,7 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
||||||
if client:
|
if client:
|
||||||
try :
|
try :
|
||||||
client.close()
|
client.close()
|
||||||
except Exception as e:
|
except Exception as e: # pragma: no cover
|
||||||
if showRet or self._conf["verbose"] > 1:
|
if showRet or self._conf["verbose"] > 1:
|
||||||
logSys.debug(e)
|
logSys.debug(e)
|
||||||
if showRet or c[0] == 'echo':
|
if showRet or c[0] == 'echo':
|
||||||
|
|
|
@ -47,6 +47,7 @@ class Fail2banCmdLine():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._argv = self._args = None
|
self._argv = self._args = None
|
||||||
self._configurator = None
|
self._configurator = None
|
||||||
|
self.cleanConfOnly = False
|
||||||
self.resetConf()
|
self.resetConf()
|
||||||
|
|
||||||
def resetConf(self):
|
def resetConf(self):
|
||||||
|
@ -101,6 +102,7 @@ class Fail2banCmdLine():
|
||||||
output(" --logtarget <FILE>|STDOUT|STDERR|SYSLOG")
|
output(" --logtarget <FILE>|STDOUT|STDERR|SYSLOG")
|
||||||
output(" --syslogsocket auto|<FILE>")
|
output(" --syslogsocket auto|<FILE>")
|
||||||
output(" -d dump configuration. For debugging")
|
output(" -d dump configuration. For debugging")
|
||||||
|
output(" -t, --test test configuration (can be also specified with start parameters)")
|
||||||
output(" -i interactive mode")
|
output(" -i interactive mode")
|
||||||
output(" -v increase verbosity")
|
output(" -v increase verbosity")
|
||||||
output(" -q decrease verbosity")
|
output(" -q decrease verbosity")
|
||||||
|
@ -136,6 +138,9 @@ class Fail2banCmdLine():
|
||||||
self._conf[ o[2:] ] = opt[1]
|
self._conf[ o[2:] ] = opt[1]
|
||||||
elif o == "-d":
|
elif o == "-d":
|
||||||
self._conf["dump"] = True
|
self._conf["dump"] = True
|
||||||
|
elif o == "-t" or o == "--test":
|
||||||
|
self.cleanConfOnly = True
|
||||||
|
self._conf["test"] = True
|
||||||
elif o == "-v":
|
elif o == "-v":
|
||||||
self._conf["verbose"] += 1
|
self._conf["verbose"] += 1
|
||||||
elif o == "-q":
|
elif o == "-q":
|
||||||
|
@ -173,8 +178,8 @@ class Fail2banCmdLine():
|
||||||
|
|
||||||
# Reads the command line options.
|
# Reads the command line options.
|
||||||
try:
|
try:
|
||||||
cmdOpts = 'hc:s:p:xfbdviqV'
|
cmdOpts = 'hc:s:p:xfbdtviqV'
|
||||||
cmdLongOpts = ['loglevel=', 'logtarget=', 'syslogsocket=', 'async', 'timeout=', 'help', 'version']
|
cmdLongOpts = ['loglevel=', 'logtarget=', 'syslogsocket=', 'test', 'async', 'timeout=', 'help', 'version']
|
||||||
optList, self._args = getopt.getopt(self._argv[1:], cmdOpts, cmdLongOpts)
|
optList, self._args = getopt.getopt(self._argv[1:], cmdOpts, cmdLongOpts)
|
||||||
except getopt.GetoptError:
|
except getopt.GetoptError:
|
||||||
self.dispUsage()
|
self.dispUsage()
|
||||||
|
@ -225,13 +230,30 @@ class Fail2banCmdLine():
|
||||||
logSys.info("Using pid file %s, [%s] logging to %s",
|
logSys.info("Using pid file %s, [%s] logging to %s",
|
||||||
self._conf["pidfile"], logging.getLevelName(llev), self._conf["logtarget"])
|
self._conf["pidfile"], logging.getLevelName(llev), self._conf["logtarget"])
|
||||||
|
|
||||||
|
readcfg = True
|
||||||
if self._conf.get("dump", False):
|
if self._conf.get("dump", False):
|
||||||
|
if readcfg:
|
||||||
ret, stream = self.readConfig()
|
ret, stream = self.readConfig()
|
||||||
|
readcfg = False
|
||||||
self.dumpConfig(stream)
|
self.dumpConfig(stream)
|
||||||
|
if not self._conf.get("test", False):
|
||||||
|
return ret
|
||||||
|
|
||||||
|
if self._conf.get("test", False):
|
||||||
|
if readcfg:
|
||||||
|
readcfg = False
|
||||||
|
ret, stream = self.readConfig()
|
||||||
|
if not ret:
|
||||||
|
raise ServerExecutionException("ERROR: test configuration failed")
|
||||||
|
# exit after test if no commands specified (test only):
|
||||||
|
if not len(self._args):
|
||||||
|
output("OK: configuration test is successful")
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
# Nothing to do here, process in client/server
|
# Nothing to do here, process in client/server
|
||||||
return None
|
return None
|
||||||
|
except ServerExecutionException:
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
output("ERROR: %s" % (e,))
|
output("ERROR: %s" % (e,))
|
||||||
if verbose > 2:
|
if verbose > 2:
|
||||||
|
@ -246,7 +268,8 @@ class Fail2banCmdLine():
|
||||||
try:
|
try:
|
||||||
self.configurator.Reload()
|
self.configurator.Reload()
|
||||||
self.configurator.readAll()
|
self.configurator.readAll()
|
||||||
ret = self.configurator.getOptions(jail, self._conf)
|
ret = self.configurator.getOptions(jail, self._conf,
|
||||||
|
ignoreWrong=not self.cleanConfOnly)
|
||||||
self.configurator.convertToProtocol()
|
self.configurator.convertToProtocol()
|
||||||
stream = self.configurator.getConfigStream()
|
stream = self.configurator.getConfigStream()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -144,6 +144,8 @@ class Fail2banServer(Fail2banCmdLine):
|
||||||
return cli
|
return cli
|
||||||
|
|
||||||
def start(self, argv):
|
def start(self, argv):
|
||||||
|
server = None
|
||||||
|
try:
|
||||||
# Command line options
|
# Command line options
|
||||||
ret = self.initCmdLine(argv)
|
ret = self.initCmdLine(argv)
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
|
@ -163,8 +165,6 @@ class Fail2banServer(Fail2banCmdLine):
|
||||||
return cli.start(argv)
|
return cli.start(argv)
|
||||||
|
|
||||||
# Start the server:
|
# Start the server:
|
||||||
server = None
|
|
||||||
try:
|
|
||||||
from ..server.utils import Utils
|
from ..server.utils import Utils
|
||||||
# background = True, if should be new process running in background, otherwise start in foreground
|
# background = True, if should be new process running in background, otherwise start in foreground
|
||||||
# process will be forked in daemonize, inside of Server module.
|
# process will be forked in daemonize, inside of Server module.
|
||||||
|
|
|
@ -118,16 +118,20 @@ class JailReader(ConfigReader):
|
||||||
defsec = self._cfg.get_defaults()
|
defsec = self._cfg.get_defaults()
|
||||||
defsec["fail2ban_version"] = version
|
defsec["fail2ban_version"] = version
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
# Read first options only needed for merge defaults ('known/...' from filter):
|
# Read first options only needed for merge defaults ('known/...' from filter):
|
||||||
self.__opts = ConfigReader.getOptions(self, self.__name, opts1st, shouldExist=True)
|
self.__opts = ConfigReader.getOptions(self, self.__name, opts1st, shouldExist=True)
|
||||||
if not self.__opts:
|
if not self.__opts: # pragma: no cover
|
||||||
return False
|
raise JailDefError("Init jail options failed")
|
||||||
|
|
||||||
if self.isEnabled():
|
if self.isEnabled():
|
||||||
# Read filter
|
# Read filter
|
||||||
if self.__opts["filter"]:
|
flt = self.__opts["filter"]
|
||||||
filterName, filterOpt = JailReader.extractOptions(
|
if flt:
|
||||||
self.__opts["filter"])
|
filterName, filterOpt = JailReader.extractOptions(flt)
|
||||||
|
if not filterName:
|
||||||
|
raise JailDefError("Invalid filter definition %r" % flt)
|
||||||
self.__filter = FilterReader(
|
self.__filter = FilterReader(
|
||||||
filterName, self.__name, filterOpt, share_config=self.share_config, basedir=self.getBaseDir())
|
filterName, self.__name, filterOpt, share_config=self.share_config, basedir=self.getBaseDir())
|
||||||
ret = self.__filter.read()
|
ret = self.__filter.read()
|
||||||
|
@ -135,16 +139,15 @@ class JailReader(ConfigReader):
|
||||||
self.__filter.getOptions(self.__opts)
|
self.__filter.getOptions(self.__opts)
|
||||||
ConfigReader.merge_section(self, self.__name, self.__filter.getCombined(), 'known/')
|
ConfigReader.merge_section(self, self.__name, self.__filter.getCombined(), 'known/')
|
||||||
if not ret:
|
if not ret:
|
||||||
logSys.error("Unable to read the filter")
|
raise JailDefError("Unable to read the filter %r" % filterName)
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
self.__filter = None
|
self.__filter = None
|
||||||
logSys.warning("No filter set for jail %s" % self.__name)
|
logSys.warning("No filter set for jail %s" % self.__name)
|
||||||
|
|
||||||
# Read second all options (so variables like %(known/param) can be interpolated):
|
# Read second all options (so variables like %(known/param) can be interpolated):
|
||||||
self.__opts = ConfigReader.getOptions(self, self.__name, opts)
|
self.__opts = ConfigReader.getOptions(self, self.__name, opts)
|
||||||
if not self.__opts:
|
if not self.__opts: # pragma: no cover
|
||||||
return False
|
raise JailDefError("Read jail options failed")
|
||||||
|
|
||||||
# cumulate filter options again (ignore given in jail):
|
# cumulate filter options again (ignore given in jail):
|
||||||
if self.__filter:
|
if self.__filter:
|
||||||
|
@ -156,6 +159,8 @@ class JailReader(ConfigReader):
|
||||||
if not act: # skip empty actions
|
if not act: # skip empty actions
|
||||||
continue
|
continue
|
||||||
actName, actOpt = JailReader.extractOptions(act)
|
actName, actOpt = JailReader.extractOptions(act)
|
||||||
|
if not actName:
|
||||||
|
raise JailDefError("Invalid action definition %r" % act)
|
||||||
if actName.endswith(".py"):
|
if actName.endswith(".py"):
|
||||||
self.__actions.append([
|
self.__actions.append([
|
||||||
"set",
|
"set",
|
||||||
|
@ -175,13 +180,22 @@ class JailReader(ConfigReader):
|
||||||
action.getOptions(self.__opts)
|
action.getOptions(self.__opts)
|
||||||
self.__actions.append(action)
|
self.__actions.append(action)
|
||||||
else:
|
else:
|
||||||
raise AttributeError("Unable to read action")
|
raise JailDefError("Unable to read action %r" % actName)
|
||||||
|
except JailDefError:
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logSys.error("Error in action definition " + act)
|
logSys.debug("Caught exception: %s", e, exc_info=True)
|
||||||
logSys.debug("Caught exception: %s" % (e,))
|
raise ValueError("Error in action definition %r: %r" % (act, e))
|
||||||
return False
|
|
||||||
if not len(self.__actions):
|
if not len(self.__actions):
|
||||||
logSys.warning("No actions were defined for %s" % self.__name)
|
logSys.warning("No actions were defined for %s" % self.__name)
|
||||||
|
|
||||||
|
except JailDefError as e:
|
||||||
|
e = str(e)
|
||||||
|
logSys.error(e)
|
||||||
|
if not self.__opts:
|
||||||
|
self.__opts = dict()
|
||||||
|
self.__opts['config-error'] = e
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def convert(self, allow_no_files=False):
|
def convert(self, allow_no_files=False):
|
||||||
|
@ -195,6 +209,10 @@ class JailReader(ConfigReader):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stream = []
|
stream = []
|
||||||
|
e = self.__opts.get('config-error')
|
||||||
|
if e:
|
||||||
|
stream.extend([['config-error', "Jail '%s' skipped, because of wrong configuration: %s" % (self.__name, e)]])
|
||||||
|
return stream
|
||||||
for opt, value in self.__opts.iteritems():
|
for opt, value in self.__opts.iteritems():
|
||||||
if opt == "logpath" and \
|
if opt == "logpath" and \
|
||||||
not self.__opts.get('backend', None).startswith("systemd"):
|
not self.__opts.get('backend', None).startswith("systemd"):
|
||||||
|
@ -264,3 +282,7 @@ class JailReader(ConfigReader):
|
||||||
val for val in optmatch.group(2,3,4) if val is not None][0]
|
val for val in optmatch.group(2,3,4) if val is not None][0]
|
||||||
option_opts[opt.strip()] = value.strip()
|
option_opts[opt.strip()] = value.strip()
|
||||||
return option_name, option_opts
|
return option_name, option_opts
|
||||||
|
|
||||||
|
|
||||||
|
class JailDefError(Exception):
|
||||||
|
pass
|
||||||
|
|
|
@ -54,7 +54,7 @@ class JailsReader(ConfigReader):
|
||||||
self.__jails = list()
|
self.__jails = list()
|
||||||
return ConfigReader.read(self, "jail")
|
return ConfigReader.read(self, "jail")
|
||||||
|
|
||||||
def getOptions(self, section=None):
|
def getOptions(self, section=None, ignoreWrong=True):
|
||||||
"""Reads configuration for jail(s) and adds enabled jails to __jails
|
"""Reads configuration for jail(s) and adds enabled jails to __jails
|
||||||
"""
|
"""
|
||||||
opts = []
|
opts = []
|
||||||
|
@ -66,7 +66,7 @@ class JailsReader(ConfigReader):
|
||||||
sections = [ section ]
|
sections = [ section ]
|
||||||
|
|
||||||
# Get the options of all jails.
|
# Get the options of all jails.
|
||||||
parse_status = True
|
parse_status = 0
|
||||||
for sec in sections:
|
for sec in sections:
|
||||||
if sec == 'INCLUDES':
|
if sec == 'INCLUDES':
|
||||||
continue
|
continue
|
||||||
|
@ -77,12 +77,16 @@ class JailsReader(ConfigReader):
|
||||||
ret = jail.getOptions()
|
ret = jail.getOptions()
|
||||||
if ret:
|
if ret:
|
||||||
if jail.isEnabled():
|
if jail.isEnabled():
|
||||||
|
# at least one jail was successful:
|
||||||
|
parse_status |= 1
|
||||||
# We only add enabled jails
|
# We only add enabled jails
|
||||||
self.__jails.append(jail)
|
self.__jails.append(jail)
|
||||||
else:
|
else:
|
||||||
logSys.error("Errors in jail %r. Skipping..." % sec)
|
logSys.error("Errors in jail %r.%s", sec, " Skipping..." if ignoreWrong else "")
|
||||||
parse_status = False
|
self.__jails.append(jail)
|
||||||
return parse_status
|
# at least one jail was invalid:
|
||||||
|
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):
|
||||||
"""Convert read before __opts and jails to the commands stream
|
"""Convert read before __opts and jails to the commands stream
|
||||||
|
@ -95,14 +99,12 @@ class JailsReader(ConfigReader):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stream = list()
|
stream = list()
|
||||||
for opt in self.__opts:
|
|
||||||
if opt == "":
|
|
||||||
stream.append([])
|
|
||||||
# Convert jails
|
# Convert jails
|
||||||
for jail in self.__jails:
|
for jail in self.__jails:
|
||||||
stream.extend(jail.convert(allow_no_files=allow_no_files))
|
stream.extend(jail.convert(allow_no_files=allow_no_files))
|
||||||
# Start jails
|
# Start jails
|
||||||
for jail in self.__jails:
|
for jail in self.__jails:
|
||||||
|
if not jail.options.get('config-error'):
|
||||||
stream.append(["start", jail.getName()])
|
stream.append(["start", jail.getName()])
|
||||||
|
|
||||||
return stream
|
return stream
|
||||||
|
|
|
@ -193,7 +193,7 @@ class Actions(JailThread, Mapping):
|
||||||
def setBanTime(self, value):
|
def setBanTime(self, value):
|
||||||
value = MyTime.str2seconds(value)
|
value = MyTime.str2seconds(value)
|
||||||
self.__banManager.setBanTime(value)
|
self.__banManager.setBanTime(value)
|
||||||
logSys.info("Set banTime = %s" % value)
|
logSys.info(" banTime: %s" % value)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the ban time.
|
# Get the ban time.
|
||||||
|
|
|
@ -241,7 +241,7 @@ class AsyncServer(asyncore.dispatcher):
|
||||||
def _remove_sock(self):
|
def _remove_sock(self):
|
||||||
try:
|
try:
|
||||||
os.remove(self.__sock)
|
os.remove(self.__sock)
|
||||||
except OSError as e:
|
except OSError as e: # pragma: no cover
|
||||||
if e.errno != errno.ENOENT:
|
if e.errno != errno.ENOENT:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,9 @@ class Transmitter:
|
||||||
return self.status(command[1:])
|
return self.status(command[1:])
|
||||||
elif command[0] == "version":
|
elif command[0] == "version":
|
||||||
return version.version
|
return version.version
|
||||||
|
elif command[0] == "config-error":
|
||||||
|
logSys.error(command[1])
|
||||||
|
return None
|
||||||
raise Exception("Invalid command")
|
raise Exception("Invalid command")
|
||||||
|
|
||||||
def __commandSet(self, command, multiple=False):
|
def __commandSet(self, command, multiple=False):
|
||||||
|
|
|
@ -170,7 +170,7 @@ class Utils():
|
||||||
time.sleep(Utils.DEFAULT_SLEEP_INTERVAL)
|
time.sleep(Utils.DEFAULT_SLEEP_INTERVAL)
|
||||||
retcode = popen.poll()
|
retcode = popen.poll()
|
||||||
#logSys.debug("%s -- killed %s ", realCmd, retcode)
|
#logSys.debug("%s -- killed %s ", realCmd, retcode)
|
||||||
if retcode is None and not Utils.pid_exists(pgid):
|
if retcode is None and not Utils.pid_exists(pgid): # pragma: no cover
|
||||||
retcode = signal.SIGKILL
|
retcode = signal.SIGKILL
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
stderr = "%s -- failed with %s" % (realCmd, e)
|
stderr = "%s -- failed with %s" % (realCmd, e)
|
||||||
|
|
|
@ -193,13 +193,15 @@ class JailReaderTest(LogCaptureTestCase):
|
||||||
self.assertTrue(jail.read())
|
self.assertTrue(jail.read())
|
||||||
self.assertFalse(jail.getOptions())
|
self.assertFalse(jail.getOptions())
|
||||||
self.assertTrue(jail.isEnabled())
|
self.assertTrue(jail.isEnabled())
|
||||||
self.assertLogged('Error in action definition joho[foo')
|
self.assertLogged("Invalid action definition 'joho[foo'")
|
||||||
# This unittest has been deactivated for some time...
|
|
||||||
# self.assertLogged(
|
def testJailFilterBrokenDef(self):
|
||||||
# 'Caught exception: While reading action joho[foo we should have got 1 or 2 groups. Got: 0')
|
jail = JailReader('brokenfilterdef', basedir=IMPERFECT_CONFIG,
|
||||||
# let's test for what is actually logged and handle changes in the future
|
share_config=IMPERFECT_CONFIG_SHARE_CFG)
|
||||||
self.assertLogged(
|
self.assertTrue(jail.read())
|
||||||
"Caught exception: 'NoneType' object has no attribute 'endswith'")
|
self.assertFalse(jail.getOptions())
|
||||||
|
self.assertTrue(jail.isEnabled())
|
||||||
|
self.assertLogged("Invalid filter definition 'flt[test'")
|
||||||
|
|
||||||
if STOCK:
|
if STOCK:
|
||||||
def testStockSSHJail(self):
|
def testStockSSHJail(self):
|
||||||
|
@ -496,7 +498,7 @@ class JailsReaderTest(LogCaptureTestCase):
|
||||||
def testReadTestJailConf(self):
|
def testReadTestJailConf(self):
|
||||||
jails = JailsReader(basedir=IMPERFECT_CONFIG, share_config=IMPERFECT_CONFIG_SHARE_CFG)
|
jails = JailsReader(basedir=IMPERFECT_CONFIG, share_config=IMPERFECT_CONFIG_SHARE_CFG)
|
||||||
self.assertTrue(jails.read())
|
self.assertTrue(jails.read())
|
||||||
self.assertFalse(jails.getOptions())
|
self.assertFalse(jails.getOptions(ignoreWrong=False))
|
||||||
self.assertRaises(ValueError, jails.convert)
|
self.assertRaises(ValueError, jails.convert)
|
||||||
comm_commands = jails.convert(allow_no_files=True)
|
comm_commands = jails.convert(allow_no_files=True)
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
|
@ -525,8 +527,18 @@ class JailsReaderTest(LogCaptureTestCase):
|
||||||
['start', 'emptyaction'],
|
['start', 'emptyaction'],
|
||||||
['start', 'missinglogfiles'],
|
['start', 'missinglogfiles'],
|
||||||
['start', 'brokenaction'],
|
['start', 'brokenaction'],
|
||||||
['start', 'parse_to_end_of_jail.conf'],]))
|
['start', 'parse_to_end_of_jail.conf'],
|
||||||
self.assertLogged("Errors in jail 'missingbitsjail'. Skipping...")
|
['config-error',
|
||||||
|
"Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo'"],
|
||||||
|
['config-error',
|
||||||
|
"Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test'"],
|
||||||
|
['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.assertLogged("Errors in jail 'missingbitsjail'.")
|
||||||
|
self.assertNotLogged("Skipping...")
|
||||||
self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction")
|
self.assertLogged("No file(s) found for glob /weapons/of/mass/destruction")
|
||||||
|
|
||||||
if STOCK:
|
if STOCK:
|
||||||
|
|
|
@ -27,10 +27,18 @@ logpath = /weapons/of/mass/destruction
|
||||||
enabled = true
|
enabled = true
|
||||||
action = joho[foo
|
action = joho[foo
|
||||||
|
|
||||||
|
[brokenfilterdef]
|
||||||
|
enabled = true
|
||||||
|
filter = flt[test
|
||||||
|
|
||||||
[brokenaction]
|
[brokenaction]
|
||||||
enabled = true
|
enabled = true
|
||||||
action = brokenaction
|
action = brokenaction
|
||||||
|
|
||||||
|
[missingaction]
|
||||||
|
enabled = true
|
||||||
|
action = noactionfileforthisaction
|
||||||
|
|
||||||
[missingbitsjail]
|
[missingbitsjail]
|
||||||
enabled = true
|
enabled = true
|
||||||
filter = catchallthebadies
|
filter = catchallthebadies
|
||||||
|
|
|
@ -675,6 +675,36 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
os.remove(pjoin(tmp, "f2b.sock"))
|
os.remove(pjoin(tmp, "f2b.sock"))
|
||||||
|
|
||||||
|
@with_tmpdir
|
||||||
|
@with_kill_srv
|
||||||
|
def testServerTestFailStart(self, tmp):
|
||||||
|
# started directly here, so prevent overwrite test cases logger with "INHERITED"
|
||||||
|
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||||
|
cfg = pjoin(tmp, "config")
|
||||||
|
|
||||||
|
# test configuration is correct:
|
||||||
|
self.pruneLog("[test-phase 0]")
|
||||||
|
self.execSuccess(startparams, "--test")
|
||||||
|
self.assertLogged("OK: configuration test is successful")
|
||||||
|
|
||||||
|
# append one wrong configured jail:
|
||||||
|
_write_file(pjoin(cfg, "jail.conf"), "a", "", "[broken-jail]",
|
||||||
|
"", "filter = broken-jail-filter", "enabled = true")
|
||||||
|
|
||||||
|
# first try test config:
|
||||||
|
self.pruneLog("[test-phase 0a]")
|
||||||
|
self.execFailed(startparams, "--test")
|
||||||
|
self.assertLogged("Unable to read the filter 'broken-jail-filter'",
|
||||||
|
"Errors in jail 'broken-jail'.",
|
||||||
|
"ERROR: test configuration failed", all=True)
|
||||||
|
|
||||||
|
# failed to start with test config:
|
||||||
|
self.pruneLog("[test-phase 0b]")
|
||||||
|
self.execFailed(startparams, "-t", "start")
|
||||||
|
self.assertLogged("Unable to read the filter 'broken-jail-filter'",
|
||||||
|
"Errors in jail 'broken-jail'.",
|
||||||
|
"ERROR: test configuration failed", all=True)
|
||||||
|
|
||||||
@with_tmpdir
|
@with_tmpdir
|
||||||
def testKillAfterStart(self, tmp):
|
def testKillAfterStart(self, tmp):
|
||||||
try:
|
try:
|
||||||
|
@ -768,6 +798,10 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
||||||
_write_action_cfg(actname="test-action2")
|
_write_action_cfg(actname="test-action2")
|
||||||
|
|
||||||
_write_jail_cfg(enabled=[1], actions=[1,2])
|
_write_jail_cfg(enabled=[1], actions=[1,2])
|
||||||
|
# append one wrong configured jail:
|
||||||
|
_write_file(pjoin(cfg, "jail.conf"), "a", "", "[broken-jail]",
|
||||||
|
"", "filter = broken-jail-filter", "enabled = true")
|
||||||
|
|
||||||
_write_file(test1log, "w", *((str(int(MyTime.time())) + " failure 401 from 192.0.2.1: test 1",) * 3))
|
_write_file(test1log, "w", *((str(int(MyTime.time())) + " failure 401 from 192.0.2.1: test 1",) * 3))
|
||||||
_write_file(test2log, "w")
|
_write_file(test2log, "w")
|
||||||
_write_file(test3log, "w")
|
_write_file(test3log, "w")
|
||||||
|
@ -787,6 +821,12 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
||||||
"stdout: '[test-jail1] test-action1: ** start'",
|
"stdout: '[test-jail1] test-action1: ** start'",
|
||||||
"stdout: '[test-jail1] test-action2: ** start'", all=True)
|
"stdout: '[test-jail1] test-action2: ** start'", all=True)
|
||||||
|
|
||||||
|
# broken jail was logged (in client and server log):
|
||||||
|
self.assertLogged(
|
||||||
|
"Unable to read the filter 'broken-jail-filter'",
|
||||||
|
"Errors in jail 'broken-jail'. Skipping...",
|
||||||
|
"Jail 'broken-jail' skipped, because of wrong configuration", all=True)
|
||||||
|
|
||||||
# enable both jails, 3 logs for jail1, etc...
|
# enable both jails, 3 logs for jail1, etc...
|
||||||
# truncate test-log - we should not find unban/ban again by reload:
|
# truncate test-log - we should not find unban/ban again by reload:
|
||||||
self.pruneLog("[test-phase 1b]")
|
self.pruneLog("[test-phase 1b]")
|
||||||
|
|
Loading…
Reference in New Issue