mirror of https://github.com/fail2ban/fail2ban
reader bug fix: prevent to silent "load" of not existing jail;
coverage of test cases increased;pull/1321/head
parent
4ec70d7851
commit
0fef5022f0
|
@ -208,7 +208,7 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
|||
# 1 -> the name of the option
|
||||
# 2 -> the default value for the option
|
||||
|
||||
def getOptions(self, sec, options, pOptions=None):
|
||||
def getOptions(self, sec, options, pOptions=None, shouldExist=False):
|
||||
values = dict()
|
||||
for option in options:
|
||||
try:
|
||||
|
@ -222,6 +222,8 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
|||
continue
|
||||
values[option[1]] = v
|
||||
except NoSectionError, e:
|
||||
if shouldExist:
|
||||
raise
|
||||
# No "Definition" section or wrong basedir
|
||||
logSys.error(e)
|
||||
values[option[1]] = option[2]
|
||||
|
|
|
@ -64,7 +64,7 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
output("and bans the corresponding IP addresses using firewall rules.")
|
||||
output("")
|
||||
|
||||
def __sigTERMhandler(self, signum, frame):
|
||||
def __sigTERMhandler(self, signum, frame): # pragma: no cover
|
||||
# Print a new line because we probably come from wait
|
||||
output("")
|
||||
logSys.warning("Caught signal %d. Exiting" % signum)
|
||||
|
@ -141,7 +141,7 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
logSys.error("Failed to access socket path: %s."
|
||||
" Is fail2ban running?",
|
||||
self._conf["socket"])
|
||||
except Exception as e:
|
||||
except Exception as e: # pragma: no cover
|
||||
logSys.error("Exception while checking socket access: %s",
|
||||
self._conf["socket"])
|
||||
logSys.error(e)
|
||||
|
@ -165,7 +165,7 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
"There is no directory %s to contain the socket file %s."
|
||||
% (socket_dir, self._conf["socket"]))
|
||||
return None
|
||||
if not os.access(socket_dir, os.W_OK | os.X_OK):
|
||||
if not os.access(socket_dir, os.W_OK | os.X_OK): # pragma: no cover
|
||||
logSys.error(
|
||||
"Directory %s exists but not accessible for writing"
|
||||
% (socket_dir,))
|
||||
|
@ -204,9 +204,9 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
# Start server direct here in main thread (not fork):
|
||||
self._server = Fail2banServer.startServerDirect(self._conf, False)
|
||||
|
||||
except ExitException:
|
||||
except ExitException: # pragma: no cover
|
||||
pass
|
||||
except Exception as e:
|
||||
except Exception as e: # pragma: no cover
|
||||
output("")
|
||||
logSys.error("Exception while starting server " + ("background" if background else "foreground"))
|
||||
if self._conf["verbose"] > 1:
|
||||
|
@ -259,7 +259,7 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
if self._conf.get("interactive", False):
|
||||
output(' ## stop ... ')
|
||||
self.__processCommand(['stop'])
|
||||
if not self.__waitOnServer(False):
|
||||
if not self.__waitOnServer(False): # pragma: no cover
|
||||
logSys.error("Could not stop server")
|
||||
return False
|
||||
# in interactive mode reset config, to make full-reload if there something changed:
|
||||
|
@ -298,12 +298,12 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
def __processStartStreamAfterWait(self, *args):
|
||||
try:
|
||||
# Wait for the server to start
|
||||
if not self.__waitOnServer():
|
||||
if not self.__waitOnServer(): # pragma: no cover
|
||||
logSys.error("Could not find server, waiting failed")
|
||||
return False
|
||||
# Configure the server
|
||||
self.__processCmd(*args)
|
||||
except ServerExecutionException as e:
|
||||
except ServerExecutionException as e: # pragma: no cover
|
||||
if self._conf["verbose"] > 1:
|
||||
logSys.exception(e)
|
||||
logSys.error("Could not start server. Maybe an old "
|
||||
|
@ -385,12 +385,12 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
elif not cmd == "":
|
||||
try:
|
||||
self.__processCommand(shlex.split(cmd))
|
||||
except Exception, e:
|
||||
except Exception, e: # pragma: no cover
|
||||
if self._conf["verbose"] > 1:
|
||||
logSys.exception(e)
|
||||
else:
|
||||
logSys.error(e)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
except (EOFError, KeyboardInterrupt): # pragma: no cover
|
||||
output("")
|
||||
raise
|
||||
# Single command mode
|
||||
|
|
|
@ -56,7 +56,7 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
server.start(conf["socket"],
|
||||
conf["pidfile"], conf["force"],
|
||||
conf=conf)
|
||||
except Exception as e:
|
||||
except Exception as e: # pragma: no cover
|
||||
try:
|
||||
if server:
|
||||
server.quit()
|
||||
|
@ -77,7 +77,7 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
# Forks the current process, don't fork if async specified (ex: test cases)
|
||||
pid = 0
|
||||
frk = not conf["async"] and PRODUCTION
|
||||
if frk:
|
||||
if frk: # pragma: no cover
|
||||
pid = os.fork()
|
||||
logSys.debug("-- async starting of server in %s, fork: %s - %s", os.getpid(), frk, pid)
|
||||
if pid == 0:
|
||||
|
@ -108,22 +108,20 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
exe = sys.executable
|
||||
args[0:0] = [exe]
|
||||
logSys.debug("Starting %r with args %r", exe, args)
|
||||
if frk:
|
||||
return os.execv(exe, args)
|
||||
if frk: # pragma: no cover
|
||||
os.execv(exe, args)
|
||||
else:
|
||||
# use P_WAIT instead of P_NOWAIT (to prevent defunct-zomby process), it startet as daemon, so parent exit fast after fork):
|
||||
ret = os.spawnv(os.P_WAIT, exe, args)
|
||||
if ret != 0:
|
||||
if ret != 0: # pragma: no cover
|
||||
raise OSError(ret, "Unknown error by executing server %r with %r" % (args[1], exe))
|
||||
return 0
|
||||
except OSError as e: # pragma: no cover
|
||||
if not frk: #not PRODUCTION:
|
||||
raise
|
||||
# Use the PATH env.
|
||||
logSys.warning("Initial start attempt failed (%s). Starting %r with the same args", e, SERVER)
|
||||
if frk:
|
||||
return os.execvp(SERVER, args)
|
||||
return pid
|
||||
if frk: # pragma: no cover
|
||||
os.execvp(SERVER, args)
|
||||
|
||||
@staticmethod
|
||||
def getServerPath():
|
||||
|
@ -189,7 +187,7 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
pid = os.getpid()
|
||||
server = Fail2banServer.startServerDirect(self._conf, background)
|
||||
# If forked - just exit other processes
|
||||
if pid != os.getpid():
|
||||
if pid != os.getpid(): # pragma: no cover
|
||||
os._exit(0)
|
||||
if cli:
|
||||
cli._server = server
|
||||
|
@ -198,7 +196,7 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
if not async and cli:
|
||||
Utils.wait_for(lambda: phase.get('done', None) is not None, self._conf["timeout"])
|
||||
if not phase.get('done', False):
|
||||
if server:
|
||||
if server: # pragma: no cover
|
||||
server.quit()
|
||||
exit(-1)
|
||||
logSys.debug('Starting server done')
|
||||
|
@ -206,7 +204,9 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
except Exception, e:
|
||||
if self._conf["verbose"] > 1:
|
||||
logSys.exception(e)
|
||||
if server:
|
||||
else:
|
||||
logSys.error(e)
|
||||
if server: # pragma: no cover
|
||||
server.quit()
|
||||
exit(-1)
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ class JailReader(ConfigReader):
|
|||
["string", "action", ""]]
|
||||
|
||||
# Read first options only needed for merge defaults ('known/...' from filter):
|
||||
self.__opts = ConfigReader.getOptions(self, self.__name, opts1st)
|
||||
self.__opts = ConfigReader.getOptions(self, self.__name, opts1st, shouldExist=True)
|
||||
if not self.__opts:
|
||||
return False
|
||||
|
||||
|
|
|
@ -347,6 +347,21 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
|||
self.assertLogged("Server ready")
|
||||
self.assertLogged("Exit with code 0")
|
||||
self.pruneLog()
|
||||
# test reload missing jail (interactive):
|
||||
INTERACT += [
|
||||
"reload ~~unknown~jail~fail~~",
|
||||
"exit"
|
||||
]
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("-i",))
|
||||
self.assertLogged("Failed during configuration: No section: '~~unknown~jail~fail~~'")
|
||||
self.pruneLog()
|
||||
# test reload missing jail (direct):
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("reload", "~~unknown~jail~fail~~"))
|
||||
self.assertLogged("Failed during configuration: No section: '~~unknown~jail~fail~~'")
|
||||
self.assertLogged("Exit with code -1")
|
||||
self.pruneLog()
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
|
@ -425,6 +440,12 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
|||
self.assertLogged("There is no directory " + tmp+"/miss" + " to contain the socket file")
|
||||
self.pruneLog()
|
||||
|
||||
## not running
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT, "-c", tmp+"/config", "-s", tmp+"/f2b.sock", "reload",))
|
||||
self.assertLogged("Could not find server")
|
||||
self.pruneLog()
|
||||
|
||||
## already exists:
|
||||
open(tmp+"/f2b.sock", 'a').close()
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
|
|
Loading…
Reference in New Issue