Merge branch 'master' into debian-release

* master: (27 commits)
  ENH: server.py -- addLogPath with tail=True
  ENH: set/getFile for ticket.py -- found in source distribution of 0.8.4
  NF: adding unittests for previous commit
  ENH: removed expansion for few Date and Revision SVN keywords
  ENH: sshd.conf -- allow user names to have spaces and trailing spaces in the line
  Removed duplicate entry for DataCha0s/2\.0 in badbots (closes: #519557)
  BF: return declaration of TABLE back (thanks to michaelberg79)
  Update server/datetemplate.py
  format output of matches data.
  ENH: minor unittest to see if tickets carry correct 'matches'
  ENH: introduced usa of Ticket.__matches throughout
  ENH: added 'matches' to the Ticket(s) and deprecated "custom" constructors for derived *Tickets
  ENH: modelines for emacs and vim to assure consistent indentation scheme (tabs)
  ENH: failmanager -- additional debug message about # of known failures
  ENH: rudimentary __str__ for the ticket
  ENH: more human-accessible printout of the dates if any comparison fails
  ENH: few debug messages and use MyTime.localtime instead of straight time.time
  ENH: Added localtime() to MyTime
  BF: set TZ to CEST while unittesting so dates matching would work
  ENH: added a .pylintrc to help with consistent appearance and catch obvious problems
  ...

Conflicts:
	MANIFEST  -- wasn't present before due to base on source distribution
	server/ticket.py  -- strange conflict -- should be benign
pull/23/head
Yaroslav Halchenko 2011-11-18 10:43:13 -05:00
commit cd38985e61
55 changed files with 506 additions and 90 deletions

37
.pylintrc Normal file
View File

@ -0,0 +1,37 @@
# Custom pylint configuration for the Fail2Ban project
#
# Set your PYLINTRC environment variable to point to this file
# e.g.
# export PYLINTRC=$PWD/.pylintrc
[FORMAT]
indent-string='\t'
[BASIC]
# Fail2Ban uses non-conventional to Python world camel-casing
# These regexps were originally borrowed from 0.4.x series of
# PyMVPA which had similar conventions.
# Regular expression which should only match correct module names
module-rgx=(([a-z][a-z0-9_]*)|([A-Z][a-zA-Z0-9_]+))$
attr-rgx=[a-z_][a-zA-Z0-9_]{2,30}
# Regular expression which should only match correct class names
class-rgx=[A-Z_]+[a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_]+[a-z_][a-zA-Z0-9]*$
# Regular expression which should only match correct method names
method-rgx=([a-z_]|__)[a-zA-Z0-9]*(__)?$
# Regular expression which should only match correct argument names
argument-rgx=[a-z][a-zA-Z0-9]*_*[a-zA-Z0-9]*_*[a-zA-Z0-9]*_?$
# Regular expression which should only match correct variable names
variable-rgx=([a-z_]+[a-zA-Z0-9]*_*[a-zA-Z0-9]*_*[a-zA-Z0-9]*_?||(__.*__))$||[A-Z]
# Regular expression which should only match correct module level names
# Default: (([A-Z_][A-Z1-9_]*)|(__.*__))$
const-rgx=([a-z_]+[a-zA-Z0-9]*_*[a-zA-Z0-9]*_*[a-zA-Z0-9]*_?|__.*__)$||[A-Z]

127
MANIFEST Normal file
View File

@ -0,0 +1,127 @@
README
ChangeLog
TODO
THANKS
COPYING
fail2ban-client
fail2ban-server
fail2ban-testcases
fail2ban-regex
client/configreader.py
client/configparserinc.py
client/jailreader.py
client/fail2banreader.py
client/jailsreader.py
client/beautifier.py
client/filterreader.py
client/actionreader.py
client/__init__.py
client/configurator.py
client/csocket.py
server/asyncserver.py
server/filter.py
server/filtergamin.py
server/filterpoll.py
server/iso8601.py
server/server.py
server/actions.py
server/faildata.py
server/failmanager.py
server/datedetector.py
server/jailthread.py
server/transmitter.py
server/action.py
server/ticket.py
server/jail.py
server/jails.py
server/__init__.py
server/banmanager.py
server/datetemplate.py
server/mytime.py
server/failregex.py
testcases/banmanagertestcase.py
testcases/failmanagertestcase.py
testcases/clientreadertestcase.py
testcases/filtertestcase.py
testcases/__init__.py
testcases/datedetectortestcase.py
testcases/actiontestcase.py
testcases/servertestcase.py
testcases/files/testcase01.log
testcases/files/testcase02.log
testcases/files/testcase03.log
testcases/files/testcase04.log
setup.py
setup.cfg
common/__init__.py
common/helpers.py
common/version.py
common/protocol.py
config/jail.conf
config/filter.d/common.conf
config/filter.d/apache-auth.conf
config/filter.d/apache-badbots.conf
config/filter.d/apache-nohome.conf
config/filter.d/apache-noscript.conf
config/filter.d/apache-overflows.conf
config/filter.d/courierlogin.conf
config/filter.d/couriersmtp.conf
config/filter.d/cyrus-imap.conf
config/filter.d/exim.conf
config/filter.d/gssftpd.conf
config/filter.d/lighttpd-fastcgi.conf
config/filter.d/named-refused.conf
config/filter.d/postfix.conf
config/filter.d/proftpd.conf
config/filter.d/pure-ftpd.conf
config/filter.d/qmail.conf
config/filter.d/pam-generic.conf
config/filter.d/php-url-fopen.conf
config/filter.d/sasl.conf
config/filter.d/sieve.conf
config/filter.d/sshd.conf
config/filter.d/sshd-ddos.conf
config/filter.d/vsftpd.conf
config/filter.d/webmin-auth.conf
config/filter.d/wuftpd.conf
config/filter.d/xinetd-fail.conf
config/action.d/complain.conf
config/action.d/dshield.conf
config/action.d/hostsdeny.conf
config/action.d/ipfw.conf
config/action.d/ipfilter.conf
config/action.d/iptables.conf
config/action.d/iptables-allports.conf
config/action.d/iptables-multiport.conf
config/action.d/iptables-multiport-log.conf
config/action.d/iptables-new.conf
config/action.d/mail.conf
config/action.d/mail-buffered.conf
config/action.d/mail-whois.conf
config/action.d/mail-whois-lines.conf
config/action.d/mynetwatchman.conf
config/action.d/sendmail.conf
config/action.d/sendmail-buffered.conf
config/action.d/sendmail-whois.conf
config/action.d/sendmail-whois-lines.conf
config/action.d/shorewall.conf
config/fail2ban.conf
man/fail2ban-client.1
man/fail2ban-client.h2m
man/fail2ban-server.1
man/fail2ban-server.h2m
man/fail2ban-regex.1
man/fail2ban-regex.h2m
man/generate-man
files/gentoo-initd
files/gentoo-confd
files/redhat-initd
files/macosx-initd
files/solaris-fail2ban.xml
files/solaris-svc-fail2ban
files/suse-initd
files/cacti/fail2ban_stats.sh
files/cacti/cacti_host_template_fail2ban.xml
files/cacti/README
files/nagios/check_fail2ban
files/nagios/f2ban.txt

14
README
View File

@ -26,8 +26,8 @@ Optional:
To install, just do:
> tar xvfj fail2ban-0.8.4.tar.bz2
> cd fail2ban-0.8.4
> tar xvfj fail2ban-0.8.5.tar.bz2
> cd fail2ban-0.8.5
> python setup.py install
This will install Fail2Ban into /usr/share/fail2ban. The executable scripts are
@ -64,15 +64,7 @@ Cyril Jaquier: <cyril.jaquier@fail2ban.org>
Thanks:
-------
Kévin Drapel, Marvin Rouge, Sireyessire, Robert Edeker, Tom Pike, Iain Lea,
Andrey G. Grozin, Yaroslav Halchenko, Jonathan Kamens, Stephen Gildea, Markus
Hoffmann, Mark Edgington, Patrick Börjesson, kojiro, zugeschmiert, Tyler, Nick
Munger, Christoph Haas, Justin Shore, Joël Bertrand, René Berber, mEDI, Axel
Thimm, Eric Gerbier, Christian Rauch, Michael C. Haller, Jonathan Underwood,
Hanno 'Rince' Wagner, Daniel B. Cid, David Nutter, Raphaël Marichez, Guillaume
Delvit, Vaclav Misek, Adrien Clerc, Michael Hanselmann, Vincent Deffontaines,
Bill Heaton, Russell Odom, Christos Psonis, Arturo 'Buanzo' Busleiman and many
others.
See THANKS file.
License:
--------

47
THANKS Normal file
View File

@ -0,0 +1,47 @@
Fail2Ban is an open source project with many contributions from its
users community. Below is an alphabetically sorted partial list of the
contributors to the project. If you have been left off, please let us
know (preferably send a pull request on github with the "fix") and you
will be added
Adrien Clerc
Andrey G. Grozin
Arturo 'Buanzo' Busleiman
Axel Thimm
Bill Heaton
Christian Rauch
Christoph Haas
Christos Psonis
Daniel B. Cid
David Nutter
Eric Gerbier
Guillaume Delvit
Hanno 'Rince' Wagner
Iain Lea
Jonathan Kamens
Jonathan Underwood
Joël Bertrand
Justin Shore
Kévin Drapel
kojiro
Mark Edgington
Markus Hoffmann
Marvin Rouge
mEDI
Michael C. Haller
Michael Hanselmann
NickMunger
Patrick Börjesson
Raphaël Marichez
René Berber
Robert Edeker
Russell Odom
Sireyessire
Stephen Gildea
Tom Pike
Tyler
Vaclav Misek
Vincent Deffontaines
Yaroslav Halchenko
Yehuda Katz
zugeschmiert

2
TODO
View File

@ -4,7 +4,7 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_|
================================================================================
ToDo $Revision$
ToDo
================================================================================
Legend:

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -87,4 +90,4 @@ class ActionReader(ConfigReader):
stream.append(head + ["setcinfo", self.__file, p, self.__cInfo[p]])
return stream

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -75,4 +78,4 @@ class Configurator:
for opt in self.__streams["jails"]:
cmds.append(opt)
return cmds

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -55,4 +58,4 @@ class Fail2banReader(ConfigReader):
elif opt == "logtarget":
stream.append(["set", "logtarget", self.__opts[opt]])
return stream

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -71,4 +74,4 @@ class FilterReader(ConfigReader):
if regex != '':
stream.append(["set", self.__name, "addignoreregex", regex])
return stream

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -84,4 +87,4 @@ class JailsReader(ConfigReader):
stream.append(["start", jail.getName()])
return stream

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -27,12 +30,12 @@ __license__ = "GPL"
def formatExceptionInfo():
""" Author: Arturo 'Buanzo' Busleiman """
import sys
cla, exc = sys.exc_info()[:2]
excName = cla.__name__
try:
excArgs = exc.__dict__["args"]
except KeyError:
excArgs = str(exc)
return (excName, excArgs)
""" Author: Arturo 'Buanzo' Busleiman """
import sys
cla, exc = sys.exc_info()[:2]
excName = cla.__name__
try:
excArgs = exc.__dict__["args"]
except KeyError:
excArgs = str(exc)
return (excName, excArgs)

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -32,10 +32,16 @@ __daemon_re = [\[\(]?%(_daemon)s(?:\(\S+\))?[\]\)]?:?
# EXAMPLES: sshd[31607], pop(pam_unix)[4920]
__daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:)
# Some messages have a kernel prefix with a timestamp
# EXAMPLES: kernel: [769570.846956]
__kernel_prefix = kernel: \[\d+\.\d+\]
__hostname = \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*
__prefix_line = \s*(?:%(__hostname)s )?(?:%(__kernel_prefix)s )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s*

View File

@ -14,7 +14,7 @@
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values: TEXT
#
failregex = (?i): warning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?$
failregex = (?i): warning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?\s*$
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.

View File

@ -1,4 +1,7 @@
#!/usr/bin/python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,4 +1,7 @@
#!/usr/bin/python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,4 +1,7 @@
#!/usr/bin/python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -26,7 +29,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import unittest, logging, sys
import unittest, logging, sys, time, os
from common.version import version
from testcases import banmanagertestcase
@ -40,6 +43,11 @@ from server.mytime import MyTime
# Set the time to a fixed, known value
# Sun Aug 14 12:00:00 CEST 2005
# yoh: we need to adjust TZ to match the one used by Cyril so all the timestamps match
old_TZ = os.environ.get('TZ', None)
os.environ['TZ'] = 'Europe/Zurich'
time.tzset()
MyTime.setTime(1124013600)
# Gets the instance of the logger.
@ -74,3 +82,10 @@ tests.addTest(unittest.makeSuite(datedetectortestcase.DateDetectorTest))
# Tests runner
testRunner = unittest.TextTestRunner()
testRunner.run(tests)
# Just for the sake of it reset the TZ
# yoh is planing to move all this into setup/teardown methods within tests
os.environ.pop('TZ')
if old_TZ:
os.environ['TZ'] = old_TZ
time.tzset()

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -158,6 +161,7 @@ class Actions(JailThread):
aInfo["ip"] = bTicket.getIP()
aInfo["failures"] = bTicket.getAttempt()
aInfo["time"] = bTicket.getTime()
aInfo["matches"] = "".join(bTicket.getMatches())
if self.__banManager.addBanTicket(bTicket):
logSys.warn("[%s] Ban %s" % (self.jail.getName(), aInfo["ip"]))
for action in self.__actions:
@ -198,6 +202,7 @@ class Actions(JailThread):
aInfo["ip"] = ticket.getIP()
aInfo["failures"] = ticket.getAttempt()
aInfo["time"] = ticket.getTime()
aInfo["matches"] = "".join(ticket.getMatches())
logSys.warn("[%s] Unban %s" % (self.jail.getName(), aInfo["ip"]))
for action in self.__actions:
action.execActionUnban(aInfo)

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -130,7 +133,7 @@ class BanManager:
ip = ticket.getIP()
#lastTime = ticket.getTime()
lastTime = MyTime.time()
banTicket = BanTicket(ip, lastTime)
banTicket = BanTicket(ip, lastTime, ticket.getMatches())
banTicket.setAttempt(ticket.getAttempt())
return banTicket
createBanTicket = staticmethod(createBanTicket)

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# emacs: -*- mode: python; coding: utf-8; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -30,6 +32,10 @@ import re, time
from mytime import MyTime
import iso8601
import logging
logSys = logging.getLogger("fail2ban.datetemplate")
class DateTemplate:
def __init__(self):
@ -76,7 +82,7 @@ class DateEpoch(DateTemplate):
dateMatch = self.matchDate(line)
if dateMatch:
# extract part of format which represents seconds since epoch
date = list(time.localtime(float(dateMatch.group())))
date = list(MyTime.localtime(float(dateMatch.group())))
return date
@ -86,20 +92,20 @@ class DateEpoch(DateTemplate):
# 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"]
TABLE["Jan"] = ["Sty"]
TABLE["Feb"] = [u"Fév", "Lut"]
TABLE["Mar"] = [u"Mär", "Mar"]
TABLE["Apr"] = ["Avr", "Kwi"]
TABLE["May"] = ["Mai", "Maj"]
TABLE["Jun"] = ["Lip"]
TABLE["Jul"] = ["Sie"]
TABLE["Aug"] = ["Aou", "Wrz"]
TABLE["Sep"] = ["Sie"]
TABLE["Oct"] = [u"Paź"]
TABLE["Nov"] = ["Lis"]
TABLE["Dec"] = [u"Déc", "Dez", "Gru"]
def __init__(self):
DateTemplate.__init__(self)
@ -116,6 +122,8 @@ class DateStrptime(DateTemplate):
for t in DateStrptime.TABLE:
for m in DateStrptime.TABLE[t]:
if date.find(m) >= 0:
logSys.debug(u"Replacing %r with %r in %r" %
(m, t, date))
return date.replace(m, t)
return date
convertLocale = staticmethod(convertLocale)
@ -145,6 +153,9 @@ class DateStrptime(DateTemplate):
# 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():
logSys.debug(
u"Correcting deduced year from %d to %d since %f > %f" %
(date[0], date[0]-1, time.mktime(date), MyTime.time()))
date[0] -= 1
elif date[1] == 1 and date[2] == 1:
# If it is Jan 1st, it is either really Jan 1st or there
@ -169,7 +180,7 @@ class DateTai64n(DateTemplate):
value = dateMatch.group()
seconds_since_epoch = value[2:17]
# convert seconds from HEX into local time stamp
date = list(time.localtime(int(seconds_since_epoch, 16)))
date = list(MyTime.localtime(int(seconds_since_epoch, 16)))
return date

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -35,16 +38,24 @@ class FailData:
self.__retry = 0
self.__lastTime = 0
self.__lastReset = 0
self.__matches = []
def setRetry(self, value):
self.__retry = value
# keep only the last matches or reset entirely
self.__matches = self.__matches[-min(len(self.__matches, value)):] \
if value else []
def getRetry(self):
return self.__retry
def inc(self):
def getMatches(self):
return self.__matches
def inc(self, matches=None):
self.__retry += 1
self.__matches += matches or []
def setLastTime(self, value):
if value > self.__lastTime:
self.__lastTime = value

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -88,19 +91,22 @@ class FailManager:
self.__lock.acquire()
ip = ticket.getIP()
unixTime = ticket.getTime()
matches = ticket.getMatches()
if self.__failList.has_key(ip):
fData = self.__failList[ip]
if fData.getLastReset() < unixTime - self.__maxTime:
fData.setLastReset(unixTime)
fData.setRetry(0)
fData.inc()
fData.inc(matches)
fData.setLastTime(unixTime)
else:
fData = FailData()
fData.inc()
fData.inc(matches)
fData.setLastReset(unixTime)
fData.setLastTime(unixTime)
self.__failList[ip] = fData
logSys.debug("Currently have failures from %d IPs: %s"
% (len(self.__failList), self.__failList.keys()))
self.__failTotal += 1
finally:
self.__lock.release()
@ -134,7 +140,7 @@ class FailManager:
if data.getRetry() >= self.__maxRetry:
self.__delFailure(ip)
# Create a FailTicket from BanData
failTicket = FailTicket(ip, data.getLastTime())
failTicket = FailTicket(ip, data.getLastTime(), data.getMatches())
failTicket.setAttempt(data.getRetry())
return failTicket
raise FailManagerEmpty

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -278,7 +281,7 @@ class Filter(JailThread):
logSys.debug("Ignore %s" % ip)
continue
logSys.debug("Found %s" % ip)
self.failManager.addFailure(FailTicket(ip, unixTime))
self.failManager.addFailure(FailTicket(ip, unixTime, [line]))
##
# Returns true if the line should be ignored.

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
# Copyright (c) 2007 Michael Twomey
#
# Permission is hereby granted, free of charge, to any person obtaining a

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -76,4 +79,10 @@ class MyTime:
else:
return time.gmtime(MyTime.myTime)
gmtime = staticmethod(gmtime)
def localtime(x=None):
if MyTime.myTime == None or x is not None:
return time.localtime(x)
else:
return time.localtime(MyTime.myTime)
localtime = staticmethod(localtime)

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -31,12 +34,25 @@ logSys = logging.getLogger("fail2ban")
class Ticket:
def __init__(self, ip, time):
def __init__(self, ip, time, matches=None):
"""Ticket constructor
@param ip the IP address
@param time the ban time
@param matches (log) lines caused the ticket
"""
self.__ip = ip
self.__time = time
self.__attempt = 0
self.__file = None
self.__matches = matches or []
def __str__(self):
return "%s: ip=%s time=%s #attempts=%d" % \
(self.__class__, self.__ip, self.__time, self.__attempt)
def setIP(self, value):
self.__ip = value
@ -61,11 +77,12 @@ class Ticket:
def getAttempt(self):
return self.__attempt
def getMatches(self):
return self.__matches
class FailTicket(Ticket):
def __init__(self, ip, time):
Ticket.__init__(self, ip, time)
pass
##
@ -74,14 +91,4 @@ class FailTicket(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)
pass

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -261,4 +264,4 @@ class Transmitter:
name = command[0]
return self.__server.statusJail(name)
raise Exception("Invalid command (no status)")

View File

@ -1,4 +1,6 @@
#!/usr/bin/python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -22,4 +25,4 @@ __author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
__license__ = "GPL"

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -44,4 +47,4 @@ class ExecuteAction(unittest.TestCase):
self.__action.setActionCheck("[ -e /tmp/fail2ban.test ]")
self.assertTrue(self.__action.execActionBan(None))

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -53,4 +56,4 @@ class AddFailure(unittest.TestCase):
def _testInListNOK(self):
ticket = BanTicket('111.111.1.111', 1167605999.0)
self.assertFalse(self.__banManager.inBanList(ticket))

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -40,4 +43,4 @@ class JailReaderTest(unittest.TestCase):
expected = ['mail-whois', {'name': 'SSH'}]
result = JailReader.splitAction(action)
self.assertEquals(expected, result)

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -64,4 +67,4 @@ class DateDetectorTest(unittest.TestCase):
#
# self.assertEqual(self.__datedetector.getTime(log), date)
# self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -25,6 +28,8 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import unittest
import time
from server.filterpoll import FilterPoll
from server.filter import FileFilter, DNSUtils
from server.failmanager import FailManager
@ -94,26 +99,44 @@ class GetFailures(unittest.TestCase):
def tearDown(self):
"""Call after every test case."""
def _assertEqualEntries(self, found, output):
"""Little helper to unify comparisons with the target entries
and report helpful failure reports instead of millions of seconds ;)
"""
self.assertEqual(found[:2], output[:2])
found_time, output_time = \
time.localtime(found[2]),\
time.localtime(output[2])
self.assertEqual(found_time, output_time)
if len(found) > 3: # match matches
self.assertEqual(found[3], output[3])
def testGetFailures01(self):
output = ('193.168.0.128', 3, 1124013599.0)
output = ('193.168.0.128', 3, 1124013599.0,
['Aug 14 11:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128\n']*3)
self.__filter.addLogPath(GetFailures.FILENAME_01)
self.__filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>")
self.__filter.getFailures(GetFailures.FILENAME_01)
ticket = self.__filter.failManager.toBan()
attempts = ticket.getAttempt()
date = ticket.getTime()
ip = ticket.getIP()
found = (ip, attempts, date)
self.assertEqual(found, output)
matches = ticket.getMatches()
found = (ip, attempts, date, matches)
self._assertEqualEntries(found, output)
def testGetFailures02(self):
output = ('141.3.81.106', 4, 1124013539.0)
output = ('141.3.81.106', 4, 1124013539.0,
['Aug 14 11:%d:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2\n'
% m for m in 53, 54, 57, 58])
self.__filter.addLogPath(GetFailures.FILENAME_02)
self.__filter.addFailRegex("Failed .* from <HOST>")
@ -125,9 +148,10 @@ class GetFailures(unittest.TestCase):
attempts = ticket.getAttempt()
date = ticket.getTime()
ip = ticket.getIP()
found = (ip, attempts, date)
matches = ticket.getMatches()
found = (ip, attempts, date, matches)
self.assertEqual(found, output)
self._assertEqualEntries(found, output)
def testGetFailures03(self):
output = ('203.162.223.135', 6, 1124013544.0)
@ -144,7 +168,7 @@ class GetFailures(unittest.TestCase):
ip = ticket.getIP()
found = (ip, attempts, date)
self.assertEqual(found, output)
self._assertEqualEntries(found, output)
def testGetFailures04(self):
output = [('212.41.96.186', 4, 1124013600.0),
@ -182,7 +206,7 @@ class GetFailures(unittest.TestCase):
ip = ticket.getIP()
found = (ip, attempts, date)
self.assertEqual(found, output)
self._assertEqualEntries(found, output)
def testGetFailuresIgnoreRegex(self):
output = ('141.3.81.106', 8, 1124013541.0)

View File

@ -1,3 +1,6 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@ -124,4 +127,4 @@ class Transmitter(unittest.TestCase):
jail = self.__server.jails[name]
self.assertEqual(jail.getFilter().failManager.size(), 0)
self.assertEqual(jail.getAction().banManager.size(), 2)