mirror of
https://github.com/fail2ban/fail2ban.git
synced 2026-03-11 08:55:31 +00:00
New command action parameter actionrepair - command executed in order to restore sane environment in error case of actioncheck.
# [WARNING] TODO: be sure all banactions get a repair command, because otherwise stop/start will theoretically remove all the bans, but the tickets are still in BanManager, so in case of new failures it will not be banned, because "already banned" will happen.
This commit is contained in:
parent
8cba537f6c
commit
d1ef33cc45
3 changed files with 57 additions and 11 deletions
|
|
@ -39,6 +39,7 @@ class ActionReader(DefinitionInitConfigReader):
|
|||
"actionstart": ["string", None],
|
||||
"actionstop": ["string", None],
|
||||
"actioncheck": ["string", None],
|
||||
"actionrepair": ["string", None],
|
||||
"actionban": ["string", None],
|
||||
"actionunban": ["string", None],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,6 +200,8 @@ class CommandAction(ActionBase):
|
|||
Attributes
|
||||
----------
|
||||
actionban
|
||||
actioncheck
|
||||
actionrepair
|
||||
actionstart
|
||||
actionstop
|
||||
actionunban
|
||||
|
|
@ -217,6 +219,8 @@ class CommandAction(ActionBase):
|
|||
actionunban = ''
|
||||
## Command executed in order to check requirements.
|
||||
actioncheck = ''
|
||||
## Command executed in order to restore sane environment in error case.
|
||||
actionrepair = ''
|
||||
## Command executed in order to stop the system.
|
||||
actionstop = ''
|
||||
|
||||
|
|
@ -271,16 +275,18 @@ class CommandAction(ActionBase):
|
|||
and executes the resulting command.
|
||||
"""
|
||||
# check valid tags in properties (raises ValueError if self recursion, etc.):
|
||||
res = True
|
||||
try:
|
||||
# common (resp. ipv4):
|
||||
startCmd = self.replaceTag('<actionstart>', self._properties,
|
||||
conditional='family=inet4', cache=self.__substCache)
|
||||
res = self.executeCmd(startCmd, self.timeout)
|
||||
if startCmd:
|
||||
res &= self.executeCmd(startCmd, self.timeout)
|
||||
# start ipv6 actions if available:
|
||||
if allowed_ipv6:
|
||||
startCmd6 = self.replaceTag('<actionstart>', self._properties,
|
||||
conditional='family=inet6', cache=self.__substCache)
|
||||
if startCmd6 != startCmd:
|
||||
if startCmd6 and startCmd6 != startCmd:
|
||||
res &= self.executeCmd(startCmd6, self.timeout)
|
||||
if not res:
|
||||
raise RuntimeError("Error starting action %s/%s" % (self._jail, self._name,))
|
||||
|
|
@ -323,15 +329,17 @@ class CommandAction(ActionBase):
|
|||
Replaces the tags in the action command with actions properties
|
||||
and executes the resulting command.
|
||||
"""
|
||||
res = True
|
||||
# common (resp. ipv4):
|
||||
stopCmd = self.replaceTag('<actionstop>', self._properties,
|
||||
conditional='family=inet4', cache=self.__substCache)
|
||||
res = self.executeCmd(stopCmd, self.timeout)
|
||||
if stopCmd:
|
||||
res &= self.executeCmd(stopCmd, self.timeout)
|
||||
# ipv6 actions if available:
|
||||
if allowed_ipv6:
|
||||
stopCmd6 = self.replaceTag('<actionstop>', self._properties,
|
||||
conditional='family=inet6', cache=self.__substCache)
|
||||
if stopCmd6 != stopCmd:
|
||||
if stopCmd6 and stopCmd6 != stopCmd:
|
||||
res &= self.executeCmd(stopCmd6, self.timeout)
|
||||
if not res:
|
||||
raise RuntimeError("Error stopping action")
|
||||
|
|
@ -520,14 +528,28 @@ class CommandAction(ActionBase):
|
|||
|
||||
checkCmd = self.replaceTag('<actioncheck>', self._properties,
|
||||
conditional=conditional, cache=self.__substCache)
|
||||
if not self.executeCmd(checkCmd, self.timeout):
|
||||
self._logSys.error(
|
||||
"Invariant check failed. Trying to restore a sane environment")
|
||||
self.stop()
|
||||
self.start()
|
||||
if checkCmd:
|
||||
if not self.executeCmd(checkCmd, self.timeout):
|
||||
self._logSys.critical("Unable to restore environment")
|
||||
return False
|
||||
self._logSys.error(
|
||||
"Invariant check failed. Trying to restore a sane environment")
|
||||
# try to find repair command, if exists - exec it:
|
||||
repairCmd = self.replaceTag('<actionrepair>', self._properties,
|
||||
conditional=conditional, cache=self.__substCache)
|
||||
if repairCmd:
|
||||
if not self.executeCmd(repairCmd, self.timeout):
|
||||
self._logSys.critical("Unable to restore environment")
|
||||
return False
|
||||
else:
|
||||
# no repair command, try to restart action...
|
||||
# [WARNING] TODO: be sure all banactions get a repair command, because
|
||||
# otherwise stop/start will theoretically remove all the bans,
|
||||
# but the tickets are still in BanManager, so in case of new failures
|
||||
# it will not be banned, because "already banned" will happen.
|
||||
self.stop()
|
||||
self.start()
|
||||
if not self.executeCmd(checkCmd, self.timeout):
|
||||
self._logSys.critical("Unable to restore environment")
|
||||
return False
|
||||
|
||||
# Replace static fields
|
||||
realCmd = self.replaceTag(cmd, self._properties,
|
||||
|
|
|
|||
|
|
@ -277,6 +277,24 @@ class CommandActionTest(LogCaptureTestCase):
|
|||
self.assertRaises(RuntimeError, self.__action.ban, {'ip': None})
|
||||
self.assertLogged('Unable to restore environment')
|
||||
|
||||
def testExecuteActionCheckRepairEnvironment(self):
|
||||
self.__action.actionstart = ""
|
||||
self.__action.actionstop = ""
|
||||
self.__action.actionban = "rm /tmp/fail2ban.test"
|
||||
self.__action.actioncheck = "[ -e /tmp/fail2ban.test ]"
|
||||
self.__action.actionrepair = "echo 'repair ...'; touch /tmp/fail2ban.test"
|
||||
# 1st time with success repair:
|
||||
self.__action.ban({'ip': None})
|
||||
self.assertLogged("Invariant check failed. Trying", "echo 'repair ...'", all=True)
|
||||
self.pruneLog()
|
||||
# 2nd time failed (not really repaired):
|
||||
self.__action.actionrepair = "echo 'repair ...'"
|
||||
self.assertRaises(RuntimeError, self.__action.ban, {'ip': None})
|
||||
self.assertLogged(
|
||||
"Invariant check failed. Trying",
|
||||
"echo 'repair ...'",
|
||||
"Unable to restore environment", all=True)
|
||||
|
||||
def testExecuteActionChangeCtags(self):
|
||||
self.assertRaises(AttributeError, getattr, self.__action, "ROST")
|
||||
self.__action.ROST = "192.0.2.0"
|
||||
|
|
@ -294,7 +312,12 @@ class CommandActionTest(LogCaptureTestCase):
|
|||
def testExecuteActionStartEmpty(self):
|
||||
self.__action.actionstart = ""
|
||||
self.__action.start()
|
||||
self.assertTrue(self.__action.executeCmd(""))
|
||||
self.assertLogged('Nothing to do')
|
||||
self.pruneLog()
|
||||
self.assertTrue(self.__action._processCmd(""))
|
||||
self.assertLogged('Nothing to do')
|
||||
self.pruneLog()
|
||||
|
||||
def testExecuteIncorrectCmd(self):
|
||||
CommandAction.executeCmd('/bin/ls >/dev/null\nbogusXXX now 2>/dev/null')
|
||||
|
|
|
|||
Loading…
Reference in a new issue