From c442569b63028c573389a673f7473a4731d43567 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 21 Nov 2016 16:35:33 +0100 Subject: [PATCH] executeCmd: added possibility to select success return codes ignorecommand: both return codes (0, 1) are success codes now, so no errors will be logged + test cases extended to check this (and error case) --- fail2ban/server/action.py | 4 ++-- fail2ban/server/filter.py | 3 ++- fail2ban/server/utils.py | 12 +++++++----- fail2ban/tests/files/ignorecommand.py | 3 +++ fail2ban/tests/filtertestcase.py | 4 ++++ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py index 976adb20..62aa51dc 100644 --- a/fail2ban/server/action.py +++ b/fail2ban/server/action.py @@ -584,7 +584,7 @@ class CommandAction(ActionBase): return self.executeCmd(realCmd, self.timeout) @staticmethod - def executeCmd(realCmd, timeout=60): + def executeCmd(realCmd, timeout=60, **kwargs): """Executes a command. Parameters @@ -613,6 +613,6 @@ class CommandAction(ActionBase): _cmd_lock.acquire() try: - return Utils.executeCmd(realCmd, timeout, shell=True, output=False) + return Utils.executeCmd(realCmd, timeout, shell=True, output=False, **kwargs) finally: _cmd_lock.release() diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index 2487b8f5..d263c901 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -455,7 +455,8 @@ class Filter(JailThread): if self.__ignoreCommand: command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip } ) logSys.debug('ignore command: ' + command) - ret_ignore = CommandAction.executeCmd(command) + ret, ret_ignore = CommandAction.executeCmd(command, success_codes=(0, 1)) + ret_ignore = ret and ret_ignore == 0 self.logIgnoreIp(ip, log_ignore and ret_ignore, ignore_source="command") return ret_ignore diff --git a/fail2ban/server/utils.py b/fail2ban/server/utils.py index 6ed3d8fa..6d74d2db 100644 --- a/fail2ban/server/utils.py +++ b/fail2ban/server/utils.py @@ -110,7 +110,7 @@ class Utils(): return flags @staticmethod - def executeCmd(realCmd, timeout=60, shell=True, output=False, tout_kill_tree=True): + def executeCmd(realCmd, timeout=60, shell=True, output=False, tout_kill_tree=True, success_codes=(0,)): """Executes a command. Parameters @@ -178,7 +178,7 @@ class Utils(): if not popen: return False if not output else (False, stdout, stderr, retcode) - std_level = retcode == 0 and logging.DEBUG or logging.ERROR + std_level = logging.DEBUG if retcode in success_codes else logging.ERROR # if we need output (to return or to log it): if output or std_level >= logSys.getEffectiveLevel(): # if was timeouted (killed/terminated) - to prevent waiting, set std handles to non-blocking mode. @@ -208,8 +208,8 @@ class Utils(): popen.stderr.close() success = False - if retcode == 0: - logSys.debug("%-.40s -- returned successfully", realCmd) + if retcode in success_codes: + logSys.debug("%-.40s -- returned successfully %i", realCmd, retcode) success = True elif retcode is None: logSys.error("%-.40s -- unable to kill PID %i", realCmd, popen.pid) @@ -223,7 +223,9 @@ class Utils(): logSys.error("%-.40s -- returned %i", realCmd, retcode) if msg: logSys.info("HINT on %i: %s", retcode, msg % locals()) - return success if not output else (success, stdout, stderr, retcode) + if output: + return success, stdout, stderr, retcode + return success if len(success_codes) == 1 else (success, retcode) @staticmethod def wait_for(cond, timeout, interval=None): diff --git a/fail2ban/tests/files/ignorecommand.py b/fail2ban/tests/files/ignorecommand.py index 7011b51b..8c115006 100755 --- a/fail2ban/tests/files/ignorecommand.py +++ b/fail2ban/tests/files/ignorecommand.py @@ -1,5 +1,8 @@ #!/usr/bin/env fail2ban-python import sys +if len(sys.argv) != 2 or sys.argv[1] == "": + sys.stderr.write('usage: ignorecommand IP') + exit(10) if sys.argv[1] == "10.0.0.1": exit(0) exit(1) diff --git a/fail2ban/tests/filtertestcase.py b/fail2ban/tests/filtertestcase.py index 2b57ce47..a6f491dd 100644 --- a/fail2ban/tests/filtertestcase.py +++ b/fail2ban/tests/filtertestcase.py @@ -377,6 +377,10 @@ class IgnoreIP(LogCaptureTestCase): self.filter.setIgnoreCommand(sys.executable + ' ' + os.path.join(TEST_FILES_DIR, "ignorecommand.py ")) self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1")) self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0")) + self.assertLogged("returned successfully 0", "returned successfully 1", all=True) + self.pruneLog() + self.assertFalse(self.filter.inIgnoreIPList("")) + self.assertLogged("usage: ignorecommand IP", "returned 10", all=True) def testIgnoreCauseOK(self): ip = "93.184.216.34"