mirror of https://github.com/fail2ban/fail2ban
Merge branch 'upstream' into debian
* upstream: (22 commits) Imported Upstream version 0.8.3 - Prepared for 0.8.3. - Prepared for 0.8.3 - Send file if the number of lines is greater or equal and not only equal to the limit. - Use poll instead of select in asyncore.loop. This should solve the "Unknown error 514". Thanks to Michael Geiger and Klaus Lehmann. - Added missing ignoreregex to filters. Thanks to Klaus Lehmann. - Added and changed some logging level and messages. - Added svn:keywords. - Added ISO 8601 date/time format. - Better (correct) fix for ignoreregex in jail.[conf|local]. - Fixed ignoreregex processing in fail2ban-client. Thanks to René Berber. - Added "Day/Month/Year Hour:Minute:Second" date template. Thanks to Dennis Winter. - Added svn:keywords. - Added gssftpd filter. Thanks to Kevin Zembower. - Changed some log level. - Fixed "fail2ban-client get <jail> logpath". Bug #1916986. - Fixed PID file while started in daemon mode. Thanks to Christian Jobic who submitted a similar patch. - Fixed socket path in redhat and suse init script. Thanks to Jim Wight. - Create /var/run/fail2ban during install. - Added "pam-generic" filter and more configuration fixes. Thanks to Yaroslav Halchenko. ...pull/3/head
commit
9eb96ab812
29
COPYING
29
COPYING
|
@ -1,3 +1,7 @@
|
|||
The following copyright applies to all files present in the Fail2ban package,
|
||||
except if a different copyright is explicitly defined in this file.
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
|
@ -337,3 +341,28 @@ proprietary programs. If your program is a subroutine library, you may
|
|||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
||||
---------------------------------
|
||||
The file server/iso8601.py is licensed under the following terms.
|
||||
|
||||
|
||||
Copyright (c) 2007 Michael Twomey
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
25
ChangeLog
25
ChangeLog
|
@ -4,9 +4,32 @@
|
|||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||
|
||||
=============================================================
|
||||
Fail2Ban (version 0.8.2) 2008/03/06
|
||||
Fail2Ban (version 0.8.3) 2008/07/17
|
||||
=============================================================
|
||||
|
||||
ver. 0.8.3 (2008/07/17) - stable
|
||||
----------
|
||||
- Process failtickets as long as failmanager is not empty.
|
||||
- Added "pam-generic" filter and more configuration fixes.
|
||||
Thanks to Yaroslav Halchenko.
|
||||
- Fixed socket path in redhat and suse init script. Thanks to
|
||||
Jim Wight.
|
||||
- Fixed PID file while started in daemon mode. Thanks to
|
||||
Christian Jobic who submitted a similar patch.
|
||||
- Fixed "fail2ban-client get <jail> logpath". Bug #1916986.
|
||||
- Added gssftpd filter. Thanks to Kevin Zembower.
|
||||
- Added "Day/Month/Year Hour:Minute:Second" date template.
|
||||
Thanks to Dennis Winter.
|
||||
- Fixed ignoreregex processing in fail2ban-client. Thanks to
|
||||
René Berber.
|
||||
- Added ISO 8601 date/time format.
|
||||
- Added and changed some logging level and messages.
|
||||
- Added missing ignoreregex to filters. Thanks to Klaus
|
||||
Lehmann.
|
||||
- Use poll instead of select in asyncore.loop. This should
|
||||
solve the "Unknown error 514". Thanks to Michael Geiger and
|
||||
Klaus Lehmann.
|
||||
|
||||
ver. 0.8.2 (2008/03/06) - stable
|
||||
----------
|
||||
- Fixed named filter. Thanks to Yaroslav Halchenko
|
||||
|
|
2
PKG-INFO
2
PKG-INFO
|
@ -1,6 +1,6 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: fail2ban
|
||||
Version: 0.8.2
|
||||
Version: 0.8.3
|
||||
Summary: Ban IPs that make too many password failure
|
||||
Home-page: http://www.fail2ban.org
|
||||
Author: Cyril Jaquier
|
||||
|
|
6
README
6
README
|
@ -4,7 +4,7 @@
|
|||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||
|
||||
=============================================================
|
||||
Fail2Ban (version 0.8.2) 2008/03/06
|
||||
Fail2Ban (version 0.8.3) 2008/07/17
|
||||
=============================================================
|
||||
|
||||
Fail2Ban scans log files like /var/log/pwdfail and bans IP
|
||||
|
@ -28,8 +28,8 @@ Optional:
|
|||
|
||||
To install, just do:
|
||||
|
||||
> tar xvfj fail2ban-0.8.2.tar.bz2
|
||||
> cd fail2ban-0.8.2
|
||||
> tar xvfj fail2ban-0.8.3.tar.bz2
|
||||
> cd fail2ban-0.8.3
|
||||
> python setup.py install
|
||||
|
||||
This will install Fail2Ban into /usr/share/fail2ban. The
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 659 $
|
||||
# $Revision: 690 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 659 $"
|
||||
__date__ = "$Date: 2008-03-05 00:09:30 +0100 (Wed, 05 Mar 2008) $"
|
||||
__version__ = "$Revision: 690 $"
|
||||
__date__ = "$Date: 2008-05-12 10:34:42 +0200 (Mon, 12 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -122,7 +122,10 @@ class JailReader(ConfigReader):
|
|||
elif opt == "failregex":
|
||||
stream.append(["set", self.__name, "failregex", self.__opts[opt]])
|
||||
elif opt == "ignoreregex":
|
||||
stream.append(["set", self.__name, "ignoreregex", self.__opts[opt]])
|
||||
for regex in self.__opts[opt].split('\n'):
|
||||
# Do not send a command if the rule is empty.
|
||||
if regex != '':
|
||||
stream.append(["set", self.__name, "addignoreregex", regex])
|
||||
stream.extend(self.__filter.convert())
|
||||
for action in self.__actions:
|
||||
stream.extend(action.convert())
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 673 $
|
||||
# $Revision: 703 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 673 $"
|
||||
__date__ = "$Date: 2008-03-06 00:19:45 +0100 (Thu, 06 Mar 2008) $"
|
||||
__version__ = "$Revision: 703 $"
|
||||
__date__ = "$Date: 2008-07-17 23:28:51 +0200 (Thu, 17 Jul 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 668 $
|
||||
# $Revision: 701 $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
@ -50,7 +50,7 @@ actioncheck =
|
|||
#
|
||||
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||
LINE=$( wc -l <tmpfile> | awk '{ print $1 }' )
|
||||
if [ $LINE -eq <lines> ]; then
|
||||
if [ $LINE -ge <lines> ]; then
|
||||
printf %%b "Hi,\n
|
||||
These hosts have been banned by Fail2Ban.\n
|
||||
`cat <tmpfile>`
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 660 $
|
||||
# $Revision: 701 $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
@ -59,7 +59,7 @@ actioncheck =
|
|||
#
|
||||
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||
LINE=$( wc -l <tmpfile> | awk '{ print $1 }' )
|
||||
if [ $LINE -eq <lines> ]; then
|
||||
if [ $LINE -ge <lines> ]; then
|
||||
printf %%b "Subject: [Fail2Ban] <name>: summary
|
||||
From: Fail2Ban <<sender>>
|
||||
To: <dest>\n
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Fail2Ban configuration file for wuftpd
|
||||
#
|
||||
# Author: Kevin Zembower (copied from wsftpd.conf)
|
||||
#
|
||||
# $Revision: 699 $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
||||
# Option: failregex
|
||||
# Notes.: regex to match the password failures messages in the logfile.
|
||||
# Values: TEXT
|
||||
#
|
||||
failregex = ftpd(?:\[\d+\])?:\s+repeated login failures from <HOST> \(\S+\)$
|
||||
|
||||
# Option: ignoreregex
|
||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||
# Values: TEXT
|
||||
#
|
||||
ignoreregex =
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# Author: Yaroslav Halchenko
|
||||
#
|
||||
# $Revision: 616 $
|
||||
# $Revision: 699 $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
@ -28,4 +28,8 @@ __line_prefix=(?:\s\S+ %(__daemon_combs_re)s\s+)?
|
|||
#
|
||||
failregex = %(__line_prefix)sclient <HOST>#\S+: query(?: \(cache\))? '.*' denied\s*$
|
||||
|
||||
|
||||
# Option: ignoreregex
|
||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||
# Values: TEXT
|
||||
#
|
||||
ignoreregex =
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Fail2Ban configuration file for generic PAM authentication errors
|
||||
#
|
||||
# Author: Yaroslav Halchenko
|
||||
#
|
||||
# $Revision: $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
||||
# if you want to catch only login erros from specific daemons, use smth like
|
||||
#_ttys_re=(?:ssh|pure-ftpd|ftp)
|
||||
# To catch all failed logins
|
||||
_ttys_re=\S*
|
||||
|
||||
#
|
||||
# Shortcuts for easier comprehension of the failregex
|
||||
__pid_re=(?:\[\d+\])
|
||||
__pam_re=\(?pam_unix(?:\(\S+\))?\)?:?
|
||||
__pam_combs_re=(?:%(__pid_re)s?:\s+%(__pam_re)s|%(__pam_re)s%(__pid_re)s?:)
|
||||
|
||||
# Option: failregex
|
||||
# Notes.: regex to match the password failures messages in the logfile.
|
||||
# Values: TEXT
|
||||
#
|
||||
failregex = \s\S+ \S+%(__pam_combs_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=%(_ttys_re)s ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
||||
|
||||
# Option: ignoreregex
|
||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||
# Values: TEXT
|
||||
#
|
||||
ignoreregex =
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Author: Yaroslav Halchenko
|
||||
#
|
||||
# $Revision: 665 $
|
||||
# $Revision: 677 $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
@ -14,7 +14,7 @@
|
|||
# (?:::f{4,6}:)?(?P<host>\S+)
|
||||
# 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+ \[\S+\] to \S+:\S+$
|
||||
\(\S+\[<HOST>\]\)[: -]+ USER \S+ \(Login failed\): Incorrect password\.$
|
||||
\(\S+\[<HOST>\]\)[: -]+ SECURITY VIOLATION: \S+ login attempted\.$
|
||||
\(\S+\[<HOST>\]\)[: -]+ Maximum login attempts \(\d+\) exceeded$
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Author: Yaroslav Halchenko
|
||||
#
|
||||
# $Revision: 592 $
|
||||
# $Revision: 699 $
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
@ -12,3 +12,9 @@
|
|||
# Values: TEXT
|
||||
#
|
||||
failregex = wu-ftpd(?:\[\d+\])?:\s+\(pam_unix\)\s+authentication failure.* rhost=<HOST>$
|
||||
|
||||
# Option: ignoreregex
|
||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||
# Values: TEXT
|
||||
#
|
||||
ignoreregex =
|
||||
|
|
|
@ -27,7 +27,7 @@ start() {
|
|||
echo -n $"Starting fail2ban: "
|
||||
getpid
|
||||
if [ -z "$pid" ]; then
|
||||
rm -rf /tmp/fail2ban.sock # in case of unclean shutdown
|
||||
rm -rf /var/run/fail2ban/fail2ban.sock # in case of unclean shutdown
|
||||
$FAIL2BAN start > /dev/null
|
||||
RETVAL=$?
|
||||
fi
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/sbin:/usr/bin:/bin
|
||||
FAIL2BAN_BIN=/usr/local/bin/fail2ban-client
|
||||
FAIL2BAN_SERVER=/usr/local/bin/fail2ban-server
|
||||
FAIL2BAN_SOCKET=/tmp/fail2ban.sock
|
||||
FAIL2BAN_SOCKET=/var/run/fail2ban/fail2ban.sock
|
||||
test -x $FAIL2BAN_BIN || { echo "$FAIL2BAN_BIN not installed";
|
||||
if [ "$1" = "stop" ]; then exit 0;
|
||||
else exit 5; fi; }
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 635 $
|
||||
# $Revision: 682 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 635 $"
|
||||
__date__ = "$Date: 2007-12-16 22:38:04 +0100 (Sun, 16 Dec 2007) $"
|
||||
__version__ = "$Revision: 682 $"
|
||||
__date__ = "$Date: 2008-04-08 00:25:16 +0200 (Tue, 08 Apr 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -106,7 +106,7 @@ class Action:
|
|||
|
||||
def setActionStart(self, value):
|
||||
self.__actionStart = value
|
||||
logSys.info("Set actionStart = %s" % value)
|
||||
logSys.debug("Set actionStart = %s" % value)
|
||||
|
||||
##
|
||||
# Get the "start" command.
|
||||
|
@ -135,7 +135,7 @@ class Action:
|
|||
|
||||
def setActionBan(self, value):
|
||||
self.__actionBan = value
|
||||
logSys.info("Set actionBan = %s" % value)
|
||||
logSys.debug("Set actionBan = %s" % value)
|
||||
|
||||
##
|
||||
# Get the "ban" command.
|
||||
|
@ -160,7 +160,7 @@ class Action:
|
|||
|
||||
def setActionUnban(self, value):
|
||||
self.__actionUnban = value
|
||||
logSys.info("Set actionUnban = %s" % value)
|
||||
logSys.debug("Set actionUnban = %s" % value)
|
||||
|
||||
##
|
||||
# Get the "unban" command.
|
||||
|
@ -185,7 +185,7 @@ class Action:
|
|||
|
||||
def setActionCheck(self, value):
|
||||
self.__actionCheck = value
|
||||
logSys.info("Set actionCheck = %s" % value)
|
||||
logSys.debug("Set actionCheck = %s" % value)
|
||||
|
||||
##
|
||||
# Get the "check" command.
|
||||
|
@ -202,7 +202,7 @@ class Action:
|
|||
|
||||
def setActionStop(self, value):
|
||||
self.__actionStop = value
|
||||
logSys.info("Set actionStop = %s" % value)
|
||||
logSys.debug("Set actionStop = %s" % value)
|
||||
|
||||
##
|
||||
# Get the "stop" command.
|
||||
|
|
|
@ -132,7 +132,7 @@ class AsyncServer(asyncore.dispatcher):
|
|||
# Sets the init flag.
|
||||
self.__init = True
|
||||
# TODO Add try..catch
|
||||
asyncore.loop()
|
||||
asyncore.loop(use_poll = True)
|
||||
|
||||
##
|
||||
# Stops the communication server.
|
||||
|
|
|
@ -16,19 +16,17 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 645 $
|
||||
# $Revision: 692 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 645 $"
|
||||
__date__ = "$Date: 2008-01-16 23:55:04 +0100 (Wed, 16 Jan 2008) $"
|
||||
__version__ = "$Revision: 692 $"
|
||||
__date__ = "$Date: 2008-05-18 21:53:18 +0200 (Sun, 18 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import time, logging
|
||||
|
||||
from datetemplate import DateStrptime
|
||||
from datetemplate import DateTai64n
|
||||
from datetemplate import DateEpoch
|
||||
from datetemplate import DateStrptime, DateTai64n, DateEpoch, DateISO8601
|
||||
from threading import Lock
|
||||
|
||||
# Gets the instance of the logger.
|
||||
|
@ -67,6 +65,12 @@ class DateDetector:
|
|||
template.setRegex("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}")
|
||||
template.setPattern("%Y/%m/%d %H:%M:%S")
|
||||
self.__templates.append(template)
|
||||
# simple date too (from x11vnc)
|
||||
template = DateStrptime()
|
||||
template.setName("Day/Month/Year Hour:Minute:Second")
|
||||
template.setRegex("\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}")
|
||||
template.setPattern("%d/%m/%Y %H:%M:%S")
|
||||
self.__templates.append(template)
|
||||
# Apache format [31/Oct/2006:09:22:55 -0000]
|
||||
template = DateStrptime()
|
||||
template.setName("Day/Month/Year:Hour:Minute:Second")
|
||||
|
@ -93,6 +97,10 @@ class DateDetector:
|
|||
template = DateEpoch()
|
||||
template.setName("Epoch")
|
||||
self.__templates.append(template)
|
||||
# ISO 8601
|
||||
template = DateISO8601()
|
||||
template.setName("ISO 8601")
|
||||
self.__templates.append(template)
|
||||
finally:
|
||||
self.__lock.release()
|
||||
|
||||
|
|
|
@ -17,17 +17,18 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 652 $
|
||||
# $Revision: 692 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 652 $"
|
||||
__date__ = "$Date: 2008-02-29 00:01:30 +0100 (Fri, 29 Feb 2008) $"
|
||||
__version__ = "$Revision: 692 $"
|
||||
__date__ = "$Date: 2008-05-18 21:53:18 +0200 (Sun, 18 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import re, time
|
||||
|
||||
from mytime import MyTime
|
||||
import iso8601
|
||||
|
||||
class DateTemplate:
|
||||
|
||||
|
@ -164,3 +165,23 @@ class DateTai64n(DateTemplate):
|
|||
seconds_since_epoch = value[2:17]
|
||||
date = list(time.gmtime(int(seconds_since_epoch, 16)))
|
||||
return date
|
||||
|
||||
|
||||
class DateISO8601(DateTemplate):
|
||||
|
||||
def __init__(self):
|
||||
DateTemplate.__init__(self)
|
||||
date_re = "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}" \
|
||||
".[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?" \
|
||||
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?"
|
||||
self.setRegex(date_re)
|
||||
|
||||
def getDate(self, line):
|
||||
date = None
|
||||
dateMatch = self.matchDate(line)
|
||||
if dateMatch:
|
||||
# Parses the date.
|
||||
value = dateMatch.group()
|
||||
print value
|
||||
date = list(iso8601.parse_date(value).utctimetuple())
|
||||
return date
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 656 $
|
||||
# $Revision: 696 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 656 $"
|
||||
__date__ = "$Date: 2008-03-04 01:17:56 +0100 (Tue, 04 Mar 2008) $"
|
||||
__version__ = "$Revision: 696 $"
|
||||
__date__ = "$Date: 2008-05-19 23:05:32 +0200 (Mon, 19 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -68,7 +68,7 @@ class Filter(JailThread):
|
|||
|
||||
self.dateDetector = DateDetector()
|
||||
self.dateDetector.addDefaultTemplate()
|
||||
logSys.info("Created Filter")
|
||||
logSys.debug("Created Filter")
|
||||
|
||||
|
||||
##
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 649 $
|
||||
# $Revision: 696 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 649 $"
|
||||
__date__ = "$Date: 2008-02-02 18:04:11 +0100 (Sat, 02 Feb 2008) $"
|
||||
__version__ = "$Revision: 696 $"
|
||||
__date__ = "$Date: 2008-05-19 23:05:32 +0200 (Mon, 19 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -53,7 +53,7 @@ class FilterGamin(FileFilter):
|
|||
self.__modified = False
|
||||
# Gamin monitor
|
||||
self.monitor = gamin.WatchMonitor()
|
||||
logSys.info("Created FilterGamin")
|
||||
logSys.debug("Created FilterGamin")
|
||||
|
||||
|
||||
def callback(self, path, event):
|
||||
|
@ -108,6 +108,7 @@ class FilterGamin(FileFilter):
|
|||
|
||||
if self.__modified:
|
||||
try:
|
||||
while True:
|
||||
ticket = self.failManager.toBan()
|
||||
self.jail.putFailTicket(ticket)
|
||||
except FailManagerEmpty:
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 649 $
|
||||
# $Revision: 696 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 649 $"
|
||||
__date__ = "$Date: 2008-02-02 18:04:11 +0100 (Sat, 02 Feb 2008) $"
|
||||
__version__ = "$Revision: 696 $"
|
||||
__date__ = "$Date: 2008-05-19 23:05:32 +0200 (Mon, 19 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -54,7 +54,7 @@ class FilterPoll(FileFilter):
|
|||
## The time of the last modification of the file.
|
||||
self.__lastModTime = dict()
|
||||
self.__file404Cnt = dict()
|
||||
logSys.info("Created FilterPoll")
|
||||
logSys.debug("Created FilterPoll")
|
||||
|
||||
##
|
||||
# Add a log file path
|
||||
|
@ -103,6 +103,7 @@ class FilterPoll(FileFilter):
|
|||
|
||||
if self.__modified:
|
||||
try:
|
||||
while True:
|
||||
ticket = self.failManager.toBan()
|
||||
self.jail.putFailTicket(ticket)
|
||||
except FailManagerEmpty:
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
# Copyright (c) 2007 Michael Twomey
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
"""ISO 8601 date time string parsing
|
||||
|
||||
Basic usage:
|
||||
>>> import iso8601
|
||||
>>> iso8601.parse_date("2007-01-25T12:00:00Z")
|
||||
datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>)
|
||||
>>>
|
||||
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
import re
|
||||
|
||||
__all__ = ["parse_date", "ParseError"]
|
||||
|
||||
# Adapted from http://delete.me.uk/2005/03/iso8601.html
|
||||
ISO8601_REGEX = re.compile(r"(?P<year>[0-9]{4})(-(?P<month>[0-9]{1,2})(-(?P<day>[0-9]{1,2})"
|
||||
r"((?P<separator>.)(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2})(:(?P<second>[0-9]{2})(\.(?P<fraction>[0-9]+))?)?"
|
||||
r"(?P<timezone>Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"
|
||||
)
|
||||
TIMEZONE_REGEX = re.compile("(?P<prefix>[+-])(?P<hours>[0-9]{2}).(?P<minutes>[0-9]{2})")
|
||||
|
||||
class ParseError(Exception):
|
||||
"""Raised when there is a problem parsing a date string"""
|
||||
|
||||
# Yoinked from python docs
|
||||
ZERO = timedelta(0)
|
||||
class Utc(tzinfo):
|
||||
"""UTC
|
||||
|
||||
"""
|
||||
def utcoffset(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC"
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
UTC = Utc()
|
||||
|
||||
class FixedOffset(tzinfo):
|
||||
"""Fixed offset in hours and minutes from UTC
|
||||
|
||||
"""
|
||||
def __init__(self, offset_hours, offset_minutes, name):
|
||||
self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes)
|
||||
self.__name = name
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self.__offset
|
||||
|
||||
def tzname(self, dt):
|
||||
return self.__name
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
def __repr__(self):
|
||||
return "<FixedOffset %r>" % self.__name
|
||||
|
||||
def parse_timezone(tzstring, default_timezone=UTC):
|
||||
"""Parses ISO 8601 time zone specs into tzinfo offsets
|
||||
|
||||
"""
|
||||
if tzstring == "Z":
|
||||
return default_timezone
|
||||
# This isn't strictly correct, but it's common to encounter dates without
|
||||
# timezones so I'll assume the default (which defaults to UTC).
|
||||
# Addresses issue 4.
|
||||
if tzstring is None:
|
||||
return default_timezone
|
||||
m = TIMEZONE_REGEX.match(tzstring)
|
||||
prefix, hours, minutes = m.groups()
|
||||
hours, minutes = int(hours), int(minutes)
|
||||
if prefix == "-":
|
||||
hours = -hours
|
||||
minutes = -minutes
|
||||
return FixedOffset(hours, minutes, tzstring)
|
||||
|
||||
def parse_date(datestring, default_timezone=UTC):
|
||||
"""Parses ISO 8601 dates into datetime objects
|
||||
|
||||
The timezone is parsed from the date string. However it is quite common to
|
||||
have dates without a timezone (not strictly correct). In this case the
|
||||
default timezone specified in default_timezone is used. This is UTC by
|
||||
default.
|
||||
"""
|
||||
if not isinstance(datestring, basestring):
|
||||
raise ParseError("Expecting a string %r" % datestring)
|
||||
m = ISO8601_REGEX.match(datestring)
|
||||
if not m:
|
||||
raise ParseError("Unable to parse date string %r" % datestring)
|
||||
groups = m.groupdict()
|
||||
tz = parse_timezone(groups["timezone"], default_timezone=default_timezone)
|
||||
if groups["fraction"] is None:
|
||||
groups["fraction"] = 0
|
||||
else:
|
||||
groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6)
|
||||
return datetime(int(groups["year"]), int(groups["month"]), int(groups["day"]),
|
||||
int(groups["hour"]), int(groups["minute"]), int(groups["second"]),
|
||||
int(groups["fraction"]), tz)
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 567 $
|
||||
# $Revision: 696 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 567 $"
|
||||
__date__ = "$Date: 2007-03-26 23:17:31 +0200 (Mon, 26 Mar 2007) $"
|
||||
__version__ = "$Revision: 696 $"
|
||||
__date__ = "$Date: 2008-05-19 23:05:32 +0200 (Mon, 19 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -37,6 +37,7 @@ class Jail:
|
|||
self.__name = name
|
||||
self.__queue = Queue.Queue()
|
||||
self.__filter = None
|
||||
logSys.info("Creating new jail '%s'" % self.__name)
|
||||
if backend == "polling":
|
||||
self.__initPoller()
|
||||
else:
|
||||
|
@ -47,14 +48,14 @@ class Jail:
|
|||
self.__action = Actions(self)
|
||||
|
||||
def __initPoller(self):
|
||||
logSys.info("Using poller")
|
||||
logSys.info("Jail '%s' uses poller" % self.__name)
|
||||
from filterpoll import FilterPoll
|
||||
self.__filter = FilterPoll(self)
|
||||
|
||||
def __initGamin(self):
|
||||
# Try to import gamin
|
||||
import gamin
|
||||
logSys.info("Using Gamin")
|
||||
logSys.info("Jail '%s' uses Gamin" % self.__name)
|
||||
from filtergamin import FilterGamin
|
||||
self.__filter = FilterGamin(self)
|
||||
|
||||
|
@ -82,12 +83,14 @@ class Jail:
|
|||
def start(self):
|
||||
self.__filter.start()
|
||||
self.__action.start()
|
||||
logSys.info("Jail '%s' started" % self.__name)
|
||||
|
||||
def stop(self):
|
||||
self.__filter.stop()
|
||||
self.__action.stop()
|
||||
self.__filter.join()
|
||||
self.__action.join()
|
||||
logSys.info("Jail '%s' stopped" % self.__name)
|
||||
|
||||
def isAlive(self):
|
||||
isAlive0 = self.__filter.isAlive()
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 647 $
|
||||
# $Revision: 696 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 647 $"
|
||||
__date__ = "$Date: 2008-01-20 17:30:35 +0100 (Sun, 20 Jan 2008) $"
|
||||
__version__ = "$Revision: 696 $"
|
||||
__date__ = "$Date: 2008-05-19 23:05:32 +0200 (Mon, 19 May 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -46,11 +46,11 @@ class Server:
|
|||
self.__daemon = daemon
|
||||
self.__transm = Transmitter(self)
|
||||
self.__asyncServer = AsyncServer(self.__transm)
|
||||
self.__logLevel = 3
|
||||
self.__logTarget = "STDOUT"
|
||||
self.__logLevel = None
|
||||
self.__logTarget = None
|
||||
# Set logging level
|
||||
self.setLogLevel(self.__logLevel)
|
||||
self.setLogTarget(self.__logTarget)
|
||||
self.setLogLevel(3)
|
||||
self.setLogTarget("STDOUT")
|
||||
|
||||
def __sigTERMhandler(self, signum, frame):
|
||||
logSys.debug("Caught signal %d. Exiting" % signum)
|
||||
|
@ -59,6 +59,21 @@ class Server:
|
|||
def start(self, sock, force = False):
|
||||
logSys.info("Starting Fail2ban v" + version.version)
|
||||
|
||||
# Install signal handlers
|
||||
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
|
||||
signal.signal(signal.SIGINT, self.__sigTERMhandler)
|
||||
|
||||
# First set the mask to only allow access to owner
|
||||
os.umask(0077)
|
||||
if self.__daemon:
|
||||
logSys.info("Starting in daemon mode")
|
||||
ret = self.__createDaemon()
|
||||
if ret:
|
||||
logSys.info("Daemon started")
|
||||
else:
|
||||
logSys.error("Could not create daemon")
|
||||
raise ServerInitializationError("Could not create daemon")
|
||||
|
||||
# Creates a PID file.
|
||||
try:
|
||||
logSys.debug("Creating PID file %s" % Server.PID_FILE)
|
||||
|
@ -68,19 +83,6 @@ class Server:
|
|||
except IOError, e:
|
||||
logSys.error("Unable to create PID file: %s" % e)
|
||||
|
||||
# Install signal handlers
|
||||
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
|
||||
signal.signal(signal.SIGINT, self.__sigTERMhandler)
|
||||
|
||||
# First set the mask to only allow access to owner
|
||||
os.umask(0077)
|
||||
if self.__daemon:
|
||||
ret = self.__createDaemon()
|
||||
if ret:
|
||||
logSys.info("Daemon started")
|
||||
else:
|
||||
logSys.error("Could not create daemon")
|
||||
raise ServerInitializationError("Could not create daemon")
|
||||
# Start the communication
|
||||
logSys.debug("Starting communication")
|
||||
try:
|
||||
|
@ -164,7 +166,8 @@ class Server:
|
|||
self.__jails.getFilter(name).delLogPath(fileName)
|
||||
|
||||
def getLogPath(self, name):
|
||||
return self.__jails.getFilter(name).getLogPath()
|
||||
return [m.getFileName()
|
||||
for m in self.__jails.getFilter(name).getLogPath()]
|
||||
|
||||
def setFindTime(self, name, value):
|
||||
self.__jails.getFilter(name).setFindTime(value)
|
||||
|
@ -343,7 +346,6 @@ class Server:
|
|||
logSys.error("Unable to log to " + target)
|
||||
logSys.info("Logging to previous target " + self.__logTarget)
|
||||
return False
|
||||
self.__logTarget = target
|
||||
# Removes previous handlers
|
||||
for handler in logging.getLogger("fail2ban").handlers:
|
||||
# Closes the handler.
|
||||
|
@ -352,6 +354,12 @@ class Server:
|
|||
# tell the handler to use this format
|
||||
hdlr.setFormatter(formatter)
|
||||
logging.getLogger("fail2ban").addHandler(hdlr)
|
||||
# Does not display this message at startup.
|
||||
if not self.__logTarget == None:
|
||||
logSys.info("Changed logging target to %s for Fail2ban v%s" %
|
||||
(target, version.version))
|
||||
# Sets the logging target.
|
||||
self.__logTarget = target
|
||||
return True
|
||||
finally:
|
||||
self.__loggingLock.release()
|
||||
|
|
9
setup.py
9
setup.py
|
@ -18,11 +18,11 @@
|
|||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision: 671 $
|
||||
# $Revision: 678 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 671 $"
|
||||
__date__ = "$Date: 2008-03-06 00:12:41 +0100 (Thu, 06 Mar 2008) $"
|
||||
__version__ = "$Revision: 678 $"
|
||||
__date__ = "$Date: 2008-03-10 23:34:46 +0100 (Mon, 10 Mar 2008) $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
@ -68,6 +68,9 @@ setup(
|
|||
),
|
||||
('/etc/fail2ban/action.d',
|
||||
glob("config/action.d/*.conf")
|
||||
),
|
||||
('/var/run/fail2ban',
|
||||
''
|
||||
)
|
||||
]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue