mirror of https://github.com/fail2ban/fail2ban
- Overwrote head with some of 0.8.
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@686 a942ae1a-1317-0410-a47c-b1dcaea8d6050.x
parent
cc57497f5b
commit
b070dc89aa
27
MANIFEST
27
MANIFEST
|
@ -1,5 +1,5 @@
|
||||||
README
|
README
|
||||||
CHANGELOG
|
ChangeLog
|
||||||
TODO
|
TODO
|
||||||
COPYING
|
COPYING
|
||||||
fail2ban-client
|
fail2ban-client
|
||||||
|
@ -7,6 +7,7 @@ fail2ban-server
|
||||||
fail2ban-testcases
|
fail2ban-testcases
|
||||||
fail2ban-regex
|
fail2ban-regex
|
||||||
client/configreader.py
|
client/configreader.py
|
||||||
|
client/configparserinc.py
|
||||||
client/jailreader.py
|
client/jailreader.py
|
||||||
client/fail2banreader.py
|
client/fail2banreader.py
|
||||||
client/jailsreader.py
|
client/jailsreader.py
|
||||||
|
@ -16,15 +17,12 @@ client/actionreader.py
|
||||||
client/__init__.py
|
client/__init__.py
|
||||||
client/configurator.py
|
client/configurator.py
|
||||||
client/csocket.py
|
client/csocket.py
|
||||||
server/banticket.py
|
server/asyncserver.py
|
||||||
server/filter.py
|
server/filter.py
|
||||||
server/filtergamin.py
|
server/filtergamin.py
|
||||||
server/filterpoll.py
|
server/filterpoll.py
|
||||||
server/server.py
|
server/server.py
|
||||||
server/datestrptime.py
|
|
||||||
server/failticket.py
|
|
||||||
server/actions.py
|
server/actions.py
|
||||||
server/datetai64n.py
|
|
||||||
server/faildata.py
|
server/faildata.py
|
||||||
server/failmanager.py
|
server/failmanager.py
|
||||||
server/datedetector.py
|
server/datedetector.py
|
||||||
|
@ -35,14 +33,10 @@ server/ticket.py
|
||||||
server/jail.py
|
server/jail.py
|
||||||
server/jails.py
|
server/jails.py
|
||||||
server/__init__.py
|
server/__init__.py
|
||||||
server/dateepoch.py
|
|
||||||
server/banmanager.py
|
server/banmanager.py
|
||||||
server/datetemplate.py
|
server/datetemplate.py
|
||||||
server/mytime.py
|
server/mytime.py
|
||||||
server/regex.py
|
|
||||||
server/failregex.py
|
server/failregex.py
|
||||||
server/communication/__init__.py
|
|
||||||
server/communication/asyncserver.py
|
|
||||||
testcases/banmanagertestcase.py
|
testcases/banmanagertestcase.py
|
||||||
testcases/failmanagertestcase.py
|
testcases/failmanagertestcase.py
|
||||||
testcases/clientreadertestcase.py
|
testcases/clientreadertestcase.py
|
||||||
|
@ -61,30 +55,43 @@ common/__init__.py
|
||||||
common/version.py
|
common/version.py
|
||||||
common/protocol.py
|
common/protocol.py
|
||||||
config/jail.conf
|
config/jail.conf
|
||||||
|
config/filter.d/common.conf
|
||||||
config/filter.d/apache-auth.conf
|
config/filter.d/apache-auth.conf
|
||||||
config/filter.d/apache-badbots.conf
|
config/filter.d/apache-badbots.conf
|
||||||
config/filter.d/apache-noscript.conf
|
config/filter.d/apache-noscript.conf
|
||||||
|
config/filter.d/apache-overflows.conf
|
||||||
config/filter.d/courierlogin.conf
|
config/filter.d/courierlogin.conf
|
||||||
config/filter.d/couriersmtp.conf
|
config/filter.d/couriersmtp.conf
|
||||||
config/filter.d/exim.conf
|
config/filter.d/exim.conf
|
||||||
|
config/filter.d/gssftpd.conf
|
||||||
|
config/filter.d/named-refused.conf
|
||||||
config/filter.d/postfix.conf
|
config/filter.d/postfix.conf
|
||||||
config/filter.d/proftpd.conf
|
config/filter.d/proftpd.conf
|
||||||
config/filter.d/pure-ftpd.conf
|
config/filter.d/pure-ftpd.conf
|
||||||
config/filter.d/qmail.conf
|
config/filter.d/qmail.conf
|
||||||
|
config/filter.d/pam-generic.conf
|
||||||
config/filter.d/sasl.conf
|
config/filter.d/sasl.conf
|
||||||
config/filter.d/sshd.conf
|
config/filter.d/sshd.conf
|
||||||
config/filter.d/sshd-ddos.conf
|
config/filter.d/sshd-ddos.conf
|
||||||
config/filter.d/vsftpd.conf
|
config/filter.d/vsftpd.conf
|
||||||
|
config/filter.d/webmin-auth.conf
|
||||||
config/filter.d/wuftpd.conf
|
config/filter.d/wuftpd.conf
|
||||||
|
config/filter.d/xinetd-fail.conf
|
||||||
config/action.d/hostsdeny.conf
|
config/action.d/hostsdeny.conf
|
||||||
config/action.d/ipfw.conf
|
config/action.d/ipfw.conf
|
||||||
config/action.d/iptables.conf
|
config/action.d/iptables.conf
|
||||||
|
config/action.d/iptables-allports.conf
|
||||||
config/action.d/iptables-multiport.conf
|
config/action.d/iptables-multiport.conf
|
||||||
|
config/action.d/iptables-multiport-log.conf
|
||||||
config/action.d/iptables-new.conf
|
config/action.d/iptables-new.conf
|
||||||
config/action.d/mail.conf
|
config/action.d/mail.conf
|
||||||
config/action.d/mail-buffered.conf
|
config/action.d/mail-buffered.conf
|
||||||
config/action.d/mail-whois.conf
|
config/action.d/mail-whois.conf
|
||||||
config/action.d/mail-whois-lines.conf
|
config/action.d/mail-whois-lines.conf
|
||||||
|
config/action.d/sendmail.conf
|
||||||
|
config/action.d/sendmail-buffered.conf
|
||||||
|
config/action.d/sendmail-whois.conf
|
||||||
|
config/action.d/sendmail-whois-lines.conf
|
||||||
config/action.d/shorewall.conf
|
config/action.d/shorewall.conf
|
||||||
config/fail2ban.conf
|
config/fail2ban.conf
|
||||||
man/fail2ban-client.1
|
man/fail2ban-client.1
|
||||||
|
@ -97,8 +104,10 @@ man/generate-man
|
||||||
files/gentoo-initd
|
files/gentoo-initd
|
||||||
files/gentoo-confd
|
files/gentoo-confd
|
||||||
files/redhat-initd
|
files/redhat-initd
|
||||||
|
files/macosx-initd
|
||||||
files/solaris-fail2ban.xml
|
files/solaris-fail2ban.xml
|
||||||
files/solaris-svc-fail2ban
|
files/solaris-svc-fail2ban
|
||||||
|
files/suse-initd
|
||||||
files/cacti/fail2ban_stats.sh
|
files/cacti/fail2ban_stats.sh
|
||||||
files/cacti/cacti_host_template_fail2ban.xml
|
files/cacti/cacti_host_template_fail2ban.xml
|
||||||
files/cacti/README
|
files/cacti/README
|
||||||
|
|
15
README
15
README
|
@ -4,7 +4,7 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
=============================================================
|
=============================================================
|
||||||
Fail2Ban (version 0.8.0) 2007/05/03
|
Fail2Ban (version 0.8.3) 2008/??/??
|
||||||
=============================================================
|
=============================================================
|
||||||
|
|
||||||
Fail2Ban scans log files like /var/log/pwdfail and bans IP
|
Fail2Ban scans log files like /var/log/pwdfail and bans IP
|
||||||
|
@ -21,15 +21,15 @@ Installation:
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
>=python-2.4 (http://www.python.org)
|
>=python-2.3 (http://www.python.org)
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
>=gamin-0.0.21 (http://www.gnome.org/~veillard/gamin)
|
>=gamin-0.0.21 (http://www.gnome.org/~veillard/gamin)
|
||||||
|
|
||||||
To install, just do:
|
To install, just do:
|
||||||
|
|
||||||
> tar xvfj fail2ban-0.8.0.tar.bz2
|
> tar xvfj fail2ban-0.8.3.tar.bz2
|
||||||
> cd fail2ban-0.8.0
|
> cd fail2ban-0.8.3
|
||||||
> python setup.py install
|
> python setup.py install
|
||||||
|
|
||||||
This will install Fail2Ban into /usr/share/fail2ban. The
|
This will install Fail2Ban into /usr/share/fail2ban. The
|
||||||
|
@ -62,7 +62,7 @@ appreciate this program, you can contact me at:
|
||||||
|
|
||||||
Website: http://www.fail2ban.org
|
Website: http://www.fail2ban.org
|
||||||
|
|
||||||
Cyril Jaquier: <lostcontrol@users.sourceforge.net>
|
Cyril Jaquier: <cyril.jaquier@fail2ban.org>
|
||||||
|
|
||||||
Thanks:
|
Thanks:
|
||||||
-------
|
-------
|
||||||
|
@ -73,7 +73,10 @@ Jonathan Kamens, Stephen Gildea, Markus Hoffmann, Mark
|
||||||
Edgington, Patrick Börjesson, kojiro, zugeschmiert, Tyler,
|
Edgington, Patrick Börjesson, kojiro, zugeschmiert, Tyler,
|
||||||
Nick Munger, Christoph Haas, Justin Shore, Joël Bertrand,
|
Nick Munger, Christoph Haas, Justin Shore, Joël Bertrand,
|
||||||
René Berber, mEDI, Axel Thimm, Eric Gerbier, Christian Rauch,
|
René Berber, mEDI, Axel Thimm, Eric Gerbier, Christian Rauch,
|
||||||
Michael C. Haller, Jonathan Underwood, Hanno 'Rince' Wagner
|
Michael C. Haller, Jonathan Underwood, Hanno 'Rince' Wagner,
|
||||||
|
Daniel B. Cid, David Nutter, Raphaël Marichez, Guillaume
|
||||||
|
Delvit, Vaclav Misek, Adrien Clerc, Michael Hanselmann,
|
||||||
|
Vincent Deffontaines, Bill Heaton and many others.
|
||||||
|
|
||||||
License:
|
License:
|
||||||
--------
|
--------
|
||||||
|
|
12
TODO
12
TODO
|
@ -13,16 +13,8 @@ Legend:
|
||||||
# partially done
|
# partially done
|
||||||
* done
|
* done
|
||||||
|
|
||||||
- <HOST> should not be mandatory. It should be possible to
|
|
||||||
start an action without an host
|
|
||||||
|
|
||||||
- Use Python 2.3
|
|
||||||
|
|
||||||
- Removed relative imports
|
- Removed relative imports
|
||||||
|
|
||||||
- Discuss where Fail2ban should be installed (/usr/share,
|
|
||||||
/usr/lib/python/site-packages/, etc)
|
|
||||||
|
|
||||||
- Cleanup fail2ban-client and fail2ban-server. Move code to
|
- Cleanup fail2ban-client and fail2ban-server. Move code to
|
||||||
server/ and client/
|
server/ and client/
|
||||||
|
|
||||||
|
@ -50,12 +42,8 @@ Legend:
|
||||||
|
|
||||||
- Add gettext support (I18N)
|
- Add gettext support (I18N)
|
||||||
|
|
||||||
- Fix the cPickle issue with Python 2.5
|
|
||||||
|
|
||||||
- Multiline log reading
|
- Multiline log reading
|
||||||
|
|
||||||
- Improve communication. (asyncore, asynchat??)
|
|
||||||
|
|
||||||
- Improve execution of action. Why does subprocess.call
|
- Improve execution of action. Why does subprocess.call
|
||||||
deadlock with multi-jails?
|
deadlock with multi-jails?
|
||||||
|
|
||||||
|
|
|
@ -72,9 +72,14 @@ class Beautifier:
|
||||||
ipList = ""
|
ipList = ""
|
||||||
for ip in response[1][1][2][1]:
|
for ip in response[1][1][2][1]:
|
||||||
ipList += ip + " "
|
ipList += ip + " "
|
||||||
|
# Creates file list.
|
||||||
|
fileList = ""
|
||||||
|
for f in response[0][1][2][1]:
|
||||||
|
fileList += f + " "
|
||||||
# Display information
|
# Display information
|
||||||
msg = "Status for the jail: " + inC[1] + "\n"
|
msg = "Status for the jail: " + inC[1] + "\n"
|
||||||
msg = msg + "|- " + response[0][0] + "\n"
|
msg = msg + "|- " + response[0][0] + "\n"
|
||||||
|
msg = msg + "| |- " + response[0][1][2][0] + ":\t" + fileList + "\n"
|
||||||
msg = msg + "| |- " + response[0][1][0][0] + ":\t" + `response[0][1][0][1]` + "\n"
|
msg = msg + "| |- " + response[0][1][0][0] + ":\t" + `response[0][1][0][1]` + "\n"
|
||||||
msg = msg + "| `- " + response[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n"
|
msg = msg + "| `- " + response[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n"
|
||||||
msg = msg + "`- " + response[1][0] + "\n"
|
msg = msg + "`- " + response[1][0] + "\n"
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
# 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: Yaroslav Halchenko
|
||||||
|
# Modified: Cyril Jaquier
|
||||||
|
# $Revision: 656 $
|
||||||
|
|
||||||
|
__author__ = 'Yaroslav Halhenko'
|
||||||
|
__revision__ = '$Revision: $'
|
||||||
|
__date__ = '$Date: $'
|
||||||
|
__copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko'
|
||||||
|
__license__ = 'GPL'
|
||||||
|
|
||||||
|
import logging, os
|
||||||
|
from ConfigParser import SafeConfigParser
|
||||||
|
|
||||||
|
# Gets the instance of the logger.
|
||||||
|
logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
|
class SafeConfigParserWithIncludes(SafeConfigParser):
|
||||||
|
"""
|
||||||
|
Class adds functionality to SafeConfigParser to handle included
|
||||||
|
other configuration files (or may be urls, whatever in the future)
|
||||||
|
|
||||||
|
File should have section [includes] and only 2 options implemented
|
||||||
|
are 'files_before' and 'files_after' where files are listed 1 per
|
||||||
|
line.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
before = 1.conf
|
||||||
|
3.conf
|
||||||
|
|
||||||
|
after = 1.conf
|
||||||
|
|
||||||
|
It is a simple implementation, so just basic care is taken about
|
||||||
|
recursion. Includes preserve right order, ie new files are
|
||||||
|
inserted to the list of read configs before original, and their
|
||||||
|
includes correspondingly so the list should follow the leaves of
|
||||||
|
the tree.
|
||||||
|
|
||||||
|
I wasn't sure what would be the right way to implement generic (aka c++
|
||||||
|
template) so we could base at any *configparser class... so I will
|
||||||
|
leave it for the future
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
SECTION_NAME = "INCLUDES"
|
||||||
|
|
||||||
|
#@staticmethod
|
||||||
|
def getIncludes(resource, seen = []):
|
||||||
|
"""
|
||||||
|
Given 1 config resource returns list of included files
|
||||||
|
(recursively) with the original one as well
|
||||||
|
Simple loops are taken care about
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Use a short class name ;)
|
||||||
|
SCPWI = SafeConfigParserWithIncludes
|
||||||
|
|
||||||
|
parser = SafeConfigParser()
|
||||||
|
parser.read(resource)
|
||||||
|
|
||||||
|
resourceDir = os.path.dirname(resource)
|
||||||
|
|
||||||
|
newFiles = [ ('before', []), ('after', []) ]
|
||||||
|
if SCPWI.SECTION_NAME in parser.sections():
|
||||||
|
for option_name, option_list in newFiles:
|
||||||
|
if option_name in parser.options(SCPWI.SECTION_NAME):
|
||||||
|
newResources = parser.get(SCPWI.SECTION_NAME, option_name)
|
||||||
|
for newResource in newResources.split('\n'):
|
||||||
|
if os.path.isabs(newResource):
|
||||||
|
r = newResource
|
||||||
|
else:
|
||||||
|
r = "%s/%s" % (resourceDir, newResource)
|
||||||
|
if r in seen:
|
||||||
|
continue
|
||||||
|
s = seen + [resource]
|
||||||
|
option_list += SCPWI.getIncludes(r, s)
|
||||||
|
# combine lists
|
||||||
|
return newFiles[0][1] + [resource] + newFiles[1][1]
|
||||||
|
#print "Includes list for " + resource + " is " + `resources`
|
||||||
|
getIncludes = staticmethod(getIncludes)
|
||||||
|
|
||||||
|
|
||||||
|
def read(self, filenames):
|
||||||
|
fileNamesFull = []
|
||||||
|
if not isinstance(filenames, list):
|
||||||
|
filenames = [ filenames ]
|
||||||
|
for filename in filenames:
|
||||||
|
fileNamesFull += SafeConfigParserWithIncludes.getIncludes(filename)
|
||||||
|
logSys.debug("Reading files: %s" % fileNamesFull)
|
||||||
|
return SafeConfigParser.read(self, fileNamesFull)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
# Modified by: Yaroslav Halchenko (SafeConfigParserWithIncludes)
|
||||||
# $Revision$
|
# $Revision$
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
|
@ -25,18 +25,18 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import logging, os
|
import logging, os
|
||||||
from ConfigParser import SafeConfigParser
|
from configparserinc import SafeConfigParserWithIncludes
|
||||||
from ConfigParser import NoOptionError, NoSectionError
|
from ConfigParser import NoOptionError, NoSectionError
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
class ConfigReader(SafeConfigParser):
|
class ConfigReader(SafeConfigParserWithIncludes):
|
||||||
|
|
||||||
BASE_DIRECTORY = "/etc/fail2ban/"
|
BASE_DIRECTORY = "/etc/fail2ban/"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
SafeConfigParser.__init__(self)
|
SafeConfigParserWithIncludes.__init__(self)
|
||||||
self.__opts = None
|
self.__opts = None
|
||||||
|
|
||||||
#@staticmethod
|
#@staticmethod
|
||||||
|
@ -56,7 +56,7 @@ class ConfigReader(SafeConfigParser):
|
||||||
bConf = basename + ".conf"
|
bConf = basename + ".conf"
|
||||||
bLocal = basename + ".local"
|
bLocal = basename + ".local"
|
||||||
if os.path.exists(bConf) or os.path.exists(bLocal):
|
if os.path.exists(bConf) or os.path.exists(bLocal):
|
||||||
SafeConfigParser.read(self, [bConf, bLocal])
|
SafeConfigParserWithIncludes.read(self, [bConf, bLocal])
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logSys.error(bConf + " and " + bLocal + " do not exist")
|
logSys.error(bConf + " and " + bLocal + " do not exist")
|
||||||
|
|
|
@ -56,13 +56,13 @@ class Configurator:
|
||||||
def readAll(self):
|
def readAll(self):
|
||||||
self.readEarly()
|
self.readEarly()
|
||||||
self.__jails.read()
|
self.__jails.read()
|
||||||
|
|
||||||
def getEarlyOptions(self):
|
def getEarlyOptions(self):
|
||||||
return self.__fail2ban.getEarlyOptions()
|
return self.__fail2ban.getEarlyOptions()
|
||||||
|
|
||||||
def getAllOptions(self):
|
def getOptions(self, jail = None):
|
||||||
self.__fail2ban.getOptions()
|
self.__fail2ban.getOptions()
|
||||||
return self.__jails.getOptions()
|
return self.__jails.getOptions(jail)
|
||||||
|
|
||||||
def convertToProtocol(self):
|
def convertToProtocol(self):
|
||||||
self.__streams["general"] = self.__fail2ban.convert()
|
self.__streams["general"] = self.__fail2ban.convert()
|
||||||
|
|
|
@ -32,7 +32,7 @@ class CSocket:
|
||||||
|
|
||||||
END_STRING = "<F2B_END_COMMAND>"
|
END_STRING = "<F2B_END_COMMAND>"
|
||||||
|
|
||||||
def __init__(self, sock = "/tmp/fail2ban.sock"):
|
def __init__(self, sock = "/var/run/fail2ban/fail2ban.sock"):
|
||||||
# Create an INET, STREAMing socket
|
# Create an INET, STREAMing socket
|
||||||
#self.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
#self.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.__csock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
self.__csock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
|
|
@ -90,7 +90,7 @@ class JailReader(ConfigReader):
|
||||||
self.__actions.append(action)
|
self.__actions.append(action)
|
||||||
else:
|
else:
|
||||||
raise AttributeError("Unable to read action")
|
raise AttributeError("Unable to read action")
|
||||||
except AttributeError, e:
|
except Exception, e:
|
||||||
logSys.error("Error in action definition " + act)
|
logSys.error("Error in action definition " + act)
|
||||||
logSys.debug(e)
|
logSys.debug(e)
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -40,12 +40,13 @@ class JailsReader(ConfigReader):
|
||||||
def read(self):
|
def read(self):
|
||||||
ConfigReader.read(self, "jail")
|
ConfigReader.read(self, "jail")
|
||||||
|
|
||||||
def getOptions(self):
|
def getOptions(self, section = None):
|
||||||
opts = []
|
opts = []
|
||||||
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
|
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
|
||||||
|
|
||||||
for sec in self.sections():
|
if section:
|
||||||
jail = JailReader(sec)
|
# Get the options of a specific jail.
|
||||||
|
jail = JailReader(section)
|
||||||
jail.read()
|
jail.read()
|
||||||
ret = jail.getOptions()
|
ret = jail.getOptions()
|
||||||
if ret:
|
if ret:
|
||||||
|
@ -53,8 +54,21 @@ class JailsReader(ConfigReader):
|
||||||
# We only add enabled jails
|
# We only add enabled jails
|
||||||
self.__jails.append(jail)
|
self.__jails.append(jail)
|
||||||
else:
|
else:
|
||||||
logSys.error("Errors in jail '" + sec + "'. Skipping...")
|
logSys.error("Errors in jail '%s'. Skipping..." % section)
|
||||||
return False
|
return False
|
||||||
|
else:
|
||||||
|
# Get the options of all jails.
|
||||||
|
for sec in self.sections():
|
||||||
|
jail = JailReader(sec)
|
||||||
|
jail.read()
|
||||||
|
ret = jail.getOptions()
|
||||||
|
if ret:
|
||||||
|
if jail.isEnabled():
|
||||||
|
# We only add enabled jails
|
||||||
|
self.__jails.append(jail)
|
||||||
|
else:
|
||||||
|
logSys.error("Errors in jail '" + sec + "'. Skipping...")
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def convert(self):
|
def convert(self):
|
||||||
|
|
|
@ -33,6 +33,7 @@ protocol = [
|
||||||
['', "BASIC", ""],
|
['', "BASIC", ""],
|
||||||
["start", "starts the server and the jails"],
|
["start", "starts the server and the jails"],
|
||||||
["reload", "reloads the configuration"],
|
["reload", "reloads the configuration"],
|
||||||
|
["reload <JAIL>", "reloads the jail <JAIL>"],
|
||||||
["stop", "stops all jails and terminate the server"],
|
["stop", "stops all jails and terminate the server"],
|
||||||
["status", "gets the current status of the server"],
|
["status", "gets the current status of the server"],
|
||||||
["ping", "tests if the server is alive"],
|
["ping", "tests if the server is alive"],
|
||||||
|
@ -51,9 +52,7 @@ protocol = [
|
||||||
["set <JAIL> addignoreip <IP>", "adds <IP> to the ignore list of <JAIL>"],
|
["set <JAIL> addignoreip <IP>", "adds <IP> to the ignore list of <JAIL>"],
|
||||||
["set <JAIL> delignoreip <IP>", "removes <IP> from the ignore list of <JAIL>"],
|
["set <JAIL> delignoreip <IP>", "removes <IP> from the ignore list of <JAIL>"],
|
||||||
["set <JAIL> addlogpath <FILE>", "adds <FILE> to the monitoring list of <JAIL>"],
|
["set <JAIL> addlogpath <FILE>", "adds <FILE> to the monitoring list of <JAIL>"],
|
||||||
["set <JAIL> dellogpath <FILE>", "removes <FILE> to the monitoring list of <JAIL>"],
|
["set <JAIL> dellogpath <FILE>", "removes <FILE> to the monitoring list of <JAIL>"],
|
||||||
["set <JAIL> timeregex <REGEX>", "sets the regular expression <REGEX> to match the date format for <JAIL>. This will disable the autodetection feature."],
|
|
||||||
["set <JAIL> timepattern <PATTERN>", "sets the pattern <PATTERN> to match the date format for <JAIL>. This will disable the autodetection feature."],
|
|
||||||
["set <JAIL> addfailregex <REGEX>", "adds the regular expression <REGEX> which must match failures for <JAIL>"],
|
["set <JAIL> addfailregex <REGEX>", "adds the regular expression <REGEX> which must match failures for <JAIL>"],
|
||||||
["set <JAIL> delfailregex <INDEX>", "removes the regular expression at <INDEX> for failregex"],
|
["set <JAIL> delfailregex <INDEX>", "removes the regular expression at <INDEX> for failregex"],
|
||||||
["set <JAIL> addignoreregex <REGEX>", "adds the regular expression <REGEX> which should match pattern to exclude for <JAIL>"],
|
["set <JAIL> addignoreregex <REGEX>", "adds the regular expression <REGEX> which should match pattern to exclude for <JAIL>"],
|
||||||
|
|
|
@ -24,4 +24,4 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
version = "0.9.0-SVN"
|
version = "0.8.2-SVN"
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstart = touch /tmp/fail2ban.dummy
|
actionstart = touch /tmp/fail2ban.dummy
|
||||||
echo "<init>" >> /tmp/fail2ban.dummy
|
printf %%b "<init>\n" >> /tmp/fail2ban.dummy
|
||||||
|
|
||||||
# Option: actionend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
|
@ -34,7 +34,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo "+<ip>" >> /tmp/fail2ban.dummy
|
actionban = printf %%b "+<ip>\n" >> /tmp/fail2ban.dummy
|
||||||
|
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
@ -44,7 +44,7 @@ actionban = echo "+<ip>" >> /tmp/fail2ban.dummy
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = echo "-<ip>" >> /tmp/fail2ban.dummy
|
actionunban = printf %%b "-<ip>\n" >> /tmp/fail2ban.dummy
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#
|
#
|
||||||
actionstart =
|
actionstart =
|
||||||
|
|
||||||
# Option: actionend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
|
@ -34,7 +34,7 @@ actioncheck =
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = IP=<ip> &&
|
actionban = IP=<ip> &&
|
||||||
echo "ALL: $IP" >> <file>
|
printf %%b "ALL: $IP\n" >> <file>
|
||||||
|
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
actionstart =
|
actionstart =
|
||||||
|
|
||||||
|
|
||||||
# Option: actionend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Cyril Jaquier
|
||||||
|
# Modified: Yaroslav O. Halchenko <debian@onerussian.com>
|
||||||
|
# made active on all ports from original iptables.conf
|
||||||
|
#
|
||||||
|
# $Revision: 658 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: actionstart
|
||||||
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstart = iptables -N fail2ban-<name>
|
||||||
|
iptables -A fail2ban-<name> -j RETURN
|
||||||
|
iptables -I INPUT -p <protocol> -j fail2ban-<name>
|
||||||
|
|
||||||
|
# Option: actionstop
|
||||||
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstop = iptables -D INPUT -p <protocol> -j fail2ban-<name>
|
||||||
|
iptables -F fail2ban-<name>
|
||||||
|
iptables -X fail2ban-<name>
|
||||||
|
|
||||||
|
# Option: actioncheck
|
||||||
|
# Notes.: command executed once before each actionban command
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actioncheck = iptables -n -L INPUT | grep -q fail2ban-<name>
|
||||||
|
|
||||||
|
# Option: actionban
|
||||||
|
# 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
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
|
|
||||||
|
# Option: actionunban
|
||||||
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
# command is executed with Fail2Ban user rights.
|
||||||
|
# Tags: <ip> IP address
|
||||||
|
# <failures> number of failures
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
|
||||||
|
# Defaut name of the chain
|
||||||
|
#
|
||||||
|
name = default
|
||||||
|
|
||||||
|
# Option: protocol
|
||||||
|
# Notes.: internally used by config reader for interpolations.
|
||||||
|
# Values: [ tcp | udp | icmp | all ] Default: tcp
|
||||||
|
#
|
||||||
|
protocol = tcp
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Guido Bozzetto
|
||||||
|
# Modified: Cyril Jaquier
|
||||||
|
#
|
||||||
|
# make "fail2ban-<name>" chain to match drop IP
|
||||||
|
# make "fail2ban-<name>-log" chain to log and drop
|
||||||
|
# insert a jump to fail2ban-<name> from -I INPUT if proto/port match
|
||||||
|
#
|
||||||
|
# $Revision: 668 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: actionstart
|
||||||
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstart = iptables -N fail2ban-<name>
|
||||||
|
iptables -A fail2ban-<name> -j RETURN
|
||||||
|
iptables -I INPUT 1 -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
|
||||||
|
iptables -N fail2ban-<name>-log
|
||||||
|
iptables -I fail2ban-<name>-log -j LOG --log-prefix "$(expr fail2ban-<name> : '\(.\{1,23\}\)'):DROP " --log-level warning -m limit --limit 6/m --limit-burst 2
|
||||||
|
iptables -A fail2ban-<name>-log -j DROP
|
||||||
|
|
||||||
|
# Option: actionstop
|
||||||
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstop = iptables -D INPUT -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
|
||||||
|
iptables -F fail2ban-<name>
|
||||||
|
iptables -F fail2ban-<name>-log
|
||||||
|
iptables -X fail2ban-<name>
|
||||||
|
iptables -X fail2ban-<name>-log
|
||||||
|
|
||||||
|
# Option: actioncheck
|
||||||
|
# Notes.: command executed once before each actionban command
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actioncheck = iptables -n -L fail2ban-<name>-log >/dev/null
|
||||||
|
|
||||||
|
# Option: actionban
|
||||||
|
# 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
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j fail2ban-<name>-log
|
||||||
|
|
||||||
|
# Option: actionunban
|
||||||
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
# command is executed with Fail2Ban user rights.
|
||||||
|
# Tags: <ip> IP address
|
||||||
|
# <failures> number of failures
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionunban = iptables -D fail2ban-<name> -s <ip> -j fail2ban-<name>-log
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
|
||||||
|
# Defaut name of the chain
|
||||||
|
#
|
||||||
|
name = default
|
||||||
|
|
||||||
|
# Option: port
|
||||||
|
# Notes.: specifies port to monitor
|
||||||
|
# Values: [ NUM | STRING ] Default:
|
||||||
|
#
|
||||||
|
port = ssh
|
||||||
|
|
||||||
|
# Option: protocol
|
||||||
|
# Notes.: internally used by config reader for interpolations.
|
||||||
|
# Values: [ tcp | udp | icmp | all ] Default: tcp
|
||||||
|
#
|
||||||
|
protocol = tcp
|
|
@ -17,7 +17,7 @@ actionstart = iptables -N fail2ban-<name>
|
||||||
iptables -A fail2ban-<name> -j RETURN
|
iptables -A fail2ban-<name> -j RETURN
|
||||||
iptables -I INPUT -m state --state NEW -p <protocol> --dport <port> -j fail2ban-<name>
|
iptables -I INPUT -m state --state NEW -p <protocol> --dport <port> -j fail2ban-<name>
|
||||||
|
|
||||||
# Option: actionend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 510 $
|
# $Revision: 668 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,25 +11,25 @@
|
||||||
# Notes.: command executed once at the start of Fail2Ban.
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstart = echo -en "Hi,\n
|
actionstart = printf %%b "Hi,\n
|
||||||
The jail <name> has been started successfuly.\n
|
The jail <name> has been started successfully.\n
|
||||||
Output will be buffered until <lines> lines are available.\n
|
Output will be buffered until <lines> lines are available.\n
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: started" <dest>
|
Fail2Ban"|mail -s "[Fail2Ban] <name>: started" <dest>
|
||||||
|
|
||||||
# Option: actionend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstop = if [ -f <tmpfile> ]; then
|
actionstop = if [ -f <tmpfile> ]; then
|
||||||
echo -en "Hi,\n
|
printf %%b "Hi,\n
|
||||||
These hosts have been banned by Fail2Ban.\n
|
These hosts have been banned by Fail2Ban.\n
|
||||||
`cat <tmpfile>`
|
`cat <tmpfile>`
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary" <dest>
|
Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary" <dest>
|
||||||
rm <tmpfile>
|
rm <tmpfile>
|
||||||
fi
|
fi
|
||||||
echo -en "Hi,\n
|
printf %%b "Hi,\n
|
||||||
The jail <name> has been stopped.\n
|
The jail <name> has been stopped.\n
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped" <dest>
|
Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped" <dest>
|
||||||
|
@ -48,10 +48,10 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo `date`": <ip> (<failures> failures)" >> <tmpfile>
|
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||||
LINE=$( wc -l <tmpfile> | awk '{ print $1 }' )
|
LINE=$( wc -l <tmpfile> | awk '{ print $1 }' )
|
||||||
if [ $LINE -eq <lines> ]; then
|
if [ $LINE -eq <lines> ]; then
|
||||||
echo -en "Hi,\n
|
printf %%b "Hi,\n
|
||||||
These hosts have been banned by Fail2Ban.\n
|
These hosts have been banned by Fail2Ban.\n
|
||||||
`cat <tmpfile>`
|
`cat <tmpfile>`
|
||||||
\nRegards,\n
|
\nRegards,\n
|
||||||
|
|
|
@ -7,31 +7,31 @@
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
# Option: fwstart
|
# Option: actionstart
|
||||||
# Notes.: command executed once at the start of Fail2Ban.
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstart = echo -en "Hi,\n
|
actionstart = printf %%b "Hi,\n
|
||||||
The jail <name> has been started successfuly.\n
|
The jail <name> has been started successfully.\n
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: started" <dest>
|
Fail2Ban"|mail -s "[Fail2Ban] <name>: started" <dest>
|
||||||
|
|
||||||
# Option: fwend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstop = echo -en "Hi,\n
|
actionstop = printf %%b "Hi,\n
|
||||||
The jail <name> has been stopped.\n
|
The jail <name> has been stopped.\n
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped" <dest>
|
Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped" <dest>
|
||||||
|
|
||||||
# Option: fwcheck
|
# Option: actioncheck
|
||||||
# Notes.: command executed once before each fwban command
|
# Notes.: command executed once before each actionban command
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actioncheck =
|
actioncheck =
|
||||||
|
|
||||||
# Option: fwban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: <ip> IP address
|
||||||
|
@ -40,7 +40,7 @@ actioncheck =
|
||||||
# <bantime> unix timestamp of the ban time
|
# <bantime> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo -en "Hi,\n
|
actionban = printf %%b "Hi,\n
|
||||||
The IP <ip> has just been banned by Fail2Ban after
|
The IP <ip> has just been banned by Fail2Ban after
|
||||||
<failures> attempts against <name>.\n\n
|
<failures> attempts against <name>.\n\n
|
||||||
Here are more information about <ip>:\n
|
Here are more information about <ip>:\n
|
||||||
|
@ -50,7 +50,7 @@ actionban = echo -en "Hi,\n
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip>" <dest>
|
Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip>" <dest>
|
||||||
|
|
||||||
# Option: fwunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: <ip> IP address
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Cyril Jaquier
|
||||||
|
#
|
||||||
|
# $Revision: 660 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: actionstart
|
||||||
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been started successfully.\n
|
||||||
|
Output will be buffered until <lines> lines are available.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actionstop
|
||||||
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstop = if [ -f <tmpfile> ]; then
|
||||||
|
printf %%b "Subject: [Fail2Ban] <name>: summary
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
These hosts have been banned by Fail2Ban.\n
|
||||||
|
`cat <tmpfile>`
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
rm <tmpfile>
|
||||||
|
fi
|
||||||
|
printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been stopped.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actioncheck
|
||||||
|
# Notes.: command executed once before each actionban command
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actioncheck =
|
||||||
|
|
||||||
|
# Option: actionban
|
||||||
|
# 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
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||||
|
LINE=$( wc -l <tmpfile> | awk '{ print $1 }' )
|
||||||
|
if [ $LINE -eq <lines> ]; then
|
||||||
|
printf %%b "Subject: [Fail2Ban] <name>: summary
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
These hosts have been banned by Fail2Ban.\n
|
||||||
|
`cat <tmpfile>`
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
rm <tmpfile>
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Option: actionunban
|
||||||
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
# command is executed with Fail2Ban user rights.
|
||||||
|
# Tags: <ip> IP address
|
||||||
|
# <failures> number of failures
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionunban =
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
|
||||||
|
# Defaut name of the chain
|
||||||
|
#
|
||||||
|
name = default
|
||||||
|
|
||||||
|
# Destination/Addressee of the mail
|
||||||
|
#
|
||||||
|
dest = root
|
||||||
|
|
||||||
|
# Sender of the mail
|
||||||
|
#
|
||||||
|
sender = fail2ban
|
||||||
|
|
||||||
|
# Default number of lines that are buffered
|
||||||
|
#
|
||||||
|
lines = 5
|
||||||
|
|
||||||
|
# Default temporary file
|
||||||
|
#
|
||||||
|
tmpfile = /tmp/fail2ban-mail.txt
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Cyril Jaquier
|
||||||
|
#
|
||||||
|
# $Revision: 660 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: actionstart
|
||||||
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been started successfully.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actionstop
|
||||||
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been stopped.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actioncheck
|
||||||
|
# Notes.: command executed once before each actionban command
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actioncheck =
|
||||||
|
|
||||||
|
# Option: actionban
|
||||||
|
# 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
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The IP <ip> has just been banned by Fail2Ban after
|
||||||
|
<failures> attempts against <name>.\n\n
|
||||||
|
Here are more information about <ip>:\n
|
||||||
|
`/usr/bin/whois <ip>`\n\n
|
||||||
|
Lines containing IP:<ip> in <logpath>\n
|
||||||
|
`/bin/grep '\<<ip>\>' <logpath>`\n\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actionunban
|
||||||
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
# command is executed with Fail2Ban user rights.
|
||||||
|
# Tags: <ip> IP address
|
||||||
|
# <failures> number of failures
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionunban =
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
|
||||||
|
# Defaut name of the chain
|
||||||
|
#
|
||||||
|
name = default
|
||||||
|
|
||||||
|
# Destination/Addressee of the mail
|
||||||
|
#
|
||||||
|
dest = root
|
||||||
|
|
||||||
|
# Sender of the mail
|
||||||
|
#
|
||||||
|
sender = fail2ban
|
||||||
|
|
||||||
|
# Path to the log files which contain relevant lines for the abuser IP
|
||||||
|
#
|
||||||
|
logpath = /dev/null
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Cyril Jaquier
|
||||||
|
#
|
||||||
|
# $Revision: 660 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: actionstart
|
||||||
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been started successfully.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actionstop
|
||||||
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been stopped.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actioncheck
|
||||||
|
# Notes.: command executed once before each actionban command
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actioncheck =
|
||||||
|
|
||||||
|
# Option: actionban
|
||||||
|
# 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
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The IP <ip> has just been banned by Fail2Ban after
|
||||||
|
<failures> attempts against <name>.\n\n
|
||||||
|
Here are more information about <ip>:\n
|
||||||
|
`/usr/bin/whois <ip>`\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actionunban
|
||||||
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
# command is executed with Fail2Ban user rights.
|
||||||
|
# Tags: <ip> IP address
|
||||||
|
# <failures> number of failures
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionunban =
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
|
||||||
|
# Defaut name of the chain
|
||||||
|
#
|
||||||
|
name = default
|
||||||
|
|
||||||
|
# Destination/Addressee of the mail
|
||||||
|
#
|
||||||
|
dest = root
|
||||||
|
|
||||||
|
# Sender of the mail
|
||||||
|
#
|
||||||
|
sender = fail2ban
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Cyril Jaquier
|
||||||
|
#
|
||||||
|
# $Revision: 660 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: actionstart
|
||||||
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been started successfully.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actionstop
|
||||||
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The jail <name> has been stopped.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actioncheck
|
||||||
|
# Notes.: command executed once before each actionban command
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actioncheck =
|
||||||
|
|
||||||
|
# Option: actionban
|
||||||
|
# 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
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
|
From: Fail2Ban <<sender>>
|
||||||
|
To: <dest>\n
|
||||||
|
Hi,\n
|
||||||
|
The IP <ip> has just been banned by Fail2Ban after
|
||||||
|
<failures> attempts against <name>.\n
|
||||||
|
Regards,\n
|
||||||
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
|
|
||||||
|
# Option: actionunban
|
||||||
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
# command is executed with Fail2Ban user rights.
|
||||||
|
# Tags: <ip> IP address
|
||||||
|
# <failures> number of failures
|
||||||
|
# <time> unix timestamp of the ban time
|
||||||
|
# Values: CMD
|
||||||
|
#
|
||||||
|
actionunban =
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
|
||||||
|
# Defaut name of the chain
|
||||||
|
#
|
||||||
|
name = default
|
||||||
|
|
||||||
|
# Destination/Addressee of the mail
|
||||||
|
#
|
||||||
|
dest = root
|
||||||
|
|
||||||
|
# Sender of the mail
|
||||||
|
#
|
||||||
|
sender = fail2ban
|
||||||
|
|
|
@ -28,7 +28,7 @@ logtarget = /var/log/fail2ban.log
|
||||||
# Notes.: Set the socket file. This is used to communicate with the daemon. Do
|
# Notes.: Set the socket file. This is used to communicate with the daemon. Do
|
||||||
# not remove this file when Fail2ban runs. It will not be possible to
|
# not remove this file when Fail2ban runs. It will not be possible to
|
||||||
# communicate with the server afterwards.
|
# communicate with the server afterwards.
|
||||||
# Values: FILE Default: /tmp/fail2ban.sock
|
# Values: FILE Default: /var/run/fail2ban/fail2ban.sock
|
||||||
#
|
#
|
||||||
socket = /tmp/fail2ban.sock
|
socket = /var/run/fail2ban/fail2ban.sock
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
#
|
#
|
||||||
# Author: Yaroslav Halchenko
|
# Author: Yaroslav Halchenko
|
||||||
#
|
#
|
||||||
|
# $Revision: 668 $
|
||||||
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02
|
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02|sogou music spider
|
||||||
badbots = atSpider/1\.0|autoemailspider|China Local Browse 2\.6|ContentSmartz|DataCha0s/2\.0|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 +http\://letscrawl\.com/|Lincoln State Web Browser|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|MVAClient|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|sogou spider|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|WebVulnCrawl\.blogspot\.com/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00
|
badbots = atSpider/1\.0|autoemailspider|China Local Browse 2\.6|ContentSmartz|DataCha0s/2\.0|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 +http\://letscrawl\.com/|Lincoln State Web Browser|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|MVAClient|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|sogou spider|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|WebVulnCrawl\.blogspot\.com/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00
|
||||||
|
|
||||||
# Option: failregex
|
# Option: failregex
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
# (?:::f{4,6}:)?(?P<host>\S+)
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = [[]client <HOST>[]] File does not exist: .*(\.php|\.asp)
|
failregex = [[]client <HOST>[]] (File does not exist|script not found or unable to stat): .*(\.php|\.asp|\.exe|\.pl)
|
||||||
|
|
||||||
# Option: ignoreregex
|
# Option: ignoreregex
|
||||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Tim Connors
|
||||||
|
#
|
||||||
|
# $Revision: 668 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: Regexp to catch Apache overflow attempts.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
failregex = [[]client <HOST>[]] (Invalid method in request|request failed: URI too long|erroneous characters after protocol string)
|
||||||
|
|
||||||
|
# Option: ignoreregex
|
||||||
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
ignoreregex =
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Generic configuration items (to be used as interpolations) in other
|
||||||
|
# filters or actions configurations
|
||||||
|
#
|
||||||
|
# Author: Yaroslav Halchenko
|
||||||
|
#
|
||||||
|
# $Revision: $
|
||||||
|
#
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
# Load customizations if any available
|
||||||
|
after = common.local
|
||||||
|
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
|
||||||
|
# Daemon definition is to be specialized (if needed) in .conf file
|
||||||
|
_daemon = \S*
|
||||||
|
|
||||||
|
#
|
||||||
|
# Shortcuts for easier comprehension of the failregex
|
||||||
|
#
|
||||||
|
# PID.
|
||||||
|
# EXAMPLES: [123]
|
||||||
|
__pid_re = (?:\[\d+\])
|
||||||
|
|
||||||
|
# Daemon name (with optional source_file:line or whatever)
|
||||||
|
# EXAMPLES: pam_rhosts_auth, [sshd], pop(pam_unix)
|
||||||
|
__daemon_re = [\[\(]?%(_daemon)s(?:\(\S+\))?[\]\)]?:?
|
||||||
|
|
||||||
|
# Combinations of daemon name and PID
|
||||||
|
# EXAMPLES: sshd[31607], pop(pam_unix)[4920]
|
||||||
|
__daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Common line prefixes (beginnings) which could be used in filters
|
||||||
|
#
|
||||||
|
# [hostname] [vserver tag] daemon_id spaces
|
||||||
|
# this can be optional (for instance if we match named native log files)
|
||||||
|
__prefix_line = \s*(?:\S+ )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s*
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Fail2Ban configuration file for wuftpd
|
||||||
|
#
|
||||||
|
# Author: Kevin Zembower (copied from wsftpd.conf)
|
||||||
|
#
|
||||||
|
# $Revision: 684 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: regex to match the password failures messages in the logfile.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
failregex = ftpd(?:\[\d+\])?:\s+repeated login failures from <HOST> \(\S+\)$
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Fail2Ban configuration file for named (bind9). Trying to generalize the
|
||||||
|
# structure which is general to capture general patterns in log
|
||||||
|
# lines to cover different configurations/distributions
|
||||||
|
#
|
||||||
|
# Author: Yaroslav Halchenko
|
||||||
|
#
|
||||||
|
# $Revision: 616 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
#
|
||||||
|
# Daemon name
|
||||||
|
_daemon=named
|
||||||
|
|
||||||
|
#
|
||||||
|
# Shortcuts for easier comprehension of the failregex
|
||||||
|
__pid_re=(?:\[\d+\])
|
||||||
|
__daemon_re=\(?%(_daemon)s(?:\(\S+\))?\)?:?
|
||||||
|
__daemon_combs_re=(?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:)
|
||||||
|
# hostname daemon_id spaces
|
||||||
|
# this can be optional (for instance if we match named native log files)
|
||||||
|
__line_prefix=(?:\s\S+ %(__daemon_combs_re)s\s+)?
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: regex to match the password failures messages in the logfile.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
failregex = %(__line_prefix)sclient <HOST>#\S+: query(?: \(cache\))? '.*' denied\s*$
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Fail2Ban configuration file for generic PAM authentication errors
|
||||||
|
#
|
||||||
|
# Author: Yaroslav Halchenko
|
||||||
|
#
|
||||||
|
# $Revision: $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# if you want to catch only login erros from specific daemons, use smth like
|
||||||
|
#_ttys_re=(?:ssh|pure-ftpd|ftp)
|
||||||
|
# To catch all failed logins
|
||||||
|
_ttys_re=\S*
|
||||||
|
|
||||||
|
#
|
||||||
|
# Shortcuts for easier comprehension of the failregex
|
||||||
|
__pid_re=(?:\[\d+\])
|
||||||
|
__pam_re=\(?pam_unix(?:\(\S+\))?\)?:?
|
||||||
|
__pam_combs_re=(?:%(__pid_re)s?:\s+%(__pam_re)s|%(__pam_re)s%(__pid_re)s?:)
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: regex to match the password failures messages in the logfile.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
failregex = \s\S+ \S+%(__pam_combs_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=%(_ttys_re)s ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
|
@ -14,7 +14,10 @@
|
||||||
# (?:::f{4,6}:)?(?P<host>\S+)
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = USER \S+: no such user found from \S* ?\[<HOST>\] to \S+\s*$
|
failregex = \(\S+\[<HOST>\]\)[: -]+ USER \S+: no such user found from \S+ \[\S+\] to \S+:\S+$
|
||||||
|
\(\S+\[<HOST>\]\)[: -]+ USER \S+ \(Login failed\): Incorrect password\.$
|
||||||
|
\(\S+\[<HOST>\]\)[: -]+ SECURITY VIOLATION: \S+ login attempted\.$
|
||||||
|
\(\S+\[<HOST>\]\)[: -]+ Maximum login attempts \(\d+\) exceeded$
|
||||||
|
|
||||||
# Option: ignoreregex
|
# Option: ignoreregex
|
||||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
|
|
@ -5,8 +5,17 @@
|
||||||
# $Revision$
|
# $Revision$
|
||||||
#
|
#
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
# Read common prefixes. If any customizations available -- read them from
|
||||||
|
# common.local
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
|
_daemon = sshd
|
||||||
|
|
||||||
# Option: failregex
|
# Option: failregex
|
||||||
# Notes.: regex to match the password failures messages in the logfile. The
|
# Notes.: regex to match the password failures messages in the logfile. The
|
||||||
# host must be matched by a group named "host". The tag "<HOST>" can
|
# host must be matched by a group named "host". The tag "<HOST>" can
|
||||||
|
@ -14,11 +23,14 @@
|
||||||
# (?:::f{4,6}:)?(?P<host>\S+)
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = Authentication failure for .* from <HOST>$
|
failregex = ^%(__prefix_line)s(?:error: PAM: )?Authentication failure for .* from <HOST>\s*$
|
||||||
Failed [-/\w]+ for .* from <HOST>$
|
^%(__prefix_line)sFailed [-/\w]+ for .* from <HOST>(?: port \d*)?(?: ssh\d*)?$
|
||||||
ROOT LOGIN REFUSED .* FROM <HOST>$
|
^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$
|
||||||
[iI](?:llegal|nvalid) user .* from <HOST>$
|
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$
|
||||||
User .* from <HOST> not allowed because not listed in AllowUsers$
|
^%(__prefix_line)sUser \S+ from <HOST> not allowed because not listed in AllowUsers$
|
||||||
|
^%(__prefix_line)sauthentication failure; logname=\S* uid=\S* euid=\S* tty=\S* ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
||||||
|
^%(__prefix_line)srefused connect from \S+ \(<HOST>\)\s*$
|
||||||
|
^%(__prefix_line)sAddress <HOST> .* POSSIBLE BREAK-IN ATTEMPT\s*$
|
||||||
|
|
||||||
# Option: ignoreregex
|
# Option: ignoreregex
|
||||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
# (?:::f{4,6}:)?(?P<host>\S+)
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = vsftpd(?:\[\d+\])?: .* authentication failure; .* rhost=<HOST>$
|
failregex = vsftpd(?:\(pam_unix\))?(?:\[\d+\])?:.* authentication failure; .* rhost=<HOST>(?:\s+user=\S*)?\s*$
|
||||||
\[.+\] FAIL LOGIN: Client "<HOST>"$
|
\[.+\] FAIL LOGIN: Client "<HOST>"\s*$
|
||||||
|
|
||||||
# Option: ignoreregex
|
# Option: ignoreregex
|
||||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Cyril Jaquier
|
||||||
|
# Rule by : Delvit Guillaume
|
||||||
|
#
|
||||||
|
# $Revision: 601 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# patern : webmin[15673]: Non-existent login as toto from 86.0.6.217
|
||||||
|
# webmin[29544]: Invalid login as root from 86.0.6.217
|
||||||
|
#
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: regex to match the password failure messages in the logfile. The
|
||||||
|
# host must be matched by a group named "host". The tag "<HOST>" can
|
||||||
|
# be used for standard IP/hostname matching and is only an alias for
|
||||||
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
failregex = webmin.* Non-existent login as .+ from <HOST>$
|
||||||
|
webmin.* Invalid login as .+ from <HOST>$
|
||||||
|
|
||||||
|
# Option: ignoreregex
|
||||||
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
ignoreregex =
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Guido Bozzetto
|
||||||
|
#
|
||||||
|
# $Revision: 668 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: regex to match the password failures messages in the logfile. The
|
||||||
|
# host must be matched by a group named "host". The tag "<HOST>" can
|
||||||
|
# be used for standard IP/hostname matching and is only an alias for
|
||||||
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
# Cfr.: /var/log/(daemon\.|sys)log
|
||||||
|
# libwrap => tcp wrappers: hosts.(allow|deny)
|
||||||
|
# address => xinetd: deny_from|only_from
|
||||||
|
# load => xinetd: max_load (temporary problem)
|
||||||
|
#
|
||||||
|
|
||||||
|
failregex = xinetd(?:\[\d{1,5}\])?: FAIL: \S+ address from=<HOST>$
|
||||||
|
xinetd(?:\[\d{1,5}\])?: FAIL: \S+ libwrap from=<HOST>$
|
||||||
|
|
||||||
|
# Option: ignoreregex
|
||||||
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
ignoreregex =
|
|
@ -45,7 +45,7 @@ backend = auto
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = sshd
|
filter = sshd
|
||||||
action = iptables[name=SSH, port=ssh, protocol=tcp]
|
action = iptables[name=SSH, port=ssh, protocol=tcp]
|
||||||
mail-whois[name=SSH, dest=yourmail@mail.com]
|
sendmail-whois[name=SSH, dest=you@mail.com, sender=fail2ban@mail.com]
|
||||||
logpath = /var/log/sshd.log
|
logpath = /var/log/sshd.log
|
||||||
maxretry = 5
|
maxretry = 5
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ maxretry = 5
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = proftpd
|
filter = proftpd
|
||||||
action = iptables[name=ProFTPD, port=ftp, protocol=tcp]
|
action = iptables[name=ProFTPD, port=ftp, protocol=tcp]
|
||||||
mail-whois[name=ProFTPD, dest=yourmail@mail.com]
|
sendmail-whois[name=ProFTPD, dest=you@mail.com]
|
||||||
logpath = /var/log/proftpd/proftpd.log
|
logpath = /var/log/proftpd/proftpd.log
|
||||||
maxretry = 6
|
maxretry = 6
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ enabled = false
|
||||||
filter = sasl
|
filter = sasl
|
||||||
backend = polling
|
backend = polling
|
||||||
action = iptables[name=sasl, port=smtp, protocol=tcp]
|
action = iptables[name=sasl, port=smtp, protocol=tcp]
|
||||||
mail-whois[name=sasl, dest=yourmail@mail.com]
|
sendmail-whois[name=sasl, dest=you@mail.com]
|
||||||
logpath = /var/log/mail.log
|
logpath = /var/log/mail.log
|
||||||
|
|
||||||
# Here we use TCP-Wrappers instead of Netfilter/Iptables. "ignoreregex" is
|
# Here we use TCP-Wrappers instead of Netfilter/Iptables. "ignoreregex" is
|
||||||
|
@ -77,7 +77,7 @@ logpath = /var/log/mail.log
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = sshd
|
filter = sshd
|
||||||
action = hostsdeny
|
action = hostsdeny
|
||||||
mail-whois[name=SSH, dest=yourmail@mail.com]
|
sendmail-whois[name=SSH, dest=you@mail.com]
|
||||||
ignoreregex = for myuser from
|
ignoreregex = for myuser from
|
||||||
logpath = /var/log/sshd.log
|
logpath = /var/log/sshd.log
|
||||||
|
|
||||||
|
@ -89,8 +89,8 @@ logpath = /var/log/sshd.log
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = apache-auth
|
filter = apache-auth
|
||||||
action = hostsdeny
|
action = hostsdeny
|
||||||
logpath = /var/log/apache*/*access.log
|
logpath = /var/log/apache*/*error.log
|
||||||
/home/www/myhomepage/access.log
|
/home/www/myhomepage/error.log
|
||||||
maxretry = 6
|
maxretry = 6
|
||||||
|
|
||||||
# The hosts.deny path can be defined with the "file" argument if it is
|
# The hosts.deny path can be defined with the "file" argument if it is
|
||||||
|
@ -101,7 +101,7 @@ maxretry = 6
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = postfix
|
filter = postfix
|
||||||
action = hostsdeny[file=/not/a/standard/path/hosts.deny]
|
action = hostsdeny[file=/not/a/standard/path/hosts.deny]
|
||||||
mail[name=Postfix, dest=yourmail@mail.com]
|
sendmail[name=Postfix, dest=you@mail.com]
|
||||||
logpath = /var/log/postfix.log
|
logpath = /var/log/postfix.log
|
||||||
bantime = 300
|
bantime = 300
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ bantime = 300
|
||||||
|
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = vsftpd
|
filter = vsftpd
|
||||||
action = mail-whois[name=VSFTPD, dest=yourmail@mail.com]
|
action = sendmail-whois[name=VSFTPD, dest=you@mail.com]
|
||||||
logpath = /var/log/vsftpd.log
|
logpath = /var/log/vsftpd.log
|
||||||
maxretry = 5
|
maxretry = 5
|
||||||
bantime = 1800
|
bantime = 1800
|
||||||
|
@ -124,7 +124,7 @@ bantime = 1800
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = vsftpd
|
filter = vsftpd
|
||||||
action = iptables[name=VSFTPD, port=ftp, protocol=tcp]
|
action = iptables[name=VSFTPD, port=ftp, protocol=tcp]
|
||||||
mail-whois[name=VSFTPD, dest=yourmail@mail.com]
|
sendmail-whois[name=VSFTPD, dest=you@mail.com]
|
||||||
logpath = /var/log/vsftpd.log
|
logpath = /var/log/vsftpd.log
|
||||||
maxretry = 5
|
maxretry = 5
|
||||||
bantime = 1800
|
bantime = 1800
|
||||||
|
@ -137,7 +137,7 @@ bantime = 1800
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = apache-badbots
|
filter = apache-badbots
|
||||||
action = iptables-multiport[name=BadBots, port="http,https"]
|
action = iptables-multiport[name=BadBots, port="http,https"]
|
||||||
mail-buffered[name=BadBots, lines=5, dest=yourmail@mail.com]
|
sendmail-buffered[name=BadBots, lines=5, dest=you@mail.com]
|
||||||
logpath = /var/www/*/logs/access_log
|
logpath = /var/www/*/logs/access_log
|
||||||
bantime = 172800
|
bantime = 172800
|
||||||
maxretry = 1
|
maxretry = 1
|
||||||
|
@ -149,7 +149,7 @@ maxretry = 1
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = apache-noscript
|
filter = apache-noscript
|
||||||
action = shorewall
|
action = shorewall
|
||||||
mail[name=Postfix, dest=yourmail@mail.com]
|
sendmail[name=Postfix, dest=you@mail.com]
|
||||||
logpath = /var/log/apache2/error_log
|
logpath = /var/log/apache2/error_log
|
||||||
|
|
||||||
# This jail uses ipfw, the standard firewall on FreeBSD. The "ignoreip"
|
# This jail uses ipfw, the standard firewall on FreeBSD. The "ignoreip"
|
||||||
|
@ -162,6 +162,44 @@ logpath = /var/log/apache2/error_log
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = sshd
|
filter = sshd
|
||||||
action = ipfw[localhost=192.168.0.1]
|
action = ipfw[localhost=192.168.0.1]
|
||||||
mail-whois[name="SSH,IPFW", dest=yourmail@mail.com]
|
sendmail-whois[name="SSH,IPFW", dest=you@mail.com]
|
||||||
logpath = /var/log/auth.log
|
logpath = /var/log/auth.log
|
||||||
ignoreip = 168.192.0.1
|
ignoreip = 168.192.0.1
|
||||||
|
|
||||||
|
# These jails block attacks against named (bind9). By default, logging is off
|
||||||
|
# with bind9 installation. You will need something like this:
|
||||||
|
#
|
||||||
|
# logging {
|
||||||
|
# channel security_file {
|
||||||
|
# file "/var/log/named/security.log" versions 3 size 30m;
|
||||||
|
# severity dynamic;
|
||||||
|
# print-time yes;
|
||||||
|
# };
|
||||||
|
# category security {
|
||||||
|
# security_file;
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# in your named.conf to provide proper logging.
|
||||||
|
# This jail blocks UDP traffic for DNS requests.
|
||||||
|
|
||||||
|
[named-refused-udp]
|
||||||
|
|
||||||
|
enabled = false
|
||||||
|
filter = named-refused
|
||||||
|
action = iptables-multiport[name=Named, port="domain,953", protocol=udp]
|
||||||
|
sendmail-whois[name=Named, dest=you@mail.com]
|
||||||
|
logpath = /var/log/named/security.log
|
||||||
|
ignoreip = 168.192.0.1
|
||||||
|
|
||||||
|
# This jail blocks TCP traffic for DNS requests.
|
||||||
|
|
||||||
|
[named-refused-tcp]
|
||||||
|
|
||||||
|
enabled = false
|
||||||
|
filter = named-refused
|
||||||
|
action = iptables-multiport[name=Named, port="domain,953", protocol=tcp]
|
||||||
|
sendmail-whois[name=Named, dest=you@mail.com]
|
||||||
|
logpath = /var/log/named/security.log
|
||||||
|
ignoreip = 168.192.0.1
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,8 @@ logSys = logging.getLogger("fail2ban.client")
|
||||||
|
|
||||||
class Fail2banClient:
|
class Fail2banClient:
|
||||||
|
|
||||||
prompt = "fail2ban> "
|
SERVER = "fail2ban-server"
|
||||||
|
PROMPT = "fail2ban> "
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__argv = None
|
self.__argv = None
|
||||||
|
@ -65,11 +66,11 @@ class Fail2banClient:
|
||||||
def dispVersion(self):
|
def dispVersion(self):
|
||||||
print "Fail2Ban v" + version
|
print "Fail2Ban v" + version
|
||||||
print
|
print
|
||||||
print "Copyright (c) 2004-2006 Cyril Jaquier"
|
print "Copyright (c) 2004-2008 Cyril Jaquier"
|
||||||
print "Copyright of modifications held by their respective authors."
|
print "Copyright of modifications held by their respective authors."
|
||||||
print "Licensed under the GNU General Public License v2 (GPL)."
|
print "Licensed under the GNU General Public License v2 (GPL)."
|
||||||
print
|
print
|
||||||
print "Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>."
|
print "Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>."
|
||||||
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
||||||
|
|
||||||
def dispUsage(self):
|
def dispUsage(self):
|
||||||
|
@ -97,7 +98,7 @@ class Fail2banClient:
|
||||||
printFormatted()
|
printFormatted()
|
||||||
|
|
||||||
print
|
print
|
||||||
print "Report bugs to <lostcontrol@users.sourceforge.net>"
|
print "Report bugs to <cyril.jaquier@fail2ban.org>"
|
||||||
|
|
||||||
def dispInteractive(self):
|
def dispInteractive(self):
|
||||||
print "Fail2Ban v" + version + " reads log file that contains password failure report"
|
print "Fail2Ban v" + version + " reads log file that contains password failure report"
|
||||||
|
@ -208,6 +209,19 @@ class Fail2banClient:
|
||||||
else:
|
else:
|
||||||
logSys.error("Could not find server")
|
logSys.error("Could not find server")
|
||||||
return False
|
return False
|
||||||
|
elif len(cmd) == 2 and cmd[0] == "reload":
|
||||||
|
if self.__ping():
|
||||||
|
jail = cmd[1]
|
||||||
|
ret = self.__readJailConfig(jail)
|
||||||
|
# Do not continue if configuration is not 100% valid
|
||||||
|
if not ret:
|
||||||
|
return False
|
||||||
|
self.__processCmd([['stop', jail]], False)
|
||||||
|
# Configure the server
|
||||||
|
return self.__processCmd(self.__stream, False)
|
||||||
|
else:
|
||||||
|
logSys.error("Could not find server")
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
return self.__processCmd([cmd])
|
return self.__processCmd([cmd])
|
||||||
|
|
||||||
|
@ -222,7 +236,7 @@ class Fail2banClient:
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid == 0:
|
if pid == 0:
|
||||||
args = list()
|
args = list()
|
||||||
args.append("fail2ban-server")
|
args.append(self.SERVER)
|
||||||
# Start in background mode.
|
# Start in background mode.
|
||||||
args.append("-b")
|
args.append("-b")
|
||||||
# Set the socket path.
|
# Set the socket path.
|
||||||
|
@ -232,14 +246,15 @@ class Fail2banClient:
|
||||||
if force:
|
if force:
|
||||||
args.append("-x")
|
args.append("-x")
|
||||||
try:
|
try:
|
||||||
# Use the PATH env
|
# Use the current directory.
|
||||||
os.execvp("fail2ban-server", args)
|
exe = os.path.abspath(os.path.join(sys.path[0], self.SERVER))
|
||||||
|
os.execv(exe, args)
|
||||||
except OSError:
|
except OSError:
|
||||||
try:
|
try:
|
||||||
# Use the current directory
|
# Use the PATH env.
|
||||||
os.execv("fail2ban-server", args)
|
os.execvp(self.SERVER, args)
|
||||||
except OSError:
|
except OSError:
|
||||||
print "Could not find fail2ban-server"
|
print "Could not find %s" % self.SERVER
|
||||||
os.exit(-1)
|
os.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
|
@ -338,7 +353,7 @@ class Fail2banClient:
|
||||||
readline.parse_and_bind("tab: complete")
|
readline.parse_and_bind("tab: complete")
|
||||||
self.dispInteractive()
|
self.dispInteractive()
|
||||||
while True:
|
while True:
|
||||||
cmd = raw_input(self.prompt)
|
cmd = raw_input(self.PROMPT)
|
||||||
if cmd == "exit" or cmd == "quit":
|
if cmd == "exit" or cmd == "quit":
|
||||||
# Exit
|
# Exit
|
||||||
return True
|
return True
|
||||||
|
@ -357,7 +372,14 @@ class Fail2banClient:
|
||||||
def __readConfig(self):
|
def __readConfig(self):
|
||||||
# Read the configuration
|
# Read the configuration
|
||||||
self.__configurator.readAll()
|
self.__configurator.readAll()
|
||||||
ret = self.__configurator.getAllOptions()
|
ret = self.__configurator.getOptions()
|
||||||
|
self.__configurator.convertToProtocol()
|
||||||
|
self.__stream = self.__configurator.getConfigStream()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def __readJailConfig(self, jail):
|
||||||
|
self.__configurator.readAll()
|
||||||
|
ret = self.__configurator.getOptions(jail)
|
||||||
self.__configurator.convertToProtocol()
|
self.__configurator.convertToProtocol()
|
||||||
self.__stream = self.__configurator.getConfigStream()
|
self.__stream = self.__configurator.getConfigStream()
|
||||||
return ret
|
return ret
|
||||||
|
|
121
fail2ban-regex
121
fail2ban-regex
|
@ -31,11 +31,11 @@ import getopt, sys, time, logging, os
|
||||||
# fix for bug #343821
|
# fix for bug #343821
|
||||||
sys.path.insert(1, "/usr/share/fail2ban")
|
sys.path.insert(1, "/usr/share/fail2ban")
|
||||||
|
|
||||||
from ConfigParser import SafeConfigParser
|
from client.configparserinc import SafeConfigParserWithIncludes
|
||||||
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
|
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
|
||||||
from common.version import version
|
from common.version import version
|
||||||
from server.filter import Filter
|
from server.filter import Filter
|
||||||
from server.regex import RegexException
|
from server.failregex import RegexException
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.regex")
|
logSys = logging.getLogger("fail2ban.regex")
|
||||||
|
@ -65,9 +65,12 @@ class RegexStat:
|
||||||
class Fail2banRegex:
|
class Fail2banRegex:
|
||||||
|
|
||||||
test = None
|
test = None
|
||||||
|
|
||||||
|
CONFIG_DEFAULTS = {'configpath' : "/etc/fail2ban/"}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__filter = Filter(None)
|
self.__filter = Filter(None)
|
||||||
|
self.__ignoreregex = list()
|
||||||
self.__failregex = list()
|
self.__failregex = list()
|
||||||
# Setup logging
|
# Setup logging
|
||||||
logging.getLogger("fail2ban").handlers = []
|
logging.getLogger("fail2ban").handlers = []
|
||||||
|
@ -83,17 +86,17 @@ class Fail2banRegex:
|
||||||
def dispVersion():
|
def dispVersion():
|
||||||
print "Fail2Ban v" + version
|
print "Fail2Ban v" + version
|
||||||
print
|
print
|
||||||
print "Copyright (c) 2004-2006 Cyril Jaquier"
|
print "Copyright (c) 2004-2008 Cyril Jaquier"
|
||||||
print "Copyright of modifications held by their respective authors."
|
print "Copyright of modifications held by their respective authors."
|
||||||
print "Licensed under the GNU General Public License v2 (GPL)."
|
print "Licensed under the GNU General Public License v2 (GPL)."
|
||||||
print
|
print
|
||||||
print "Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>."
|
print "Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>."
|
||||||
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
||||||
dispVersion = staticmethod(dispVersion)
|
dispVersion = staticmethod(dispVersion)
|
||||||
|
|
||||||
#@staticmethod
|
#@staticmethod
|
||||||
def dispUsage():
|
def dispUsage():
|
||||||
print "Usage: "+sys.argv[0]+" [OPTIONS] <LOG> <REGEX>"
|
print "Usage: "+sys.argv[0]+" [OPTIONS] <LOG> <REGEX> [IGNOREREGEX]"
|
||||||
print
|
print
|
||||||
print "Fail2Ban v" + version + " reads log file that contains password failure report"
|
print "Fail2Ban v" + version + " reads log file that contains password failure report"
|
||||||
print "and bans the corresponding IP addresses using firewall rules."
|
print "and bans the corresponding IP addresses using firewall rules."
|
||||||
|
@ -112,7 +115,11 @@ class Fail2banRegex:
|
||||||
print " string a string representing a 'failregex'"
|
print " string a string representing a 'failregex'"
|
||||||
print " filename path to a filter file (filter.d/sshd.conf)"
|
print " filename path to a filter file (filter.d/sshd.conf)"
|
||||||
print
|
print
|
||||||
print "Report bugs to <lostcontrol@users.sourceforge.net>"
|
print "IgnoreRegex:"
|
||||||
|
print " string a string representing an 'ignoreregex'"
|
||||||
|
print " filename path to a filter file (filter.d/sshd.conf)"
|
||||||
|
print
|
||||||
|
print "Report bugs to <cyril.jaquier@fail2ban.org>"
|
||||||
dispUsage = staticmethod(dispUsage)
|
dispUsage = staticmethod(dispUsage)
|
||||||
|
|
||||||
def getCmdLineOptions(self, optList):
|
def getCmdLineOptions(self, optList):
|
||||||
|
@ -131,9 +138,38 @@ class Fail2banRegex:
|
||||||
return os.path.isfile(value)
|
return os.path.isfile(value)
|
||||||
logIsFile = staticmethod(logIsFile)
|
logIsFile = staticmethod(logIsFile)
|
||||||
|
|
||||||
|
def readIgnoreRegex(self, value):
|
||||||
|
if os.path.isfile(value):
|
||||||
|
reader = SafeConfigParserWithIncludes(defaults=self.CONFIG_DEFAULTS)
|
||||||
|
try:
|
||||||
|
reader.read(value)
|
||||||
|
print "Use ignoreregex file : " + value
|
||||||
|
self.__ignoreregex = [RegexStat(m)
|
||||||
|
for m in reader.get("Definition", "ignoreregex").split('\n')]
|
||||||
|
except NoSectionError:
|
||||||
|
print "No [Definition] section in " + value
|
||||||
|
print
|
||||||
|
return False
|
||||||
|
except NoOptionError:
|
||||||
|
print "No failregex option in " + value
|
||||||
|
print
|
||||||
|
return False
|
||||||
|
except MissingSectionHeaderError:
|
||||||
|
print "No section headers in " + value
|
||||||
|
print
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if len(value) > 53:
|
||||||
|
stripReg = value[0:50] + "..."
|
||||||
|
else:
|
||||||
|
stripReg = value
|
||||||
|
print "Use ignoreregex line : " + stripReg
|
||||||
|
self.__ignoreregex = [RegexStat(value)]
|
||||||
|
return True
|
||||||
|
|
||||||
def readRegex(self, value):
|
def readRegex(self, value):
|
||||||
if os.path.isfile(value):
|
if os.path.isfile(value):
|
||||||
reader = SafeConfigParser()
|
reader = SafeConfigParserWithIncludes(defaults=self.CONFIG_DEFAULTS)
|
||||||
try:
|
try:
|
||||||
reader.read(value)
|
reader.read(value)
|
||||||
print "Use regex file : " + value
|
print "Use regex file : " + value
|
||||||
|
@ -160,14 +196,33 @@ class Fail2banRegex:
|
||||||
self.__failregex = [RegexStat(value)]
|
self.__failregex = [RegexStat(value)]
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def testIgnoreRegex(self, line):
|
||||||
|
found = False
|
||||||
|
for regex in self.__ignoreregex:
|
||||||
|
logging.getLogger("fail2ban").setLevel(logging.DEBUG)
|
||||||
|
try:
|
||||||
|
self.__filter.addIgnoreRegex(regex.getFailRegex())
|
||||||
|
try:
|
||||||
|
ret = self.__filter.ignoreLine(line)
|
||||||
|
if ret:
|
||||||
|
regex.inc()
|
||||||
|
except RegexException, e:
|
||||||
|
print e
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
self.__filter.delIgnoreRegex(0)
|
||||||
|
logging.getLogger("fail2ban").setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
def testRegex(self, line):
|
def testRegex(self, line):
|
||||||
found = False
|
found = False
|
||||||
|
for regex in self.__ignoreregex:
|
||||||
|
self.__filter.addIgnoreRegex(regex.getFailRegex())
|
||||||
for regex in self.__failregex:
|
for regex in self.__failregex:
|
||||||
logging.getLogger("fail2ban").setLevel(logging.DEBUG)
|
logging.getLogger("fail2ban").setLevel(logging.DEBUG)
|
||||||
try:
|
try:
|
||||||
self.__filter.addFailRegex(regex.getFailRegex())
|
self.__filter.addFailRegex(regex.getFailRegex())
|
||||||
try:
|
try:
|
||||||
ret = self.__filter.findFailure(line)
|
ret = self.__filter.processLine(line)
|
||||||
if not len(ret) == 0:
|
if not len(ret) == 0:
|
||||||
if found == True:
|
if found == True:
|
||||||
ret[0].append(True)
|
ret[0].append(True)
|
||||||
|
@ -185,6 +240,8 @@ class Fail2banRegex:
|
||||||
finally:
|
finally:
|
||||||
self.__filter.delFailRegex(0)
|
self.__filter.delFailRegex(0)
|
||||||
logging.getLogger("fail2ban").setLevel(logging.CRITICAL)
|
logging.getLogger("fail2ban").setLevel(logging.CRITICAL)
|
||||||
|
for regex in self.__ignoreregex:
|
||||||
|
self.__filter.delIgnoreRegex(0)
|
||||||
|
|
||||||
def printStats(self):
|
def printStats(self):
|
||||||
print
|
print
|
||||||
|
@ -194,25 +251,51 @@ class Fail2banRegex:
|
||||||
|
|
||||||
# Print title
|
# Print title
|
||||||
cnt = 1
|
cnt = 1
|
||||||
print "Failregex:"
|
print "Failregex"
|
||||||
|
print "|- Regular expressions:"
|
||||||
for failregex in self.__failregex:
|
for failregex in self.__failregex:
|
||||||
print "[" + str(cnt) + "] " + failregex.getFailRegex()
|
print "| [" + str(cnt) + "] " + failregex.getFailRegex()
|
||||||
cnt += 1
|
cnt += 1
|
||||||
|
cnt = 1
|
||||||
|
|
||||||
print
|
print "|"
|
||||||
|
|
||||||
# Print stats
|
# Print stats
|
||||||
cnt = 1
|
cnt = 1
|
||||||
total = 0
|
total = 0
|
||||||
print "Number of matches:"
|
print "`- Number of matches:"
|
||||||
for failregex in self.__failregex:
|
for failregex in self.__failregex:
|
||||||
match = failregex.getStats()
|
match = failregex.getStats()
|
||||||
total += match
|
total += match
|
||||||
print "[" + str(cnt) + "] " + str(match) + " match(es)"
|
print " [" + str(cnt) + "] " + str(match) + " match(es)"
|
||||||
cnt += 1
|
cnt += 1
|
||||||
|
|
||||||
print
|
print
|
||||||
|
|
||||||
|
# Print title
|
||||||
|
cnt = 1
|
||||||
|
print "Ignoreregex"
|
||||||
|
print "|- Regular expressions:"
|
||||||
|
for failregex in self.__ignoreregex:
|
||||||
|
print "| [" + str(cnt) + "] " + failregex.getFailRegex()
|
||||||
|
cnt += 1
|
||||||
|
cnt = 1
|
||||||
|
|
||||||
|
print "|"
|
||||||
|
|
||||||
|
# Print stats
|
||||||
|
cnt = 1
|
||||||
|
print "`- Number of matches:"
|
||||||
|
for failregex in self.__ignoreregex:
|
||||||
|
match = failregex.getStats()
|
||||||
|
print " [" + str(cnt) + "] " + str(match) + " match(es)"
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
print
|
||||||
|
print "Summary"
|
||||||
|
print "======="
|
||||||
|
print
|
||||||
|
|
||||||
if total == 0:
|
if total == 0:
|
||||||
print "Sorry, no match"
|
print "Sorry, no match"
|
||||||
print
|
print
|
||||||
|
@ -239,7 +322,7 @@ class Fail2banRegex:
|
||||||
|
|
||||||
print "Date template hits:"
|
print "Date template hits:"
|
||||||
for template in self.__filter.dateDetector.getTemplates():
|
for template in self.__filter.dateDetector.getTemplates():
|
||||||
print `template.getHits()` + " hit: " + template.getName()
|
print `template.getHits()` + " hit(s): " + template.getName()
|
||||||
|
|
||||||
print
|
print
|
||||||
|
|
||||||
|
@ -263,7 +346,7 @@ if __name__ == "__main__":
|
||||||
# Process command line
|
# Process command line
|
||||||
fail2banRegex.getCmdLineOptions(optList)
|
fail2banRegex.getCmdLineOptions(optList)
|
||||||
# We need exactly 3 parameters
|
# We need exactly 3 parameters
|
||||||
if not len(sys.argv) == 3:
|
if not len(sys.argv) in (3, 4):
|
||||||
fail2banRegex.dispUsage()
|
fail2banRegex.dispUsage()
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
else:
|
else:
|
||||||
|
@ -272,6 +355,10 @@ if __name__ == "__main__":
|
||||||
print "============="
|
print "============="
|
||||||
print
|
print
|
||||||
|
|
||||||
|
if len(sys.argv) == 4:
|
||||||
|
if fail2banRegex.readIgnoreRegex(sys.argv[3]) == False:
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
if fail2banRegex.readRegex(sys.argv[2]) == False:
|
if fail2banRegex.readRegex(sys.argv[2]) == False:
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
|
@ -281,6 +368,7 @@ if __name__ == "__main__":
|
||||||
print "Use log file : " + sys.argv[1]
|
print "Use log file : " + sys.argv[1]
|
||||||
print
|
print
|
||||||
for line in hdlr:
|
for line in hdlr:
|
||||||
|
fail2banRegex.testIgnoreRegex(line)
|
||||||
fail2banRegex.testRegex(line)
|
fail2banRegex.testRegex(line)
|
||||||
except IOError, e:
|
except IOError, e:
|
||||||
print e
|
print e
|
||||||
|
@ -293,6 +381,7 @@ if __name__ == "__main__":
|
||||||
stripLog = sys.argv[1]
|
stripLog = sys.argv[1]
|
||||||
print "Use single line: " + stripLog
|
print "Use single line: " + stripLog
|
||||||
print
|
print
|
||||||
|
fail2banRegex.testIgnoreRegex(sys.argv[1])
|
||||||
fail2banRegex.testRegex(sys.argv[1])
|
fail2banRegex.testRegex(sys.argv[1])
|
||||||
|
|
||||||
if fail2banRegex.printStats():
|
if fail2banRegex.printStats():
|
||||||
|
|
|
@ -25,7 +25,7 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import getopt, sys
|
import getopt, sys, logging
|
||||||
|
|
||||||
# Inserts our own modules path first in the list
|
# Inserts our own modules path first in the list
|
||||||
# fix for bug #343821
|
# fix for bug #343821
|
||||||
|
@ -34,6 +34,9 @@ sys.path.insert(1, "/usr/share/fail2ban")
|
||||||
from common.version import version
|
from common.version import version
|
||||||
from server.server import Server
|
from server.server import Server
|
||||||
|
|
||||||
|
# Gets the instance of the logger.
|
||||||
|
logSys = logging.getLogger("fail2ban")
|
||||||
|
|
||||||
##
|
##
|
||||||
# \mainpage Fail2Ban
|
# \mainpage Fail2Ban
|
||||||
#
|
#
|
||||||
|
@ -50,16 +53,16 @@ class Fail2banServer:
|
||||||
self.__conf = dict()
|
self.__conf = dict()
|
||||||
self.__conf["background"] = True
|
self.__conf["background"] = True
|
||||||
self.__conf["force"] = False
|
self.__conf["force"] = False
|
||||||
self.__conf["socket"] = "/tmp/fail2ban.sock"
|
self.__conf["socket"] = "/var/run/fail2ban/fail2ban.sock"
|
||||||
|
|
||||||
def dispVersion(self):
|
def dispVersion(self):
|
||||||
print "Fail2Ban v" + version
|
print "Fail2Ban v" + version
|
||||||
print
|
print
|
||||||
print "Copyright (c) 2004-2006 Cyril Jaquier"
|
print "Copyright (c) 2004-2008 Cyril Jaquier"
|
||||||
print "Copyright of modifications held by their respective authors."
|
print "Copyright of modifications held by their respective authors."
|
||||||
print "Licensed under the GNU General Public License v2 (GPL)."
|
print "Licensed under the GNU General Public License v2 (GPL)."
|
||||||
print
|
print
|
||||||
print "Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>."
|
print "Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>."
|
||||||
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
||||||
|
|
||||||
def dispUsage(self):
|
def dispUsage(self):
|
||||||
|
@ -82,7 +85,7 @@ class Fail2banServer:
|
||||||
print " -h, --help display this help message"
|
print " -h, --help display this help message"
|
||||||
print " -V, --version print the version"
|
print " -V, --version print the version"
|
||||||
print
|
print
|
||||||
print "Report bugs to <lostcontrol@users.sourceforge.net>"
|
print "Report bugs to <cyril.jaquier@fail2ban.org>"
|
||||||
|
|
||||||
def __getCmdLineOptions(self, optList):
|
def __getCmdLineOptions(self, optList):
|
||||||
""" Gets the command line options
|
""" Gets the command line options
|
||||||
|
@ -123,7 +126,7 @@ class Fail2banServer:
|
||||||
self.__server.start(self.__conf["socket"], self.__conf["force"])
|
self.__server.start(self.__conf["socket"], self.__conf["force"])
|
||||||
return True
|
return True
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
logSys.exception(e)
|
||||||
self.__server.quit()
|
self.__server.quit()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
=============================================================
|
=============================================================
|
||||||
Fail2Ban (version 0.7.7) 2007/??/??
|
Fail2Ban (version 0.8.2) 2008/03/06
|
||||||
=============================================================
|
=============================================================
|
||||||
|
|
||||||
Cacti is a graphing solution using RRDTool. It is possible to
|
Cacti is a graphing solution using RRDTool. It is possible to
|
||||||
|
@ -13,7 +13,7 @@ use Cacti to display statistics about Fail2ban.
|
||||||
Installation:
|
Installation:
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
1/ Install Fail2ban version 0.7 or higher and ensure that it
|
1/ Install Fail2ban version 0.8 or higher and ensure that it
|
||||||
works properly.
|
works properly.
|
||||||
2/ The user running poller.php must have read and write
|
2/ The user running poller.php must have read and write
|
||||||
access to the socket used by Fail2ban.
|
access to the socket used by Fail2ban.
|
||||||
|
@ -30,7 +30,7 @@ appreciate this program, you can contact me at:
|
||||||
|
|
||||||
Website: http://www.fail2ban.org
|
Website: http://www.fail2ban.org
|
||||||
|
|
||||||
Cyril Jaquier: <lostcontrol@users.sourceforge.net>
|
Cyril Jaquier: <cyril.jaquier@fail2ban.org>
|
||||||
|
|
||||||
License:
|
License:
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/Library/LaunchDaemonsm/org.fail2ban.plist
|
||||||
|
===================================
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Disabled</key>
|
||||||
|
<false/>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>fail2ban</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>/usr/local/bin/fail2ban-client</string>
|
||||||
|
<string>start</string>
|
||||||
|
</array>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -20,14 +20,14 @@ FAIL2BAN="/usr/bin/fail2ban-client"
|
||||||
RETVAL=0
|
RETVAL=0
|
||||||
|
|
||||||
getpid() {
|
getpid() {
|
||||||
pid=`ps -ef | grep fail2ban-|grep -v grep|awk '{print $2}'`
|
pid=`ps -eo pid,comm | grep fail2ban- | awk '{ print $1 }'`
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
echo -n $"Starting fail2ban: "
|
echo -n $"Starting fail2ban: "
|
||||||
getpid
|
getpid
|
||||||
if [ -z "$pid" ]; then
|
if [ -z "$pid" ]; then
|
||||||
rm -rf /tmp/fail2ban.sock # in case of unclean shutdown
|
rm -rf /var/run/fail2ban/fail2ban.sock # in case of unclean shutdown
|
||||||
$FAIL2BAN start > /dev/null
|
$FAIL2BAN start > /dev/null
|
||||||
RETVAL=$?
|
RETVAL=$?
|
||||||
fi
|
fi
|
||||||
|
|
111
files/suse-initd
111
files/suse-initd
|
@ -6,26 +6,26 @@
|
||||||
#
|
#
|
||||||
### BEGIN INIT INFO
|
### BEGIN INIT INFO
|
||||||
# Provides: fail2ban
|
# Provides: fail2ban
|
||||||
# Required-Start: $syslog $remote_fs postfix
|
# Required-Start: $syslog $remote_fs sendmail
|
||||||
# Required-Stop: $syslog $remote_fs
|
# Required-Stop: $syslog $remote_fs
|
||||||
# Should-Stop: $time ypbind sendmail
|
# Should-Stop: $time ypbind sendmail
|
||||||
# Default-Start: 3 5
|
# Default-Start: 3 5
|
||||||
# Default-Stop: 0 1 2 6
|
# Default-Stop: 0 1 2 6
|
||||||
# Description: startup Fail2Ban
|
# Description: startup Fail2Ban
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/sbin:/usr/bin:/bin
|
||||||
FAIL2BAN_BIN=/usr/local/bin/fail2ban-client
|
FAIL2BAN_BIN=/usr/local/bin/fail2ban-client
|
||||||
FAIL2BAN_SERVER=/usr/local/bin/fail2ban-server
|
FAIL2BAN_SERVER=/usr/local/bin/fail2ban-server
|
||||||
FAIL2BAN_SOCKET=/tmp/fail2ban.sock
|
FAIL2BAN_SOCKET=/var/run/fail2ban/fail2ban.sock
|
||||||
test -x $FAIL2BAN_BIN || { echo "$FAIL2BAN_BIN not installed";
|
test -x $FAIL2BAN_BIN || { echo "$FAIL2BAN_BIN not installed";
|
||||||
if [ "$1" = "stop" ]; then exit 0;
|
if [ "$1" = "stop" ]; then exit 0;
|
||||||
else exit 5; fi; }
|
else exit 5; fi; }
|
||||||
|
|
||||||
# Check for existence of needed config file and read it
|
# Check for existence of needed config file and read it
|
||||||
FAIL2BAN_CONFIG=/etc/fail2ban/fail2ban.conf
|
FAIL2BAN_CONFIG=/etc/fail2ban/fail2ban.conf
|
||||||
test -r $FAIL2BAN_CONFIG || { echo "$FAIL2BAN_CONFIG not existing";
|
test -r $FAIL2BAN_CONFIG || { echo "$FAIL2BAN_CONFIG not existing";
|
||||||
if [ "$1" = "stop" ]; then exit 0;
|
if [ "$1" = "stop" ]; then exit 0;
|
||||||
else exit 6; fi; }
|
else exit 6; fi; }
|
||||||
|
|
||||||
. /etc/rc.status
|
. /etc/rc.status
|
||||||
|
|
||||||
|
@ -34,54 +34,63 @@ rc_reset
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
start)
|
start)
|
||||||
echo -n "Starting Fail2Ban "
|
echo -n "Starting Fail2Ban "
|
||||||
/sbin/startproc $FAIL2BAN_BIN -q start 2>1 > /dev/null
|
/sbin/startproc $FAIL2BAN_BIN start &>/dev/null
|
||||||
rc_status -v
|
rc_status -v
|
||||||
;;
|
;;
|
||||||
stop)
|
stop)
|
||||||
echo -n "Shutting down Fail2ban "
|
echo -n "Shutting down Fail2ban "
|
||||||
/sbin/startproc $FAIL2BAN_BIN -q stop
|
/sbin/startproc $FAIL2BAN_BIN -q stop
|
||||||
rc_status -v
|
rc_status -v
|
||||||
;;
|
;;
|
||||||
try-restart|condrestart)
|
try-restart|condrestart)
|
||||||
if test "$1" = "condrestart"; then
|
if test "$1" = "condrestart"; then
|
||||||
echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
|
echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
|
||||||
fi
|
fi
|
||||||
$0 status
|
$0 status
|
||||||
if test $? = 0; then
|
if test $? = 0; then
|
||||||
$0 restart
|
$0 restart
|
||||||
else
|
else
|
||||||
rc_reset # Not running is not a failure.
|
rc_reset # Not running is not a failure.
|
||||||
fi
|
fi
|
||||||
rc_status
|
rc_status
|
||||||
;;
|
;;
|
||||||
restart)
|
restart)
|
||||||
$0 stop
|
$0 stop
|
||||||
i=60
|
echo -n "-wait a minute "
|
||||||
while [ -e $FAIL2BAN_SOCKET ] && [ $i -gt 60 ]
|
i=60
|
||||||
sleep 1
|
while [ -e $FAIL2BAN_SOCKET ] && [ $i -gt 0 ]; do
|
||||||
i=$[i-1]
|
sleep 1
|
||||||
echo -n "."
|
i=$[$i-1]
|
||||||
done
|
echo -n "."
|
||||||
echo "."
|
done
|
||||||
$0 start
|
echo "."
|
||||||
|
$0 start
|
||||||
|
|
||||||
# Remember status and be quiet
|
# Remember status and be quiet
|
||||||
rc_status
|
rc_status
|
||||||
;;
|
;;
|
||||||
force-reload)
|
force-reload)
|
||||||
echo -n "Reload service Fail2ban "
|
echo -n "Reload service Fail2ban "
|
||||||
/sbin/startproc $FAIL2BAN_BIN -q reload
|
/sbin/startproc $FAIL2BAN_BIN -q reload
|
||||||
rc_status -v
|
rc_status -v
|
||||||
;;
|
;;
|
||||||
reload)
|
reload)
|
||||||
echo -n "Reload service Fail2ban "
|
echo -n "Reload service Fail2ban "
|
||||||
/sbin/startproc $FAIL2BAN_BIN -q reload
|
/sbin/startproc $FAIL2BAN_BIN -q reload
|
||||||
rc_status -v
|
rc_status -v
|
||||||
;;
|
;;
|
||||||
status)
|
status)
|
||||||
echo -n "Checking for service Fail2ban "
|
echo -n "Checking for service Fail2ban "
|
||||||
/sbin/checkproc $FAIL2BAN_SERVER
|
/sbin/checkproc $FAIL2BAN_SERVER
|
||||||
rc_status -v
|
rc_status -v
|
||||||
;;
|
;;
|
||||||
probe)
|
probe)
|
||||||
|
test /etc/fail2ban/fail2ban.conf -nt /var/run/fail2ban.pid && echo reload
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
rc_exit
|
|
@ -106,7 +106,7 @@ class Action:
|
||||||
|
|
||||||
def setActionStart(self, value):
|
def setActionStart(self, value):
|
||||||
self.__actionStart = value
|
self.__actionStart = value
|
||||||
logSys.info("Set actionStart = %s" % value)
|
logSys.debug("Set actionStart = %s" % value)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the "start" command.
|
# Get the "start" command.
|
||||||
|
@ -135,7 +135,7 @@ class Action:
|
||||||
|
|
||||||
def setActionBan(self, value):
|
def setActionBan(self, value):
|
||||||
self.__actionBan = value
|
self.__actionBan = value
|
||||||
logSys.info("Set actionBan = %s" % value)
|
logSys.debug("Set actionBan = %s" % value)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the "ban" command.
|
# Get the "ban" command.
|
||||||
|
@ -160,7 +160,7 @@ class Action:
|
||||||
|
|
||||||
def setActionUnban(self, value):
|
def setActionUnban(self, value):
|
||||||
self.__actionUnban = value
|
self.__actionUnban = value
|
||||||
logSys.info("Set actionUnban = %s" % value)
|
logSys.debug("Set actionUnban = %s" % value)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the "unban" command.
|
# Get the "unban" command.
|
||||||
|
@ -185,7 +185,7 @@ class Action:
|
||||||
|
|
||||||
def setActionCheck(self, value):
|
def setActionCheck(self, value):
|
||||||
self.__actionCheck = value
|
self.__actionCheck = value
|
||||||
logSys.info("Set actionCheck = %s" % value)
|
logSys.debug("Set actionCheck = %s" % value)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the "check" command.
|
# Get the "check" command.
|
||||||
|
@ -202,7 +202,7 @@ class Action:
|
||||||
|
|
||||||
def setActionStop(self, value):
|
def setActionStop(self, value):
|
||||||
self.__actionStop = value
|
self.__actionStop = value
|
||||||
logSys.info("Set actionStop = %s" % value)
|
logSys.debug("Set actionStop = %s" % value)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the "stop" command.
|
# Get the "stop" command.
|
||||||
|
@ -314,3 +314,4 @@ class Action:
|
||||||
logSys.error("%s failed with %s" % (realCmd, e))
|
logSys.error("%s failed with %s" % (realCmd, e))
|
||||||
return False
|
return False
|
||||||
executeCmd = staticmethod(executeCmd)
|
executeCmd = staticmethod(executeCmd)
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,10 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from pickle import dumps, loads, HIGHEST_PROTOCOL
|
from pickle import dumps, loads, HIGHEST_PROTOCOL
|
||||||
import asyncore, asynchat, socket, os, logging, sys
|
import asyncore, asynchat, socket, os, logging
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.server.communication")
|
logSys = logging.getLogger("fail2ban.server")
|
||||||
|
|
||||||
##
|
##
|
||||||
# Request handler class.
|
# Request handler class.
|
||||||
|
@ -46,10 +46,9 @@ class RequestHandler(asynchat.async_chat):
|
||||||
self.__buffer = []
|
self.__buffer = []
|
||||||
# Sets the terminator.
|
# Sets the terminator.
|
||||||
self.set_terminator(RequestHandler.END_STRING)
|
self.set_terminator(RequestHandler.END_STRING)
|
||||||
self.found_terminator = self.handle_request_line
|
|
||||||
|
|
||||||
def collect_incoming_data(self, data):
|
def collect_incoming_data(self, data):
|
||||||
logSys.debug("Received raw data: " + str(data))
|
#logSys.debug("Received raw data: " + str(data))
|
||||||
self.__buffer.append(data)
|
self.__buffer.append(data)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -57,7 +56,7 @@ class RequestHandler(asynchat.async_chat):
|
||||||
#
|
#
|
||||||
# This method is called once we have a complete request.
|
# This method is called once we have a complete request.
|
||||||
|
|
||||||
def handle_request_line(self):
|
def found_terminator(self):
|
||||||
# Joins the buffer items.
|
# Joins the buffer items.
|
||||||
message = loads("".join(self.__buffer))
|
message = loads("".join(self.__buffer))
|
||||||
# Gives the message to the transmitter.
|
# Gives the message to the transmitter.
|
||||||
|
@ -84,7 +83,7 @@ class AsyncServer(asyncore.dispatcher):
|
||||||
def __init__(self, transmitter):
|
def __init__(self, transmitter):
|
||||||
asyncore.dispatcher.__init__(self)
|
asyncore.dispatcher.__init__(self)
|
||||||
self.__transmitter = transmitter
|
self.__transmitter = transmitter
|
||||||
self.__sock = "/tmp/fail2ban.sock"
|
self.__sock = "/var/run/fail2ban/fail2ban.sock"
|
||||||
self.__init = False
|
self.__init = False
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -125,12 +124,15 @@ class AsyncServer(asyncore.dispatcher):
|
||||||
# Creates the socket.
|
# Creates the socket.
|
||||||
self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
self.set_reuse_addr()
|
self.set_reuse_addr()
|
||||||
self.bind(sock)
|
try:
|
||||||
|
self.bind(sock)
|
||||||
|
except Exception:
|
||||||
|
raise AsyncServerException("Unable to bind socket %s" % self.__sock)
|
||||||
self.listen(1)
|
self.listen(1)
|
||||||
# Sets the init flag.
|
# Sets the init flag.
|
||||||
self.__init = True
|
self.__init = True
|
||||||
# TODO Add try..catch
|
# TODO Add try..catch
|
||||||
asyncore.loop(timeout = 2)
|
asyncore.loop()
|
||||||
|
|
||||||
##
|
##
|
||||||
# Stops the communication server.
|
# Stops the communication server.
|
|
@ -24,7 +24,7 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from banticket import BanTicket
|
from ticket import BanTicket
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from mytime import MyTime
|
from mytime import MyTime
|
||||||
import logging
|
import logging
|
||||||
|
|
|
@ -1,50 +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 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)
|
|
||||||
|
|
|
@ -1,25 +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: 433 $
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision: 433 $"
|
|
||||||
__date__ = "$Date: 2006-10-24 21:40:51 +0200 (Tue, 24 Oct 2006) $"
|
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
|
||||||
__license__ = "GPL"
|
|
|
@ -26,9 +26,9 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import time, logging
|
import time, logging
|
||||||
|
|
||||||
from datestrptime import DateStrptime
|
from datetemplate import DateStrptime
|
||||||
from datetai64n import DateTai64n
|
from datetemplate import DateTai64n
|
||||||
from dateepoch import DateEpoch
|
from datetemplate import DateEpoch
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
|
@ -39,11 +39,10 @@ class DateDetector:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__lock = Lock()
|
self.__lock = Lock()
|
||||||
self.__templates = list()
|
self.__templates = list()
|
||||||
self.__defTemplate = DateStrptime()
|
|
||||||
|
|
||||||
def addDefaultTemplate(self):
|
def addDefaultTemplate(self):
|
||||||
|
self.__lock.acquire()
|
||||||
try:
|
try:
|
||||||
self.__lock.acquire()
|
|
||||||
# standard
|
# standard
|
||||||
template = DateStrptime()
|
template = DateStrptime()
|
||||||
template.setName("Month Day Hour:Minute:Second")
|
template.setName("Month Day Hour:Minute:Second")
|
||||||
|
@ -68,6 +67,12 @@ class DateDetector:
|
||||||
template.setRegex("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}")
|
template.setRegex("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}")
|
||||||
template.setPattern("%Y/%m/%d %H:%M:%S")
|
template.setPattern("%Y/%m/%d %H:%M:%S")
|
||||||
self.__templates.append(template)
|
self.__templates.append(template)
|
||||||
|
# simple date too (from x11vnc)
|
||||||
|
template = DateStrptime()
|
||||||
|
template.setName("Day/Month/Year Hour:Minute:Second")
|
||||||
|
template.setRegex("\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}")
|
||||||
|
template.setPattern("%d/%m/%Y %H:%M:%S")
|
||||||
|
self.__templates.append(template)
|
||||||
# Apache format [31/Oct/2006:09:22:55 -0000]
|
# Apache format [31/Oct/2006:09:22:55 -0000]
|
||||||
template = DateStrptime()
|
template = DateStrptime()
|
||||||
template.setName("Day/Month/Year:Hour:Minute:Second")
|
template.setName("Day/Month/Year:Hour:Minute:Second")
|
||||||
|
@ -80,6 +85,12 @@ class DateDetector:
|
||||||
template.setRegex("\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
|
template.setRegex("\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
|
||||||
template.setPattern("%Y-%m-%d %H:%M:%S")
|
template.setPattern("%Y-%m-%d %H:%M:%S")
|
||||||
self.__templates.append(template)
|
self.__templates.append(template)
|
||||||
|
# named 26-Jul-2007 15:20:52.252
|
||||||
|
template = DateStrptime()
|
||||||
|
template.setName("Day-Month-Year Hour:Minute:Second[.Millisecond]")
|
||||||
|
template.setRegex("\d{2}-\S{3}-\d{4} \d{2}:\d{2}:\d{2}")
|
||||||
|
template.setPattern("%d-%b-%Y %H:%M:%S")
|
||||||
|
self.__templates.append(template)
|
||||||
# TAI64N
|
# TAI64N
|
||||||
template = DateTai64n()
|
template = DateTai64n()
|
||||||
template.setName("TAI64N")
|
template.setName("TAI64N")
|
||||||
|
@ -94,54 +105,31 @@ class DateDetector:
|
||||||
def getTemplates(self):
|
def getTemplates(self):
|
||||||
return self.__templates
|
return self.__templates
|
||||||
|
|
||||||
def setDefaultRegex(self, value):
|
|
||||||
self.__defTemplate.setRegex(value)
|
|
||||||
|
|
||||||
def getDefaultRegex(self):
|
|
||||||
return self.__defTemplate.getRegex()
|
|
||||||
|
|
||||||
def setDefaultPattern(self, value):
|
|
||||||
self.__defTemplate.setPattern(value)
|
|
||||||
|
|
||||||
def getDefaultPattern(self):
|
|
||||||
return self.__defTemplate.getPattern()
|
|
||||||
|
|
||||||
def matchTime(self, line):
|
def matchTime(self, line):
|
||||||
if self.__defTemplate.isValid():
|
self.__lock.acquire()
|
||||||
return self.__defTemplate.matchDate(line)
|
try:
|
||||||
else:
|
for template in self.__templates:
|
||||||
try:
|
match = template.matchDate(line)
|
||||||
self.__lock.acquire()
|
if not match == None:
|
||||||
for template in self.__templates:
|
return match
|
||||||
match = template.matchDate(line)
|
return None
|
||||||
if not match == None:
|
finally:
|
||||||
return match
|
self.__lock.release()
|
||||||
return None
|
|
||||||
finally:
|
|
||||||
self.__lock.release()
|
|
||||||
|
|
||||||
def getTime(self, line):
|
def getTime(self, line):
|
||||||
if self.__defTemplate.isValid():
|
self.__lock.acquire()
|
||||||
try:
|
try:
|
||||||
date = self.__defTemplate.getDate(line)
|
for template in self.__templates:
|
||||||
return date
|
try:
|
||||||
except ValueError:
|
date = template.getDate(line)
|
||||||
return None
|
if date == None:
|
||||||
else:
|
continue
|
||||||
try:
|
return date
|
||||||
self.__lock.acquire()
|
except ValueError:
|
||||||
for template in self.__templates:
|
pass
|
||||||
try:
|
return None
|
||||||
date = template.getDate(line)
|
finally:
|
||||||
if date == None:
|
self.__lock.release()
|
||||||
continue
|
|
||||||
template.incHits()
|
|
||||||
return date
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return None
|
|
||||||
finally:
|
|
||||||
self.__lock.release()
|
|
||||||
|
|
||||||
def getUnixTime(self, line):
|
def getUnixTime(self, line):
|
||||||
date = self.getTime(line)
|
date = self.getTime(line)
|
||||||
|
@ -155,8 +143,8 @@ class DateDetector:
|
||||||
# in this object and thus should be called from time to time.
|
# in this object and thus should be called from time to time.
|
||||||
|
|
||||||
def sortTemplate(self):
|
def sortTemplate(self):
|
||||||
|
self.__lock.acquire()
|
||||||
try:
|
try:
|
||||||
self.__lock.acquire()
|
|
||||||
logSys.debug("Sorting the template list")
|
logSys.debug("Sorting the template list")
|
||||||
self.__templates.sort(lambda x, y: cmp(x.getHits(), y.getHits()))
|
self.__templates.sort(lambda x, y: cmp(x.getHits(), y.getHits()))
|
||||||
self.__templates.reverse()
|
self.__templates.reverse()
|
||||||
|
|
|
@ -1,44 +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
|
|
||||||
|
|
||||||
from datetemplate import DateTemplate
|
|
||||||
|
|
||||||
class DateEpoch(DateTemplate):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
DateTemplate.__init__(self)
|
|
||||||
# We already know the format for TAI64N
|
|
||||||
self.setRegex("^\d{10}(\.\d{6})?")
|
|
||||||
|
|
||||||
def getDate(self, line):
|
|
||||||
date = None
|
|
||||||
dateMatch = self.matchDate(line)
|
|
||||||
if dateMatch:
|
|
||||||
# extract part of format which represents seconds since epoch
|
|
||||||
date = list(time.localtime(float(dateMatch.group())))
|
|
||||||
return date
|
|
|
@ -1,85 +0,0 @@
|
||||||
# -*- coding: utf8 -*-
|
|
||||||
# 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 mytime import MyTime
|
|
||||||
import time
|
|
||||||
|
|
||||||
from datetemplate import DateTemplate
|
|
||||||
|
|
||||||
##
|
|
||||||
# Use strptime() to parse a date. Our current locale is the 'C'
|
|
||||||
# one because we do not set the locale explicitly. This is POSIX
|
|
||||||
# standard.
|
|
||||||
|
|
||||||
class DateStrptime(DateTemplate):
|
|
||||||
|
|
||||||
TABLE = dict()
|
|
||||||
TABLE["Jan"] = []
|
|
||||||
TABLE["Feb"] = [u"Fév"]
|
|
||||||
TABLE["Mar"] = [u"Mär"]
|
|
||||||
TABLE["Apr"] = ["Avr"]
|
|
||||||
TABLE["May"] = ["Mai"]
|
|
||||||
TABLE["Jun"] = []
|
|
||||||
TABLE["Jul"] = []
|
|
||||||
TABLE["Aug"] = ["Aou"]
|
|
||||||
TABLE["Sep"] = []
|
|
||||||
TABLE["Oct"] = ["Okt"]
|
|
||||||
TABLE["Nov"] = []
|
|
||||||
TABLE["Dec"] = [u"Déc", "Dez"]
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
DateTemplate.__init__(self)
|
|
||||||
|
|
||||||
#@staticmethod
|
|
||||||
def convertLocale(date):
|
|
||||||
for t in DateStrptime.TABLE:
|
|
||||||
for m in DateStrptime.TABLE[t]:
|
|
||||||
if date.find(m) >= 0:
|
|
||||||
return date.replace(m, t)
|
|
||||||
return date
|
|
||||||
convertLocale = staticmethod(convertLocale)
|
|
||||||
|
|
||||||
def getDate(self, line):
|
|
||||||
date = None
|
|
||||||
dateMatch = self.matchDate(line)
|
|
||||||
if dateMatch:
|
|
||||||
try:
|
|
||||||
# Try first with 'C' locale
|
|
||||||
date = list(time.strptime(dateMatch.group(), self.getPattern()))
|
|
||||||
except ValueError:
|
|
||||||
# Try to convert date string to 'C' locale
|
|
||||||
conv = self.convertLocale(dateMatch.group())
|
|
||||||
date = list(time.strptime(conv, self.getPattern()))
|
|
||||||
if date[0] < 2000:
|
|
||||||
# There is probably no year field in the logs
|
|
||||||
date[0] = MyTime.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) > MyTime.time():
|
|
||||||
date[0] -= 1
|
|
||||||
return date
|
|
|
@ -1,46 +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
|
|
||||||
|
|
||||||
from datetemplate import DateTemplate
|
|
||||||
|
|
||||||
class DateTai64n(DateTemplate):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
DateTemplate.__init__(self)
|
|
||||||
# We already know the format for TAI64N
|
|
||||||
self.setRegex("@[0-9a-f]{24}")
|
|
||||||
|
|
||||||
def getDate(self, line):
|
|
||||||
date = None
|
|
||||||
dateMatch = self.matchDate(line)
|
|
||||||
if dateMatch:
|
|
||||||
# extract part of format which represents seconds since epoch
|
|
||||||
value = dateMatch.group()
|
|
||||||
seconds_since_epoch = value[2:17]
|
|
||||||
date = list(time.gmtime(int(seconds_since_epoch, 16)))
|
|
||||||
return date
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf8 -*-
|
||||||
# This file is part of Fail2Ban.
|
# This file is part of Fail2Ban.
|
||||||
#
|
#
|
||||||
# Fail2Ban is free software; you can redistribute it and/or modify
|
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||||
|
@ -24,7 +25,9 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import re
|
import re, time
|
||||||
|
|
||||||
|
from mytime import MyTime
|
||||||
|
|
||||||
class DateTemplate:
|
class DateTemplate:
|
||||||
|
|
||||||
|
@ -32,7 +35,6 @@ class DateTemplate:
|
||||||
self.__name = ""
|
self.__name = ""
|
||||||
self.__regex = ""
|
self.__regex = ""
|
||||||
self.__cRegex = None
|
self.__cRegex = None
|
||||||
self.__pattern = ""
|
|
||||||
self.__hits = 0
|
self.__hits = 0
|
||||||
|
|
||||||
def setName(self, name):
|
def setName(self, name):
|
||||||
|
@ -48,24 +50,117 @@ class DateTemplate:
|
||||||
def getRegex(self):
|
def getRegex(self):
|
||||||
return self.__regex
|
return self.__regex
|
||||||
|
|
||||||
|
def getHits(self):
|
||||||
|
return self.__hits
|
||||||
|
|
||||||
|
def matchDate(self, line):
|
||||||
|
dateMatch = self.__cRegex.search(line)
|
||||||
|
if not dateMatch == None:
|
||||||
|
self.__hits += 1
|
||||||
|
return dateMatch
|
||||||
|
|
||||||
|
def getDate(self, line):
|
||||||
|
raise Exception("matchDate() is abstract")
|
||||||
|
|
||||||
|
|
||||||
|
class DateEpoch(DateTemplate):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
DateTemplate.__init__(self)
|
||||||
|
# We already know the format for TAI64N
|
||||||
|
self.setRegex("^\d{10}(\.\d{6})?")
|
||||||
|
|
||||||
|
def getDate(self, line):
|
||||||
|
date = None
|
||||||
|
dateMatch = self.matchDate(line)
|
||||||
|
if dateMatch:
|
||||||
|
# extract part of format which represents seconds since epoch
|
||||||
|
date = list(time.localtime(float(dateMatch.group())))
|
||||||
|
return date
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Use strptime() to parse a date. Our current locale is the 'C'
|
||||||
|
# one because we do not set the locale explicitly. This is POSIX
|
||||||
|
# standard.
|
||||||
|
|
||||||
|
class DateStrptime(DateTemplate):
|
||||||
|
|
||||||
|
TABLE = dict()
|
||||||
|
TABLE["Jan"] = []
|
||||||
|
TABLE["Feb"] = [u"Fév"]
|
||||||
|
TABLE["Mar"] = [u"Mär"]
|
||||||
|
TABLE["Apr"] = ["Avr"]
|
||||||
|
TABLE["May"] = ["Mai"]
|
||||||
|
TABLE["Jun"] = []
|
||||||
|
TABLE["Jul"] = []
|
||||||
|
TABLE["Aug"] = ["Aou"]
|
||||||
|
TABLE["Sep"] = []
|
||||||
|
TABLE["Oct"] = ["Okt"]
|
||||||
|
TABLE["Nov"] = []
|
||||||
|
TABLE["Dec"] = [u"Déc", "Dez"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
DateTemplate.__init__(self)
|
||||||
|
self.__pattern = ""
|
||||||
|
|
||||||
def setPattern(self, pattern):
|
def setPattern(self, pattern):
|
||||||
self.__pattern = pattern.strip()
|
self.__pattern = pattern.strip()
|
||||||
|
|
||||||
def getPattern(self):
|
def getPattern(self):
|
||||||
return self.__pattern
|
return self.__pattern
|
||||||
|
|
||||||
def isValid(self):
|
#@staticmethod
|
||||||
return self.__regex != "" and self.__pattern != ""
|
def convertLocale(date):
|
||||||
|
for t in DateStrptime.TABLE:
|
||||||
def incHits(self):
|
for m in DateStrptime.TABLE[t]:
|
||||||
self.__hits = self.__hits + 1
|
if date.find(m) >= 0:
|
||||||
|
return date.replace(m, t)
|
||||||
def getHits(self):
|
return date
|
||||||
return self.__hits
|
convertLocale = staticmethod(convertLocale)
|
||||||
|
|
||||||
def matchDate(self, line):
|
|
||||||
dateMatch = self.__cRegex.search(line)
|
|
||||||
return dateMatch
|
|
||||||
|
|
||||||
def getDate(self, line):
|
def getDate(self, line):
|
||||||
raise Exception("matchDate() is abstract")
|
date = None
|
||||||
|
dateMatch = self.matchDate(line)
|
||||||
|
if dateMatch:
|
||||||
|
try:
|
||||||
|
# Try first with 'C' locale
|
||||||
|
date = list(time.strptime(dateMatch.group(), self.getPattern()))
|
||||||
|
except ValueError:
|
||||||
|
# Try to convert date string to 'C' locale
|
||||||
|
conv = self.convertLocale(dateMatch.group())
|
||||||
|
try:
|
||||||
|
date = list(time.strptime(conv, self.getPattern()))
|
||||||
|
except ValueError:
|
||||||
|
# Try to add the current year to the pattern. Should fix
|
||||||
|
# the "Feb 29" issue.
|
||||||
|
conv += " %s" % MyTime.gmtime()[0]
|
||||||
|
pattern = "%s %%Y" % self.getPattern()
|
||||||
|
date = list(time.strptime(conv, pattern))
|
||||||
|
if date[0] < 2000:
|
||||||
|
# There is probably no year field in the logs
|
||||||
|
date[0] = MyTime.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) > MyTime.time():
|
||||||
|
date[0] -= 1
|
||||||
|
return date
|
||||||
|
|
||||||
|
|
||||||
|
class DateTai64n(DateTemplate):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
DateTemplate.__init__(self)
|
||||||
|
# We already know the format for TAI64N
|
||||||
|
self.setRegex("@[0-9a-f]{24}")
|
||||||
|
|
||||||
|
def getDate(self, line):
|
||||||
|
date = None
|
||||||
|
dateMatch = self.matchDate(line)
|
||||||
|
if dateMatch:
|
||||||
|
# extract part of format which represents seconds since epoch
|
||||||
|
value = dateMatch.group()
|
||||||
|
seconds_since_epoch = value[2:17]
|
||||||
|
date = list(time.gmtime(int(seconds_since_epoch, 16)))
|
||||||
|
return date
|
|
@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from faildata import FailData
|
from faildata import FailData
|
||||||
from failticket import FailTicket
|
from ticket import FailTicket
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,74 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from regex import Regex, RegexException
|
import re, sre_constants
|
||||||
|
|
||||||
|
##
|
||||||
|
# Regular expression class.
|
||||||
|
#
|
||||||
|
# This class represents a regular expression with its compiled version.
|
||||||
|
|
||||||
|
class Regex:
|
||||||
|
|
||||||
|
##
|
||||||
|
# Constructor.
|
||||||
|
#
|
||||||
|
# Creates a new object. This method can throw RegexException in order to
|
||||||
|
# avoid construction of invalid object.
|
||||||
|
# @param value the regular expression
|
||||||
|
|
||||||
|
def __init__(self, regex):
|
||||||
|
self._matchCache = None
|
||||||
|
# Perform shortcuts expansions.
|
||||||
|
# Replace "<HOST>" with default regular expression for host.
|
||||||
|
regex = regex.replace("<HOST>", "(?:::f{4,6}:)?(?P<host>\S+)")
|
||||||
|
if regex.lstrip() == '':
|
||||||
|
raise RegexException("Cannot add empty regex")
|
||||||
|
try:
|
||||||
|
self._regexObj = re.compile(regex)
|
||||||
|
self._regex = regex
|
||||||
|
except sre_constants.error:
|
||||||
|
raise RegexException("Unable to compile regular expression '%s'" %
|
||||||
|
regex)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Gets the regular expression.
|
||||||
|
#
|
||||||
|
# The effective regular expression used is returned.
|
||||||
|
# @return the regular expression
|
||||||
|
|
||||||
|
def getRegex(self):
|
||||||
|
return self._regex
|
||||||
|
|
||||||
|
##
|
||||||
|
# Searches the regular expression.
|
||||||
|
#
|
||||||
|
# Sets an internal cache (match object) in order to avoid searching for
|
||||||
|
# the pattern again. This method must be called before calling any other
|
||||||
|
# method of this object.
|
||||||
|
# @param value the line
|
||||||
|
|
||||||
|
def search(self, value):
|
||||||
|
self._matchCache = self._regexObj.search(value)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Checks if the previous call to search() matched.
|
||||||
|
#
|
||||||
|
# @return True if a match was found, False otherwise
|
||||||
|
|
||||||
|
def hasMatched(self):
|
||||||
|
if self._matchCache:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Exception dedicated to the class Regex.
|
||||||
|
|
||||||
|
class RegexException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Regular expression class.
|
# Regular expression class.
|
||||||
|
@ -56,5 +123,8 @@ class FailRegex(Regex):
|
||||||
def getHost(self):
|
def getHost(self):
|
||||||
host = self._matchCache.group("host")
|
host = self._matchCache.group("host")
|
||||||
if host == None:
|
if host == None:
|
||||||
raise RegexException("Unexpected error. Please check your regex")
|
# Gets a few information.
|
||||||
|
s = self._matchCache.string
|
||||||
|
r = self._matchCache.re
|
||||||
|
raise RegexException("No 'host' found in '%s' using '%s'" % (s, r))
|
||||||
return host
|
return host
|
||||||
|
|
|
@ -1,37 +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 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)
|
|
||||||
|
|
400
server/filter.py
400
server/filter.py
|
@ -25,12 +25,11 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from failmanager import FailManager
|
from failmanager import FailManager
|
||||||
from failticket import FailTicket
|
from ticket import FailTicket
|
||||||
from jailthread import JailThread
|
from jailthread import JailThread
|
||||||
from datedetector import DateDetector
|
from datedetector import DateDetector
|
||||||
from mytime import MyTime
|
from mytime import MyTime
|
||||||
from regex import Regex, RegexException
|
from failregex import FailRegex, Regex, RegexException
|
||||||
from failregex import FailRegex
|
|
||||||
|
|
||||||
import logging, re
|
import logging, re
|
||||||
|
|
||||||
|
@ -58,11 +57,6 @@ class Filter(JailThread):
|
||||||
self.jail = jail
|
self.jail = jail
|
||||||
## The failures manager.
|
## The failures manager.
|
||||||
self.failManager = FailManager()
|
self.failManager = FailManager()
|
||||||
## The log file handler.
|
|
||||||
self.__crtHandler = None
|
|
||||||
self.__crtFilename = None
|
|
||||||
## The log file path.
|
|
||||||
self.__logPath = []
|
|
||||||
## The regular expression list matching the failures.
|
## The regular expression list matching the failures.
|
||||||
self.__failRegex = list()
|
self.__failRegex = list()
|
||||||
## The regular expression list with expressions to ignore.
|
## The regular expression list with expressions to ignore.
|
||||||
|
@ -71,92 +65,12 @@ class Filter(JailThread):
|
||||||
self.__findTime = 6000
|
self.__findTime = 6000
|
||||||
## The ignore IP list.
|
## The ignore IP list.
|
||||||
self.__ignoreIpList = []
|
self.__ignoreIpList = []
|
||||||
## The last position of the file.
|
|
||||||
self.__lastPos = dict()
|
|
||||||
## The last date in tht log file.
|
|
||||||
self.__lastDate = dict()
|
|
||||||
|
|
||||||
self.dateDetector = DateDetector()
|
self.dateDetector = DateDetector()
|
||||||
self.dateDetector.addDefaultTemplate()
|
self.dateDetector.addDefaultTemplate()
|
||||||
logSys.info("Created Filter")
|
logSys.info("Created Filter")
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Add a log file path
|
|
||||||
#
|
|
||||||
# @param path log file path
|
|
||||||
|
|
||||||
def addLogPath(self, path):
|
|
||||||
self.getLogPath().append(path)
|
|
||||||
# Initialize default values
|
|
||||||
self.__lastDate[path] = 0
|
|
||||||
self.__lastPos[path] = 0
|
|
||||||
|
|
||||||
##
|
|
||||||
# Delete a log path
|
|
||||||
#
|
|
||||||
# @param path the log file to delete
|
|
||||||
|
|
||||||
def delLogPath(self, path):
|
|
||||||
self.getLogPath().remove(path)
|
|
||||||
del self.__lastDate[path]
|
|
||||||
del self.__lastPos[path]
|
|
||||||
|
|
||||||
##
|
|
||||||
# Get the log file path
|
|
||||||
#
|
|
||||||
# @return log file path
|
|
||||||
|
|
||||||
def getLogPath(self):
|
|
||||||
return self.__logPath
|
|
||||||
|
|
||||||
##
|
|
||||||
# Check whether path is already monitored.
|
|
||||||
#
|
|
||||||
# @param path The path
|
|
||||||
# @return True if the path is already monitored else False
|
|
||||||
|
|
||||||
def containsLogPath(self, path):
|
|
||||||
try:
|
|
||||||
self.getLogPath().index(path)
|
|
||||||
return True
|
|
||||||
except ValueError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
##
|
|
||||||
# Set the regular expression which matches the time.
|
|
||||||
#
|
|
||||||
# @param value the regular expression
|
|
||||||
|
|
||||||
def setTimeRegex(self, value):
|
|
||||||
self.dateDetector.setDefaultRegex(value)
|
|
||||||
logSys.info("Set default regex = %s" % value)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Get the regular expression which matches the time.
|
|
||||||
#
|
|
||||||
# @return the regular expression
|
|
||||||
|
|
||||||
def getTimeRegex(self):
|
|
||||||
return self.dateDetector.getDefaultRegex()
|
|
||||||
|
|
||||||
##
|
|
||||||
# Set the time pattern.
|
|
||||||
#
|
|
||||||
# @param value the time pattern
|
|
||||||
|
|
||||||
def setTimePattern(self, value):
|
|
||||||
self.dateDetector.setDefaultPattern(value)
|
|
||||||
logSys.info("Set default pattern = %s" % value)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Get the time pattern.
|
|
||||||
#
|
|
||||||
# @return the time pattern
|
|
||||||
|
|
||||||
def getTimePattern(self):
|
|
||||||
return self.dateDetector.getDefaultPattern()
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Add a regular expression which matches the failure.
|
# Add a regular expression which matches the failure.
|
||||||
#
|
#
|
||||||
|
@ -267,7 +181,7 @@ class Filter(JailThread):
|
||||||
# @return True when the thread exits nicely
|
# @return True when the thread exits nicely
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
raise NotImplementedException("run() is abstract")
|
raise Exception("run() is abstract")
|
||||||
|
|
||||||
##
|
##
|
||||||
# Add an IP/DNS to the ignore list.
|
# Add an IP/DNS to the ignore list.
|
||||||
|
@ -299,7 +213,7 @@ class Filter(JailThread):
|
||||||
for i in self.__ignoreIpList:
|
for i in self.__ignoreIpList:
|
||||||
# An empty string is always false
|
# An empty string is always false
|
||||||
if i == "":
|
if i == "":
|
||||||
return False
|
continue
|
||||||
s = i.split('/', 1)
|
s = i.split('/', 1)
|
||||||
# IP address without CIDR mask
|
# IP address without CIDR mask
|
||||||
if len(s) == 1:
|
if len(s) == 1:
|
||||||
|
@ -314,130 +228,79 @@ class Filter(JailThread):
|
||||||
if ip in ips:
|
if ip in ips:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
continue
|
||||||
if a == b:
|
if a == b:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
##
|
|
||||||
# Open the log file.
|
def processLine(self, line):
|
||||||
|
|
||||||
def __openLogFile(self, filename):
|
|
||||||
""" Opens the log file specified on init.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
self.__crtFilename = filename
|
# Decode line to UTF-8
|
||||||
self.__crtHandler = open(filename)
|
l = line.decode('utf-8')
|
||||||
logSys.debug("Opened " + filename)
|
except UnicodeDecodeError:
|
||||||
return True
|
l = line
|
||||||
except OSError:
|
timeMatch = self.dateDetector.matchTime(l)
|
||||||
logSys.error("Unable to open " + filename)
|
if not timeMatch:
|
||||||
except IOError:
|
# There is no valid time in this line
|
||||||
logSys.error("Unable to read " + filename +
|
return []
|
||||||
". Please check permissions")
|
# Lets split into time part and log part of the line
|
||||||
return False
|
timeLine = timeMatch.group()
|
||||||
|
# Lets leave the beginning in as well, so if there is no
|
||||||
##
|
# anchore at the beginning of the time regexp, we don't
|
||||||
# Close the log file.
|
# at least allow injection. Should be harmless otherwise
|
||||||
|
logLine = l[:timeMatch.start()] + l[timeMatch.end():]
|
||||||
def __closeLogFile(self):
|
return self.findFailure(timeLine, logLine)
|
||||||
self.__crtFilename = None
|
|
||||||
self.__crtHandler.close()
|
|
||||||
|
|
||||||
##
|
def processLineAndAdd(self, line):
|
||||||
# Set the file position.
|
for element in self.processLine(line):
|
||||||
#
|
ip = element[0]
|
||||||
# Sets the file position. We must take care of log file rotation
|
unixTime = element[1]
|
||||||
# and reset the position to 0 in that case. Use the log message
|
if unixTime < MyTime.time() - self.getFindTime():
|
||||||
# timestamp in order to detect this.
|
|
||||||
|
|
||||||
def __setFilePos(self):
|
|
||||||
line = self.__crtHandler.readline()
|
|
||||||
lastDate = self.__lastDate[self.__crtFilename]
|
|
||||||
lineDate = self.dateDetector.getUnixTime(line)
|
|
||||||
if lastDate < lineDate:
|
|
||||||
logSys.debug("Date " + `lastDate` + " is smaller than " + `lineDate`)
|
|
||||||
logSys.debug("Log rotation detected for " + self.__crtFilename)
|
|
||||||
self.__lastPos[self.__crtFilename] = 0
|
|
||||||
lastPos = self.__lastPos[self.__crtFilename]
|
|
||||||
logSys.debug("Setting file position to " + `lastPos` + " for " +
|
|
||||||
self.__crtFilename)
|
|
||||||
self.__crtHandler.seek(lastPos)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Get the file position.
|
|
||||||
|
|
||||||
def __getFilePos(self):
|
|
||||||
return self.__crtHandler.tell()
|
|
||||||
|
|
||||||
##
|
|
||||||
# Gets all the failure in the log file.
|
|
||||||
#
|
|
||||||
# Gets all the failure in the log file which are newer than
|
|
||||||
# MyTime.time()-self.findTime. When a failure is detected, a FailTicket
|
|
||||||
# is created and is added to the FailManager.
|
|
||||||
|
|
||||||
def getFailures(self, filename):
|
|
||||||
# Try to open log file.
|
|
||||||
if not self.__openLogFile(filename):
|
|
||||||
logSys.error("Unable to get failures in " + filename)
|
|
||||||
return False
|
|
||||||
self.__setFilePos()
|
|
||||||
lastLine = None
|
|
||||||
for line in self.__crtHandler:
|
|
||||||
if not self._isActive():
|
|
||||||
# The jail has been stopped
|
|
||||||
break
|
break
|
||||||
try:
|
if self.inIgnoreIPList(ip):
|
||||||
# Decode line to UTF-8
|
logSys.debug("Ignore %s" % ip)
|
||||||
line = line.decode('utf-8')
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
pass
|
|
||||||
if not self.dateDetector.matchTime(line):
|
|
||||||
# There is no valid time in this line
|
|
||||||
continue
|
continue
|
||||||
lastLine = line
|
logSys.debug("Found %s" % ip)
|
||||||
for element in self.findFailure(line):
|
self.failManager.addFailure(FailTicket(ip, unixTime))
|
||||||
ip = element[0]
|
|
||||||
unixTime = element[1]
|
|
||||||
if unixTime < MyTime.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[filename] = self.__getFilePos()
|
|
||||||
if lastLine:
|
|
||||||
self.__lastDate[filename] = self.dateDetector.getUnixTime(lastLine)
|
|
||||||
self.__closeLogFile()
|
|
||||||
return True
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Finds the failure in a line.
|
# Returns true if the line should be ignored.
|
||||||
|
#
|
||||||
|
# Uses ignoreregex.
|
||||||
|
# @param line: the line
|
||||||
|
# @return: a boolean
|
||||||
|
|
||||||
|
def ignoreLine(self, line):
|
||||||
|
for ignoreRegex in self.__ignoreRegex:
|
||||||
|
ignoreRegex.search(line)
|
||||||
|
if ignoreRegex.hasMatched():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
##
|
||||||
|
# Finds the failure in a line given split into time and log parts.
|
||||||
#
|
#
|
||||||
# Uses the failregex pattern to find it and timeregex in order
|
# Uses the failregex pattern to find it and timeregex in order
|
||||||
# to find the logging time.
|
# to find the logging time.
|
||||||
# @return a dict with IP and timestamp.
|
# @return a dict with IP and timestamp.
|
||||||
|
|
||||||
def findFailure(self, line):
|
def findFailure(self, timeLine, logLine):
|
||||||
failList = list()
|
failList = list()
|
||||||
# Checks if we must ignore this line.
|
# Checks if we must ignore this line.
|
||||||
for ignoreRegex in self.__ignoreRegex:
|
if self.ignoreLine(logLine):
|
||||||
ignoreRegex.search(line)
|
# The ignoreregex matched. Return.
|
||||||
if ignoreRegex.hasMatched():
|
return failList
|
||||||
# The ignoreregex matched. Return.
|
|
||||||
logSys.debug("Ignoring this line")
|
|
||||||
return failList
|
|
||||||
# Iterates over all the regular expressions.
|
# Iterates over all the regular expressions.
|
||||||
for failRegex in self.__failRegex:
|
for failRegex in self.__failRegex:
|
||||||
failRegex.search(line)
|
failRegex.search(logLine)
|
||||||
if failRegex.hasMatched():
|
if failRegex.hasMatched():
|
||||||
# The failregex matched.
|
# The failregex matched.
|
||||||
date = self.dateDetector.getUnixTime(line)
|
date = self.dateDetector.getUnixTime(timeLine)
|
||||||
if date == None:
|
if date == None:
|
||||||
logSys.debug("Found a match but no valid date/time found "
|
logSys.debug("Found a match for '" + logLine +"' but no "
|
||||||
+ "for " + line + ". Please contact the "
|
+ "valid date/time found for '"
|
||||||
|
+ timeLine + "'. Please contact the "
|
||||||
+ "author in order to get support for this "
|
+ "author in order to get support for this "
|
||||||
+ "format")
|
+ "format")
|
||||||
else:
|
else:
|
||||||
|
@ -467,6 +330,157 @@ class Filter(JailThread):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class FileFilter(Filter):
|
||||||
|
|
||||||
|
def __init__(self, jail):
|
||||||
|
Filter.__init__(self, jail)
|
||||||
|
## The log file path.
|
||||||
|
self.__logPath = []
|
||||||
|
|
||||||
|
##
|
||||||
|
# Add a log file path
|
||||||
|
#
|
||||||
|
# @param path log file path
|
||||||
|
|
||||||
|
def addLogPath(self, path, tail = False):
|
||||||
|
container = FileContainer(path, tail)
|
||||||
|
self.__logPath.append(container)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Delete a log path
|
||||||
|
#
|
||||||
|
# @param path the log file to delete
|
||||||
|
|
||||||
|
def delLogPath(self, path):
|
||||||
|
for log in self.__logPath:
|
||||||
|
if log.getFileName() == path:
|
||||||
|
self.__logPath.remove(log)
|
||||||
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Get the log file path
|
||||||
|
#
|
||||||
|
# @return log file path
|
||||||
|
|
||||||
|
def getLogPath(self):
|
||||||
|
return self.__logPath
|
||||||
|
|
||||||
|
##
|
||||||
|
# Check whether path is already monitored.
|
||||||
|
#
|
||||||
|
# @param path The path
|
||||||
|
# @return True if the path is already monitored else False
|
||||||
|
|
||||||
|
def containsLogPath(self, path):
|
||||||
|
for log in self.__logPath:
|
||||||
|
if log.getFileName() == path:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def getFileContainer(self, path):
|
||||||
|
for log in self.__logPath:
|
||||||
|
if log.getFileName() == path:
|
||||||
|
return log
|
||||||
|
return None
|
||||||
|
|
||||||
|
##
|
||||||
|
# Gets all the failure in the log file.
|
||||||
|
#
|
||||||
|
# Gets all the failure in the log file which are newer than
|
||||||
|
# MyTime.time()-self.findTime. When a failure is detected, a FailTicket
|
||||||
|
# is created and is added to the FailManager.
|
||||||
|
|
||||||
|
def getFailures(self, filename):
|
||||||
|
container = self.getFileContainer(filename)
|
||||||
|
if container == None:
|
||||||
|
logSys.error("Unable to get failures in " + filename)
|
||||||
|
return False
|
||||||
|
# Try to open log file.
|
||||||
|
try:
|
||||||
|
container.open()
|
||||||
|
except Exception, e:
|
||||||
|
logSys.error("Unable to open %s" % filename)
|
||||||
|
logSys.exception(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
line = container.readline()
|
||||||
|
while not line == "":
|
||||||
|
if not self._isActive():
|
||||||
|
# The jail has been stopped
|
||||||
|
break
|
||||||
|
self.processLineAndAdd(line)
|
||||||
|
# Read a new line.
|
||||||
|
line = container.readline()
|
||||||
|
container.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
ret = Filter.status(self)
|
||||||
|
path = [m.getFileName() for m in self.getLogPath()]
|
||||||
|
ret.append(("File list", path))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
##
|
||||||
|
# FileContainer class.
|
||||||
|
#
|
||||||
|
# This class manages a file handler and takes care of log rotation detection.
|
||||||
|
# In order to detect log rotation, the hash (MD5) of the first line of the file
|
||||||
|
# is computed and compared to the previous hash of this line.
|
||||||
|
|
||||||
|
import md5
|
||||||
|
|
||||||
|
class FileContainer:
|
||||||
|
|
||||||
|
def __init__(self, filename, tail = False):
|
||||||
|
self.__filename = filename
|
||||||
|
self.__tail = tail
|
||||||
|
self.__handler = None
|
||||||
|
# Try to open the file. Raises an exception if an error occured.
|
||||||
|
handler = open(filename)
|
||||||
|
try:
|
||||||
|
firstLine = handler.readline()
|
||||||
|
# Computes the MD5 of the first line.
|
||||||
|
self.__hash = md5.new(firstLine).digest()
|
||||||
|
# Start at the beginning of file if tail mode is off.
|
||||||
|
if tail:
|
||||||
|
handler.seek(0, 2)
|
||||||
|
self.__pos = handler.tell()
|
||||||
|
else:
|
||||||
|
self.__pos = 0
|
||||||
|
finally:
|
||||||
|
handler.close()
|
||||||
|
|
||||||
|
def getFileName(self):
|
||||||
|
return self.__filename
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
self.__handler = open(self.__filename)
|
||||||
|
firstLine = self.__handler.readline()
|
||||||
|
# Computes the MD5 of the first line.
|
||||||
|
myHash = md5.new(firstLine).digest()
|
||||||
|
# Compare hash.
|
||||||
|
if not self.__hash == myHash:
|
||||||
|
logSys.info("Log rotation detected for %s" % self.__filename)
|
||||||
|
self.__hash = myHash
|
||||||
|
self.__pos = 0
|
||||||
|
# Sets the file pointer to the last position.
|
||||||
|
self.__handler.seek(self.__pos)
|
||||||
|
|
||||||
|
def readline(self):
|
||||||
|
if self.__handler == None:
|
||||||
|
return ""
|
||||||
|
return self.__handler.readline()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if not self.__handler == None:
|
||||||
|
# Saves the last position.
|
||||||
|
self.__pos = self.__handler.tell()
|
||||||
|
# Closes the file.
|
||||||
|
self.__handler.close()
|
||||||
|
self.__handler = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Utils class for DNS and IP handling.
|
# Utils class for DNS and IP handling.
|
||||||
#
|
#
|
||||||
|
@ -477,8 +491,6 @@ import socket, struct
|
||||||
|
|
||||||
class DNSUtils:
|
class DNSUtils:
|
||||||
|
|
||||||
#DNS_CRE = re.compile("(?:(?:\w|-)+\.){2,}\w+")
|
|
||||||
DNS_CRE = re.compile("\S+")
|
|
||||||
IP_CRE = re.compile("(?:\d{1,3}\.){3}\d{1,3}")
|
IP_CRE = re.compile("(?:\d{1,3}\.){3}\d{1,3}")
|
||||||
|
|
||||||
#@staticmethod
|
#@staticmethod
|
||||||
|
|
|
@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from failmanager import FailManagerEmpty
|
from failmanager import FailManagerEmpty
|
||||||
from filter import Filter
|
from filter import FileFilter
|
||||||
from mytime import MyTime
|
from mytime import MyTime
|
||||||
|
|
||||||
import time, logging, gamin
|
import time, logging, gamin
|
||||||
|
@ -40,7 +40,7 @@ logSys = logging.getLogger("fail2ban.filter")
|
||||||
# that matches a given regular expression. This class is instanciated by
|
# that matches a given regular expression. This class is instanciated by
|
||||||
# a Jail object.
|
# a Jail object.
|
||||||
|
|
||||||
class FilterGamin(Filter):
|
class FilterGamin(FileFilter):
|
||||||
|
|
||||||
##
|
##
|
||||||
# Constructor.
|
# Constructor.
|
||||||
|
@ -49,7 +49,7 @@ class FilterGamin(Filter):
|
||||||
# @param jail the jail object
|
# @param jail the jail object
|
||||||
|
|
||||||
def __init__(self, jail):
|
def __init__(self, jail):
|
||||||
Filter.__init__(self, jail)
|
FileFilter.__init__(self, jail)
|
||||||
self.__modified = False
|
self.__modified = False
|
||||||
# Gamin monitor
|
# Gamin monitor
|
||||||
self.monitor = gamin.WatchMonitor()
|
self.monitor = gamin.WatchMonitor()
|
||||||
|
@ -69,12 +69,12 @@ class FilterGamin(Filter):
|
||||||
#
|
#
|
||||||
# @param path log file path
|
# @param path log file path
|
||||||
|
|
||||||
def addLogPath(self, path):
|
def addLogPath(self, path, tail = False):
|
||||||
if self.containsLogPath(path):
|
if self.containsLogPath(path):
|
||||||
logSys.error(path + " already exists")
|
logSys.error(path + " already exists")
|
||||||
else:
|
else:
|
||||||
self.monitor.watch_file(path, self.callback)
|
self.monitor.watch_file(path, self.callback)
|
||||||
Filter.addLogPath(self, path)
|
FileFilter.addLogPath(self, path, tail)
|
||||||
logSys.info("Added logfile = %s" % path)
|
logSys.info("Added logfile = %s" % path)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -87,7 +87,7 @@ class FilterGamin(Filter):
|
||||||
logSys.error(path + " is not monitored")
|
logSys.error(path + " is not monitored")
|
||||||
else:
|
else:
|
||||||
self.monitor.stop_watch(path)
|
self.monitor.stop_watch(path)
|
||||||
Filter.delLogPath(self, path)
|
FileFilter.delLogPath(self, path)
|
||||||
logSys.info("Removed logfile = %s" % path)
|
logSys.info("Removed logfile = %s" % path)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -108,8 +108,9 @@ class FilterGamin(Filter):
|
||||||
|
|
||||||
if self.__modified:
|
if self.__modified:
|
||||||
try:
|
try:
|
||||||
ticket = self.failManager.toBan()
|
while True:
|
||||||
self.jail.putFailTicket(ticket)
|
ticket = self.failManager.toBan()
|
||||||
|
self.jail.putFailTicket(ticket)
|
||||||
except FailManagerEmpty:
|
except FailManagerEmpty:
|
||||||
self.failManager.cleanup(MyTime.time())
|
self.failManager.cleanup(MyTime.time())
|
||||||
self.dateDetector.sortTemplate()
|
self.dateDetector.sortTemplate()
|
||||||
|
@ -126,6 +127,6 @@ class FilterGamin(Filter):
|
||||||
# Desallocates the resources used by Gamin.
|
# Desallocates the resources used by Gamin.
|
||||||
|
|
||||||
def __cleanup(self):
|
def __cleanup(self):
|
||||||
for path in Filter.getLogPath(self):
|
for path in self.getLogPath():
|
||||||
self.monitor.stop_watch(path)
|
self.monitor.stop_watch(path.getFileName())
|
||||||
del self.monitor
|
del self.monitor
|
||||||
|
|
|
@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from failmanager import FailManagerEmpty
|
from failmanager import FailManagerEmpty
|
||||||
from filter import Filter
|
from filter import FileFilter
|
||||||
from mytime import MyTime
|
from mytime import MyTime
|
||||||
|
|
||||||
import time, logging, os
|
import time, logging, os
|
||||||
|
@ -40,7 +40,7 @@ logSys = logging.getLogger("fail2ban.filter")
|
||||||
# that matches a given regular expression. This class is instanciated by
|
# that matches a given regular expression. This class is instanciated by
|
||||||
# a Jail object.
|
# a Jail object.
|
||||||
|
|
||||||
class FilterPoll(Filter):
|
class FilterPoll(FileFilter):
|
||||||
|
|
||||||
##
|
##
|
||||||
# Constructor.
|
# Constructor.
|
||||||
|
@ -49,7 +49,7 @@ class FilterPoll(Filter):
|
||||||
# @param jail the jail object
|
# @param jail the jail object
|
||||||
|
|
||||||
def __init__(self, jail):
|
def __init__(self, jail):
|
||||||
Filter.__init__(self, jail)
|
FileFilter.__init__(self, jail)
|
||||||
self.__modified = False
|
self.__modified = False
|
||||||
## The time of the last modification of the file.
|
## The time of the last modification of the file.
|
||||||
self.__lastModTime = dict()
|
self.__lastModTime = dict()
|
||||||
|
@ -61,13 +61,13 @@ class FilterPoll(Filter):
|
||||||
#
|
#
|
||||||
# @param path log file path
|
# @param path log file path
|
||||||
|
|
||||||
def addLogPath(self, path):
|
def addLogPath(self, path, tail = False):
|
||||||
if self.containsLogPath(path):
|
if self.containsLogPath(path):
|
||||||
logSys.error(path + " already exists")
|
logSys.error(path + " already exists")
|
||||||
else:
|
else:
|
||||||
self.__lastModTime[path] = 0
|
self.__lastModTime[path] = 0
|
||||||
self.__file404Cnt[path] = 0
|
self.__file404Cnt[path] = 0
|
||||||
Filter.addLogPath(self, path)
|
FileFilter.addLogPath(self, path, tail)
|
||||||
logSys.info("Added logfile = %s" % path)
|
logSys.info("Added logfile = %s" % path)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -81,7 +81,7 @@ class FilterPoll(Filter):
|
||||||
else:
|
else:
|
||||||
del self.__lastModTime[path]
|
del self.__lastModTime[path]
|
||||||
del self.__file404Cnt[path]
|
del self.__file404Cnt[path]
|
||||||
Filter.delLogPath(self, path)
|
FileFilter.delLogPath(self, path)
|
||||||
logSys.info("Removed logfile = %s" % path)
|
logSys.info("Removed logfile = %s" % path)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -96,15 +96,16 @@ class FilterPoll(Filter):
|
||||||
while self._isActive():
|
while self._isActive():
|
||||||
if not self.getIdle():
|
if not self.getIdle():
|
||||||
# Get file modification
|
# Get file modification
|
||||||
for f in self.getLogPath():
|
for container in self.getLogPath():
|
||||||
if self.isModified(f):
|
if self.isModified(container.getFileName()):
|
||||||
self.getFailures(f)
|
self.getFailures(container.getFileName())
|
||||||
self.__modified = True
|
self.__modified = True
|
||||||
|
|
||||||
if self.__modified:
|
if self.__modified:
|
||||||
try:
|
try:
|
||||||
ticket = self.failManager.toBan()
|
while True:
|
||||||
self.jail.putFailTicket(ticket)
|
ticket = self.failManager.toBan()
|
||||||
|
self.jail.putFailTicket(ticket)
|
||||||
except FailManagerEmpty:
|
except FailManagerEmpty:
|
||||||
self.failManager.cleanup(MyTime.time())
|
self.failManager.cleanup(MyTime.time())
|
||||||
self.dateDetector.sortTemplate()
|
self.dateDetector.sortTemplate()
|
||||||
|
|
|
@ -1,93 +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 re, sre_constants
|
|
||||||
|
|
||||||
##
|
|
||||||
# Regular expression class.
|
|
||||||
#
|
|
||||||
# This class represents a regular expression with its compiled version.
|
|
||||||
|
|
||||||
class Regex:
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructor.
|
|
||||||
#
|
|
||||||
# Creates a new object. This method can throw RegexException in order to
|
|
||||||
# avoid construction of invalid object.
|
|
||||||
# @param value the regular expression
|
|
||||||
|
|
||||||
def __init__(self, regex):
|
|
||||||
self._matchCache = None
|
|
||||||
# Perform shortcuts expansions
|
|
||||||
# Replace "<HOST>" with default regular expression for host.
|
|
||||||
regex = regex.replace("<HOST>", "(?:::f{4,6}:)?(?P<host>\S+)")
|
|
||||||
if regex.lstrip() == '':
|
|
||||||
raise RegexException("Cannot add empty regex")
|
|
||||||
try:
|
|
||||||
self._regexObj = re.compile(regex)
|
|
||||||
self._regex = regex
|
|
||||||
except sre_constants.error:
|
|
||||||
raise RegexException("Unable to compile regular expression '%s'" %
|
|
||||||
regex)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Gets the regular expression.
|
|
||||||
#
|
|
||||||
# The effective regular expression used is returned.
|
|
||||||
# @return the regular expression
|
|
||||||
|
|
||||||
def getRegex(self):
|
|
||||||
return self._regex
|
|
||||||
|
|
||||||
##
|
|
||||||
# Searches the regular expression.
|
|
||||||
#
|
|
||||||
# Sets an internal cache (match object) in order to avoid searching for
|
|
||||||
# the pattern again. This method must be called before calling any other
|
|
||||||
# method of this object.
|
|
||||||
# @param value the line
|
|
||||||
|
|
||||||
def search(self, value):
|
|
||||||
self._matchCache = self._regexObj.search(value)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Checks if the previous call to search() matched.
|
|
||||||
#
|
|
||||||
# @return True if a match was found, False otherwise
|
|
||||||
|
|
||||||
def hasMatched(self):
|
|
||||||
if self._matchCache:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Exception dedicated to the class Regex.
|
|
||||||
|
|
||||||
class RegexException(Exception):
|
|
||||||
pass
|
|
|
@ -27,14 +27,17 @@ __license__ = "GPL"
|
||||||
from threading import Lock, RLock
|
from threading import Lock, RLock
|
||||||
from jails import Jails
|
from jails import Jails
|
||||||
from transmitter import Transmitter
|
from transmitter import Transmitter
|
||||||
from communication.asyncserver import AsyncServer
|
from asyncserver import AsyncServer
|
||||||
from communication.asyncserver import AsyncServerException
|
from asyncserver import AsyncServerException
|
||||||
|
from common import version
|
||||||
import logging, logging.handlers, sys, os, signal
|
import logging, logging.handlers, sys, os, signal
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.server")
|
logSys = logging.getLogger("fail2ban.server")
|
||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
|
|
||||||
|
PID_FILE = "/var/run/fail2ban/fail2ban.pid"
|
||||||
|
|
||||||
def __init__(self, daemon = False):
|
def __init__(self, daemon = False):
|
||||||
self.__loggingLock = Lock()
|
self.__loggingLock = Lock()
|
||||||
|
@ -54,7 +57,7 @@ class Server:
|
||||||
self.quit()
|
self.quit()
|
||||||
|
|
||||||
def start(self, sock, force = False):
|
def start(self, sock, force = False):
|
||||||
logSys.info("Starting Fail2ban")
|
logSys.info("Starting Fail2ban v" + version.version)
|
||||||
|
|
||||||
# Install signal handlers
|
# Install signal handlers
|
||||||
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
|
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
|
||||||
|
@ -69,18 +72,40 @@ class Server:
|
||||||
else:
|
else:
|
||||||
logSys.error("Could not create daemon")
|
logSys.error("Could not create daemon")
|
||||||
raise ServerInitializationError("Could not create daemon")
|
raise ServerInitializationError("Could not create daemon")
|
||||||
|
|
||||||
|
# Creates a PID file.
|
||||||
|
try:
|
||||||
|
logSys.debug("Creating PID file %s" % Server.PID_FILE)
|
||||||
|
pidFile = open(Server.PID_FILE, 'w')
|
||||||
|
pidFile.write("%s\n" % os.getpid())
|
||||||
|
pidFile.close()
|
||||||
|
except IOError, e:
|
||||||
|
logSys.error("Unable to create PID file: %s" % e)
|
||||||
|
|
||||||
# Start the communication
|
# Start the communication
|
||||||
logSys.debug("Starting communication")
|
logSys.debug("Starting communication")
|
||||||
try:
|
try:
|
||||||
self.__asyncServer.start(sock, force)
|
self.__asyncServer.start(sock, force)
|
||||||
except AsyncServerException:
|
except AsyncServerException, e:
|
||||||
logSys.error("Could not start server")
|
logSys.error("Could not start server: %s", e)
|
||||||
|
# Removes the PID file.
|
||||||
|
try:
|
||||||
|
logSys.debug("Remove PID file %s" % Server.PID_FILE)
|
||||||
|
os.remove(Server.PID_FILE)
|
||||||
|
except OSError, e:
|
||||||
|
logSys.error("Unable to remove PID file: %s" % e)
|
||||||
logSys.info("Exiting Fail2ban")
|
logSys.info("Exiting Fail2ban")
|
||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
self.stopAllJail()
|
self.stopAllJail()
|
||||||
# Stop communication
|
# Stop communication
|
||||||
self.__asyncServer.stop()
|
self.__asyncServer.stop()
|
||||||
|
# Shutdowns the logging.
|
||||||
|
try:
|
||||||
|
self.__loggingLock.acquire()
|
||||||
|
logging.shutdown()
|
||||||
|
finally:
|
||||||
|
self.__loggingLock.release()
|
||||||
|
|
||||||
def addJail(self, name, backend):
|
def addJail(self, name, backend):
|
||||||
self.__jails.add(name, backend)
|
self.__jails.add(name, backend)
|
||||||
|
@ -140,19 +165,8 @@ class Server:
|
||||||
self.__jails.getFilter(name).delLogPath(fileName)
|
self.__jails.getFilter(name).delLogPath(fileName)
|
||||||
|
|
||||||
def getLogPath(self, name):
|
def getLogPath(self, name):
|
||||||
return self.__jails.getFilter(name).getLogPath()
|
return [m.getFileName()
|
||||||
|
for m in self.__jails.getFilter(name).getLogPath()]
|
||||||
def setTimeRegex(self, name, value):
|
|
||||||
self.__jails.getFilter(name).setTimeRegex(value)
|
|
||||||
|
|
||||||
def getTimeRegex(self, name):
|
|
||||||
return self.__jails.getFilter(name).getTimeRegex()
|
|
||||||
|
|
||||||
def setTimePattern(self, name, value):
|
|
||||||
self.__jails.getFilter(name).setTimePattern(value)
|
|
||||||
|
|
||||||
def getTimePattern(self, name):
|
|
||||||
return self.__jails.getFilter(name).getTimePattern()
|
|
||||||
|
|
||||||
def setFindTime(self, name, value):
|
def setFindTime(self, name, value):
|
||||||
self.__jails.getFilter(name).setFindTime(value)
|
self.__jails.getFilter(name).setFindTime(value)
|
||||||
|
@ -310,7 +324,11 @@ class Server:
|
||||||
def setLogTarget(self, target):
|
def setLogTarget(self, target):
|
||||||
try:
|
try:
|
||||||
self.__loggingLock.acquire()
|
self.__loggingLock.acquire()
|
||||||
|
# set a format which is simpler for console use
|
||||||
|
formatter = logging.Formatter("%(asctime)s %(name)-16s: %(levelname)-6s %(message)s")
|
||||||
if target == "SYSLOG":
|
if target == "SYSLOG":
|
||||||
|
# Syslog daemons already add date to the message.
|
||||||
|
formatter = logging.Formatter("%(name)-16s: %(levelname)-6s %(message)s")
|
||||||
facility = logging.handlers.SysLogHandler.LOG_DAEMON
|
facility = logging.handlers.SysLogHandler.LOG_DAEMON
|
||||||
hdlr = logging.handlers.SysLogHandler("/dev/log",
|
hdlr = logging.handlers.SysLogHandler("/dev/log",
|
||||||
facility = facility)
|
facility = facility)
|
||||||
|
@ -331,10 +349,8 @@ class Server:
|
||||||
# Removes previous handlers
|
# Removes previous handlers
|
||||||
for handler in logging.getLogger("fail2ban").handlers:
|
for handler in logging.getLogger("fail2ban").handlers:
|
||||||
# Closes the handler.
|
# Closes the handler.
|
||||||
handler.close()
|
|
||||||
logging.getLogger("fail2ban").removeHandler(handler)
|
logging.getLogger("fail2ban").removeHandler(handler)
|
||||||
# set a format which is simpler for console use
|
handler.close()
|
||||||
formatter = logging.Formatter("%(asctime)s %(name)-16s: %(levelname)-6s %(message)s")
|
|
||||||
# tell the handler to use this format
|
# tell the handler to use this format
|
||||||
hdlr.setFormatter(formatter)
|
hdlr.setFormatter(formatter)
|
||||||
logging.getLogger("fail2ban").addHandler(hdlr)
|
logging.getLogger("fail2ban").addHandler(hdlr)
|
||||||
|
|
|
@ -53,4 +53,28 @@ class Ticket:
|
||||||
|
|
||||||
def getAttempt(self):
|
def getAttempt(self):
|
||||||
return self.__attempt
|
return self.__attempt
|
||||||
|
|
||||||
|
|
||||||
|
class FailTicket(Ticket):
|
||||||
|
|
||||||
|
def __init__(self, ip, time):
|
||||||
|
Ticket.__init__(self, ip, time)
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# 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)
|
||||||
|
|
|
@ -135,14 +135,6 @@ class Transmitter:
|
||||||
value = command[2]
|
value = command[2]
|
||||||
self.__server.delLogPath(name, value)
|
self.__server.delLogPath(name, value)
|
||||||
return self.__server.getLogPath(name)
|
return self.__server.getLogPath(name)
|
||||||
elif command[1] == "timeregex":
|
|
||||||
value = command[2]
|
|
||||||
self.__server.setTimeRegex(name, value)
|
|
||||||
return self.__server.getTimeRegex(name)
|
|
||||||
elif command[1] == "timepattern":
|
|
||||||
value = command[2]
|
|
||||||
self.__server.setTimePattern(name, value)
|
|
||||||
return self.__server.getTimePattern(name)
|
|
||||||
elif command[1] == "addfailregex":
|
elif command[1] == "addfailregex":
|
||||||
value = command[2]
|
value = command[2]
|
||||||
self.__server.addFailRegex(name, value)
|
self.__server.addFailRegex(name, value)
|
||||||
|
@ -229,10 +221,6 @@ class Transmitter:
|
||||||
return self.__server.getLogPath(name)
|
return self.__server.getLogPath(name)
|
||||||
elif command[1] == "ignoreip":
|
elif command[1] == "ignoreip":
|
||||||
return self.__server.getIgnoreIP(name)
|
return self.__server.getIgnoreIP(name)
|
||||||
elif command[1] == "timeregex":
|
|
||||||
return self.__server.getTimeRegex(name)
|
|
||||||
elif command[1] == "timepattern":
|
|
||||||
return self.__server.getTimePattern(name)
|
|
||||||
elif command[1] == "failregex":
|
elif command[1] == "failregex":
|
||||||
return self.__server.getFailRegex(name)
|
return self.__server.getFailRegex(name)
|
||||||
elif command[1] == "ignoreregex":
|
elif command[1] == "ignoreregex":
|
||||||
|
|
10
setup.py
10
setup.py
|
@ -45,8 +45,8 @@ setup(
|
||||||
description = "Ban IPs that make too many password failure",
|
description = "Ban IPs that make too many password failure",
|
||||||
long_description = longdesc,
|
long_description = longdesc,
|
||||||
author = "Cyril Jaquier",
|
author = "Cyril Jaquier",
|
||||||
author_email = "lostcontrol@users.sourceforge.net",
|
author_email = "cyril.jaquier@fail2ban.org",
|
||||||
url = "http://fail2ban.sourceforge.net",
|
url = "http://www.fail2ban.org",
|
||||||
license = "GPL",
|
license = "GPL",
|
||||||
platforms = "Posix",
|
platforms = "Posix",
|
||||||
scripts = [
|
scripts = [
|
||||||
|
@ -57,8 +57,7 @@ setup(
|
||||||
packages = [
|
packages = [
|
||||||
'common',
|
'common',
|
||||||
'client',
|
'client',
|
||||||
'server',
|
'server'
|
||||||
'server/communication'
|
|
||||||
],
|
],
|
||||||
data_files = [
|
data_files = [
|
||||||
('/etc/fail2ban',
|
('/etc/fail2ban',
|
||||||
|
@ -69,6 +68,9 @@ setup(
|
||||||
),
|
),
|
||||||
('/etc/fail2ban/action.d',
|
('/etc/fail2ban/action.d',
|
||||||
glob("config/action.d/*.conf")
|
glob("config/action.d/*.conf")
|
||||||
|
),
|
||||||
|
('/var/run/fail2ban',
|
||||||
|
''
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -43,5 +43,5 @@ class ExecuteAction(unittest.TestCase):
|
||||||
self.__action.setActionBan("echo -n")
|
self.__action.setActionBan("echo -n")
|
||||||
self.__action.setActionCheck("[ -e /tmp/fail2ban.test ]")
|
self.__action.setActionCheck("[ -e /tmp/fail2ban.test ]")
|
||||||
|
|
||||||
self.failUnless(self.__action.execActionBan(None))
|
self.assertTrue(self.__action.execActionBan(None))
|
||||||
|
|
|
@ -24,9 +24,9 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest, socket, time, pickle
|
import unittest
|
||||||
from server.banmanager import BanManager
|
from server.banmanager import BanManager
|
||||||
from server.banticket import BanTicket
|
from server.ticket import BanTicket
|
||||||
|
|
||||||
class AddFailure(unittest.TestCase):
|
class AddFailure(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class AddFailure(unittest.TestCase):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
self.__ticket = BanTicket('193.168.0.128', 1167605999.0)
|
self.__ticket = BanTicket('193.168.0.128', 1167605999.0)
|
||||||
self.__banManager = BanManager()
|
self.__banManager = BanManager()
|
||||||
self.failUnless(self.__banManager.addBanTicket(self.__ticket))
|
self.assertTrue(self.__banManager.addBanTicket(self.__ticket))
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Call after every test case."""
|
"""Call after every test case."""
|
||||||
|
@ -43,14 +43,14 @@ class AddFailure(unittest.TestCase):
|
||||||
self.assertEqual(self.__banManager.size(), 1)
|
self.assertEqual(self.__banManager.size(), 1)
|
||||||
|
|
||||||
def testAddDuplicate(self):
|
def testAddDuplicate(self):
|
||||||
self.failIf(self.__banManager.addBanTicket(self.__ticket))
|
self.assertFalse(self.__banManager.addBanTicket(self.__ticket))
|
||||||
self.assertEqual(self.__banManager.size(), 1)
|
self.assertEqual(self.__banManager.size(), 1)
|
||||||
|
|
||||||
def _testInListOK(self):
|
def _testInListOK(self):
|
||||||
ticket = BanTicket('193.168.0.128', 1167605999.0)
|
ticket = BanTicket('193.168.0.128', 1167605999.0)
|
||||||
self.failUnless(self.__banManager.inBanList(ticket))
|
self.assertTrue(self.__banManager.inBanList(ticket))
|
||||||
|
|
||||||
def _testInListNOK(self):
|
def _testInListNOK(self):
|
||||||
ticket = BanTicket('111.111.1.111', 1167605999.0)
|
ticket = BanTicket('111.111.1.111', 1167605999.0)
|
||||||
self.failIf(self.__banManager.inBanList(ticket))
|
self.assertFalse(self.__banManager.inBanList(ticket))
|
||||||
|
|
|
@ -40,8 +40,8 @@ class DateDetectorTest(unittest.TestCase):
|
||||||
|
|
||||||
def testGetEpochTime(self):
|
def testGetEpochTime(self):
|
||||||
log = "1138049999 [sshd] error: PAM: Authentication failure"
|
log = "1138049999 [sshd] error: PAM: Authentication failure"
|
||||||
date = [2006, 1, 23, 20, 59, 59, 0, 23, 0]
|
date = [2006, 1, 23, 21, 59, 59, 0, 23, 0]
|
||||||
dateUnix = 1138046399.0
|
dateUnix = 1138049999.0
|
||||||
|
|
||||||
self.assertEqual(self.__datedetector.getTime(log), date)
|
self.assertEqual(self.__datedetector.getTime(log), date)
|
||||||
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
||||||
|
@ -54,14 +54,14 @@ class DateDetectorTest(unittest.TestCase):
|
||||||
self.assertEqual(self.__datedetector.getTime(log), date)
|
self.assertEqual(self.__datedetector.getTime(log), date)
|
||||||
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
||||||
|
|
||||||
def testDefaultTempate(self):
|
# def testDefaultTempate(self):
|
||||||
self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
# self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
||||||
self.__datedetector.setDefaultPattern("%b %d %H:%M:%S")
|
# self.__datedetector.setDefaultPattern("%b %d %H:%M:%S")
|
||||||
|
#
|
||||||
log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure"
|
# log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure"
|
||||||
date = [2005, 1, 23, 21, 59, 59, 1, 23, -1]
|
# date = [2005, 1, 23, 21, 59, 59, 1, 23, -1]
|
||||||
dateUnix = 1106513999.0
|
# dateUnix = 1106513999.0
|
||||||
|
#
|
||||||
self.assertEqual(self.__datedetector.getTime(log), date)
|
# self.assertEqual(self.__datedetector.getTime(log), date)
|
||||||
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
# self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
||||||
|
|
|
@ -25,9 +25,8 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest, socket, time, pickle
|
import unittest, socket, time, pickle
|
||||||
from server.failmanager import FailManager
|
from server.failmanager import FailManager, FailManagerEmpty
|
||||||
from server.failmanager import FailManagerEmpty
|
from server.ticket import FailTicket
|
||||||
from server.failticket import FailTicket
|
|
||||||
|
|
||||||
class AddFailure(unittest.TestCase):
|
class AddFailure(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from server.filterpoll import FilterPoll
|
from server.filterpoll import FilterPoll
|
||||||
from server.filter import Filter
|
from server.filter import FileFilter
|
||||||
from server.failmanager import FailManager
|
from server.failmanager import FailManager
|
||||||
from server.failmanager import FailManagerEmpty
|
from server.failmanager import FailManagerEmpty
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class IgnoreIP(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
self.__filter = Filter(None)
|
self.__filter = FileFilter(None)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Call after every test case."""
|
"""Call after every test case."""
|
||||||
|
@ -43,19 +43,19 @@ class IgnoreIP(unittest.TestCase):
|
||||||
ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99"
|
ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99"
|
||||||
for ip in ipList:
|
for ip in ipList:
|
||||||
self.__filter.addIgnoreIP(ip)
|
self.__filter.addIgnoreIP(ip)
|
||||||
self.failUnless(self.__filter.inIgnoreIPList(ip))
|
self.assertTrue(self.__filter.inIgnoreIPList(ip))
|
||||||
# Test DNS
|
# Test DNS
|
||||||
self.__filter.addIgnoreIP("www.epfl.ch")
|
self.__filter.addIgnoreIP("www.epfl.ch")
|
||||||
self.failUnless(self.__filter.inIgnoreIPList("128.178.50.12"))
|
self.assertTrue(self.__filter.inIgnoreIPList("128.178.50.12"))
|
||||||
|
|
||||||
def testIgnoreIPNOK(self):
|
def testIgnoreIPNOK(self):
|
||||||
ipList = "", "999.999.999.999", "abcdef", "192.168.0."
|
ipList = "", "999.999.999.999", "abcdef", "192.168.0."
|
||||||
for ip in ipList:
|
for ip in ipList:
|
||||||
self.__filter.addIgnoreIP(ip)
|
self.__filter.addIgnoreIP(ip)
|
||||||
self.failIf(self.__filter.inIgnoreIPList(ip))
|
self.assertFalse(self.__filter.inIgnoreIPList(ip))
|
||||||
# Test DNS
|
# Test DNS
|
||||||
self.__filter.addIgnoreIP("www.epfl.ch")
|
self.__filter.addIgnoreIP("www.epfl.ch")
|
||||||
self.failIf(self.__filter.inIgnoreIPList("127.177.50.10"))
|
self.assertFalse(self.__filter.inIgnoreIPList("127.177.50.10"))
|
||||||
|
|
||||||
|
|
||||||
class LogFile(unittest.TestCase):
|
class LogFile(unittest.TestCase):
|
||||||
|
@ -74,7 +74,7 @@ class LogFile(unittest.TestCase):
|
||||||
# self.__filter.openLogFile(LogFile.FILENAME)
|
# self.__filter.openLogFile(LogFile.FILENAME)
|
||||||
|
|
||||||
def testIsModified(self):
|
def testIsModified(self):
|
||||||
self.failUnless(self.__filter.isModified(LogFile.FILENAME))
|
self.assertTrue(self.__filter.isModified(LogFile.FILENAME))
|
||||||
|
|
||||||
|
|
||||||
class GetFailures(unittest.TestCase):
|
class GetFailures(unittest.TestCase):
|
||||||
|
@ -86,7 +86,7 @@ class GetFailures(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
self.__filter = Filter(None)
|
self.__filter = FileFilter(None)
|
||||||
self.__filter.setActive(True)
|
self.__filter.setActive(True)
|
||||||
# TODO Test this
|
# TODO Test this
|
||||||
#self.__filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
#self.__filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
||||||
|
|
Loading…
Reference in New Issue