diff --git a/config/action.d/smtp.py b/config/action.d/smtp.py index 1a9a7496..8d1b0c95 100644 --- a/config/action.d/smtp.py +++ b/config/action.d/smtp.py @@ -103,7 +103,7 @@ class SMTPAction(ActionBase): self.message_values = CallingMap( jailname = self._jail.getName(), # Doesn't change hostname = socket.gethostname, - bantime = self._jail.getAction().getBanTime, + bantime = self._jail.actions.getBanTime, ) def _sendMessage(self, subject, text): diff --git a/fail2ban/exceptions.py b/fail2ban/exceptions.py index 7e933544..a7fe5ccc 100644 --- a/fail2ban/exceptions.py +++ b/fail2ban/exceptions.py @@ -29,7 +29,7 @@ __license__ = "GPL" class DuplicateJailException(Exception): pass -class UnknownJailException(Exception): +class UnknownJailException(KeyError): pass diff --git a/fail2ban/protocol.py b/fail2ban/protocol.py index 417780e5..977cc891 100644 --- a/fail2ban/protocol.py +++ b/fail2ban/protocol.py @@ -102,7 +102,6 @@ protocol = [ ["get usedns", "gets the usedns setting for "], ["get maxretry", "gets the number of failures allowed for "], ["get maxlines", "gets the number of lines to buffer for "], -["get addaction", "gets the last action which has been added for "], ["get actions", "gets a list of actions for "], ["", "COMMAND ACTION INFORMATION",""], ["get action actionstart", "gets the start command for the action for "], diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py index 7c6e3386..8295ca8c 100644 --- a/fail2ban/server/action.py +++ b/fail2ban/server/action.py @@ -79,12 +79,11 @@ class ActionBase(object): place to create a python based action for fail2ban. This class can be inherited from to ease implementation, but is not required as long as the following required methods/properties are implemented: - - __init__(jail, actionname) + - __init__(jail, name) - start() - stop() - ban(aInfo) - unban(aInfo) - - actionname """ __metaclass__ = ABCMeta @@ -101,23 +100,17 @@ class ActionBase(object): return False return True - def __init__(self, jail, actionname): + def __init__(self, jail, name): """Should initialise the action class with `jail` being the Jail - object the action belongs to, `actionname` being the name assigned + object the action belongs to, `name` being the name assigned to the action, and `kwargs` being all other args that have been specified with jail.conf or on the fail2ban-client. """ self._jail = jail - self._actionname = actionname + self._name = name self._logSys = logging.getLogger( '%s.%s' % (__name__, self.__class__.__name__)) - @property - def actionname(self): - """The name of the action, which should not change in the - lifetime of the action.""" - return self._actionname - def start(self): """Executed when the jail/action starts.""" pass @@ -144,8 +137,8 @@ class CommandAction(ActionBase): Fail2Ban uses. """ - def __init__(self, jail, actionname): - super(CommandAction, self).__init__(jail, actionname) + def __init__(self, jail, name): + super(CommandAction, self).__init__(jail, name) self.timeout = 60 ## Command executed in order to initialize the system. self.actionstart = '' @@ -172,7 +165,7 @@ class CommandAction(ActionBase): def timeout(self, timeout): self._timeout = int(timeout) self._logSys.debug("Set action %s timeout = %i" % - (self.actionname, self.timeout)) + (self._name, self.timeout)) @property def _properties(self): diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index e62ecf9b..a07afeeb 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -27,6 +27,7 @@ __license__ = "GPL" import time, logging import os import imp +from collections import Mapping from .banmanager import BanManager from .jailthread import JailThread @@ -36,40 +37,61 @@ from .mytime import MyTime # Gets the instance of the logger. logSys = logging.getLogger(__name__) -## -# Execute commands. -# -# This class reads the failures from the Jail queue and decide if an -# action has to be taken. A BanManager take care of the banned IP -# addresses. +class Actions(JailThread, Mapping): + """Handles jail actions. + + This class handles the actions of the jail. Creation, deletion or to + actions must be done through this class. This class is based on the + Mapping type, and the `add` method must be used to add new actions. + This class also starts and stops the actions, and fetches bans from + the jail executing these bans via the actions. + """ -class Actions(JailThread): - - ## - # Constructor. - # - # Initialize the filter object with default values. - # @param jail the jail object - def __init__(self, jail): + """Initialise an empty Actions instance. + + Parameters + ---------- + jail: Jail + The jail of which the actions belongs to. + """ JailThread.__init__(self) ## The jail which contains this action. - self.jail = jail - self.__actions = list() + self._jail = jail + self._actions = dict() ## The ban manager. self.__banManager = BanManager() - - ## - # Adds an action. - # - # @param name The action name - - def addAction(self, name, pythonModule=None, initOpts=None): + + def add(self, name, pythonModule=None, initOpts=None): + """Adds a new action. + + Add a new action if not already present, defaulting to standard + `CommandAction`, or specified Python module. + + Parameters + ---------- + name : str + The name of the action. + pythonModule : str + Path to Python file which must contain `Action` class. + initOpts : dict + Options for Python Action, used as keyword arguments for + initialisation. + + Raises + ------ + ValueError + If action name already exists. + RuntimeError + If external Python module does not have `Action` class + or does not implement necessary methods as per `ActionBase` + abstract class. + """ # Check is action name already exists - if name in [action.actionname for action in self.__actions]: + if name in self._actions: raise ValueError("Action %s already exists" % name) if pythonModule is None: - action = CommandAction(self.jail, name) + action = CommandAction(self._jail, name) else: pythonModuleName = os.path.basename(pythonModule.strip(".py")) customActionModule = imp.load_source( @@ -79,53 +101,35 @@ class Actions(JailThread): "%s module does not have 'Action' class" % pythonModule) elif not issubclass(customActionModule.Action, ActionBase): raise RuntimeError( - "%s module %s does not implment required methods" % ( + "%s module %s does not implement required methods" % ( pythonModule, customActionModule.Action.__name__)) - action = customActionModule.Action(self.jail, name, **initOpts) - self.__actions.append(action) - - ## - # Removes an action. - # - # @param name The action name - - def delAction(self, name): - for action in self.__actions: - if action.actionname == name: - self.__actions.remove(action) - return - raise KeyError("Invalid Action name: %s" % name) - - ## - # Returns an action. - # - # Raises a KeyError exception if the action does not exist. - # - # @param name the action name - # @return the action - - def getAction(self, name): - for action in self.__actions: - if action.actionname == name: - return action - raise KeyError("Invalid Action name") - - ## - # Returns the last defined action. - # - # @return The last defined action. - - def getLastAction(self): - return self.__actions[-1] - - ## - # Returns the list of actions - # - # @return list of actions - - def getActions(self): - return self.__actions - + action = customActionModule.Action(self._jail, name, **initOpts) + self._actions[name] = action + + def __getitem__(self, name): + try: + return self._actions[name] + except KeyError: + raise KeyError("Invalid Action name: %s" % name) + + def __delitem__(self, name): + try: + del self._actions[name] + except KeyError: + raise KeyError("Invalid Action name: %s" % name) + + def __iter__(self): + return iter(self._actions) + + def __len__(self): + return len(self._actions) + + def __eq__(self, other): # Required for Threading + return False + + def __hash__(self): # Required for Threading + return id(self) + ## # Set the ban time. # @@ -142,38 +146,52 @@ class Actions(JailThread): def getBanTime(self): return self.__banManager.getBanTime() - - ## - # Remove a banned IP now, rather than waiting for it to expire, even if set to never expire. - # - # @return the IP string or 'None' if not unbanned. + def removeBannedIP(self, ip): + """Removes banned IP calling actions' unban method + + Remove a banned IP now, rather than waiting for it to expire, + even if set to never expire. + + Parameters + ---------- + ip : str + The IP address to unban + + Raises + ------ + ValueError + If `ip` is not banned + """ # Find the ticket with the IP. ticket = self.__banManager.getTicketByIP(ip) if ticket is not None: # Unban the IP. self.__unBan(ticket) - return ip - raise ValueError("IP %s is not banned" % ip) + else: + raise ValueError("IP %s is not banned" % ip) - ## - # Main loop. - # - # This function is the main loop of the thread. It checks the Jail - # queue and executes commands when an IP address is banned. - # @return True when the thread exits nicely - def run(self): + """Main loop for Threading. + + This function is the main loop of the thread. It checks the jail + queue and executes commands when an IP address is banned. + + Returns + ------- + bool + True when the thread exits nicely. + """ self.setActive(True) - for action in self.__actions: + for name, action in self._actions.iteritems(): try: action.start() except Exception as e: logSys.error("Failed to start jail '%s' action '%s': %s", - self.jail.getName(), action.actionname, e) + self._jail.getName(), name, e) while self._isActive(): if not self.getIdle(): - #logSys.debug(self.jail.getName() + ": action") + #logSys.debug(self._jail.getName() + ": action") ret = self.__checkBan() if not ret: self.__checkUnBan() @@ -181,24 +199,27 @@ class Actions(JailThread): else: time.sleep(self.getSleepTime()) self.__flushBan() - for action in self.__actions: + for name, action in self._actions.iteritems(): try: action.stop() except Exception as e: logSys.error("Failed to stop jail '%s' action '%s': %s", - self.jail.getName(), action.actionname, e) - logSys.debug(self.jail.getName() + ": action terminated") + self._jail.getName(), name, e) + logSys.debug(self._jail.getName() + ": action terminated") return True - ## - # Check for IP address to ban. - # - # Look in the Jail queue for FailTicket. If a ticket is available, - # it executes the "ban" command and add a ticket to the BanManager. - # @return True if an IP address get banned - def __checkBan(self): - ticket = self.jail.getFailTicket() + """Check for IP address to ban. + + Look in the jail queue for FailTicket. If a ticket is available, + it executes the "ban" command and adds a ticket to the BanManager. + + Returns + ------- + bool + True if an IP address get banned. + """ + ticket = self._jail.getFailTicket() if ticket != False: aInfo = CallingMap() bTicket = BanManager.createBanTicket(ticket) @@ -206,83 +227,88 @@ class Actions(JailThread): aInfo["failures"] = bTicket.getAttempt() aInfo["time"] = bTicket.getTime() aInfo["matches"] = "\n".join(bTicket.getMatches()) - if self.jail.getDatabase() is not None: + if self._jail.getDatabase() is not None: aInfo["ipmatches"] = lambda: "\n".join( - self.jail.getDatabase().getBansMerged( + self._jail.getDatabase().getBansMerged( ip=bTicket.getIP()).getMatches()) aInfo["ipjailmatches"] = lambda: "\n".join( - self.jail.getDatabase().getBansMerged( - ip=bTicket.getIP(), jail=self.jail).getMatches()) + self._jail.getDatabase().getBansMerged( + ip=bTicket.getIP(), jail=self._jail).getMatches()) aInfo["ipfailures"] = lambda: "\n".join( - self.jail.getDatabase().getBansMerged( + self._jail.getDatabase().getBansMerged( ip=bTicket.getIP()).getAttempt()) aInfo["ipjailfailures"] = lambda: "\n".join( - self.jail.getDatabase().getBansMerged( - ip=bTicket.getIP(), jail=self.jail).getAttempt()) + self._jail.getDatabase().getBansMerged( + ip=bTicket.getIP(), jail=self._jail).getAttempt()) if self.__banManager.addBanTicket(bTicket): - logSys.warning("[%s] Ban %s" % (self.jail.getName(), aInfo["ip"])) - for action in self.__actions: + logSys.warning("[%s] Ban %s" % (self._jail.getName(), aInfo["ip"])) + for name, action in self._actions.iteritems(): try: action.ban(aInfo) except Exception as e: logSys.error( "Failed to execute ban jail '%s' action '%s': %s", - self.jail.getName(), action.actionname, e) + self._jail.getName(), name, e) return True else: - logSys.info("[%s] %s already banned" % (self.jail.getName(), + logSys.info("[%s] %s already banned" % (self._jail.getName(), aInfo["ip"])) return False - - ## - # Check for IP address to unban. - # - # Unban IP address which are outdated. - + def __checkUnBan(self): + """Check for IP address to unban. + + Unban IP addresses which are outdated. + """ for ticket in self.__banManager.unBanList(MyTime.time()): self.__unBan(ticket) - - ## - # Flush the ban list. - # - # Unban all IP address which are still in the banning list. - + def __flushBan(self): + """Flush the ban list. + + Unban all IP address which are still in the banning list. + """ logSys.debug("Flush ban list") for ticket in self.__banManager.flushBanList(): self.__unBan(ticket) - - ## - # Unbans host corresponding to the ticket. - # - # Executes the actions in order to unban the host given in the - # ticket. - + def __unBan(self, ticket): + """Unbans host corresponding to the ticket. + + Executes the actions in order to unban the host given in the + ticket. + + Parameters + ---------- + ticket : FailTicket + Ticket of failures of which to unban + """ aInfo = dict() aInfo["ip"] = ticket.getIP() aInfo["failures"] = ticket.getAttempt() aInfo["time"] = ticket.getTime() aInfo["matches"] = "".join(ticket.getMatches()) - logSys.warning("[%s] Unban %s" % (self.jail.getName(), aInfo["ip"])) - for action in self.__actions: + logSys.warning("[%s] Unban %s" % (self._jail.getName(), aInfo["ip"])) + for name, action in self._actions.iteritems(): try: action.unban(aInfo) except Exception as e: logSys.error( "Failed to execute unban jail '%s' action '%s': %s", - self.jail.getName(), action.actionname, e) - - - ## - # Get the status of the filter. - # - # Get some informations about the filter state such as the total - # number of failures. - # @return a list with tuple - + self._jail.getName(), name, e) + def status(self): + """Get the status of the filter. + + Get some informations about the filter state such as the total + number of failures. + + Returns + ------- + list + List of tuple pairs, each containing a description and value + for general status information. + """ ret = [("Currently banned", self.__banManager.size()), ("Total banned", self.__banManager.getBanTotal()), ("IP list", self.__banManager.getBanList())] diff --git a/fail2ban/server/jail.py b/fail2ban/server/jail.py index 7683a087..fe7ec327 100644 --- a/fail2ban/server/jail.py +++ b/fail2ban/server/jail.py @@ -71,7 +71,7 @@ class Jail: "%r was requested" % (b, backend)) else: logSys.info("Initiated %r backend" % b) - self.__action = Actions(self) + self.__actions = Actions(self) return # we are done except ImportError, e: logSys.debug( @@ -124,11 +124,17 @@ class Jail: def getDatabase(self): return self.__db - def getFilter(self): + @property + def filter(self): + """The filter which the jail is using to monitor log files. + """ return self.__filter - - def getAction(self): - return self.__action + + @property + def actions(self): + """Actions object used to manage actions for jail. + """ + return self.__actions def putFailTicket(self, ticket): self.__queue.put(ticket) @@ -143,36 +149,36 @@ class Jail: def start(self): self.__filter.start() - self.__action.start() + self.__actions.start() # Restore any previous valid bans from the database if self.__db is not None: for ticket in self.__db.getBans( - jail=self, bantime=self.__action.getBanTime()): + jail=self, bantime=self.__actions.getBanTime()): self.__queue.put(ticket) logSys.info("Jail '%s' started" % self.__name) def stop(self): self.__filter.stop() - self.__action.stop() + self.__actions.stop() self.__filter.join() - self.__action.join() + self.__actions.join() logSys.info("Jail '%s' stopped" % self.__name) def isAlive(self): isAlive0 = self.__filter.isAlive() - isAlive1 = self.__action.isAlive() + isAlive1 = self.__actions.isAlive() return isAlive0 or isAlive1 def setIdle(self, value): self.__filter.setIdle(value) - self.__action.setIdle(value) + self.__actions.setIdle(value) def getIdle(self): - return self.__filter.getIdle() or self.__action.getIdle() + return self.__filter.getIdle() or self.__actions.getIdle() def getStatus(self): fStatus = self.__filter.status() - aStatus = self.__action.status() + aStatus = self.__actions.status() ret = [("filter", fStatus), ("action", aStatus)] return ret diff --git a/fail2ban/server/jails.py b/fail2ban/server/jails.py index 53b0345b..7fe7a231 100644 --- a/fail2ban/server/jails.py +++ b/fail2ban/server/jails.py @@ -22,136 +22,83 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2013- Yaroslav Halchenko" __license__ = "GPL" from threading import Lock +from collections import Mapping from ..exceptions import DuplicateJailException, UnknownJailException from .jail import Jail -## -# Handles the jails. -# -# This class handles the jails. Creation, deletion or access to a jail must be -# done through this class. This class is thread-safe which is not the case of -# the jail itself, including filter and actions. -class Jails: - - ## - # Constructor. - +class Jails(Mapping): + """Handles the jails. + + This class handles the jails. Creation, deletion or access to a jail + must be done through this class. This class is thread-safe which is + not the case of the jail itself, including filter and actions. This + class is based on Mapping type, and the `add` method must be used to + add additional jails. + """ + def __init__(self): + """Initialise an empty Jails instance. + """ self.__lock = Lock() - self.__jails = dict() - - ## - # Adds a jail. - # - # Adds a new jail which should use the given backend. Raises a - # DuplicateJailException if the jail is already defined. - # @param name The name of the jail - # @param backend The backend to use - + self._jails = dict() + def add(self, name, backend, db=None): + """Adds a jail. + + Adds a new jail if not already present which should use the + given backend. + + Parameters + ---------- + name : str + The name of the jail. + backend : str + The backend to use. + + Raises + ------ + DuplicateJailException + If jail name is already present. + """ try: self.__lock.acquire() - if self.__jails.has_key(name): + if name in self._jails: raise DuplicateJailException(name) else: - self.__jails[name] = Jail(name, backend, db) - finally: - self.__lock.release() - - ## - # Removes a jail. - # - # Removes the jail name. Raise an UnknownJailException - # if the jail does not exist. - # @param name The name of the jail - - def remove(self, name): - try: - self.__lock.acquire() - if self.__jails.has_key(name): - del self.__jails[name] - else: - raise UnknownJailException(name) - finally: - self.__lock.release() - - ## - # Returns a jail. - # - # Returns the jail name. Raise an UnknownJailException - # if the jail does not exist. - # @param name The name of the jail - - def get(self, name): - try: - self.__lock.acquire() - if self.__jails.has_key(name): - jail = self.__jails[name] - return jail - else: - raise UnknownJailException(name) - finally: - self.__lock.release() - - ## - # Returns an action class instance. - # - # Returns the action object of the jail name. Raise an - # UnknownJailException if the jail does not exist. - # @param name The name of the jail - - def getAction(self, name): - try: - self.__lock.acquire() - if self.__jails.has_key(name): - action = self.__jails[name].getAction() - return action - else: - raise UnknownJailException(name) - finally: - self.__lock.release() - - ## - # Returns a filter class instance. - # - # Returns the filter object of the jail name. Raise an - # UnknownJailException if the jail does not exist. - # @param name The name of the jail - - def getFilter(self, name): - try: - self.__lock.acquire() - if self.__jails.has_key(name): - action = self.__jails[name].getFilter() - return action - else: - raise UnknownJailException(name) - finally: - self.__lock.release() - - ## - # Returns the jails. - # - # Returns a copy of the jails list. - - def getAll(self): - try: - self.__lock.acquire() - return self.__jails.copy() - finally: - self.__lock.release() - - ## - # Returns the size of the jails. - # - # Returns the number of jails. - - def size(self): - try: - self.__lock.acquire() - return len(self.__jails) + self._jails[name] = Jail(name, backend, db) finally: self.__lock.release() + def __getitem__(self, name): + try: + self.__lock.acquire() + return self._jails[name] + except KeyError: + raise UnknownJailException(name) + finally: + self.__lock.release() + + def __delitem__(self, name): + try: + self.__lock.acquire() + del self._jails[name] + except KeyError: + raise UnknownJailException(name) + finally: + self.__lock.release() + + def __len__(self): + try: + self.__lock.acquire() + return len(self._jails) + finally: + self.__lock.release() + + def __iter__(self): + try: + self.__lock.acquire() + return iter(self._jails) + finally: + self.__lock.release() diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py index 7b074b26..3d2b54f7 100644 --- a/fail2ban/server/server.py +++ b/fail2ban/server/server.py @@ -122,10 +122,10 @@ class Server: def addJail(self, name, backend): self.__jails.add(name, backend, self.__db) if self.__db is not None: - self.__db.addJail(self.__jails.get(name)) + self.__db.addJail(self.__jails[name]) def delJail(self, name): - self.__jails.remove(name) + del self.__jails[name] if self.__db is not None: self.__db.delJailName(name) @@ -133,7 +133,7 @@ class Server: try: self.__lock.acquire() if not self.isAlive(name): - self.__jails.get(name).start() + self.__jails[name].start() finally: self.__lock.release() @@ -142,7 +142,7 @@ class Server: try: self.__lock.acquire() if self.isAlive(name): - self.__jails.get(name).stop() + self.__jails[name].stop() self.delJail(name) finally: self.__lock.release() @@ -151,43 +151,43 @@ class Server: logSys.info("Stopping all jails") try: self.__lock.acquire() - for jail in self.__jails.getAll(): + for jail in self.__jails.keys(): self.stopJail(jail) finally: self.__lock.release() def isAlive(self, name): - return self.__jails.get(name).isAlive() + return self.__jails[name].isAlive() def setIdleJail(self, name, value): - self.__jails.get(name).setIdle(value) + self.__jails[name].setIdle(value) return True def getIdleJail(self, name): - return self.__jails.get(name).getIdle() + return self.__jails[name].getIdle() # Filter def addIgnoreIP(self, name, ip): - self.__jails.getFilter(name).addIgnoreIP(ip) + self.__jails[name].filter.addIgnoreIP(ip) def delIgnoreIP(self, name, ip): - self.__jails.getFilter(name).delIgnoreIP(ip) + self.__jails[name].filter.delIgnoreIP(ip) def getIgnoreIP(self, name): - return self.__jails.getFilter(name).getIgnoreIP() + return self.__jails[name].filter.getIgnoreIP() def addLogPath(self, name, fileName, tail=False): - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, FileFilter): filter_.addLogPath(fileName, tail) def delLogPath(self, name, fileName): - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, FileFilter): filter_.delLogPath(fileName) def getLogPath(self, name): - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, FileFilter): return [m.getFileName() for m in filter_.getLogPath()] @@ -196,17 +196,17 @@ class Server: return [] def addJournalMatch(self, name, match): # pragma: systemd no cover - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, JournalFilter): filter_.addJournalMatch(match) def delJournalMatch(self, name, match): # pragma: systemd no cover - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, JournalFilter): filter_.delJournalMatch(match) def getJournalMatch(self, name): # pragma: systemd no cover - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, JournalFilter): return filter_.getJournalMatch() else: @@ -214,112 +214,109 @@ class Server: return [] def setLogEncoding(self, name, encoding): - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, FileFilter): filter_.setLogEncoding(encoding) def getLogEncoding(self, name): - filter_ = self.__jails.getFilter(name) + filter_ = self.__jails[name].filter if isinstance(filter_, FileFilter): return filter_.getLogEncoding() def setFindTime(self, name, value): - self.__jails.getFilter(name).setFindTime(value) + self.__jails[name].filter.setFindTime(value) def getFindTime(self, name): - return self.__jails.getFilter(name).getFindTime() + return self.__jails[name].filter.getFindTime() def setDatePattern(self, name, pattern): - self.__jails.getFilter(name).setDatePattern(pattern) + self.__jails[name].filter.setDatePattern(pattern) def getDatePattern(self, name): - return self.__jails.getFilter(name).getDatePattern() + return self.__jails[name].filter.getDatePattern() def setIgnoreCommand(self, name, value): - self.__jails.getFilter(name).setIgnoreCommand(value) + self.__jails[name].filter.setIgnoreCommand(value) def getIgnoreCommand(self, name): - return self.__jails.getFilter(name).getIgnoreCommand() + return self.__jails[name].filter.getIgnoreCommand() def addFailRegex(self, name, value): - self.__jails.getFilter(name).addFailRegex(value) + self.__jails[name].filter.addFailRegex(value) def delFailRegex(self, name, index): - self.__jails.getFilter(name).delFailRegex(index) + self.__jails[name].filter.delFailRegex(index) def getFailRegex(self, name): - return self.__jails.getFilter(name).getFailRegex() + return self.__jails[name].filter.getFailRegex() def addIgnoreRegex(self, name, value): - self.__jails.getFilter(name).addIgnoreRegex(value) + self.__jails[name].filter.addIgnoreRegex(value) def delIgnoreRegex(self, name, index): - self.__jails.getFilter(name).delIgnoreRegex(index) + self.__jails[name].filter.delIgnoreRegex(index) def getIgnoreRegex(self, name): - return self.__jails.getFilter(name).getIgnoreRegex() + return self.__jails[name].filter.getIgnoreRegex() def setUseDns(self, name, value): - self.__jails.getFilter(name).setUseDns(value) + self.__jails[name].filter.setUseDns(value) def getUseDns(self, name): - return self.__jails.getFilter(name).getUseDns() + return self.__jails[name].filter.getUseDns() def setMaxRetry(self, name, value): - self.__jails.getFilter(name).setMaxRetry(value) + self.__jails[name].filter.setMaxRetry(value) def getMaxRetry(self, name): - return self.__jails.getFilter(name).getMaxRetry() + return self.__jails[name].filter.getMaxRetry() def setMaxLines(self, name, value): - self.__jails.getFilter(name).setMaxLines(value) + self.__jails[name].filter.setMaxLines(value) def getMaxLines(self, name): - return self.__jails.getFilter(name).getMaxLines() + return self.__jails[name].filter.getMaxLines() # Action def addAction(self, name, value, *args): - self.__jails.getAction(name).addAction(value, *args) - - def getLastAction(self, name): - return self.__jails.getAction(name).getLastAction() + self.__jails[name].actions.add(value, *args) def getActions(self, name): - return self.__jails.getAction(name).getActions() + return self.__jails[name].actions def delAction(self, name, value): - self.__jails.getAction(name).delAction(value) + del self.__jails[name].actions[value] def getAction(self, name, value): - return self.__jails.getAction(name).getAction(value) + return self.__jails[name].actions[value] def setBanTime(self, name, value): - self.__jails.getAction(name).setBanTime(value) + self.__jails[name].actions.setBanTime(value) def setBanIP(self, name, value): - return self.__jails.getFilter(name).addBannedIP(value) + return self.__jails[name].filter.addBannedIP(value) def setUnbanIP(self, name, value): - return self.__jails.getAction(name).removeBannedIP(value) + self.__jails[name].actions.removeBannedIP(value) def getBanTime(self, name): - return self.__jails.getAction(name).getBanTime() + return self.__jails[name].actions.getBanTime() # Status def status(self): try: self.__lock.acquire() - jails = list(self.__jails.getAll()) + jails = list(self.__jails) jails.sort() jailList = ", ".join(jails) - ret = [("Number of jail", self.__jails.size()), + ret = [("Number of jail", len(self.__jails)), ("Jail list", jailList)] return ret finally: self.__lock.release() def statusJail(self, name): - return self.__jails.get(name).getStatus() + return self.__jails[name].getStatus() # Logging @@ -447,7 +444,7 @@ class Server: return "flushed" def setDatabase(self, filename): - if self.__jails.size() == 0: + if len(self.__jails) == 0: if filename.lower() == "none": self.__db = None else: diff --git a/fail2ban/server/transmitter.py b/fail2ban/server/transmitter.py index 6a7d4de1..0a955883 100644 --- a/fail2ban/server/transmitter.py +++ b/fail2ban/server/transmitter.py @@ -227,13 +227,14 @@ class Transmitter: return self.__server.setBanIP(name,value) elif command[1] == "unbanip": value = command[2] - return self.__server.setUnbanIP(name,value) + self.__server.setUnbanIP(name, value) + return value elif command[1] == "addaction": args = [command[2]] if len(command) > 3: args.extend([command[3], json.loads(command[4])]) self.__server.addAction(name, *args) - return self.__server.getLastAction(name).actionname + return args[0] elif command[1] == "delaction": value = command[2] self.__server.delAction(name, value) @@ -300,10 +301,7 @@ class Transmitter: elif command[1] == "bantime": return self.__server.getBanTime(name) elif command[1] == "actions": - return [action.actionname - for action in self.__server.getActions(name)] - elif command[1] == "addaction": - return self.__server.getLastAction(name).actionname + return self.__server.getActions(name).keys() elif command[1] == "action": actionname = command[2] actionvalue = command[3] diff --git a/fail2ban/tests/actionstestcase.py b/fail2ban/tests/actionstestcase.py index 6708b403..83319cb8 100644 --- a/fail2ban/tests/actionstestcase.py +++ b/fail2ban/tests/actionstestcase.py @@ -47,8 +47,8 @@ class ExecuteActions(LogCaptureTestCase): os.remove(self.__tmpfilename) def defaultActions(self): - self.__actions.addAction('ip') - self.__ip = self.__actions.getAction('ip') + self.__actions.add('ip') + self.__ip = self.__actions['ip'] self.__ip.actionstart = 'echo ip start 64 >> "%s"' % self.__tmpfilename self.__ip.actionban = 'echo ip ban >> "%s"' % self.__tmpfilename self.__ip.actionunban = 'echo ip unban >> "%s"' % self.__tmpfilename @@ -56,15 +56,15 @@ class ExecuteActions(LogCaptureTestCase): self.__ip.actionstop = 'echo ip stop >> "%s"' % self.__tmpfilename def testActionsManipulation(self): - self.__actions.addAction('test') - self.assertTrue(self.__actions.getAction('test')) - self.assertTrue(self.__actions.getLastAction()) - self.assertRaises(KeyError,self.__actions.getAction,*['nonexistant action']) - self.__actions.addAction('test1') - self.__actions.delAction('test') - self.__actions.delAction('test1') - self.assertRaises(KeyError, self.__actions.getAction, *['test']) - self.assertRaises(IndexError,self.__actions.getLastAction) + self.__actions.add('test') + self.assertTrue(self.__actions['test']) + self.assertTrue('test' in self.__actions) + self.assertFalse('nonexistant action' in self.__actions) + self.__actions.add('test1') + del self.__actions['test'] + del self.__actions['test1'] + self.assertFalse('test' in self.__actions) + self.assertEqual(len(self.__actions), 0) self.__actions.setBanTime(127) self.assertEqual(self.__actions.getBanTime(),127) @@ -85,7 +85,7 @@ class ExecuteActions(LogCaptureTestCase): def testAddActionPython(self): - self.__actions.addAction( + self.__actions.add( "Action", os.path.join(TEST_FILES_DIR, "action.d/action.py"), {'opt1': 'value'}) @@ -100,18 +100,18 @@ class ExecuteActions(LogCaptureTestCase): self.assertTrue(self._is_logged("TestAction action stop")) self.assertRaises(IOError, - self.__actions.addAction, "Action3", "/does/not/exist.py", {}) + self.__actions.add, "Action3", "/does/not/exist.py", {}) # With optional argument - self.__actions.addAction( + self.__actions.add( "Action4", os.path.join(TEST_FILES_DIR, "action.d/action.py"), {'opt1': 'value', 'opt2': 'value2'}) # With too many arguments self.assertRaises( - TypeError, self.__actions.addAction, "Action5", + TypeError, self.__actions.add, "Action5", os.path.join(TEST_FILES_DIR, "action.d/action.py"), {'opt1': 'value', 'opt2': 'value2', 'opt3': 'value3'}) # Missing required argument self.assertRaises( - TypeError, self.__actions.addAction, "Action5", + TypeError, self.__actions.add, "Action5", os.path.join(TEST_FILES_DIR, "action.d/action.py"), {}) diff --git a/fail2ban/tests/files/action.d/action.py b/fail2ban/tests/files/action.d/action.py index 83e7a43b..2dd64c3f 100644 --- a/fail2ban/tests/files/action.d/action.py +++ b/fail2ban/tests/files/action.d/action.py @@ -3,8 +3,8 @@ from fail2ban.server.action import ActionBase class TestAction(ActionBase): - def __init__(self, jail, actionname, opt1, opt2=None): - super(TestAction, self).__init__(jail, actionname) + def __init__(self, jail, name, opt1, opt2=None): + super(TestAction, self).__init__(jail, name) self._logSys.debug("%s initialised" % self.__class__.__name__) self.opt1 = opt1 self.opt2 = opt2 diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 7159fdc3..dd3c740c 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -518,9 +518,6 @@ class Transmitter(TransmitterBase): self.assertEqual( self.transm.proceed(["set", self.jailName, "addaction", action]), (0, action)) - self.assertEqual( - self.transm.proceed(["get", self.jailName, "addaction"]), - (0, action)) self.assertEqual( self.transm.proceed( ["get", self.jailName, "actions"])[1][0], @@ -546,10 +543,6 @@ class Transmitter(TransmitterBase): self.transm.proceed( ["get", self.jailName, "action", action, "InvalidKey"])[0], 1) - self.assertEqual( - self.transm.proceed( - ["get", self.jailName, "action", action, "actionname"]), - (0, action)) self.assertEqual( self.transm.proceed( ["set", self.jailName, "action", action, "timeout", "10"]), @@ -575,7 +568,7 @@ class Transmitter(TransmitterBase): self.assertEqual( sorted(self.transm.proceed(["get", self.jailName, "actionproperties", action])[1]), - ['actionname', 'opt1', 'opt2']) + ['opt1', 'opt2']) self.assertEqual( self.transm.proceed(["get", self.jailName, "action", action, "opt1"]),