Skip to content

Instantly share code, notes, and snippets.

@kwirk
Created December 12, 2013 23:26
Show Gist options
  • Save kwirk/7937442 to your computer and use it in GitHub Desktop.
Save kwirk/7937442 to your computer and use it in GitHub Desktop.
fail2ban - callable tags in actions
diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py
index 7e16901..c34c839 100644
--- a/fail2ban/server/action.py
+++ b/fail2ban/server/action.py
@@ -314,12 +314,15 @@ class Action:
"""
string = query
for tag, value in aInfo.iteritems():
- value = str(value) # assure string
- if tag == 'matches':
- # That one needs to be escaped since its content is
- # out of our control
- value = Action.escapeTag(value)
- string = string.replace('<' + tag + '>', value)
+ if "<%s>" % tag in query:
+ if callable(value):
+ value = value()
+ value = str(value) # assure string
+ if tag.endswith('matches'):
+ # That one needs to be escaped since its content is
+ # out of our control
+ value = Action.escapeTag(value)
+ string = string.replace('<' + tag + '>', value)
# New line
string = string.replace("<br>", '\n')
return string
diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py
index 520886a..3f76830 100644
--- a/fail2ban/server/actions.py
+++ b/fail2ban/server/actions.py
@@ -184,6 +184,13 @@ class Actions(JailThread):
aInfo["failures"] = bTicket.getAttempt()
aInfo["time"] = bTicket.getTime()
aInfo["matches"] = "".join(bTicket.getMatches())
+ if self.jail.getDatabase() is not None:
+ aInfo["ipmatches"] = lambda: "".join(
+ self.jail.getDatabase().getBansMerged(
+ bTicket.getIP()).getMatches())
+ aInfo["ipjailmatches"] = lambda: "".join(
+ self.jail.getDatabase().getBansMerged(
+ bTicket.getIP(), jail=self.jail).getMatches())
if self.__banManager.addBanTicket(bTicket):
logSys.warning("[%s] Ban %s" % (self.jail.getName(), aInfo["ip"]))
for action in self.__actions:
diff --git a/fail2ban/tests/actiontestcase.py b/fail2ban/tests/actiontestcase.py
index e25f4cb..9a255ac 100644
--- a/fail2ban/tests/actiontestcase.py
+++ b/fail2ban/tests/actiontestcase.py
@@ -104,6 +104,26 @@ class ExecuteAction(unittest.TestCase):
self.__action.replaceTag("<matches>",
{'matches': "some >char< should \< be[ escap}ed&"}),
r"some \>char\< should \\\< be\[ escap\}ed\&")
+ self.assertEqual(
+ self.__action.replaceTag("<ipmatches>",
+ {'ipmatches': "some >char< should \< be[ escap}ed&"}),
+ r"some \>char\< should \\\< be\[ escap\}ed\&")
+ self.assertEqual(
+ self.__action.replaceTag("<ipjailmatches>",
+ {'ipjailmatches': "some >char< should \< be[ escap}ed&"}),
+ r"some \>char\< should \\\< be\[ escap\}ed\&")
+
+ # Callable
+ self.assertEqual(
+ self.__action.replaceTag("09 <callable> 11",
+ {'callable': lambda: str(10)}),
+ "09 10 11")
+
+ # As tag not present, therefore callable should not be called
+ # Will raise ValueError if it is
+ self.assertEqual(
+ self.__action.replaceTag("abc",
+ {'callable': lambda: int("a")}), "abc")
def testExecuteActionBan(self):
self.__action.setActionStart("touch /tmp/fail2ban.test")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment