mirror of https://github.com/fail2ban/fail2ban
RF: Change Jails and Actions to Mapping types
parent
a070284a18
commit
6e63f0ea5a
|
@ -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):
|
||||
|
|
|
@ -29,7 +29,7 @@ __license__ = "GPL"
|
|||
class DuplicateJailException(Exception):
|
||||
pass
|
||||
|
||||
class UnknownJailException(Exception):
|
||||
class UnknownJailException(KeyError):
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -102,7 +102,6 @@ protocol = [
|
|||
["get <JAIL> usedns", "gets the usedns setting for <JAIL>"],
|
||||
["get <JAIL> maxretry", "gets the number of failures allowed for <JAIL>"],
|
||||
["get <JAIL> maxlines", "gets the number of lines to buffer for <JAIL>"],
|
||||
["get <JAIL> addaction", "gets the last action which has been added for <JAIL>"],
|
||||
["get <JAIL> actions", "gets a list of actions for <JAIL>"],
|
||||
["", "COMMAND ACTION INFORMATION",""],
|
||||
["get <JAIL> action <ACT> actionstart", "gets the start command for the action <ACT> for <JAIL>"],
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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())]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
# <code>DuplicateJailException</code> 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 <code>name</code>. Raise an <code>UnknownJailException</code>
|
||||
# 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 <code>name</code>. Raise an <code>UnknownJailException</code>
|
||||
# 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 <code>name</code>. Raise an
|
||||
# <code>UnknownJailException</code> 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 <code>name</code>. Raise an
|
||||
# <code>UnknownJailException</code> 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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 <ip> >> "%s"' % self.__tmpfilename
|
||||
self.__ip.actionunban = 'echo ip unban <ip> >> "%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"), {})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]),
|
||||
|
|
Loading…
Reference in New Issue