diff options
author | Cyril Jaquier <cyril.jaquier@fail2ban.org> | 2006-06-26 20:05:00 +0000 |
---|---|---|
committer | Cyril Jaquier <cyril.jaquier@fail2ban.org> | 2006-06-26 20:05:00 +0000 |
commit | ea1948eff40953b4590858698ced9f6b4c3733f8 (patch) | |
tree | e667d2906e70b34fe233c3409cb9052e4a77fe6a | |
parent | 97aa913e243eacb8b93610d4ef6954d89c01a5eb (diff) | |
download | fail2ban-ea1948eff40953b4590858698ced9f6b4c3733f8.tar.gz |
- Initial commit of the new development release 0.7
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@249 a942ae1a-1317-0410-a47c-b1dcaea8d605
62 files changed, 4734 insertions, 3156 deletions
@@ -1,95 +1,2 @@ - __ _ _ ___ _ - / _|__ _(_) |_ ) |__ __ _ _ _ - | _/ _` | | |/ /| '_ \/ _` | ' \ - |_| \__,_|_|_/___|_.__/\__,_|_||_| - -============================================================= -ToDo $Revision$ -============================================================= - -See Feature Request Tracking System at SourceForge.net - -- improve installation process (better prefix support) - -- improve documentation and website for user - -- use Doxygen - -- use PyLint to check the code - -- better configuration files - -- add a check to see if the time of the log messages is - correctly detected (valid regexp) - -- use Gentoo Portage style for scripts. - - banning engines script in /etc/fail2ban/scripts.d - Example: /etc/fail2ban/scripts.d/iptables - Will be mostly bash scripting which is more "user - friendly". - - split configuration files in /etc/fail2ban/services.d - for log files - Example: /etc/fail2ban/services.d/apache - Mainly regular expressions. - - template for common regex in /etc/fail2ban/templates.d - Example: /etc/fail2ban/templates.d/date - Mainly regular expressions. - -- remove debug mode (root check) - -- better return values in function - -- use more email.Utils in mail.py - -- add gettext support. Is this really needed for a server - utility? - -- send an email when fail2ban is running - -- add multithreading. Python threading is not really - efficient. However, fail2ban could benefit of it. We could - use threads like this: - - one thread which check for host to unban. - - one thread per file to watch. This will allow things like - different polling time for each file. - <srv> is read-only (we only read log files) thus no locks - are required. However, <meth> is read-write and must take - care of concurrency in case of multithreading. - -- add FAM/Gamin support. Should be quite efficient with - threading. Take care that handle_one_event() release the - Python lock. - -- add a test framework. We could use unittest which is in - Python since 2.1. It should be possible to run all tests - automatically. - -- add client/server using socket. Something similar to - gdesklets. DBUS seems to be designed for desktop use. - - fail2ban start -> start the daemon. - - fail2ban stop -> stop the daemon. - - fail2ban add <srv> <meth> -> add <srv> monitoring with - <meth> ban method (iptables, hosts.deny, etc). - - fail2ban del <srv> -> remove <srv> monitoring. - - fail2ban status <srv> -> query current fail2ban status. - Should return infos like a ban counter. Could be graph - with rrdtool. - - fail2ban pause <srv> -> suspend monitoring. - - fail2ban resume <srv> -> resume monitoring. - - fail2ban list -> list available services. - - fail2ban flush <srv> -> flush the <srv> ban list. - -- remove PID file. - -- remove most of the command lines options if possible. - -- add the possibility to specify wildcard in log files. - Example: logfile = /var/log/apache2/access-*.log - Should we start one thread per file or just one thread per - serivce? - -- autodetect date format in log file. Match the most popular - format and sort them using the hit ratio. Should avoid - user problem with regex and not have a big impact on perfs. - -- restart automatically the daemon if an exception occurs. +- Don't close socket after a send +- Multiple actions !!!
\ No newline at end of file diff --git a/confreader/__init__.py b/client/__init__.py index 76dba873..60ef5531 100644 --- a/confreader/__init__.py +++ b/client/__init__.py @@ -16,10 +16,10 @@ # Author: Cyril Jaquier # -# $Revision$ +# $Revision: 1.1 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL"
\ No newline at end of file diff --git a/client/actionreader.py b/client/actionreader.py new file mode 100644 index 00000000..5486b90e --- /dev/null +++ b/client/actionreader.py @@ -0,0 +1,80 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.6 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.6 $" +__date__ = "$Date: 2005/11/20 17:07:47 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import logging +from configreader import ConfigReader + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client.config") + +class ActionReader(ConfigReader): + + def __init__(self, file, name): + ConfigReader.__init__(self) + self.file = file + self.name = name + + def setFile(self, file): + self.file = file + + def getFile(self): + return self.file + + def setName(self, name): + self.name = name + + def getName(self): + return self.name + + def read(self): + ConfigReader.read(self, "action.d/" + self.file) + + def getOptions(self, pOpts): + opts = [["string", "bantime", "600"], + ["string", "actionstart", ""], + ["string", "actionstop", ""], + ["string", "actioncheck", ""], + ["string", "actionban", ""], + ["string", "actionunban", ""]] + self.opts = ConfigReader.getOptions(self, "DEFAULT", opts, pOpts) + + def convert(self): + stream = list() + for opt in self.opts: + if opt == "bantime": + stream.append(["set", self.name, "bantime", self.opts[opt]]) + elif opt == "actionstart": + stream.append(["set", self.name, "actionstart", self.opts[opt]]) + elif opt == "actionstop": + stream.append(["set", self.name, "actionstop", self.opts[opt]]) + elif opt == "actioncheck": + stream.append(["set", self.name, "actioncheck", self.opts[opt]]) + elif opt == "actionban": + stream.append(["set", self.name, "actionban", self.opts[opt]]) + elif opt == "actionunban": + stream.append(["set", self.name, "actionunban", self.opts[opt]]) + return stream +
\ No newline at end of file diff --git a/confreader/configreader.py b/client/configreader.py index 150858b5..27b56fd2 100644 --- a/confreader/configreader.py +++ b/client/configreader.py @@ -16,70 +16,73 @@ # Author: Cyril Jaquier # -# $Revision$ +# $Revision: 1.6 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" +__version__ = "$Revision: 1.6 $" +__date__ = "$Date: 2005/11/20 17:07:47 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" import logging - from ConfigParser import * # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban") - -class ConfigReader: - """ This class allow the handling of the configuration options. - The DEFAULT section contains the global information about - Fail2Ban. Each other section is for a different log file. - """ +logSys = logging.getLogger("fail2ban.client.config") - def __init__(self, confPath): - self.confPath = confPath - self.configParser = SafeConfigParser() +class ConfigReader(SafeConfigParser): + + basedir = "/etc/fail2ban/" + + def __init__(self): + SafeConfigParser.__init__(self) + self.opts = None + + @staticmethod + def setBaseDir(dir): + global basedir + path = dir.rstrip('/') + basedir = path + '/' - def openConf(self): - """ Opens the configuration file. - """ - self.configParser.read(self.confPath) + @staticmethod + def getBaseDir(): + global basedir + return basedir - def getSections(self): - """ Returns all the sections present in the configuration - file except the DEFAULT and MAIL sections. - """ - sections = self.configParser.sections() - sections.remove("MAIL") - logSys.debug("Found sections: " + `sections`) - return sections + def read(self, filename): + global basedir + basename = basedir + filename + logSys.debug("Reading " + basename) + SafeConfigParser.read(self, [basename + ".conf", basename + ".local"]) + ## + # Read the options. + # + # Read the given option in the configuration file. Default values + # are used... # Each optionValues entry is composed of an array with: # 0 -> the type of the option # 1 -> the name of the option # 2 -> the default value for the option - def getLogOptions(self, sec, options): - """ Gets all the options of a given section. The options - are defined in the optionValues list. - """ + def getOptions(self, sec, options, pOptions = None): values = dict() for option in options: try: if option[0] == "bool": - v = self.configParser.getboolean(sec, option[1]) + v = self.getboolean(sec, option[1]) elif option[0] == "int": - v = self.configParser.getint(sec, option[1]) + v = self.getint(sec, option[1]) else: - v = self.configParser.get(sec, option[1]) - + v = self.get(sec, option[1]) + if not pOptions == None and option[1] in pOptions: + continue values[option[1]] = v except NoOptionError: - logSys.warn("No '" + option[1] + "' defined in '" + sec + "'") - values[option[1]] = option[2] + if not option[2] == None: + logSys.warn("No '" + option[1] + "' defined in '" + sec + "'") + values[option[1]] = option[2] except ValueError: logSys.warn("Wrong value for '" + option[1] + "' in '" + sec + "'. Using default one: '" + `option[2]` + "'") values[option[1]] = option[2] - return values -
\ No newline at end of file + return values
\ No newline at end of file diff --git a/client/configurator.py b/client/configurator.py new file mode 100644 index 00000000..9ceed3d2 --- /dev/null +++ b/client/configurator.py @@ -0,0 +1,68 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.6 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.6 $" +__date__ = "$Date: 2005/11/20 17:07:47 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import logging +from configreader import ConfigReader +from fail2banreader import Fail2banReader +from jailsreader import JailsReader + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client.config") + +class Configurator: + + def __init__(self): + self.settings = dict() + self.streams = dict() + self.fail2ban = Fail2banReader() + self.jails = JailsReader() + + def setBaseDir(self, dir): + ConfigReader.setBaseDir(dir) + + def getBaseDir(self): + return ConfigReader.getBaseDir() + + def readAll(self): + self.fail2ban.read() + self.jails.read() + + def getAllOptions(self): + self.settings["general"] = self.fail2ban.getOptions() + self.settings["jails"] = self.jails.getOptions() + + def convertToProtocol(self): + self.streams["general"] = self.fail2ban.convert() + self.streams["jails"] = self.jails.convert() + + def getConfigStream(self): + cmds = list() + for opt in self.streams["general"]: + cmds.append(opt) + for opt in self.streams["jails"]: + cmds.append(opt) + return cmds +
\ No newline at end of file diff --git a/client/csocket.py b/client/csocket.py new file mode 100644 index 00000000..4e07fa0d --- /dev/null +++ b/client/csocket.py @@ -0,0 +1,54 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import socket, pickle + +class CSocket: + + def __init__(self): + self.socketFile = "/tmp/fail2ban.sock" + # Create an INET, STREAMing socket + #self.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.csock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + #self.csock.connect(("localhost", 2222)) + self.csock.connect(self.socketFile) + + def send(self, msg): + # Convert every list member to string + obj = pickle.dumps(map(str, msg)) + self.csock.send(obj + "<F2B_END_COMMAND>") + ret = self.receive(self.csock) + self.csock.close() + return ret + + def receive(self, socket): + msg = '' + while msg.rfind("<F2B_END_COMMAND>") == -1: + chunk = socket.recv(6) + if chunk == '': + raise RuntimeError, "socket connection broken" + msg = msg + chunk + return pickle.loads(msg) diff --git a/client/fail2banreader.py b/client/fail2banreader.py new file mode 100644 index 00000000..a99c3001 --- /dev/null +++ b/client/fail2banreader.py @@ -0,0 +1,51 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.6 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.6 $" +__date__ = "$Date: 2005/11/20 17:07:47 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import logging +from configreader import ConfigReader + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client.config") + +class Fail2banReader(ConfigReader): + + def __init__(self): + ConfigReader.__init__(self) + + def read(self): + ConfigReader.read(self, "fail2ban") + + def getOptions(self): + opts = [["int", "loglevel", 1]] + self.opts = ConfigReader.getOptions(self, "DEFAULT", opts) + + def convert(self): + stream = list() + for opt in self.opts: + if opt == "loglevel": + stream.append(["set", "loglevel", self.opts[opt]]) + return stream +
\ No newline at end of file diff --git a/client/filterreader.py b/client/filterreader.py new file mode 100644 index 00000000..79f517b8 --- /dev/null +++ b/client/filterreader.py @@ -0,0 +1,80 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.6 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.6 $" +__date__ = "$Date: 2005/11/20 17:07:47 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import logging +from configreader import ConfigReader + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client.config") + +class FilterReader(ConfigReader): + + def __init__(self, file, name): + ConfigReader.__init__(self) + self.file = file + self.name = name + + def setFile(self, file): + self.file = file + + def getFile(self): + return self.file + + def setName(self, name): + self.name = name + + def getName(self): + return self.name + + def read(self): + ConfigReader.read(self, "filter.d/" + self.file) + + def getOptions(self, pOpts): + opts = [["string", "logpath", "/var/log/sshd.log"], + ["string", "timeregex", ""], + ["string", "timepattern", ""], + ["string", "failregex", ""], + ["int", "maxtime", 600], + ["int", "maxretry", 3]] + self.opts = ConfigReader.getOptions(self, "DEFAULT", opts, pOpts) + + def convert(self): + stream = list() + for opt in self.opts: + if opt == "logpath": + stream.append(["set", self.name, "logpath", self.opts[opt]]) + elif opt == "timeregex": + stream.append(["set", self.name, "timeregex", self.opts[opt]]) + elif opt == "timepattern": + stream.append(["set", self.name, "timepattern", self.opts[opt]]) + elif opt == "failregex": + stream.append(["set", self.name, "failregex", self.opts[opt]]) + elif opt == "maxtime": + stream.append(["set", self.name, "maxtime", self.opts[opt]]) + elif opt == "maxretry": + stream.append(["set", self.name, "maxretry", self.opts[opt]]) + return stream +
\ No newline at end of file diff --git a/client/jailreader.py b/client/jailreader.py new file mode 100644 index 00000000..b839172c --- /dev/null +++ b/client/jailreader.py @@ -0,0 +1,84 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.6 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.6 $" +__date__ = "$Date: 2005/11/20 17:07:47 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import logging +from configreader import ConfigReader +from filterreader import FilterReader +from actionreader import ActionReader + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client.config") + +class JailReader(ConfigReader): + + def __init__(self, name): + ConfigReader.__init__(self) + self.name = name + self.filter = None + self.action = None + + def setName(self, value): + self.name = value + + def getName(self): + return self.name + + def read(self): + ConfigReader.read(self, "jail") + + def isEnabled(self): + return self.opts["enabled"] + + def getOptions(self): + opts = [["bool", "enabled", "false"], + ["int", "maxretry", None], + ["int", "bantime", None], + ["string", "filter", ""], + ["string", "action", ""]] + self.opts = ConfigReader.getOptions(self, self.name, opts) + + if self.isEnabled(): + # Read filter + self.filter = FilterReader(self.opts["filter"], self.name) + self.filter.read() + self.filter.getOptions(self.opts) + + # Read action + self.action = ActionReader(self.opts["action"], self.name) + self.action.read() + self.action.getOptions(self.opts) + + def convert(self): + stream = [["add", self.name]] + for opt in self.opts: + if opt == "maxretry": + stream.append(["set", self.name, "maxretry", self.opts[opt]]) + elif opt == "bantime": + stream.append(["set", self.name, "bantime", self.opts[opt]]) + stream.extend(self.filter.convert()) + stream.extend(self.action.convert()) + return stream +
\ No newline at end of file diff --git a/client/jailsreader.py b/client/jailsreader.py new file mode 100644 index 00000000..b092cf21 --- /dev/null +++ b/client/jailsreader.py @@ -0,0 +1,73 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.6 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.6 $" +__date__ = "$Date: 2005/11/20 17:07:47 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import logging +from configreader import ConfigReader +from jailreader import JailReader + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client.config") + +class JailsReader(ConfigReader): + + def __init__(self): + ConfigReader.__init__(self) + self.jails = list() + + def read(self): + ConfigReader.read(self, "jail") + + def getOptions(self): + opts = [] + self.opts = ConfigReader.getOptions(self, "DEFAULT", opts) + + for sec in self.sections(): + jail = JailReader(sec) + jail.read() + jail.getOptions() + if jail.isEnabled(): + # We only add enabled jails + self.jails.append(jail) + + def getFilterOptions(self, file): + filter = FilterReader(file) + filter.read() + return filter.getOptions() + + def convert(self): + stream = list() + for opt in self.opts: + if opt == "": + stream.append([]) + # Convert jails + for jail in self.jails: + stream.extend(jail.convert()) + # Start jails + for jail in self.jails: + stream.append(["start", jail.getName()]) + + return stream +
\ No newline at end of file diff --git a/config/action.d/dummy.conf b/config/action.d/dummy.conf new file mode 100644 index 00000000..1be6253b --- /dev/null +++ b/config/action.d/dummy.conf @@ -0,0 +1,52 @@ +[DEFAULT] + +bantime = 1234 + +name = temporary + +# Option: protocol +# Notes.: internally used by config reader for interpolations. +# Values: [ tcp | udp | icmp | all ] Default: tcp +# +protocol = tcp + +# Option: fwstart +# Notes.: command executed once at the start of Fail2Ban. +# Values: CMD Default: +# +actionstart = touch /tmp/fail2ban.dummy + +# Option: fwend +# Notes.: command executed once at the end of Fail2Ban +# Values: CMD Default: +# +actionstop = rm /tmp/fail2ban.dummy + +# Option: fwcheck +# Notes.: command executed once before each fwban command +# Values: CMD Default: +# +actioncheck = + +# Option: fwban +# Notes.: command executed when banning an IP. Take care that the +# command is executed with Fail2Ban user rights. +# Tags: <ip> IP address +# <failures> number of failures +# <failtime> unix timestamp of the last failure +# <bantime> unix timestamp of the ban time +# Values: CMD +# Default: iptables -I INPUT 1 -s <ip> -j DROP +# +actionban = echo "+<ip>" >> /tmp/fail2ban.dummy + +# Option: fwunban +# Notes.: command executed when unbanning an IP. Take care that the +# command is executed with Fail2Ban user rights. +# Tags: <ip> IP address +# <bantime> unix timestamp of the ban time +# <unbantime> unix timestamp of the unban time +# Values: CMD +# Default: iptables -D INPUT -s <ip> -j DROP +# +actionunban = echo "-<ip>" >> /tmp/fail2ban.dummy diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf new file mode 100644 index 00000000..2da845f4 --- /dev/null +++ b/config/action.d/iptables.conf @@ -0,0 +1,55 @@ +[DEFAULT] + +name = temporary +port = 22 + +# Option: protocol +# Notes.: internally used by config reader for interpolations. +# Values: [ tcp | udp | icmp | all ] Default: tcp +# +protocol = tcp + +# Option: fwstart +# Notes.: command executed once at the start of Fail2Ban. +# Values: CMD Default: +# +actionstart = iptables -N fail2ban-%(name)s + iptables -A fail2ban-%(name)s -j RETURN + iptables -I INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(name)s + +# Option: fwend +# Notes.: command executed once at the end of Fail2Ban +# Values: CMD Default: +# +actionstop = iptables -D INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(name)s + iptables -F fail2ban-%(name)s + iptables -X fail2ban-%(name)s + +# Option: fwcheck +# Notes.: command executed once before each fwban command +# Values: CMD Default: +# +actioncheck = iptables -L INPUT | grep -q fail2ban-%(name)s + +# Option: fwban +# Notes.: command executed when banning an IP. Take care that the +# command is executed with Fail2Ban user rights. +# Tags: <ip> IP address +# <failures> number of failures +# <failtime> unix timestamp of the last failure +# <bantime> unix timestamp of the ban time +# Values: CMD +# Default: iptables -I INPUT 1 -s <ip> -j DROP +# +actionban = iptables -I fail2ban-%(name)s 1 -s <ip> -j DROP + +# Option: fwunban +# Notes.: command executed when unbanning an IP. Take care that the +# command is executed with Fail2Ban user rights. +# Tags: <ip> IP address +# <bantime> unix timestamp of the ban time +# <unbantime> unix timestamp of the unban time +# Values: CMD +# Default: iptables -D INPUT -s <ip> -j DROP +# +actionunban = iptables -D fail2ban-%(name)s -s <ip> -j DROP diff --git a/config/debian-initd b/config/debian-initd deleted file mode 100644 index 2c5c48d1..00000000 --- a/config/debian-initd +++ /dev/null @@ -1,73 +0,0 @@ -#! /bin/sh -# -# Fail2Ban init.d file - to be launched on boot -# -# Written by Miquel van Smoorenburg <miquels@cistron.nl>. -# Modified for Debian -# by Ian Murdock <imurdock@gnu.ai.mit.edu>. -# Adjusted for Fail2Ban -# by Yaroslav Halchenko <debian@onerussian.com>. -# -# Version: $Id$ -# - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/bin/fail2ban -NAME=fail2ban -DESC=fail2ban -PIDFILE=/var/run/$NAME.pid - -test -x $DAEMON || exit 0 - -# Include fail2ban defaults if available -if [ -f /etc/default/fail2ban ] ; then - . /etc/default/fail2ban -fi -DAEMON_OPTS=$FAIL2BAN_OPTS -set -e - -case "$1" in - start) - echo -n "Starting $DESC: " - [ -f $PIDFILE ] && [ ! -d /proc/`cat $PIDFILE` ] && rm -f $PIDFILE - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - -b --exec $DAEMON -- $DAEMON_OPTS - echo "$NAME." - ;; - stop) - echo -n "Stopping $DESC: " - start-stop-daemon --stop --quiet --pidfile $PIDFILE - echo "$NAME." - ;; - restart|force-reload) - echo -n "Restarting $DESC: " - ( $0 stop ) - sleep 1 - $0 start - ;; - status) - echo -n "Status of $DESC: " - if [ ! -e "$PIDFILE" ]; then - echo "$NAME is not running." - exit 3 - fi - if [ ! -r "$PIDFILE" ]; then - echo "$PIDFILE not readable, status of $NAME unknown." - exit 4 - fi - if [ -d /proc/`cat "$PIDFILE"` ]; then - echo "$NAME is running." - exit 0 - else - echo "$NAME is not running but $PIDFILE exists." - exit 1 - fi - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/config/fail2ban.conf b/config/fail2ban.conf new file mode 100644 index 00000000..32a33411 --- /dev/null +++ b/config/fail2ban.conf @@ -0,0 +1,4 @@ +[DEFAULT] + +loglevel = 4 + diff --git a/config/fail2ban.conf.hostsdeny b/config/fail2ban.conf.hostsdeny deleted file mode 100644 index 05c9d582..00000000 --- a/config/fail2ban.conf.hostsdeny +++ /dev/null @@ -1,327 +0,0 @@ -# Fail2Ban configuration file -# -# $Revision$ -# -# 2005.06.21 modified for readability Iain Lea iain@bricbrac.de - -[DEFAULT] -# Option: background -# Notes.: start fail2ban as a daemon. Output is redirect to logfile. -# Values: [true | false] Default: false -# -background = false - -# Option: logtargets -# Notes.: log targets. Space separated list of logging targets. -# Values: STDERR SYSLOG file Default: /var/log/fail2ban.log -# -logtargets = /var/log/fail2ban.log - -# Option: syslog-target -# Notes.: where to find syslog facility if logtarget SYSLOG. -# Values: SOCKET HOST HOST:PORT Default: /dev/log -# -syslog-target = /dev/log - -# Option: syslog-facility -# Notes.: which syslog facility to use if logtarget SYSLOG. -# Values: NUM Default: 1 -# -syslog-facility = 1 - -# Option: pidlock -# Notes.: path of the PID lock file (must be able to write to file). -# Values: FILE Default: /var/run/fail2ban.pid -# -pidlock = /var/run/fail2ban.pid - -# Option: maxfailures -# Notes.: number of failures before IP gets banned. -# Values: NUM Default: 5 -# -maxfailures = 5 - -# Option: bantime -# Notes.: number of seconds an IP will be banned. If set to a negative -# value, IP will never be unbanned (permanent banning). -# Values: NUM Default: 600 -# -bantime = 600 - -# Option: findtime -# Notes.: lifetime in seconds of a "failed" log entry. -# Values: NUM Default: 600 -# -findtime = 600 - -# Option: ignoreip -# Notes.: space separated list of IP's to be ignored by fail2ban. -# You can use CIDR mask in order to specify a range. -# Example: ignoreip = 192.168.0.1/24 123.45.235.65 -# Values: IP Default: -# -ignoreip = - -# Option: cmdstart -# Notes.: command executed once at the start of Fail2Ban -# Values: CMD Default: -# -cmdstart = - -# Option: cmdend -# Notes.: command executed once at the end of Fail2Ban. -# Values: CMD Default: -# -cmdend = - -# Option: polltime -# Notes.: number of seconds fail2ban sleeps between iterations. -# Values: NUM Default: 1 -# -polltime = 1 - -# Option: reinittime -# Notes.: minimal number of seconds between the re-initialization of -# firewalls due to external changes in their rules (see fwcheck) -# Values: NUM Default: 100 -# -reinittime = 10 - -# Option: maxreinits -# Notes.: maximal number of re-initialization of firewalls due to external -# changes. -1 stays for infinite, so only reinittime is of importance -# Values: NUM Default: -1 -# -maxreinits = -1 - -# NOTE: Interpolations -# -# fwstart, as well as fwend, fwcheck, fwban, fwunban, use interpolations -# so %(__name__)s will be substituted by a name of each section -# (unless the option is overriden in a section). -# If you are going to use interpolations in your setup, please make -# sure that you specified options port and protocol (which also has -# an option in DEFAULT). -# - -# Option: hostsdeny -# Notes.: hosts.deny file path. -# Values: STR Default: /etc/hosts.deny -# -hostsdeny = /etc/hosts.deny - -# Option: fwban -# Notes.: command executed when banning an IP. Take care that the -# command is executed with Fail2Ban user rights. -# Tags: <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# <bantime> unix timestamp of the ban time -# Values: CMD -# Default: iptables -I INPUT 1 -s <ip> -j DROP -# -fwban = IP=<ip> && echo "ALL: $IP" >> %(hostsdeny)s - -# Option: fwunban -# Notes.: command executed when unbanning an IP. Take care that the -# command is executed with Fail2Ban user rights. -# Tags: <ip> IP address -# <bantime> unix timestamp of the ban time -# <unbantime> unix timestamp of the unban time -# Values: CMD -# Default: iptables -D INPUT -s <ip> -j DROP -# -fwunban = IP=<ip> && sed -i.old s/ALL:\ $IP// %(hostsdeny)s - -[MAIL] -# Option: enabled -# Notes.: enable mail notification when banning an IP address. -# Values: [true | false] Default: false -# -enabled = false - -# Option: host -# Notes.: host running the mail server. -# Values: STR Default: localhost -# -host = localhost - -# Option: port -# Notes.: port of the mail server. -# Values: INT Default: 25 -# -port = 25 - -# Option: user -# Notes.: the username for smtp-server if authentification is required. -# if user is empty, no authentification is done. -# Values: STR Default: -# -user = - -# Option: password -# Notes.: the smtp-user's password if authentification is required. -# Values: STR Default: -# -password = - -# Option: from -# Notes.: e-mail address of the sender. -# Values: MAIL Default: fail2ban -# -from = fail2ban - -# Option: to -# Notes.: e-mail addresses of the receiver. Addresses are space -# separated. -# Values: MAIL Default: root -# -to = root - -# Option: localtime -# Notes.: report local time (including timezone) or GMT -# Values: [true | false] Default: false -# -localtime = true - -# Option: subject -# Notes.: subject of the e-mail. -# Tags: <section> active section (eg ssh, apache, etc) -# <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# Values: TEXT Default: [Fail2Ban] <section>: Banned <ip> -# -subject = [Fail2Ban] <section>: Banned <ip> - -# Option: message -# Notes.: message of the e-mail. -# Tags: <section> active section (eg ssh, apache, etc) -# <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# <br> new line -# Values: TEXT Default: -# -message = Hi,<br> - The IP <ip> has just been banned by Fail2Ban after - <failures> attempts against <section>.<br> - Regards,<br> - Fail2Ban - -# You can define a new section for each log file to check for -# password failure. Each section has to define the following -# options: logfile, fwban, fwunban, timeregex, timepattern, -# failregex. - - -[Apache] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: false -# -enabled = false - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/httpd/access_log -# -logfile = /var/log/httpd/access_log - -# Option: timeregex -# Notes.: regex to match timestamp in Apache logfile. For TAI64N format, -# use timeregex = @[0-9a-f]{24} -# Values: [Wed Jan 05 15:08:01 2005] -# Default: \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4} -# -timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule). -# For TAI64N format, use timepattern = tai64n -# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y -# -timepattern = %%a %%b %%d %%H:%%M:%%S %%Y - -# Option: failregex -# Notes.: regex to match the password failure messages in the logfile. -# Values: TEXT Default: authentication failure|user .* not found -# -failregex = authentication failure|user .* not found - - -[VSFTPD] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: false -# -enabled = false - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/secure -# -logfile = /var/log/vsftpd.log - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = ftp - -# Option: timeregex -# Notes.: regex to match timestamp in VSFTPD logfile. -# Values: [Mar 7 17:53:28] -# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} -# -timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule) -# Values: TEXT Default: %%b %%d %%H:%%M:%%S -# -timepattern = %%b %%d %%H:%%M:%%S - -# Option: failregex -# Notes.: regex to match the password failures messages in the logfile. -# Values: TEXT Default: Authentication failure|Failed password|Invalid user -# -failregex = FAIL LOGIN - - -[SSH] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: true -# -enabled = true - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/secure -# -logfile = /var/log/secure - -# Option: timeregex -# Notes.: regex to match timestamp in SSH logfile. For TAI64N format, -# use timeregex = @[0-9a-f]{24} -# Values: [Mar 7 17:53:28] -# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} -# -timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule). -# For TAI64N format, use timepattern = tai64n -# Values: TEXT Default: %%b %%d %%H:%%M:%%S -# -timepattern = %%b %%d %%H:%%M:%%S - -# Option: failregex -# Notes.: regex to match the password failures messages in the logfile. -# Values: TEXT Default: Authentication failure|Failed password|Invalid user -# -failregex = Authentication failure|Failed password|Invalid user diff --git a/config/fail2ban.conf.iptables b/config/fail2ban.conf.iptables deleted file mode 100644 index 46da5466..00000000 --- a/config/fail2ban.conf.iptables +++ /dev/null @@ -1,362 +0,0 @@ -# Fail2Ban configuration file -# -# $Revision$ -# -# 2005.06.21 modified for readability Iain Lea iain@bricbrac.de - -[DEFAULT] -# Option: background -# Notes.: start fail2ban as a daemon. Output is redirect to logfile. -# Values: [true | false] Default: false -# -background = false - -# Option: logtargets -# Notes.: log targets. Space separated list of logging targets. -# Values: STDERR SYSLOG file Default: /var/log/fail2ban.log -# -logtargets = /var/log/fail2ban.log - -# Option: syslog-target -# Notes.: where to find syslog facility if logtarget SYSLOG. -# Values: SOCKET HOST HOST:PORT Default: /dev/log -# -syslog-target = /dev/log - -# Option: syslog-facility -# Notes.: which syslog facility to use if logtarget SYSLOG. -# Values: NUM Default: 1 -# -syslog-facility = 1 - -# Option: pidlock -# Notes.: path of the PID lock file (must be able to write to file). -# Values: FILE Default: /var/run/fail2ban.pid -# -pidlock = /var/run/fail2ban.pid - -# Option: maxfailures -# Notes.: number of failures before IP gets banned. -# Values: NUM Default: 5 -# -maxfailures = 5 - -# Option: bantime -# Notes.: number of seconds an IP will be banned. If set to a negative -# value, IP will never be unbanned (permanent banning). -# Values: NUM Default: 600 -# -bantime = 600 - -# Option: findtime -# Notes.: lifetime in seconds of a "failed" log entry. -# Values: NUM Default: 600 -# -findtime = 600 - -# Option: ignoreip -# Notes.: space separated list of IP's to be ignored by fail2ban. -# You can use CIDR mask in order to specify a range. -# Example: ignoreip = 192.168.0.1/24 123.45.235.65 -# Values: IP Default: -# -ignoreip = - -# Option: cmdstart -# Notes.: command executed once at the start of Fail2Ban -# Values: CMD Default: -# -cmdstart = - -# Option: cmdend -# Notes.: command executed once at the end of Fail2Ban. -# Values: CMD Default: -# -cmdend = - -# Option: polltime -# Notes.: number of seconds fail2ban sleeps between iterations. -# Values: NUM Default: 1 -# -polltime = 1 - -# Option: reinittime -# Notes.: minimal number of seconds between the re-initialization of -# firewalls due to external changes in their rules (see fwcheck) -# Values: NUM Default: 100 -# -reinittime = 10 - -# Option: maxreinits -# Notes.: maximal number of re-initialization of firewalls due to external -# changes. -1 stays for infinite, so only reinittime is of importance -# Values: NUM Default: -1 -# -maxreinits = -1 - -# NOTE: Interpolations -# -# fwstart, as well as fwend, fwcheck, fwban, fwunban, use interpolations -# so %(__name__)s will be substituted by a name of each section -# (unless the option is overriden in a section). -# If you are going to use interpolations in your setup, please make -# sure that you specified options port and protocol (which also has -# an option in DEFAULT). -# - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp - -# Option: fwstart -# Notes.: command executed once at the start of Fail2Ban. -# Values: CMD Default: -# -fwstart = iptables -N fail2ban-%(__name__)s - iptables -A fail2ban-%(__name__)s -j RETURN - iptables -I INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(__name__)s - -# Option: fwend -# Notes.: command executed once at the end of Fail2Ban -# Values: CMD Default: -# -fwend = iptables -D INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(__name__)s - iptables -F fail2ban-%(__name__)s - iptables -X fail2ban-%(__name__)s - -# Option: fwcheck -# Notes.: command executed once before each fwban command -# Values: CMD Default: -# -fwcheck = iptables -L INPUT | grep -q fail2ban-%(__name__)s - -# Option: fwban -# Notes.: command executed when banning an IP. Take care that the -# command is executed with Fail2Ban user rights. -# Tags: <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# <bantime> unix timestamp of the ban time -# Values: CMD -# Default: iptables -I INPUT 1 -s <ip> -j DROP -# -fwban = iptables -I fail2ban-%(__name__)s 1 -s <ip> -j DROP - -# Option: fwunban -# Notes.: command executed when unbanning an IP. Take care that the -# command is executed with Fail2Ban user rights. -# Tags: <ip> IP address -# <bantime> unix timestamp of the ban time -# <unbantime> unix timestamp of the unban time -# Values: CMD -# Default: iptables -D INPUT -s <ip> -j DROP -# -fwunban = iptables -D fail2ban-%(__name__)s -s <ip> -j DROP - -[MAIL] -# Option: enabled -# Notes.: enable mail notification when banning an IP address. -# Values: [true | false] Default: false -# -enabled = false - -# Option: host -# Notes.: host running the mail server. -# Values: STR Default: localhost -# -host = localhost - -# Option: port -# Notes.: port of the mail server. -# Values: INT Default: 25 -# -port = 25 - -# Option: user -# Notes.: the username for smtp-server if authentification is required. -# if user is empty, no authentification is done. -# Values: STR Default: -# -user = - -# Option: password -# Notes.: the smtp-user's password if authentification is required. -# Values: STR Default: -# -password = - -# Option: from -# Notes.: e-mail address of the sender. -# Values: MAIL Default: fail2ban -# -from = fail2ban - -# Option: to -# Notes.: e-mail addresses of the receiver. Addresses are space -# separated. -# Values: MAIL Default: root -# -to = root - -# Option: localtime -# Notes.: report local time (including timezone) or GMT -# Values: [true | false] Default: false -# -localtime = true - -# Option: subject -# Notes.: subject of the e-mail. -# Tags: <section> active section (eg ssh, apache, etc) -# <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# Values: TEXT Default: [Fail2Ban] <section>: Banned <ip> -# -subject = [Fail2Ban] <section>: Banned <ip> - -# Option: message -# Notes.: message of the e-mail. -# Tags: <section> active section (eg ssh, apache, etc) -# <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# <br> new line -# Values: TEXT Default: -# -message = Hi,<br> - The IP <ip> has just been banned by Fail2Ban after - <failures> attempts against <section>.<br> - Regards,<br> - Fail2Ban - -# You can define a new section for each log file to check for -# password failure. Each section has to define the following -# options: logfile, fwban, fwunban, timeregex, timepattern, -# failregex. - - -[Apache] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: false -# -enabled = false - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/httpd/access_log -# -logfile = /var/log/httpd/access_log - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = http - -# Option: timeregex -# Notes.: regex to match timestamp in Apache logfile. For TAI64N format, -# use timeregex = @[0-9a-f]{24} -# Values: [Wed Jan 05 15:08:01 2005] -# Default: \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4} -# -timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule). -# For TAI64N format, use timepattern = tai64n -# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y -# -timepattern = %%a %%b %%d %%H:%%M:%%S %%Y - -# Option: failregex -# Notes.: regex to match the password failure messages in the logfile. -# Values: TEXT Default: authentication failure|user .* not found -# -failregex = authentication failure|user .* not found - - -[VSFTPD] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: false -# -enabled = false - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/secure -# -logfile = /var/log/vsftpd.log - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = ftp - -# Option: timeregex -# Notes.: regex to match timestamp in VSFTPD logfile. -# Values: [Mar 7 17:53:28] -# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} -# -timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule) -# Values: TEXT Default: %%b %%d %%H:%%M:%%S -# -timepattern = %%b %%d %%H:%%M:%%S - -# Option: failregex -# Notes.: regex to match the password failures messages in the logfile. -# Values: TEXT Default: Authentication failure|Failed password|Invalid user -# -failregex = FAIL LOGIN - - -[SSH] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: true -# -enabled = true - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/secure -# -#logfile = /var/log/secure -logfile = /home/cyril/workspace/fail2ban-stable/log-test/test - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = ssh - -# Option: timeregex -# Notes.: regex to match timestamp in SSH logfile. For TAI64N format, -# use timeregex = @[0-9a-f]{24} -# Values: [Mar 7 17:53:28] -# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} -# -timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule). -# For TAI64N format, use timepattern = tai64n -# Values: TEXT Default: %%b %%d %%H:%%M:%%S -# -timepattern = %%b %%d %%H:%%M:%%S - -# Option: failregex -# Notes.: regex to match the password failures messages in the logfile. -# Values: TEXT Default: Authentication failure|Failed password|Invalid user -# -failregex = Authentication failure|Failed password|Invalid user diff --git a/config/fail2ban.conf.shorewall b/config/fail2ban.conf.shorewall deleted file mode 100644 index 2cb0fc46..00000000 --- a/config/fail2ban.conf.shorewall +++ /dev/null @@ -1,314 +0,0 @@ -# Fail2Ban configuration file -# -# $Revision$ -# -# 2005.06.21 modified for readability Iain Lea iain@bricbrac.de - -[DEFAULT] -# Option: background -# Notes.: start fail2ban as a daemon. Output is redirect to logfile. -# Values: [true | false] Default: false -# -background = false - -# Option: logtargets -# Notes.: log targets. Space separated list of logging targets. -# Values: STDERR SYSLOG file Default: /var/log/fail2ban.log -# -logtargets = /var/log/fail2ban.log - -# Option: syslog-target -# Notes.: where to find syslog facility if logtarget SYSLOG. -# Values: SOCKET HOST HOST:PORT Default: /dev/log -# -syslog-target = /dev/log - -# Option: syslog-facility -# Notes.: which syslog facility to use if logtarget SYSLOG. -# Values: NUM Default: 1 -# -syslog-facility = 1 - -# Option: pidlock -# Notes.: path of the PID lock file (must be able to write to file). -# Values: FILE Default: /var/run/fail2ban.pid -# -pidlock = /var/run/fail2ban.pid - -# Option: maxfailures -# Notes.: number of failures before IP gets banned. -# Values: NUM Default: 5 -# -maxfailures = 5 - -# Option: bantime -# Notes.: number of seconds an IP will be banned. If set to a negative -# value, IP will never be unbanned (permanent banning). -# Values: NUM Default: 600 -# -bantime = 600 - -# Option: findtime -# Notes.: lifetime in seconds of a "failed" log entry. -# Values: NUM Default: 600 -# -findtime = 600 - -# Option: ignoreip -# Notes.: space separated list of IP's to be ignored by fail2ban. -# You can use CIDR mask in order to specify a range. -# Example: ignoreip = 192.168.0.1/24 123.45.235.65 -# Values: IP Default: -# -ignoreip = - -# Option: cmdstart -# Notes.: command executed once at the start of Fail2Ban -# Values: CMD Default: -# -cmdstart = - -# Option: cmdend -# Notes.: command executed once at the end of Fail2Ban. -# Values: CMD Default: -# -cmdend = - -# Option: polltime -# Notes.: number of seconds fail2ban sleeps between iterations. -# Values: NUM Default: 1 -# -polltime = 1 - -# Option: reinittime -# Notes.: minimal number of seconds between the re-initialization of -# firewalls due to external changes in their rules (see fwcheck) -# Values: NUM Default: 100 -# -reinittime = 10 - -# Option: maxreinits -# Notes.: maximal number of re-initialization of firewalls due to external -# changes. -1 stays for infinite, so only reinittime is of importance -# Values: NUM Default: -1 -# -maxreinits = -1 - -# NOTE: Interpolations -# -# fwstart, as well as fwend, fwcheck, fwban, fwunban, use interpolations -# so %(__name__)s will be substituted by a name of each section -# (unless the option is overriden in a section). -# If you are going to use interpolations in your setup, please make -# sure that you specified options port and protocol (which also has -# an option in DEFAULT). -# - -# Option: fwban -# Notes.: command executed when banning an IP. Take care that the -# command is executed with Fail2Ban user rights. -# Tags: <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# <bantime> unix timestamp of the ban time -# Values: CMD -# Default: iptables -I INPUT 1 -s <ip> -j DROP -# -fwban = shorewall drop <ip> - -# Option: fwunban -# Notes.: command executed when unbanning an IP. Take care that the -# command is executed with Fail2Ban user rights. -# Tags: <ip> IP address -# <bantime> unix timestamp of the ban time -# <unbantime> unix timestamp of the unban time -# Values: CMD -# Default: iptables -D INPUT -s <ip> -j DROP -# -fwunban = shorewall allow <ip> - -[MAIL] -# Option: enabled -# Notes.: enable mail notification when banning an IP address. -# Values: [true | false] Default: false -# -enabled = false - -# Option: host -# Notes.: host running the mail server. -# Values: STR Default: localhost -# -host = localhost - -# Option: port -# Notes.: port of the mail server. -# Values: INT Default: 25 -# -port = 25 - -# Option: user -# Notes.: the username for smtp-server if authentification is required. -# if user is empty, no authentification is done. -# Values: STR Default: -# -user = - -# Option: password -# Notes.: the smtp-user's password if authentification is required. -# Values: STR Default: -# -password = - -# Option: from -# Notes.: e-mail address of the sender. -# Values: MAIL Default: fail2ban -# -from = fail2ban - -# Option: to -# Notes.: e-mail addresses of the receiver. Addresses are space -# separated. -# Values: MAIL Default: root -# -to = root - -# Option: localtime -# Notes.: report local time (including timezone) or GMT -# Values: [true | false] Default: false -# -localtime = true - -# Option: subject -# Notes.: subject of the e-mail. -# Tags: <section> active section (eg ssh, apache, etc) -# <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# Values: TEXT Default: [Fail2Ban] <section>: Banned <ip> -# -subject = [Fail2Ban] <section>: Banned <ip> - -# Option: message -# Notes.: message of the e-mail. -# Tags: <section> active section (eg ssh, apache, etc) -# <ip> IP address -# <failures> number of failures -# <failtime> unix timestamp of the last failure -# <br> new line -# Values: TEXT Default: -# -message = Hi,<br> - The IP <ip> has just been banned by Fail2Ban after - <failures> attempts against <section>.<br> - Regards,<br> - Fail2Ban - -# You can define a new section for each log file to check for -# password failure. Each section has to define the following -# options: logfile, fwban, fwunban, timeregex, timepattern, -# failregex. - - -[Apache] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: false -# -enabled = false - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/httpd/access_log -# -logfile = /var/log/httpd/access_log - -# Option: timeregex -# Notes.: regex to match timestamp in Apache logfile. For TAI64N format, -# use timeregex = @[0-9a-f]{24} -# Values: [Wed Jan 05 15:08:01 2005] -# Default: \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4} -# -timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule). -# For TAI64N format, use timepattern = tai64n -# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y -# -timepattern = %%a %%b %%d %%H:%%M:%%S %%Y - -# Option: failregex -# Notes.: regex to match the password failure messages in the logfile. -# Values: TEXT Default: authentication failure|user .* not found -# -failregex = authentication failure|user .* not found - -[VSFTPD] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: false -# -enabled = false - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/secure -# -logfile = /var/log/vsftpd.log - -# Option: timeregex -# Notes.: regex to match timestamp in VSFTPD logfile. -# Values: [Mar 7 17:53:28] -# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} -# -timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule) -# Values: TEXT Default: %%b %%d %%H:%%M:%%S -# -timepattern = %%b %%d %%H:%%M:%%S - -# Option: failregex -# Notes.: regex to match the password failures messages in the logfile. -# Values: TEXT Default: Authentication failure|Failed password|Invalid user -# -failregex = FAIL LOGIN - - -[SSH] -# Option: enabled -# Notes.: enable monitoring for this section. -# Values: [true | false] Default: true -# -enabled = true - -# Option: logfile -# Notes.: logfile to monitor. -# Values: FILE Default: /var/log/secure -# -logfile = /var/log/secure - -# Option: timeregex -# Notes.: regex to match timestamp in SSH logfile. For TAI64N format, -# use timeregex = @[0-9a-f]{24} -# Values: [Mar 7 17:53:28] -# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} -# -timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} - -# Option: timepattern -# Notes.: format used in "timeregex" fields definition. Note that '%' must be -# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule). -# For TAI64N format, use timepattern = tai64n -# Values: TEXT Default: %%b %%d %%H:%%M:%%S -# -timepattern = %%b %%d %%H:%%M:%%S - -# Option: failregex -# Notes.: regex to match the password failures messages in the logfile. -# Values: TEXT Default: Authentication failure|Failed password|Invalid user -# -failregex = Authentication failure|Failed password|Invalid user diff --git a/config/fail2ban.local b/config/fail2ban.local new file mode 100644 index 00000000..12b8a6f5 --- /dev/null +++ b/config/fail2ban.local @@ -0,0 +1,4 @@ +[DEFAULT] + +test = 4567 +prout = fuck you diff --git a/config/filter.d/apache-auth.conf b/config/filter.d/apache-auth.conf new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/config/filter.d/apache-auth.conf diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf new file mode 100644 index 00000000..7d2a007a --- /dev/null +++ b/config/filter.d/sshd.conf @@ -0,0 +1,32 @@ +[DEFAULT] + +maxretry = 22 + +# Option: logpath +# Notes.: logfile to monitor. +# Values: FILE Default: /var/log/secure +# +logpath = testcases/files/testcase01.log + +# Option: timeregex +# Notes.: regex to match timestamp in SSH logfile. For TAI64N format, +# use timeregex = @[0-9a-f]{24} +# Values: [Mar 7 17:53:28] +# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} +# +timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} + +# Option: timepattern +# Notes.: format used in "timeregex" fields definition. Note that '%' must be +# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule). +# For TAI64N format, use timepattern = tai64n +# Values: TEXT Default: %%b %%d %%H:%%M:%%S +# +timepattern = %%b %%d %%H:%%M:%%S + +# Option: failregex +# Notes.: regex to match the password failures messages in the logfile. +# Values: TEXT Default: Authentication failure|Failed password|Invalid user +# +failregex = Authentication failure|Failed password|Invalid user + diff --git a/config/gentoo-confd b/config/gentoo-confd deleted file mode 100644 index bea9017e..00000000 --- a/config/gentoo-confd +++ /dev/null @@ -1,23 +0,0 @@ -# This file is part of Fail2Ban. -# -# Fail2Ban is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Fail2Ban is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Fail2Ban; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Author: Cyril Jaquier -# -# $Revision$ - -# Command line options for Fail2Ban. Refer to "fail2ban -h" for -# valid options. -FAIL2BAN_OPTS="-v" diff --git a/config/gentoo-initd b/config/gentoo-initd deleted file mode 100755 index 8cab7535..00000000 --- a/config/gentoo-initd +++ /dev/null @@ -1,50 +0,0 @@ -#!/sbin/runscript -# This file is part of Fail2Ban. -# -# Fail2Ban is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Fail2Ban is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Fail2Ban; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Author: Sireyessire, Cyril Jaquier -# -# $Revision$ - -opts="start stop restart showlog" - -FAIL2BAN="/usr/bin/fail2ban" - -depend() { - need net - need logger - after iptables -} - -start() { - ebegin "Starting fail2ban" - ${FAIL2BAN} -b ${FAIL2BAN_OPTS} > /dev/null - eend $? "Failed to start fail2ban" -} - -stop() { - ebegin "Stopping fail2ban" - ${FAIL2BAN} -k > /dev/null - eend $? "Failed to stop fail2ban" -} - -zap() { - rm /var/run/fail2ban.pid -} - -showlog(){ - less /var/log/fail2ban.log -} diff --git a/config/jail.conf b/config/jail.conf new file mode 100644 index 00000000..66853517 --- /dev/null +++ b/config/jail.conf @@ -0,0 +1,21 @@ +[dummy] + +enabled = true +filter = sshd +action = dummy +maxretry = 2 +#bantime = 10 + +[SSH] + +enabled = false +filter = sshd +action = iptables +bantime = 10 + +[Apache-error] + +enabled = false +filter = apache-error +action = hostdeny + diff --git a/config/redhat-initd b/config/redhat-initd deleted file mode 100644 index 6e885ab5..00000000 --- a/config/redhat-initd +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash -# -# fail2ban -# -# chkconfig: 345 91 9 -# description: if many unsuccessfull login attempts from some ip address \ -# during a short period happen, this address is banned \ -# by the firewall -# -# Author: Andrey G. Grozin -# -# $Revision$ - -# Source function library. -. /etc/init.d/functions - -# Get config. -. /etc/sysconfig/network - -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 -[ -f /etc/fail2ban.conf ] || exit 0 - -FAIL2BAN="/usr/bin/fail2ban" -PIDFILE="/var/run/fail2ban.pid" - -RETVAL=0 - -start() { - echo -n $"Starting fail2ban: " - "${FAIL2BAN}" -b > /dev/null - RETVAL=$? - echo -} - -stop() { - if [ -f "${PIDFILE}" ]; then - echo -n $"Stopping fail2ban: " - "${FAIL2BAN}" -k > /dev/null - echo - fi -} - -restart() { - stop - start -} - -# See how we were called. -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - status fail2ban - RETVAL=$? - ;; - reload) - restart - ;; - restart) - restart - ;; - condrestart) - if [ -f "${PIDFILE}" ]; then - restart - fi - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart}" - exit 1 - ;; -esac - -exit $RETVAL diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 00000000..39a9beae --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,1237 @@ +# Doxyfile 1.4.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Fail2Ban + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.7 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = YES + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../server ../client ../testcases ../utils ../ + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = *.py + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/fail2ban b/fail2ban deleted file mode 100755 index 5eace8bd..00000000 --- a/fail2ban +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python - -# This file is part of Fail2Ban. -# -# Fail2Ban is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Fail2Ban is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Fail2Ban; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -# Author: Cyril Jaquier -# -# $Revision$ - -__author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" -__copyright__ = "Copyright (c) 2004 Cyril Jaquier" -__license__ = "GPL" - -import sys, traceback, logging, locale - -# Set the locale with the user's default setting -try: - locale.setlocale(locale.LC_ALL, '') -except Exception: - print "Unable to set locale to " + `locale.getdefaultlocale()` - sys.exit(-1) - -# Inserts our own modules path first in the list -# fix for bug #343821 -sys.path.insert(1, "/usr/lib/fail2ban") - -# Now we can import our modules. -import fail2ban -from utils.pidlock import PIDLock - -# Get the instance of the logger. -logSys = logging.getLogger("fail2ban") - -# Get PID lock file instance -pidLock = PIDLock() - -# Handle all the unhandled exceptions -try: - # Start the application - fail2ban.main() -except SystemExit: - # We called sys.exit(). Nothing wrong so just pass - pass -except Exception, e: - # Print the exception data - (type, value, tb) = sys.exc_info() - tbStack = traceback.extract_tb(tb) - logSys.error("Fail2Ban got an unhandled exception and died.") - logSys.error("Type: " + `type.__name__` + "\n" + - "Value: " + `e.args` + "\n" + - "TB: " + `tbStack`) - # Try to clean up after ourselves - # just for extreme caution - wrapping with try - try: - fail2ban.restoreFwRules() - except Exception: - pass - # Remove the PID lock file. Should close #1239562 - pidLock.remove() - logging.shutdown() diff --git a/fail2ban-client b/fail2ban-client new file mode 100755 index 00000000..fa395b6e --- /dev/null +++ b/fail2ban-client @@ -0,0 +1,236 @@ +#!/usr/bin/env python +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import sys, string, os, pickle, re, logging, getopt, time + +# Inserts our own modules path first in the list +# fix for bug #343821 +sys.path.insert(1, "/usr/lib/fail2ban") + +# Now we can import our modules +from client.csocket import CSocket +from client.configurator import Configurator + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.client") + +## +# +# @todo This class needs cleanup. + +class Fail2banClient: + + def __init__(self): + self.argv = None + self.stream = None + self.conf = dict() + self.conf["cmdfile"] = None + self.conf["background"] = True + self.conf["dump"] = False + + def dispUsage(self): + """ Prints Fail2Ban command line options and exits + """ + print "Usage: "+self.argv[0]+" [OPTIONS] <COMMAND>" + print + print "Fail2Ban v0.7 reads log file that contains password failure report" + print "and bans the corresponding IP addresses using firewall rules." + print + print " -b start in background" + print " -f start in foreground" + print " -c <DIR> configuration directory" + print " -s <FILE> read command file" + print " -d dump configuration" + print " -h display this help message" + print + print "Report bugs to <lostcontrol@users.sourceforge.net>" + sys.exit(0) + + def getCmdLineOptions(self, optList): + """ Gets the command line options + """ + for opt in optList: + if opt[0] == "-d": + self.conf["dump"] = True + if opt[0] == "-b": + self.conf["background"] = True + if opt[0] == "-f": + self.conf["background"] = False + if opt[0] == "-s": + self.conf["cmdfile"] = opt[1] + if opt[0] in ["-h", "--help"]: + self.dispUsage() + + def ping(self): + return self.processCmd([["ping"]]) + + @staticmethod + def processCmd(cmd): + for c in cmd: + try: + client = CSocket() + except Exception, e: + logSys.error(e) + logSys.error("Arrggh... Start the server first") + return False + ret = client.send(c) + if ret[0] == 0: + logSys.info("OK : " + `ret[1]`) + else: + logSys.info("NOK: " + `ret[1].args`) + return False + return True + + ## + # Process a command line. + # + # Process one command line and exit. + # @param cmd the command line + + def processCommand(self, cmd): + if self.conf["dump"]: + self.readConfig() + self.dumpConfig(self.stream) + return True + + if len(sys.argv) < 2: + logSys.error("Add some options...") + return False + + if cmd[0] == "start" and len(cmd) == 1: + self.readConfig() + self.startServer(self.conf["background"]) + # Configure the server + self.processCmd(self.stream) + else: + try: + client = CSocket() + ret = client.send(cmd) + if ret[0] == 0: + logSys.info("OK : " + `ret[1]`) + return True + else: + logSys.info("NOK: " + `ret[1].args`) + return False + except SystemExit, e: + return True + except Exception, e: + logSys.error(e) + logSys.error("Arrggh... Start the server first") + return False + + ## + # Process a script file. + # + # Read each line of the file and execute the command. Lines which + # start with '#' are ignored. + # @bug The splitting of the command is wrong and awful. + # @param file the path of the script file + + def processFile(self, file): + try: + handler = open(file) + except IOError: + logSys.fatal("Unable to open " + file) + return False + for line in handler: + l = line.strip() + if l.find('#') != 0: + s = re.split("\s+", l, 3) + j = list() + for i in s: + j.append(i.strip("'")) + self.processCommand(j) + return True + + ## + # Start Fail2Ban server. + # + # Start the Fail2ban server in daemon mode. + + def startServer(self, background = True): + args = list() + args.append("fail2ban-server") + if background: + args.append("-b") + else: + args.append("-f") + + pid = os.fork() + if pid == 0: + os.execv("fail2ban-server", args) + else: + # Wait for the server to start + while not self.ping(): + time.sleep(0.1) + + def start(self, argv): + # Command line options + self.argv = argv + + # Reads the command line options. + try: + cmdOpts = 'bfhc:s:d' + cmdLongOpts = ['help'] + optList, args = getopt.getopt(self.argv[1:], cmdOpts, cmdLongOpts) + except getopt.GetoptError: + self.dispUsage() + + self.getCmdLineOptions(optList) + + logSys.setLevel(logging.DEBUG) + # Add the default logging handler + stdout = logging.StreamHandler(sys.stdout) + # set a format which is simpler for console use + formatter = logging.Formatter('%(name)-16s: %(levelname)-6s %(message)s') + # tell the handler to use this format + stdout.setFormatter(formatter) + logSys.addHandler(stdout) + + if self.conf["cmdfile"] == None: + self.processCommand(args) + else: + self.processFile(self.conf["cmdfile"]) + + def readConfig(self): + # Read the configuration + cfg = Configurator() + cfg.setBaseDir("config") + cfg.readAll() + cfg.getAllOptions() + cfg.convertToProtocol() + self.stream = cfg.getConfigStream() + + @staticmethod + def dumpConfig(cmd): + for c in cmd: + print c + return True + +if __name__ == "__main__": + client = Fail2banClient() + client.start(sys.argv) diff --git a/fail2ban-server b/fail2ban-server new file mode 100755 index 00000000..1d8ece42 --- /dev/null +++ b/fail2ban-server @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from server.server import Server +from utils.process import * +import locale, getopt, logging, sys + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban") + +## +# \mainpage Fail2Ban +# +# \section Introduction +# +# Fail2ban is designed to protect your server against brute force attacks. +# Its first goal was to protect a SSH server. + +class Fail2banServer: + + def __init__(self): + self.server = None + self.argv = None + self.conf = dict() + self.conf["background"] = True + + def dispUsage(self): + """ Prints Fail2Ban command line options and exits + """ + print "Usage: "+self.argv[0]+" [OPTIONS]" + print + print "Fail2Ban v0.7 reads log file that contains password failure report" + print "and bans the corresponding IP addresses using firewall rules." + print + print " -b start in background" + print " -f start in foreground" + print " -h display this help message" + print + print "Report bugs to <lostcontrol@users.sourceforge.net>" + sys.exit(0) + + def getCmdLineOptions(self, optList): + """ Gets the command line options + """ + for opt in optList: + if opt[0] == "-b": + self.conf["background"] = True + if opt[0] == "-f": + self.conf["background"] = False + if opt[0] in ["-h", "--help"]: + self.dispUsage() + + #def sigTERMhandler(signum, frame): + # """ Handles the TERM signal when in daemon mode in order to + # exit properly. + # """ + # logSys.debug("Signal handler called with sig "+`signum`) + # server.quit() + + def start(self, argv): + # Command line options + self.argv = argv + + # Reads the command line options. + try: + cmdOpts = 'bfh' + cmdLongOpts = ['help'] + optList, args = getopt.getopt(self.argv[1:], cmdOpts, cmdLongOpts) + except getopt.GetoptError: + self.dispUsage() + + self.getCmdLineOptions(optList) + + # Add the default logging handler + stdout = logging.StreamHandler(sys.stdout) + # set a format which is simpler for console use + formatter = logging.Formatter('%(name)-16s: %(levelname)-6s %(message)s') + # tell the handler to use this format + stdout.setFormatter(formatter) + logSys.addHandler(stdout) + + if self.conf["background"]: + retCode = createDaemon() + #signal.signal(signal.SIGTERM, sigTERMhandler) + if not retCode: + logSys.error("Unable to start daemon") + sys.exit(-1) + + try: + self.server = Server() + self.server.start() + except Exception, e: + print e + self.server.quit() + +if __name__ == "__main__": + server = Fail2banServer() + server.start(sys.argv) diff --git a/fail2ban-testcases b/fail2ban-testcases new file mode 100755 index 00000000..3c427fe9 --- /dev/null +++ b/fail2ban-testcases @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + + +import unittest, logging, sys + +from testcases import filtertestcase +from testcases import servertestcase +from testcases import failmanagertestcase +from testcases import banmanagertestcase + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban") +# Add the default logging handler +stdout = logging.StreamHandler(sys.stdout) +logSys.addHandler(stdout) +logSys.setLevel(logging.FATAL) + +print "Fail2ban test suite. Please wait..." + +tests = unittest.TestSuite() + +# Filter +tests.addTest(unittest.makeSuite(filtertestcase.IgnoreIP)) +tests.addTest(unittest.makeSuite(filtertestcase.LogFile)) +tests.addTest(unittest.makeSuite(filtertestcase.GetFailures)) +# Server +#tests.addTest(unittest.makeSuite(servertestcase.StartStop)) +#tests.addTest(unittest.makeSuite(servertestcase.Transmitter)) +# FailManager +tests.addTest(unittest.makeSuite(failmanagertestcase.AddFailure)) +# BanManager +tests.addTest(unittest.makeSuite(banmanagertestcase.AddFailure)) + +# Tests runner +testRunner = unittest.TextTestRunner() +testRunner.run(tests) diff --git a/fail2ban.py b/fail2ban.py deleted file mode 100755 index 1ab2ab90..00000000 --- a/fail2ban.py +++ /dev/null @@ -1,542 +0,0 @@ -# This file is part of Fail2Ban. -# -# Fail2Ban is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Fail2Ban is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Fail2Ban; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -# Author: Cyril Jaquier -# Modified by: Yaroslav Halchenko (SYSLOG, findtime) -# -# $Revision$ - -__author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" -__copyright__ = "Copyright (c) 2004 Cyril Jaquier" -__license__ = "GPL" - -import time, sys, getopt, os, string, signal, logging, logging.handlers, copy -from ConfigParser import * - -from version import version -from firewall.firewall import Firewall -from logreader.logreader import LogReader -from confreader.configreader import ConfigReader -from utils.mail import Mail -from utils.pidlock import PIDLock -from utils.dns import * -from utils.process import * - -# Get the instance of the logger. -logSys = logging.getLogger("fail2ban") - -# Get PID lock file instance -pidLock = PIDLock() - -# Global variables -logFwList = list() -conf = dict() - -def dispUsage(): - """ Prints Fail2Ban command line options and exits - """ - print "Usage: "+sys.argv[0]+" [OPTIONS]" - print - print "Fail2Ban v"+version+" reads log file that contains password failure report" - print "and bans the corresponding IP addresses using firewall rules." - print - print " -b start in background" - print " -c <FILE> read configuration file FILE" - print " -p <FILE> create PID lock in FILE" - print " -h display this help message" - print " -i <IP(s)> IP(s) to ignore" - print " -k kill a currently running instance" - print " -r <VALUE> allow a max of VALUE password failure [maxfailures]" - print " -t <TIME> ban IP for TIME seconds [bantime]" - print " -f <TIME> lifetime in seconds of failed entry [findtime]" - print " -v verbose. Use twice for greater effect" - print " -V print software version" - print - print "Report bugs to <lostcontrol@users.sourceforge.net>" - sys.exit(0) - -def dispVersion(): - """ Prints Fail2Ban version and exits - """ - print sys.argv[0]+" "+version - sys.exit(0) - -def checkForRoot(): - """ Check for root user. - """ - uid = `os.getuid()` - if uid == '0': - return True - else: - return False - -def sigTERMhandler(signum, frame): - """ Handles the TERM signal when in daemon mode in order to - exit properly. - """ - logSys.debug("Signal handler called with sig "+`signum`) - killApp() - -def setFwMustCheck(value): - """ Set the mustCheck value of the firewalls (True/False) - """ - for element in logFwList: - element[2].setMustCheck(value) - -def initializeFwRules(): - """ Initializes firewalls by running cmdstart and then - fwstart for each section - """ - # Execute global start command - executeCmd(conf["cmdstart"], conf["debug"]) - # Execute start command of each section - for element in logFwList: - element[2].initialize(conf["debug"]) - -def reBan(): - """ For each section asks the Firewall to reban known IPs - """ - for element in logFwList: - element[2].reBan(conf["debug"]) - -def restoreFwRules(): - """ Flush the ban list - """ - logSys.warn("Restoring firewall rules...") - try: - for element in logFwList: - # Execute end command of each section - element[2].restore(conf["debug"]) - # Execute global end command - executeCmd(conf["cmdend"], conf["debug"]) - except ExternalError: - # nothing bad really - we can survive :-) - pass - -def killApp(): - """ Flush the ban list, remove the PID lock file and exit - nicely. - """ - # Restore Fw rules - restoreFwRules() - # Remove the PID lock - pidLock.remove() - logSys.info("Exiting...") - logging.shutdown() - sys.exit(0) - -def getCmdLineOptions(optList): - """ Gets the command line options - """ - for opt in optList: - if opt[0] == "-v": - conf["verbose"] = conf["verbose"] + 1 - if opt[0] == "-b": - conf["background"] = True - if opt[0] == "-d": - conf["debug"] = True - if opt[0] == "-t": - try: - conf["bantime"] = int(opt[1]) - except ValueError: - logSys.warn("banTime must be an integer") - logSys.warn("Using default value") - if opt[0] == "-f": - try: - conf["findtime"] = int(opt[1]) - except ValueError: - logSys.warn("findTime must be an integer") - logSys.warn("Using default value") - if opt[0] == "-i": - conf["ignoreip"] = opt[1] - if opt[0] == "-r": - conf["maxfailures"] = int(opt[1]) - if opt[0] == "-p": - conf["pidlock"] = opt[1] - if opt[0] == "-k": - conf["kill"] = True - -def main(): - """ Fail2Ban main function - """ - - # Add the default logging handler - stdout = logging.StreamHandler(sys.stdout) - logSys.addHandler(stdout) - - # Default formatter - formatterstring='%(levelname)s: %(message)s' - formatter = logging.Formatter('%(asctime)s ' + formatterstring) - stdout.setFormatter(formatter) - - conf["kill"] = False - conf["debug"] = False - conf["verbose"] = 0 - conf["conffile"] = "/etc/fail2ban.conf" - - # Reads the command line options. - try: - cmdOpts = 'hvVbdkc:t:i:r:p:' - cmdLongOpts = ['help','version'] - optList, args = getopt.getopt(sys.argv[1:], cmdOpts, cmdLongOpts) - except getopt.GetoptError: - dispUsage() - - # Pre-parsing of command line options for the -c option - for opt in optList: - if opt[0] == "-c": - conf["conffile"] = opt[1] - if opt[0] in ["-h", "--help"]: - dispUsage() - if opt[0] in ["-V", "--version"]: - dispVersion() - - # Reads the config file and create a LogReader instance for - # each log file to check. - confReader = ConfigReader(conf["conffile"]) - confReader.openConf() - - # Options - optionValues = (["bool", "background", False], - ["str", "logtargets", "/var/log/fail2ban.log"], - ["str", "syslog-target", "/dev/log"], - ["int", "syslog-facility", 1], - ["str", "pidlock", "/var/run/fail2ban.pid"], - ["int", "maxfailures", 5], - ["int", "bantime", 600], - ["int", "findtime", 600], - ["str", "ignoreip", ""], - ["int", "polltime", 1], - ["str", "cmdstart", ""], - ["str", "cmdend", ""], - ["int", "reinittime", 100], - ["int", "maxreinits", 100]) - - # Gets global configuration options - conf.update(confReader.getLogOptions("DEFAULT", optionValues)) - - # Gets command line options - getCmdLineOptions(optList) - - # PID lock - pidLock.setPath(conf["pidlock"]) - - # Now we can kill properly a running instance if needed - if conf["kill"]: - pid = pidLock.exists() - if pid: - killPID(int(pid)) - logSys.warn("Killed Fail2Ban with PID "+pid) - sys.exit(0) - else: - logSys.error("No running Fail2Ban found") - sys.exit(-1) - - # Start Fail2Ban in daemon mode - if conf["background"]: - retCode = createDaemon() - signal.signal(signal.SIGTERM, sigTERMhandler) - if not retCode: - logSys.error("Unable to start daemon") - sys.exit(-1) - - # Process some options - # First setup Log targets - # Bug fix for #1234699 - os.umask(0077) - for target in conf["logtargets"].split(): - # target formatter - # By default global formatter is taken. Is different for SYSLOG - tformatter = formatter - if target == "STDERR": - hdlr = logging.StreamHandler(sys.stderr) - elif target == "SYSLOG": - # SYSLOG target can be either - # a socket (file, so it starts with /) - # or hostname - # or hostname:port - syslogtargets = re.findall("(/[\w/]*)|([^/ ][^: ]*)(:(\d+)){,1}", - conf["syslog-target"]) - # we are waiting for a single match - syslogtargets = syslogtargets[0] - - # assign facility if it was defined - if conf["syslog-facility"] < 0: - facility = handlers.SysLogHandler.LOG_USER - else: - facility = conf["syslog-facility"] - - if len(syslogtargets) == 0: # everything default - hdlr = logging.handlers.SysLogHandler() - else: - if not ( syslogtargets[0] == "" ): # got socket - syslogtarget = syslogtargets[0] - else: # got hostname and maybe a port - if syslogtargets[3] == "": # no port specified - port = 514 - else: - port = int(syslogtargets[3]) - syslogtarget = (syslogtargets[1], port) - hdlr = logging.handlers.SysLogHandler(syslogtarget, facility) - tformatter = logging.Formatter("%(asctime)s %(name)s " + - formatterstring, "%b %e %T"); - else: - # Target should be a file - try: - open(target, "a") - hdlr = logging.FileHandler(target) - except IOError: - logSys.error("Unable to log to " + target) - continue - # Set formatter and add handler to logger - hdlr.setFormatter(tformatter) - logSys.addHandler(hdlr) - - # Verbose level - if conf["verbose"]: - logSys.warn("Verbose level is "+`conf["verbose"]`) - if conf["verbose"] == 1: - logSys.setLevel(logging.INFO) - elif conf["verbose"] > 1: - logSys.setLevel(logging.DEBUG) - if conf["verbose"] > 2: - formatterstring = ('%(levelname)s: [%(filename)s (%(lineno)d)] ' + - '%(message)s') - formatter = logging.Formatter("%(asctime)s " + formatterstring) - stdout.setFormatter(formatter) - - # Debug mode. Should only be used by developers - if conf["debug"]: - logSys.warn("DEBUG MODE: FIREWALL COMMANDS ARE _NOT_ EXECUTED BUT " + - "ONLY DISPLAYED IN THE LOG MESSAGES") - - # Ignores IP list - ignoreIPList = conf["ignoreip"].split(' ') - - # Checks for root user. This is necessary because log files - # are owned by root and firewall needs root access. - if not checkForRoot(): - logSys.error("You must be root") - if not conf["debug"]: - sys.exit(-1) - - # Checks that no instance of Fail2Ban is currently running. - pid = pidLock.exists() - if pid: - logSys.error("Fail2Ban already running with PID "+pid) - sys.exit(-1) - else: - ret = pidLock.create() - if not ret: - # Unable to create PID lock. Exit - sys.exit(-1) - - logSys.debug("ConfFile is " + conf["conffile"]) - logSys.debug("BanTime is " + `conf["bantime"]`) - logSys.debug("FindTime is " + `conf["findtime"]`) - logSys.debug("MaxFailure is " + `conf["maxfailures"]`) - - # Options - optionValues = (["bool", "enabled", False], - ["str", "host", "localhost"], - ["int", "port", "25"], - ["str", "from", "root"], - ["str", "to", "root"], - ["str", "user", ''], - ["str", "password", ''], - ["bool", "localtime", False], - ["str", "subject", "[Fail2Ban] Banned <ip>"], - ["str", "message", "Fail2Ban notification"]) - - # Gets global configuration options - mailConf = confReader.getLogOptions("MAIL", optionValues) - - # Create mailer if enabled - if mailConf["enabled"]: - logSys.debug("Mail enabled") - mail = Mail(mailConf["host"], mailConf["port"]) - mail.setFromAddr(mailConf["from"]) - mail.setUser(mailConf["user"]) - mail.setPassword(mailConf["password"]) - mail.setToAddr(mailConf["to"]) - mail.setLocalTimeFlag(mailConf["localtime"]) - logSys.debug("to: " + mailConf["to"] + " from: " + mailConf["from"]) - - # Options - optionValues = (["bool", "enabled", False], - ["str", "logfile", "/dev/null"], - ["int", "maxfailures", conf["maxfailures"]], - ["int", "bantime", conf["bantime"]], - ["int", "findtime", conf["findtime"]], - ["str", "timeregex", ""], - ["str", "timepattern", ""], - ["str", "failregex", ""], - ["str", "fwstart", ""], - ["str", "fwend", ""], - ["str", "fwban", ""], - ["str", "fwunban", ""], - ["str", "fwcheck", ""]) - - logSys.info("Fail2Ban v" + version + " is running") - - # Gets the options of each sections - for t in confReader.getSections(): - l = confReader.getLogOptions(t, optionValues) - if l["enabled"]: - # Creates a logreader object - lObj = LogReader(l["logfile"], l["timeregex"], l["timepattern"], - l["failregex"], l["maxfailures"], l["findtime"]) - # Creates a firewall object - fObj = Firewall(l["fwstart"], l["fwend"], l["fwban"], l["fwunban"], - l["fwcheck"], l["bantime"]) - # "Name" the firewall - fObj.setSection(t) - # Links them into a list. I'm not really happy - # with this :/ - logFwList.append([t, lObj, fObj, dict(), l]) - - # We add 127.0.0.1 to the ignore list has we do not want - # to be ban ourself. - for element in logFwList: - element[1].addIgnoreIP("127.0.0.1") - while len(ignoreIPList) > 0: - ip = ignoreIPList.pop() - # Bug fix for #1239557 - if isValidIP(ip): - for element in logFwList: - element[1].addIgnoreIP(ip) - else: - logSys.warn(ip + " is not a valid IP address") - - # Startup loop -- necessary to avoid crash if it takes time for iptables - # to startup. To avoid introduction of new config options, reusing - # maxreinits and polltime. - reinits = 0 - while True: - try: - initializeFwRules() - break - except ExternalError, e: - reinits += 1 - logSys.warn(e) - if conf["maxreinits"] < 0 or (reinits < conf["maxreinits"]): - logSys.warn("#%d attempt to initialize the firewalls" % reinits) - else: - logSys.error("Exiting: Too many attempts to initialize the " + - "firewall") - killApp() - time.sleep(conf["polltime"]) - - # try to reinit once if it fails immediately - lastReinitTime = time.time() - conf["reinittime"] - 1 - reinits = 0 - # Main loop - while True: - try: - sys.stdout.flush() - sys.stderr.flush() - - # Checks if some IP have to be remove from ban - # list. - for element in logFwList: - element[2].checkForUnBan(conf["debug"]) - - # If the log file has not been modified since the - # last time, we sleep for 1 second. This is active - # polling so not very effective. - modList = list() - for element in logFwList: - if element[1].isModified(): - modList.append(element) - - if len(modList) == 0: - time.sleep(conf["polltime"]) - continue - - # Gets the failure list from the log file. For a given IP, - # takes only the service which has the most password failures. - for element in modList: - e = element[1].getFailures() - for key in e.iterkeys(): - if element[3].has_key(key): - element[3][key] = (element[3][key][0] + e[key][0], - e[key][1]) - else: - element[3][key] = (e[key][0], e[key][1]) - - # Remove the oldest failure attempts from the global list. - # We iterate the failure list and ban IP that make - # *retryAllowed* login failures. - unixTime = time.time() - for element in logFwList: - fails = element[3].copy() - findTime = element[1].getFindTime() - for attempt in fails: - failTime = fails[attempt][1] - if failTime < unixTime - findTime: - del element[3][attempt] - elif fails[attempt][0] >= element[1].getMaxRetry(): - aInfo = {"section": element[0], - "ip": attempt, - "failures": element[3][attempt][0], - "failtime": failTime} - logSys.info(element[0] + ": " + aInfo["ip"] + - " has " + `aInfo["failures"]` + - " login failure(s). Banned.") - element[2].addBanIP(aInfo, conf["debug"]) - # Send a mail notification - if 'mail' in locals(): - mail.sendmail(mailConf["subject"], - mailConf["message"], aInfo) - del element[3][attempt] - except ExternalError, e: - # Something wrong while dealing with Iptables. - # May be chain got removed? - reinits += 1 - logSys.error(e) - if ((unixTime - lastReinitTime > conf["reinittime"]) and - ((conf["maxreinits"] < 0) or (reinits < conf["maxreinits"]))): - logSys.warn("#%d reinitialization of firewalls"%reinits) - lastReinitTime = unixTime - else: - logSys.error("Exiting: reinits follow too often, or too many " + - "reinit attempts") - killApp() - # We already failed runCheck so disable it until - # restoring a safe state - setFwMustCheck(False) - # save firewalls to keep a list of IPs for rebanning - logFwListCopy = copy.deepcopy(logFwList) - try: - # restore as much as possible - restoreFwRules() - # reinitialize all the chains - initializeFwRules() - # restore the lists of baned IPs - logFwList.__init__(logFwListCopy) - # reBan known IPs - reBan() - # Now we can enable the runCheck test again - setFwMustCheck(True) - except ExternalError: - raise ExternalError("Big Oops happened: situation is out of " + - "control. Something is wrong with your " + - "setup. Please check your settings") - except KeyboardInterrupt: - # When the user press <ctrl>+<c> we exit nicely. - killApp() diff --git a/firewall/firewall.py b/firewall/firewall.py deleted file mode 100644 index ebba2545..00000000 --- a/firewall/firewall.py +++ /dev/null @@ -1,192 +0,0 @@ -# This file is part of Fail2Ban. -# -# Fail2Ban is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Fail2Ban is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Fail2Ban; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -# Author: Cyril Jaquier -# -# $Revision$ - -__author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" -__copyright__ = "Copyright (c) 2004 Cyril Jaquier" -__license__ = "GPL" - -import time, os, logging, re - -from utils.process import executeCmd -from utils.strings import replaceTag -# unfortunately but I have to bring ExternalError in especially for -# flushBanList: if one of IPs got flushed manually outside or something, we -# might endup with not "full" flush unless we handle exception within the loop -from utils.process import ExternalError - -# Gets the instance of the logger. -logSys = logging.getLogger("fail2ban") - -class Firewall: - """ Manages the ban list and executes the command that ban - the IP. - """ - - def __init__(self, startRule, endRule, banRule, unBanRule, checkRule, - banTime): - self.banRule = banRule - self.unBanRule = unBanRule - self.checkRule = checkRule - self.startRule = startRule - self.endRule = endRule - self.banTime = banTime - self.banList = dict() - self.section = "" - self.mustCheck = True - - def setSection(self, section): - """ Set optional section name for clarify of logging - """ - self.section = section - - def getMustCheck(self): - """ Return true if the runCheck test is executed - """ - return self.mustCheck - - def setMustCheck(self, value): - """ Enable or disable the execution of runCheck test - """ - self.mustCheck = value - - def initialize(self, debug): - logSys.debug("%s: Initialize firewall rules"%self.section) - executeCmd(self.startRule, debug) - - def restore(self, debug): - logSys.debug("%s: Restore firewall rules"%self.section) - try: - self.flushBanList(debug) - executeCmd(self.endRule, debug) - except ExternalError: - pass - - def addBanIP(self, aInfo, debug): - """ Bans an IP. - """ - ip = aInfo["ip"] - if not self.inBanList(ip): - crtTime = time.time() - if self.banTime < 0: - banMsg = "Ban (permanent)" - else: - banMsg = "Ban (%d s)"%self.banTime - logSys.warn("%s: %s "%(self.section, banMsg) + ip) - self.banList[ip] = crtTime - aInfo["bantime"] = crtTime - self.runCheck(debug) - cmd = self.banIP(aInfo) - if executeCmd(cmd, debug): - raise ExternalError("Firewall: execution of fwban command " + - "'%s' failed"%cmd) - else: - self.runCheck(debug) - logSys.error("%s: "%self.section+ip+" already in ban list") - - def delBanIP(self, aInfo, debug): - """ Unban an IP. - """ - ip = aInfo["ip"] - if self.inBanList(ip): - logSys.warn("%s: Unban "%self.section + ip) - del self.banList[ip] - self.runCheck(debug) - executeCmd(self.unBanIP(aInfo), debug) - else: - logSys.error("%s: "%self.section+ip+" not in ban list") - - def reBan(self, debug): - """ Re-Bans known IPs. - TODO: implement "failures" and "failtime" - """ - for ip in self.banList: - aInfo = {"ip": ip, - "bantime":self.banList[ip]} - logSys.warn("%s: ReBan "%self.section + ip) - # next piece is similar to the on in addBanIp - # so might be one more function will not hurt - self.runCheck(debug) - executeCmd(self.banIP(aInfo), debug) - - def inBanList(self, ip): - """ Checks if IP is in ban list. - """ - return self.banList.has_key(ip) - - def runCheck(self, debug): - """ Runs fwcheck command and throws an exception if it returns non-0 - result - """ - if self.mustCheck: - executeCmd(self.checkRule, debug) - else: - return None - - def checkForUnBan(self, debug): - """ Check for IP to remove from ban list. If banTime is smaller than - zero, IP will be never removed. - """ - if self.banTime < 0: - # Permanent banning - return - banListTemp = self.banList.copy() - for element in banListTemp.iteritems(): - btime = element[1] - if btime < time.time()-self.banTime: - aInfo = {"ip": element[0], - "bantime": btime, - "unbantime": time.time()} - self.delBanIP(aInfo, debug) - - def flushBanList(self, debug): - """ Flushes the ban list and of course the firewall rules. - Called when fail2ban exits. - """ - banListTemp = self.banList.copy() - for element in banListTemp.iteritems(): - aInfo = {"ip": element[0], - "bantime": element[1], - "unbantime": time.time()} - try: - self.delBanIP(aInfo, debug) - except ExternalError: - # we must let it fail here in the loop, or we don't - # flush properly - pass - - def banIP(self, aInfo): - """ Returns query to ban IP. - """ - query = replaceTag(self.banRule, aInfo) - return query - - def unBanIP(self, aInfo): - """ Returns query to unban IP. - """ - query = replaceTag(self.unBanRule, aInfo) - return query - - def viewBanList(self): - """ Prints the ban list on screen. Usefull for debugging. - """ - for element in self.banList.iteritems(): - print element diff --git a/kill-server b/kill-server new file mode 100755 index 00000000..0e6a26db --- /dev/null +++ b/kill-server @@ -0,0 +1,2 @@ +#!/bin/bash +kill `ps ax|grep fail2ban|grep -v grep|awk '{print $1}'` diff --git a/log-test/apache b/log-test/apache deleted file mode 100644 index 227f8df9..00000000 --- a/log-test/apache +++ /dev/null @@ -1,108 +0,0 @@ -[Wed Mar 31 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Mon Jan 03 05:02:15 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc -[Mon Jan 03 05:02:20 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc -[Mon Jan 03 05:02:20 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc -[Mon Jan 03 05:02:21 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc -[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc -[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc -[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc -[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/\xe0 -[Mon Jan 03 05:02:23 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msdac -[Mon Jan 03 05:02:23 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msdac -[Mon Jan 03 05:02:24 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/PBServer -[Mon Jan 03 05:02:24 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/PBServer -[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/Rpc -[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/Rpc -[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/samples -[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/samples -[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts..\xc1\x9c.. -[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:32 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:32 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:34 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:34 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:39 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 05:02:39 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts -[Mon Jan 03 11:08:29 2005] [error] [client 128.178.150.127] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Mon Jan 03 20:08:52 2005] [error] [client 83.76.202.195] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:19:50 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:19:55 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:01 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:05 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:08 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:12 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:16 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:22 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:26 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:28 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 15:20:38 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 20:54:59 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 20:55:04 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 20:55:29 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 21:34:29 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Tue Jan 04 21:34:32 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 00:17:41 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 00:18:03 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 00:18:12 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 01:24:38 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 01:24:40 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 01:24:46 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 01:24:48 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 01:25:58 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 01:26:34 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 01:26:37 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 10:13:02 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 10:13:07 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 10:13:10 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 10:17:07 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 14:41:40 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 14:41:45 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 14:41:47 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 14:41:51 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 14:55:30 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:03:44 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:03:48 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:03:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:03:57 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:06:45 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Mar 05 15:07:28 2005] [error] [client 192.168.0.128] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Wed Jan 05 15:08:01 2005] [error] [client 192.168.0.128] user not found: /phpinfo -[Wed Jan 05 15:10:45 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/css/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo -[Wed Jan 05 15:10:45 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/images/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo -[Wed Jan 05 15:10:45 2005] [error] [client 192.168.0.128] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:11:09 2005] [error] [client 192.168.0.128] user test not found: /phpinfo -[Wed Jan 05 15:11:10 2005] [error] [client 192.168.0.128] user test not found: /phpinfo -[Wed Jan 06 15:11:11 2005] [error] [client 192.168.0.128] user test not found: /phpinfo -[Wed Jan 06 15:11:13 2005] [error] [client 192.168.0.128] user test not found: /phpinfo -[Wed Jan 06 15:11:14 2005] [error] [client 192.168.0.128] user test not found: /phpinfo -[Wed Jan 05 15:11:15 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/css/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo -[Wed Jan 05 15:11:15 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/images/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo -[Wed Jan 05 15:11:15 2005] [error] [client 192.168.0.128] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:12:32 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:13:48 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:13:51 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:13:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:13:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:13:54 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:13:56 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:13:59 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:14:20 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:14:24 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:14:29 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Jan 05 15:14:34 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico -[Wed Mar 10 15:08:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Wed Mar 10 15:09:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Wed Mar 10 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch -[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
\ No newline at end of file diff --git a/log-test/current b/log-test/current deleted file mode 100644 index 18258689..00000000 --- a/log-test/current +++ /dev/null @@ -1,11 +0,0 @@ -Jan 7 17:53:15 [sshd] (pam_unix) 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=62.220.137.36 user=kevin -Jan 7 17:53:26 [sshd] (pam_unix) authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=62.220.137.36 user=kevin -Mar 7 17:53:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36 -Mar 7 17:55:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36 -Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36 -Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128 -Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128 -Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128 -Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128 -Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from www.google.ch -Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from www.google.ch diff --git a/log-test/test b/log-test/test deleted file mode 100644 index d370ca46..00000000 --- a/log-test/test +++ /dev/null @@ -1,432 +0,0 @@ -Sep 28 13:18:43 [sshd] Failed password for illegal user test from 211.112.229.69 port 59506 ssh2 -Sep 28 13:18:45 [sshd] Failed password for illegal user guest from 211.112.229.69 port 59584 ssh2 -Sep 28 13:18:48 [sshd] Failed password for illegal user admin from 211.112.229.69 port 59668 ssh2 -Sep 28 13:18:51 [sshd] Failed password for illegal user admin from 211.112.229.69 port 59746 ssh2 -Sep 28 13:18:54 [sshd] Failed password for illegal user user from 211.112.229.69 port 59809 ssh2 -Sep 28 13:18:57 [sshd] Failed password for illegal user root from 211.112.229.69 port 59881 ssh2 -Sep 28 13:19:00 [sshd] Failed password for illegal user root from 211.112.229.69 port 59944 ssh2 -Sep 28 13:19:03 [sshd] Failed password for illegal user root from 211.112.229.69 port 59999 ssh2 -Sep 28 13:19:06 [sshd] Failed password for illegal user test from 211.112.229.69 port 60055 ssh2 -Sep 28 21:05:25 [sshd(pam_unix)] authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.0.128.local.home user=cyril -Sep 28 21:05:27 [sshd] error: PAM: Authentication failure for cyril from 192.168.0.128.local.home -Sep 29 03:45:18 [sshd] Failed password for illegal user nobody from 203.198.168.66 port 55927 ssh2 -Sep 29 03:45:21 [sshd] Failed password for illegal user patrick from 203.198.168.66 port 55973 ssh2 -Sep 29 03:45:23 [sshd] Failed password for illegal user patrick from 203.198.168.66 port 56010 ssh2 -Sep 29 03:45:26 [sshd] Failed password for illegal user root from 203.198.168.66 port 56060 ssh2 -Sep 29 03:45:29 [sshd] Failed password for illegal user root from 203.198.168.66 port 56107 ssh2 -Sep 29 03:45:32 [sshd] Failed password for illegal user root from 203.198.168.66 port 56152 ssh2 -Sep 29 03:45:34 [sshd] Failed password for illegal user root from 203.198.168.66 port 56200 ssh2 -Sep 29 03:45:37 [sshd] Failed password for illegal user root from 203.198.168.66 port 56243 ssh2 -Sep 29 03:45:40 [sshd] Failed password for illegal user rolo from 203.198.168.66 port 56288 ssh2 -Sep 29 03:45:43 [sshd] Failed password for illegal user iceuser from 203.198.168.66 port 56333 ssh2 -Sep 29 03:45:46 [sshd] Failed password for illegal user horde from 203.198.168.66 port 56379 ssh2 -Sep 29 03:45:48 [sshd] Failed password for illegal user cyrus from 203.198.168.66 port 56425 ssh2 -Sep 29 03:45:52 [sshd] Failed password for illegal user www from 203.198.168.66 port 56470 ssh2 -Sep 29 03:45:55 [sshd] Failed password for illegal user wwwrun from 203.198.168.66 port 56534 ssh2 -Sep 29 03:45:58 [sshd] Failed password for illegal user matt from 203.198.168.66 port 56572 ssh2 -Sep 29 03:46:01 [sshd] Failed password for illegal user test from 203.198.168.66 port 56616 ssh2 -Sep 29 03:46:03 [sshd] Failed password for illegal user test from 203.198.168.66 port 56660 ssh2 -Sep 29 03:46:06 [sshd] Failed password for illegal user test from 203.198.168.66 port 56704 ssh2 -Sep 29 03:46:09 [sshd] Failed password for illegal user test from 203.198.168.66 port 56752 ssh2 -Sep 29 03:46:12 [sshd] Failed password for illegal user www-data from 203.198.168.66 port 56795 ssh2 -Sep 29 03:46:15 [sshd] Failed password for illegal user mysql from 203.198.168.66 port 56839 ssh2 -Sep 29 03:46:17 [sshd] Failed password for illegal user operator from 203.198.168.66 port 56882 ssh2 -Sep 29 03:46:20 [sshd] Failed password for illegal user adm from 203.198.168.66 port 56929 ssh2 -Sep 29 03:46:23 [sshd] Failed password for illegal user apache from 203.198.168.66 port 56971 ssh2 -Sep 29 03:46:26 [sshd] Failed password for illegal user irc from 203.198.168.66 port 57011 ssh2 -Sep 29 03:46:29 [sshd] Failed password for illegal user irc from 203.198.168.66 port 57060 ssh2 -Sep 29 03:46:31 [sshd] Failed password for illegal user adm from 203.198.168.66 port 57100 ssh2 -Sep 29 03:46:34 [sshd] Failed password for illegal user root from 203.198.168.66 port 57148 ssh2 -Sep 29 03:46:37 [sshd] Failed password for illegal user root from 203.198.168.66 port 57194 ssh2 -Sep 29 03:46:40 [sshd] Failed password for illegal user root from 203.198.168.66 port 57236 ssh2 -Sep 29 03:46:43 [sshd] Failed password for illegal user jane from 203.198.168.66 port 57281 ssh2 -Sep 29 03:46:45 [sshd] Failed password for illegal user pamela from 203.198.168.66 port 57328 ssh2 -Sep 29 03:46:48 [sshd] Failed password for illegal user root from 203.198.168.66 port 57372 ssh2 -Sep 29 03:46:51 [sshd] Failed password for illegal user root from 203.198.168.66 port 57418 ssh2 -Sep 29 03:46:54 [sshd] Failed password for illegal user root from 203.198.168.66 port 57463 ssh2 -Sep 29 03:46:57 [sshd] Failed password for illegal user root from 203.198.168.66 port 57506 ssh2 -Sep 29 03:46:59 [sshd] Failed password for illegal user root from 203.198.168.66 port 57549 ssh2 -Sep 29 03:47:02 [sshd] Failed password for illegal user cosmin from 203.198.168.66 port 57594 ssh2 -Sep 29 03:47:05 [sshd] Failed password for illegal user root from 203.198.168.66 port 57637 ssh2 -Sep 29 03:47:08 [sshd] Failed password for illegal user root from 203.198.168.66 port 57689 ssh2 -Sep 29 03:47:11 [sshd] Failed password for illegal user root from 203.198.168.66 port 57730 ssh2 -Sep 29 03:47:13 [sshd] Failed password for illegal user root from 203.198.168.66 port 57774 ssh2 -Sep 29 03:47:16 [sshd] Failed password for illegal user root from 203.198.168.66 port 57820 ssh2 -Sep 29 03:47:19 [sshd] Failed password for illegal user root from 203.198.168.66 port 57866 ssh2 -Sep 29 03:47:22 [sshd] Failed password for illegal user root from 203.198.168.66 port 57901 ssh2 -Sep 29 03:47:25 [sshd] Failed password for illegal user root from 203.198.168.66 port 57944 ssh2 -Sep 29 03:47:27 [sshd] Failed password for illegal user root from 203.198.168.66 port 57990 ssh2 -Sep 29 03:47:31 [sshd] Failed password for illegal user root from 203.198.168.66 port 58031 ssh2 -Sep 29 03:47:34 [sshd] Failed password for illegal user root from 203.198.168.66 port 58098 ssh2 -Sep 29 03:47:37 [sshd] Failed password for illegal user root from 203.198.168.66 port 58137 ssh2 -Sep 29 03:47:40 [sshd] Failed password for illegal user root from 203.198.168.66 port 58183 ssh2 -Sep 29 03:47:42 [sshd] Failed password for illegal user root from 203.198.168.66 port 58228 ssh2 -Sep 29 03:47:45 [sshd] Failed password for illegal user root from 203.198.168.66 port 58273 ssh2 -Sep 29 03:47:48 [sshd] Failed password for illegal user root from 203.198.168.66 port 58314 ssh2 -Sep 29 03:47:51 [sshd] Failed password for illegal user root from 203.198.168.66 port 58358 ssh2 -Sep 29 03:47:54 [sshd] Failed password for illegal user root from 203.198.168.66 port 58401 ssh2 -Sep 29 03:47:56 [sshd] Failed password for illegal user root from 203.198.168.66 port 58443 ssh2 -Sep 29 03:47:59 [sshd] Failed password for illegal user root from 203.198.168.66 port 58484 ssh2 -Sep 29 03:48:02 [sshd] Failed password for illegal user root from 203.198.168.66 port 58528 ssh2 -Sep 29 03:48:05 [sshd] Failed password for illegal user root from 203.198.168.66 port 58574 ssh2 -Sep 29 03:48:07 [sshd] Failed password for illegal user root from 203.198.168.66 port 58613 ssh2 -Sep 29 03:48:10 [sshd] Failed password for illegal user root from 203.198.168.66 port 58662 ssh2 -Sep 29 03:48:13 [sshd] Failed password for illegal user root from 203.198.168.66 port 58703 ssh2 -Sep 29 03:48:16 [sshd] Failed password for illegal user root from 203.198.168.66 port 58748 ssh2 -Sep 29 03:48:19 [sshd] Failed password for illegal user root from 203.198.168.66 port 58792 ssh2 -Sep 29 03:48:21 [sshd] Failed password for illegal user root from 203.198.168.66 port 58839 ssh2 -Sep 29 03:48:24 [sshd] Failed password for illegal user root from 203.198.168.66 port 58880 ssh2 -Sep 29 03:48:27 [sshd] Failed password for illegal user root from 203.198.168.66 port 58926 ssh2 -Sep 29 03:48:30 [sshd] Failed password for illegal user root from 203.198.168.66 port 58967 ssh2 -Sep 29 03:48:33 [sshd] Failed password for illegal user root from 203.198.168.66 port 59012 ssh2 -Sep 29 03:48:35 [sshd] Failed password for illegal user root from 203.198.168.66 port 59052 ssh2 -Sep 29 03:48:38 [sshd] Failed password for illegal user root from 203.198.168.66 port 59095 ssh2 -Sep 29 03:48:41 [sshd] Failed password for illegal user root from 203.198.168.66 port 59140 ssh2 -Sep 29 03:48:44 [sshd] Failed password for illegal user root from 203.198.168.66 port 59182 ssh2 -Sep 29 03:48:47 [sshd] Failed password for illegal user cip52 from 203.198.168.66 port 59222 ssh2 -Sep 29 03:48:49 [sshd] Failed password for illegal user cip51 from 203.198.168.66 port 59264 ssh2 -Sep 29 03:48:52 [sshd] Failed password for illegal user root from 203.198.168.66 port 59309 ssh2 -Sep 29 03:48:55 [sshd] Failed password for illegal user noc from 203.198.168.66 port 59351 ssh2 -Sep 29 03:48:58 [sshd] Failed password for illegal user root from 203.198.168.66 port 59395 ssh2 -Sep 29 03:49:01 [sshd] Failed password for illegal user root from 203.198.168.66 port 59432 ssh2 -Sep 29 03:49:04 [sshd] Failed password for illegal user root from 203.198.168.66 port 59479 ssh2 -Sep 29 03:49:07 [sshd] Failed password for illegal user root from 203.198.168.66 port 59951 ssh2 -Sep 29 03:49:11 [sshd] Failed password for illegal user webmaster from 203.198.168.66 port 60006 ssh2 -Sep 29 03:49:14 [sshd] Failed password for illegal user data from 203.198.168.66 port 60463 ssh2 -Sep 29 03:49:17 [sshd] Failed password for illegal user user from 203.198.168.66 port 60880 ssh2 -Sep 29 03:49:20 [sshd] Failed password for illegal user user from 203.198.168.66 port 60947 ssh2 -Sep 29 03:49:23 [sshd] Failed password for illegal user user from 203.198.168.66 port 33137 ssh2 -Sep 29 03:49:26 [sshd] Failed password for illegal user web from 203.198.168.66 port 33572 ssh2 -Sep 29 03:49:31 [sshd] Failed password for illegal user web from 203.198.168.66 port 33630 ssh2 -Sep 29 03:49:34 [sshd] Failed password for illegal user oracle from 203.198.168.66 port 34129 ssh2 -Sep 29 03:49:39 [sshd] Failed password for illegal user sybase from 203.198.168.66 port 34558 ssh2 -Sep 29 03:49:42 [sshd] Failed password for illegal user master from 203.198.168.66 port 35018 ssh2 -Sep 29 03:49:45 [sshd] Failed password for illegal user account from 203.198.168.66 port 35095 ssh2 -Sep 29 03:49:48 [sshd] Failed password for illegal user backup from 203.198.168.66 port 35506 ssh2 -Sep 29 03:49:51 [sshd] Failed password for illegal user server from 203.198.168.66 port 35935 ssh2 -Sep 29 03:49:54 [sshd] Failed password for illegal user adam from 203.198.168.66 port 36016 ssh2 -Sep 29 03:49:57 [sshd] Failed password for illegal user alan from 203.198.168.66 port 36399 ssh2 -Sep 29 03:49:59 [sshd] Failed password for illegal user frank from 203.198.168.66 port 36488 ssh2 -Sep 29 03:50:04 [sshd] Failed password for illegal user george from 203.198.168.66 port 36876 ssh2 -Sep 29 03:50:07 [sshd] Failed password for illegal user henry from 203.198.168.66 port 37333 ssh2 -Sep 29 03:50:11 [sshd] Failed password for illegal user john from 203.198.168.66 port 37423 ssh2 -Sep 29 03:50:14 [sshd] Failed password for illegal user root from 203.198.168.66 port 37837 ssh2 -Sep 29 03:50:16 [sshd] Failed password for illegal user root from 203.198.168.66 port 38210 ssh2 -Sep 29 03:50:19 [sshd] Failed password for illegal user root from 203.198.168.66 port 38286 ssh2 -Sep 29 03:50:22 [sshd] Failed password for illegal user root from 203.198.168.66 port 38653 ssh2 -Sep 29 03:50:26 [sshd] Failed password for illegal user root from 203.198.168.66 port 38749 ssh2 -Sep 29 03:50:29 [sshd] Failed password for illegal user test from 203.198.168.66 port 39162 ssh2 -Sep 29 10:19:26 [sshd] Failed password for illegal user test from 24.19.0.105 port 3765 ssh2 -Sep 29 10:19:32 [sshd] Failed password for illegal user guest from 24.19.0.105 port 3846 ssh2 -Sep 29 10:19:39 [sshd] Failed password for illegal user admin from 24.19.0.105 port 3929 ssh2 -Sep 29 10:19:45 [sshd] Failed password for illegal user admin from 24.19.0.105 port 3992 ssh2 -Sep 29 10:19:49 [sshd] Failed password for illegal user user from 24.19.0.105 port 4057 ssh2 -Sep 29 10:19:54 [sshd] Failed password for illegal user root from 24.19.0.105 port 4115 ssh2 -Sep 29 10:19:58 [sshd] Failed password for illegal user root from 24.19.0.105 port 4170 ssh2 -Sep 29 10:20:01 [sshd] Failed password for illegal user root from 24.19.0.105 port 4202 ssh2 -Sep 29 10:20:04 [sshd] Failed password for illegal user test from 24.19.0.105 port 4242 ssh2 -Oct 1 15:53:46 [sshd] Failed password for illegal user test from 210.51.173.75 port 40940 ssh2 -Oct 1 15:53:53 [sshd] Failed password for illegal user guest from 210.51.173.75 port 41196 ssh2 -Oct 1 15:53:59 [sshd] Failed password for illegal user admin from 210.51.173.75 port 41480 ssh2 -Oct 1 15:54:05 [sshd] Failed password for illegal user admin from 210.51.173.75 port 41738 ssh2 -Oct 1 15:54:12 [sshd] Failed password for illegal user user from 210.51.173.75 port 42036 ssh2 -Oct 1 15:54:18 [sshd] Failed password for illegal user root from 210.51.173.75 port 42393 ssh2 -Oct 1 15:54:24 [sshd] Failed password for illegal user root from 210.51.173.75 port 42721 ssh2 -Oct 1 15:54:30 [sshd] Failed password for illegal user root from 210.51.173.75 port 42984 ssh2 -Oct 1 15:54:36 [sshd] Failed password for illegal user test from 210.51.173.75 port 43299 ssh2 -Oct 2 20:24:36 [sshd] Failed password for illegal user test from 220.64.223.249 port 2460 ssh2 -Oct 2 20:24:39 [sshd] Failed password for illegal user guest from 220.64.223.249 port 2527 ssh2 -Oct 2 20:24:42 [sshd] Failed password for illegal user admin from 220.64.223.249 port 2584 ssh2 -Oct 2 20:24:45 [sshd] Failed password for illegal user admin from 220.64.223.249 port 2645 ssh2 -Oct 2 20:24:48 [sshd] Failed password for illegal user user from 220.64.223.249 port 2708 ssh2 -Oct 2 20:24:51 [sshd] Failed password for illegal user root from 220.64.223.249 port 2794 ssh2 -Oct 2 20:24:54 [sshd] Failed password for illegal user root from 220.64.223.249 port 2868 ssh2 -Oct 2 20:24:58 [sshd] Failed password for illegal user root from 220.64.223.249 port 2931 ssh2 -Oct 2 20:25:01 [sshd] Failed password for illegal user test from 220.64.223.249 port 2994 ssh2 -Oct 3 02:17:47 [sshd] Failed password for illegal user nobody from 216.65.197.170 port 54324 ssh2 -Oct 3 02:17:48 [sshd] Failed password for illegal user patrick from 216.65.197.170 port 54491 ssh2 -Oct 3 02:17:50 [sshd] Failed password for illegal user patrick from 216.65.197.170 port 54669 ssh2 -Oct 3 02:17:52 [sshd] Failed password for illegal user root from 216.65.197.170 port 54845 ssh2 -Oct 3 02:17:53 [sshd] Failed password for illegal user root from 216.65.197.170 port 55021 ssh2 -Oct 3 02:17:55 [sshd] Failed password for illegal user root from 216.65.197.170 port 55201 ssh2 -Oct 3 02:17:57 [sshd] Failed password for illegal user root from 216.65.197.170 port 55381 ssh2 -Oct 3 02:17:59 [sshd] Failed password for illegal user root from 216.65.197.170 port 55553 ssh2 -Oct 3 02:18:00 [sshd] Failed password for illegal user rolo from 216.65.197.170 port 55730 ssh2 -Oct 3 02:18:02 [sshd] Failed password for illegal user iceuser from 216.65.197.170 port 55892 ssh2 -Oct 3 02:18:04 [sshd] Failed password for illegal user horde from 216.65.197.170 port 56054 ssh2 -Oct 3 02:18:05 [sshd] Failed password for illegal user cyrus from 216.65.197.170 port 56231 ssh2 -Oct 3 02:18:07 [sshd] Failed password for illegal user www from 216.65.197.170 port 56412 ssh2 -Oct 3 02:18:09 [sshd] Failed password for illegal user wwwrun from 216.65.197.170 port 56594 ssh2 -Oct 3 02:18:11 [sshd] Failed password for illegal user matt from 216.65.197.170 port 56755 ssh2 -Oct 3 02:18:12 [sshd] Failed password for illegal user test from 216.65.197.170 port 56928 ssh2 -Oct 3 02:18:14 [sshd] Failed password for illegal user test from 216.65.197.170 port 57112 ssh2 -Oct 3 02:18:16 [sshd] Failed password for illegal user test from 216.65.197.170 port 57292 ssh2 -Oct 3 02:18:17 [sshd] Failed password for illegal user test from 216.65.197.170 port 57465 ssh2 -Oct 3 02:18:19 [sshd] Failed password for illegal user www-data from 216.65.197.170 port 57631 ssh2 -Oct 3 02:18:21 [sshd] Failed password for illegal user mysql from 216.65.197.170 port 57802 ssh2 -Oct 3 02:18:22 [sshd] Failed password for illegal user operator from 216.65.197.170 port 57989 ssh2 -Oct 3 02:18:24 [sshd] Failed password for illegal user adm from 216.65.197.170 port 58151 ssh2 -Oct 3 02:18:26 [sshd] Failed password for illegal user apache from 216.65.197.170 port 58319 ssh2 -Oct 3 02:18:28 [sshd] Failed password for illegal user irc from 216.65.197.170 port 58492 ssh2 -Oct 3 02:18:29 [sshd] Failed password for illegal user irc from 216.65.197.170 port 58662 ssh2 -Oct 3 02:18:31 [sshd] Failed password for illegal user adm from 216.65.197.170 port 58818 ssh2 -Oct 3 02:18:33 [sshd] Failed password for illegal user root from 216.65.197.170 port 58976 ssh2 -Oct 3 02:18:34 [sshd] Failed password for illegal user root from 216.65.197.170 port 59147 ssh2 -Oct 3 02:18:36 [sshd] Failed password for illegal user root from 216.65.197.170 port 59306 ssh2 -Oct 3 02:18:38 [sshd] Failed password for illegal user jane from 216.65.197.170 port 59474 ssh2 -Oct 3 02:18:40 [sshd] Failed password for illegal user pamela from 216.65.197.170 port 59644 ssh2 -Oct 3 02:18:41 [sshd] Failed password for illegal user root from 216.65.197.170 port 59797 ssh2 -Oct 3 02:18:43 [sshd] Failed password for illegal user root from 216.65.197.170 port 59963 ssh2 -Oct 3 02:18:45 [sshd] Failed password for illegal user root from 216.65.197.170 port 60139 ssh2 -Oct 3 02:18:47 [sshd] Failed password for illegal user root from 216.65.197.170 port 60308 ssh2 -Oct 3 02:18:48 [sshd] Failed password for illegal user root from 216.65.197.170 port 60479 ssh2 -Oct 3 02:18:50 [sshd] Failed password for illegal user cosmin from 216.65.197.170 port 60654 ssh2 -Oct 3 02:18:52 [sshd] Failed password for illegal user root from 216.65.197.170 port 60830 ssh2 -Oct 3 02:18:54 [sshd] Failed password for illegal user root from 216.65.197.170 port 60992 ssh2 -Oct 3 02:18:55 [sshd] Failed password for illegal user root from 216.65.197.170 port 32945 ssh2 -Oct 3 02:18:58 [sshd] Failed password for illegal user root from 216.65.197.170 port 33101 ssh2 -Oct 3 02:18:59 [sshd] Failed password for illegal user root from 216.65.197.170 port 33343 ssh2 -Oct 3 02:19:02 [sshd] Failed password for illegal user root from 216.65.197.170 port 33501 ssh2 -Oct 3 02:19:03 [sshd] Failed password for illegal user root from 216.65.197.170 port 33733 ssh2 -Oct 3 02:19:05 [sshd] Failed password for illegal user root from 216.65.197.170 port 33892 ssh2 -Oct 3 02:19:07 [sshd] Failed password for illegal user root from 216.65.197.170 port 34066 ssh2 -Oct 3 02:19:08 [sshd] Failed password for illegal user root from 216.65.197.170 port 34212 ssh2 -Oct 3 02:19:10 [sshd] Failed password for illegal user root from 216.65.197.170 port 34376 ssh2 -Oct 3 02:19:12 [sshd] Failed password for illegal user root from 216.65.197.170 port 34535 ssh2 -Oct 3 02:19:14 [sshd] Failed password for illegal user root from 216.65.197.170 port 34704 ssh2 -Oct 3 02:19:16 [sshd] Failed password for illegal user root from 216.65.197.170 port 34853 ssh2 -Oct 3 02:19:18 [sshd] Failed password for illegal user root from 216.65.197.170 port 35092 ssh2 -Oct 3 02:19:19 [sshd] Failed password for illegal user root from 216.65.197.170 port 35261 ssh2 -Oct 3 02:19:21 [sshd] Failed password for illegal user root from 216.65.197.170 port 35425 ssh2 -Oct 3 02:19:23 [sshd] Failed password for illegal user root from 216.65.197.170 port 35583 ssh2 -Oct 3 02:19:24 [sshd] Failed password for illegal user root from 216.65.197.170 port 35753 ssh2 -Oct 3 02:19:26 [sshd] Failed password for illegal user root from 216.65.197.170 port 35901 ssh2 -Oct 3 02:19:28 [sshd] Failed password for illegal user root from 216.65.197.170 port 36068 ssh2 -Oct 3 02:19:30 [sshd] Failed password for illegal user root from 216.65.197.170 port 36227 ssh2 -Oct 3 02:19:33 [sshd] Failed password for illegal user root from 216.65.197.170 port 36453 ssh2 -Oct 3 02:19:34 [sshd] Failed password for illegal user root from 216.65.197.170 port 36673 ssh2 -Oct 3 02:19:36 [sshd] Failed password for illegal user root from 216.65.197.170 port 36823 ssh2 -Oct 3 02:19:38 [sshd] Failed password for illegal user root from 216.65.197.170 port 36981 ssh2 -Oct 3 02:19:39 [sshd] Failed password for illegal user root from 216.65.197.170 port 37152 ssh2 -Oct 3 02:19:41 [sshd] Failed password for illegal user root from 216.65.197.170 port 37310 ssh2 -Oct 3 02:19:43 [sshd] Failed password for illegal user root from 216.65.197.170 port 37484 ssh2 -Oct 3 02:19:45 [sshd] Failed password for illegal user root from 216.65.197.170 port 37644 ssh2 -Oct 3 02:19:46 [sshd] Failed password for illegal user root from 216.65.197.170 port 37827 ssh2 -Oct 3 02:19:48 [sshd] Failed password for illegal user root from 216.65.197.170 port 37989 ssh2 -Oct 3 02:19:50 [sshd] Failed password for illegal user root from 216.65.197.170 port 38163 ssh2 -Oct 3 02:19:52 [sshd] Failed password for illegal user root from 216.65.197.170 port 38329 ssh2 -Oct 3 02:19:54 [sshd] Failed password for illegal user root from 216.65.197.170 port 38559 ssh2 -Oct 3 02:19:56 [sshd] Failed password for illegal user root from 216.65.197.170 port 38735 ssh2 -Oct 3 02:19:58 [sshd] Failed password for illegal user cip52 from 216.65.197.170 port 38893 ssh2 -Oct 3 02:20:00 [sshd] Failed password for illegal user cip51 from 216.65.197.170 port 39109 ssh2 -Oct 3 02:20:01 [sshd] Failed password for illegal user root from 216.65.197.170 port 39282 ssh2 -Oct 3 02:20:03 [sshd] Failed password for illegal user noc from 216.65.197.170 port 39448 ssh2 -Oct 3 02:20:05 [sshd] Failed password for illegal user root from 216.65.197.170 port 39621 ssh2 -Oct 3 02:20:06 [sshd] Failed password for illegal user root from 216.65.197.170 port 39781 ssh2 -Oct 3 02:20:08 [sshd] Failed password for illegal user root from 216.65.197.170 port 39958 ssh2 -Oct 3 02:20:10 [sshd] Failed password for illegal user root from 216.65.197.170 port 40125 ssh2 -Oct 3 02:20:12 [sshd] Failed password for illegal user webmaster from 216.65.197.170 port 40316 ssh2 -Oct 3 02:20:13 [sshd] Failed password for illegal user data from 216.65.197.170 port 40473 ssh2 -Oct 3 02:20:15 [sshd] Failed password for illegal user user from 216.65.197.170 port 40645 ssh2 -Oct 3 02:20:17 [sshd] Failed password for illegal user user from 216.65.197.170 port 40800 ssh2 -Oct 3 02:20:19 [sshd] Failed password for illegal user user from 216.65.197.170 port 40965 ssh2 -Oct 3 02:20:20 [sshd] Failed password for illegal user web from 216.65.197.170 port 41120 ssh2 -Oct 3 02:20:22 [sshd] Failed password for illegal user web from 216.65.197.170 port 41300 ssh2 -Oct 3 02:20:24 [sshd] Failed password for illegal user oracle from 216.65.197.170 port 41468 ssh2 -Oct 3 02:20:25 [sshd] Failed password for illegal user sybase from 216.65.197.170 port 41642 ssh2 -Oct 3 02:20:27 [sshd] Failed password for illegal user master from 216.65.197.170 port 41809 ssh2 -Oct 3 02:20:29 [sshd] Failed password for illegal user account from 216.65.197.170 port 41987 ssh2 -Oct 3 02:20:31 [sshd] Failed password for illegal user backup from 216.65.197.170 port 42143 ssh2 -Oct 3 02:20:32 [sshd] Failed password for illegal user server from 216.65.197.170 port 42316 ssh2 -Oct 3 02:20:34 [sshd] Failed password for illegal user adam from 216.65.197.170 port 42481 ssh2 -Oct 3 02:20:36 [sshd] Failed password for illegal user alan from 216.65.197.170 port 42647 ssh2 -Oct 3 02:20:37 [sshd] Failed password for illegal user frank from 216.65.197.170 port 42817 ssh2 -Oct 3 02:20:39 [sshd] Failed password for illegal user george from 216.65.197.170 port 42993 ssh2 -Oct 3 02:20:41 [sshd] Failed password for illegal user henry from 216.65.197.170 port 43170 ssh2 -Oct 3 02:20:43 [sshd] Failed password for illegal user john from 216.65.197.170 port 43319 ssh2 -Oct 3 02:20:44 [sshd] Failed password for illegal user root from 216.65.197.170 port 43504 ssh2 -Oct 3 02:20:46 [sshd] Failed password for illegal user root from 216.65.197.170 port 43664 ssh2 -Oct 3 02:20:48 [sshd] Failed password for illegal user root from 216.65.197.170 port 43844 ssh2 -Oct 3 02:20:49 [sshd] Failed password for illegal user root from 216.65.197.170 port 44008 ssh2 -Oct 3 02:20:51 [sshd] Failed password for illegal user root from 216.65.197.170 port 44182 ssh2 -Oct 3 02:20:53 [sshd] Failed password for illegal user test from 216.65.197.170 port 44338 ssh2 -Oct 3 06:37:34 [sshd] Failed password for illegal user nobody from 217.56.33.194 port 1969 ssh2 -Oct 3 06:37:36 [sshd] Failed password for illegal user patrick from 217.56.33.194 port 2002 ssh2 -Oct 3 06:37:37 [sshd] Failed password for illegal user patrick from 217.56.33.194 port 2039 ssh2 -Oct 3 06:37:38 [sshd] Failed password for illegal user root from 217.56.33.194 port 2070 ssh2 -Oct 3 06:37:40 [sshd] Failed password for illegal user root from 217.56.33.194 port 2109 ssh2 -Oct 3 06:37:41 [sshd] Failed password for illegal user root from 217.56.33.194 port 2142 ssh2 -Oct 3 06:37:42 [sshd] Failed password for illegal user root from 217.56.33.194 port 2173 ssh2 -Oct 3 06:37:44 [sshd] Failed password for illegal user root from 217.56.33.194 port 2211 ssh2 -Oct 3 06:37:45 [sshd] Failed password for illegal user rolo from 217.56.33.194 port 2244 ssh2 -Oct 3 06:37:46 [sshd] Failed password for illegal user iceuser from 217.56.33.194 port 2272 ssh2 -Oct 3 06:37:48 [sshd] Failed password for illegal user horde from 217.56.33.194 port 2305 ssh2 -Oct 3 06:37:49 [sshd] Failed password for illegal user cyrus from 217.56.33.194 port 2337 ssh2 -Oct 3 06:37:50 [sshd] Failed password for illegal user www from 217.56.33.194 port 2373 ssh2 -Oct 3 06:37:52 [sshd] Failed password for illegal user wwwrun from 217.56.33.194 port 2407 ssh2 -Oct 3 06:37:53 [sshd] Failed password for illegal user matt from 217.56.33.194 port 2439 ssh2 -Oct 3 06:37:55 [sshd] Failed password for illegal user test from 217.56.33.194 port 2466 ssh2 -Oct 3 06:37:56 [sshd] Failed password for illegal user test from 217.56.33.194 port 2501 ssh2 -Oct 3 06:37:57 [sshd] Failed password for illegal user test from 217.56.33.194 port 2533 ssh2 -Oct 3 06:37:59 [sshd] Failed password for illegal user test from 217.56.33.194 port 2567 ssh2 -Oct 3 06:38:00 [sshd] Failed password for illegal user www-data from 217.56.33.194 port 2605 ssh2 -Oct 3 06:38:01 [sshd] Failed password for illegal user mysql from 217.56.33.194 port 2635 ssh2 -Oct 3 06:38:03 [sshd] Failed password for illegal user operator from 217.56.33.194 port 2667 ssh2 -Oct 3 06:38:04 [sshd] Failed password for illegal user adm from 217.56.33.194 port 2697 ssh2 -Oct 3 06:38:05 [sshd] Failed password for illegal user apache from 217.56.33.194 port 2733 ssh2 -Oct 3 06:38:07 [sshd] Failed password for illegal user irc from 217.56.33.194 port 2768 ssh2 -Oct 3 06:38:08 [sshd] Failed password for illegal user irc from 217.56.33.194 port 2804 ssh2 -Oct 3 06:38:09 [sshd] Failed password for illegal user adm from 217.56.33.194 port 2837 ssh2 -Oct 3 06:38:11 [sshd] Failed password for illegal user root from 217.56.33.194 port 2872 ssh2 -Oct 3 06:38:13 [sshd] Failed password for illegal user root from 217.56.33.194 port 2907 ssh2 -Oct 3 06:38:14 [sshd] Failed password for illegal user root from 217.56.33.194 port 2950 ssh2 -Oct 3 06:38:16 [sshd] Failed password for illegal user jane from 217.56.33.194 port 2986 ssh2 -Oct 3 06:38:17 [sshd] Failed password for illegal user pamela from 217.56.33.194 port 3019 ssh2 -Oct 3 06:38:18 [sshd] Failed password for illegal user root from 217.56.33.194 port 3053 ssh2 -Oct 3 06:38:20 [sshd] Failed password for illegal user root from 217.56.33.194 port 3085 ssh2 -Oct 3 06:38:21 [sshd] Failed password for illegal user root from 217.56.33.194 port 3115 ssh2 -Oct 3 06:38:22 [sshd] Failed password for illegal user root from 217.56.33.194 port 3147 ssh2 -Oct 3 06:38:24 [sshd] Failed password for illegal user root from 217.56.33.194 port 3177 ssh2 -Oct 3 06:38:25 [sshd] Failed password for illegal user cosmin from 217.56.33.194 port 3208 ssh2 -Oct 3 06:38:26 [sshd] Failed password for illegal user root from 217.56.33.194 port 3239 ssh2 -Oct 3 06:38:28 [sshd] Failed password for illegal user root from 217.56.33.194 port 3272 ssh2 -Oct 3 06:38:29 [sshd] Failed password for illegal user root from 217.56.33.194 port 3302 ssh2 -Oct 3 06:38:30 [sshd] Failed password for illegal user root from 217.56.33.194 port 3336 ssh2 -Oct 3 06:38:32 [sshd] Failed password for illegal user root from 217.56.33.194 port 3367 ssh2 -Oct 3 06:38:33 [sshd] Failed password for illegal user root from 217.56.33.194 port 3403 ssh2 -Oct 3 06:38:34 [sshd] Failed password for illegal user root from 217.56.33.194 port 3432 ssh2 -Oct 3 06:38:36 [sshd] Failed password for illegal user root from 217.56.33.194 port 3458 ssh2 -Oct 3 06:38:37 [sshd] Failed password for illegal user root from 217.56.33.194 port 3494 ssh2 -Oct 3 06:38:38 [sshd] Failed password for illegal user root from 217.56.33.194 port 3525 ssh2 -Oct 3 06:38:40 [sshd] Failed password for illegal user root from 217.56.33.194 port 3554 ssh2 -Oct 3 06:38:41 [sshd] Failed password for illegal user root from 217.56.33.194 port 3590 ssh2 -Oct 3 06:38:42 [sshd] Failed password for illegal user root from 217.56.33.194 port 3623 ssh2 -Oct 3 06:38:44 [sshd] Failed password for illegal user root from 217.56.33.194 port 3654 ssh2 -Oct 3 06:38:45 [sshd] Failed password for illegal user root from 217.56.33.194 port 3690 ssh2 -Oct 3 06:38:46 [sshd] Failed password for illegal user root from 217.56.33.194 port 3720 ssh2 -Oct 3 06:38:48 [sshd] Failed password for illegal user root from 217.56.33.194 port 3752 ssh2 -Oct 3 06:38:49 [sshd] Failed password for illegal user root from 217.56.33.194 port 3785 ssh2 -Oct 3 06:38:51 [sshd] Failed password for illegal user root from 217.56.33.194 port 3817 ssh2 -Oct 3 06:38:52 [sshd] Failed password for illegal user root from 217.56.33.194 port 3853 ssh2 -Oct 3 06:38:53 [sshd] Failed password for illegal user root from 217.56.33.194 port 3886 ssh2 -Oct 3 06:38:55 [sshd] Failed password for illegal user root from 217.56.33.194 port 3923 ssh2 -Oct 3 06:38:56 [sshd] Failed password for illegal user root from 217.56.33.194 port 3955 ssh2 -Oct 3 06:38:57 [sshd] Failed password for illegal user root from 217.56.33.194 port 3983 ssh2 -Oct 3 06:38:59 [sshd] Failed password for illegal user root from 217.56.33.194 port 4016 ssh2 -Oct 3 06:39:00 [sshd] Failed password for illegal user root from 217.56.33.194 port 4045 ssh2 -Oct 3 06:39:01 [sshd] Failed password for illegal user root from 217.56.33.194 port 4073 ssh2 -Oct 3 06:39:03 [sshd] Failed password for illegal user root from 217.56.33.194 port 4110 ssh2 -Oct 3 06:39:04 [sshd] Failed password for illegal user root from 217.56.33.194 port 4140 ssh2 -Oct 3 06:39:05 [sshd] Failed password for illegal user root from 217.56.33.194 port 4171 ssh2 -Oct 3 06:39:07 [sshd] Failed password for illegal user root from 217.56.33.194 port 4201 ssh2 -Oct 3 06:39:08 [sshd] Failed password for illegal user root from 217.56.33.194 port 4235 ssh2 -Oct 3 06:39:09 [sshd] Failed password for illegal user root from 217.56.33.194 port 4267 ssh2 -Oct 3 06:39:11 [sshd] Failed password for illegal user root from 217.56.33.194 port 4300 ssh2 -Oct 3 06:39:12 [sshd] Failed password for illegal user root from 217.56.33.194 port 4326 ssh2 -Oct 3 06:39:13 [sshd] Failed password for illegal user root from 217.56.33.194 port 4358 ssh2 -Oct 3 06:39:15 [sshd] Failed password for illegal user cip52 from 217.56.33.194 port 4390 ssh2 -Oct 3 06:39:16 [sshd] Failed password for illegal user cip51 from 217.56.33.194 port 4427 ssh2 -Oct 3 06:39:18 [sshd] Failed password for illegal user root from 217.56.33.194 port 4459 ssh2 -Oct 3 06:39:19 [sshd] Failed password for illegal user noc from 217.56.33.194 port 4492 ssh2 -Oct 3 06:39:20 [sshd] Failed password for illegal user root from 217.56.33.194 port 4526 ssh2 -Oct 3 06:39:22 [sshd] Failed password for illegal user root from 217.56.33.194 port 4557 ssh2 -Oct 3 06:39:23 [sshd] Failed password for illegal user root from 217.56.33.194 port 4588 ssh2 -Oct 3 06:39:24 [sshd] Failed password for illegal user root from 217.56.33.194 port 4618 ssh2 -Oct 3 06:39:26 [sshd] Failed password for illegal user webmaster from 217.56.33.194 port 4652 ssh2 -Oct 3 06:39:27 [sshd] Failed password for illegal user data from 217.56.33.194 port 4679 ssh2 -Oct 3 06:39:28 [sshd] Failed password for illegal user user from 217.56.33.194 port 4716 ssh2 -Oct 3 06:39:30 [sshd] Failed password for illegal user user from 217.56.33.194 port 4744 ssh2 -Oct 3 06:39:31 [sshd] Failed password for illegal user user from 217.56.33.194 port 4777 ssh2 -Oct 3 06:39:32 [sshd] Failed password for illegal user web from 217.56.33.194 port 4808 ssh2 -Oct 3 06:39:34 [sshd] Failed password for illegal user web from 217.56.33.194 port 4842 ssh2 -Oct 3 06:39:35 [sshd] Failed password for illegal user oracle from 217.56.33.194 port 4869 ssh2 -Oct 3 06:39:36 [sshd] Failed password for illegal user sybase from 217.56.33.194 port 4899 ssh2 -Oct 3 06:39:38 [sshd] Failed password for illegal user master from 217.56.33.194 port 4933 ssh2 -Oct 3 06:39:39 [sshd] Failed password for illegal user account from 217.56.33.194 port 4969 ssh2 -Oct 3 06:39:40 [sshd] Failed password for illegal user backup from 217.56.33.194 port 4999 ssh2 -Oct 3 06:39:42 [sshd] Failed password for illegal user server from 217.56.33.194 port 1051 ssh2 -Oct 3 06:39:43 [sshd] Failed password for illegal user adam from 217.56.33.194 port 1082 ssh2 -Oct 3 06:39:44 [sshd] Failed password for illegal user alan from 217.56.33.194 port 1114 ssh2 -Oct 3 06:39:46 [sshd] Failed password for illegal user frank from 217.56.33.194 port 1141 ssh2 -Oct 3 06:39:47 [sshd] Failed password for illegal user george from 217.56.33.194 port 1174 ssh2 -Oct 3 06:39:49 [sshd] Failed password for illegal user henry from 217.56.33.194 port 1205 ssh2 -Oct 3 06:39:50 [sshd] Failed password for illegal user john from 217.56.33.194 port 1236 ssh2 -Oct 3 06:39:51 [sshd] Failed password for illegal user root from 217.56.33.194 port 1271 ssh2 -Oct 3 06:39:53 [sshd] Failed password for illegal user root from 217.56.33.194 port 1300 ssh2 -Oct 3 06:39:55 [sshd] Failed password for illegal user root from 217.56.33.194 port 1332 ssh2 -Oct 3 06:39:56 [sshd] Failed password for illegal user root from 217.56.33.194 port 1380 ssh2 -Oct 3 06:39:57 [sshd] Failed password for illegal user root from 217.56.33.194 port 1412 ssh2 -Oct 3 06:39:59 [sshd] Failed password for illegal user test from 217.56.33.194 port 1449 ssh2 -Oct 4 04:43:59 [sshd] Failed password for illegal user test from 212.204.226.21 port 60349 ssh2 -Oct 4 04:44:03 [sshd] Failed password for illegal user guest from 212.204.226.21 port 60394 ssh2 -Oct 4 04:44:06 [sshd] Failed password for illegal user admin from 212.204.226.21 port 60540 ssh2 -Oct 4 04:44:08 [sshd] Failed password for illegal user admin from 212.204.226.21 port 60620 ssh2 -Oct 4 04:44:11 [sshd] Failed password for illegal user user from 212.204.226.21 port 60679 ssh2 -Oct 4 04:44:14 [sshd] Failed password for illegal user root from 212.204.226.21 port 60773 ssh2 -Oct 4 04:44:15 [sshd] Failed password for illegal user root from 212.204.226.21 port 60828 ssh2 -Oct 4 04:44:18 [sshd] Failed password for illegal user root from 212.204.226.21 port 60880 ssh2 -Oct 4 04:44:21 [sshd] Failed password for illegal user test from 212.204.226.21 port 60957 ssh2 -Oct 4 09:32:21 [sshd] Failed password for illegal user test from 62.141.56.70 port 45600 ssh2 -Oct 4 09:32:27 [sshd] Failed password for illegal user guest from 62.141.56.70 port 47635 ssh2 -Oct 4 09:32:32 [sshd] Failed password for illegal user admin from 62.141.56.70 port 49967 ssh2 -Oct 4 09:32:37 [sshd] Failed password for illegal user admin from 62.141.56.70 port 52093 ssh2 -Oct 4 09:32:42 [sshd] Failed password for illegal user user from 62.141.56.70 port 53840 ssh2 -Oct 4 09:32:47 [sshd] Failed password for illegal user root from 62.141.56.70 port 55568 ssh2 -Oct 4 09:32:51 [sshd] Failed password for illegal user root from 62.141.56.70 port 57526 ssh2 -Oct 4 09:32:51 [sshd] Failed password for illegal user root from 62.141.56.70 port 58454 ssh2 -Oct 4 09:32:52 [sshd] Failed password for illegal user test from 62.141.56.70 port 58819 ssh2 -Oct 4 14:09:11 [sshd] Failed password for illegal user test from 211.234.125.100 port 46642 ssh2 -Oct 4 14:09:18 [sshd] Failed password for illegal user guest from 211.234.125.100 port 46788 ssh2 -Oct 4 14:09:23 [sshd] Failed password for illegal user admin from 211.234.125.100 port 46886 ssh2 -Oct 4 14:09:30 [sshd] Failed password for illegal user admin from 211.234.125.100 port 46960 ssh2 -Oct 4 14:09:43 [sshd] Failed password for illegal user user from 211.234.125.100 port 47025 ssh2 -Oct 6 04:13:11 [sshd] Failed password for illegal user test from 64.246.30.17 port 58277 ssh2 -Oct 6 04:13:13 [sshd] Failed password for illegal user guest from 64.246.30.17 port 58360 ssh2 -Oct 6 04:13:15 [sshd] Failed password for illegal user admin from 64.246.30.17 port 58428 ssh2 -Oct 6 04:13:17 [sshd] Failed password for illegal user admin from 64.246.30.17 port 58514 ssh2 -Oct 6 22:13:56 [sshd] Failed password for illegal user test from 61.11.98.217 port 45434 ssh2 -Oct 6 22:14:00 [sshd] Failed password for illegal user guest from 61.11.98.217 port 45586 ssh2 -Oct 6 22:14:05 [sshd] Failed password for illegal user admin from 61.11.98.217 port 45672 ssh2 -Oct 6 22:14:10 [sshd] Failed password for illegal user admin from 61.11.98.217 port 45748 ssh2 -Oct 6 22:14:18 [sshd] Failed password for illegal user user from 61.11.98.217 port 45833 ssh2 -Oct 7 00:25:34 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37086 ssh2 -Oct 7 00:25:34 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37086 ssh2 - - Last output repeated twice - -Oct 7 00:26:27 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37089 ssh2 - - Last output repeated 2 times - -Oct 7 00:26:37 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37092 ssh2 - - Last output repeated 2 times - -Oct 7 00:27:21 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37095 ssh2 - - Last output repeated twice - -Oct 7 00:51:31 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37130 ssh2 - - Last output repeated 2 times - -Oct 7 00:51:48 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37138 ssh2 - - Last output repeated 2 times - -Oct 7 00:52:02 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37141 ssh2 -Oct 7 00:56:10 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37153 ssh2 - - Last output repeated 2 times - -Oct 7 00:56:41 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37156 ssh2 - - Last output repeated 2 times - -Oct 7 00:57:00 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37159 ssh2 -Oct 7 00:58:17 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37162 ssh2 - - Last output repeated 2 times - -Oct 7 00:58:29 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37165 ssh2 - - Last output repeated 2 times - -Oct 7 00:58:39 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37168 ssh2 -Oct 7 01:00:32 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37171 ssh2 - - Last output repeated 2 times - -Oct 7 01:00:44 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37175 ssh2 - - Last output repeated 2 times - -Oct 7 01:01:23 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37178 ssh2 - - Last output repeated 2 times - -Oct 7 01:03:01 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37181 ssh2 - - Last output repeated 2 times - -Oct 7 01:03:12 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37184 ssh2 - - Last output repeated 2 times - -Oct 7 01:03:20 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37187 ssh2 - - Last output repeated 2 times - -Nov 14 11:47:08 [sshd] Failed password for illegal user test from 69.182.27.122 port 34015 ssh2 -Nov 14 11:47:09 [sshd] Failed password for illegal user guest from 69.182.27.122 port 34068 ssh2 -Nov 14 11:47:11 [sshd] Failed password for illegal user admin from 69.182.27.122 port 34127 ssh2 -Nov 15 11:12:11 yellow sshd[16069]: Failed password for cyril from 212.41.79.210 port 29404 ssh2 -Nov 15 21:54:11 yellow sshd[16069]: Illegal user for cyril from 212.41.79.210 port 29404 ssh2 diff --git a/logreader/logreader.py b/logreader/logreader.py deleted file mode 100644 index 72043e4d..00000000 --- a/logreader/logreader.py +++ /dev/null @@ -1,225 +0,0 @@ -# This file is part of Fail2Ban. -# -# Fail2Ban is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Fail2Ban is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Fail2Ban; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -# Author: Cyril Jaquier -# -# $Revision$ - -__author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" -__copyright__ = "Copyright (c) 2004 Cyril Jaquier" -__license__ = "GPL" - -import os, sys, time, re, logging - -from utils.dns import * - -# Gets the instance of the logger. -logSys = logging.getLogger("fail2ban") - -class LogReader: - """ Reads a log file and reports information about IP that make password - failure, bad user or anything else that is considered as doubtful login - attempt. - """ - - def __init__(self, logPath, timeregex, timepattern, failregex, - maxRetry, findTime): - self.logPath = logPath - self.maxRetry = maxRetry - self.timeregex = timeregex - self.timepattern = timepattern - self.failregex = failregex - self.findTime = findTime - self.ignoreIpList = [] - self.lastModTime = 0 - self.lastPos = 0 - self.lastDate = 0 - self.logStats = None - - def getMaxRetry(self): - """ Gets the maximum number of failures - """ - return self.maxRetry - - def getFindTime(self): - """ Gets the find time. - """ - return self.findTime - - def addIgnoreIP(self, ip): - """ Adds an IP to the ignore list. - """ - logSys.debug("Add "+ip+" to ignore list") - self.ignoreIpList.append(ip) - - def inIgnoreIPList(self, ip): - """ Checks if IP is in the ignore list. - """ - for i in self.ignoreIpList: - s = i.split('/', 1) - # IP address without CIDR mask - if len(s) == 1: - s.insert(1, '32') - s[1] = long(s[1]) - a = cidr(s[0], s[1]) - b = cidr(ip, s[1]) - if a == b: - return True - return False - - def openLogFile(self): - """ Opens the log file specified on init. - """ - try: - fileHandler = open(self.logPath) - except OSError: - logSys.error("Unable to open "+self.logPath) - - return fileHandler - - def isModified(self): - """ Checks if the log file has been modified using os.stat(). - """ - try: - self.logStats = os.stat(self.logPath) - if self.lastModTime == self.logStats.st_mtime: - return False - else: - logSys.debug(self.logPath+" has been modified") - self.lastModTime = self.logStats.st_mtime - return True - except OSError: - logSys.error("Unable to get stat on "+self.logPath) - return False - - def setFilePos(self, file): - """ Sets the file position. We must take care of log file rotation - and reset the position to 0 in that case. Use the log message - timestamp in order to detect this. - """ - line = file.readline() - if self.lastDate < self.getTime(line): - logSys.debug("Date " + `self.lastDate` + " is " + "smaller than " + - `self.getTime(line)`) - logSys.debug("Log rotation detected for " + self.logPath) - self.lastPos = 0 - - logSys.debug("Setting file position to " + `self.lastPos` + " for " + - self.logPath) - file.seek(self.lastPos) - - def getFailures(self): - """ Gets all the failure in the log file which are - newer than time.time()-self.findTime. - - Returns a dict with the IP, the number of failure - and the latest failure time. - """ - ipList = dict() - logSys.debug(self.logPath) - logFile = self.openLogFile() - self.setFilePos(logFile) - lastLine = None - for line in logFile: - if not self.hasTime(line): - # There is no valid time in this line - continue - lastLine = line - for element in self.findFailure(line): - ip = element[0] - unixTime = element[1] - if unixTime < time.time()-self.findTime: - break - if self.inIgnoreIPList(ip): - logSys.debug("Ignore "+ip) - continue - logSys.debug("Found "+ip) - if ipList.has_key(ip): - ipList[ip] = (ipList[ip][0]+1, unixTime) - else: - ipList[ip] = (1, unixTime) - self.lastPos = logFile.tell() - if lastLine: - self.lastDate = self.getTime(lastLine) - logFile.close() - return ipList - - def findFailure(self, line): - """ Finds the failure in line. Uses the failregex pattern - to find it and timeregex in order to find the logging - time. - - Returns a dict with IP and timestamp. - """ - failList = list() - match = re.search(self.failregex, line) - if match: - timeMatch = re.search(self.timeregex, match.string) - if timeMatch: - date = self.getUnixTime(timeMatch.group()) - ipMatch = textToIp(match.string) - if ipMatch: - for ip in ipMatch: - failList.append([ip, date]) - return failList - - def hasTime(self, line): - """ Return true if the line contains a date - """ - timeMatch = re.search(self.timeregex, line) - if timeMatch: - return True - else: - return False - - def getTime(self, line): - """ Gets the time of a log message. - """ - date = 0 - timeMatch = re.search(self.timeregex, line) - if timeMatch: - date = self.getUnixTime(timeMatch.group()) - return date - - def getUnixTime(self, value): - """ Returns the Unix timestamp of the given value. - Pattern should describe the date construction of - value. - """ - try: - # Check if the parsed value is in TAI64N format - if not self.timepattern.lower() == "tai64n": - date = list(time.strptime(value, self.timepattern)) - else: - # extract part of format which represents seconds since epoch - seconds_since_epoch = value[2:17] - date = list(time.gmtime(int(seconds_since_epoch, 16))) - except ValueError, e: - logSys.error(e) - logSys.error("Please check the format and your locale settings.") - return None - if date[0] < 2000: - # There is probably no year field in the logs - date[0] = time.gmtime()[0] - # Bug fix for #1241756 - # If the date is greater than the current time, we suppose - # that the log is not from this year but from the year before - if time.mktime(date) > time.time(): - date[0] -= 1 - unixTime = time.mktime(date) - return unixTime diff --git a/man/fail2ban.8 b/man/fail2ban.8 deleted file mode 100644 index 1c2e4f73..00000000 --- a/man/fail2ban.8 +++ /dev/null @@ -1,58 +0,0 @@ -.\" -.TH "FAIL2BAN" "8" "July 2005" "Cyril Jaquier" "System administration tools" -.SH "NAME" -fail2ban \- bans IP that makes too many password failures -.SH "SYNOPSIS" -.B fail2ban -[\fIOPTIONS\fR] -.SH "DESCRIPTION" -\fBFail2Ban\fR reads log file that contains password failure report -and bans the corresponding IP addresses using firewall rules. It updates -firewall rules to reject the IP address. -.SH "OPTIONS" -.TP -\fB\-b\fR -start in background -.TP -\fB\-c\fR \fIFILE\fR -read configuration file \fIFILE\fR -.TP -\fB\-p\fR \fIFILE\fR -create PID lock in \fIFILE\fR -.TP -\fB\-h, \-\-help\fR -display this help message -.TP -\fB\-i\fR \fIIP\fR -\fIIP\fR(s) to ignore -.TP -\fB\-k\fR -kill a currently running Fail2Ban instance -.TP -\fB\-r\fR \fIVALUE\fR -allow a max of \fIVALUE\fR password failure [maxfailures] -.TP -\fB\-t\fR \fITIME\fR -ban IP for \fITIME\fR seconds [bantime] -.TP -\fB\-f\fR \fITIME\fR -lifetime in seconds of failed entry [findtime] -.TP -\fB\-v\fR -verbose. Use twice for greater effect -.TP -\fB\-V, \-\-version\fR -print software version -.SH "FILES" -.I /etc/fail2ban.conf -.RS -The configuration file. See \fBfail2ban.conf\fR(5) for further details. -.SH "REPORTING BUGS" -Please report bugs at http://sourceforge.net/projects/fail2ban/ -via bug tracker -.SH "AUTHOR" -Cyril Jaquier <lostcontrol@users.sourceforge.net> -.SH "SEE ALSO" -.TP -See -.BR "http://fail2ban.sourceforge.net/". diff --git a/man/fail2ban.conf.5 b/man/fail2ban.conf.5 deleted file mode 100644 index 91328a35..00000000 --- a/man/fail2ban.conf.5 +++ /dev/null @@ -1,20 +0,0 @@ -.\" -.TH "FAIL2BAN.CONF" "5" "July 2005" "Cyril Jaquier" "System administration tools" -.SH "NAME" -fail2ban.conf \- configuration data for fail2ban -.SH "DESCRIPTION" -\fB/etc/fail2ban.conf\fR contains data about the general configuration of fail2ban, the mail notification and services to monitor. -.SH "VARIABLES" -Please look at the file itself -.SH "FILES" -.I /etc/fail2ban.conf -.SH "REPORTING BUGS" -Please report bugs at http://sourceforge.net/projects/fail2ban/ -via bug tracker -.SH "AUTHOR" -Cyril Jaquier <lostcontrol@users.sourceforge.net> -.SH "SEE ALSO" -.BR fail2ban (8) -.TP -See -.BR "http://fail2ban.sourceforge.net/". diff --git a/logreader/__init__.py b/server/__init__.py index 76dba873..60ef5531 100644 --- a/logreader/__init__.py +++ b/server/__init__.py @@ -16,10 +16,10 @@ # Author: Cyril Jaquier # -# $Revision$ +# $Revision: 1.1 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL"
\ No newline at end of file diff --git a/server/action.py b/server/action.py new file mode 100644 index 00000000..f47fe579 --- /dev/null +++ b/server/action.py @@ -0,0 +1,281 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from banmanager import BanManager +from failmanager import FailManager, FailManagerEmpty +from jailthread import JailThread +import time, logging, os + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.action") + +## +# 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 Action(JailThread): + + ## + # Constructor. + # + # Initialize the filter object with default values. + # @param jail the jail object + + def __init__(self, jail): + JailThread.__init__(self, jail) + ## The jail which contains this action. + self.jail = jail + ## The ban manager. + self.banManager = BanManager() + ## Command executed in order to initialize the system. + self.actionStart = '' + ## Command executed when an IP address gets banned. + self.actionBan = '' + ## Command executed when an IP address gets removed. + self.actionUnban = '' + ## Command executed in order to check requirements. + self.actionCheck = '' + ## Command executed in order to stop the system. + self.actionStop = '' + logSys.debug("Created Action") + + ## + # Set the "start" command. + # + # @param value the command + + def setActionStart(self, value): + self.actionStart = value + logSys.info("Set actionStart = %s" % value) + + ## + # Get the "start" command. + # + # @return the command + + def getActionStart(self): + return self.actionStart + + ## + # Set the "ban" command. + # + # @param value the command + + def setActionBan(self, value): + self.actionBan = value + logSys.info("Set actionBan = %s" % value) + + ## + # Get the "ban" command. + # + # @return the command + + def getActionBan(self): + return self.actionBan + + ## + # Set the "unban" command. + # + # @param value the command + + def setActionUnban(self, value): + self.actionUnban = value + logSys.info("Set actionUnban = %s" % value) + + ## + # Get the "unban" command. + # + # @return the command + + def getActionUnban(self): + return self.actionUnban + + ## + # Set the "check" command. + # + # @param value the command + + def setActionCheck(self, value): + self.actionCheck = value + logSys.info("Set actionCheck = %s" % value) + + ## + # Get the "check" command. + # + # @return the command + + def getActionCheck(self): + return self.actionCheck + + ## + # Set the "stop" command. + # + # @param value the command + + def setActionStop(self, value): + self.actionStop = value + logSys.info("Set actionStop = %s" % value) + + ## + # Get the "stop" command. + # + # @return the command + + def getActionStop(self): + return self.actionStop + + ## + # Set the ban time. + # + # @param value the time + + def setBanTime(self, value): + self.banManager.setBanTime(value) + logSys.info("Set banTime = %s" % value) + + ## + # Get the ban time. + # + # @return the time + + def getBanTime(self): + return self.banManager.getBanTime() + + ## + # 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): + self.executeCmd(self.actionStart) + self.setActive(True) + while self.isActive(): + if not self.isIdle: + #logSys.debug(self.jail.getName() + ": action") + ret = self.checkBan() + if not ret: + self.checkUnBan() + time.sleep(self.sleepTime) + else: + time.sleep(self.sleepTime) + self.flushBan() + self.executeCmd(self.actionStop) + 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): + logSys.debug("Check for IP address to ban") + ticket = self.jail.getFailTicket() + if ticket != False: + aInfo = dict() + bTicket = BanManager.createBanTicket(ticket) + aInfo["ip"] = bTicket.getIP() + logSys.info("Ban %s" % aInfo["ip"]) + self.executeCmd(self.replaceTag(self.actionBan, aInfo)) + self.banManager.addBanTicket(bTicket) + return True + return False + + ## + # Check for IP address to unban. + # + # Unban IP address which are outdated. + + def checkUnBan(self): + logSys.debug("Check for IP address to unban") + for ticket in self.banManager.unBanList(time.time()): + aInfo = dict() + aInfo["ip"] = ticket.getIP() + logSys.info("Unban %s" % aInfo["ip"]) + self.executeCmd(self.replaceTag(self.actionUnban, aInfo)) + + ## + # Flush the ban list. + # + # Unban all IP address which are still in the banning list. + + def flushBan(self): + logSys.debug("Flush ban list") + for ticket in self.banManager.flushBanList(): + aInfo = dict() + aInfo["ip"] = ticket.getIP() + logSys.info("Unban %s" % aInfo["ip"]) + self.executeCmd(self.replaceTag(self.actionUnban, aInfo)) + + ## + # 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 + + def status(self): + ret = [("Currently banned", self.banManager.size()), + ("Total banned", self.banManager.getBanTotal())] + return ret + + @staticmethod + def replaceTag(query, aInfo): + """ Replace tags in query + """ + string = query + for tag in aInfo: + string = string.replace('<' + tag + '>', str(aInfo[tag])) + # New line + string = string.replace("<br>", '\n') + return string + + @staticmethod + def executeCmd(cmd): + """ Executes an OS command. + """ + if cmd == "": + logSys.debug("Nothing to do") + return True + + logSys.debug(cmd) + retval = os.system(cmd) + #if not retval == 0: + # logSys.error("'" + cmd + "' returned " + `retval`) + # raise Exception("Execution of command '%s' failed" % cmd) + if retval == 0: + return True + else: + logSys.error("%s returned %x" % (cmd, retval)) + return False +
\ No newline at end of file diff --git a/server/banmanager.py b/server/banmanager.py new file mode 100644 index 00000000..1ae6122b --- /dev/null +++ b/server/banmanager.py @@ -0,0 +1,184 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from banticket import BanTicket +from threading import Lock +import time, logging + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.action") + +## +# Banning Manager. +# +# Manage the banned IP addresses. Convert FailTicket to BanTicket. +# This class is mainly used by the Action class. + +class BanManager: + + ## + # Constructor. + # + # Initialize members with default values. + + def __init__(self): + ## Mutex used to protect the ban list. + self.lock = Lock() + ## The ban list. + self.banList = list() + ## The amount of time an IP address gets banned. + self.banTime = 600 + ## Total number of banned IP address + self.banTotal = 0 + + ## + # Set the ban time. + # + # Set the amount of time an IP address get banned. + # @param value the time + + def setBanTime(self, value): + self.banTime = int(value) + + ## + # Get the ban time. + # + # Get the amount of time an IP address get banned. + # @return the time + + def getBanTime(self): + return self.banTime + + ## + # Set the total number of banned address. + # + # @param value total number + + def setBanTotal(self, value): + self.banTotal = value + + ## + # Get the total number of banned address. + # + # @return the total number + + def getBanTotal(self): + return self.banTotal + + ## + # Create a ban ticket. + # + # Create a BanTicket from a FailTicket. The timestamp of the BanTicket + # is the current time. This is a static method. + # @param ticket the FailTicket + # @return a BanTicket + + @staticmethod + def createBanTicket(ticket): + ip = ticket.getIP() + #lastTime = ticket.getTime() + lastTime = time.time() + return BanTicket(ip, lastTime) + + ## + # Add a ban ticket. + # + # Add a BanTicket instance into the ban list. + # @param ticket the ticket + # @return True if the IP address is not in the ban list + + def addBanTicket(self, ticket): + self.lock.acquire() + if not self.inBanList(ticket): + self.banList.append(ticket) + self.banTotal += 1 + self.lock.release() + return True + self.lock.release() + return False + + ## + # Delete a ban ticket. + # + # Remove a BanTicket from the ban list. + # @param ticket the ticket + + def delBanTicket(self, ticket): + self.banList.remove(ticket) + + ## + # Get the size of the ban list. + # + # @return the size + + def size(self): + return len(self.banList) + + ## + # Check if a ticket is in the list. + # + # Check if a BanTicket with a given IP address is already in the + # ban list. + # @param ticket the ticket + # @return True if a ticket already exists + + def inBanList(self, ticket): + for i in self.banList: + if ticket.getIP() == i.getIP(): + return True + return False + + ## + # Get the list of IP address to unban. + # + # Return a list of BanTicket which need to be unbanned. + # @param time the time + # @return the list of ticket to unban + # @todo Check the delete operation + + def unBanList(self, time): + uBList = list() + self.lock.acquire() + for ticket in self.banList: + if ticket.getTime() < time - self.banTime: + uBList.append(ticket) + self.delBanTicket(ticket) + self.lock.release() + return uBList + + ## + # Flush the ban list. + # + # Get the ban list and initialize it with an empty one. + # @return the complete ban list + + def flushBanList(self): + self.lock.acquire() + uBList = self.banList + self.banList = list() + self.lock.release() + return uBList +
\ No newline at end of file diff --git a/server/banticket.py b/server/banticket.py new file mode 100644 index 00000000..7d271e6c --- /dev/null +++ b/server/banticket.py @@ -0,0 +1,50 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import time, logging +from ticket import Ticket + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban") + +## +# Ban Ticket. +# +# This class extends the Ticket class. It is mainly used by the BanManager. + +class BanTicket(Ticket): + + ## + # Constructor. + # + # Call the Ticket (parent) constructor and initialize default + # values. + # @param ip the IP address + # @param time the ban time + + def __init__(self, ip, time): + Ticket.__init__(self, ip, time) +
\ No newline at end of file diff --git a/server/faildata.py b/server/faildata.py new file mode 100644 index 00000000..f1b2441e --- /dev/null +++ b/server/faildata.py @@ -0,0 +1,53 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import time, logging + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban") + +class FailData: + + def __init__(self): + self.retry = 0 + self.lastTime = 0 + + def setRetry(self, value): + self.retry = value + + def getRetry(self): + return self.retry + + def inc(self): + self.retry += 1 + + def setLastTime(self, value): + if value > self.lastTime: + self.lastTime = value + + def getLastTime(self): + return self.lastTime +
\ No newline at end of file diff --git a/server/failmanager.py b/server/failmanager.py new file mode 100644 index 00000000..0a4266b9 --- /dev/null +++ b/server/failmanager.py @@ -0,0 +1,106 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from faildata import FailData +from failticket import FailTicket +from threading import Lock +import time, logging + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.filter") + +class FailManager: + + def __init__(self): + self.lock = Lock() + self.failList = dict() + self.maxRetry = 3 + self.maxTime = 600 + self.failTotal = 0 + + def setFailTotal(self, value): + self.failTotal = value + + def getFailTotal(self): + return self.failTotal + + def setMaxRetry(self, value): + self.maxRetry = value + + def getMaxRetry(self): + return self.maxRetry + + def setMaxTime(self, value): + self.maxTime = value + + def getMaxTime(self): + return self.maxTime + + def addFailure(self, ticket): + self.lock.acquire() + ip = ticket.getIP() + unixTime = ticket.getTime() + if self.failList.has_key(ip): + fData = self.failList[ip] + fData.inc() + fData.setLastTime(unixTime) + else: + fData = FailData() + fData.inc() + fData.setLastTime(unixTime) + self.failList[ip] = fData + self.failTotal += 1 + self.lock.release() + + def size(self): + return len(self.failList) + + def cleanup(self, time): + self.lock.acquire() + tmp = self.failList.copy() + for item in tmp: + if tmp[item].getLastTime() < time - self.maxTime: + self.delFailure(item) + self.lock.release() + + def delFailure(self, ip): + if self.failList.has_key(ip): + del self.failList[ip] + + def toBan(self): + self.lock.acquire() + for ip in self.failList: + data = self.failList[ip] + if data.getRetry() >= self.maxRetry: + self.delFailure(ip) + self.lock.release() + return FailTicket(ip, data.getLastTime()) + self.lock.release() + raise FailManagerEmpty + +class FailManagerEmpty(Exception): + pass +
\ No newline at end of file diff --git a/version.py b/server/failticket.py index 80f0c7a8..395ec0d3 100644 --- a/version.py +++ b/server/failticket.py @@ -16,12 +16,22 @@ # Author: Cyril Jaquier # -# $Revision$ +# $Revision: 1.1 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -version = "0.6.1" +import time, logging +from ticket import Ticket + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban") + +class FailTicket(Ticket): + + def __init__(self, ip, time): + Ticket.__init__(self, ip, time) +
\ No newline at end of file diff --git a/server/filter.py b/server/filter.py new file mode 100644 index 00000000..ccbea64d --- /dev/null +++ b/server/filter.py @@ -0,0 +1,452 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from failmanager import FailManager +from failmanager import FailManagerEmpty +from failticket import FailTicket +from jailthread import JailThread +from utils.dns import * +import time, logging, os, re, sys, socket + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.filter") + +## +# Log reader class. +# +# This class reads a log file and detects login failures or anything else +# that matches a given regular expression. This class is instanciated by +# a Jail object. + +class Filter(JailThread): + + ## + # Constructor. + # + # Initialize the filter object with default values. + # @param jail the jail object + + def __init__(self, jail): + JailThread.__init__(self, jail) + ## The jail which contains this filter. + self.jail = jail + ## The failures manager. + self.failManager = FailManager() + ## The log file handler. + self.fileHandler = None + ## The log file path. + self.logPath = '' + ## The regular expression matching the date. + self.timeRegex = '' + ## The pattern matching the date. + self.timePattern = '' + ## The regular expression matching the failure. + self.failRegex = '' + ## The amount of time to look back. + self.findTime = 6000 + ## The ignore IP list. + self.ignoreIpList = [] + ## The time of the last modification of the file. + self.lastModTime = 0 + ## The last position of the file. + self.lastPos = 0 + ## The last date in tht log file. + self.lastDate = 0 + ## The file statistics. + self.logStats = None + logSys.info("Created Filter") + + ## + # Set the log file path + # + # @param value log file path + + def setLogPath(self, value): + self.logPath = value + logSys.info("Set logfile = %s" % value) + + ## + # Get the log file path + # + # @return log file path + + def getLogPath(self): + return self.logPath + + ## + # Set the regular expression which matches the time. + # + # @param value the regular expression + + def setTimeRegex(self, value): + self.timeRegex = value + logSys.info("Set timeregex = %s" % value) + + ## + # Get the regular expression which matches the time. + # + # @return the regular expression + + def getTimeRegex(self): + return self.timeRegex + + ## + # Set the time pattern. + # + # @param value the time pattern + + def setTimePattern(self, value): + self.timePattern = value + logSys.info("Set timepattern = %s" % value) + + ## + # Get the time pattern. + # + # @return the time pattern + + def getTimePattern(self): + return self.timePattern + + ## + # Set the regular expression which matches the failure. + # + # The regular expression can also match any other pattern than failures + # and thus can be used for many purporse. + # @param value the regular expression + + def setFailRegex(self, value): + self.failRegex = value + logSys.info("Set failregex = %s" % value) + + ## + # Get the regular expression which matches the failure. + # + # @return the regular expression + + def getFailRegex(self): + return self.failRegex + + ## + # Set the time needed to find a failure. + # + # This value tells the filter how long it has to take failures into + # account. + # @param value the time + + def setFindTime(self, value): + self.findTime = value + logSys.info("Set findtime = %s" % value) + + ## + # Get the time needed to find a failure. + # + # @return the time + + def getFindTime(self): + return self.findTime + + ## + # Set the maximum retry value. + # + # @param value the retry value + + def setMaxRetry(self, value): + self.failManager.setMaxRetry(value) + logSys.info("Set maxRetry = %s" % value) + + ## + # Get the maximum retry value. + # + # @return the retry value + + def getMaxRetry(self): + return self.failManager.getMaxRetry() + + ## + # Set the maximum time a failure stays in the list. + # + # @param value the maximum time + + def setMaxTime(self, value): + self.failManager.setMaxTime(value) + logSys.info("Set maxTime = %s" % value) + + ## + # Get the maximum time a failure stays in the list. + # + # @return the time value + + def getMaxTime(self): + return self.failManager.getMaxTime() + + ## + # Main loop. + # + # This function is the main loop of the thread. It checks if the + # file has been modified and looks for failures. + # @return True when the thread exits nicely + + def run(self): + self.setActive(True) + while self.isActive(): + if not self.isIdle: + if self.isModified(): + self.getFailures() + try: + ticket = self.failManager.toBan() + self.jail.putFailTicket(ticket) + except FailManagerEmpty: + self.failManager.cleanup(time.time()) + time.sleep(self.sleepTime) + else: + time.sleep(self.sleepTime) + logSys.debug(self.jail.getName() + ": filter terminated") + return True + + ## + # Add an IP to the ignore list. + # + # IP addresses in the ignore list are not taken into account + # when finding failures. CIDR mask are also accepted. + # @param ip IP address to ignore + + def addIgnoreIP(self, ip): + logSys.debug("Add " + ip + " to ignore list") + self.ignoreIpList.append(ip) + + ## + # Check if IP address is in the ignore list. + # + # Check if the given IP address matches an IP address or a CIDR + # mask in the ignore list. + # @param ip IP address + # @return True if IP address is in ignore list + + def inIgnoreIPList(self, ip): + for i in self.ignoreIpList: + s = i.split('/', 1) + # IP address without CIDR mask + if len(s) == 1: + s.insert(1, '32') + s[1] = long(s[1]) + try: + a = cidr(s[0], s[1]) + b = cidr(ip, s[1]) + except Exception: + return False + if a == b: + return True + return False + + ## + # Open the log file. + + def openLogFile(self): + """ Opens the log file specified on init. + """ + try: + self.fileHandler = open(self.logPath) + except OSError: + logSys.error("Unable to open "+self.logPath) + + ## + # Close the log file. + + def closeLogFile(self): + self.fileHandler.close() + + ## + # Checks if the log file has been modified. + # + # Checks if the log file has been modified using os.stat(). + # @return True if log file has been modified + + def isModified(self): + try: + self.logStats = os.stat(self.logPath) + if self.lastModTime == self.logStats.st_mtime: + return False + else: + logSys.debug(self.logPath + " has been modified") + self.lastModTime = self.logStats.st_mtime + return True + except OSError: + logSys.error("Unable to get stat on " + self.logPath) + return False + + ## + # Set the file position. + # + # Sets the file position. We must take care of log file rotation + # and reset the position to 0 in that case. Use the log message + # timestamp in order to detect this. + + def setFilePos(self): + line = self.fileHandler.readline() + if self.lastDate < self.getTime(line): + logSys.debug("Date " + `self.lastDate` + " is " + "smaller than " + + `self.getTime(line)`) + logSys.debug("Log rotation detected for " + self.logPath) + self.lastPos = 0 + + logSys.debug("Setting file position to " + `self.lastPos` + " for " + + self.logPath) + self.fileHandler.seek(self.lastPos) + + ## + # Get the file position. + + def getFilePos(self): + return self.fileHandler.tell() + + ## + # Gets all the failure in the log file. + # + # Gets all the failure in the log file which are newer than + # time.time()-self.findTime. When a failure is detected, a FailTicket + # is created and is added to the FailManager. + + def getFailures(self): + ipList = dict() + logSys.debug(self.logPath) + self.openLogFile() + self.setFilePos() + lastLine = None + for line in self.fileHandler: + try: + # Try to convert UTF-8 string to Latin-1 + line = line.decode('utf-8').encode('latin-1') + except UnicodeDecodeError: + pass + if not self.hasTime(line): + # There is no valid time in this line + continue + lastLine = line + for element in self.findFailure(line): + ip = element[0] + unixTime = element[1] + if unixTime < time.time()-self.findTime: + break + if self.inIgnoreIPList(ip): + logSys.debug("Ignore "+ip) + continue + logSys.debug("Found "+ip) + self.failManager.addFailure(FailTicket(ip, unixTime)) + self.lastPos = self.getFilePos() + if lastLine: + self.lastDate = self.getTime(lastLine) + self.closeLogFile() + + ## + # Finds the failure in a line. + # + # Uses the failregex pattern to find it and timeregex in order + # to find the logging time. + # @return a dict with IP and timestamp. + + def findFailure(self, line): + failList = list() + match = re.search(self.failRegex, line) + if match: + timeMatch = re.search(self.timeRegex, match.string) + if timeMatch: + date = self.getUnixTime(timeMatch.group()) + ipMatch = textToIp(match.string) + if ipMatch: + for ip in ipMatch: + failList.append([ip, date]) + return failList + + ## + # Check is a line contains a valid date. + # + # @param line the line + # @return True if the line contains a valid date + + def hasTime(self, line): + timeMatch = re.search(self.timeRegex, line) + if timeMatch: + return True + else: + return False + + ## + # Get the time of a log line. + # + # @param line the line + # @return the timestamp of the log line + + def getTime(self, line): + date = 0 + timeMatch = re.search(self.timeRegex, line) + if timeMatch: + date = self.getUnixTime(timeMatch.group()) + return date + + ## + # Get the Unix timestamp. + # + # Get the Unix timestamp of a given date. Pattern should describe the + # date construction of value. + # @param value the date + # @return the Unix timestamp + + def getUnixTime(self, value): + try: + # Check if the parsed value is in TAI64N format + if not self.timePattern.lower() == "tai64n": + date = list(time.strptime(value, self.timePattern)) + else: + # extract part of format which represents seconds since epoch + seconds_since_epoch = value[2:17] + date = list(time.gmtime(int(seconds_since_epoch, 16))) + except ValueError, e: + logSys.error(e) + logSys.error("Please check the format and your locale settings.") + return None + if date[0] < 2000: + # There is probably no year field in the logs + date[0] = time.gmtime()[0] + # Bug fix for #1241756 + # If the date is greater than the current time, we suppose + # that the log is not from this year but from the year before + #if time.mktime(date) > time.time(): + # date[0] -= 1 + unixTime = time.mktime(date) + return unixTime + + ## + # 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 + + def status(self): + ret = [("Currently failed", self.failManager.size()), + ("Total failed", self.failManager.getFailTotal())] + return ret +
\ No newline at end of file diff --git a/server/jail.py b/server/jail.py new file mode 100644 index 00000000..06b1229d --- /dev/null +++ b/server/jail.py @@ -0,0 +1,95 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from action import Action +from filter import Filter +import Queue + + +class Jail: + + def __init__(self, name, filter = None, action = None): + self.name = name + self.queue = Queue.Queue() + self.filter = Filter(self) + self.action = Action(self) + + def setName(self, name): + self.name = name + + def getName(self): + return self.name + + def setFilter(self, filter): + self.filter = filter + + def getFilter(self): + return self.filter + + def setAction(self, action): + self.action = action + + def getAction(self): + return self.action + + def putFailTicket(self, ticket): + self.queue.put(ticket) + + def getFailTicket(self): + try: + return self.queue.get(False) + except Queue.Empty: + return False + + def start(self): + self.filter.start() + self.action.start() + + def stop(self): + self.filter.stop() + self.action.stop() + self.filter.join() + self.action.join() + + def isActive(self): + isActive0 = self.filter.isActive() + isActive1 = self.action.isActive() + return isActive0 or isActive1 + + def setIdle(self, value): + self.filter.setIdle(value) + self.action.setIdle(value) + + def getIdle(self): + return self.filter.getIdle() or self.action.getIdle() + + def getStatus(self): + fStatus = self.filter.status() + aStatus = self.action.status() + ret = [("filter", fStatus), + ("action", aStatus)] + return ret +
\ No newline at end of file diff --git a/server/jailthread.py b/server/jailthread.py new file mode 100644 index 00000000..e74c4db2 --- /dev/null +++ b/server/jailthread.py @@ -0,0 +1,114 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from threading import Thread + +class JailThread(Thread): + + ## + # Constructor. + # + # Initialize the filter object with default values. + # @param jail the jail object + + def __init__(self, jail): + Thread.__init__(self) + ## Control the state of the thread. + self.isRunning = False + ## Control the idle state of the thread. + self.isIdle = False + ## The time the thread sleeps in the loop. + self.sleepTime = 1 + + ## + # Set the time that the thread sleeps. + # + # This value could also be called "polling time". A value of 1 is a + # good one. This unit is "second" + # @param value the polling time (second) + + def setSleepTime(self, value): + self.sleepTime = value + logSys.info("Set sleeptime = " + value) + + ## + # Get the time that the thread sleeps. + # + # @return the polling time + + def getSleepTime(self): + return self.sleeptime + + ## + # Set the idle flag. + # + # This flag stops the check of the log file. + # @param value boolean value + + def setIdle(self, value): + self.isIdle = value + + ## + # Get the idle state. + # + # @return the idle state + + def getIdle(self): + return self.isIdle + + ## + # Stop the thread. + # + # Stop the exection of the thread and quit. + + def stop(self): + self.isRunning = False + + ## + # Set the isRunning flag. + # + # @param value True if the thread is running + + def setActive(self, value): + self.isRunning = value + + ## + # Check if the thread is active. + # + # Check if the filter thread is running. + # @return True if the thread is running + + def isActive(self): + return self.isRunning + + ## + # Get the status of the thread + # + # Get some informations about the thread. This is an abstract method. + # @return a list with tuple + + def status(self): + pass
\ No newline at end of file diff --git a/server/server.py b/server/server.py new file mode 100644 index 00000000..7ef3886f --- /dev/null +++ b/server/server.py @@ -0,0 +1,291 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from jail import Jail +from transmitter import Transmitter +import locale, logging + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.server") + +class Server: + + def __init__(self): + self.jails = dict() + self.transm = Transmitter(self) + self.logLevel = 3 + # Set logging level + self.setLogLevel(self.logLevel) + + def start(self): + # Start the communication + self.transm.start() + + def quit(self): + for jail in self.jails.copy(): + self.stopJail(jail) + self.transm.stop() + + def addJail(self, name): + self.jails[name] = Jail(name) + + def delJail(self, name): + if self.jails.has_key(name): + del self.jails[name] + else: + raise ServerUnknownJail(name) + + def startJail(self, name): + if self.jails.has_key(name): + self.jails[name].start() + else: + raise ServerUnknownJail(name) + + def stopJail(self, name): + if self.jails.has_key(name): + if self.isActive(name): + self.jails[name].stop() + self.delJail(name) + else: + raise ServerUnknownJail(name) + + def isActive(self, name): + if self.jails.has_key(name): + return self.jails[name].isActive() + else: + raise ServerUnknownJail(name) + + def setIdleJail(self, name, value): + if self.jails.has_key(name): + self.jails[name].setIdle(value) + return True + else: + raise ServerUnknownJail(name) + + def getIdleJail(self, name): + if self.jails.has_key(name): + return self.jails[name].getIdle() + else: + raise ServerUnknownJail(name) + + # Filter + def setLogPath(self, name, file): + if self.jails.has_key(name): + self.jails[name].getFilter().setLogPath(file) + + def getLogPath(self, name): + if self.jails.has_key(name): + return self.jails[name].getFilter().getLogPath() + else: + raise ServerUnknownJail(name) + + def setTimeRegex(self, name, value): + if self.jails.has_key(name): + self.jails[name].getFilter().setTimeRegex(value) + else: + raise ServerUnknownJail(name) + + def getTimeRegex(self, name): + if self.jails.has_key(name): + return self.jails[name].getFilter().getTimeRegex() + else: + raise ServerUnknownJail(name) + + def setTimePattern(self, name, value): + if self.jails.has_key(name): + self.jails[name].getFilter().setTimePattern(value) + else: + raise ServerUnknownJail(name) + + def getTimePattern(self, name): + if self.jails.has_key(name): + return self.jails[name].getFilter().getTimePattern() + else: + raise ServerUnknownJail(name) + + def setFailRegex(self, name, value): + if self.jails.has_key(name): + self.jails[name].getFilter().setFailRegex(value) + else: + raise ServerUnknownJail(name) + + def getFailRegex(self, name): + if self.jails.has_key(name): + return self.jails[name].getFilter().getFailRegex() + else: + raise ServerUnknownJail(name) + + def setMaxRetry(self, name, value): + if self.jails.has_key(name): + self.jails[name].getFilter().setMaxRetry(value) + else: + raise ServerUnknownJail(name) + + def getMaxRetry(self, name): + if self.jails.has_key(name): + return self.jails[name].getFilter().getMaxRetry() + else: + raise ServerUnknownJail(name) + + def setMaxTime(self, name, value): + if self.jails.has_key(name): + self.jails[name].getFilter().setMaxTime(value) + else: + raise ServerUnknownJail(name) + + def getMaxTime(self, name): + if self.jails.has_key(name): + return self.jails[name].getFilter().getMaxTime() + else: + raise ServerUnknownJail(name) + + # Action + def setBanTime(self, name, value): + if self.jails.has_key(name): + self.jails[name].getAction().setBanTime(value) + else: + raise ServerUnknownJail(name) + + def getBanTime(self, name): + if self.jails.has_key(name): + return self.jails[name].getAction().getBanTime() + else: + raise ServerUnknownJail(name) + + def setActionStart(self, name, value): + if self.jails.has_key(name): + self.jails[name].getAction().setActionStart(value) + else: + raise ServerUnknownJail(name) + + def getActionStart(self, name): + if self.jails.has_key(name): + return self.jails[name].getAction().getActionStart() + else: + raise ServerUnknownJail(name) + + def setActionStop(self, name, value): + if self.jails.has_key(name): + self.jails[name].getAction().setActionStop(value) + else: + raise ServerUnknownJail(name) + + def getActionStop(self, name): + if self.jails.has_key(name): + return self.jails[name].getAction().getActionStop() + else: + raise ServerUnknownJail(name) + + def setActionCheck(self, name, value): + if self.jails.has_key(name): + self.jails[name].getAction().setActionCheck(value) + else: + raise ServerUnknownJail(name) + + def getActionCheck(self, name): + if self.jails.has_key(name): + return self.jails[name].getAction().getActionCheck() + else: + raise ServerUnknownJail(name) + + def setActionBan(self, name, value): + if self.jails.has_key(name): + self.jails[name].getAction().setActionBan(value) + else: + raise ServerUnknownJail(name) + + def getActionBan(self, name): + if self.jails.has_key(name): + return self.jails[name].getAction().getActionBan() + else: + raise ServerUnknownJail(name) + + def setActionUnban(self, name, value): + if self.jails.has_key(name): + self.jails[name].getAction().setActionUnban(value) + else: + raise ServerUnknownJail(name) + + def getActionUnban(self, name): + if self.jails.has_key(name): + return self.jails[name].getAction().getActionUnban() + else: + raise ServerUnknownJail(name) + + # Status + def status(self): + jailList = '' + for jail in self.jails: + jailList += jail + ', ' + length = len(jailList) + if not length == 0: + jailList = jailList[:length-2] + ret = [("Number of jail", len(self.jails)), + ("Jail list", jailList)] + return ret + + def statusJail(self, name): + if self.jails.has_key(name): + return self.jails[name].getStatus() + raise ServerUnknownJail(name) + + # Logging + + ## + # Set the logging level. + # + # Incrementing the value gives more messages. + # 0 = FATAL + # 1 = ERROR + # 2 = WARNING + # 3 = INFO + # 4 = DEBUG + # @param value the level + + def setLogLevel(self, value): + self.logLevel = value + logLevel = logging.DEBUG + if value == 0: + logLevel = logging.FATAL + elif value == 1: + logLevel = logging.ERROR + elif value == 2: + logLevel = logging.WARNING + elif value == 3: + logLevel = logging.INFO + logging.getLogger("fail2ban").setLevel(logLevel) + + ## + # Get the logging level. + # + # @see setLogLevel + # @return the log level + + def getLogLevel(self): + return self.logLevel + +class ServerUnknownJail(Exception): + pass
\ No newline at end of file diff --git a/server/ssocket.py b/server/ssocket.py new file mode 100644 index 00000000..2c3fcf0a --- /dev/null +++ b/server/ssocket.py @@ -0,0 +1,103 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from threading import Thread +import socket, time, logging, pickle, os, os.path + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.comm") + +class SSocket(Thread): + + def __init__(self, transmitter): + Thread.__init__(self) + self.socketFile = "/tmp/fail2ban.sock" + self.transmit = transmitter + self.isRunning = False + logSys.debug("Created SSocket") + + def initialize(self): + # Remove socket + if os.path.exists(self.socketFile): + os.remove(self.socketFile) + # Create an INET, STREAMing socket + #self.ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.ssock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + #self.ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.ssock.setblocking(False) + # Bind the socket to a public host and a well-known port + #self.ssock.bind(("localhost", 2222)) + self.ssock.bind(self.socketFile) + # Become a server socket + self.ssock.listen(1) + + def run(self): + self.isRunning = True + stime = 1.0 + while self.isRunning: + try: + # Accept connections from outside + (csock, address) = self.ssock.accept() + stime /= 10 + logSys.debug("Connection accepted") + msg = self.receive(csock) + msg = self.transmit.proceed(msg) + self.send(csock, msg) + csock.close() + except Exception: + time.sleep(stime) + stime += 0.05 + if stime > 1.0: + stime = 1.0 + self.ssock.close() + # Remove socket + if os.path.exists(self.socketFile): + logSys.debug("Removed socket file " + self.socketFile) + os.remove(self.socketFile) + logSys.debug("Socket shutdown") + return True + + ## + # Stop the thread. + # + # Set the isRunning flag to False. + # @bug It seems to be some concurrency problem with this flag + + def stop(self): + self.isRunning = False + + def send(self, socket, msg): + obj = pickle.dumps(msg) + socket.send(obj + "<F2B_END_COMMAND>") + + def receive(self, socket): + msg = '' + while msg.rfind("<F2B_END_COMMAND>") == -1: + chunk = socket.recv(6) + if chunk == '': + raise RuntimeError, "socket connection broken" + msg = msg + chunk + return pickle.loads(msg) diff --git a/server/ticket.py b/server/ticket.py new file mode 100644 index 00000000..511f4769 --- /dev/null +++ b/server/ticket.py @@ -0,0 +1,49 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import time, logging + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban") + +class Ticket: + + def __init__(self, ip, time): + self.ip = ip + self.time = time + + def setIP(self, value): + self.ip = value + + def getIP(self): + return self.ip + + def setTime(self, value): + self.time = value + + def getTime(self): + return self.time +
\ No newline at end of file diff --git a/server/transmitter.py b/server/transmitter.py new file mode 100644 index 00000000..a3de9a23 --- /dev/null +++ b/server/transmitter.py @@ -0,0 +1,182 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +from ssocket import SSocket +import re, pickle, logging + +# Gets the instance of the logger. +logSys = logging.getLogger("fail2ban.comm") + +class Transmitter: + + def __init__(self, server): + self.server = server + self.socket = SSocket(self) + + def start(self): + self.socket.initialize() + self.socket.start() + + ## + # Stop the transmitter. + # + # @bug Fix the issue with join(). When using servertestcase.py, errors + # happen which disappear when using join() in this function. + + def stop(self): + self.socket.stop() + #self.socket.join() + + def proceed(self, action): + # Deserialize object + logSys.debug("Action: " + `action`) + try: + ret = self.actionHandler(action) + ack = 0, ret + except Exception, e: + logSys.warn("Invalid command") + ack = 1, e + return ack + + ## + # Handle an action. + # + # + + def actionHandler(self, action): + if action[0] == "ping": + return "pong" + elif action[0] == "add": + name = action[1] + self.server.addJail(name) + return name + elif action[0] == "start": + name = action[1] + self.server.startJail(name) + return None + elif action[0] == "stop": + name = action[1] + self.server.stopJail(name) + return None + elif action[0] == "sleep": + value = action[1] + time.sleep(int(value)) + return None + elif action[0] == "set": + return self.actionSet(action[1:]) + elif action[0] == "get": + return self.actionGet(action[1:]) + elif action[0] == "status": + return self.status(action[1:]) + elif action[0] == "quit": + self.server.quit() + return None + raise Exception("Invalid command") + + def actionSet(self, action): + name = action[0] + # Logging + if name == "loglevel": + value = int(action[1]) + self.server.setLogLevel(value) + return self.server.getLogLevel() + # Jail + if action[1] == "idle": + if action[2] == "on": + self.server.setIdleJail(name, True) + elif action[2] == "off": + self.server.setIdleJail(name, False) + return self.server.getIdleJail(name) + # Filter + elif action[1] == "logpath": + value = action[2] + self.server.setLogPath(name, value) + return self.server.getLogPath(name) + elif action[1] == "timeregex": + value = action[2] + self.server.setTimeRegex(name, value) + return self.server.getTimeRegex(name) + elif action[1] == "timepattern": + value = action[2] + self.server.setTimePattern(name, value) + return self.server.getTimePattern(name) + elif action[1] == "failregex": + value = action[2] + self.server.setFailRegex(name, value) + return self.server.getFailRegex(name) + elif action[1] == "maxtime": + value = action[2] + self.server.setMaxTime(name, int(value)) + return self.server.getMaxTime(name) + elif action[1] == "maxretry": + value = action[2] + self.server.setMaxRetry(name, int(value)) + return self.server.getMaxRetry(name) + # Action + elif action[1] == "bantime": + value = action[2] + self.server.setBanTime(name, int(value)) + return self.server.getBanTime(name) + elif action[1] == "actionstart": + value = action[2] + self.server.setActionStart(name, value) + return self.server.getActionStart(name) + elif action[1] == "actionstop": + value = action[2] + self.server.setActionStop(name, value) + return self.server.getActionStop(name) + elif action[1] == "actioncheck": + value = action[2] + self.server.setActionCheck(name, value) + return self.server.getActionCheck(name) + elif action[1] == "actionban": + value = action[2] + self.server.setActionBan(name, value) + return self.server.getActionBan(name) + elif action[1] == "actionunban": + value = action[2] + self.server.setActionUnban(name, value) + return self.server.getActionUnban(name) + raise Exception("Invalid command (no set action)") + + def actionGet(self, action): + name = action[0] + # Logging + if name == "loglevel": + return self.server.getLogLevel() + # Filter + if action[1] == "logpath": + return self.server.getLogPath(name) + raise Exception("Invalid command (no get action)") + + def status(self, action): + if len(action) == 0: + return self.server.status() + else: + name = action[0] + return self.server.statusJail(name) + raise Exception("Invalid command (no status)") +
\ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index fba97f88..00000000 --- a/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[install] -install-purelib=/usr/lib/fail2ban - -[sdist] -formats=bztar diff --git a/setup.py b/setup.py deleted file mode 100755 index 99b7f024..00000000 --- a/setup.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# This file is part of Fail2Ban. -# -# Fail2Ban is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Fail2Ban is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Fail2Ban; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -# Author: Cyril Jaquier -# -# $Revision$ - -__author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" -__copyright__ = "Copyright (c) 2004 Cyril Jaquier" -__license__ = "GPL" - -from distutils.core import setup -from version import version -from os.path import isfile, join -from sys import exit, argv - -longdesc = ''' -Fail2Ban scans log files like /var/log/pwdfail or -/var/log/apache/error_log and bans IP that makes -too many password failures. It updates firewall rules -to reject the IP address or executes user defined -commands.''' - -setup( - name = "fail2ban", - version = version, - description = "Ban IPs that make too many password failure", - long_description = longdesc, - author = "Cyril Jaquier", - author_email = "lostcontrol@users.sourceforge.net", - url = "http://fail2ban.sourceforge.net", - license = "GPL", - platforms = "Posix", - scripts = ['fail2ban'], - py_modules = ['fail2ban', 'version'], - packages = ['firewall', 'logreader', 'confreader', 'utils'] -) - -# Do some checks after installation -# Search for obsolete files. -obsoleteFiles = [] -elements = {"/usr/bin/": ["fail2ban.py"], - "/usr/lib/fail2ban/firewall/": ["iptables.py", "ipfwadm.py", - "ipfw.py"]} -for dir in elements: - for f in elements[dir]: - path = join(dir, f) - if isfile(path): - obsoleteFiles.append(path) -if obsoleteFiles: - print - print "Obsolete files from previous Fail2Ban versions were found on " \ - "your system." - print "Please delete them:" - print - for f in obsoleteFiles: - print "\t" + f - print - -# Update config file -if argv[1] == "install": - print - print "Please do not forget to update your configuration file." - print "Use config/fail2ban.conf.* as example." - print diff --git a/firewall/__init__.py b/testcases/__init__.py index 76dba873..60ef5531 100644 --- a/firewall/__init__.py +++ b/testcases/__init__.py @@ -16,10 +16,10 @@ # Author: Cyril Jaquier # -# $Revision$ +# $Revision: 1.1 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision$" -__date__ = "$Date$" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL"
\ No newline at end of file diff --git a/testcases/banmanagertestcase.py b/testcases/banmanagertestcase.py new file mode 100644 index 00000000..8fcedfbb --- /dev/null +++ b/testcases/banmanagertestcase.py @@ -0,0 +1,56 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import unittest, socket, time, pickle +from server.banmanager import BanManager +from server.banticket import BanTicket + +class AddFailure(unittest.TestCase): + + def setUp(self): + """Call before every test case.""" + self.ticket = BanTicket('193.168.0.128', 1167605999.0) + self.banManager = BanManager() + self.assertTrue(self.banManager.addBanTicket(self.ticket)) + + def tearDown(self): + """Call after every test case.""" + + def testAdd(self): + self.assertEqual(self.banManager.size(), 1) + + def testAddDuplicate(self): + self.assertFalse(self.banManager.addBanTicket(self.ticket)) + self.assertEqual(self.banManager.size(), 1) + + def testInListOK(self): + ticket = BanTicket('193.168.0.128', 1167605999.0) + self.assertTrue(self.banManager.inBanList(ticket)) + + def testInListNOK(self): + ticket = BanTicket('111.111.1.111', 1167605999.0) + self.assertFalse(self.banManager.inBanList(ticket)) +
\ No newline at end of file diff --git a/testcases/failmanagertestcase.py b/testcases/failmanagertestcase.py new file mode 100644 index 00000000..24d82bd5 --- /dev/null +++ b/testcases/failmanagertestcase.py @@ -0,0 +1,79 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import unittest, socket, time, pickle +from server.failmanager import FailManager +from server.failmanager import FailManagerEmpty +from server.failticket import FailTicket + +class AddFailure(unittest.TestCase): + + def setUp(self): + """Call before every test case.""" + self.items = [['193.168.0.128', 1167605999.0], + ['193.168.0.128', 1167605999.0], + ['193.168.0.128', 1167605999.0], + ['193.168.0.128', 1167605999.0], + ['193.168.0.128', 1167605999.0], + ['87.142.124.10', 1167605999.0], + ['87.142.124.10', 1167605999.0], + ['87.142.124.10', 1167605999.0]] + + self.failManager = FailManager() + for i in self.items: + self.failManager.addFailure(FailTicket(i[0], i[1])) + + def tearDown(self): + """Call after every test case.""" + + def testAdd(self): + self.assertEqual(self.failManager.size(), 2) + + def testDel(self): + self.failManager.delFailure('193.168.0.128') + self.failManager.delFailure('111.111.1.111') + + self.assertEqual(self.failManager.size(), 1) + + def testCleanupOK(self): + timestamp = 1167606999.0 + self.failManager.cleanup(timestamp) + self.assertEqual(self.failManager.size(), 0) + + def testCleanupNOK(self): + timestamp = 1167605990.0 + self.failManager.cleanup(timestamp) + self.assertEqual(self.failManager.size(), 2) + + def testbanOK(self): + self.failManager.setMaxRetry(5) + #ticket = FailTicket('193.168.0.128', None) + ticket = self.failManager.toBan() + self.assertEqual(ticket.getIP(), "193.168.0.128") + + def testbanNOK(self): + self.failManager.setMaxRetry(10) + self.assertRaises(FailManagerEmpty, self.failManager.toBan) diff --git a/testcases/files/testcase01.log b/testcases/files/testcase01.log new file mode 100644 index 00000000..43143d0b --- /dev/null +++ b/testcases/files/testcase01.log @@ -0,0 +1,18 @@ +Déc 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Déc 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Déc 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from failed.dns.ch +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from failed.dns.ch +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from failed.dns.ch +Dez 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Dez 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Dez 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +De 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +De 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +De 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128 +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 87.142.124.10 +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 87.142.124.10 +Dec 31 23:59:59 [sshd] error: PAM: Authentication failure for kevin from 87.142.124.10 diff --git a/testcases/files/testcase02.log b/testcases/files/testcase02.log new file mode 100644 index 00000000..547f8a53 --- /dev/null +++ b/testcases/files/testcase02.log @@ -0,0 +1,10 @@ +Mar 16 04:57:00 i60p295 sshd[11437]: input_userauth_request: illegal user test123 +Mar 16 04:57:00 i60p295 sshd[11437]: Failed password for illegal user test123 from ::ffff:66.38.192.238 port 51381 ssh2 +Mar 16 04:57:00 i60p295 sshd[11437]: Connection closed by ::ffff:66.38.192.238 +Mar 16 10:33:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2 +Mar 16 10:33:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2 +Mar 16 10:33:59 i60p295 sshd[12365]: Postponed keyboard-interactive for roehl from ::ffff:141.3.81.106 port 51332 ssh2 +Mar 16 10:34:01 i60p295 sshd[12365]: Postponed keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2 +Mar 16 10:34:01 i60p295 sshd[12365]: Accepted keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2 +Mär 16 10:33:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2 +Mär 16 10:33:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2 diff --git a/testcases/filtertestcase.py b/testcases/filtertestcase.py new file mode 100644 index 00000000..5465400c --- /dev/null +++ b/testcases/filtertestcase.py @@ -0,0 +1,98 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import unittest, socket +from server.filter import Filter +from server.failmanager import FailManager + +class IgnoreIP(unittest.TestCase): + + def setUp(self): + """Call before every test case.""" + self.filter = Filter(None) + + def tearDown(self): + """Call after every test case.""" + + def testIgnoreIPOK(self): + ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99" + for ip in ipList: + self.filter.addIgnoreIP(ip) + self.assertTrue(self.filter.inIgnoreIPList(ip)) + + def testIgnoreIPNOK(self): + ipList = "", "999.999.999.999", "abcdef", "192.168.0" + for ip in ipList: + self.filter.addIgnoreIP(ip) + self.assertFalse(self.filter.inIgnoreIPList(ip)) + + +class LogFile(unittest.TestCase): + + def setUp(self): + """Call before every test case.""" + self.filter = Filter(None) + self.filter.setLogPath("testcases/files/testcase01.log") + + def tearDown(self): + """Call after every test case.""" + + def testOpen(self): + self.filter.openLogFile() + + def testIsModified(self): + self.filter.openLogFile() + self.assertTrue(self.filter.isModified()) + + +class GetFailures(unittest.TestCase): + + def setUp(self): + """Call before every test case.""" + self.filter = Filter(None) + self.filter.setLogPath("testcases/files/testcase01.log") + self.filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}") + self.filter.setTimePattern("%b %d %H:%M:%S") + self.filter.setFailRegex("Authentication failure") + + def tearDown(self): + """Call after every test case.""" + + def testGetFailures(self): + output = [('87.142.124.10', 3, 1167605999.0), + ('193.168.0.128', 3, 1167605999.0)] + + self.filter.openLogFile() + self.filter.getFailures() + + found = [] + for ip in self.filter.failManager.failList: + fData = self.filter.failManager.failList[ip] + retry = fData.getRetry() + lTime = fData.getLastTime() + found.append((ip, retry, lTime)) + self.assertEqual(found, output) +
\ No newline at end of file diff --git a/testcases/servertestcase.py b/testcases/servertestcase.py new file mode 100644 index 00000000..34e60537 --- /dev/null +++ b/testcases/servertestcase.py @@ -0,0 +1,127 @@ +# This file is part of Fail2Ban. +# +# Fail2Ban is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Fail2Ban is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Fail2Ban; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Author: Cyril Jaquier +# +# $Revision: 1.1 $ + +__author__ = "Cyril Jaquier" +__version__ = "$Revision: 1.1 $" +__date__ = "$Date: 2004/10/10 13:33:40 $" +__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +__license__ = "GPL" + +import unittest, socket, time +from server.server import Server + +class StartStop(unittest.TestCase): + + def setUp(self): + """Call before every test case.""" + self.server = Server() + self.server.setLogLevel(0) + self.server.start() + + def tearDown(self): + """Call after every test case.""" + self.server.quit() + + def testStartStopJail(self): + name = "TestCase" + self.server.addJail(name) + self.server.startJail(name) + time.sleep(1) + self.server.stopJail(name) + + +class Transmitter(unittest.TestCase): + + def setUp(self): + """Call before every test case.""" + self.server = Server() + self.server.setLogLevel(0) + self.server.start() + + def tearDown(self): + """Call after every test case.""" + self.server.quit() + + def testSetActionOK(self): + name = "TestCase" + cmdList = [["add", name], + ["set", name, "actionstart", "Action Start"], + ["set", name, "actionstop", "Action Stop"], + ["set", name, "actioncheck", "Action Check"], + ["set", name, "actionban", "Action Ban"], + ["set", name, "actionunban", "Action Unban"], + ["quit"]] + + outList = [(0, name), + (0, 'Action Start'), + (0, 'Action Stop'), + (0, 'Action Check'), + (0, 'Action Ban'), + (0, 'Action Unban'), + (0, None)] + + cnt = 0 + for cmd in cmdList: + self.assertEqual(self.server.transm.proceed(cmd), outList[cnt]) + cnt += 1 + + def testSetActionNOK(self): + name = "TestCase" + cmdList = [["addd", name], + ["set", name, "test"], + ["prout prout", "Stop"], + ["fail2ban", "sucks"], + ["set"], + ["_/&%", "@*+%&"], + [" quit"]] + + outList = [1, + 1, + 1, + 1, + 1, + 1, + 1] + + cnt = 0 + for cmd in cmdList: + msg = self.server.transm.proceed(cmd) + self.assertEqual(msg[0], outList[cnt]) + cnt += 1 + + def testJail(self): + name = "TestCase" + cmdList = [["add", name], + ["set", name, "logpath", "testcases/files/testcase01.log"], + ["set", name, "timeregex", "\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}"], + ["set", name, "timepattern", "%b %d %H:%M:%S"], + ["set", name, "failregex", "Authentication failure"], + ["start", name], + ["stop", name], + ["quit"]] + + for cmd in cmdList: + self.server.transm.proceed(cmd) + if cmd == ["start", name]: + time.sleep(2) + jail = self.server.jails[name] + self.assertEqual(jail.getFilter().failManager.size(), 0) + self.assertEqual(jail.getAction().banManager.size(), 2) +
\ No newline at end of file diff --git a/utils/process.py b/utils/process.py index b310f090..cf6aafcd 100644 --- a/utils/process.py +++ b/utils/process.py @@ -51,8 +51,8 @@ def createDaemon(): pid = os.fork() except OSError, e: return((e.errno, e.strerror)) # ERROR (return a tuple) - - if (pid == 0): # The first child. + + if pid == 0: # The first child. # Next we call os.setsid() to become the session leader of this new # session. The process also becomes the process group leader of the @@ -85,7 +85,7 @@ def createDaemon(): os._exit(0) # Exit parent (the first child) of the second child. else: os._exit(0) # Exit parent of the first child. - + # Close all open files. Try the system configuration variable, SC_OPEN_MAX, # for the maximum number of open files to close. If it doesn't exist, use # the default value (configurable). @@ -104,34 +104,5 @@ def createDaemon(): os.open("/dev/null", os.O_RDONLY) # standard input (0) os.open("/dev/null", os.O_RDWR) # standard output (1) os.open("/dev/null", os.O_RDWR) # standard error (2) - - return True - -def killPID(pid): - """ Kills the process with the given PID using the - INT signal (same effect as <ctrl>+<c>). - """ - try: - return os.kill(pid, 2) - except OSError: - logSys.error("Can not kill process " + `pid` + ". Please check that " + - "Fail2Ban is not running and remove the file " + - "'/tmp/fail2ban.pid'") - return False - -def executeCmd(cmd, debug): - """ Executes an OS command. - """ - if cmd == "": - logSys.debug("Nothing to do") - return None - logSys.debug(cmd) - if not debug: - retval = os.system(cmd) - if not retval == 0: - logSys.error("'" + cmd + "' returned " + `retval`) - raise ExternalError("Execution of command '%s' failed" % cmd) - return retval - else: - return None + return True |