- Overwrote head with some of 0.8.

git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@686 a942ae1a-1317-0410-a47c-b1dcaea8d605
0.x
Cyril Jaquier 2008-04-13 17:48:52 +00:00
parent cc57497f5b
commit b070dc89aa
72 changed files with 1761 additions and 932 deletions

View File

@ -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
View File

@ -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
View File

@ -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?

View File

@ -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"

108
client/configparserinc.py Normal file
View File

@ -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)

View File

@ -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")

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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>"],

View File

@ -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"

View File

@ -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]

View File

@ -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

View File

@ -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
# #

View File

@ -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

View File

@ -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

View File

@ -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
# #

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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 =

View File

@ -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*

View File

@ -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+\)$

View File

@ -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*$

View File

@ -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*$

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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 =

View File

@ -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 =

View File

@ -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

View File

@ -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

View File

@ -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():

View File

@ -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

View File

@ -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:
-------- --------

19
files/macosx-initd Normal file
View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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":

View File

@ -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',
''
) )
] ]
) )

View File

@ -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))

View File

@ -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))

View File

@ -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)

View File

@ -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):

View File

@ -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}")