mirror of https://github.com/fail2ban/fail2ban
Merge branch 'debian' into build
* debian: (56 commits) Imported upstream version 0.8.2 debian/watch: switched to git-import-orig - Tag for 0.8.2 - Updated for 0.8.2 - Updated e-mail - Changed homepage and e-mail - Updated copyright. - readline is now optional in fail2ban-client (not needed in fail2ban-server). - Added svn:keywords - Fixed Debian bug #461426 - Fixed Debian bug #462060 - Fixed Debian bug #468477 - Fixed Debian bug #456567 - Added revision. - Added "reload <JAIL>" - Replaced "reject" with "drop" in shorwall action. Fix #1854875 - Replaced "echo" with "printf" in actions. Fix #1839673 - Catch Exception instead of AttributeError. - Absorbed some Debian patches. Thanks to Yaroslav Halchenko. - Updated. ... Conflicts: config/fail2ban.conf config/filter.d/proftpd.conf config/filter.d/sshd.conf man/fail2ban-client.1 man/fail2ban-server.1 server/datestrptime.py server/server.pydebian-releases/squeeze
commit
9ab6db30c7
|
@ -4,9 +4,46 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
=============================================================
|
=============================================================
|
||||||
Fail2Ban (version 0.8.1) 2007/08/14
|
Fail2Ban (version 0.8.2) 2008/03/06
|
||||||
=============================================================
|
=============================================================
|
||||||
|
|
||||||
|
ver. 0.8.2 (2008/03/06) - stable
|
||||||
|
----------
|
||||||
|
- Fixed named filter. Thanks to Yaroslav Halchenko
|
||||||
|
- Fixed wrong path for apache-auth in jail.conf. Thanks to
|
||||||
|
Vincent Deffontaines
|
||||||
|
- Fixed timezone bug with epoch date template. Thanks to
|
||||||
|
Michael Hanselmann
|
||||||
|
- Added "full line failregex" patch. Thanks to Yaroslav
|
||||||
|
Halchenko. It will be possible to create stronger failregex
|
||||||
|
against log injection
|
||||||
|
- Fixed ipfw action script. Thanks to Nick Munger
|
||||||
|
- Removed date from logging message when using SYSLOG. Thanks
|
||||||
|
to Iain Lea
|
||||||
|
- Fixed "ignore IPs". Only the first value was taken into
|
||||||
|
account. Thanks to Adrien Clerc
|
||||||
|
- Moved socket to /var/run/fail2ban.
|
||||||
|
- Rewrote the communication server.
|
||||||
|
- Refactoring. Reduced number of files.
|
||||||
|
- Removed Python 2.4. Minimum required version is now Python
|
||||||
|
2.3.
|
||||||
|
- New log rotation detection algorithm.
|
||||||
|
- Print monitored files in status.
|
||||||
|
- Create a PID file in /var/run/fail2ban/. Thanks to Julien
|
||||||
|
Perez.
|
||||||
|
- Fixed "Feb 29" bug. Thanks to James Andrewartha who pointed
|
||||||
|
this out. Thanks to Yaroslav Halchenko for the fix.
|
||||||
|
- "reload <jail>" reloads a single jail and the parameters in
|
||||||
|
fail2ban.conf.
|
||||||
|
- Added Mac OS/X startup script. Thanks to Bill Heaton.
|
||||||
|
- Absorbed some Debian patches. Thanks to Yaroslav Halchenko.
|
||||||
|
- Replaced "echo" with "printf" in actions. Fix #1839673
|
||||||
|
- Replaced "reject" with "drop" in shorwall action. Fix
|
||||||
|
#1854875
|
||||||
|
- Fixed Debian bug #456567, #468477, #462060, #461426
|
||||||
|
- readline is now optional in fail2ban-client (not needed in
|
||||||
|
fail2ban-server).
|
||||||
|
|
||||||
ver. 0.8.1 (2007/08/14) - stable
|
ver. 0.8.1 (2007/08/14) - stable
|
||||||
----------
|
----------
|
||||||
- Fixed vulnerability in sshd.conf. Thanks to Daniel B. Cid
|
- Fixed vulnerability in sshd.conf. Thanks to Daniel B. Cid
|
6
PKG-INFO
6
PKG-INFO
|
@ -1,10 +1,10 @@
|
||||||
Metadata-Version: 1.0
|
Metadata-Version: 1.0
|
||||||
Name: fail2ban
|
Name: fail2ban
|
||||||
Version: 0.8.1
|
Version: 0.8.2
|
||||||
Summary: Ban IPs that make too many password failure
|
Summary: Ban IPs that make too many password failure
|
||||||
Home-page: http://fail2ban.sourceforge.net
|
Home-page: http://www.fail2ban.org
|
||||||
Author: Cyril Jaquier
|
Author: Cyril Jaquier
|
||||||
Author-email: lostcontrol@users.sourceforge.net
|
Author-email: cyril.jaquier@fail2ban.org
|
||||||
License: GPL
|
License: GPL
|
||||||
Description:
|
Description:
|
||||||
Fail2Ban scans log files like /var/log/pwdfail or
|
Fail2Ban scans log files like /var/log/pwdfail or
|
||||||
|
|
13
README
13
README
|
@ -4,7 +4,7 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
=============================================================
|
=============================================================
|
||||||
Fail2Ban (version 0.8.1) 2007/08/14
|
Fail2Ban (version 0.8.2) 2008/03/06
|
||||||
=============================================================
|
=============================================================
|
||||||
|
|
||||||
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.1.tar.bz2
|
> tar xvfj fail2ban-0.8.2.tar.bz2
|
||||||
> cd fail2ban-0.8.1
|
> cd fail2ban-0.8.2
|
||||||
> 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:
|
||||||
-------
|
-------
|
||||||
|
@ -75,7 +75,8 @@ 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
|
Daniel B. Cid, David Nutter, Raphaël Marichez, Guillaume
|
||||||
Delvit, Vaclav Misek
|
Delvit, Vaclav Misek, Adrien Clerc, Michael Hanselmann,
|
||||||
|
Vincent Deffontaines, Bill Heaton and many others.
|
||||||
|
|
||||||
License:
|
License:
|
||||||
--------
|
--------
|
||||||
|
|
9
TODO
9
TODO
|
@ -4,7 +4,7 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
=============================================================
|
=============================================================
|
||||||
ToDo $Revision: 557 $
|
ToDo $Revision: 653 $
|
||||||
=============================================================
|
=============================================================
|
||||||
|
|
||||||
Legend:
|
Legend:
|
||||||
|
@ -15,9 +15,6 @@ Legend:
|
||||||
|
|
||||||
- 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/
|
||||||
|
|
||||||
|
@ -45,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?
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 547 $
|
# $Revision: 644 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 547 $"
|
__version__ = "$Revision: 644 $"
|
||||||
__date__ = "$Date: 2007-02-12 00:21:56 +0100 (Mon, 12 Feb 2007) $"
|
__date__ = "$Date: 2008-01-15 00:12:21 +0100 (Tue, 15 Jan 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -72,9 +72,14 @@ class Beautifier:
|
||||||
ipList = ""
|
ipList = ""
|
||||||
for ip in response[1][1][2][1]:
|
for ip in response[1][1][2][1]:
|
||||||
ipList += ip + " "
|
ipList += ip + " "
|
||||||
|
# Creates file list.
|
||||||
|
fileList = ""
|
||||||
|
for f in response[0][1][2][1]:
|
||||||
|
fileList += f + " "
|
||||||
# Display information
|
# Display information
|
||||||
msg = "Status for the jail: " + inC[1] + "\n"
|
msg = "Status for the jail: " + inC[1] + "\n"
|
||||||
msg = msg + "|- " + response[0][0] + "\n"
|
msg = msg + "|- " + response[0][0] + "\n"
|
||||||
|
msg = msg + "| |- " + response[0][1][2][0] + ":\t" + fileList + "\n"
|
||||||
msg = msg + "| |- " + response[0][1][0][0] + ":\t" + `response[0][1][0][1]` + "\n"
|
msg = msg + "| |- " + response[0][1][0][0] + ":\t" + `response[0][1][0][1]` + "\n"
|
||||||
msg = msg + "| `- " + response[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n"
|
msg = msg + "| `- " + response[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n"
|
||||||
msg = msg + "`- " + response[1][0] + "\n"
|
msg = msg + "`- " + response[1][0] + "\n"
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
# This file is part of Fail2Ban.
|
||||||
|
#
|
||||||
|
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Fail2Ban is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Fail2Ban; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
# Author: Yaroslav Halchenko
|
||||||
|
# Modified: Cyril Jaquier
|
||||||
|
# $Revision: 656 $
|
||||||
|
|
||||||
|
__author__ = 'Yaroslav Halhenko'
|
||||||
|
__revision__ = '$Revision: $'
|
||||||
|
__date__ = '$Date: $'
|
||||||
|
__copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko'
|
||||||
|
__license__ = 'GPL'
|
||||||
|
|
||||||
|
import logging, os
|
||||||
|
from ConfigParser import SafeConfigParser
|
||||||
|
|
||||||
|
# Gets the instance of the logger.
|
||||||
|
logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
|
class SafeConfigParserWithIncludes(SafeConfigParser):
|
||||||
|
"""
|
||||||
|
Class adds functionality to SafeConfigParser to handle included
|
||||||
|
other configuration files (or may be urls, whatever in the future)
|
||||||
|
|
||||||
|
File should have section [includes] and only 2 options implemented
|
||||||
|
are 'files_before' and 'files_after' where files are listed 1 per
|
||||||
|
line.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
before = 1.conf
|
||||||
|
3.conf
|
||||||
|
|
||||||
|
after = 1.conf
|
||||||
|
|
||||||
|
It is a simple implementation, so just basic care is taken about
|
||||||
|
recursion. Includes preserve right order, ie new files are
|
||||||
|
inserted to the list of read configs before original, and their
|
||||||
|
includes correspondingly so the list should follow the leaves of
|
||||||
|
the tree.
|
||||||
|
|
||||||
|
I wasn't sure what would be the right way to implement generic (aka c++
|
||||||
|
template) so we could base at any *configparser class... so I will
|
||||||
|
leave it for the future
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
SECTION_NAME = "INCLUDES"
|
||||||
|
|
||||||
|
#@staticmethod
|
||||||
|
def getIncludes(resource, seen = []):
|
||||||
|
"""
|
||||||
|
Given 1 config resource returns list of included files
|
||||||
|
(recursively) with the original one as well
|
||||||
|
Simple loops are taken care about
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Use a short class name ;)
|
||||||
|
SCPWI = SafeConfigParserWithIncludes
|
||||||
|
|
||||||
|
parser = SafeConfigParser()
|
||||||
|
parser.read(resource)
|
||||||
|
|
||||||
|
resourceDir = os.path.dirname(resource)
|
||||||
|
|
||||||
|
newFiles = [ ('before', []), ('after', []) ]
|
||||||
|
if SCPWI.SECTION_NAME in parser.sections():
|
||||||
|
for option_name, option_list in newFiles:
|
||||||
|
if option_name in parser.options(SCPWI.SECTION_NAME):
|
||||||
|
newResources = parser.get(SCPWI.SECTION_NAME, option_name)
|
||||||
|
for newResource in newResources.split('\n'):
|
||||||
|
if os.path.isabs(newResource):
|
||||||
|
r = newResource
|
||||||
|
else:
|
||||||
|
r = "%s/%s" % (resourceDir, newResource)
|
||||||
|
if r in seen:
|
||||||
|
continue
|
||||||
|
s = seen + [resource]
|
||||||
|
option_list += SCPWI.getIncludes(r, s)
|
||||||
|
# combine lists
|
||||||
|
return newFiles[0][1] + [resource] + newFiles[1][1]
|
||||||
|
#print "Includes list for " + resource + " is " + `resources`
|
||||||
|
getIncludes = staticmethod(getIncludes)
|
||||||
|
|
||||||
|
|
||||||
|
def read(self, filenames):
|
||||||
|
fileNamesFull = []
|
||||||
|
if not isinstance(filenames, list):
|
||||||
|
filenames = [ filenames ]
|
||||||
|
for filename in filenames:
|
||||||
|
fileNamesFull += SafeConfigParserWithIncludes.getIncludes(filename)
|
||||||
|
logSys.debug("Reading files: %s" % fileNamesFull)
|
||||||
|
return SafeConfigParser.read(self, fileNamesFull)
|
||||||
|
|
|
@ -15,38 +15,40 @@
|
||||||
# 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: 458 $
|
# $Revision: 656 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 458 $"
|
__version__ = "$Revision: 656 $"
|
||||||
__date__ = "$Date: 2006-11-12 15:52:36 +0100 (Sun, 12 Nov 2006) $"
|
__date__ = "$Date: 2008-03-04 01:17:56 +0100 (Tue, 04 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__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
|
||||||
def setBaseDir(folderName):
|
def setBaseDir(folderName):
|
||||||
path = folderName.rstrip('/')
|
path = folderName.rstrip('/')
|
||||||
ConfigReader.BASE_DIRECTORY = path + '/'
|
ConfigReader.BASE_DIRECTORY = path + '/'
|
||||||
|
setBaseDir = staticmethod(setBaseDir)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def getBaseDir():
|
def getBaseDir():
|
||||||
return ConfigReader.BASE_DIRECTORY
|
return ConfigReader.BASE_DIRECTORY
|
||||||
|
getBaseDir = staticmethod(getBaseDir)
|
||||||
|
|
||||||
def read(self, filename):
|
def read(self, filename):
|
||||||
basename = ConfigReader.BASE_DIRECTORY + filename
|
basename = ConfigReader.BASE_DIRECTORY + filename
|
||||||
|
@ -54,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")
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 518 $
|
# $Revision: 655 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 518 $"
|
__version__ = "$Revision: 655 $"
|
||||||
__date__ = "$Date: 2007-01-08 22:15:47 +0100 (Mon, 08 Jan 2007) $"
|
__date__ = "$Date: 2008-03-04 01:13:39 +0100 (Tue, 04 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -40,13 +40,15 @@ class Configurator:
|
||||||
self.__fail2ban = Fail2banReader()
|
self.__fail2ban = Fail2banReader()
|
||||||
self.__jails = JailsReader()
|
self.__jails = JailsReader()
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def setBaseDir(folderName):
|
def setBaseDir(folderName):
|
||||||
ConfigReader.setBaseDir(folderName)
|
ConfigReader.setBaseDir(folderName)
|
||||||
|
setBaseDir = staticmethod(setBaseDir)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def getBaseDir():
|
def getBaseDir():
|
||||||
return ConfigReader.getBaseDir()
|
return ConfigReader.getBaseDir()
|
||||||
|
getBaseDir = staticmethod(getBaseDir)
|
||||||
|
|
||||||
def readEarly(self):
|
def readEarly(self):
|
||||||
self.__fail2ban.read()
|
self.__fail2ban.read()
|
||||||
|
@ -54,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()
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 459 $
|
# $Revision: 635 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 459 $"
|
__version__ = "$Revision: 635 $"
|
||||||
__date__ = "$Date: 2006-11-12 22:55:57 +0100 (Sun, 12 Nov 2006) $"
|
__date__ = "$Date: 2007-12-16 22:38:04 +0100 (Sun, 16 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -47,7 +47,7 @@ class CSocket:
|
||||||
self.__csock.close()
|
self.__csock.close()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def receive(sock):
|
def receive(sock):
|
||||||
msg = ''
|
msg = ''
|
||||||
while msg.rfind(CSocket.END_STRING) == -1:
|
while msg.rfind(CSocket.END_STRING) == -1:
|
||||||
|
@ -56,3 +56,4 @@ class CSocket:
|
||||||
raise RuntimeError, "socket connection broken"
|
raise RuntimeError, "socket connection broken"
|
||||||
msg = msg + chunk
|
msg = msg + chunk
|
||||||
return loads(msg)
|
return loads(msg)
|
||||||
|
receive = staticmethod(receive)
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 509 $
|
# $Revision: 659 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 509 $"
|
__version__ = "$Revision: 659 $"
|
||||||
__date__ = "$Date: 2007-01-04 12:58:58 +0100 (Thu, 04 Jan 2007) $"
|
__date__ = "$Date: 2008-03-05 00:09:30 +0100 (Wed, 05 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -129,7 +129,7 @@ class JailReader(ConfigReader):
|
||||||
stream.insert(0, ["add", self.__name, backend])
|
stream.insert(0, ["add", self.__name, backend])
|
||||||
return stream
|
return stream
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def splitAction(action):
|
def splitAction(action):
|
||||||
m = JailReader.actionCRE.match(action)
|
m = JailReader.actionCRE.match(action)
|
||||||
d = dict()
|
d = dict()
|
||||||
|
@ -165,3 +165,4 @@ class JailReader(ConfigReader):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
logSys.error("Invalid argument %s in '%s'" % (p, m.group(2)))
|
logSys.error("Invalid argument %s in '%s'" % (p, m.group(2)))
|
||||||
return [m.group(1), d]
|
return [m.group(1), d]
|
||||||
|
splitAction = staticmethod(splitAction)
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 518 $
|
# $Revision: 655 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 518 $"
|
__version__ = "$Revision: 655 $"
|
||||||
__date__ = "$Date: 2007-01-08 22:15:47 +0100 (Mon, 08 Jan 2007) $"
|
__date__ = "$Date: 2008-03-04 01:13:39 +0100 (Tue, 04 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 529 $
|
# $Revision: 662 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 529 $"
|
__version__ = "$Revision: 662 $"
|
||||||
__date__ = "$Date: 2007-01-29 21:27:51 +0100 (Mon, 29 Jan 2007) $"
|
__date__ = "$Date: 2008-03-05 00:41:58 +0100 (Wed, 05 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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>"],
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 614 $
|
# $Revision: 673 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 614 $"
|
__version__ = "$Revision: 673 $"
|
||||||
__date__ = "$Date: 2007-08-14 23:39:15 +0200 (Tue, 14 Aug 2007) $"
|
__date__ = "$Date: 2008-03-06 00:19:45 +0100 (Thu, 06 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 554 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -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
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Author: Nick Munger
|
# Author: Nick Munger
|
||||||
# Modified by: Cyril Jaquier
|
# Modified by: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 510 $
|
# $Revision: 658 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -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
|
||||||
#
|
#
|
||||||
|
@ -37,7 +37,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = ipaction add deny tcp from <ip> to <localhost> <port>
|
actionban = ipfw add deny tcp from <ip> to <localhost> <port>
|
||||||
|
|
||||||
|
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
|
@ -48,7 +48,7 @@ actionban = ipaction add deny tcp from <ip> to <localhost> <port>
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = ipaction delete `ipfw list | grep -i <ip> | awk '{print $1;}'`
|
actionunban = ipfw delete `ipfw list | grep -i <ip> | awk '{print $1;}'`
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# Modified: Yaroslav O. Halchenko <debian@onerussian.com>
|
# Modified: Yaroslav O. Halchenko <debian@onerussian.com>
|
||||||
# made active on all ports from original iptables.conf
|
# made active on all ports from original iptables.conf
|
||||||
#
|
#
|
||||||
# $Revision: 606 $
|
# $Revision: 658 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -17,7 +17,7 @@ actionstart = iptables -N fail2ban-<name>
|
||||||
iptables -A fail2ban-<name> -j RETURN
|
iptables -A fail2ban-<name> -j RETURN
|
||||||
iptables -I INPUT -p <protocol> -j fail2ban-<name>
|
iptables -I INPUT -p <protocol> -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
|
||||||
#
|
#
|
||||||
|
|
|
@ -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
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
# Modified by Yaroslav Halchenko for multiport banning
|
# Modified by Yaroslav Halchenko for multiport banning
|
||||||
# $Revision: 520 $
|
# $Revision: 658 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -15,7 +15,7 @@ actionstart = iptables -N fail2ban-<name>
|
||||||
iptables -A fail2ban-<name> -j RETURN
|
iptables -A fail2ban-<name> -j RETURN
|
||||||
iptables -I INPUT -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
|
iptables -I INPUT -p <protocol> -m multiport --dports <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
|
||||||
#
|
#
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# Copied from iptables.conf and modified by Yaroslav Halchenko
|
# Copied from iptables.conf and modified by Yaroslav Halchenko
|
||||||
# to fullfill the needs of bugreporter dbts#350746.
|
# to fullfill the needs of bugreporter dbts#350746.
|
||||||
#
|
#
|
||||||
# $Revision: 520 $
|
# $Revision: 658 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -17,7 +17,7 @@ actionstart = iptables -N fail2ban-<name>
|
||||||
iptables -A fail2ban-<name> -j RETURN
|
iptables -A fail2ban-<name> -j RETURN
|
||||||
iptables -I INPUT -m state --state NEW -p <protocol> --dport <port> -j fail2ban-<name>
|
iptables -I INPUT -m state --state NEW -p <protocol> --dport <port> -j fail2ban-<name>
|
||||||
|
|
||||||
# Option: actionend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 494 $
|
# $Revision: 658 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -15,7 +15,7 @@ actionstart = iptables -N fail2ban-<name>
|
||||||
iptables -A fail2ban-<name> -j RETURN
|
iptables -A fail2ban-<name> -j RETURN
|
||||||
iptables -I INPUT -p <protocol> --dport <port> -j fail2ban-<name>
|
iptables -I INPUT -p <protocol> --dport <port> -j fail2ban-<name>
|
||||||
|
|
||||||
# Option: actionend
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 510 $
|
# $Revision: 668 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,25 +11,25 @@
|
||||||
# Notes.: command executed once at the start of Fail2Ban.
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstart = echo -en "Hi,\n
|
actionstart = printf %%b "Hi,\n
|
||||||
The jail <name> has been started successfully.\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
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
# Modified-By: Yaroslav Halchenko to include grepping on IP over log files
|
# Modified-By: Yaroslav Halchenko to include grepping on IP over log files
|
||||||
# $Revision: 595 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
# 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 successfully.\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>
|
||||||
|
@ -20,7 +20,7 @@ actionstart = echo -en "Hi,\n
|
||||||
# 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>
|
||||||
|
@ -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
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 595 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,16 +11,16 @@
|
||||||
# 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 successfully.\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: 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 = 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>
|
||||||
|
@ -39,7 +39,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> 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
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 595 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,16 +11,16 @@
|
||||||
# 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 successfully.\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: 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 = 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>
|
||||||
|
@ -39,7 +39,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> 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
|
<failures> attempts against <name>.\n
|
||||||
Regards,\n
|
Regards,\n
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 604 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
# 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 "Subject: [Fail2Ban] <name>: started
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -20,12 +20,12 @@ actionstart = echo -en "Subject: [Fail2Ban] <name>: started
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <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 "Subject: [Fail2Ban] <name>: summary
|
printf %%b "Subject: [Fail2Ban] <name>: summary
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -35,7 +35,7 @@ actionstop = if [ -f <tmpfile> ]; then
|
||||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||||
rm <tmpfile>
|
rm <tmpfile>
|
||||||
fi
|
fi
|
||||||
echo -en "Subject: [Fail2Ban] <name>: stopped
|
printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -57,10 +57,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 "Subject: [Fail2Ban] <name>: summary
|
printf %%b "Subject: [Fail2Ban] <name>: summary
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 595 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
# 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 "Subject: [Fail2Ban] <name>: started
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -19,11 +19,11 @@ actionstart = echo -en "Subject: [Fail2Ban] <name>: started
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <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 = echo -en "Subject: [Fail2Ban] <name>: stopped
|
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -45,7 +45,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo -en "Subject: [Fail2Ban] <name>: banned <ip>
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 595 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
# 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 "Subject: [Fail2Ban] <name>: started
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -19,11 +19,11 @@ actionstart = echo -en "Subject: [Fail2Ban] <name>: started
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <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 = echo -en "Subject: [Fail2Ban] <name>: stopped
|
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -45,7 +45,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo -en "Subject: [Fail2Ban] <name>: banned <ip>
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 595 $
|
# $Revision: 660 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
# 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 "Subject: [Fail2Ban] <name>: started
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -19,11 +19,11 @@ actionstart = echo -en "Subject: [Fail2Ban] <name>: started
|
||||||
Regards,\n
|
Regards,\n
|
||||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
Fail2Ban" | /usr/sbin/sendmail -f <sender> <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 = echo -en "Subject: [Fail2Ban] <name>: stopped
|
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -45,7 +45,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo -en "Subject: [Fail2Ban] <name>: banned <ip>
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
From: Fail2Ban <<sender>>
|
From: Fail2Ban <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -2,8 +2,16 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 510 $
|
# $Revision: 661 $
|
||||||
#
|
#
|
||||||
|
# The default Shorewall configuration is with "BLACKLISTNEWONLY=Yes" (see
|
||||||
|
# file /etc/shorewall/shorewall.conf). This means that when Fail2ban adds a
|
||||||
|
# new shorewall rule to ban an IP address, that rule will affect only new
|
||||||
|
# connections. So if the attempter goes on trying using the same connection
|
||||||
|
# he could even log in. In order to get the same behavior of the iptable
|
||||||
|
# action (so that the ban is immediate) the /etc/shorewall/shorewall.conf
|
||||||
|
# file should me modified with "BLACKLISTNEWONLY=No".
|
||||||
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
|
@ -13,7 +21,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
|
||||||
#
|
#
|
||||||
|
@ -33,7 +41,7 @@ actioncheck =
|
||||||
# <time> unix timestamp of the ban time
|
# <time> unix timestamp of the ban time
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = shorewall reject <ip>
|
actionban = shorewall drop <ip>
|
||||||
|
|
||||||
# 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
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 494 $
|
# $Revision: 629 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -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: /var/run/fail2ban.sock
|
# Values: FILE Default: /var/run/fail2ban/fail2ban.sock
|
||||||
#
|
#
|
||||||
socket = /var/run/fail2ban.sock
|
socket = /var/run/fail2ban/fail2ban.sock
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
#
|
#
|
||||||
# Author: Yaroslav Halchenko
|
# Author: Yaroslav Halchenko
|
||||||
#
|
#
|
||||||
|
# $Revision: 668 $
|
||||||
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02
|
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02|sogou music spider
|
||||||
badbots = atSpider/1\.0|autoemailspider|China Local Browse 2\.6|ContentSmartz|DataCha0s/2\.0|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 +http\://letscrawl\.com/|Lincoln State Web Browser|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|MVAClient|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|sogou spider|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|WebVulnCrawl\.blogspot\.com/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00
|
badbots = atSpider/1\.0|autoemailspider|China Local Browse 2\.6|ContentSmartz|DataCha0s/2\.0|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 +http\://letscrawl\.com/|Lincoln State Web Browser|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|MVAClient|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|sogou spider|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|WebVulnCrawl\.blogspot\.com/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00
|
||||||
|
|
||||||
# Option: failregex
|
# Option: failregex
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 510 $
|
# $Revision: 658 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Tim Connors
|
||||||
|
#
|
||||||
|
# $Revision: 668 $
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: Regexp to catch Apache overflow attempts.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
failregex = [[]client <HOST>[]] (Invalid method in request|request failed: URI too long|erroneous characters after protocol string)
|
||||||
|
|
||||||
|
# Option: ignoreregex
|
||||||
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
ignoreregex =
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Generic configuration items (to be used as interpolations) in other
|
||||||
|
# filters or actions configurations
|
||||||
|
#
|
||||||
|
# Author: Yaroslav Halchenko
|
||||||
|
#
|
||||||
|
# $Revision: $
|
||||||
|
#
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
# Load customizations if any available
|
||||||
|
after = common.local
|
||||||
|
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
|
||||||
|
# Daemon definition is to be specialized (if needed) in .conf file
|
||||||
|
_daemon = \S*
|
||||||
|
|
||||||
|
#
|
||||||
|
# Shortcuts for easier comprehension of the failregex
|
||||||
|
#
|
||||||
|
# PID.
|
||||||
|
# EXAMPLES: [123]
|
||||||
|
__pid_re = (?:\[\d+\])
|
||||||
|
|
||||||
|
# Daemon name (with optional source_file:line or whatever)
|
||||||
|
# EXAMPLES: pam_rhosts_auth, [sshd], pop(pam_unix)
|
||||||
|
__daemon_re = [\[\(]?%(_daemon)s(?:\(\S+\))?[\]\)]?:?
|
||||||
|
|
||||||
|
# Combinations of daemon name and PID
|
||||||
|
# EXAMPLES: sshd[31607], pop(pam_unix)[4920]
|
||||||
|
__daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Common line prefixes (beginnings) which could be used in filters
|
||||||
|
#
|
||||||
|
# [hostname] [vserver tag] daemon_id spaces
|
||||||
|
# this can be optional (for instance if we match named native log files)
|
||||||
|
__prefix_line = \s*(?:\S+ )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s*
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
# Author: Yaroslav Halchenko
|
# Author: Yaroslav Halchenko
|
||||||
#
|
#
|
||||||
# $Revision: 608 $
|
# $Revision: 616 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Yaroslav Halchenko
|
# Author: Yaroslav Halchenko
|
||||||
#
|
#
|
||||||
# $Revision: 603 $
|
# $Revision: 665 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
@ -14,10 +14,10 @@
|
||||||
# (?:::f{4,6}:)?(?P<host>\S+)
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = \(\S+\[<HOST>\]\): USER \S+: no such user found from \S+ \[[0-9.]+\] to \S+:\S+$
|
failregex = \(\S+\[<HOST>\]\)[: -]+ USER \S+: no such user found from \S+ \[[0-9.]+\] to \S+:\S+$
|
||||||
\(\S+\[<HOST>\]\): USER \S+ \(Login failed\): Incorrect password\.$
|
\(\S+\[<HOST>\]\)[: -]+ USER \S+ \(Login failed\): Incorrect password\.$
|
||||||
\(\S+\[<HOST>\]\): SECURITY VIOLATION: \S+ login attempted\.$
|
\(\S+\[<HOST>\]\)[: -]+ SECURITY VIOLATION: \S+ login attempted\.$
|
||||||
\(\S+\[<HOST>\]\): Maximum login attempts \(\d+\) exceeded$
|
\(\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.
|
||||||
|
|
|
@ -2,11 +2,20 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 613 $
|
# $Revision: 663 $
|
||||||
#
|
#
|
||||||
|
|
||||||
|
[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,13 +23,15 @@
|
||||||
# (?:::f{4,6}:)?(?P<host>\S+)
|
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = (?:error: PAM: )?Authentication failure for .* from <HOST>\s*$
|
failregex = ^%(__prefix_line)s(?:error: PAM: )?Authentication failure for .* from <HOST>\s*$
|
||||||
Failed [-/\w]+ for .* from <HOST>(?: port \d*)?(?: ssh\d*)?\s*$
|
^%(__prefix_line)sFailed [-/\w]+ for .* from <HOST>(?: port \d*)?(?: ssh\d*)?$
|
||||||
ROOT LOGIN REFUSED.* FROM <HOST>\s*$
|
^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$
|
||||||
[iI](?:llegal|nvalid) user .* from <HOST>\s*$
|
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$
|
||||||
User .+ from <HOST> not allowed because not listed in AllowUsers\s*$
|
^%(__prefix_line)sUser .+ from <HOST> not allowed because not listed in AllowUsers$
|
||||||
User .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$
|
^%(__prefix_line)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$
|
||||||
sshd(?:\[\d+\])?: refused connect from \S+ \(<HOST>\)\s*$
|
^%(__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.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 610 $
|
# $Revision: 658 $
|
||||||
#
|
#
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
|
@ -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 =
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 611 $
|
# $Revision: 617 $
|
||||||
#
|
#
|
||||||
|
|
||||||
# The DEFAULT allows a global definition of the options. They can be override
|
# The DEFAULT allows a global definition of the options. They can be override
|
||||||
|
@ -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
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
# Site Directory Pattern Version Script
|
# Site Directory Pattern Version Script
|
||||||
version=3
|
version=3
|
||||||
|
|
||||||
http://sf.net/fail2ban/ fail2ban-(.*)\.tar\.bz2 debian svn-upgrade
|
http://sf.net/fail2ban/ fail2ban-(.*)\.tar\.bz2 debian git-import-orig
|
||||||
|
|
|
@ -17,16 +17,16 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 528 $
|
# $Revision: 672 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 528 $"
|
__version__ = "$Revision: 672 $"
|
||||||
__date__ = "$Date: 2007-01-29 21:27:01 +0100 (Mon, 29 Jan 2007) $"
|
__date__ = "$Date: 2008-03-06 00:18:06 +0100 (Thu, 06 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import sys, string, os, pickle, re, logging, signal
|
import sys, string, os, pickle, re, logging, signal
|
||||||
import getopt, time, readline, shlex, socket
|
import getopt, time, shlex, socket
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -325,6 +340,11 @@ class Fail2banClient:
|
||||||
|
|
||||||
# Interactive mode
|
# Interactive mode
|
||||||
if self.__conf["interactive"]:
|
if self.__conf["interactive"]:
|
||||||
|
try:
|
||||||
|
import readline
|
||||||
|
except ImportError:
|
||||||
|
logSys.error("Readline not available")
|
||||||
|
return False
|
||||||
try:
|
try:
|
||||||
ret = True
|
ret = True
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
|
@ -333,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
|
||||||
|
@ -352,16 +372,24 @@ 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.__configurator.convertToProtocol()
|
||||||
self.__stream = self.__configurator.getConfigStream()
|
self.__stream = self.__configurator.getConfigStream()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@staticmethod
|
def __readJailConfig(self, jail):
|
||||||
|
self.__configurator.readAll()
|
||||||
|
ret = self.__configurator.getOptions(jail)
|
||||||
|
self.__configurator.convertToProtocol()
|
||||||
|
self.__stream = self.__configurator.getConfigStream()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
#@staticmethod
|
||||||
def dumpConfig(cmd):
|
def dumpConfig(cmd):
|
||||||
for c in cmd:
|
for c in cmd:
|
||||||
print c
|
print c
|
||||||
return True
|
return True
|
||||||
|
dumpConfig = staticmethod(dumpConfig)
|
||||||
|
|
||||||
|
|
||||||
class ServerExecutionException(Exception):
|
class ServerExecutionException(Exception):
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 596 $
|
# $Revision: 672 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 596 $"
|
__version__ = "$Revision: 672 $"
|
||||||
__date__ = "$Date: 2007-07-10 21:54:01 +0200 (Tue, 10 Jul 2007) $"
|
__date__ = "$Date: 2008-03-06 00:18:06 +0100 (Thu, 06 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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,7 +65,9 @@ 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.__ignoreregex = list()
|
||||||
|
@ -80,18 +82,19 @@ class Fail2banRegex:
|
||||||
logging.getLogger("fail2ban").addHandler(self.__hdlr)
|
logging.getLogger("fail2ban").addHandler(self.__hdlr)
|
||||||
logging.getLogger("fail2ban").setLevel(logging.ERROR)
|
logging.getLogger("fail2ban").setLevel(logging.ERROR)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
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)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def dispUsage():
|
def dispUsage():
|
||||||
print "Usage: "+sys.argv[0]+" [OPTIONS] <LOG> <REGEX> [IGNOREREGEX]"
|
print "Usage: "+sys.argv[0]+" [OPTIONS] <LOG> <REGEX> [IGNOREREGEX]"
|
||||||
print
|
print
|
||||||
|
@ -116,7 +119,8 @@ class Fail2banRegex:
|
||||||
print " string a string representing an 'ignoreregex'"
|
print " string a string representing an 'ignoreregex'"
|
||||||
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 "Report bugs to <cyril.jaquier@fail2ban.org>"
|
||||||
|
dispUsage = staticmethod(dispUsage)
|
||||||
|
|
||||||
def getCmdLineOptions(self, optList):
|
def getCmdLineOptions(self, optList):
|
||||||
""" Gets the command line options
|
""" Gets the command line options
|
||||||
|
@ -129,13 +133,14 @@ class Fail2banRegex:
|
||||||
self.dispVersion()
|
self.dispVersion()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def logIsFile(value):
|
def logIsFile(value):
|
||||||
return os.path.isfile(value)
|
return os.path.isfile(value)
|
||||||
|
logIsFile = staticmethod(logIsFile)
|
||||||
|
|
||||||
def readIgnoreRegex(self, value):
|
def readIgnoreRegex(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 ignoreregex file : " + value
|
print "Use ignoreregex file : " + value
|
||||||
|
@ -164,7 +169,7 @@ class Fail2banRegex:
|
||||||
|
|
||||||
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
|
||||||
|
@ -217,7 +222,7 @@ class Fail2banRegex:
|
||||||
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)
|
||||||
|
|
|
@ -17,15 +17,15 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 522 $
|
# $Revision: 672 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 522 $"
|
__version__ = "$Revision: 672 $"
|
||||||
__date__ = "$Date: 2007-01-21 23:19:57 +0100 (Sun, 21 Jan 2007) $"
|
__date__ = "$Date: 2008-03-06 00:18:06 +0100 (Thu, 06 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import getopt, sys
|
import getopt, sys, logging
|
||||||
|
|
||||||
# Inserts our own modules path first in the list
|
# Inserts our own modules path first in the list
|
||||||
# fix for bug #343821
|
# fix for bug #343821
|
||||||
|
@ -34,6 +34,9 @@ sys.path.insert(1, "/usr/share/fail2ban")
|
||||||
from common.version import version
|
from common.version import version
|
||||||
from server.server import Server
|
from server.server import Server
|
||||||
|
|
||||||
|
# Gets the instance of the logger.
|
||||||
|
logSys = logging.getLogger("fail2ban")
|
||||||
|
|
||||||
##
|
##
|
||||||
# \mainpage Fail2Ban
|
# \mainpage Fail2Ban
|
||||||
#
|
#
|
||||||
|
@ -50,16 +53,16 @@ class Fail2banServer:
|
||||||
self.__conf = dict()
|
self.__conf = dict()
|
||||||
self.__conf["background"] = True
|
self.__conf["background"] = True
|
||||||
self.__conf["force"] = False
|
self.__conf["force"] = False
|
||||||
self.__conf["socket"] = "/tmp/fail2ban.sock"
|
self.__conf["socket"] = "/var/run/fail2ban/fail2ban.sock"
|
||||||
|
|
||||||
def dispVersion(self):
|
def dispVersion(self):
|
||||||
print "Fail2Ban v" + version
|
print "Fail2Ban v" + version
|
||||||
print
|
print
|
||||||
print "Copyright (c) 2004-2006 Cyril Jaquier"
|
print "Copyright (c) 2004-2008 Cyril Jaquier"
|
||||||
print "Copyright of modifications held by their respective authors."
|
print "Copyright of modifications held by their respective authors."
|
||||||
print "Licensed under the GNU General Public License v2 (GPL)."
|
print "Licensed under the GNU General Public License v2 (GPL)."
|
||||||
print
|
print
|
||||||
print "Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>."
|
print "Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>."
|
||||||
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
||||||
|
|
||||||
def dispUsage(self):
|
def dispUsage(self):
|
||||||
|
@ -82,7 +85,7 @@ class Fail2banServer:
|
||||||
print " -h, --help display this help message"
|
print " -h, --help display this help message"
|
||||||
print " -V, --version print the version"
|
print " -V, --version print the version"
|
||||||
print
|
print
|
||||||
print "Report bugs to <lostcontrol@users.sourceforge.net>"
|
print "Report bugs to <cyril.jaquier@fail2ban.org>"
|
||||||
|
|
||||||
def __getCmdLineOptions(self, optList):
|
def __getCmdLineOptions(self, optList):
|
||||||
""" Gets the command line options
|
""" Gets the command line options
|
||||||
|
@ -123,7 +126,7 @@ class Fail2banServer:
|
||||||
self.__server.start(self.__conf["socket"], self.__conf["force"])
|
self.__server.start(self.__conf["socket"], self.__conf["force"])
|
||||||
return True
|
return True
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
logSys.exception(e)
|
||||||
self.__server.quit()
|
self.__server.quit()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
=============================================================
|
=============================================================
|
||||||
Fail2Ban (version 0.7.7) 2007/??/??
|
Fail2Ban (version 0.8.2) 2008/03/06
|
||||||
=============================================================
|
=============================================================
|
||||||
|
|
||||||
Cacti is a graphing solution using RRDTool. It is possible to
|
Cacti is a graphing solution using RRDTool. It is possible to
|
||||||
|
@ -13,7 +13,7 @@ use Cacti to display statistics about Fail2ban.
|
||||||
Installation:
|
Installation:
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
1/ Install Fail2ban version 0.7 or higher and ensure that it
|
1/ Install Fail2ban version 0.8 or higher and ensure that it
|
||||||
works properly.
|
works properly.
|
||||||
2/ The user running poller.php must have read and write
|
2/ The user running poller.php must have read and write
|
||||||
access to the socket used by Fail2ban.
|
access to the socket used by Fail2ban.
|
||||||
|
@ -30,7 +30,7 @@ appreciate this program, you can contact me at:
|
||||||
|
|
||||||
Website: http://www.fail2ban.org
|
Website: http://www.fail2ban.org
|
||||||
|
|
||||||
Cyril Jaquier: <lostcontrol@users.sourceforge.net>
|
Cyril Jaquier: <cyril.jaquier@fail2ban.org>
|
||||||
|
|
||||||
License:
|
License:
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/Library/LaunchDaemonsm/org.fail2ban.plist
|
||||||
|
===================================
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Disabled</key>
|
||||||
|
<false/>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>fail2ban</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>/usr/local/bin/fail2ban-client</string>
|
||||||
|
<string>start</string>
|
||||||
|
</array>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -1,11 +1,12 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||||
.TH FAIL2BAN-CLIENT "1" "August 2007" "fail2ban-client v0.8.1" "User Commands"
|
.TH FAIL2BAN-CLIENT "1" "March 2008" "fail2ban-client v0.8.2" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-client \- configure and control the server
|
fail2ban-client \- configure and control the server
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B fail2ban-client
|
||||||
|
[\fIOPTIONS\fR] \fI<COMMAND>\fR
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
[?1034hUsage: ../fail2ban\-client [OPTIONS] <COMMAND>
|
Fail2Ban v0.8.2 reads log file that contains password failure report
|
||||||
.PP
|
|
||||||
Fail2Ban v0.8.1 reads log file that contains password failure report
|
|
||||||
and bans the corresponding IP addresses using firewall rules.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
|
@ -45,6 +46,9 @@ starts the server and the jails
|
||||||
\fBreload\fR
|
\fBreload\fR
|
||||||
reloads the configuration
|
reloads the configuration
|
||||||
.TP
|
.TP
|
||||||
|
\fBreload <JAIL>\fR
|
||||||
|
reloads the jail <JAIL>
|
||||||
|
.TP
|
||||||
\fBstop\fR
|
\fBstop\fR
|
||||||
stops all jails and terminate the
|
stops all jails and terminate the
|
||||||
server
|
server
|
||||||
|
@ -109,18 +113,6 @@ of <JAIL>
|
||||||
removes <FILE> to the monitoring
|
removes <FILE> to the monitoring
|
||||||
list of <JAIL>
|
list of <JAIL>
|
||||||
.TP
|
.TP
|
||||||
\fBset <JAIL> timeregex <REGEX>\fR
|
|
||||||
sets the regular expression
|
|
||||||
<REGEX> to match the date format
|
|
||||||
for <JAIL>. This will disable the
|
|
||||||
autodetection feature.
|
|
||||||
.TP
|
|
||||||
\fBset <JAIL> timepattern <PATTERN>\fR
|
|
||||||
sets the pattern <PATTERN> to
|
|
||||||
match the date format for <JAIL>.
|
|
||||||
This will disable the
|
|
||||||
autodetection feature.
|
|
||||||
.TP
|
|
||||||
\fBset <JAIL> addfailregex <REGEX>\fR
|
\fBset <JAIL> addfailregex <REGEX>\fR
|
||||||
adds the regular expression
|
adds the regular expression
|
||||||
<REGEX> which must match failures
|
<REGEX> which must match failures
|
||||||
|
@ -256,13 +248,13 @@ action <ACT> for <JAIL>
|
||||||
.SH FILES
|
.SH FILES
|
||||||
\fI/etc/fail2ban/*\fR
|
\fI/etc/fail2ban/*\fR
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>.
|
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||||
.SH "REPORTING BUGS"
|
.SH "REPORTING BUGS"
|
||||||
Please report bugs via Debian bug tracking system
|
Please report bugs via Debian bug tracking system
|
||||||
http://www.debian.org/Bugs/.
|
http://www.debian.org/Bugs/.
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2004-2006 Cyril Jaquier
|
Copyright \(co 2004-2008 Cyril Jaquier
|
||||||
.br
|
.br
|
||||||
Copyright of modifications held by their respective authors.
|
Copyright of modifications held by their respective authors.
|
||||||
Licensed under the GNU General Public License v2 (GPL).
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||||
.TH FAIL2BAN-REGEX "1" "August 2007" "fail2ban-regex v0.8.1" "User Commands"
|
.TH FAIL2BAN-REGEX "1" "March 2008" "fail2ban-regex v0.8.2" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-regex \- test Fail2ban "failregex" option
|
fail2ban-regex \- test Fail2ban "failregex" option
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-regex
|
.B fail2ban-regex
|
||||||
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
|
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Fail2Ban v0.8.1 reads log file that contains password failure report
|
Fail2Ban v0.8.2 reads log file that contains password failure report
|
||||||
and bans the corresponding IP addresses using firewall rules.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
.PP
|
.PP
|
||||||
This tools can test regular expressions for "fail2ban".
|
This tools can test regular expressions for "fail2ban".
|
||||||
|
@ -39,12 +39,12 @@ a string representing an 'ignoreregex'
|
||||||
\fBfilename\fR
|
\fBfilename\fR
|
||||||
path to a filter file (filter.d/sshd.conf)
|
path to a filter file (filter.d/sshd.conf)
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>.
|
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||||
.SH "REPORTING BUGS"
|
.SH "REPORTING BUGS"
|
||||||
Report bugs to <lostcontrol@users.sourceforge.net>
|
Report bugs to <cyril.jaquier@fail2ban.org>
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2004-2006 Cyril Jaquier
|
Copyright \(co 2004-2008 Cyril Jaquier
|
||||||
.br
|
.br
|
||||||
Copyright of modifications held by their respective authors.
|
Copyright of modifications held by their respective authors.
|
||||||
Licensed under the GNU General Public License v2 (GPL).
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||||
.TH FAIL2BAN-SERVER "1" "August 2007" "fail2ban-server v0.8.1" "User Commands"
|
.TH FAIL2BAN-SERVER "1" "March 2008" "fail2ban-server v0.8.2" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-server \- start the server
|
fail2ban-server \- start the server
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-server
|
.B fail2ban-server
|
||||||
[\fIOPTIONS\fR]
|
[\fIOPTIONS\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Fail2Ban v0.8.1 reads log file that contains password failure report
|
Fail2Ban v0.8.2 reads log file that contains password failure report
|
||||||
and bans the corresponding IP addresses using firewall rules.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
.PP
|
.PP
|
||||||
Only use this command for debugging purpose. Start the server with
|
Only use this command for debugging purpose. Start the server with
|
||||||
|
@ -32,13 +32,13 @@ display this help message
|
||||||
\fB\-V\fR, \fB\-\-version\fR
|
\fB\-V\fR, \fB\-\-version\fR
|
||||||
print the version
|
print the version
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>.
|
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||||
.SH "REPORTING BUGS"
|
.SH "REPORTING BUGS"
|
||||||
Please report bugs via Debian bug tracking system
|
Please report bugs via Debian bug tracking system
|
||||||
http://www.debian.org/Bugs/.
|
http://www.debian.org/Bugs/.
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2004-2006 Cyril Jaquier
|
Copyright \(co 2004-2008 Cyril Jaquier
|
||||||
.br
|
.br
|
||||||
Copyright of modifications held by their respective authors.
|
Copyright of modifications held by their respective authors.
|
||||||
Licensed under the GNU General Public License v2 (GPL).
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 556 $
|
# $Revision: 635 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 556 $"
|
__version__ = "$Revision: 635 $"
|
||||||
__date__ = "$Date: 2007-03-07 21:54:32 +0100 (Wed, 07 Mar 2007) $"
|
__date__ = "$Date: 2007-12-16 22:38:04 +0100 (Sun, 16 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ class Action:
|
||||||
# @param aInfo the properties
|
# @param aInfo the properties
|
||||||
# @return a string
|
# @return a string
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def replaceTag(query, aInfo):
|
def replaceTag(query, aInfo):
|
||||||
""" Replace tags in query
|
""" Replace tags in query
|
||||||
"""
|
"""
|
||||||
|
@ -241,6 +241,7 @@ class Action:
|
||||||
# New line
|
# New line
|
||||||
string = string.replace("<br>", '\n')
|
string = string.replace("<br>", '\n')
|
||||||
return string
|
return string
|
||||||
|
replaceTag = staticmethod(replaceTag)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Executes a command with preliminary checks and substitutions.
|
# Executes a command with preliminary checks and substitutions.
|
||||||
|
@ -297,7 +298,7 @@ class Action:
|
||||||
# @param realCmd the command to execute
|
# @param realCmd the command to execute
|
||||||
# @return True if the command succeeded
|
# @return True if the command succeeded
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def executeCmd(realCmd):
|
def executeCmd(realCmd):
|
||||||
logSys.debug(realCmd)
|
logSys.debug(realCmd)
|
||||||
try:
|
try:
|
||||||
|
@ -312,3 +313,5 @@ class Action:
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
logSys.error("%s failed with %s" % (realCmd, e))
|
logSys.error("%s failed with %s" % (realCmd, e))
|
||||||
return False
|
return False
|
||||||
|
executeCmd = staticmethod(executeCmd)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
# 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: 567 $
|
||||||
|
|
||||||
|
__author__ = "Cyril Jaquier"
|
||||||
|
__version__ = "$Revision: 567 $"
|
||||||
|
__date__ = "$Date: 2007-03-26 23:17:31 +0200 (Mon, 26 Mar 2007) $"
|
||||||
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
from pickle import dumps, loads, HIGHEST_PROTOCOL
|
||||||
|
import asyncore, asynchat, socket, os, logging
|
||||||
|
|
||||||
|
# Gets the instance of the logger.
|
||||||
|
logSys = logging.getLogger("fail2ban.server")
|
||||||
|
|
||||||
|
##
|
||||||
|
# Request handler class.
|
||||||
|
#
|
||||||
|
# This class extends asynchat in order to provide a request handler for
|
||||||
|
# incoming query.
|
||||||
|
|
||||||
|
class RequestHandler(asynchat.async_chat):
|
||||||
|
|
||||||
|
END_STRING = "<F2B_END_COMMAND>"
|
||||||
|
|
||||||
|
def __init__(self, conn, transmitter):
|
||||||
|
asynchat.async_chat.__init__(self, conn)
|
||||||
|
self.__transmitter = transmitter
|
||||||
|
self.__buffer = []
|
||||||
|
# Sets the terminator.
|
||||||
|
self.set_terminator(RequestHandler.END_STRING)
|
||||||
|
|
||||||
|
def collect_incoming_data(self, data):
|
||||||
|
#logSys.debug("Received raw data: " + str(data))
|
||||||
|
self.__buffer.append(data)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Handles a new request.
|
||||||
|
#
|
||||||
|
# This method is called once we have a complete request.
|
||||||
|
|
||||||
|
def found_terminator(self):
|
||||||
|
# Joins the buffer items.
|
||||||
|
message = loads("".join(self.__buffer))
|
||||||
|
# Gives the message to the transmitter.
|
||||||
|
message = self.__transmitter.proceed(message)
|
||||||
|
# Serializes the response.
|
||||||
|
message = dumps(message, HIGHEST_PROTOCOL)
|
||||||
|
# Sends the response to the client.
|
||||||
|
self.send(message + RequestHandler.END_STRING)
|
||||||
|
# Closes the channel.
|
||||||
|
self.close_when_done()
|
||||||
|
|
||||||
|
def handle_error(self):
|
||||||
|
logSys.error("Unexpected communication error")
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
##
|
||||||
|
# Asynchronous server class.
|
||||||
|
#
|
||||||
|
# This class extends asyncore and dispatches connection requests to
|
||||||
|
# RequestHandler.
|
||||||
|
|
||||||
|
class AsyncServer(asyncore.dispatcher):
|
||||||
|
|
||||||
|
def __init__(self, transmitter):
|
||||||
|
asyncore.dispatcher.__init__(self)
|
||||||
|
self.__transmitter = transmitter
|
||||||
|
self.__sock = "/var/run/fail2ban/fail2ban.sock"
|
||||||
|
self.__init = False
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns False as we only read the socket first.
|
||||||
|
|
||||||
|
def writable(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def handle_accept(self):
|
||||||
|
try:
|
||||||
|
conn, addr = self.accept()
|
||||||
|
except socket.error:
|
||||||
|
logSys.warning("Socket error")
|
||||||
|
return
|
||||||
|
except TypeError:
|
||||||
|
logSys.warning("Type error")
|
||||||
|
return
|
||||||
|
# Creates an instance of the handler class to handle the
|
||||||
|
# request/response on the incoming connection.
|
||||||
|
RequestHandler(conn, self.__transmitter)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Starts the communication server.
|
||||||
|
#
|
||||||
|
# @param sock: socket file.
|
||||||
|
# @param force: remove the socket file if exists.
|
||||||
|
|
||||||
|
def start(self, sock, force):
|
||||||
|
self.__sock = sock
|
||||||
|
# Remove socket
|
||||||
|
if os.path.exists(sock):
|
||||||
|
logSys.error("Fail2ban seems to be already running")
|
||||||
|
if force:
|
||||||
|
logSys.warn("Forcing execution of the server")
|
||||||
|
os.remove(sock)
|
||||||
|
else:
|
||||||
|
raise AsyncServerException("Server already running")
|
||||||
|
# Creates the socket.
|
||||||
|
self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
self.set_reuse_addr()
|
||||||
|
try:
|
||||||
|
self.bind(sock)
|
||||||
|
except Exception:
|
||||||
|
raise AsyncServerException("Unable to bind socket %s" % self.__sock)
|
||||||
|
self.listen(1)
|
||||||
|
# Sets the init flag.
|
||||||
|
self.__init = True
|
||||||
|
# TODO Add try..catch
|
||||||
|
asyncore.loop()
|
||||||
|
|
||||||
|
##
|
||||||
|
# Stops the communication server.
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if self.__init:
|
||||||
|
# Only closes the socket if it was initialized first.
|
||||||
|
self.close()
|
||||||
|
# Remove socket
|
||||||
|
if os.path.exists(self.__sock):
|
||||||
|
logSys.debug("Removed socket file " + self.__sock)
|
||||||
|
os.remove(self.__sock)
|
||||||
|
logSys.debug("Socket shutdown")
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# AsyncServerException is used to wrap communication exceptions.
|
||||||
|
|
||||||
|
class AsyncServerException(Exception):
|
||||||
|
pass
|
|
@ -16,15 +16,15 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 553 $
|
# $Revision: 638 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 553 $"
|
__version__ = "$Revision: 638 $"
|
||||||
__date__ = "$Date: 2007-02-26 00:53:22 +0100 (Mon, 26 Feb 2007) $"
|
__date__ = "$Date: 2007-12-17 21:00:36 +0100 (Mon, 17 Dec 2007) $"
|
||||||
__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
|
||||||
|
@ -125,7 +125,7 @@ class BanManager:
|
||||||
# @param ticket the FailTicket
|
# @param ticket the FailTicket
|
||||||
# @return a BanTicket
|
# @return a BanTicket
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def createBanTicket(ticket):
|
def createBanTicket(ticket):
|
||||||
ip = ticket.getIP()
|
ip = ticket.getIP()
|
||||||
#lastTime = ticket.getTime()
|
#lastTime = ticket.getTime()
|
||||||
|
@ -133,6 +133,7 @@ class BanManager:
|
||||||
banTicket = BanTicket(ip, lastTime)
|
banTicket = BanTicket(ip, lastTime)
|
||||||
banTicket.setAttempt(ticket.getAttempt())
|
banTicket.setAttempt(ticket.getAttempt())
|
||||||
return banTicket
|
return banTicket
|
||||||
|
createBanTicket = staticmethod(createBanTicket)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Add a ban ticket.
|
# Add a ban ticket.
|
||||||
|
|
|
@ -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: 382 $
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision: 382 $"
|
|
||||||
__date__ = "$Date: 2006-09-25 19:03:48 +0200 (Mon, 25 Sep 2006) $"
|
|
||||||
__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)
|
|
||||||
|
|
|
@ -16,19 +16,19 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 607 $
|
# $Revision: 645 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 607 $"
|
__version__ = "$Revision: 645 $"
|
||||||
__date__ = "$Date: 2007-08-09 00:16:22 +0200 (Thu, 09 Aug 2007) $"
|
__date__ = "$Date: 2008-01-16 23:55:04 +0100 (Wed, 16 Jan 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__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")
|
||||||
|
@ -100,54 +99,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)
|
||||||
|
@ -161,11 +137,10 @@ 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(cmp = lambda x, y:
|
self.__templates.sort(lambda x, y: cmp(x.getHits(), y.getHits()))
|
||||||
cmp(x.getHits(), y.getHits()),
|
self.__templates.reverse()
|
||||||
reverse = True)
|
|
||||||
finally:
|
finally:
|
||||||
self.__lock.release()
|
self.__lock.release()
|
||||||
|
|
|
@ -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: 504 $
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision: 504 $"
|
|
||||||
__date__ = "$Date: 2006-12-23 17:37:17 +0100 (Sat, 23 Dec 2006) $"
|
|
||||||
__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.gmtime(float(dateMatch.group())))
|
|
||||||
return date
|
|
|
@ -1,91 +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: 504 $
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision: 504 $"
|
|
||||||
__date__ = "$Date: 2006-12-23 17:37:17 +0100 (Sat, 23 Dec 2006) $"
|
|
||||||
__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
|
|
||||||
|
|
||||||
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())
|
|
||||||
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
|
|
|
@ -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: 504 $
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision: 504 $"
|
|
||||||
__date__ = "$Date: 2006-12-23 17:37:17 +0100 (Sat, 23 Dec 2006) $"
|
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
|
||||||
__license__ = "GPL"
|
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
from datetemplate import DateTemplate
|
|
||||||
|
|
||||||
class DateTai64n(DateTemplate):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
DateTemplate.__init__(self)
|
|
||||||
# We already know the format for TAI64N
|
|
||||||
self.setRegex("@[0-9a-f]{24}")
|
|
||||||
|
|
||||||
def getDate(self, line):
|
|
||||||
date = None
|
|
||||||
dateMatch = self.matchDate(line)
|
|
||||||
if dateMatch:
|
|
||||||
# extract part of format which represents seconds since epoch
|
|
||||||
value = dateMatch.group()
|
|
||||||
seconds_since_epoch = value[2:17]
|
|
||||||
date = list(time.gmtime(int(seconds_since_epoch, 16)))
|
|
||||||
return date
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf8 -*-
|
||||||
# This file is part of Fail2Ban.
|
# This file is part of Fail2Ban.
|
||||||
#
|
#
|
||||||
# Fail2Ban is free software; you can redistribute it and/or modify
|
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||||
|
@ -16,15 +17,17 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 504 $
|
# $Revision: 652 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 504 $"
|
__version__ = "$Revision: 652 $"
|
||||||
__date__ = "$Date: 2006-12-23 17:37:17 +0100 (Sat, 23 Dec 2006) $"
|
__date__ = "$Date: 2008-02-29 00:01:30 +0100 (Fri, 29 Feb 2008) $"
|
||||||
__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
|
|
@ -16,16 +16,16 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 553 $
|
# $Revision: 638 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 553 $"
|
__version__ = "$Revision: 638 $"
|
||||||
__date__ = "$Date: 2007-02-26 00:53:22 +0100 (Mon, 26 Feb 2007) $"
|
__date__ = "$Date: 2007-12-17 21:00:36 +0100 (Mon, 17 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__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
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,82 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 589 $
|
# $Revision: 642 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 589 $"
|
__version__ = "$Revision: 642 $"
|
||||||
__date__ = "$Date: 2007-06-25 23:43:25 +0200 (Mon, 25 Jun 2007) $"
|
__date__ = "$Date: 2008-01-05 23:33:44 +0100 (Sat, 05 Jan 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from regex import Regex, RegexException
|
import re, sre_constants
|
||||||
|
|
||||||
|
##
|
||||||
|
# Regular expression class.
|
||||||
|
#
|
||||||
|
# This class represents a regular expression with its compiled version.
|
||||||
|
|
||||||
|
class Regex:
|
||||||
|
|
||||||
|
##
|
||||||
|
# Constructor.
|
||||||
|
#
|
||||||
|
# Creates a new object. This method can throw RegexException in order to
|
||||||
|
# avoid construction of invalid object.
|
||||||
|
# @param value the regular expression
|
||||||
|
|
||||||
|
def __init__(self, regex):
|
||||||
|
self._matchCache = None
|
||||||
|
# Perform shortcuts expansions.
|
||||||
|
# Replace "<HOST>" with default regular expression for host.
|
||||||
|
regex = regex.replace("<HOST>", "(?:::f{4,6}:)?(?P<host>\S+)")
|
||||||
|
if regex.lstrip() == '':
|
||||||
|
raise RegexException("Cannot add empty regex")
|
||||||
|
try:
|
||||||
|
self._regexObj = re.compile(regex)
|
||||||
|
self._regex = regex
|
||||||
|
except sre_constants.error:
|
||||||
|
raise RegexException("Unable to compile regular expression '%s'" %
|
||||||
|
regex)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Gets the regular expression.
|
||||||
|
#
|
||||||
|
# The effective regular expression used is returned.
|
||||||
|
# @return the regular expression
|
||||||
|
|
||||||
|
def getRegex(self):
|
||||||
|
return self._regex
|
||||||
|
|
||||||
|
##
|
||||||
|
# Searches the regular expression.
|
||||||
|
#
|
||||||
|
# Sets an internal cache (match object) in order to avoid searching for
|
||||||
|
# the pattern again. This method must be called before calling any other
|
||||||
|
# method of this object.
|
||||||
|
# @param value the line
|
||||||
|
|
||||||
|
def search(self, value):
|
||||||
|
self._matchCache = self._regexObj.search(value)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Checks if the previous call to search() matched.
|
||||||
|
#
|
||||||
|
# @return True if a match was found, False otherwise
|
||||||
|
|
||||||
|
def hasMatched(self):
|
||||||
|
if self._matchCache:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Exception dedicated to the class Regex.
|
||||||
|
|
||||||
|
class RegexException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Regular expression class.
|
# Regular expression class.
|
||||||
|
@ -56,5 +123,8 @@ class FailRegex(Regex):
|
||||||
def getHost(self):
|
def getHost(self):
|
||||||
host = self._matchCache.group("host")
|
host = self._matchCache.group("host")
|
||||||
if host == None:
|
if host == None:
|
||||||
raise RegexException("Unexpected error. Please check your regex")
|
# Gets a few information.
|
||||||
|
s = self._matchCache.string
|
||||||
|
r = self._matchCache.re
|
||||||
|
raise RegexException("No 'host' found in '%s' using '%s'" % (s, r))
|
||||||
return host
|
return host
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
# This file is part of Fail2Ban.
|
|
||||||
#
|
|
||||||
# Fail2Ban is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Fail2Ban is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Fail2Ban; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
|
||||||
#
|
|
||||||
# $Revision: 382 $
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision: 382 $"
|
|
||||||
__date__ = "$Date: 2006-09-25 19:03:48 +0200 (Mon, 25 Sep 2006) $"
|
|
||||||
__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)
|
|
||||||
|
|
403
server/filter.py
403
server/filter.py
|
@ -16,21 +16,20 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 605 $
|
# $Revision: 656 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 605 $"
|
__version__ = "$Revision: 656 $"
|
||||||
__date__ = "$Date: 2007-08-08 00:11:34 +0200 (Wed, 08 Aug 2007) $"
|
__date__ = "$Date: 2008-03-04 01:17:56 +0100 (Tue, 04 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__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.
|
||||||
#
|
#
|
||||||
|
@ -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,104 +228,41 @@ 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
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns true if the line should be ignored.
|
# Returns true if the line should be ignored.
|
||||||
|
@ -428,27 +279,28 @@ class Filter(JailThread):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
##
|
##
|
||||||
# Finds the failure in a line.
|
# 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.
|
||||||
if self.ignoreLine(line):
|
if self.ignoreLine(logLine):
|
||||||
# The ignoreregex matched. Return.
|
# The ignoreregex matched. Return.
|
||||||
return failList
|
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:
|
||||||
|
@ -478,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.
|
||||||
#
|
#
|
||||||
|
@ -488,10 +491,9 @@ import socket, struct
|
||||||
|
|
||||||
class DNSUtils:
|
class DNSUtils:
|
||||||
|
|
||||||
DNS_CRE = re.compile("(?:(?:\w|-)+\.){2,}\w+")
|
|
||||||
IP_CRE = re.compile("(?:\d{1,3}\.){3}\d{1,3}")
|
IP_CRE = re.compile("(?:\d{1,3}\.){3}\d{1,3}")
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def dnsToIp(dns):
|
def dnsToIp(dns):
|
||||||
""" Convert a DNS into an IP address using the Python socket module.
|
""" Convert a DNS into an IP address using the Python socket module.
|
||||||
Thanks to Kevin Drapel.
|
Thanks to Kevin Drapel.
|
||||||
|
@ -502,8 +504,9 @@ class DNSUtils:
|
||||||
logSys.warn("Unable to find a corresponding IP address for %s"
|
logSys.warn("Unable to find a corresponding IP address for %s"
|
||||||
% dns)
|
% dns)
|
||||||
return list()
|
return list()
|
||||||
|
dnsToIp = staticmethod(dnsToIp)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def searchIP(text):
|
def searchIP(text):
|
||||||
""" Search if an IP address if directly available and return
|
""" Search if an IP address if directly available and return
|
||||||
it.
|
it.
|
||||||
|
@ -513,8 +516,9 @@ class DNSUtils:
|
||||||
return match
|
return match
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
searchIP = staticmethod(searchIP)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def isValidIP(string):
|
def isValidIP(string):
|
||||||
""" Return true if str is a valid IP
|
""" Return true if str is a valid IP
|
||||||
"""
|
"""
|
||||||
|
@ -524,8 +528,9 @@ class DNSUtils:
|
||||||
return True
|
return True
|
||||||
except socket.error:
|
except socket.error:
|
||||||
return False
|
return False
|
||||||
|
isValidIP = staticmethod(isValidIP)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def textToIp(text):
|
def textToIp(text):
|
||||||
""" Return the IP of DNS found in a given text.
|
""" Return the IP of DNS found in a given text.
|
||||||
"""
|
"""
|
||||||
|
@ -542,8 +547,9 @@ class DNSUtils:
|
||||||
for e in ip:
|
for e in ip:
|
||||||
ipList.append(e)
|
ipList.append(e)
|
||||||
return ipList
|
return ipList
|
||||||
|
textToIp = staticmethod(textToIp)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def cidr(i, n):
|
def cidr(i, n):
|
||||||
""" Convert an IP address string with a CIDR mask into a 32-bit
|
""" Convert an IP address string with a CIDR mask into a 32-bit
|
||||||
integer.
|
integer.
|
||||||
|
@ -551,15 +557,18 @@ class DNSUtils:
|
||||||
# 32-bit IPv4 address mask
|
# 32-bit IPv4 address mask
|
||||||
MASK = 0xFFFFFFFFL
|
MASK = 0xFFFFFFFFL
|
||||||
return ~(MASK >> n) & MASK & DNSUtils.addr2bin(i)
|
return ~(MASK >> n) & MASK & DNSUtils.addr2bin(i)
|
||||||
|
cidr = staticmethod(cidr)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def addr2bin(string):
|
def addr2bin(string):
|
||||||
""" Convert a string IPv4 address into an unsigned integer.
|
""" Convert a string IPv4 address into an unsigned integer.
|
||||||
"""
|
"""
|
||||||
return struct.unpack("!L", socket.inet_aton(string))[0]
|
return struct.unpack("!L", socket.inet_aton(string))[0]
|
||||||
|
addr2bin = staticmethod(addr2bin)
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def bin2addr(addr):
|
def bin2addr(addr):
|
||||||
""" Convert a numeric IPv4 address into string n.n.n.n form.
|
""" Convert a numeric IPv4 address into string n.n.n.n form.
|
||||||
"""
|
"""
|
||||||
return socket.inet_ntoa(struct.pack("!L", addr))
|
return socket.inet_ntoa(struct.pack("!L", addr))
|
||||||
|
bin2addr = staticmethod(bin2addr)
|
||||||
|
|
|
@ -16,16 +16,16 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 567 $
|
# $Revision: 649 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 567 $"
|
__version__ = "$Revision: 649 $"
|
||||||
__date__ = "$Date: 2007-03-26 23:17:31 +0200 (Mon, 26 Mar 2007) $"
|
__date__ = "$Date: 2008-02-02 18:04:11 +0100 (Sat, 02 Feb 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__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)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -126,6 +126,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
|
||||||
|
|
|
@ -16,16 +16,16 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 567 $
|
# $Revision: 649 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 567 $"
|
__version__ = "$Revision: 649 $"
|
||||||
__date__ = "$Date: 2007-03-26 23:17:31 +0200 (Mon, 26 Mar 2007) $"
|
__date__ = "$Date: 2008-02-02 18:04:11 +0100 (Sat, 02 Feb 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__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,9 +96,9 @@ 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:
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 556 $
|
# $Revision: 635 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 556 $"
|
__version__ = "$Revision: 635 $"
|
||||||
__date__ = "$Date: 2007-03-07 21:54:32 +0100 (Wed, 07 Mar 2007) $"
|
__date__ = "$Date: 2007-12-16 22:38:04 +0100 (Sun, 16 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -46,31 +46,34 @@ class MyTime:
|
||||||
#
|
#
|
||||||
# @param t the time to set or None
|
# @param t the time to set or None
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def setTime(t):
|
def setTime(t):
|
||||||
MyTime.myTime = t
|
MyTime.myTime = t
|
||||||
|
setTime = staticmethod(setTime)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Equivalent to time.time()
|
# Equivalent to time.time()
|
||||||
#
|
#
|
||||||
# @return time.time() if setTime was called with None
|
# @return time.time() if setTime was called with None
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def time():
|
def time():
|
||||||
if MyTime.myTime == None:
|
if MyTime.myTime == None:
|
||||||
return time.time()
|
return time.time()
|
||||||
else:
|
else:
|
||||||
return MyTime.myTime
|
return MyTime.myTime
|
||||||
|
time = staticmethod(time)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Equivalent to time.gmtime()
|
# Equivalent to time.gmtime()
|
||||||
#
|
#
|
||||||
# @return time.gmtime() if setTime was called with None
|
# @return time.gmtime() if setTime was called with None
|
||||||
|
|
||||||
@staticmethod
|
#@staticmethod
|
||||||
def gmtime():
|
def gmtime():
|
||||||
if MyTime.myTime == None:
|
if MyTime.myTime == None:
|
||||||
return time.gmtime()
|
return time.gmtime()
|
||||||
else:
|
else:
|
||||||
return time.gmtime(MyTime.myTime)
|
return time.gmtime(MyTime.myTime)
|
||||||
|
gmtime = staticmethod(gmtime)
|
||||||
|
|
|
@ -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: 589 $
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision: 589 $"
|
|
||||||
__date__ = "$Date: 2007-06-25 23:43:25 +0200 (Mon, 25 Jun 2007) $"
|
|
||||||
__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
|
|
|
@ -16,25 +16,28 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 567 $
|
# $Revision: 647 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 567 $"
|
__version__ = "$Revision: 647 $"
|
||||||
__date__ = "$Date: 2007-03-26 23:17:31 +0200 (Mon, 26 Mar 2007) $"
|
__date__ = "$Date: 2008-01-20 17:30:35 +0100 (Sun, 20 Jan 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__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,16 @@ 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)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
# Install signal handlers
|
# Install signal handlers
|
||||||
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
|
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
|
||||||
|
@ -73,14 +85,26 @@ class Server:
|
||||||
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)
|
||||||
|
@ -142,18 +166,6 @@ class Server:
|
||||||
def getLogPath(self, name):
|
def getLogPath(self, name):
|
||||||
return self.__jails.getFilter(name).getLogPath()
|
return 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 +322,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 +347,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)
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 382 $
|
# $Revision: 638 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 382 $"
|
__version__ = "$Revision: 638 $"
|
||||||
__date__ = "$Date: 2006-09-25 19:03:48 +0200 (Mon, 25 Sep 2006) $"
|
__date__ = "$Date: 2007-12-17 21:00:36 +0100 (Mon, 17 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 503 $
|
# $Revision: 639 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 503 $"
|
__version__ = "$Revision: 639 $"
|
||||||
__date__ = "$Date: 2006-12-23 17:31:00 +0100 (Sat, 23 Dec 2006) $"
|
__date__ = "$Date: 2007-12-17 21:04:29 +0100 (Mon, 17 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -135,14 +135,6 @@ class Transmitter:
|
||||||
value = command[2]
|
value = command[2]
|
||||||
self.__server.delLogPath(name, value)
|
self.__server.delLogPath(name, value)
|
||||||
return self.__server.getLogPath(name)
|
return self.__server.getLogPath(name)
|
||||||
elif command[1] == "timeregex":
|
|
||||||
value = command[2]
|
|
||||||
self.__server.setTimeRegex(name, value)
|
|
||||||
return self.__server.getTimeRegex(name)
|
|
||||||
elif command[1] == "timepattern":
|
|
||||||
value = command[2]
|
|
||||||
self.__server.setTimePattern(name, value)
|
|
||||||
return self.__server.getTimePattern(name)
|
|
||||||
elif command[1] == "addfailregex":
|
elif command[1] == "addfailregex":
|
||||||
value = command[2]
|
value = command[2]
|
||||||
self.__server.addFailRegex(name, value)
|
self.__server.addFailRegex(name, value)
|
||||||
|
@ -229,10 +221,6 @@ class Transmitter:
|
||||||
return self.__server.getLogPath(name)
|
return self.__server.getLogPath(name)
|
||||||
elif command[1] == "ignoreip":
|
elif command[1] == "ignoreip":
|
||||||
return self.__server.getIgnoreIP(name)
|
return self.__server.getIgnoreIP(name)
|
||||||
elif command[1] == "timeregex":
|
|
||||||
return self.__server.getTimeRegex(name)
|
|
||||||
elif command[1] == "timepattern":
|
|
||||||
return self.__server.getTimePattern(name)
|
|
||||||
elif command[1] == "failregex":
|
elif command[1] == "failregex":
|
||||||
return self.__server.getFailRegex(name)
|
return self.__server.getFailRegex(name)
|
||||||
elif command[1] == "ignoreregex":
|
elif command[1] == "ignoreregex":
|
||||||
|
|
10
setup.py
10
setup.py
|
@ -18,11 +18,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 522 $
|
# $Revision: 671 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 522 $"
|
__version__ = "$Revision: 671 $"
|
||||||
__date__ = "$Date: 2007-01-21 23:19:57 +0100 (Sun, 21 Jan 2007) $"
|
__date__ = "$Date: 2008-03-06 00:12:41 +0100 (Thu, 06 Mar 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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 = [
|
||||||
|
|
|
@ -16,17 +16,17 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 382 $
|
# $Revision: 638 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 382 $"
|
__version__ = "$Revision: 638 $"
|
||||||
__date__ = "$Date: 2006-09-25 19:03:48 +0200 (Mon, 25 Sep 2006) $"
|
__date__ = "$Date: 2007-12-17 21:00:36 +0100 (Mon, 17 Dec 2007) $"
|
||||||
__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):
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 504 $
|
# $Revision: 650 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 504 $"
|
__version__ = "$Revision: 650 $"
|
||||||
__date__ = "$Date: 2006-12-23 17:37:17 +0100 (Sat, 23 Dec 2006) $"
|
__date__ = "$Date: 2008-02-02 21:07:06 +0100 (Sat, 02 Feb 2008) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -16,18 +16,17 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 382 $
|
# $Revision: 638 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 382 $"
|
__version__ = "$Revision: 638 $"
|
||||||
__date__ = "$Date: 2006-09-25 19:03:48 +0200 (Mon, 25 Sep 2006) $"
|
__date__ = "$Date: 2007-12-17 21:00:36 +0100 (Mon, 17 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__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):
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,17 @@
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
# $Revision: 503 $
|
# $Revision: 641 $
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__version__ = "$Revision: 503 $"
|
__version__ = "$Revision: 641 $"
|
||||||
__date__ = "$Date: 2006-12-23 17:31:00 +0100 (Sat, 23 Dec 2006) $"
|
__date__ = "$Date: 2007-12-26 12:46:22 +0100 (Wed, 26 Dec 2007) $"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__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."""
|
||||||
|
@ -86,7 +86,7 @@ class GetFailures(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
self.__filter = Filter(None)
|
self.__filter = FileFilter(None)
|
||||||
self.__filter.setActive(True)
|
self.__filter.setActive(True)
|
||||||
# TODO Test this
|
# TODO Test this
|
||||||
#self.__filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
#self.__filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
||||||
|
|
Loading…
Reference in New Issue