Release 0.8.9

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iEYEABECAAYFAlGRBZ8ACgkQjRFFY3XAJMhqzwCgvUsrv6cSjo1d8YCQUA8Na0Kk
 44QAoKk7X2sqFM+wvj2vK3stsHa/80qm
 =iBfR
 -----END PGP SIGNATURE-----

Merge tag '0.8.9' into 0.9 (quite a bit of conflicts "resolved")

Release 0.8.9

* tag '0.8.9':
  BF: add missing files to MANIFEST (I think we shoult not rely on sdist anyways -- 'git tag' tarballs are more thorough ;) )
  All the (version) updates for the release of 0.8.9
  BF: (travis) relax the test for needed to be presented installed directories -- allow new
  BF: (travis) if tests ran under coverage -- there is a traceback parts to report (thus > would be present)
  ENH: also print the failing traceback line in case of failure
  ENH: include explicit list of new files which should not be there upon "install --root"
  ENH: now we know that logging handlers closing was still buggy in 2.6.2
  ENH: issue a warning if jail name is longer than 19 symbols (Close #222)
  DOC: inline commends with ';' are in effect only if ';' follows as space
  BF: Fix for filterpoll incorrectly checking for jailless state
  ENH: strengthen detection of working pyinotify
  ENH: use the same python executable for setup.py test
  ENH: actually tune up TraceBack to determine "unittest" portions of the stack across all python  releases
  TST: Some primarily smoke tests for tests utils
  TST: cover few more lines in fail2banreader.py
  ENH: basic test for setup.py itself (when applicable, should greatly improve coverage ;) )
  ENH: consistent operation of formatExceptionInfo + unittest for it
  ENH: point to the status of master branch on travis

Conflicts:
	ChangeLog
	MANIFEST
	README.md
	fail2ban/version.py -- all of the above obvious version changes

   below files primarily  needed just a bit of help in resolution
	config/jail.conf
	fail2ban/server/filterpoll.py
	fail2ban/server/server.py
	fail2ban/tests/servertestcase.py

   and following were more difficult -- git wasn't able to track renames/moves of the code
    fail2ban-testcases -- needed to introduce those changes to tests/utils.py
	testcases/clientreadertestcase.py -- manually applied patch from master
	testcases/utils.py -- manually applied patch from master
pull/224/merge
Yaroslav Halchenko 12 years ago
commit f5a8a8ac7c

@ -41,7 +41,7 @@ code-review and minor additions from Yaroslav Halchenko.
* [..e019ab7] Multiple instances of the same action are allowed in the
same jail -- use actname option to disambiguate.
ver. 0.8.9 (2013/05/XX) - wanna-be-stable
ver. 0.8.9 (2013/05/13) - wanna-be-stable
----------
Originally targeted as a bugfix release, it incorporated many new

@ -54,6 +54,7 @@ fail2ban/tests/actiontestcase.py
fail2ban/tests/servertestcase.py
fail2ban/tests/sockettestcase.py
fail2ban/tests/utils.py
fail2ban/tests/misctestcase.py
fail2ban/tests/files/testcase01.log
fail2ban/tests/files/testcase02.log
fail2ban/tests/files/testcase03.log
@ -62,6 +63,26 @@ fail2ban/tests/files/testcase-usedns.log
fail2ban/tests/files/logs/bsd/syslog-plain.txt
fail2ban/tests/files/logs/bsd/syslog-v.txt
fail2ban/tests/files/logs/bsd/syslog-vv.txt
fail2ban/tests/files/logs/apache-overflows
fail2ban/tests/files/logs/assp
fail2ban/tests/files/logs/asterisk
fail2ban/tests/files/logs/dovecot
fail2ban/tests/files/logs/exim
fail2ban/tests/files/logs/lighttpd
fail2ban/tests/files/logs/mysqld.log
fail2ban/tests/files/logs/named-refused
fail2ban/tests/files/logs/pam-generic
fail2ban/tests/files/logs/postfix
fail2ban/tests/files/logs/proftpd
fail2ban/tests/files/logs/pure-ftpd
fail2ban/tests/files/logs/roundcube-auth
fail2ban/tests/files/logs/sasl
fail2ban/tests/files/logs/sogo-auth
fail2ban/tests/files/logs/sshd
fail2ban/tests/files/logs/sshd-ddos
fail2ban/tests/files/logs/vsftpd
fail2ban/tests/files/logs/webmin-auth
fail2ban/tests/files/logs/wu-ftpd
setup.py
setup.cfg
fail2ban/__init__.py
@ -103,6 +124,9 @@ config/filter.d/dropbear.conf
config/filter.d/lighttpd-auth.conf
config/filter.d/recidive.conf
config/filter.d/roundcube-auth.conf
config/filter.d/assp.conf
config/filter.d/mysqld-auth.conf
config/filter.d/sogo-auth.conf
config/action.d/bsd-ipfw.conf
config/action.d/dummy.conf
config/action.d/iptables-blocktype.conf
@ -155,3 +179,7 @@ files/cacti/README
files/nagios/check_fail2ban
files/nagios/f2ban.txt
files/bash-completion
files/fail2ban-tmpfiles.conf
files/fail2ban.service
files/ipmasq-ZZZzzz_fail2ban.rul
files/nagios/README

@ -71,7 +71,7 @@ OPT: Create /etc/fail2ban/fail2ban.local containing:
# Fail2Ban main configuration file
#
# Comments: use '#' for comment lines and ';' for inline comments
# Comments: use '#' for comment lines and ';' (following a space) for inline comments
#
# Changes: in most of the cases you should not modify this
# file, but provide customizations in fail2ban.local file, e.g.:

@ -2,7 +2,7 @@
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
v0.9.0a0 2013/05/02
v0.9.0a0 2013/05/??
## Fail2Ban: ban hosts that cause multiple authentication errors
@ -30,8 +30,8 @@ Optional:
To install, just do:
tar xvfj fail2ban-0.8.8.tar.bz2
cd fail2ban-0.8.8
tar xvfj fail2ban-0.8.9.tar.bz2
cd fail2ban-0.8.9
python setup.py install
This will install Fail2Ban into /usr/share/fail2ban. The executable scripts are
@ -56,7 +56,7 @@ the website: http://www.fail2ban.org
Code status:
------------
* [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.png)](https://travis-ci.org/fail2ban/fail2ban) travis-ci.org (master branch)
* [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.png?branch=master)](https://travis-ci.org/fail2ban/fail2ban) travis-ci.org (master branch)
* [![Coverage Status](https://coveralls.io/repos/fail2ban/fail2ban/badge.png?branch=master)](https://coveralls.io/r/fail2ban/fail2ban)

@ -1,6 +1,6 @@
# Fail2Ban main configuration file
#
# Comments: use '#' for comment lines and ';' for inline comments
# Comments: use '#' for comment lines and ';' (following a space) for inline comments
#
# Changes: in most of the cases you should not modify this
# file, but provide customizations in fail2ban.local file, e.g.:

@ -3,7 +3,7 @@
# WARNING: heavily refactored in 0.9.0 release. Please review and
# customize settings for your setup.
#
# Comments: use '#' for comment lines and ';' for inline comments
# Comments: use '#' for comment lines and ';' (following a space) for inline comments
#
# Changes: in most of the cases you should not modify this
# file, but provide customizations in jail.local file,

@ -17,11 +17,7 @@
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Author: Cyril Jaquier
# Author: Arturo 'Buanzo' Busleiman
#
__author__ = "Cyril Jaquier"
__author__ = "Cyril Jaquier, Arturo 'Buanzo' Busleiman"
__copyright__ = "Copyright (c) 2009 Cyril Jaquier"
__license__ = "GPL"
@ -33,6 +29,12 @@ def formatExceptionInfo():
excName = cla.__name__
try:
excArgs = exc.__dict__["args"]
# Assure that we always return a string, without unneeded
# 'decorations' with python <= 2.5 where args would be a tuple
if isinstance(excArgs, tuple) and len(excArgs) == 1:
excArgs = excArgs[0]
excArgs = str(excArgs)
except KeyError:
# And always provide a string output
excArgs = str(exc)
return (excName, excArgs)

@ -81,8 +81,8 @@ class RequestHandler(asynchat.async_chat):
self.close_when_done()
def handle_error(self):
e1,e2 = helpers.formatExceptionInfo()
logSys.error("Unexpected communication error: "+e2)
e1, e2 = helpers.formatExceptionInfo()
logSys.error("Unexpected communication error: %s" % str(e2))
logSys.error(traceback.format_exc().splitlines())
self.close()

@ -104,7 +104,8 @@ class FilterPoll(FileFilter):
time.sleep(self.getSleepTime())
else:
time.sleep(self.getSleepTime())
logSys.debug((self.jail and self.jail.getName() or "jailless") +
logSys.debug(
(self.jail is not None and self.jail.getName() or "jailless") +
" filter terminated")
return True
@ -130,7 +131,7 @@ class FilterPoll(FileFilter):
self.__file404Cnt[filename] += 1
if self.__file404Cnt[filename] > 2:
logSys.warning("Too many errors. Setting the jail idle")
if self.jail:
if self.jail is not None:
self.jail.setIdle(True)
else:
logSys.warning("No jail is assigned to %s" % self)

@ -23,19 +23,28 @@ __author__ = "Cyril Jaquier, Lee Clemens, Yaroslav Halchenko"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2012 Lee Clemens, 2012 Yaroslav Halchenko"
__license__ = "GPL"
import time, logging, pyinotify
from distutils.version import LooseVersion
from os.path import dirname, sep as pathsep
from failmanager import FailManagerEmpty
from filter import FileFilter
from mytime import MyTime
import time, logging, pyinotify
if not hasattr(pyinotify, '__version__') \
or LooseVersion(pyinotify.__version__) < '0.8.3':
raise ImportError("Fail2Ban requires pyinotify >= 0.8.3")
from os.path import dirname, sep as pathsep
# Verify that pyinotify is functional on this system
# Even though imports -- might be dysfunctional, e.g. as on kfreebsd
try:
manager = pyinotify.WatchManager()
del manager
except Exception, e:
raise ImportError("Pyinotify is probably not functional on this system: %s"
% str(e))
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)

@ -38,7 +38,7 @@ class Jail:
_BACKENDS = ['pyinotify', 'gamin', 'polling']
def __init__(self, name, backend = "auto"):
self.__name = name
self.setName(name)
self.__queue = Queue.Queue()
self.__filter = None
logSys.info("Creating new jail '%s'" % self.__name)
@ -102,6 +102,10 @@ class Jail:
self.__filter = FilterPyinotify(self)
def setName(self, name):
if len(name) >= 20:
logSys.warning("Jail name %r might be too long and some commands "
"might not function correctly. Please shorten"
% name)
self.__name = name
def getName(self):

@ -396,11 +396,12 @@ class Server:
handler.flush()
handler.close()
except (ValueError, KeyError): # pragma: no cover
if (2,6) <= sys.version_info < (3,) or \
# Is known to be thrown after logging was shutdown once
# with older Pythons -- seems to be safe to ignore there
# At least it was still failing on 2.6.2-0ubuntu1 (jaunty)
if (2,6,3) <= sys.version_info < (3,) or \
(3,2) <= sys.version_info:
raise
# is known to be thrown after logging was shutdown once
# with older Pythons -- seems to be safe to ignore there
# tell the handler to use this format
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)

@ -296,6 +296,15 @@ class JailsReaderTest(unittest.TestCase):
self.assertEqual(opts['socket'], '/var/run/fail2ban/fail2ban.sock')
self.assertEqual(opts['pidfile'], '/var/run/fail2ban/fail2ban.pid')
configurator.getOptions()
configurator.convertToProtocol()
commands = configurator.getConfigStream()
# and there is logging information left to be passed into the
# server
self.assertEqual(commands,
[['set', 'loglevel', 3],
['set', 'logtarget', '/var/log/fail2ban.log']])
# and if we force change configurator's fail2ban's baseDir
# there should be an error message (test visually ;) --
# otherwise just a code smoke test)

@ -0,0 +1,169 @@
# 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
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
__author__ = "Yaroslav Halchenko"
__copyright__ = "Copyright (c) 2013 Yaroslav Halchenko"
__license__ = "GPL"
import logging
import os, sys, unittest
import tempfile
import shutil
from glob import glob
from utils import mbasename, TraceBack, FormatterWithTraceBack
from fail2ban.helpers import formatExceptionInfo
class HelpersTest(unittest.TestCase):
def testFormatExceptionInfoBasic(self):
try:
raise ValueError("Very bad exception")
except:
name, args = formatExceptionInfo()
self.assertEqual(name, "ValueError")
self.assertEqual(args, "Very bad exception")
def testFormatExceptionConvertArgs(self):
try:
raise ValueError("Very bad", None)
except:
name, args = formatExceptionInfo()
self.assertEqual(name, "ValueError")
# might be fragile due to ' vs "
self.assertEqual(args, "('Very bad', None)")
# based on
# http://stackoverflow.com/questions/2186525/use-a-glob-to-find-files-recursively-in-python
def recursive_glob(treeroot, pattern):
import fnmatch, os
results = []
for base, dirs, files in os.walk(treeroot):
goodfiles = fnmatch.filter(dirs + files, pattern)
results.extend(os.path.join(base, f) for f in goodfiles)
return results
class SetupTest(unittest.TestCase):
def setUp(self):
setup = os.path.join(os.path.dirname(__file__), '..', 'setup.py')
self.setup = os.path.exists(setup) and setup or None
if not self.setup and sys.version_info >= (2,7): # running not out of the source
raise unittest.SkipTest(
"Seems to be running not out of source distribution"
" -- cannot locate setup.py")
def testSetupInstallRoot(self):
if not self.setup: return # if verbose skip didn't work out
tmp = tempfile.mkdtemp()
os.system("%s %s install --root=%s >/dev/null"
% (sys.executable, self.setup, tmp))
def addpath(l):
return [os.path.join(tmp, x) for x in l]
def strippath(l):
return [x[len(tmp)+1:] for x in l]
got = strippath(sorted(glob('%s/*' % tmp)))
need = ['etc', 'usr', 'var']
# if anything is missing
if set(need).difference(got):
# below code was actually to print out not missing but
# rather files in 'excess'. Left in place in case we
# decide to revert to such more strict test
files = {}
for missing in set(got).difference(need):
missing_full = os.path.join(tmp, missing)
files[missing] = os.path.exists(missing_full) \
and strippath(recursive_glob(missing_full, '*')) or None
self.assertEqual(
got, need,
msg="Got: %s Needed: %s under %s. Files under new paths: %s"
% (got, need, tmp, files))
# Assure presence of some files we expect to see in the installation
for f in ('etc/fail2ban/fail2ban.conf',
'etc/fail2ban/jail.conf'):
self.assertTrue(os.path.exists(os.path.join(tmp, f)),
msg="Can't find %s" % f)
# clean up
shutil.rmtree(tmp)
class TestsUtilsTest(unittest.TestCase):
def testmbasename(self):
self.assertEqual(mbasename("sample.py"), 'sample')
self.assertEqual(mbasename("/long/path/sample.py"), 'sample')
# this one would include only the directory for the __init__ and base files
self.assertEqual(mbasename("/long/path/__init__.py"), 'path.__init__')
self.assertEqual(mbasename("/long/path/base.py"), 'path.base')
self.assertEqual(mbasename("/long/path/base"), 'path.base')
def testTraceBack(self):
# pretty much just a smoke test since tests runners swallow all the detail
for compress in True, False:
tb = TraceBack(compress=compress)
def func_raise():
raise ValueError()
def deep_function(i):
if i: deep_function(i-1)
else: func_raise()
try:
print deep_function(3)
except ValueError:
s = tb()
# if we run it through 'coverage' (e.g. on travis) then we
# would get a traceback
if 'coverage' in s:
self.assertTrue('>' in s, msg="no '>' in %r" % s)
else:
self.assertFalse('>' in s, msg="'>' present in %r" % s) # There is only "fail2ban-testcases" in this case, no true traceback
self.assertTrue(':' in s, msg="no ':' in %r" % s)
def testFormatterWithTraceBack(self):
from StringIO import StringIO
strout = StringIO()
Formatter = FormatterWithTraceBack
# and both types of traceback at once
fmt = ' %(tb)s | %(tbc)s : %(message)s'
logSys = logging.getLogger("fail2ban_tests")
out = logging.StreamHandler(strout)
out.setFormatter(Formatter(fmt))
logSys.addHandler(out)
logSys.error("XXX")
s = strout.getvalue()
self.assertTrue(s.rstrip().endswith(': XXX'))
pindex = s.index('|')
# in this case compressed and not should be the same (?)
self.assertTrue(pindex > 10) # we should have some traceback
self.assertEqual(s[:pindex], s[pindex+1:pindex*2 + 1])

@ -27,6 +27,7 @@ __license__ = "GPL"
import unittest, socket, time, tempfile, os, locale
from fail2ban.server.server import Server
from fail2ban.server.jail import Jail
from fail2ban.exceptions import UnknownJailException
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
@ -535,3 +536,12 @@ class TransmitterLogging(TransmitterBase):
self.setGetTest("loglevel", "-1", -1)
self.setGetTest("loglevel", "0", 0)
self.setGetTestNOK("loglevel", "Bird")
class JailTests(unittest.TestCase):
def testLongName(self):
# Just a smoke test for now
longname = "veryveryverylongname"
jail = Jail(longname)
self.assertEqual(jail.getName(), longname)

@ -65,11 +65,12 @@ class TraceBack(object):
def __call__(self):
ftb = traceback.extract_stack(limit=100)[:-2]
entries = [[mbasename(x[0]), str(x[1])] for x in ftb]
entries = [ e for e in entries
if not e[0] in ['unittest', 'logging.__init__' ]]
entries = [[mbasename(x[0]), dirname(x[0]), str(x[1])] for x in ftb]
entries = [ [e[0], e[2]] for e in entries
if not (e[0] in ['unittest', 'logging.__init__']
or e[1].endswith('/unittest'))]
# lets make it more consize
# lets make it more concise
entries_out = [entries[0]]
for entry in entries[1:]:
if entry[0] == entries_out[-1][0]:
@ -131,6 +132,7 @@ def gatherTests(regexps=None, no_network=False):
from fail2ban.tests import datedetectortestcase
from fail2ban.tests import actiontestcase
from fail2ban.tests import sockettestcase
from fail2ban.tests import misctestcase
if not regexps: # pragma: no cover
tests = unittest.TestSuite()
@ -150,6 +152,7 @@ def gatherTests(regexps=None, no_network=False):
# Server
#tests.addTest(unittest.makeSuite(servertestcase.StartStop))
tests.addTest(unittest.makeSuite(servertestcase.Transmitter))
tests.addTest(unittest.makeSuite(servertestcase.JailTests))
tests.addTest(unittest.makeSuite(actiontestcase.ExecuteAction))
# FailManager
tests.addTest(unittest.makeSuite(failmanagertestcase.AddFailure))
@ -162,6 +165,10 @@ def gatherTests(regexps=None, no_network=False):
tests.addTest(unittest.makeSuite(clientreadertestcase.JailsReaderTest))
# CSocket and AsyncServer
tests.addTest(unittest.makeSuite(sockettestcase.Socket))
# Misc helpers
tests.addTest(unittest.makeSuite(misctestcase.HelpersTest))
tests.addTest(unittest.makeSuite(misctestcase.SetupTest))
tests.addTest(unittest.makeSuite(misctestcase.TestsUtilsTest))
# Filter
if not no_network:

@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Author: Cyril Jaquier
#
#
__author__ = "Cyril Jaquier, Yaroslav Halchenko"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10.
.TH FAIL2BAN-CLIENT "1" "March 2013" "fail2ban-client v0.8.8" "User Commands"
.TH FAIL2BAN-CLIENT "1" "May 2013" "fail2ban-client v0.8.9" "User Commands"
.SH NAME
fail2ban-client \- configure and control the server
.SH SYNOPSIS
.B fail2ban-client
[\fIOPTIONS\fR] \fI<COMMAND>\fR
.SH DESCRIPTION
Fail2Ban v0.8.8 reads log file that contains password failure report
Fail2Ban v0.8.9 reads log file that contains password failure report
and bans the corresponding IP addresses using firewall rules.
.SH OPTIONS
.TP
@ -62,6 +62,9 @@ server
.TP
\fBping\fR
tests if the server is alive
.TP
\fBhelp\fR
return this output
.IP
LOGGING
.TP

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10.
.TH FAIL2BAN-REGEX "1" "March 2013" "fail2ban-regex v0.8.8" "User Commands"
.TH FAIL2BAN-REGEX "1" "May 2013" "fail2ban-regex v0.8.9" "User Commands"
.SH NAME
fail2ban-regex \- test Fail2ban "failregex" option
.SH SYNOPSIS
.B fail2ban-regex
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
.SH DESCRIPTION
Fail2Ban v0.8.8 reads log file that contains password failure report
Fail2Ban v0.8.9 reads log file that contains password failure report
and bans the corresponding IP addresses using firewall rules.
.PP
This tools can test regular expressions for "fail2ban".

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10.
.TH FAIL2BAN-SERVER "1" "March 2013" "fail2ban-server v0.8.8" "User Commands"
.TH FAIL2BAN-SERVER "1" "May 2013" "fail2ban-server v0.8.9" "User Commands"
.SH NAME
fail2ban-server \- start the server
.SH SYNOPSIS
.B fail2ban-server
[\fIOPTIONS\fR]
.SH DESCRIPTION
Fail2Ban v0.8.8 reads log file that contains password failure report
Fail2Ban v0.8.9 reads log file that contains password failure report
and bans the corresponding IP addresses using firewall rules.
.PP
Only use this command for debugging purpose. Start the server with

Loading…
Cancel
Save