Upgraded to fresh upstream 0.7.8

debian-upstream sdist/0.7.8
Yaroslav Halchenko 2007-10-16 17:01:22 -04:00
commit d77f67bb89
24 changed files with 558 additions and 172 deletions

View File

@ -4,9 +4,17 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_| |_| \__,_|_|_/___|_.__/\__,_|_||_|
============================================================= =============================================================
Fail2Ban (version 0.7.7) 2007/02/08 Fail2Ban (version 0.7.8) 2007/03/21
============================================================= =============================================================
ver. 0.7.8 (2007/03/21) - release candidate
----------
- Fixed asctime pattern in datedetector.py
- Added new filters/actions. Thanks to Yaroslav Halchenko
- Added Suse init script and modified gentoo-initd. Thanks to
Christian Rauch
- Moved every locking statements in a try..finally block
ver. 0.7.7 (2007/02/08) - release candidate ver. 0.7.7 (2007/02/08) - release candidate
---------- ----------
- Added signal handling in fail2ban-client - Added signal handling in fail2ban-client

View File

@ -1,6 +1,6 @@
Metadata-Version: 1.0 Metadata-Version: 1.0
Name: fail2ban Name: fail2ban
Version: 0.7.7 Version: 0.7.8
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://fail2ban.sourceforge.net
Author: Cyril Jaquier Author: Cyril Jaquier

8
README
View File

@ -4,7 +4,7 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_| |_| \__,_|_|_/___|_.__/\__,_|_||_|
============================================================= =============================================================
Fail2Ban (version 0.7.7) 2007/02/08 Fail2Ban (version 0.7.8) 2007/03/21
============================================================= =============================================================
Fail2Ban scans log files like /var/log/pwdfail and bans IP Fail2Ban scans log files like /var/log/pwdfail and bans IP
@ -28,8 +28,8 @@ Optional:
To install, just do: To install, just do:
> tar xvfj fail2ban-0.7.7.tar.bz2 > tar xvfj fail2ban-0.7.8.tar.bz2
> cd fail2ban-0.7.7 > cd fail2ban-0.7.8
> 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
@ -73,7 +73,7 @@ Tom Pike, Iain Lea, Andrey G. Grozin, Yaroslav Halchenko,
Jonathan Kamens, Stephen Gildea, Markus Hoffmann, Mark Jonathan Kamens, Stephen Gildea, Markus Hoffmann, Mark
Edgington, Patrick Börjesson, kojiro, zugeschmiert, Tyler, Edgington, Patrick Börjesson, kojiro, zugeschmiert, Tyler,
Nick Munger, Christoph Haas, Justin Shore, Joël Bertrand, Nick Munger, Christoph Haas, Justin Shore, Joël Bertrand,
René Berber, mEDI, Axel Thimm, Eric Gerbier René Berber, mEDI, Axel Thimm, Eric Gerbier, Christian Rauch
License: License:
-------- --------

14
TODO
View File

@ -4,7 +4,7 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_| |_| \__,_|_|_/___|_.__/\__,_|_||_|
============================================================= =============================================================
ToDo $Revision: 540 $ ToDo $Revision: 557 $
============================================================= =============================================================
Legend: Legend:
@ -13,16 +13,24 @@ Legend:
# partially done # partially done
* done * done
- 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
server/ and client/
- Add timeout to external commands (signal alarm, watchdog - Add timeout to external commands (signal alarm, watchdog
thread, etc) thread, etc)
- New backend: pynotify - New backend: pyinotify
- Uniformize filters and actions name. Use the software name - Uniformize filters and actions name. Use the software name
(openssh, postfix, proftp) (openssh, postfix, proftp)
- Added <USER> tag for failregex. Add features using this - Added <USER> tag for failregex. Add features using this
information information. Maybe add more tags
- Look at the memory consumption. Decrease memory usage - Look at the memory consumption. Decrease memory usage

View File

@ -16,11 +16,11 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 537 $ # $Revision: 547 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 537 $" __version__ = "$Revision: 547 $"
__date__ = "$Date: 2007-02-01 21:50:12 +0100 (Thu, 01 Feb 2007) $" __date__ = "$Date: 2007-02-12 00:21:56 +0100 (Mon, 12 Feb 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
@ -68,13 +68,18 @@ class Beautifier:
msg = "Added jail " + response msg = "Added jail " + response
elif inC[0:1] == ['status']: elif inC[0:1] == ['status']:
if len(inC) > 1: if len(inC) > 1:
# Create IP list
ipList = ""
for ip in response[1][1][2][1]:
ipList += ip + " "
# 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][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"
msg = msg + " |- " + response[1][1][0][0] + ":\t" + `response[1][1][0][1]` + "\n" msg = msg + " |- " + response[1][1][0][0] + ":\t" + `response[1][1][0][1]` + "\n"
msg = msg + " | `- " + response[1][1][2][0] + ":\t" + `response[1][1][2][1]` + "\n" msg = msg + " | `- " + response[1][1][2][0] + ":\t" + ipList + "\n"
msg = msg + " `- " + response[1][1][1][0] + ":\t" + `response[1][1][1][1]` msg = msg + " `- " + response[1][1][1][0] + ":\t" + `response[1][1][1][1]`
else: else:
msg = "Status\n" msg = "Status\n"

View File

@ -16,12 +16,12 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 543 $ # $Revision: 561 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 543 $" __version__ = "$Revision: 561 $"
__date__ = "$Date: 2007-02-08 22:14:01 +0100 (Thu, 08 Feb 2007) $" __date__ = "$Date: 2007-03-21 22:44:07 +0100 (Wed, 21 Mar 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
version = "0.7.7" version = "0.7.8"

View File

@ -2,7 +2,7 @@
# #
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 496 $ # $Revision: 554 $
# #
[Definition] [Definition]
@ -11,13 +11,13 @@
# Notes.: command executed once at the start of Fail2Ban. # Notes.: command executed once at the start of Fail2Ban.
# Values: CMD # Values: CMD
# #
actionstart = touch <tmpfile> actionstart =
# Option: actionend # Option: actionend
# Notes.: command executed once at the end of Fail2Ban # Notes.: command executed once at the end of Fail2Ban
# Values: CMD # Values: CMD
# #
actionstop = rm -f <tmpfile> actionstop =
# Option: actioncheck # Option: actioncheck
# Notes.: command executed once before each actionban command # Notes.: command executed once before each actionban command

View File

@ -0,0 +1,88 @@
# Fail2Ban configuration file
#
# Author: Cyril Jaquier
#
# $Revision: 510 $
#
[Definition]
# Option: actionstart
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD
#
actionstart = echo -en "Hi,\n
The jail <name> has been started successfuly.\n
Output will be buffered until <lines> lines are available.\n
Regards,\n
Fail2Ban"|mail -s "[Fail2Ban] <name>: started" <dest>
# Option: actionend
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop = if [ -d <tmpfile> ]; then
echo -en "Hi,\n
These hosts have been banned by Fail2Ban.\n
`cat <tmpfile>`
Regards,\n
Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary" <dest>
rm <tmpfile>
fi
echo -en "Hi,\n
The jail <name> has been stopped.\n
Regards,\n
Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped" <dest>
# Option: actioncheck
# Notes.: command executed once before each actionban command
# Values: CMD
#
actioncheck =
# Option: actionban
# Notes.: command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <time> unix timestamp of the ban time
# Values: CMD
#
actionban = echo `date`": <ip> (<failures> failures)" >> <tmpfile>
LINE=$( wc -l <tmpfile> | awk '{ print $1 }' )
if [ $LINE -eq <lines> ]; then
echo -en "Hi,\n
These hosts have been banned by Fail2Ban.\n
`cat <tmpfile>`
Regards,\n
Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary" <dest>
rm <tmpfile>
fi
# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <time> unix timestamp of the ban time
# Values: CMD
#
actionunban =
[Init]
# Default name of the chain
#
name = default
# Default number of lines that are buffered
#
lines = 5
# Default temporary file
#
tmpfile = /tmp/fail2ban-mail.txt
# Destination/Addressee of the mail
#
dest = root

View File

@ -0,0 +1,26 @@
# Fail2Ban configuration file
#
# List of bad bots fetched from http://www.user-agents.org
# Generated on Sun Feb 11 01:09:15 EST 2007 by ./badbots.sh
#
# Author: Yaroslav Halchenko
#
[Definition]
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02
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
# Notes.: Regexp to catch known spambots and software alike. Please verify
# that it is your intent to block IPs which were driven by
# abovementioned bots.
# Values: TEXT
#
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

23
config/filter.d/exim.conf Normal file
View File

@ -0,0 +1,23 @@
# Fail2Ban configuration file
#
# Author: Cyril Jaquier
#
# $Revision: 510 $
#
[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
#
failregex = \[<HOST>\] .*(?:rejected by local_scan|Unrouteable address)
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

View File

@ -0,0 +1,29 @@
# Fail2Ban configuration file
#
# Author: Cyril Jaquier
# Modified: Yaroslav Halchenko for pure-ftpd
#
# $Revision: 3$
#
[Definition]
# Error message specified in multiple languages
__errmsg = (?:Authentication failed for user|Erreur d'authentification pour l'utilisateur)
#
# 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
#
failregex = pure-ftpd: (.+?@<HOST>) \[WARNING\] %(__errmsg)s \[.+\]$
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

View File

@ -0,0 +1,23 @@
# Fail2Ban configuration file
#
# Author: Yaroslav Halchenko
#
# $Revision: 510 $
#
[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
#
failregex = sshd\[\S*\]: Did not receive identification string from <HOST>
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

View File

@ -2,7 +2,7 @@
# #
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 532 $ # $Revision: 551 $
# #
[Definition] [Definition]
@ -15,7 +15,7 @@
# Values: TEXT # Values: TEXT
# #
failregex = Authentication failure for .* from <HOST> failregex = Authentication failure for .* from <HOST>
Failed [-/\w+]+ for .* from <HOST> Failed [-/\w]+ for .* from <HOST>
ROOT LOGIN REFUSED .* FROM <HOST> ROOT LOGIN REFUSED .* FROM <HOST>
[iI](?:llegal|nvalid) user .* from <HOST> [iI](?:llegal|nvalid) user .* from <HOST>

View File

@ -2,7 +2,7 @@
# #
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 524 $ # $Revision: 552 $
# #
# 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
@ -117,6 +117,31 @@ logpath = /var/log/vsftpd.log
maxretry = 5 maxretry = 5
bantime = 1800 bantime = 1800
# Same as above but with banning the IP address.
[vsftpd-iptables]
enabled = false
filter = vsftpd
action = iptables[name=VSFTPD, port=ftp, protocol=tcp]
mail-whois[name=VSFTPD, dest=yourmail@mail.com]
logpath = /var/log/vsftpd.log
maxretry = 5
bantime = 1800
# Ban hosts which agent identifies spammer robots crawling the web
# for email addresses. The mail outputs are buffered.
[apache-badbots]
enabled = false
filter = apache-badbots
action = iptables-multiport[name=BadBots, port="http,https"]
mail-buffered[name=BadBots, lines=5, dest=yourmail@mail.com]
logpath = /var/www/*/logs/access_log
bantime = 172800
maxretry = 1
# Use shorewall instead of iptables. # Use shorewall instead of iptables.
[apache-shorewall] [apache-shorewall]

8
files/gentoo-confd Normal file
View File

@ -0,0 +1,8 @@
# Config file for /etc/init.d/fail2ban
#
# For information on options, see "/usr/bin/fail2ban-client -h".
FAIL2BAN_OPTIONS=""
# Force execution of the server even if the socket already exists:
#FAIL2BAN_OPTIONS="-x"

View File

@ -17,11 +17,11 @@
# #
# Author: Sireyessire, Cyril Jaquier # Author: Sireyessire, Cyril Jaquier
# #
# $Revision: 491 $ # $Revision: 559 $
opts="start stop restart reload showlog" opts="start stop restart reload showlog"
FAIL2BAN="/usr/bin/fail2ban-client" FAIL2BAN="/usr/bin/fail2ban-client ${FAIL2BAN_OPTIONS}"
depend() { depend() {
need net need net
@ -42,29 +42,11 @@ stop() {
} }
restart() { restart() {
if ! service_stopped "${SVCNAME}" ; then if ! service_stopped "${SVCNAME}" ; then
svc_stop || return "$?" svc_stop || return "$?"
einfon "Waiting for server to shutdown ." sleep 1
cnt=0 fi
while [ 1 ]; do svc_start
# Ping fail2ban-server
${FAIL2BAN} ping &> /dev/null
if [ ! "$?" == "0" ]; then
break
fi
cnt=`expr $cnt + 1`
if [ $cnt -gt 60 ] ; then
# We have waited 1 minute. Failed
echo
eend 1 "Failed"
break
fi
sleep 1
echo -n "."
done
echo
fi
svc_start
} }
reload() { reload() {

View File

@ -16,11 +16,11 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 434 $ # $Revision: 556 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 434 $" __version__ = "$Revision: 556 $"
__date__ = "$Date: 2006-10-24 21:49:31 +0200 (Tue, 24 Oct 2006) $" __date__ = "$Date: 2007-03-07 21:54:32 +0100 (Wed, 07 Mar 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
@ -54,18 +54,48 @@ class Action:
self.__actionStop = '' self.__actionStop = ''
logSys.debug("Created Action") logSys.debug("Created Action")
##
# Sets the action name.
#
# @param name the name of the action
def setName(self, name): def setName(self, name):
self.__name = name self.__name = name
##
# Returns the action name.
#
# @return the name of the action
def getName(self): def getName(self):
return self.__name return self.__name
##
# Sets a "CInfo".
#
# CInfo are statically defined properties. They can be definied by
# the user and are used to set e-mail addresses, port, host or
# anything that should not change during the life of the server.
#
# @param key the property name
# @param value the property value
def setCInfo(self, key, value): def setCInfo(self, key, value):
self.__cInfo[key] = value self.__cInfo[key] = value
##
# Returns a "CInfo".
#
# @param key the property name
def getCInfo(self, key): def getCInfo(self, key):
return self.__cInfo[key] return self.__cInfo[key]
##
# Removes a "CInfo".
#
# @param key the property name
def delCInfo(self, key): def delCInfo(self, key):
del self.__cInfo[key] del self.__cInfo[key]
@ -86,6 +116,14 @@ class Action:
def getActionStart(self): def getActionStart(self):
return self.__actionStart return self.__actionStart
##
# Executes the action "start" command.
#
# Replaces the tags in the action command with value of "cInfo"
# and executes the resulting command.
#
# @return True if the command succeeded
def execActionStart(self): def execActionStart(self):
startCmd = Action.replaceTag(self.__actionStart, self.__cInfo) startCmd = Action.replaceTag(self.__actionStart, self.__cInfo)
return Action.executeCmd(startCmd) return Action.executeCmd(startCmd)
@ -107,6 +145,11 @@ class Action:
def getActionBan(self): def getActionBan(self):
return self.__actionBan return self.__actionBan
##
# Executes the action "ban" command.
#
# @return True if the command succeeded
def execActionBan(self, aInfo): def execActionBan(self, aInfo):
return self.__processCmd(self.__actionBan, aInfo) return self.__processCmd(self.__actionBan, aInfo)
@ -127,6 +170,11 @@ class Action:
def getActionUnban(self): def getActionUnban(self):
return self.__actionUnban return self.__actionUnban
##
# Executes the action "unban" command.
#
# @return True if the command succeeded
def execActionUnban(self, aInfo): def execActionUnban(self, aInfo):
return self.__processCmd(self.__actionUnban, aInfo) return self.__processCmd(self.__actionUnban, aInfo)
@ -164,10 +212,25 @@ class Action:
def getActionStop(self): def getActionStop(self):
return self.__actionStop return self.__actionStop
##
# Executes the action "stop" command.
#
# Replaces the tags in the action command with value of "cInfo"
# and executes the resulting command.
#
# @return True if the command succeeded
def execActionStop(self): def execActionStop(self):
stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo) stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo)
return Action.executeCmd(stopCmd) return Action.executeCmd(stopCmd)
##
# Replaces tags in query with property values in aInfo.
#
# @param query the query string with tags
# @param aInfo the properties
# @return a string
@staticmethod @staticmethod
def replaceTag(query, aInfo): def replaceTag(query, aInfo):
""" Replace tags in query """ Replace tags in query
@ -179,6 +242,19 @@ class Action:
string = string.replace("<br>", '\n') string = string.replace("<br>", '\n')
return string return string
##
# Executes a command with preliminary checks and substitutions.
#
# Before executing any commands, executes the "check" command first
# in order to check if prerequirements are met. If this check fails,
# it tries to restore a sane environnement before executing the real
# command.
# Replaces "aInfo" and "cInfo" in the query too.
#
# @param cmd The command to execute
# @param aInfo Dynamic properties
# @return True if the command succeeded
def __processCmd(self, cmd, aInfo = None): def __processCmd(self, cmd, aInfo = None):
""" Executes an OS command. """ Executes an OS command.
""" """
@ -209,6 +285,18 @@ class Action:
return Action.executeCmd(realCmd) return Action.executeCmd(realCmd)
##
# Executes a command.
#
# We need a shell here because commands are mainly shell script. They
# contain pipe, redirection, etc.
#
# @todo Force the use of bash!?
# @todo Kill the command after a given timeout
#
# @param realCmd the command to execute
# @return True if the command succeeded
@staticmethod @staticmethod
def executeCmd(realCmd): def executeCmd(realCmd):
logSys.debug(realCmd) logSys.debug(realCmd)

View File

@ -16,11 +16,11 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 535 $ # $Revision: 556 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 535 $" __version__ = "$Revision: 556 $"
__date__ = "$Date: 2007-01-29 22:46:59 +0100 (Mon, 29 Jan 2007) $" __date__ = "$Date: 2007-03-07 21:54:32 +0100 (Wed, 07 Mar 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
@ -56,22 +56,45 @@ class Actions(JailThread):
## The ban manager. ## The ban manager.
self.__banManager = BanManager() self.__banManager = BanManager()
##
# Adds an action.
#
# @param name The action name
def addAction(self, name): def addAction(self, name):
action = Action(name) action = Action(name)
self.__actions.append(action) self.__actions.append(action)
##
# Removes an action.
#
# @param name The action name
def delAction(self, name): def delAction(self, name):
for action in self.__actions: for action in self.__actions:
if action.getName() == name: if action.getName() == name:
self.__actions.remove(action) self.__actions.remove(action)
break break
##
# Returns an action.
#
# Raises a KeyError exception if the action does not exist.
#
# @param name the action name
# @return the action
def getAction(self, name): def getAction(self, name):
for action in self.__actions: for action in self.__actions:
if action.getName() == name: if action.getName() == name:
return action return action
raise KeyError raise KeyError
##
# Returns the last defined action.
#
# @return The last defined action.
def getLastAction(self): def getLastAction(self):
action = self.__actions.pop() action = self.__actions.pop()
self.__actions.append(action) self.__actions.append(action)

View File

@ -16,11 +16,11 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 536 $ # $Revision: 553 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 536 $" __version__ = "$Revision: 553 $"
__date__ = "$Date: 2007-01-31 23:31:42 +0100 (Wed, 31 Jan 2007) $" __date__ = "$Date: 2007-02-26 00:53:22 +0100 (Mon, 26 Feb 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
@ -62,9 +62,11 @@ class BanManager:
# @param value the time # @param value the time
def setBanTime(self, value): def setBanTime(self, value):
self.__lock.acquire() try:
self.__banTime = int(value) self.__lock.acquire()
self.__lock.release() self.__banTime = int(value)
finally:
self.__lock.release()
## ##
# Get the ban time. # Get the ban time.
@ -85,9 +87,11 @@ class BanManager:
# @param value total number # @param value total number
def setBanTotal(self, value): def setBanTotal(self, value):
self.__lock.acquire() try:
self.__banTotal = value self.__lock.acquire()
self.__lock.release() self.__banTotal = value
finally:
self.__lock.release()
## ##
# Get the total number of banned address. # Get the total number of banned address.

View File

@ -16,11 +16,11 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 504 $ # $Revision: 553 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 504 $" __version__ = "$Revision: 553 $"
__date__ = "$Date: 2006-12-23 17:37:17 +0100 (Sat, 23 Dec 2006) $" __date__ = "$Date: 2007-02-26 00:53:22 +0100 (Mon, 26 Feb 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
@ -42,44 +42,48 @@ class DateDetector:
self.__defTemplate = DateStrptime() self.__defTemplate = DateStrptime()
def addDefaultTemplate(self): def addDefaultTemplate(self):
# standard try:
template = DateStrptime() self.__lock.acquire()
template.setName("Month Day Hour:Minute:Second") # standard
template.setRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}") template = DateStrptime()
template.setPattern("%b %d %H:%M:%S") template.setName("Month Day Hour:Minute:Second")
self.__templates.append(template) template.setRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
# asctime template.setPattern("%b %d %H:%M:%S")
template = DateStrptime() self.__templates.append(template)
template.setName("Weekday Month Day Hour:Minute:Second Year") # asctime
template.setRegex("\S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}") template = DateStrptime()
template.setPattern("%a %b %d %H:%M:%S %Y") template.setName("Weekday Month Day Hour:Minute:Second Year")
self.__templates.append(template) template.setRegex("\S{3} \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} \d{4}")
# simple date template.setPattern("%a %b %d %H:%M:%S %Y")
template = DateStrptime() self.__templates.append(template)
template.setName("Year/Month/Day Hour:Minute:Second") # simple date
template.setRegex("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}") template = DateStrptime()
template.setPattern("%Y/%m/%d %H:%M:%S") template.setName("Year/Month/Day Hour:Minute:Second")
self.__templates.append(template) template.setRegex("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}")
# Apache format [31/Oct/2006:09:22:55 -0000] template.setPattern("%Y/%m/%d %H:%M:%S")
template = DateStrptime() self.__templates.append(template)
template.setName("Day/Month/Year:Hour:Minute:Second") # Apache format [31/Oct/2006:09:22:55 -0000]
template.setRegex("\d{2}/\S{3}/\d{4}:\d{2}:\d{2}:\d{2}") template = DateStrptime()
template.setPattern("%d/%b/%Y:%H:%M:%S") template.setName("Day/Month/Year:Hour:Minute:Second")
self.__templates.append(template) template.setRegex("\d{2}/\S{3}/\d{4}:\d{2}:\d{2}:\d{2}")
# Exim 2006-12-21 06:43:20 template.setPattern("%d/%b/%Y:%H:%M:%S")
template = DateStrptime() self.__templates.append(template)
template.setName("Year-Month-Day Hour:Minute:Second") # Exim 2006-12-21 06:43:20
template.setRegex("\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}") template = DateStrptime()
template.setPattern("%Y-%m-%d %H:%M:%S") template.setName("Year-Month-Day Hour:Minute:Second")
self.__templates.append(template) template.setRegex("\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
# TAI64N template.setPattern("%Y-%m-%d %H:%M:%S")
template = DateTai64n() self.__templates.append(template)
template.setName("TAI64N") # TAI64N
self.__templates.append(template) template = DateTai64n()
# Epoch template.setName("TAI64N")
template = DateEpoch() self.__templates.append(template)
template.setName("Epoch") # Epoch
self.__templates.append(template) template = DateEpoch()
template.setName("Epoch")
self.__templates.append(template)
finally:
self.__lock.release()
def getTemplates(self): def getTemplates(self):
return self.__templates return self.__templates
@ -100,14 +104,15 @@ class DateDetector:
if self.__defTemplate.isValid(): if self.__defTemplate.isValid():
return self.__defTemplate.matchDate(line) return self.__defTemplate.matchDate(line)
else: else:
self.__lock.acquire() try:
for template in self.__templates: self.__lock.acquire()
match = template.matchDate(line) for template in self.__templates:
if not match == None: match = template.matchDate(line)
self.__lock.release() if not match == None:
return match return match
self.__lock.release() return None
return None finally:
self.__lock.release()
def getTime(self, line): def getTime(self, line):
if self.__defTemplate.isValid(): if self.__defTemplate.isValid():
@ -117,19 +122,20 @@ class DateDetector:
except ValueError: except ValueError:
return None return None
else: else:
self.__lock.acquire() try:
for template in self.__templates: self.__lock.acquire()
try: for template in self.__templates:
date = template.getDate(line) try:
if date == None: date = template.getDate(line)
continue if date == None:
template.incHits() continue
self.__lock.release() template.incHits()
return date return date
except ValueError: except ValueError:
pass pass
self.__lock.release() return None
return None finally:
self.__lock.release()
def getUnixTime(self, line): def getUnixTime(self, line):
date = self.getTime(line) date = self.getTime(line)
@ -143,8 +149,11 @@ 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:
logSys.debug("Sorting the template list") self.__lock.acquire()
self.__templates.sort(cmp = lambda x, y: cmp(x.getHits(), y.getHits()), logSys.debug("Sorting the template list")
reverse=True) self.__templates.sort(cmp = lambda x, y:
self.__lock.release() cmp(x.getHits(), y.getHits()),
reverse = True)
finally:
self.__lock.release()

View File

@ -16,11 +16,11 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 537 $ # $Revision: 553 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 537 $" __version__ = "$Revision: 553 $"
__date__ = "$Date: 2007-02-01 21:50:12 +0100 (Thu, 01 Feb 2007) $" __date__ = "$Date: 2007-02-26 00:53:22 +0100 (Mon, 26 Feb 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
@ -42,9 +42,11 @@ class FailManager:
self.__failTotal = 0 self.__failTotal = 0
def setFailTotal(self, value): def setFailTotal(self, value):
self.__lock.acquire() try:
self.__failTotal = value self.__lock.acquire()
self.__lock.release() self.__failTotal = value
finally:
self.__lock.release()
def getFailTotal(self): def getFailTotal(self):
try: try:
@ -54,9 +56,11 @@ class FailManager:
self.__lock.release() self.__lock.release()
def setMaxRetry(self, value): def setMaxRetry(self, value):
self.__lock.acquire() try:
self.__maxRetry = value self.__lock.acquire()
self.__lock.release() self.__maxRetry = value
finally:
self.__lock.release()
def getMaxRetry(self): def getMaxRetry(self):
try: try:
@ -66,9 +70,11 @@ class FailManager:
self.__lock.release() self.__lock.release()
def setMaxTime(self, value): def setMaxTime(self, value):
self.__lock.acquire() try:
self.__maxTime = value self.__lock.acquire()
self.__lock.release() self.__maxTime = value
finally:
self.__lock.release()
def getMaxTime(self): def getMaxTime(self):
try: try:
@ -78,20 +84,22 @@ class FailManager:
self.__lock.release() self.__lock.release()
def addFailure(self, ticket): def addFailure(self, ticket):
self.__lock.acquire() try:
ip = ticket.getIP() self.__lock.acquire()
unixTime = ticket.getTime() ip = ticket.getIP()
if self.__failList.has_key(ip): unixTime = ticket.getTime()
fData = self.__failList[ip] if self.__failList.has_key(ip):
fData.inc() fData = self.__failList[ip]
fData.setLastTime(unixTime) fData.inc()
else: fData.setLastTime(unixTime)
fData = FailData() else:
fData.inc() fData = FailData()
fData.setLastTime(unixTime) fData.inc()
self.__failList[ip] = fData fData.setLastTime(unixTime)
self.__failTotal += 1 self.__failList[ip] = fData
self.__lock.release() self.__failTotal += 1
finally:
self.__lock.release()
def size(self): def size(self):
try: try:
@ -101,12 +109,14 @@ class FailManager:
self.__lock.release() self.__lock.release()
def cleanup(self, time): def cleanup(self, time):
self.__lock.acquire() try:
tmp = self.__failList.copy() self.__lock.acquire()
for item in tmp: tmp = self.__failList.copy()
if tmp[item].getLastTime() < time - self.__maxTime: for item in tmp:
self.__delFailure(item) if tmp[item].getLastTime() < time - self.__maxTime:
self.__lock.release() self.__delFailure(item)
finally:
self.__lock.release()
def __delFailure(self, ip): def __delFailure(self, ip):
if self.__failList.has_key(ip): if self.__failList.has_key(ip):
@ -129,4 +139,3 @@ class FailManager:
class FailManagerEmpty(Exception): class FailManagerEmpty(Exception):
pass pass

View File

@ -16,24 +16,45 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 504 $ # $Revision: 556 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 504 $" __version__ = "$Revision: 556 $"
__date__ = "$Date: 2006-12-23 17:37:17 +0100 (Sat, 23 Dec 2006) $" __date__ = "$Date: 2007-03-07 21:54:32 +0100 (Wed, 07 Mar 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
import time import time
##
# MyTime class.
#
# This class is a wrapper around time.time() and time.gmtime(). When
# performing unit test, it is very useful to get a fixed value from these
# functions.
# Thus, time.time() and time.gmtime() should never be called directly.
# This wrapper should be called instead. The API are equivalent.
class MyTime: class MyTime:
myTime = None myTime = None
##
# Sets the current time.
#
# Use None in order to always get the real current time.
#
# @param t the time to set or None
@staticmethod @staticmethod
def setTime(t): def setTime(t):
MyTime.myTime = t MyTime.myTime = t
##
# Equivalent to time.time()
#
# @return time.time() if setTime was called with None
@staticmethod @staticmethod
def time(): def time():
if MyTime.myTime == None: if MyTime.myTime == None:
@ -41,6 +62,11 @@ class MyTime:
else: else:
return MyTime.myTime return MyTime.myTime
##
# Equivalent to time.gmtime()
#
# @return time.gmtime() if setTime was called with None
@staticmethod @staticmethod
def gmtime(): def gmtime():
if MyTime.myTime == None: if MyTime.myTime == None:

View File

@ -16,11 +16,11 @@
# Author: Cyril Jaquier # Author: Cyril Jaquier
# #
# $Revision: 443 $ # $Revision: 555 $
__author__ = "Cyril Jaquier" __author__ = "Cyril Jaquier"
__version__ = "$Revision: 443 $" __version__ = "$Revision: 555 $"
__date__ = "$Date: 2006-11-01 00:36:59 +0100 (Wed, 01 Nov 2006) $" __date__ = "$Date: 2007-03-07 21:53:37 +0100 (Wed, 07 Mar 2007) $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
@ -68,7 +68,7 @@ class SSocket(Thread):
#self.__ssock.bind(("localhost", 2222)) #self.__ssock.bind(("localhost", 2222))
self.__ssock.bind(sock) self.__ssock.bind(sock)
# Become a server socket # Become a server socket
self.__ssock.listen(5) self.__ssock.listen(1)
def run(self): def run(self):
self.__isRunning = True self.__isRunning = True
@ -80,6 +80,9 @@ class SSocket(Thread):
except socket.timeout: except socket.timeout:
# Do nothing here # Do nothing here
pass pass
except socket.error:
# Do nothing here
pass
self.__ssock.close() self.__ssock.close()
# Remove socket # Remove socket
if os.path.exists(self.__socket): if os.path.exists(self.__socket):
@ -122,7 +125,7 @@ class SocketWorker(Thread):
def __receive(sock): def __receive(sock):
msg = '' msg = ''
while msg.rfind(SSocket.END_STRING) == -1: while msg.rfind(SSocket.END_STRING) == -1:
chunk = sock.recv(6) chunk = sock.recv(128)
if chunk == '': if chunk == '':
raise RuntimeError, "socket connection broken" raise RuntimeError, "socket connection broken"
msg = msg + chunk msg = msg + chunk

View File

@ -11,4 +11,3 @@ Aug 14 11:58:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.
Aug 14 11:59:01 i60p295 sshd[12365]: Accepted keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2 Aug 14 11:59:01 i60p295 sshd[12365]: Accepted keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2
Aug 14 11:59:01 i60p295 sshd[12365]: Accepted keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2 Aug 14 11:59:01 i60p295 sshd[12365]: Accepted keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2
Aug 14 11:59:01 i60p295 sshd[12365]: Accepted keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2 Aug 14 11:59:01 i60p295 sshd[12365]: Accepted keyboard-interactive/pam for roehl from ::ffff:141.3.81.106 port 51332 ssh2
Aug 14 11:59:59 i60p295 sshd[11437]: Failed password for illegal user from from toto.com from ::ffff:66.38.192.238 port 51381 ssh2