summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyril Jaquier <cyril.jaquier@fail2ban.org>2006-06-26 20:05:00 +0000
committerCyril Jaquier <cyril.jaquier@fail2ban.org>2006-06-26 20:05:00 +0000
commitea1948eff40953b4590858698ced9f6b4c3733f8 (patch)
treee667d2906e70b34fe233c3409cb9052e4a77fe6a
parent97aa913e243eacb8b93610d4ef6954d89c01a5eb (diff)
downloadfail2ban-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
-rw-r--r--TODO97
-rw-r--r--client/__init__.py (renamed from confreader/__init__.py)6
-rw-r--r--client/actionreader.py80
-rw-r--r--client/configreader.py (renamed from confreader/configreader.py)79
-rw-r--r--client/configurator.py68
-rw-r--r--client/csocket.py54
-rw-r--r--client/fail2banreader.py51
-rw-r--r--client/filterreader.py80
-rw-r--r--client/jailreader.py84
-rw-r--r--client/jailsreader.py73
-rw-r--r--config/action.d/dummy.conf52
-rw-r--r--config/action.d/iptables.conf55
-rw-r--r--config/debian-initd73
-rw-r--r--config/fail2ban.conf4
-rw-r--r--config/fail2ban.conf.hostsdeny327
-rw-r--r--config/fail2ban.conf.iptables362
-rw-r--r--config/fail2ban.conf.shorewall314
-rw-r--r--config/fail2ban.local4
-rw-r--r--config/filter.d/apache-auth.conf0
-rw-r--r--config/filter.d/sshd.conf32
-rw-r--r--config/gentoo-confd23
-rwxr-xr-xconfig/gentoo-initd50
-rw-r--r--config/jail.conf21
-rw-r--r--config/redhat-initd78
-rw-r--r--doc/Doxyfile1237
-rwxr-xr-xfail2ban75
-rwxr-xr-xfail2ban-client236
-rwxr-xr-xfail2ban-server122
-rwxr-xr-xfail2ban-testcases61
-rwxr-xr-xfail2ban.py542
-rw-r--r--firewall/firewall.py192
-rwxr-xr-xkill-server2
-rw-r--r--log-test/apache108
-rw-r--r--log-test/current11
-rw-r--r--log-test/test432
-rw-r--r--logreader/logreader.py225
-rw-r--r--man/fail2ban.858
-rw-r--r--man/fail2ban.conf.520
-rw-r--r--server/__init__.py (renamed from logreader/__init__.py)6
-rw-r--r--server/action.py281
-rw-r--r--server/banmanager.py184
-rw-r--r--server/banticket.py50
-rw-r--r--server/faildata.py53
-rw-r--r--server/failmanager.py106
-rw-r--r--server/failticket.py (renamed from version.py)18
-rw-r--r--server/filter.py452
-rw-r--r--server/jail.py95
-rw-r--r--server/jailthread.py114
-rw-r--r--server/server.py291
-rw-r--r--server/ssocket.py103
-rw-r--r--server/ticket.py49
-rw-r--r--server/transmitter.py182
-rw-r--r--setup.cfg5
-rwxr-xr-xsetup.py82
-rw-r--r--testcases/__init__.py (renamed from firewall/__init__.py)6
-rw-r--r--testcases/banmanagertestcase.py56
-rw-r--r--testcases/failmanagertestcase.py79
-rw-r--r--testcases/files/testcase01.log18
-rw-r--r--testcases/files/testcase02.log10
-rw-r--r--testcases/filtertestcase.py98
-rw-r--r--testcases/servertestcase.py127
-rw-r--r--utils/process.py37
62 files changed, 4734 insertions, 3156 deletions
diff --git a/TODO b/TODO
index 5e7b6347..7c388e85 100644
--- a/TODO
+++ b/TODO
@@ -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