MRG: merge so far - flushLogs not working yet

pull/494/head
Daniel Black 2013-12-16 15:08:34 +00:00
commit 7c0efc8ec8
60 changed files with 631 additions and 104 deletions

View File

@ -70,8 +70,27 @@ ver. 0.8.12 (2013/12/XX) - things-can-only-get-better
- IMPORTANT incompatible changes:
- Fixes:
- Rename firewall-cmd-direct-new to firewall-cmd-new to fit within jail name
name length. As per gh-395
- allow for ",milliseconds" in the custom date format of proftpd.log
- allow for ", referer ..." in apache-* filter for apache error logs.
- allow for spaces at the beginning of kernel messages. Closes gh-448
- recidive jail to block all protocols. Closes gh-440. Thanks Ioan Indreias
- smtps not a IANA standard and has been removed from Arch. Replaced with
465. Thanks Stefan. Closes gh-447
- mysqld-syslog-iptables rule was too long. Part of gh-447.
- add 'flushlogs' command to allow logrotation without clobbering logtarget
settings. Closes gh-458, Debian bug #697333, Redhat bug #891798.
- complain action - ensure where not matching other IPs in log sample.
Closes gh-467
- Fix firewall-cmd actioncheck - patch from Adam Tkac. Redhat Bug #979622
- Enhancements:
- long names on jails documented based on iptables limit of 30 less
len("fail2ban-").
- remove indentation of name and loglevel while logging to SYSLOG to
resolve syslog(-ng) parsing problems. Closes Debian bug #730202.
- added squid filter. Thanks Roman Gelfand.
- New Features:
@ -79,6 +98,7 @@ ver. 0.8.12 (2013/12/XX) - things-can-only-get-better
* filter.d/solid-pop3d -- added thanks to Jacques Lav!gnotte on mailinglist.
- Enhancements:
- loglines now also report "[PID]" after the name portion
ver. 0.8.11 (2013/11/13) - loves-unittests-and-tight-DoS-free-filter-regexes

View File

@ -743,10 +743,14 @@ Releasing
* https://github.com/fail2ban/fail2ban/issues?sort=updated&state=open
* http://bugs.debian.org/cgi-bin/pkgreport.cgi?dist=unstable;package=fail2ban
* https://bugs.launchpad.net/ubuntu/+source/fail2ban
* http://bugs.sabayon.org/buglist.cgi?quicksearch=net-analyzer%2Ffail2ban
* https://bugs.archlinux.org/?project=5&cat%5B%5D=33&string=fail2ban
* https://bugs.gentoo.org/buglist.cgi?query_format=advanced&short_desc=fail2ban&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=IN_PROGRESS&short_desc_type=allwords
* https://bugzilla.redhat.com/buglist.cgi?query_format=advanced&bug_status=NEW&bug_status=ASSIGNED&component=fail2ban&classification=Red%20Hat&classification=Fedora
* http://www.freebsd.org/cgi/query-pr-summary.cgi?text=fail2ban
* https://bugs.mageia.org/buglist.cgi?quicksearch=fail2ban
* https://build.opensuse.org/package/requests/openSUSE:Factory/fail2ban
# Make sure the tests pass

View File

@ -261,3 +261,7 @@ files/fail2ban-tmpfiles.conf
files/fail2ban.service
files/ipmasq-ZZZzzz_fail2ban.rul
files/gen_badbots
testcases/config/jail.conf
testcases/config/fail2ban.conf
testcases/config/filter.d/simple.conf
testcases/config/action.d/brokenaction.conf

5
THANKS
View File

@ -6,8 +6,10 @@ 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
Adam Tkac
Adrien Clerc
ache
ag4ve (Shawn)
Amir Caspi
Andrey G. Grozin
Andy Fragen
@ -35,6 +37,7 @@ Hanno 'Rince' Wagner
Iain Lea
John Thoe
Jacques Lav!gnotte
Ioan Indreias
Jonathan Kamens
Jonathan Lanning
Jonathan Underwood
@ -61,10 +64,12 @@ RealRancor
René Berber
Robert Edeker
Rolf Fokkens
Roman Gelfand
Russell Odom
Sebastian Arcus
Sireyessire
silviogarbes
Stefan Tatschner
Stephen Gildea
Steven Hiscocks
TESTOVIK

View File

@ -48,7 +48,7 @@ def get_opt_parser():
p.add_options([
Option('-l', "--log-level", type="choice",
dest="log_level",
choices=('heavydebug', 'debug', 'info', 'warn', 'error', 'fatal'),
choices=('heavydebug', 'debug', 'info', 'warning', 'error', 'fatal'),
default=None,
help="Log level for the logger to use during running tests"),
Option('-n', "--no-network", action="store_true",
@ -72,7 +72,7 @@ parser = get_opt_parser()
logSys = logging.getLogger("fail2ban")
# Numerical level of verbosity corresponding to a log "level"
verbosity = {'heavydebug': 3,
verbosity = {'heavydebug': 4,
'debug': 3,
'info': 2,
'warning': 1,

View File

@ -41,3 +41,10 @@ actionban = apf --deny <ip> "banned by Fail2Ban <name>"
# Values: CMD
#
actionunban = apf --remove <ip>
[Init]
# Name used in APF configuration
#
name = default

View File

@ -0,0 +1,86 @@
# Fail2Ban configuration file
#
# Author: Steven Hiscocks
#
#
# Action to report IP address to blocklist.de
# Blocklist.de must be signed up to at www.blocklist.de
# Once registered, one or more servers can be added.
# This action requires the server 'email address' and the assoicate apikey.
#
# From blocklist.de:
# www.blocklist.de is a free and voluntary service provided by a
# Fraud/Abuse-specialist, whose servers are often attacked on SSH-,
# Mail-Login-, FTP-, Webserver- and other services.
# The mission is to report all attacks to the abuse deparments of the
# infected PCs/servers to ensure that the responsible provider can inform
# the customer about the infection and disable them
#
# IMPORTANT:
#
# Reporting an IP of abuse is a serious complaint. Make sure that it is
# serious. Fail2ban developers and network owners recommend you only use this
# action for:
# * The recidive where the IP has been banned multiple times
# * Where maxretry has been set quite high, beyond the normal user typing
# password incorrectly.
# * For filters that have a low likelyhood of receiving human errors
#
[Definition]
# Option: actionstart
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD
#
actionstart =
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop =
# 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: See jail.conf(5) man page
# Values: CMD
#
actionban = curl --fail --data-urlencode 'server=<email>' --data 'apikey=<apikey>' --data 'service=<service>' --data 'ip=<ip>' --data-urlencode 'logs=<matches>' --data 'format=text' --user-agent "fail2ban v0.8.12" "https://www.blocklist.de/en/httpreports.html"
# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: See jail.conf(5) man page
# Values: CMD
#
actionunban =
[Init]
# Option: email
# Notes server email address, as per blocklise.de account
# Values: STRING Default: None
#
#email =
# Option: apikey
# Notes your user blocklist.de user account apikey
# Values: STRING Default: None
#
#apikey =
# Option: service
# Notes service name you are reporting on, typically aligns with filter name
# see http://www.blocklist.de/en/httpreports.html for full list
# Values: STRING Default: None
#
#service =

View File

@ -58,7 +58,7 @@ actioncheck =
actionban = ADDRESSES=`whois <ip> | perl -e 'while (<STDIN>) { next if /^changed|@(ripe|apnic)\.net/io; $m += (/abuse|trouble:|report|spam|security/io?3:0); if (/([a-z0-9_\-\.+]+@[a-z0-9\-]+(\.[[a-z0-9\-]+)+)/io) { while (s/([a-z0-9_\-\.+]+@[a-z0-9\-]+(\.[[a-z0-9\-]+)+)//io) { if ($m) { $a{lc($1)}=$m } else { $b{lc($1)}=$m } } $m=0 } else { $m && --$m } } if (%%a) {print join(",",keys(%%a))} else {print join(",",keys(%%b))}'`
IP=<ip>
if [ ! -z "$ADDRESSES" ]; then
(printf %%b "<message>\n"; date '+Note: Local timezone is %%z (%%Z)'; grep '<ip>' <logpath>) | <mailcmd> "Abuse from <ip>" <mailargs> $ADDRESSES
(printf %%b "<message>\n"; date '+Note: Local timezone is %%z (%%Z)'; grep -E '(^|[^0-9])<ip>([^0-9]|$)' <logpath>) | <mailcmd> "Abuse from <ip>" <mailargs> $ADDRESSES
fi
# Option: actionunban

View File

@ -1,9 +1,5 @@
# Fail2Ban configuration file
#
# Author: Edgar Hoch
# Copied from iptables-new.conf and modified for use with firewalld by Edgar Hoch.
# It uses "firewall-cmd" instead of "iptables".
#
# Because of the --remove-rules in stop this action requires firewalld-0.3.8+
[INCLUDES]
@ -20,7 +16,7 @@ actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -m state
firewall-cmd --direct --remove-rules ipv4 filter fail2ban-<name>
firewall-cmd --direct --remove-chain ipv4 filter fail2ban-<name>
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | grep -q 'fail2ban-<name>[ \t]'
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | grep -q '^fail2ban-<name>$'
actionban = firewall-cmd --direct --add-rule ipv4 filter fail2ban-<name> 0 -s <ip> -j <blocktype>
@ -50,3 +46,27 @@ protocol = tcp
# Values: [ STRING ]
#
chain = INPUT_direct
# DEV NOTES:
#
# Author: Edgar Hoch
# Copied from iptables-new.conf and modified for use with firewalld by Edgar Hoch.
# It uses "firewall-cmd" instead of "iptables".
#
# Output:
#
# $ firewall-cmd --direct --add-chain ipv4 filter fail2ban-name
# success
# $ firewall-cmd --direct --add-rule ipv4 filter fail2ban-name 1000 -j RETURN
# success
# $ sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 0 -m state --state NEW -p tcp --dport 22 -j fail2ban-name
# success
# $ firewall-cmd --direct --get-chains ipv4 filter
# fail2ban-name
# $ firewall-cmd --direct --get-chains ipv4 filter | od -h
# 0000000 6166 6c69 6232 6e61 6e2d 6d61 0a65
# $ firewall-cmd --direct --get-chains ipv4 filter | grep -Eq 'fail2ban-name( |$)' ; echo $?
# 0
# $ firewall-cmd -V
# 0.3.8

View File

@ -43,7 +43,7 @@ actionban = ipfw add <blocktype> tcp from <ip> to <localhost> <port>
# Tags: See jail.conf(5) man page
# Values: CMD
#
actionunban = ipfw delete `ipfw list | grep -i <ip> | awk '{print $1;}'`
actionunban = ipfw delete `ipfw list | grep -i "[^0-9]<ip>[^0-9]" | awk '{print $1;}'`
[Init]

View File

@ -39,10 +39,10 @@ actioncheck =
actionban = printf %%b "Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here are more information about <ip>:\n
`whois <ip>`\n\n
Here is more information about <ip>:\n
`whois <ip> || echo missing whois program`\n\n
Lines containing IP:<ip> in <logpath>\n
`grep '\<<ip>\>' <logpath>`\n\n
`grep '[^0-9]<ip>[^0-9]' <logpath>`\n\n
Regards,\n
Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>

View File

@ -39,8 +39,8 @@ actioncheck =
actionban = printf %%b "Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here are more information about <ip>:\n
`whois <ip>`\n
Here is more information about <ip>:\n
`whois <ip> || echo missing whois program`\n
Regards,\n
Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>

View File

@ -23,10 +23,10 @@ actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here are more information about <ip>:\n
`/usr/bin/whois <ip>`\n\n
Here is more information about <ip>:\n
`/usr/bin/whois <ip> || echo missing whois program`\n\n
Lines containing IP:<ip> in <logpath>\n
`grep '\<<ip>\>' <logpath>`\n\n
`grep '[^0-9]<ip>[^0-9]' <logpath>`\n\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>

View File

@ -23,8 +23,8 @@ actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here are more information about <ip>:\n
`/usr/bin/whois <ip>`\n
Here is more information about <ip>:\n
`/usr/bin/whois <ip> || echo missing whois program`\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>

View File

@ -34,7 +34,7 @@ __daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_r
# Some messages have a kernel prefix with a timestamp
# EXAMPLES: kernel: [769570.846956]
__kernel_prefix = kernel: \[\d+\.\d+\]
__kernel_prefix = kernel: \[ *\d+\.\d+\]
__hostname = \S+

View File

@ -1,5 +1,7 @@
# Fail2Ban fitler for the Proftpd FTP daemon
#
# Set "UseReverseDNS off" in proftpd.conf to avoid the need for DNS.
# See: http://www.proftpd.org/docs/howto/DNS.html
[INCLUDES]

View File

@ -27,7 +27,7 @@ _daemon = fail2ban\.server\.actions
# jail using this filter 'recidive', or change this line!
_jailname = recidive
failregex = ^(%(__prefix_line)s|,\d{3} %(_daemon)s:\s+)WARNING\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
failregex = ^(%(__prefix_line)s|,\d{3} fail2ban.actions%(__pid_re)s?:\s+)WARNING\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
[Init]

View File

@ -0,0 +1,13 @@
# Fail2Ban filter for Squid attempted proxy bypasses
#
#
[Definition]
failregex = ^\s+\d\s<HOST>\s+[A-Z_]+_DENIED/403 .*$
^\s+\d\s<HOST>\s+NONE/405 .*$
# Author: Daniel Black

View File

@ -158,6 +158,17 @@ action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(proto
action_xarf = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
# Report block via blocklist.de fail2ban reporting service API
#
# See the IMPORTANT note in action.d/blocklist_de.conf for when to
# use this action. Create a file jail.d/blocklist_de.local containing
# [Init]
# blocklist_de_apikey = {api key from registration]
#
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s"]
# Choose default action. To change, just override value of 'action' with the
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
# globally (section [DEFAULT]) or per specific section
@ -646,9 +657,6 @@ findtime = 86400 ; 1 day
maxretry = 5
# Generic filter for PAM. Has to be used with action which bans all
# ports such as iptables-allports, shorewall
[pam-generic]
# pam-generic filter can be customized to monitor specific subset of 'tty's
banaction = iptables-allports

View File

@ -63,6 +63,8 @@ class Beautifier:
msg = "Jail stopped"
elif inC[0] == "add":
msg = "Added jail " + response
elif inC[0] == "flushlogs":
msg = "logs: " + response
elif inC[0:1] == ['status']:
if len(inC) > 1:
# Create IP list

View File

@ -113,6 +113,7 @@ class ConfigReader(SafeConfigParserWithIncludes):
# No "Definition" section or wrong basedir
logSys.error(e)
values[option[1]] = option[2]
# TODO: validate error handling here.
except NoOptionError:
if not option[2] is None:
logSys.warning("'%s' not defined in '%s'. Using default one: %r"

View File

@ -62,7 +62,7 @@ class JailReader(ConfigReader):
return out
def isEnabled(self):
return self.__force_enable or self.__opts["enabled"]
return self.__force_enable or ( self.__opts and self.__opts["enabled"] )
@staticmethod
def _glob(path):
@ -72,12 +72,10 @@ class JailReader(ConfigReader):
"""
pathList = []
for p in glob.glob(path):
if not os.path.exists(p):
logSys.warning("File %s doesn't even exist, thus cannot be monitored" % p)
elif not os.path.lexists(p):
logSys.warning("File %s is a dangling link, thus cannot be monitored" % p)
else:
if os.path.exists(p):
pathList.append(p)
else:
logSys.warning("File %s is a dangling link, thus cannot be monitored" % p)
return pathList
def getOptions(self):
@ -95,20 +93,26 @@ class JailReader(ConfigReader):
["string", "filter", ""],
["string", "action", ""]]
self.__opts = ConfigReader.getOptions(self, self.__name, opts)
if not self.__opts:
return False
if self.isEnabled():
# Read filter
filterName, filterOpt = JailReader.extractOptions(
self.__opts["filter"])
self.__filter = FilterReader(
filterName, self.__name, filterOpt, basedir=self.getBaseDir())
ret = self.__filter.read()
if ret:
self.__filter.getOptions(self.__opts)
if self.__opts["filter"]:
filterName, filterOpt = JailReader.extractOptions(
self.__opts["filter"])
self.__filter = FilterReader(
filterName, self.__name, filterOpt, basedir=self.getBaseDir())
ret = self.__filter.read()
if ret:
self.__filter.getOptions(self.__opts)
else:
logSys.error("Unable to read the filter")
return False
else:
logSys.error("Unable to read the filter")
return False
self.__filter = None
logSys.warn("No filter set for jail %s" % self.__name)
# Read action
for act in self.__opts["action"].split('\n'):
try:
@ -180,7 +184,8 @@ class JailReader(ConfigReader):
# Do not send a command if the rule is empty.
if regex != '':
stream.append(["set", self.__name, "addignoreregex", regex])
stream.extend(self.__filter.convert())
if self.__filter:
stream.extend(self.__filter.convert())
for action in self.__actions:
stream.extend(action.convert())
stream.insert(0, ["add", self.__name, backend])
@ -188,7 +193,11 @@ class JailReader(ConfigReader):
#@staticmethod
def extractOptions(option):
option_name, optstr = JailReader.optionCRE.match(option).groups()
match = JailReader.optionCRE.match(option)
if not match:
# TODO propper error handling
return None, None
option_name, optstr = match.groups()
option_opts = dict()
if optstr:
for optmatch in JailReader.optionExtractRE.finditer(optstr):

View File

@ -60,6 +60,7 @@ class JailsReader(ConfigReader):
sections = [ section ]
# Get the options of all jails.
parse_status = True
for sec in sections:
jail = JailReader(sec, basedir=self.getBaseDir(),
force_enable=self.__force_enable)
@ -71,8 +72,8 @@ class JailsReader(ConfigReader):
self.__jails.append(jail)
else:
logSys.error("Errors in jail %r. Skipping..." % sec)
return False
return True
parse_status = False
return parse_status
def convert(self, allow_no_files=False):
"""Convert read before __opts and jails to the commands stream

View File

@ -43,6 +43,7 @@ protocol = [
["get loglevel", "gets the logging level"],
["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"],
["get logtarget", "gets logging target"],
["flushlogs", "flushes the logtarget if a file and reopens it. For log rotation."],
['', "DATABASE", ""],
["set dbfile <FILE>", "set the location of fail2ban persistent datastore. Set to \"None\" to disable"],
["get dbfile", "get the location of fail2ban persistent datastore"],

View File

@ -140,7 +140,7 @@ class DateDetector:
date = template.getDate(line)
if date is None:
continue
logSys.debug("Got time %i for \"%r\" using template %s" % (date[0], date[1].group(), template.getName()))
logSys.debug("Got time %f for \"%r\" using template %s" % (date[0], date[1].group(), template.getName()))
return date
except ValueError:
pass

View File

@ -293,6 +293,9 @@ class Filter(JailThread):
# to enable banip fail2ban-client BAN command
def addBannedIP(self, ip):
if self.inIgnoreIPList(ip):
logSys.warning('Requested to manually ban an ignored IP %s. User knows best. Proceeding to ban it.' % ip)
unixTime = MyTime.time()
for i in xrange(self.failManager.getMaxRetry()):
self.failManager.addFailure(FailTicket(ip, unixTime))
@ -561,7 +564,7 @@ class FileFilter(Filter):
self._delLogPath(path)
return
def _delLogPath(self, path):
def _delLogPath(self, path): # pragma: no cover - overwritten function
# nothing to do by default
# to be overridden by backends
pass

View File

@ -110,9 +110,11 @@ class Jail:
self.__filter = FilterSystemd(self)
def setName(self, name):
# 20 based on iptable chain name limit of 30 less len('fail2ban-')
if len(name) >= 20:
logSys.warning("Jail name %r might be too long and some commands "
"might not function correctly. Please shorten"
logSys.warning("Jail name %r might be too long and some commands"
" (e.g. iptables) might not function correctly."
" Please shorten"
% name)
self.__name = name

View File

@ -409,13 +409,12 @@ class Server:
try:
self.__loggingLock.acquire()
# set a format which is simpler for console use
formatter = logging.Formatter("%(asctime)s %(name)-16s: %(levelname)-6s %(message)s")
formatter = logging.Formatter("%(asctime)s %(name)-16s[%(process)d]: %(levelname)-7s %(message)s")
if target == "SYSLOG":
# Syslog daemons already add date to the message.
formatter = logging.Formatter("%(name)-16s: %(levelname)-6s %(message)s")
formatter = logging.Formatter("%(name)s[%(process)d]: %(levelname)s %(message)s")
facility = logging.handlers.SysLogHandler.LOG_DAEMON
hdlr = logging.handlers.SysLogHandler("/dev/log",
facility = facility)
hdlr = logging.handlers.SysLogHandler("/dev/log", facility=facility)
elif target == "STDOUT":
hdlr = logging.StreamHandler(sys.stdout)
elif target == "STDERR":
@ -424,7 +423,7 @@ class Server:
# Target should be a file
try:
open(target, "a").close()
hdlr = logging.FileHandler(target)
hdlr = logging.handlers.RotatingFileHandler(target)
except IOError:
logSys.error("Unable to log to " + target)
logSys.info("Logging to previous target " + self.__logTarget)
@ -466,6 +465,19 @@ class Server:
finally:
self.__loggingLock.release()
def flushLogs(self):
if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']:
for handler in logging.getLogger("fail2ban").handlers:
try:
handler.doRollover()
except AttributeError:
handler.flush()
return "rolled over"
else:
for handler in logging.getLogger("fail2ban").handlers:
handler.flush()
return "flushed"
def setDatabase(self, filename):
if self.__jails.size() == 0:
if filename.lower() == "none":
@ -480,6 +492,7 @@ class Server:
def getDatabase(self):
return self.__db
def __createDaemon(self): # pragma: no cover
""" Detach a process from the controlling terminal and run it in the
background as a daemon.
@ -487,6 +500,14 @@ class Server:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
"""
# When the first child terminates, all processes in the second child
# are sent a SIGHUP, so it's ignored.
# We need to set this in the parent process, so it gets inherited by the
# child process, and this makes sure that it is effect even if the parent
# terminates quickly.
signal.signal(signal.SIGHUP, signal.SIG_IGN)
try:
# Fork a child process so the parent can exit. This will return control
# to the command line or shell. This is required so that the new process
@ -509,10 +530,6 @@ class Server:
# leader.
os.setsid()
# When the first child terminates, all processes in the second child
# are sent a SIGHUP, so it's ignored.
signal.signal(signal.SIGHUP, signal.SIG_IGN)
try:
# Fork a second child to prevent zombies. Since the first child is
# a session leader without a controlling terminal, it's possible for

View File

@ -92,6 +92,8 @@ class Transmitter:
value = command[1]
time.sleep(int(value))
return None
elif command[0] == "flushlogs":
return self.__server.flushLogs()
elif command[0] == "set":
return self.__commandSet(command[1:])
elif command[0] == "get":

View File

@ -24,41 +24,25 @@ __author__ = "Cyril Jaquier"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import unittest, time
import time
import logging, sys
from StringIO import StringIO
from fail2ban.server.action import Action
class ExecuteAction(unittest.TestCase):
from fail2ban.tests.utils import LogCaptureTestCase
class ExecuteAction(LogCaptureTestCase):
def setUp(self):
"""Call before every test case."""
self.__action = Action("Test")
# For extended testing of what gets output into logging
# system, we will redirect it to a string
logSys = logging.getLogger("fail2ban")
# Keep old settings
self._old_level = logSys.level
self._old_handlers = logSys.handlers
# Let's log everything into a string
self._log = StringIO()
logSys.handlers = [logging.StreamHandler(self._log)]
logSys.setLevel(getattr(logging, 'DEBUG'))
LogCaptureTestCase.setUp(self)
def tearDown(self):
"""Call after every test case."""
# print "O: >>%s<<" % self._log.getvalue()
logSys = logging.getLogger("fail2ban")
logSys.handlers = self._old_handlers
logSys.level = self._old_level
LogCaptureTestCase.tearDown(self)
self.__action.execActionStop()
def _is_logged(self, s):
return s in self._log.getvalue()
def testNameChange(self):
self.assertEqual(self.__action.getName(), "Test")
self.__action.setName("Tricky Test")

View File

@ -29,6 +29,7 @@ from fail2ban.client.filterreader import FilterReader
from fail2ban.client.jailsreader import JailsReader
from fail2ban.client.actionreader import ActionReader
from fail2ban.client.configurator import Configurator
from fail2ban.tests.utils import LogCaptureTestCase
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
if os.path.exists('config/fail2ban.conf'):
@ -36,6 +37,9 @@ if os.path.exists('config/fail2ban.conf'):
else:
CONFIG_DIR='/etc/fail2ban'
IMPERFECT_CONFIG = os.path.join('fail2ban', 'tests','config')
class ConfigReaderTest(unittest.TestCase):
def setUp(self):
@ -79,7 +83,14 @@ option = %s
self._write('d.conf', 0)
self.assertEqual(self._getoption('d'), 0)
os.chmod(f, 0)
self.assertFalse(self.c.read('d')) # should not be readable BUT present
# fragile test and known to fail e.g. under Cygwin where permissions
# seems to be not enforced, thus condition
if not os.access(f, os.R_OK):
self.assertFalse(self.c.read('d')) # should not be readable BUT present
else:
# SkipTest introduced only in 2.7 thus can't yet use generally
# raise unittest.SkipTest("Skipping on %s -- access rights are not enforced" % platform)
pass
def testOptionalDotDDir(self):
@ -143,11 +154,37 @@ c = d ;in line comment
self.assertEqual(self.c.get('DEFAULT', 'b'), 'a')
self.assertEqual(self.c.get('DEFAULT', 'c'), 'd')
class JailReaderTest(unittest.TestCase):
class JailReaderTest(LogCaptureTestCase):
def testIncorrectJail(self):
jail = JailReader('XXXABSENTXXX', basedir=CONFIG_DIR)
self.assertRaises(ValueError, jail.read)
def testJailActionEmpty(self):
jail = JailReader('emptyaction', basedir=IMPERFECT_CONFIG)
self.assertTrue(jail.read())
self.assertTrue(jail.getOptions())
self.assertTrue(jail.isEnabled())
self.assertTrue(self._is_logged('No filter set for jail emptyaction'))
self.assertTrue(self._is_logged('No actions were defined for emptyaction'))
def testJailActionFilterMissing(self):
jail = JailReader('missingbitsjail', basedir=IMPERFECT_CONFIG)
self.assertTrue(jail.read())
self.assertFalse(jail.getOptions())
self.assertTrue(jail.isEnabled())
self.assertTrue(self._is_logged("Found no accessible config files for 'filter.d/catchallthebadies' under %s" % IMPERFECT_CONFIG))
self.assertTrue(self._is_logged('Unable to read the filter'))
def TODOtestJailActionBrokenDef(self):
jail = JailReader('brokenactiondef', basedir=IMPERFECT_CONFIG)
self.assertTrue(jail.read())
self.assertFalse(jail.getOptions())
self.assertTrue(jail.isEnabled())
self.printLog()
self.assertTrue(self._is_logged('Error in action definition joho[foo'))
self.assertTrue(self._is_logged('Caught exception: While reading action joho[foo we should have got 1 or 2 groups. Got: 0'))
def testStockSSHJail(self):
jail = JailReader('sshd', basedir=CONFIG_DIR) # we are running tests from root project dir atm
@ -155,7 +192,9 @@ class JailReaderTest(unittest.TestCase):
self.assertTrue(jail.getOptions())
self.assertFalse(jail.isEnabled())
self.assertEqual(jail.getName(), 'sshd')
jail.setName('ssh-funky-blocker')
self.assertEqual(jail.getName(), 'ssh-funky-blocker')
def testSplitOption(self):
# Simple example
option = "mail-whois[name=SSH]"
@ -163,6 +202,19 @@ class JailReaderTest(unittest.TestCase):
result = JailReader.extractOptions(option)
self.assertEqual(expected, result)
self.assertEqual(('mail.who_is', {}), JailReader.extractOptions("mail.who_is"))
self.assertEqual(('mail.who_is', {'a':'cat', 'b':'dog'}), JailReader.extractOptions("mail.who_is[a=cat,b=dog]"))
self.assertEqual(('mail--ho_is', {}), JailReader.extractOptions("mail--ho_is"))
self.assertEqual(('mail--ho_is', {}), JailReader.extractOptions("mail--ho_is['s']"))
#self.printLog()
#self.assertTrue(self._is_logged("Invalid argument ['s'] in ''s''"))
self.assertEqual(('mail', {'a': ','}), JailReader.extractOptions("mail[a=',']"))
#self.assertRaises(ValueError, JailReader.extractOptions ,'mail-how[')
# Empty option
option = "abc[]"
expected = ('abc', {})
@ -187,6 +239,27 @@ class JailReaderTest(unittest.TestCase):
result = JailReader.extractOptions(option)
self.assertEqual(expected, result)
def testGlob(self):
d = tempfile.mkdtemp(prefix="f2b-temp")
# Generate few files
# regular file
f1 = os.path.join(d, 'f1')
open(f1, 'w').close()
# dangling link
f2 = os.path.join(d, 'f2')
os.symlink('nonexisting',f2)
# must be only f1
self.assertEqual(JailReader._glob(os.path.join(d, '*')), [f1])
# since f2 is dangling -- empty list
self.assertEqual(JailReader._glob(f2), [])
self.assertTrue(self._is_logged('File %s is a dangling link, thus cannot be monitored' % f2))
self.assertEqual(JailReader._glob(os.path.join(d, 'nonexisting')), [])
os.remove(f1)
os.remove(f2)
os.rmdir(d)
class FilterReaderTest(unittest.TestCase):
def testConvert(self):
@ -235,13 +308,74 @@ class FilterReaderTest(unittest.TestCase):
output[-1][-1] = "5"
self.assertEqual(sorted(filterReader.convert()), sorted(output))
class JailsReaderTest(unittest.TestCase):
class JailsReaderTest(LogCaptureTestCase):
def testProvidingBadBasedir(self):
if not os.path.exists('/XXX'):
reader = JailsReader(basedir='/XXX')
self.assertRaises(ValueError, reader.read)
def testReadTestJailConf(self):
jails = JailsReader(basedir=IMPERFECT_CONFIG)
self.assertTrue(jails.read())
self.assertFalse(jails.getOptions())
self.assertRaises(ValueError, jails.convert)
comm_commands = jails.convert(allow_no_files=True)
self.maxDiff = None
self.assertEqual(sorted(comm_commands),
sorted([['add', 'emptyaction', 'auto'],
['set', 'emptyaction', 'usedns', 'warn'],
['set', 'emptyaction', 'maxretry', 3],
['set', 'emptyaction', 'findtime', 600],
['set', 'emptyaction', 'logencoding', 'auto'],
['set', 'emptyaction', 'bantime', 600],
['add', 'special', 'auto'],
['set', 'special', 'usedns', 'warn'],
['set', 'special', 'maxretry', 3],
['set', 'special', 'addfailregex', '<IP>'],
['set', 'special', 'findtime', 600],
['set', 'special', 'logencoding', 'auto'],
['set', 'special', 'bantime', 600],
['add', 'missinglogfiles', 'auto'],
['set', 'missinglogfiles', 'usedns', 'warn'],
['set', 'missinglogfiles', 'maxretry', 3],
['set', 'missinglogfiles', 'findtime', 600],
['set', 'missinglogfiles', 'logencoding', 'auto'],
['set', 'missinglogfiles', 'bantime', 600],
['set', 'missinglogfiles', 'addfailregex', '<IP>'],
['add', 'brokenaction', 'auto'],
['set', 'brokenaction', 'usedns', 'warn'],
['set', 'brokenaction', 'maxretry', 3],
['set', 'brokenaction', 'findtime', 600],
['set', 'brokenaction', 'logencoding', 'auto'],
['set', 'brokenaction', 'bantime', 600],
['set', 'brokenaction', 'addfailregex', '<IP>'],
['set', 'brokenaction', 'addaction', 'brokenaction'],
['set',
'brokenaction',
'actionban',
'brokenaction',
'hit with big stick <ip>'],
['set', 'brokenaction', 'actionstop', 'brokenaction', ''],
['set', 'brokenaction', 'actionstart', 'brokenaction', ''],
['set', 'brokenaction', 'actionunban', 'brokenaction', ''],
['set', 'brokenaction', 'actioncheck', 'brokenaction', ''],
['add', 'parse_to_end_of_jail.conf', 'auto'],
['set', 'parse_to_end_of_jail.conf', 'usedns', 'warn'],
['set', 'parse_to_end_of_jail.conf', 'maxretry', 3],
['set', 'parse_to_end_of_jail.conf', 'findtime', 600],
['set', 'parse_to_end_of_jail.conf', 'logencoding', 'auto'],
['set', 'parse_to_end_of_jail.conf', 'bantime', 600],
['set', 'parse_to_end_of_jail.conf', 'addfailregex', '<IP>'],
['start', 'emptyaction'],
['start', 'special'],
['start', 'missinglogfiles'],
['start', 'brokenaction'],
['start', 'parse_to_end_of_jail.conf'],]))
self.assertTrue(self._is_logged("Errors in jail 'missingbitsjail'. Skipping..."))
self.assertTrue(self._is_logged("No file(s) found for glob /weapons/of/mass/destruction"))
def testReadStockJailConf(self):
jails = JailsReader(basedir=CONFIG_DIR) # we are running tests from root project dir atm
self.assertTrue(jails.read()) # opens fine
@ -251,6 +385,15 @@ class JailsReaderTest(unittest.TestCase):
# commands to communicate to the server
self.assertEqual(comm_commands, [])
# TODO: make sure this is handled well
## We should not "read" some bogus jail
#old_comm_commands = comm_commands[:] # make a copy
#self.assertRaises(ValueError, jails.getOptions, "BOGUS")
#self.printLog()
#self.assertTrue(self._is_logged("No section: 'BOGUS'"))
## and there should be no side-effects
#self.assertEqual(jails.convert(), old_comm_commands)
allFilters = set()
# All jails must have filter and action set

View File

@ -0,0 +1,4 @@
[Definition]
actionban = hit with big stick <ip>

View File

@ -0,0 +1,5 @@
[Definition]
# 3 = INFO
loglevel = 3

View File

@ -0,0 +1,4 @@
[Definition]
failregex = <IP>

View File

@ -0,0 +1,33 @@
[DEFAULT]
filter = simple
logpath = /non/exist
[emptyaction]
enabled = true
filter =
action =
[special]
failregex = <IP>
ignoreregex =
ignoreip =
[missinglogfiles]
logpath = /weapons/of/mass/destruction
[brokenactiondef]
enabled = true
action = joho[foo
[brokenaction]
enabled = true
action = brokenaction
[missingbitsjail]
filter = catchallthebadies
action = thefunkychickendance
[parse_to_end_of_jail.conf]
enabled = true
action =

View File

@ -1,5 +1,7 @@
# failJSON: { "time": "2006-02-13T15:52:30", "match": true , "host": "1.2.3.4" }
2006-02-13 15:52:30,388 fail2ban.server.actions: WARNING [sendmail] Ban 1.2.3.4
# failJSON: { "time": "2006-02-13T15:52:30", "match": true , "host": "1.2.3.4", "desc": "Extended with [PID]" }
2006-02-13 15:52:30,388 fail2ban.server.actions[123]: WARNING [sendmail] Ban 1.2.3.4
# failJSON: { "match": false }
2006-02-13 16:07:31,183 fail2ban.server.actions: WARNING [sendmail] Unban 1.2.3.4
# failJSON: { "match": false }

View File

@ -0,0 +1,13 @@
# Logs thanks to Roman Gelfand
#
# failJSON: { "time": "2013-12-08T23:55:23.000", "match": true , "host": "91.188.124.227" }
1386543323.000 4 91.188.124.227 TCP_DENIED/403 4099 GET http://www.proxy-listen.de/azenv.php - HIER_NONE/- text/html
# failJSON: { "time": "2013-12-08T23:58:20", "match": true , "host": "175.44.0.184" }
1386543500.000 5 175.44.0.184 NONE/405 3364 CONNECT error:method-not-allowed - HIER_NONE/- text/html
# failJSON: { "time": "2013-12-09T00:08:04.000", "match": true , "host": "198.74.125.200" }
1386544084.000 3 198.74.125.200 TCP_DENIED/403 3722 GET http://www2t.biglobe.ne.jp/~take52/test/env.cgi - HIER_NONE/- text/html
# failJSON: { "time": "2013-12-09T00:09:06.000", "match": true , "host": "175.42.91.151" }
1386544146.000 1 175.42.91.151 TCP_DENIED/403 3745 GET http://pkfsp.ru/wp-content/uploads/proxyc/engine.php - HIER_NONE/- text/html

View File

@ -41,14 +41,11 @@ from fail2ban.server.failmanager import FailManager
from fail2ban.server.failmanager import FailManagerEmpty
from fail2ban.server.mytime import MyTime
from fail2ban.tests.utils import setUpMyTime, tearDownMyTime
from fail2ban.tests.utils import mtimesleep, LogCaptureTestCase
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
#
# Useful helpers
#
from utils import mtimesleep
from fail2ban.tests.dummyjail import DummyJail
# yoh: per Steven Hiscocks's insight while troubleshooting
# https://github.com/fail2ban/fail2ban/issues/103#issuecomment-15542836
@ -192,14 +189,27 @@ def _copy_lines_to_journal(in_, fields={},n=None, skip=0, terminal_line=""): # p
# Actual tests
#
class IgnoreIP(unittest.TestCase):
class BasicFilter(unittest.TestCase):
def setUp(self):
self.filter = Filter('name')
def testGetSetUseDNS(self):
# default is warn
self.assertEqual(self.filter.getUseDns(), 'warn')
self.filter.setUseDns(True)
self.assertEqual(self.filter.getUseDns(), 'yes')
self.filter.setUseDns(False)
self.assertEqual(self.filter.getUseDns(), 'no')
class IgnoreIP(LogCaptureTestCase):
def setUp(self):
"""Call before every test case."""
self.filter = FileFilter(None)
def tearDown(self):
"""Call after every test case."""
LogCaptureTestCase.setUp(self)
self.jail = DummyJail()
self.filter = FileFilter(self.jail)
def testIgnoreIPOK(self):
ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99"
@ -207,19 +217,47 @@ class IgnoreIP(unittest.TestCase):
self.filter.addIgnoreIP(ip)
self.assertTrue(self.filter.inIgnoreIPList(ip))
# Test DNS
self.filter.addIgnoreIP("www.epfl.ch")
self.assertTrue(self.filter.inIgnoreIPList("128.178.50.12"))
def testIgnoreIPNOK(self):
ipList = "", "999.999.999.999", "abcdef", "192.168.0."
for ip in ipList:
self.filter.addIgnoreIP(ip)
self.assertFalse(self.filter.inIgnoreIPList(ip))
def testIgnoreIPCIDR(self):
self.filter.addIgnoreIP('192.168.1.0/25')
self.assertTrue(self.filter.inIgnoreIPList('192.168.1.0'))
self.assertTrue(self.filter.inIgnoreIPList('192.168.1.1'))
self.assertTrue(self.filter.inIgnoreIPList('192.168.1.127'))
self.assertFalse(self.filter.inIgnoreIPList('192.168.1.128'))
self.assertFalse(self.filter.inIgnoreIPList('192.168.1.255'))
self.assertFalse(self.filter.inIgnoreIPList('192.168.0.255'))
def testIgnoreInProcessLine(self):
self.filter.addIgnoreIP('192.168.1.0/25')
self.filter.addFailRegex('<HOST>')
self.filter.processLineAndAdd('1387203300.222 192.168.1.32')
self.assertTrue(self._is_logged('Ignore 192.168.1.32'))
def testIgnoreAddBannedIP(self):
self.filter.addIgnoreIP('192.168.1.0/25')
self.filter.addBannedIP('192.168.1.32')
self.assertFalse(self._is_logged('Ignore 192.168.1.32'))
self.assertTrue(self._is_logged('Requested to manually ban an ignored IP 192.168.1.32. User knows best. Proceeding to ban it.'))
class IgnoreIPDNS(IgnoreIP):
def testIgnoreIPDNSOK(self):
self.filter.addIgnoreIP("www.epfl.ch")
self.assertTrue(self.filter.inIgnoreIPList("128.178.50.12"))
def testIgnoreIPDNSNOK(self):
# Test DNS
self.filter.addIgnoreIP("www.epfl.ch")
self.assertFalse(self.filter.inIgnoreIPList("127.177.50.10"))
self.assertFalse(self.filter.inIgnoreIPList("128.178.50.11"))
self.assertFalse(self.filter.inIgnoreIPList("128.178.50.13"))
class LogFile(unittest.TestCase):
@ -242,12 +280,13 @@ class LogFile(unittest.TestCase):
self.assertTrue(self.filter.isModified(LogFile.FILENAME))
class LogFileMonitor(unittest.TestCase):
class LogFileMonitor(LogCaptureTestCase):
"""Few more tests for FilterPoll API
"""
def setUp(self):
"""Call before every test case."""
setUpMyTime()
LogCaptureTestCase.setUp(self)
self.filter = self.name = 'NA'
_, self.name = tempfile.mkstemp('fail2ban', 'monitorfailures')
self.file = open(self.name, 'a')
@ -258,6 +297,7 @@ class LogFileMonitor(unittest.TestCase):
def tearDown(self):
tearDownMyTime()
LogCaptureTestCase.tearDown(self)
_killfile(self.file, self.name)
pass
@ -275,6 +315,21 @@ class LogFileMonitor(unittest.TestCase):
# shorter wait time for not modified status
return not self.isModified(0.4)
def testNoLogFile(self):
os.chmod(self.name, 0)
self.filter.getFailures(self.name)
self.assertTrue(self._is_logged('Unable to open %s' % self.name))
def testRemovingFailRegex(self):
self.filter.delFailRegex(0)
self.assertFalse(self._is_logged('Cannot remove regular expression. Index 0 is not valid'))
self.filter.delFailRegex(0)
self.assertTrue(self._is_logged('Cannot remove regular expression. Index 0 is not valid'))
def testRemovingIgnoreRegex(self):
self.filter.delIgnoreRegex(0)
self.assertTrue(self._is_logged('Cannot remove regular expression. Index 0 is not valid'))
def testNewChangeViaIsModified(self):
# it is a brand new one -- so first we think it is modified
self.assertTrue(self.isModified())
@ -357,7 +412,6 @@ class LogFileMonitor(unittest.TestCase):
from threading import Lock
from dummyjail import DummyJail
def get_monitor_failures_testcase(Filter_):
"""Generator of TestCase's for different filters/backends
@ -726,7 +780,13 @@ class GetFailures(unittest.TestCase):
"""Call after every test case."""
tearDownMyTime()
def testTail(self):
self.filter.addLogPath(LogFile.FILENAME, tail=True)
self.assertEqual(self.filter.getLogPath()[-1].getPos(), 1653)
self.filter.getLogPath()[-1].close()
self.assertEqual(self.filter.getLogPath()[-1].readline(), "")
self.filter.delLogPath(LogFile.FILENAME)
self.assertEqual(self.filter.getLogPath(),[])
def testGetFailures01(self, filename=None, failures=None):
filename = filename or GetFailures.FILENAME_01

View File

@ -141,7 +141,6 @@ def testSampleRegexsFactory(name):
regexsUsed.add(failregex)
# TODO: Remove exception handling once all regexs have samples
for failRegexIndex, failRegex in enumerate(self.filter.getFailRegex()):
self.assertTrue(
failRegexIndex in regexsUsed,

View File

@ -26,7 +26,7 @@ __license__ = "GPL"
import unittest, socket, time, tempfile, os, locale, sys
from fail2ban.server.server import Server
from fail2ban.server.server import Server, logSys
from fail2ban.server.jail import Jail
from fail2ban.exceptions import UnknownJailException
try:
@ -662,6 +662,38 @@ class TransmitterLogging(TransmitterBase):
self.setGetTest("loglevel", "0", 0)
self.setGetTestNOK("loglevel", "Bird")
def testFlushLogs(self):
self.assertEqual(self.transm.proceed(["flushlogs"]), (0, "rolled over"))
try:
f, fn = tempfile.mkstemp("fail2ban.log")
os.close(f)
self.server.setLogLevel(2)
self.assertEqual(self.transm.proceed(["set", "logtarget", fn]), (0, fn))
logSys.warn("Before file moved")
try:
f2, fn2 = tempfile.mkstemp("fail2ban.log")
os.close(f2)
os.rename(fn, fn2)
logSys.warn("After file moved")
self.assertEqual(self.transm.proceed(["flushlogs"]), (0, "rolled over"))
logSys.warn("After flushlogs")
with open(fn2,'r') as f:
self.assertTrue(f.next().endswith("Before file moved\n"))
self.assertTrue(f.next().endswith("After file moved\n"))
self.assertRaises(StopIteration, f.next)
with open(fn,'r') as f:
self.assertTrue(f.next().endswith("After flushlogs\n"))
self.assertRaises(StopIteration, f.next)
finally:
os.remove(fn2)
finally:
try:
os.remove(fn)
except OSError:
pass
self.assertEqual(self.transm.proceed(["set", "logtarget", "STDERR"]), (0, "STDERR"))
self.assertEqual(self.transm.proceed(["flushlogs"]), (0, "flushed"))
class JailTests(unittest.TestCase):

View File

@ -24,6 +24,7 @@ __license__ = "GPL"
import logging, os, re, traceback, time, unittest, sys
from os.path import basename, dirname
from StringIO import StringIO
if sys.version_info >= (2, 6):
import json
@ -244,3 +245,32 @@ def gatherTests(regexps=None, no_network=False):
tests.addTest(unittest.makeSuite(servertestcase.TransmitterLogging))
return tests
class LogCaptureTestCase(unittest.TestCase):
def setUp(self):
# For extended testing of what gets output into logging
# system, we will redirect it to a string
logSys = logging.getLogger("fail2ban")
# Keep old settings
self._old_level = logSys.level
self._old_handlers = logSys.handlers
# Let's log everything into a string
self._log = StringIO()
logSys.handlers = [logging.StreamHandler(self._log)]
logSys.setLevel(getattr(logging, 'DEBUG'))
def tearDown(self):
"""Call after every test case."""
# print "O: >>%s<<" % self._log.getvalue()
logSys = logging.getLogger("fail2ban")
logSys.handlers = self._old_handlers
logSys.level = self._old_level
def _is_logged(self, s):
return s in self._log.getvalue()
def printLog(self):
print(self._log.getvalue())

View File

@ -13,6 +13,6 @@
missingok
compress
postrotate
/usr/bin/fail2ban-client set logtarget /var/log/fail2ban.log 1>/dev/null || true
/usr/bin/fail2ban-client flushlogs 1>/dev/null || true
endscript
}

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
# chkconfig: 345 92 08
# chkconfig: - 92 08
# processname: fail2ban-server
# config: /etc/fail2ban/fail2ban.conf
# pidfile: /var/run/fail2ban/fail2ban.pid

View File

@ -64,6 +64,12 @@ Comments: use '#' for comment lines and ';' (following a space) for inline comme
.SH DEFAULT
The following options are applicable to all jails. Their meaning is described in the default \fIjail.conf\fR file.
.TP
\fBfilter\fR
.TP
\fBlogpath\fR
.TP
\fBaction\fR
.TP
\fBignoreip\fR
.TP
\fBbantime\fR
@ -75,6 +81,11 @@ The following options are applicable to all jails. Their meaning is described in
\fBbackend\fR
.TP
\fBusedns\fR
.TP
\fBfailregex\fR
.TP
\fBignoreregex\fR
.PP
.SS Backends
\fBbackend\fR specifies the backend used to get files modification. This option can be overridden in each jail as well.