mirror of https://github.com/fail2ban/fail2ban
Merge tag '0.10.0a1' into 0.10-full
commit
922213f3d9
|
@ -88,10 +88,14 @@ ver. 0.9.5 (2016/XX/XXX) - wanna-be-released
|
|||
added new parameter `__date_ambit`
|
||||
* gentoo-initd fixed --pidfile bug: `--pidfile` is option of start-stop-daemon,
|
||||
not argument of fail2ban (see gh-1434)
|
||||
* filter.d/asterisk.conf
|
||||
- fix security log support for PJSIP and Asterisk 13+ (gh-1456)
|
||||
- improved log support for PJSIP and Asterisk 13+ with different callID (gh-1458)
|
||||
|
||||
- New Features:
|
||||
* New Actions:
|
||||
- action.d/firewallcmd-rich-rules and action.d/firewallcmd-rich-logging (gh-1367)
|
||||
|
||||
- Enhancements:
|
||||
* Extreme speedup of all sqlite database operations (gh-1436),
|
||||
by using of following sqlite options:
|
||||
|
@ -100,7 +104,9 @@ ver. 0.9.5 (2016/XX/XXX) - wanna-be-released
|
|||
- (temp_store = MEMORY) temporary tables and indices are kept in memory
|
||||
* journald journalmatch for pure-ftpd (gh-1362)
|
||||
* Add additional regex filter for dovecot ldap authentication failures (gh-1370)
|
||||
* added additional regex filters for exim (gh-1371)
|
||||
* filter.d/exim*conf
|
||||
- added additional regexes (gh-1371)
|
||||
- made port entry optional
|
||||
|
||||
|
||||
ver. 0.9.4 (2016/03/08) - for-you-ladies
|
||||
|
|
30
MANIFEST
30
MANIFEST
|
@ -13,9 +13,12 @@ config/action.d/complain.conf
|
|||
config/action.d/dshield.conf
|
||||
config/action.d/dummy.conf
|
||||
config/action.d/firewallcmd-allports.conf
|
||||
config/action.d/firewallcmd-common.conf
|
||||
config/action.d/firewallcmd-ipset.conf
|
||||
config/action.d/firewallcmd-multiport.conf
|
||||
config/action.d/firewallcmd-new.conf
|
||||
config/action.d/firewallcmd-rich-logging.conf
|
||||
config/action.d/firewallcmd-rich-rules.conf
|
||||
config/action.d/hostsdeny.conf
|
||||
config/action.d/ipfilter.conf
|
||||
config/action.d/ipfw.conf
|
||||
|
@ -31,6 +34,7 @@ config/action.d/iptables-new.conf
|
|||
config/action.d/iptables-xt_recent-echo.conf
|
||||
config/action.d/mail-buffered.conf
|
||||
config/action.d/mail.conf
|
||||
config/action.d/mail-whois-common.conf
|
||||
config/action.d/mail-whois.conf
|
||||
config/action.d/mail-whois-lines.conf
|
||||
config/action.d/mynetwatchman.conf
|
||||
|
@ -52,6 +56,7 @@ config/action.d/sendmail-whois-ipmatches.conf
|
|||
config/action.d/sendmail-whois-lines.conf
|
||||
config/action.d/sendmail-whois-matches.conf
|
||||
config/action.d/shorewall.conf
|
||||
config/action.d/shorewall-ipset-proto6.conf
|
||||
config/action.d/smtp.py
|
||||
config/action.d/symbiosis-blacklist-allports.conf
|
||||
config/action.d/ufw.conf
|
||||
|
@ -67,6 +72,7 @@ config/filter.d/apache-modsecurity.conf
|
|||
config/filter.d/apache-nohome.conf
|
||||
config/filter.d/apache-noscript.conf
|
||||
config/filter.d/apache-overflows.conf
|
||||
config/filter.d/apache-pass.conf
|
||||
config/filter.d/apache-shellshock.conf
|
||||
config/filter.d/assp.conf
|
||||
config/filter.d/asterisk.conf
|
||||
|
@ -79,17 +85,18 @@ config/filter.d/cyrus-imap.conf
|
|||
config/filter.d/directadmin.conf
|
||||
config/filter.d/dovecot.conf
|
||||
config/filter.d/dropbear.conf
|
||||
config/filter.d/drupal-auth.conf
|
||||
config/filter.d/ejabberd-auth.conf
|
||||
config/filter.d/exim-common.conf
|
||||
config/filter.d/exim.conf
|
||||
config/filter.d/exim-spam.conf
|
||||
config/filter.d/freeswitch.conf
|
||||
config/filter.d/froxlor-auth.conf
|
||||
config/filter.d/groupoffice.conf
|
||||
config/filter.d/gssftpd.conf
|
||||
config/filter.d/guacamole.conf
|
||||
config/filter.d/haproxy-http-auth.conf
|
||||
config/filter.d/horde.conf
|
||||
config/filter.d/ignorecommands
|
||||
config/filter.d/ignorecommands/apache-fakegooglebot
|
||||
config/filter.d/kerio.conf
|
||||
config/filter.d/lighttpd-auth.conf
|
||||
|
@ -122,7 +129,6 @@ config/filter.d/selinux-common.conf
|
|||
config/filter.d/selinux-ssh.conf
|
||||
config/filter.d/sendmail-auth.conf
|
||||
config/filter.d/sendmail-reject.conf
|
||||
config/filter.d/sendmail-spam.conf
|
||||
config/filter.d/sieve.conf
|
||||
config/filter.d/sogo-auth.conf
|
||||
config/filter.d/solid-pop3d.conf
|
||||
|
@ -148,7 +154,6 @@ config/paths-osx.conf
|
|||
CONTRIBUTING.md
|
||||
COPYING
|
||||
DEVELOP
|
||||
doc/run-rootless.txt
|
||||
fail2ban-2to3
|
||||
fail2ban/client/actionreader.py
|
||||
fail2ban/client/beautifier.py
|
||||
|
@ -185,7 +190,6 @@ fail2ban/server/filterpyinotify.py
|
|||
fail2ban/server/filtersystemd.py
|
||||
fail2ban/server/__init__.py
|
||||
fail2ban/server/ipdns.py
|
||||
fail2ban/server/iso8601.py
|
||||
fail2ban/server/jail.py
|
||||
fail2ban/server/jails.py
|
||||
fail2ban/server/jailthread.py
|
||||
|
@ -203,21 +207,19 @@ fail2ban/tests/action_d/test_smtp.py
|
|||
fail2ban/tests/actionstestcase.py
|
||||
fail2ban/tests/actiontestcase.py
|
||||
fail2ban/tests/banmanagertestcase.py
|
||||
fail2ban/tests/clientreadertestcase.py
|
||||
fail2ban/tests/clientbeautifiertestcase.py
|
||||
fail2ban/tests/clientreadertestcase.py
|
||||
fail2ban/tests/config/action.d/brokenaction.conf
|
||||
fail2ban/tests/config/fail2ban.conf
|
||||
fail2ban/tests/config/filter.d/simple.conf
|
||||
fail2ban/tests/config/filter.d/test.conf
|
||||
fail2ban/tests/config/filter.d/test.local
|
||||
fail2ban/tests/config/filter.d/zzz-generic-example.conf
|
||||
fail2ban/tests/config/jail.conf
|
||||
fail2ban/tests/config/paths-common.conf
|
||||
fail2ban/tests/config/paths-debian.conf
|
||||
fail2ban/tests/config/paths-freebsd.conf
|
||||
fail2ban/tests/config/paths-osx.conf
|
||||
fail2ban/tests/databasetestcase.py
|
||||
fail2ban/tests/datedetectortestcase.py
|
||||
fail2ban/tests/dummyjail.py
|
||||
fail2ban/tests/fail2banclienttestcase.py
|
||||
fail2ban/tests/fail2banregextestcase.py
|
||||
fail2ban/tests/failmanagertestcase.py
|
||||
fail2ban/tests/files/action.d/action_checkainfo.py
|
||||
|
@ -250,13 +252,13 @@ fail2ban/tests/files/ignorecommand.py
|
|||
fail2ban/tests/files/logs/3proxy
|
||||
fail2ban/tests/files/logs/apache-auth
|
||||
fail2ban/tests/files/logs/apache-badbots
|
||||
fail2ban/tests/files/logs/apache-botscripts
|
||||
fail2ban/tests/files/logs/apache-botsearch
|
||||
fail2ban/tests/files/logs/apache-fakegooglebot
|
||||
fail2ban/tests/files/logs/apache-modsecurity
|
||||
fail2ban/tests/files/logs/apache-nohome
|
||||
fail2ban/tests/files/logs/apache-noscript
|
||||
fail2ban/tests/files/logs/apache-overflows
|
||||
fail2ban/tests/files/logs/apache-pass
|
||||
fail2ban/tests/files/logs/apache-shellshock
|
||||
fail2ban/tests/files/logs/assp
|
||||
fail2ban/tests/files/logs/asterisk
|
||||
|
@ -270,10 +272,12 @@ fail2ban/tests/files/logs/cyrus-imap
|
|||
fail2ban/tests/files/logs/directadmin
|
||||
fail2ban/tests/files/logs/dovecot
|
||||
fail2ban/tests/files/logs/dropbear
|
||||
fail2ban/tests/files/logs/drupal-auth
|
||||
fail2ban/tests/files/logs/ejabberd-auth
|
||||
fail2ban/tests/files/logs/exim
|
||||
fail2ban/tests/files/logs/exim-spam
|
||||
fail2ban/tests/files/logs/freeswitch
|
||||
fail2ban/tests/files/logs/froxlor-auth
|
||||
fail2ban/tests/files/logs/groupoffice
|
||||
fail2ban/tests/files/logs/gssftpd
|
||||
fail2ban/tests/files/logs/guacamole
|
||||
|
@ -309,7 +313,6 @@ fail2ban/tests/files/logs/screensharingd
|
|||
fail2ban/tests/files/logs/selinux-ssh
|
||||
fail2ban/tests/files/logs/sendmail-auth
|
||||
fail2ban/tests/files/logs/sendmail-reject
|
||||
fail2ban/tests/files/logs/sendmail-spam
|
||||
fail2ban/tests/files/logs/sieve
|
||||
fail2ban/tests/files/logs/sogo-auth
|
||||
fail2ban/tests/files/logs/solid-pop3d
|
||||
|
@ -325,6 +328,7 @@ fail2ban/tests/files/logs/vsftpd
|
|||
fail2ban/tests/files/logs/webmin-auth
|
||||
fail2ban/tests/files/logs/wuftpd
|
||||
fail2ban/tests/files/logs/xinetd-fail
|
||||
fail2ban/tests/files/logs/zzz-generic-example
|
||||
fail2ban/tests/files/testcase01.log
|
||||
fail2ban/tests/files/testcase02.log
|
||||
fail2ban/tests/files/testcase03.log
|
||||
|
@ -356,6 +360,8 @@ files/gentoo-confd
|
|||
files/gentoo-initd
|
||||
files/ipmasq-ZZZzzz_fail2ban.rul
|
||||
files/logwatch/fail2ban
|
||||
files/logwatch/fail2ban-0.8.log
|
||||
files/logwatch/fail2ban-0.9.log
|
||||
files/macosx-initd
|
||||
files/monit/fail2ban
|
||||
files/nagios/check_fail2ban
|
||||
|
@ -373,6 +379,8 @@ man/fail2ban-regex.1
|
|||
man/fail2ban-regex.h2m
|
||||
man/fail2ban-server.1
|
||||
man/fail2ban-server.h2m
|
||||
man/fail2ban-testcases.1
|
||||
man/fail2ban-testcases.h2m
|
||||
man/generate-man
|
||||
man/jail.conf.5
|
||||
README.md
|
||||
|
|
2
RELEASE
2
RELEASE
|
@ -190,7 +190,7 @@ Post Release
|
|||
|
||||
Add the following to the top of the ChangeLog::
|
||||
|
||||
ver. 0.9.6 (2016/XX/XXX) - wanna-be-released
|
||||
ver. 0.10.0 (2016/XX/XXX) - wanna-be-released
|
||||
-----------
|
||||
|
||||
- Fixes:
|
||||
|
|
|
@ -122,7 +122,7 @@ if verbosity > 1: # pragma: no cover
|
|||
if verbosity > 3:
|
||||
fmt = ' | %(module)15.15s-%(levelno)-2d: %(funcName)-20.20s |' + fmt
|
||||
if verbosity > 2:
|
||||
fmt = ' +%(relativeCreated)5d %(thread)X %(levelname)-5.5s' + fmt
|
||||
fmt = ' +%(relativeCreated)5d %(thread)X %(name)-25.25s %(levelname)-5.5s' + fmt
|
||||
else:
|
||||
fmt = ' %(asctime)-15s %(thread)X %(levelname)-5.5s' + fmt
|
||||
#
|
||||
|
|
|
@ -27,6 +27,7 @@ failregex = ^%(__prefix_line)s%(log_prefix)s Registration from '[^']*' failed fo
|
|||
^%(__prefix_line)s%(log_prefix)s hacking attempt detected '<HOST>'$
|
||||
^%(__prefix_line)s%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="([\d-]+|%(iso8601)s)",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="(\d*|<unknown>)",SessionID=".+",LocalAddress="IPV[46]/(UDP|TCP|WS)/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UDP|TCP|WS)/<HOST>/\d+"(,Challenge="[\w/]+")?(,ReceivedChallenge="\w+")?(,Response="\w+",ExpectedResponse="\w*")?(,ReceivedHash="[\da-f]+")?(,ACLName="\w+")?$
|
||||
^%(__prefix_line)s%(log_prefix)s "Rejecting unknown SIP connection from <HOST>"$
|
||||
^%(__prefix_line)s%(log_prefix)s Request (?:'[^']*' )?from '[^']*' failed for '<HOST>(?::\d+)?'\s\(callid: [^\)]*\) - (?:No matching endpoint found|Not match Endpoint(?: Contact)? ACL|(?:Failed|Error) to authenticate)\s*$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ after = exim-common.local
|
|||
|
||||
[Definition]
|
||||
|
||||
host_info = H=([\w.-]+ )?(\(\S+\) )?\[<HOST>\](:\d+)? (I=\[\S+\]:\d+ )?(U=\S+ )?(P=e?smtp )?
|
||||
pid = ( \[\d+\])?
|
||||
host_info = (?:H=([\w.-]+ )?(?:\(\S+\) )?)?\[<HOST>\](?::\d+)? (?:I=\[\S+\](:\d+)? )?(?:U=\S+ )?(?:P=e?smtp )?
|
||||
pid = (?: \[\d+\])?
|
||||
|
||||
# DEV Notes:
|
||||
# From exim source code: ./src/receive.c:add_host_info_for_log
|
||||
|
|
|
@ -14,13 +14,13 @@ before = exim-common.conf
|
|||
[Definition]
|
||||
|
||||
failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$
|
||||
^%(pid)s \w+ authenticator failed for (\S+ )?\(\S+\) \[<HOST>\](:\d+)?( I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$
|
||||
^%(pid)s %(host_info)sF=(<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (relay not permitted|Sender verify failed|Unknown user)\s*$
|
||||
^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (connection from|"\S+") %(host_info)s(next )?input=".*"\s*$
|
||||
^%(pid)s SMTP call from \S+ \[<HOST>\](:\d+)? (I=\[\S+\](:\d+)? )?dropped: too many nonmail commands \(last was "\S+"\)\s*$
|
||||
^%(pid)s SMTP protocol error in "AUTH \S*(| \S*)" H=(|\S* )(|\(\S*\) )\[<HOST>\]\:\d+ I=\[\S*\]\:\d+ AUTH command used when not advertised\s*$
|
||||
^%(pid)s no MAIL in SMTP connection from (|\S* )(|\(\S*\) )\[<HOST>\]\:\d+ I=\[\S*\]\:\d+ D=\d+s(| C=\S*)\s*$
|
||||
^%(pid)s \S+ SMTP connection from (|\S* )(|\(\S*\) )\[<HOST>\]\:\d+ I=\[\S*\]\:\d+ closed by DROP in ACL\s*$
|
||||
^%(pid)s \w+ authenticator failed for (\S+ )?\(\S+\) \[<HOST>\](?::\d+)?(?: I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$
|
||||
^%(pid)s %(host_info)sF=(?:<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user)\s*$
|
||||
^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (?:connection from|"\S+") %(host_info)s(?:next )?input=".*"\s*$
|
||||
^%(pid)s SMTP call from \S+ %(host_info)sdropped: too many nonmail commands \(last was "\S+"\)\s*$
|
||||
^%(pid)s SMTP protocol error in "AUTH \S*(?: \S*)?" %(host_info)sAUTH command used when not advertised\s*$
|
||||
^%(pid)s no MAIL in SMTP connection from (?:\S* )?(?:\(\S*\) )?%(host_info)sD=\d+s(?: C=\S*)?\s*$
|
||||
^%(pid)s \S+ SMTP connection from (?:\S* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ from ..version import version
|
|||
from .csocket import CSocket
|
||||
from .beautifier import Beautifier
|
||||
from .fail2bancmdline import Fail2banCmdLine, ServerExecutionException, ExitException, \
|
||||
logSys, PRODUCTION, exit, output
|
||||
logSys, exit, output
|
||||
|
||||
PROMPT = "fail2ban> "
|
||||
|
||||
|
@ -227,11 +227,11 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
# prepare: read config, check configuration is valid, etc.:
|
||||
if phase is not None:
|
||||
phase['start'] = True
|
||||
logSys.debug('-- client phase %s', phase)
|
||||
logSys.debug(' client phase %s', phase)
|
||||
stream = self.__prepareStartServer()
|
||||
if phase is not None:
|
||||
phase['ready'] = phase['start'] = (True if stream else False)
|
||||
logSys.debug('-- client phase %s', phase)
|
||||
logSys.debug(' client phase %s', phase)
|
||||
if not stream:
|
||||
return False
|
||||
# configure server with config stream:
|
||||
|
@ -361,8 +361,6 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
|
||||
# Interactive mode
|
||||
if self._conf.get("interactive", False):
|
||||
# no readline in test:
|
||||
if PRODUCTION: # pragma: no cover
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
|
@ -372,7 +370,6 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
if len(args) > 0:
|
||||
ret = self.__processCommand(args)
|
||||
if ret:
|
||||
if PRODUCTION: # pragma: no cover
|
||||
readline.parse_and_bind("tab: complete")
|
||||
self.dispInteractive()
|
||||
while True:
|
||||
|
@ -411,11 +408,9 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
|||
signal.signal(s, sh)
|
||||
|
||||
|
||||
##
|
||||
# Wonderful visual :)
|
||||
#
|
||||
|
||||
class _VisualWait:
|
||||
"""Small progress indication (as "wonderful visual") during waiting process
|
||||
"""
|
||||
pos = 0
|
||||
delta = 1
|
||||
def __init__(self, maxpos=10):
|
||||
|
@ -427,6 +422,8 @@ class _VisualWait:
|
|||
sys.stdout.write('\r'+(' '*(35+self.maxpos))+'\r')
|
||||
sys.stdout.flush()
|
||||
def heartbeat(self):
|
||||
"""Show or step for progress indicator
|
||||
"""
|
||||
if not self.pos:
|
||||
sys.stdout.write("\nINFO [#" + (' '*self.maxpos) + "] Waiting on the server...\r\x1b[8C")
|
||||
self.pos += self.delta
|
||||
|
@ -441,6 +438,8 @@ class _VisualWait:
|
|||
elif self.pos < 2:
|
||||
self.delta = 1
|
||||
class _NotVisualWait:
|
||||
"""Mockup for invisible progress indication (not verbose)
|
||||
"""
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, *args):
|
||||
|
@ -449,6 +448,8 @@ class _NotVisualWait:
|
|||
pass
|
||||
|
||||
def VisualWait(verbose, *args, **kwargs):
|
||||
"""Wonderful visual progress indication (if verbose)
|
||||
"""
|
||||
return _VisualWait(*args, **kwargs) if verbose > 1 else _NotVisualWait()
|
||||
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ PRODUCTION = True
|
|||
|
||||
MAX_WAITTIME = 30
|
||||
|
||||
|
||||
class Fail2banCmdLine():
|
||||
|
||||
def __init__(self):
|
||||
|
@ -83,9 +84,6 @@ class Fail2banCmdLine():
|
|||
output("Copyright (c) 2004-2008 Cyril Jaquier, 2008- Fail2Ban Contributors")
|
||||
output("Copyright of modifications held by their respective authors.")
|
||||
output("Licensed under the GNU General Public License v2 (GPL).")
|
||||
output("")
|
||||
output("Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.")
|
||||
output("Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.")
|
||||
|
||||
def dispUsage(self):
|
||||
""" Prints Fail2Ban command line options and exits
|
||||
|
@ -187,7 +185,7 @@ class Fail2banCmdLine():
|
|||
if ret is not None:
|
||||
return ret
|
||||
|
||||
logSys.debug("-- conf: %r, args: %r", self._conf, self._args)
|
||||
logSys.debug(" conf: %r, args: %r", self._conf, self._args)
|
||||
|
||||
if initial and PRODUCTION: # pragma: no cover - can't test
|
||||
verbose = self._conf["verbose"]
|
||||
|
@ -259,14 +257,26 @@ class Fail2banCmdLine():
|
|||
output(c)
|
||||
return True
|
||||
|
||||
#
|
||||
# _exit is made to ease mocking out of the behaviour in tests,
|
||||
# since method is also exposed in API via globally bound variable
|
||||
@staticmethod
|
||||
def exit(code=0): # pragma: no cover - can't test
|
||||
logSys.debug("Exit with code %s", code)
|
||||
if os._exit:
|
||||
def _exit(code=0):
|
||||
if hasattr(os, '_exit') and os._exit:
|
||||
os._exit(code)
|
||||
else:
|
||||
sys.exit(code)
|
||||
|
||||
@staticmethod
|
||||
def exit(code=0):
|
||||
logSys.debug("Exit with code %s", code)
|
||||
# because of possible buffered output in python, we should flush it before exit:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
# exit
|
||||
Fail2banCmdLine._exit(code)
|
||||
|
||||
|
||||
# global exit handler:
|
||||
exit = Fail2banCmdLine.exit
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
|
||||
@staticmethod
|
||||
def startServerDirect(conf, daemon=True):
|
||||
logSys.debug("-- direct starting of server in %s, deamon: %s", os.getpid(), daemon)
|
||||
logSys.debug(" direct starting of server in %s, deamon: %s", os.getpid(), daemon)
|
||||
from ..server.server import Server
|
||||
server = None
|
||||
try:
|
||||
|
@ -79,7 +79,7 @@ class Fail2banServer(Fail2banCmdLine):
|
|||
frk = not conf["async"] and PRODUCTION
|
||||
if frk: # pragma: no cover
|
||||
pid = os.fork()
|
||||
logSys.debug("-- async starting of server in %s, fork: %s - %s", os.getpid(), frk, pid)
|
||||
logSys.debug(" async starting of server in %s, fork: %s - %s", os.getpid(), frk, pid)
|
||||
if pid == 0:
|
||||
args = list()
|
||||
args.append(SERVER)
|
||||
|
|
|
@ -27,6 +27,9 @@ __license__ = "GPL"
|
|||
import textwrap
|
||||
|
||||
def output(s):
|
||||
"""Default output handler for printing protocol.
|
||||
Used to ease mocking in the test cases.
|
||||
"""
|
||||
print(s)
|
||||
|
||||
##
|
||||
|
|
|
@ -88,6 +88,11 @@ class Server:
|
|||
logSys.debug("Caught signal %d. Flushing logs" % signum)
|
||||
self.flushLogs()
|
||||
|
||||
def _rebindSignal(self, s, new):
|
||||
"""Bind new signal handler while storing old one in _prev_signals"""
|
||||
self.__prev_signals[s] = signal.getsignal(s)
|
||||
signal.signal(s, new)
|
||||
|
||||
def start(self, sock, pidfile, force=False, observer=True, conf={}):
|
||||
# First set the mask to only allow access to owner
|
||||
os.umask(0077)
|
||||
|
@ -121,9 +126,10 @@ class Server:
|
|||
|
||||
# Install signal handlers
|
||||
if _thread_name() == '_MainThread':
|
||||
for s in (signal.SIGTERM, signal.SIGINT, signal.SIGUSR1):
|
||||
self.__prev_signals[s] = signal.getsignal(s)
|
||||
signal.signal(s, self.__sigTERMhandler if s != signal.SIGUSR1 else self.__sigUSR1handler)
|
||||
for s in (signal.SIGTERM, signal.SIGINT):
|
||||
self._rebindSignal(s, self.__sigTERMhandler)
|
||||
self._rebindSignal(signal.SIGUSR1, self.__sigUSR1handler)
|
||||
|
||||
# Ensure unhandled exceptions are logged
|
||||
sys.excepthook = excepthook
|
||||
|
||||
|
@ -389,7 +395,7 @@ class Server:
|
|||
return self.__jails[name].getBanTimeExtra(opt)
|
||||
|
||||
def isStarted(self):
|
||||
self.__asyncServer.isActive()
|
||||
return self.__asyncServer is not None and self.__asyncServer.isActive()
|
||||
|
||||
def isAlive(self, jailnum=None):
|
||||
if jailnum is not None and len(self.__jails) != jailnum:
|
||||
|
@ -437,7 +443,7 @@ class Server:
|
|||
getLogger("fail2ban").setLevel(getattr(logging, value))
|
||||
self.__logLevel = value
|
||||
except AttributeError:
|
||||
raise ValueError("Invalid log level")
|
||||
raise ValueError("Invalid log level %r" % value)
|
||||
|
||||
##
|
||||
# Get the logging level.
|
||||
|
@ -519,7 +525,7 @@ class Server:
|
|||
hdlr.setFormatter(formatter)
|
||||
logger.addHandler(hdlr)
|
||||
# Does not display this message at startup.
|
||||
if not self.__logTarget is None:
|
||||
if self.__logTarget is not None:
|
||||
logSys.info("Start Fail2ban v%s", version.version)
|
||||
logSys.info(
|
||||
"Changed logging target to %s for Fail2ban v%s"
|
||||
|
@ -608,9 +614,7 @@ class Server:
|
|||
# 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.
|
||||
for s in (signal.SIGHUP,):
|
||||
self.__prev_signals[s] = signal.getsignal(s)
|
||||
signal.signal(s, signal.SIG_IGN)
|
||||
self._rebindSignal(signal.SIGHUP, signal.SIG_IGN)
|
||||
|
||||
try:
|
||||
# Fork a child process so the parent can exit. This will return control
|
||||
|
|
|
@ -31,25 +31,30 @@ import time
|
|||
import signal
|
||||
import unittest
|
||||
|
||||
from os.path import join as pjoin, isdir, isfile, exists, dirname
|
||||
from functools import wraps
|
||||
from threading import Thread
|
||||
|
||||
|
||||
from ..client import fail2banclient, fail2banserver, fail2bancmdline
|
||||
from ..client.fail2banclient import Fail2banClient, exec_command_line as _exec_client, VisualWait
|
||||
from ..client.fail2bancmdline import Fail2banCmdLine
|
||||
from ..client.fail2banclient import exec_command_line as _exec_client, VisualWait
|
||||
from ..client.fail2banserver import Fail2banServer, exec_command_line as _exec_server
|
||||
from .. import protocol
|
||||
from ..server import server
|
||||
from ..server.utils import Utils
|
||||
from .utils import LogCaptureTestCase, logSys, with_tmpdir, shutil, logging
|
||||
from .utils import LogCaptureTestCase, with_tmpdir, shutil, logging
|
||||
|
||||
from ..helpers import getLogger
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
STOCK_CONF_DIR = "config"
|
||||
STOCK = os.path.exists(os.path.join(STOCK_CONF_DIR,'fail2ban.conf'))
|
||||
STOCK = exists(pjoin(STOCK_CONF_DIR, 'fail2ban.conf'))
|
||||
|
||||
CLIENT = "fail2ban-client"
|
||||
SERVER = "fail2ban-server"
|
||||
BIN = os.path.dirname(Fail2banServer.getServerPath())
|
||||
BIN = dirname(Fail2banServer.getServerPath())
|
||||
|
||||
MAX_WAITTIME = 30 if not unittest.F2B.fast else 5
|
||||
|
||||
|
@ -72,63 +77,68 @@ fail2banclient.output = \
|
|||
fail2banserver.output = \
|
||||
protocol.output = _test_output
|
||||
|
||||
def _test_exit(code=0):
|
||||
logSys.debug("Exit with code %s", code)
|
||||
if code == 0:
|
||||
raise ExitException()
|
||||
else:
|
||||
raise FailExitException()
|
||||
fail2bancmdline.exit = \
|
||||
fail2banclient.exit = \
|
||||
fail2banserver.exit = _test_exit
|
||||
|
||||
#
|
||||
# Mocking .exit so we could test its correct operation.
|
||||
# Two custom exceptions will be assessed to be raised in the tests
|
||||
#
|
||||
|
||||
class ExitException(fail2bancmdline.ExitException):
|
||||
"""Exception upon a normal exit"""
|
||||
pass
|
||||
|
||||
|
||||
class FailExitException(fail2bancmdline.ExitException):
|
||||
"""Exception upon abnormal exit"""
|
||||
pass
|
||||
|
||||
|
||||
INTERACT = []
|
||||
|
||||
|
||||
def _test_input_command(*args):
|
||||
if len(INTERACT):
|
||||
#logSys.debug('--- interact command: %r', INTERACT[0])
|
||||
return INTERACT.pop(0)
|
||||
else:
|
||||
return "exit"
|
||||
|
||||
fail2banclient.input_command = _test_input_command
|
||||
|
||||
# prevents change logging params, log capturing, etc:
|
||||
fail2bancmdline.PRODUCTION = \
|
||||
fail2banclient.PRODUCTION = \
|
||||
fail2banserver.PRODUCTION = False
|
||||
|
||||
|
||||
class ExitException(fail2bancmdline.ExitException):
|
||||
pass
|
||||
class FailExitException(fail2bancmdline.ExitException):
|
||||
pass
|
||||
|
||||
|
||||
def _out_file(fn): # pragma: no cover
|
||||
def _out_file(fn):
|
||||
"""Helper which outputs content of the file at HEAVYDEBUG loglevels"""
|
||||
logSys.debug('---- ' + fn + ' ----')
|
||||
for line in fileinput.input(fn):
|
||||
line = line.rstrip('\n')
|
||||
logSys.debug(line)
|
||||
logSys.debug('-'*30)
|
||||
|
||||
|
||||
def _start_params(tmp, use_stock=False, logtarget="/dev/null"):
|
||||
cfg = tmp+"/config"
|
||||
cfg = pjoin(tmp, "config")
|
||||
if use_stock and STOCK:
|
||||
# copy config (sub-directories as alias):
|
||||
def ig_dirs(dir, files):
|
||||
return [f for f in files if os.path.isdir(os.path.join(dir, f))]
|
||||
"""Filters list of 'files' to contain only directories (under dir)"""
|
||||
return [f for f in files if isdir(pjoin(dir, f))]
|
||||
shutil.copytree(STOCK_CONF_DIR, cfg, ignore=ig_dirs)
|
||||
os.symlink(STOCK_CONF_DIR+"/action.d", cfg+"/action.d")
|
||||
os.symlink(STOCK_CONF_DIR+"/filter.d", cfg+"/filter.d")
|
||||
os.symlink(pjoin(STOCK_CONF_DIR, "action.d"), pjoin(cfg, "action.d"))
|
||||
os.symlink(pjoin(STOCK_CONF_DIR, "filter.d"), pjoin(cfg, "filter.d"))
|
||||
# replace fail2ban params (database with memory):
|
||||
r = re.compile(r'^dbfile\s*=')
|
||||
for line in fileinput.input(cfg+"/fail2ban.conf", inplace=True):
|
||||
for line in fileinput.input(pjoin(cfg, "fail2ban.conf"), inplace=True):
|
||||
line = line.rstrip('\n')
|
||||
if r.match(line):
|
||||
line = "dbfile = :memory:"
|
||||
print(line)
|
||||
# replace jail params (polling as backend to be fast in initialize):
|
||||
r = re.compile(r'^backend\s*=')
|
||||
for line in fileinput.input(cfg+"/jail.conf", inplace=True):
|
||||
for line in fileinput.input(pjoin(cfg, "jail.conf"), inplace=True):
|
||||
line = line.rstrip('\n')
|
||||
if r.match(line):
|
||||
line = "backend = polling"
|
||||
|
@ -136,21 +146,21 @@ def _start_params(tmp, use_stock=False, logtarget="/dev/null"):
|
|||
else:
|
||||
# just empty config directory without anything (only fail2ban.conf/jail.conf):
|
||||
os.mkdir(cfg)
|
||||
f = open(cfg+"/fail2ban.conf", "w")
|
||||
f = open(pjoin(cfg, "fail2ban.conf"), "w")
|
||||
f.write('\n'.join((
|
||||
"[Definition]",
|
||||
"loglevel = INFO",
|
||||
"logtarget = " + logtarget,
|
||||
"syslogsocket = auto",
|
||||
"socket = "+tmp+"/f2b.sock",
|
||||
"pidfile = "+tmp+"/f2b.pid",
|
||||
"socket = " + pjoin(tmp, "f2b.sock"),
|
||||
"pidfile = " + pjoin(tmp, "f2b.pid"),
|
||||
"backend = polling",
|
||||
"dbfile = :memory:",
|
||||
"dbpurgeage = 1d",
|
||||
"",
|
||||
)))
|
||||
f.close()
|
||||
f = open(cfg+"/jail.conf", "w")
|
||||
f = open(pjoin(cfg, "jail.conf"), "w")
|
||||
f.write('\n'.join((
|
||||
"[INCLUDES]", "",
|
||||
"[DEFAULT]", "",
|
||||
|
@ -158,54 +168,60 @@ def _start_params(tmp, use_stock=False, logtarget="/dev/null"):
|
|||
)))
|
||||
f.close()
|
||||
if logSys.level < logging.DEBUG: # if HEAVYDEBUG
|
||||
_out_file(cfg+"/fail2ban.conf")
|
||||
_out_file(cfg+"/jail.conf")
|
||||
_out_file(pjoin(cfg, "fail2ban.conf"))
|
||||
_out_file(pjoin(cfg, "jail.conf"))
|
||||
# parameters (sock/pid and config, increase verbosity, set log, etc.):
|
||||
return ("-c", cfg, "-s", tmp+"/f2b.sock", "-p", tmp+"/f2b.pid",
|
||||
return (
|
||||
"-c", cfg, "-s", pjoin(tmp, "f2b.sock"), "-p", pjoin(tmp, "f2b.pid"),
|
||||
"-vv", "--logtarget", logtarget, "--loglevel", "DEBUG", "--syslogsocket", "auto",
|
||||
"--timeout", str(fail2bancmdline.MAX_WAITTIME),
|
||||
)
|
||||
|
||||
def _kill_srv(pidfile): # pragma: no cover
|
||||
def _pid_exists(pid):
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
logSys.debug("-- cleanup: %r", (pidfile, os.path.isdir(pidfile)))
|
||||
if os.path.isdir(pidfile):
|
||||
|
||||
def _kill_srv(pidfile):
|
||||
logSys.debug("cleanup: %r", (pidfile, isdir(pidfile)))
|
||||
if isdir(pidfile):
|
||||
piddir = pidfile
|
||||
pidfile = piddir + "/f2b.pid"
|
||||
if not os.path.isfile(pidfile):
|
||||
pidfile = piddir + "/fail2ban.pid"
|
||||
if not os.path.isfile(pidfile):
|
||||
logSys.debug("--- cleanup: no pidfile for %r", piddir)
|
||||
pidfile = pjoin(piddir, "f2b.pid")
|
||||
if not isfile(pidfile): # pragma: no cover
|
||||
pidfile = pjoin(piddir, "fail2ban.pid")
|
||||
|
||||
if not isfile(pidfile):
|
||||
logSys.debug("cleanup: no pidfile for %r", piddir)
|
||||
return True
|
||||
|
||||
f = pid = None
|
||||
try:
|
||||
logSys.debug("--- cleanup pidfile: %r", pidfile)
|
||||
logSys.debug("cleanup pidfile: %r", pidfile)
|
||||
f = open(pidfile)
|
||||
pid = f.read().split()[1]
|
||||
pid = f.read()
|
||||
pid = re.match(r'\S+', pid).group()
|
||||
pid = int(pid)
|
||||
logSys.debug("--- cleanup pid: %r", pid)
|
||||
if pid <= 0:
|
||||
raise ValueError('pid %s of %s is invalid' % (pid, pidfile))
|
||||
if not _pid_exists(pid):
|
||||
return True
|
||||
## try to preper stop (have signal handler):
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
## check still exists after small timeout:
|
||||
if not Utils.wait_for(lambda: not _pid_exists(pid), 1):
|
||||
## try to kill hereafter:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
return not _pid_exists(pid)
|
||||
except Exception as e:
|
||||
except Exception as e: # pragma: no cover
|
||||
logSys.debug(e)
|
||||
return False
|
||||
finally:
|
||||
if f is not None:
|
||||
f.close()
|
||||
|
||||
try:
|
||||
logSys.debug("cleanup pid: %r", pid)
|
||||
if pid <= 0 or pid == os.getpid(): # pragma: no cover
|
||||
raise ValueError('pid %s of %s is invalid' % (pid, pidfile))
|
||||
if not Utils.pid_exists(pid):
|
||||
return True
|
||||
## try to properly stop (have signal handler):
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
## check still exists after small timeout:
|
||||
if not Utils.wait_for(lambda: not Utils.pid_exists(pid), 1):
|
||||
## try to kill hereafter:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
logSys.debug("cleanup: kill ready")
|
||||
return not Utils.pid_exists(pid)
|
||||
except Exception as e: # pragma: no cover
|
||||
logSys.exception(e)
|
||||
return True
|
||||
|
||||
|
||||
def with_kill_srv(f):
|
||||
"""Helper to decorate tests which receive in the last argument tmpdir to pass to kill_srv
|
||||
|
@ -224,187 +240,83 @@ def with_kill_srv(f):
|
|||
|
||||
class Fail2banClientServerBase(LogCaptureTestCase):
|
||||
|
||||
_orig_exit = Fail2banCmdLine._exit
|
||||
|
||||
def setUp(self):
|
||||
"""Call before every test case."""
|
||||
LogCaptureTestCase.setUp(self)
|
||||
Fail2banCmdLine._exit = staticmethod(self._test_exit)
|
||||
|
||||
def tearDown(self):
|
||||
"""Call after every test case."""
|
||||
Fail2banCmdLine._exit = self._orig_exit
|
||||
LogCaptureTestCase.tearDown(self)
|
||||
|
||||
@staticmethod
|
||||
def _test_exit(code=0):
|
||||
if code == 0:
|
||||
raise ExitException()
|
||||
else:
|
||||
raise FailExitException()
|
||||
|
||||
def _wait_for_srv(self, tmp, ready=True, startparams=None):
|
||||
try:
|
||||
sock = tmp+"/f2b.sock"
|
||||
sock = pjoin(tmp, "f2b.sock")
|
||||
# wait for server (socket):
|
||||
ret = Utils.wait_for(lambda: os.path.exists(sock), MAX_WAITTIME)
|
||||
ret = Utils.wait_for(lambda: exists(sock), MAX_WAITTIME)
|
||||
if not ret:
|
||||
raise Exception('Unexpected: Socket file does not exists.\nStart failed: %r' % (startparams,))
|
||||
raise Exception(
|
||||
'Unexpected: Socket file does not exists.\nStart failed: %r'
|
||||
% (startparams,)
|
||||
)
|
||||
if ready:
|
||||
# wait for communication with worker ready:
|
||||
ret = Utils.wait_for(lambda: "Server ready" in self.getLog(), MAX_WAITTIME)
|
||||
if not ret:
|
||||
raise Exception('Unexpected: Server ready was not found.\nStart failed: %r' % (startparams,))
|
||||
raise Exception(
|
||||
'Unexpected: Server ready was not found.\nStart failed: %r'
|
||||
% (startparams,)
|
||||
)
|
||||
except: # pragma: no cover
|
||||
log = tmp+"/f2b.log"
|
||||
if os.path.isfile(log):
|
||||
log = pjoin(tmp, "f2b.log")
|
||||
if isfile(log):
|
||||
_out_file(log)
|
||||
else:
|
||||
logSys.debug("No log file %s to examine details of error", log)
|
||||
raise
|
||||
|
||||
def execSuccess(self, startparams, *args):
|
||||
raise NotImplementedError("To be defined in subclass")
|
||||
|
||||
class Fail2banClientTest(Fail2banClientServerBase):
|
||||
def execFailed(self, startparams, *args):
|
||||
raise NotImplementedError("To be defined in subclass")
|
||||
|
||||
def testConsistency(self):
|
||||
self.assertTrue(os.path.isfile(os.path.join(os.path.join(BIN), CLIENT)))
|
||||
self.assertTrue(os.path.isfile(os.path.join(os.path.join(BIN), SERVER)))
|
||||
|
||||
def testClientUsage(self):
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT, "-h",))
|
||||
self.assertLogged("Usage: " + CLIENT)
|
||||
self.assertLogged("Report bugs to ")
|
||||
self.pruneLog()
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT, "-vq", "-V",))
|
||||
self.assertLogged("Fail2Ban v" + fail2bancmdline.version)
|
||||
|
||||
@with_tmpdir
|
||||
def testClientDump(self, tmp):
|
||||
# use here the stock configuration (if possible)
|
||||
startparams = _start_params(tmp, True)
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
((CLIENT,) + startparams + ("-vvd",)))
|
||||
self.assertLogged("Loading files")
|
||||
self.assertLogged("logtarget")
|
||||
|
||||
@with_tmpdir
|
||||
@with_kill_srv
|
||||
def testClientStartBackgroundInside(self, tmp):
|
||||
# use once the stock configuration (to test starting also)
|
||||
startparams = _start_params(tmp, True)
|
||||
# start:
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT, "-b") + startparams + ("start",))
|
||||
# wait for server (socket and ready):
|
||||
self._wait_for_srv(tmp, True, startparams=startparams)
|
||||
self.assertLogged("Server ready")
|
||||
self.assertLogged("Exit with code 0")
|
||||
try:
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("echo", "TEST-ECHO",))
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("~~unknown~cmd~failed~~",))
|
||||
self.pruneLog()
|
||||
# start again (should fail):
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT, "-b") + startparams + ("start",))
|
||||
self.assertLogged("Server already running")
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("stop",))
|
||||
self.assertLogged("Shutdown successful")
|
||||
self.assertLogged("Exit with code 0")
|
||||
|
||||
self.pruneLog()
|
||||
# stop again (should fail):
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("stop",))
|
||||
self.assertLogged("Failed to access socket path")
|
||||
self.assertLogged("Is fail2ban running?")
|
||||
|
||||
@with_tmpdir
|
||||
@with_kill_srv
|
||||
def testClientStartBackgroundCall(self, tmp):
|
||||
global INTERACT
|
||||
startparams = _start_params(tmp, logtarget=tmp+"/f2b.log")
|
||||
# start (in new process, using the same python version):
|
||||
cmd = (sys.executable, os.path.join(os.path.join(BIN), CLIENT))
|
||||
logSys.debug('Start %s ...', cmd)
|
||||
cmd = cmd + startparams + ("--async", "start",)
|
||||
ret = Utils.executeCmd(cmd, timeout=MAX_WAITTIME, shell=False, output=True)
|
||||
self.assertTrue(len(ret) and ret[0])
|
||||
# wait for server (socket and ready):
|
||||
self._wait_for_srv(tmp, True, startparams=cmd)
|
||||
self.assertLogged("Server ready")
|
||||
self.pruneLog()
|
||||
try:
|
||||
# echo from client (inside):
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("echo", "TEST-ECHO",))
|
||||
self.assertLogged("TEST-ECHO")
|
||||
self.assertLogged("Exit with code 0")
|
||||
self.pruneLog()
|
||||
# interactive client chat with started server:
|
||||
INTERACT += [
|
||||
"echo INTERACT-ECHO",
|
||||
"status",
|
||||
"exit"
|
||||
]
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("-i",))
|
||||
self.assertLogged("INTERACT-ECHO")
|
||||
self.assertLogged("Status", "Number of jail:")
|
||||
self.assertLogged("Exit with code 0")
|
||||
self.pruneLog()
|
||||
# test reload and restart over interactive client:
|
||||
INTERACT += [
|
||||
"reload",
|
||||
"restart",
|
||||
"exit"
|
||||
]
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("-i",))
|
||||
self.assertLogged("Reading config files:")
|
||||
self.assertLogged("Shutdown successful")
|
||||
self.assertLogged("Server ready")
|
||||
self.assertLogged("Exit with code 0")
|
||||
self.pruneLog()
|
||||
# test reload missing jail (interactive):
|
||||
INTERACT += [
|
||||
"reload ~~unknown~jail~fail~~",
|
||||
"exit"
|
||||
]
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("-i",))
|
||||
self.assertLogged("Failed during configuration: No section: '~~unknown~jail~fail~~'")
|
||||
self.pruneLog()
|
||||
# test reload missing jail (direct):
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("reload", "~~unknown~jail~fail~~"))
|
||||
self.assertLogged("Failed during configuration: No section: '~~unknown~jail~fail~~'")
|
||||
self.assertLogged("Exit with code -1")
|
||||
self.pruneLog()
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("stop",))
|
||||
self.assertLogged("Shutdown successful")
|
||||
self.assertLogged("Exit with code 0")
|
||||
|
||||
def _testClientStartForeground(self, tmp, startparams, phase):
|
||||
#
|
||||
# Common tests
|
||||
#
|
||||
def _testStartForeground(self, tmp, startparams, phase):
|
||||
# start and wait to end (foreground):
|
||||
logSys.debug("-- start of test worker")
|
||||
logSys.debug("start of test worker")
|
||||
phase['start'] = True
|
||||
self.assertRaises(fail2bancmdline.ExitException, _exec_client,
|
||||
(CLIENT, "-f") + startparams + ("start",))
|
||||
self.execSuccess(("-f",) + startparams, "start")
|
||||
# end :
|
||||
phase['end'] = True
|
||||
logSys.debug("-- end of test worker")
|
||||
logSys.debug("end of test worker")
|
||||
|
||||
@with_tmpdir
|
||||
def testClientStartForeground(self, tmp):
|
||||
def testStartForeground(self, tmp):
|
||||
# intended to be ran only in subclasses
|
||||
th = None
|
||||
phase = dict()
|
||||
try:
|
||||
# started directly here, so prevent overwrite test cases logger with "INHERITED"
|
||||
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||
# because foreground block execution - start it in thread:
|
||||
phase = dict()
|
||||
th = Thread(name="_TestCaseWorker",
|
||||
target=Fail2banClientTest._testClientStartForeground, args=(self, tmp, startparams, phase))
|
||||
th = Thread(
|
||||
name="_TestCaseWorker",
|
||||
target=self._testStartForeground,
|
||||
args=(tmp, startparams, phase)
|
||||
)
|
||||
th.daemon = True
|
||||
th.start()
|
||||
try:
|
||||
|
@ -415,26 +327,150 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
|||
self._wait_for_srv(tmp, True, startparams=startparams)
|
||||
self.pruneLog()
|
||||
# several commands to server:
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("ping",))
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("~~unknown~cmd~failed~~",))
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("echo", "TEST-ECHO",))
|
||||
self.execSuccess(startparams, "ping")
|
||||
self.execFailed(startparams, "~~unknown~cmd~failed~~")
|
||||
self.execSuccess(startparams, "echo", "TEST-ECHO")
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
(CLIENT,) + startparams + ("stop",))
|
||||
self.execSuccess(startparams, "stop")
|
||||
# wait for end:
|
||||
Utils.wait_for(lambda: phase.get('end', None) is not None, MAX_WAITTIME)
|
||||
self.assertTrue(phase.get('end', None))
|
||||
self.assertLogged("Shutdown successful", "Exiting Fail2ban")
|
||||
finally:
|
||||
_kill_srv(tmp)
|
||||
if th:
|
||||
# we start client/server directly in current process (new thread),
|
||||
# so don't kill (same process) - if success, just wait for end of worker:
|
||||
if phase.get('end', None):
|
||||
th.join()
|
||||
|
||||
|
||||
class Fail2banClientTest(Fail2banClientServerBase):
|
||||
|
||||
def execSuccess(self, startparams, *args):
|
||||
self.assertRaises(ExitException, _exec_client,
|
||||
((CLIENT,) + startparams + args))
|
||||
|
||||
def execFailed(self, startparams, *args):
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
((CLIENT,) + startparams + args))
|
||||
|
||||
def testConsistency(self):
|
||||
self.assertTrue(isfile(pjoin(BIN, CLIENT)))
|
||||
self.assertTrue(isfile(pjoin(BIN, SERVER)))
|
||||
|
||||
def testClientUsage(self):
|
||||
self.execSuccess((), "-h")
|
||||
self.assertLogged("Usage: " + CLIENT)
|
||||
self.assertLogged("Report bugs to ")
|
||||
self.pruneLog()
|
||||
self.execSuccess((), "-vq", "-V")
|
||||
self.assertLogged("Fail2Ban v" + fail2bancmdline.version)
|
||||
|
||||
@with_tmpdir
|
||||
def testClientDump(self, tmp):
|
||||
# use here the stock configuration (if possible)
|
||||
startparams = _start_params(tmp, True)
|
||||
self.execSuccess(startparams, "-vvd")
|
||||
self.assertLogged("Loading files")
|
||||
self.assertLogged("logtarget")
|
||||
|
||||
@with_tmpdir
|
||||
@with_kill_srv
|
||||
def testClientStartBackgroundInside(self, tmp):
|
||||
# use once the stock configuration (to test starting also)
|
||||
startparams = _start_params(tmp, True)
|
||||
# start:
|
||||
self.execSuccess(("-b",) + startparams, "start")
|
||||
# wait for server (socket and ready):
|
||||
self._wait_for_srv(tmp, True, startparams=startparams)
|
||||
self.assertLogged("Server ready")
|
||||
self.assertLogged("Exit with code 0")
|
||||
try:
|
||||
self.execSuccess(startparams, "echo", "TEST-ECHO")
|
||||
self.execFailed(startparams, "~~unknown~cmd~failed~~")
|
||||
self.pruneLog()
|
||||
# start again (should fail):
|
||||
self.execFailed(("-b",) + startparams, "start")
|
||||
self.assertLogged("Server already running")
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
self.execSuccess(startparams, "stop")
|
||||
self.assertLogged("Shutdown successful")
|
||||
self.assertLogged("Exit with code 0")
|
||||
|
||||
self.pruneLog()
|
||||
# stop again (should fail):
|
||||
self.execFailed(startparams, "stop")
|
||||
self.assertLogged("Failed to access socket path")
|
||||
self.assertLogged("Is fail2ban running?")
|
||||
|
||||
@with_tmpdir
|
||||
@with_kill_srv
|
||||
def testClientStartBackgroundCall(self, tmp):
|
||||
global INTERACT
|
||||
startparams = _start_params(tmp, logtarget=pjoin(tmp, "f2b.log"))
|
||||
# start (in new process, using the same python version):
|
||||
cmd = (sys.executable, pjoin(BIN, CLIENT))
|
||||
logSys.debug('Start %s ...', cmd)
|
||||
cmd = cmd + startparams + ("--async", "start",)
|
||||
ret = Utils.executeCmd(cmd, timeout=MAX_WAITTIME, shell=False, output=True)
|
||||
self.assertTrue(len(ret) and ret[0])
|
||||
# wait for server (socket and ready):
|
||||
self._wait_for_srv(tmp, True, startparams=cmd)
|
||||
self.assertLogged("Server ready")
|
||||
self.pruneLog()
|
||||
try:
|
||||
# echo from client (inside):
|
||||
self.execSuccess(startparams, "echo", "TEST-ECHO")
|
||||
self.assertLogged("TEST-ECHO")
|
||||
self.assertLogged("Exit with code 0")
|
||||
self.pruneLog()
|
||||
# interactive client chat with started server:
|
||||
INTERACT += [
|
||||
"echo INTERACT-ECHO",
|
||||
"status",
|
||||
"exit"
|
||||
]
|
||||
self.execSuccess(startparams, "-i")
|
||||
self.assertLogged("INTERACT-ECHO")
|
||||
self.assertLogged("Status", "Number of jail:")
|
||||
self.assertLogged("Exit with code 0")
|
||||
self.pruneLog()
|
||||
# test reload and restart over interactive client:
|
||||
INTERACT += [
|
||||
"reload",
|
||||
"restart",
|
||||
"exit"
|
||||
]
|
||||
self.execSuccess(startparams, "-i")
|
||||
self.assertLogged("Reading config files:")
|
||||
self.assertLogged("Shutdown successful")
|
||||
self.assertLogged("Server ready")
|
||||
self.assertLogged("Exit with code 0")
|
||||
self.pruneLog()
|
||||
# test reload missing jail (interactive):
|
||||
INTERACT += [
|
||||
"reload ~~unknown~jail~fail~~",
|
||||
"exit"
|
||||
]
|
||||
self.execSuccess(startparams, "-i")
|
||||
self.assertLogged("Failed during configuration: No section: '~~unknown~jail~fail~~'")
|
||||
self.pruneLog()
|
||||
# test reload missing jail (direct):
|
||||
self.execFailed(startparams, "reload", "~~unknown~jail~fail~~")
|
||||
self.assertLogged("Failed during configuration: No section: '~~unknown~jail~fail~~'")
|
||||
self.assertLogged("Exit with code -1")
|
||||
self.pruneLog()
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
self.execSuccess(startparams, "stop")
|
||||
self.assertLogged("Shutdown successful")
|
||||
self.assertLogged("Exit with code 0")
|
||||
|
||||
@with_tmpdir
|
||||
@with_kill_srv
|
||||
def testClientFailStart(self, tmp):
|
||||
|
@ -442,34 +478,33 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
|||
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||
|
||||
## wrong config directory
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT, "--async", "-c", tmp+"/miss", "start",))
|
||||
self.assertLogged("Base configuration directory " + tmp+"/miss" + " does not exist")
|
||||
self.execFailed((),
|
||||
"--async", "-c", pjoin(tmp, "miss"), "start")
|
||||
self.assertLogged("Base configuration directory " + pjoin(tmp, "miss") + " does not exist")
|
||||
self.pruneLog()
|
||||
|
||||
## wrong socket
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT, "--async", "-c", tmp+"/config", "-s", tmp+"/miss/f2b.sock", "start",))
|
||||
self.assertLogged("There is no directory " + tmp+"/miss" + " to contain the socket file")
|
||||
self.execFailed((),
|
||||
"--async", "-c", pjoin(tmp, "config"), "-s", pjoin(tmp, "miss/f2b.sock"), "start")
|
||||
self.assertLogged("There is no directory " + pjoin(tmp, "miss") + " to contain the socket file")
|
||||
self.pruneLog()
|
||||
|
||||
## not running
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT, "-c", tmp+"/config", "-s", tmp+"/f2b.sock", "reload",))
|
||||
self.execFailed((),
|
||||
"-c", pjoin(tmp, "config"), "-s", pjoin(tmp, "f2b.sock"), "reload")
|
||||
self.assertLogged("Could not find server")
|
||||
self.pruneLog()
|
||||
|
||||
## already exists:
|
||||
open(tmp+"/f2b.sock", 'a').close()
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT, "--async", "-c", tmp+"/config", "-s", tmp+"/f2b.sock", "start",))
|
||||
open(pjoin(tmp, "f2b.sock"), 'a').close()
|
||||
self.execFailed((),
|
||||
"--async", "-c", pjoin(tmp, "config"), "-s", pjoin(tmp, "f2b.sock"), "start")
|
||||
self.assertLogged("Fail2ban seems to be in unexpected state (not running but the socket exists)")
|
||||
self.pruneLog()
|
||||
os.remove(tmp+"/f2b.sock")
|
||||
os.remove(pjoin(tmp, "f2b.sock"))
|
||||
|
||||
## wrong option:
|
||||
self.assertRaises(FailExitException, _exec_client,
|
||||
(CLIENT, "-s",))
|
||||
self.execFailed((), "-s")
|
||||
self.assertLogged("Usage: ")
|
||||
self.pruneLog()
|
||||
|
||||
|
@ -487,9 +522,16 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
|||
|
||||
class Fail2banServerTest(Fail2banClientServerBase):
|
||||
|
||||
def testServerUsage(self):
|
||||
def execSuccess(self, startparams, *args):
|
||||
self.assertRaises(ExitException, _exec_server,
|
||||
(SERVER, "-h",))
|
||||
((SERVER,) + startparams + args))
|
||||
|
||||
def execFailed(self, startparams, *args):
|
||||
self.assertRaises(FailExitException, _exec_server,
|
||||
((SERVER,) + startparams + args))
|
||||
|
||||
def testServerUsage(self):
|
||||
self.execSuccess((), "-h")
|
||||
self.assertLogged("Usage: " + SERVER)
|
||||
self.assertLogged("Report bugs to ")
|
||||
|
||||
|
@ -497,9 +539,9 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
|||
@with_kill_srv
|
||||
def testServerStartBackground(self, tmp):
|
||||
# to prevent fork of test-cases process, start server in background via command:
|
||||
startparams = _start_params(tmp, logtarget=tmp+"/f2b.log")
|
||||
startparams = _start_params(tmp, logtarget=pjoin(tmp, "f2b.log"))
|
||||
# start (in new process, using the same python version):
|
||||
cmd = (sys.executable, os.path.join(os.path.join(BIN), SERVER))
|
||||
cmd = (sys.executable, pjoin(BIN, SERVER))
|
||||
logSys.debug('Start %s ...', cmd)
|
||||
cmd = cmd + startparams + ("-b",)
|
||||
ret = Utils.executeCmd(cmd, timeout=MAX_WAITTIME, shell=False, output=True)
|
||||
|
@ -509,68 +551,15 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
|||
self.assertLogged("Server ready")
|
||||
self.pruneLog()
|
||||
try:
|
||||
self.assertRaises(ExitException, _exec_server,
|
||||
(SERVER,) + startparams + ("echo", "TEST-ECHO",))
|
||||
self.assertRaises(FailExitException, _exec_server,
|
||||
(SERVER,) + startparams + ("~~unknown~cmd~failed~~",))
|
||||
self.execSuccess(startparams, "echo", "TEST-ECHO")
|
||||
self.execFailed(startparams, "~~unknown~cmd~failed~~")
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
self.assertRaises(ExitException, _exec_server,
|
||||
(SERVER,) + startparams + ("stop",))
|
||||
self.execSuccess(startparams, "stop")
|
||||
self.assertLogged("Shutdown successful")
|
||||
self.assertLogged("Exit with code 0")
|
||||
|
||||
def _testServerStartForeground(self, tmp, startparams, phase):
|
||||
# start and wait to end (foreground):
|
||||
logSys.debug("-- start of test worker")
|
||||
phase['start'] = True
|
||||
self.assertRaises(fail2bancmdline.ExitException, _exec_server,
|
||||
(SERVER, "-f") + startparams + ("start",))
|
||||
# end :
|
||||
phase['end'] = True
|
||||
logSys.debug("-- end of test worker")
|
||||
|
||||
@with_tmpdir
|
||||
def testServerStartForeground(self, tmp):
|
||||
th = None
|
||||
try:
|
||||
# started directly here, so prevent overwrite test cases logger with "INHERITED"
|
||||
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||
# because foreground block execution - start it in thread:
|
||||
phase = dict()
|
||||
th = Thread(name="_TestCaseWorker",
|
||||
target=Fail2banServerTest._testServerStartForeground, args=(self, tmp, startparams, phase))
|
||||
th.daemon = True
|
||||
th.start()
|
||||
try:
|
||||
# wait for start thread:
|
||||
Utils.wait_for(lambda: phase.get('start', None) is not None, MAX_WAITTIME)
|
||||
self.assertTrue(phase.get('start', None))
|
||||
# wait for server (socket and ready):
|
||||
self._wait_for_srv(tmp, True, startparams=startparams)
|
||||
self.pruneLog()
|
||||
# several commands to server:
|
||||
self.assertRaises(ExitException, _exec_server,
|
||||
(SERVER,) + startparams + ("ping",))
|
||||
self.assertRaises(FailExitException, _exec_server,
|
||||
(SERVER,) + startparams + ("~~unknown~cmd~failed~~",))
|
||||
self.assertRaises(ExitException, _exec_server,
|
||||
(SERVER,) + startparams + ("echo", "TEST-ECHO",))
|
||||
finally:
|
||||
self.pruneLog()
|
||||
# stop:
|
||||
self.assertRaises(ExitException, _exec_server,
|
||||
(SERVER,) + startparams + ("stop",))
|
||||
# wait for end:
|
||||
Utils.wait_for(lambda: phase.get('end', None) is not None, MAX_WAITTIME)
|
||||
self.assertTrue(phase.get('end', None))
|
||||
self.assertLogged("Shutdown successful", "Exiting Fail2ban")
|
||||
finally:
|
||||
_kill_srv(tmp)
|
||||
if th:
|
||||
th.join()
|
||||
|
||||
@with_tmpdir
|
||||
@with_kill_srv
|
||||
def testServerFailStart(self, tmp):
|
||||
|
@ -578,21 +567,48 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
|||
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||
|
||||
## wrong config directory
|
||||
self.assertRaises(FailExitException, _exec_server,
|
||||
(SERVER, "-c", tmp+"/miss",))
|
||||
self.assertLogged("Base configuration directory " + tmp+"/miss" + " does not exist")
|
||||
self.execFailed((),
|
||||
"-c", pjoin(tmp, "miss"))
|
||||
self.assertLogged("Base configuration directory " + pjoin(tmp, "miss") + " does not exist")
|
||||
self.pruneLog()
|
||||
|
||||
## wrong socket
|
||||
self.assertRaises(FailExitException, _exec_server,
|
||||
(SERVER, "-c", tmp+"/config", "-x", "-s", tmp+"/miss/f2b.sock",))
|
||||
self.assertLogged("There is no directory " + tmp+"/miss" + " to contain the socket file")
|
||||
self.execFailed((),
|
||||
"-c", pjoin(tmp, "config"), "-x", "-s", pjoin(tmp, "miss/f2b.sock"))
|
||||
self.assertLogged("There is no directory " + pjoin(tmp, "miss") + " to contain the socket file")
|
||||
self.pruneLog()
|
||||
|
||||
## already exists:
|
||||
open(tmp+"/f2b.sock", 'a').close()
|
||||
self.assertRaises(FailExitException, _exec_server,
|
||||
(SERVER, "-c", tmp+"/config", "-s", tmp+"/f2b.sock",))
|
||||
open(pjoin(tmp, "f2b.sock"), 'a').close()
|
||||
self.execFailed((),
|
||||
"-c", pjoin(tmp, "config"), "-s", pjoin(tmp, "f2b.sock"))
|
||||
self.assertLogged("Fail2ban seems to be in unexpected state (not running but the socket exists)")
|
||||
self.pruneLog()
|
||||
os.remove(tmp+"/f2b.sock")
|
||||
os.remove(pjoin(tmp, "f2b.sock"))
|
||||
|
||||
@with_tmpdir
|
||||
def testKillAfterStart(self, tmp):
|
||||
try:
|
||||
# to prevent fork of test-cases process, start server in background via command:
|
||||
startparams = _start_params(tmp, logtarget=pjoin(tmp, "f2b.log"))
|
||||
# start (in new process, using the same python version):
|
||||
cmd = (sys.executable, pjoin(BIN, SERVER))
|
||||
logSys.debug('Start %s ...', cmd)
|
||||
cmd = cmd + startparams + ("-b",)
|
||||
ret = Utils.executeCmd(cmd, timeout=MAX_WAITTIME, shell=False, output=True)
|
||||
self.assertTrue(len(ret) and ret[0])
|
||||
# wait for server (socket and ready):
|
||||
self._wait_for_srv(tmp, True, startparams=cmd)
|
||||
self.assertLogged("Server ready")
|
||||
self.pruneLog()
|
||||
logSys.debug('Kill server ... %s', tmp)
|
||||
finally:
|
||||
self.assertTrue(_kill_srv(tmp))
|
||||
# wait for end (kill was successful):
|
||||
Utils.wait_for(lambda: not isfile(pjoin(tmp, "f2b.pid")), MAX_WAITTIME)
|
||||
self.assertFalse(isfile(pjoin(tmp, "f2b.pid")))
|
||||
self.assertLogged("cleanup: kill ready")
|
||||
self.pruneLog()
|
||||
# again:
|
||||
self.assertTrue(_kill_srv(tmp))
|
||||
self.assertLogged("cleanup: no pidfile for")
|
||||
|
|
|
@ -67,3 +67,18 @@ Nov 4 18:30:40 localhost asterisk[32229]: NOTICE[32257]: chan_sip.c:23417 in han
|
|||
[2016-01-28 10:34:31] NOTICE[3477][C-000003c3] chan_sip.c: Call from '' (1.2.3.4:10836) to extension '0+441772285407' rejected because extension not found in context 'default'.
|
||||
# failJSON: { "time": "2016-01-28T10:34:33", "match": true , "host": "1.2.3.4" }
|
||||
[2016-01-28 10:34:33] NOTICE[3477][C-000003c3] chan_sip.c: Call from '' (1.2.3.4:10836) to extension '' rejected because extension not found in context 'my-context'.
|
||||
|
||||
# Failed authentication with pjsip on Asterisk 13+
|
||||
# failJSON: { "time": "2016-05-23T10:18:16", "match": true , "host": "1.2.3.4" }
|
||||
[2016-05-23 10:18:16] NOTICE[19388] res_pjsip/pjsip_distributor.c: Request from '"1000" <sip:1000@10.0.0.1>' failed for '1.2.3.4:48336' (callid: 276666022) - No matching endpoint found
|
||||
# failJSON: { "time": "2016-05-23T10:18:16", "match": true , "host": "1.2.3.4" }
|
||||
[2016-05-23 10:18:16] NOTICE[19388] res_pjsip/pjsip_distributor.c: Request from '"1000" <sip:1000@10.0.0.1>' failed for '1.2.3.4:48336' (callid: 276666022) - Not match Endpoint ACL
|
||||
# failJSON: { "time": "2016-05-23T10:18:16", "match": true , "host": "1.2.3.4" }
|
||||
[2016-05-23 10:18:16] NOTICE[19388] res_pjsip/pjsip_distributor.c: Request from '"1000" <sip:1000@10.0.0.1>' failed for '1.2.3.4:48336' (callid: 276666022) - Not match Endpoint Contact ACL
|
||||
# failJSON: { "time": "2016-05-23T10:18:16", "match": true , "host": "1.2.3.4" }
|
||||
[2016-05-23 10:18:16] NOTICE[19388] res_pjsip/pjsip_distributor.c: Request from '"1000" <sip:1000@10.0.0.1>' failed for '1.2.3.4:48336' (callid: 276666022) - Failed to authenticate
|
||||
# failJSON: { "time": "2016-05-23T10:18:16", "match": true , "host": "1.2.3.4" }
|
||||
[2016-05-23 10:18:16] NOTICE[19388] res_pjsip/pjsip_distributor.c: Request from '"1000" <sip:1000@10.0.0.1>' failed for '1.2.3.4:48336' (callid: 276666022) - Error to authenticate
|
||||
# Failed authentication with pjsip on Asterisk 13+
|
||||
# failJSON: { "time": "2016-06-08T23:40:26", "match": true , "host": "2.3.4.5" }
|
||||
[2016-06-08 23:40:26] NOTICE[32497] res_pjsip/pjsip_distributor.c: Request from '"317" <sip:317@1.2.3.4>' failed for '2.3.4.5:5089' (callid: 206f178f-896564cb-57573f49@1.2.3.4) - No matching endpoint found
|
||||
|
|
|
@ -48,10 +48,14 @@
|
|||
2016-03-18 00:34:06 [7513] SMTP protocol error in "AUTH LOGIN" H=(ylmf-pc) [45.32.34.167]:60723 I=[172.89.0.6]:587 AUTH command used when not advertised
|
||||
# failJSON: { "time": "2016-03-19T18:40:44", "match": true , "host": "92.45.204.170" }
|
||||
2016-03-19 18:40:44 [26221] SMTP protocol error in "AUTH LOGIN aW5mb0BtYW5iYXQub3Jn" H=([127.0.0.1]) [92.45.204.170]:14243 I=[172.89.0.6]:587 AUTH command used when not advertised
|
||||
# failJSON: { "time": "2016-05-17T06:25:27", "match": true , "host": "69.10.61.61", "desc": "from gh-1430" }
|
||||
2016-05-17 06:25:27 SMTP protocol error in "AUTH LOGIN" H=(ylmf-pc) [69.10.61.61] AUTH command used when not advertised
|
||||
# failJSON: { "time": "2016-03-21T06:38:05", "match": true , "host": "49.212.207.15" }
|
||||
2016-03-21 06:38:05 [5718] no MAIL in SMTP connection from www3005.sakura.ne.jp [49.212.207.15]:28890 I=[172.89.0.6]:25 D=21s C=EHLO,STARTTLS
|
||||
# failJSON: { "time": "2016-03-21T06:57:36", "match": true , "host": "122.165.71.116" }
|
||||
2016-03-21 06:57:36 [5908] no MAIL in SMTP connection from [122.165.71.116]:2056 I=[172.89.0.6]:25 D=10s
|
||||
# failJSON: { "time": "2016-03-21T06:57:36", "match": true , "host": "122.165.71.116" }
|
||||
2016-03-21 06:57:36 [5908] no MAIL in SMTP connection from [122.165.71.116] I=[172.89.0.6]:25 D=10s
|
||||
# failJSON: { "time": "2016-03-21T04:07:49", "match": true , "host": "174.137.147.204" }
|
||||
2016-03-21 04:07:49 [25874] 1ahr79-0006jK-G9 SMTP connection from (voyeur.webair.com) [174.137.147.204]:44884 I=[172.89.0.6]:25 closed by DROP in ACL
|
||||
# failJSON: { "time": "2016-03-21T04:33:13", "match": true , "host": "206.214.71.53" }
|
||||
|
|
|
@ -159,6 +159,11 @@ class Transmitter(TransmitterBase):
|
|||
self.server = TestServer()
|
||||
super(Transmitter, self).setUp()
|
||||
|
||||
def testServerIsNotStarted(self):
|
||||
# so far isStarted only tested but not used otherwise
|
||||
# and here we don't really .start server
|
||||
self.assertFalse(self.server.isStarted())
|
||||
|
||||
def testStopServer(self):
|
||||
self.assertEqual(self.transm.proceed(["stop"]), (0, None))
|
||||
|
||||
|
@ -1014,6 +1019,7 @@ class LoggingTests(LogCaptureTestCase):
|
|||
server = TestServer()
|
||||
try:
|
||||
server.start(sock_name, pidfile_name, force=False)
|
||||
self.assertFalse(server.isStarted())
|
||||
self.assertLogged("Server already running")
|
||||
finally:
|
||||
server.quit()
|
||||
|
|
|
@ -54,8 +54,7 @@ if not CONFIG_DIR:
|
|||
else:
|
||||
CONFIG_DIR = '/etc/fail2ban'
|
||||
|
||||
# In not installed env (setup, test-cases) use fail2ban modules from main directory:
|
||||
if 1 or os.environ.get('PYTHONPATH', None) is None:
|
||||
# During the test cases (or setup) use fail2ban modules from main directory:
|
||||
os.putenv('PYTHONPATH', os.path.dirname(os.path.dirname(os.path.dirname(
|
||||
os.path.abspath(__file__)))))
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
||||
.TH FAIL2BAN-CLIENT "1" "March 2016" "fail2ban-client v0.9.4" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||
.TH FAIL2BAN-CLIENT "1" "July 2016" "fail2ban-client v0.10.0a1" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-client \- configure and control the server
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-client
|
||||
[\fI\,OPTIONS\/\fR] \fI\,<COMMAND>\/\fR
|
||||
[\fIOPTIONS\fR] \fI<COMMAND>\fR
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.9.4 reads log file that contains password failure report
|
||||
Fail2Ban v0.10.0a1 reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
|
@ -19,6 +19,13 @@ socket path
|
|||
\fB\-p\fR <FILE>
|
||||
pidfile path
|
||||
.TP
|
||||
\fB\-\-loglevel\fR <LEVEL>
|
||||
logging level
|
||||
.HP
|
||||
\fB\-\-logtarget\fR <FILE>|STDOUT|STDERR|SYSLOG
|
||||
.HP
|
||||
\fB\-\-syslogsocket\fR auto|<FILE>
|
||||
.TP
|
||||
\fB\-d\fR
|
||||
dump configuration. For debugging
|
||||
.TP
|
||||
|
@ -38,7 +45,13 @@ force execution of the server (remove socket file)
|
|||
start server in background (default)
|
||||
.TP
|
||||
\fB\-f\fR
|
||||
start server in foreground (note that the client forks once itself)
|
||||
start server in foreground
|
||||
.TP
|
||||
\fB\-\-async\fR
|
||||
start server in async mode (for internal usage only, don't read configuration)
|
||||
.TP
|
||||
\fB\-\-timeout\fR
|
||||
timeout to wait for the server (for internal usage only, don't read configuration)
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
display this help message
|
||||
|
@ -52,8 +65,12 @@ BASIC
|
|||
\fBstart\fR
|
||||
starts the server and the jails
|
||||
.TP
|
||||
\fBrestart\fR
|
||||
restarts the server
|
||||
.TP
|
||||
\fBreload\fR
|
||||
reloads the configuration
|
||||
reloads the configuration without
|
||||
restart
|
||||
.TP
|
||||
\fBreload <JAIL>\fR
|
||||
reloads the jail <JAIL>
|
||||
|
@ -69,6 +86,10 @@ server
|
|||
\fBping\fR
|
||||
tests if the server is alive
|
||||
.TP
|
||||
\fBecho\fR
|
||||
for internal usage, returns back
|
||||
and outputs a given string
|
||||
.TP
|
||||
\fBhelp\fR
|
||||
return this output
|
||||
.TP
|
||||
|
@ -227,8 +248,9 @@ for <JAIL>
|
|||
\fBset <JAIL> maxlines <LINES>\fR
|
||||
sets the number of <LINES> to
|
||||
buffer for regex search for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> addaction <ACT>[ <PYTHONFILE> <JSONKWARGS>]\fR
|
||||
.IP
|
||||
set <JAIL> addaction <ACT>[ <PYTHONFILE> <JSONKWARGS>]
|
||||
.IP
|
||||
adds a new action named <ACT> for
|
||||
<JAIL>. Optionally for a Python
|
||||
based action, a <PYTHONFILE> and
|
||||
|
@ -240,38 +262,45 @@ removes the action <ACT> from
|
|||
<JAIL>
|
||||
.IP
|
||||
COMMAND ACTION CONFIGURATION
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionstart <CMD>\fR
|
||||
.IP
|
||||
set <JAIL> action <ACT> actionstart <CMD>
|
||||
.IP
|
||||
sets the start command <CMD> of
|
||||
the action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionstop <CMD> sets the stop command <CMD> of the\fR
|
||||
.IP
|
||||
set <JAIL> action <ACT> actionstop <CMD> sets the stop command <CMD> of the
|
||||
.IP
|
||||
action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actioncheck <CMD>\fR
|
||||
.IP
|
||||
set <JAIL> action <ACT> actioncheck <CMD>
|
||||
.IP
|
||||
sets the check command <CMD> of
|
||||
the action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionban <CMD>\fR
|
||||
sets the ban command <CMD> of the
|
||||
action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionunban <CMD>\fR
|
||||
.IP
|
||||
set <JAIL> action <ACT> actionunban <CMD>
|
||||
.IP
|
||||
sets the unban command <CMD> of
|
||||
the action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> timeout <TIMEOUT>\fR
|
||||
.IP
|
||||
set <JAIL> action <ACT> timeout <TIMEOUT>
|
||||
.IP
|
||||
sets <TIMEOUT> as the command
|
||||
timeout in seconds for the action
|
||||
<ACT> for <JAIL>
|
||||
.IP
|
||||
GENERAL ACTION CONFIGURATION
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> <PROPERTY> <VALUE>\fR
|
||||
.IP
|
||||
set <JAIL> action <ACT> <PROPERTY> <VALUE>
|
||||
.IP
|
||||
sets the <VALUE> of <PROPERTY> for
|
||||
the action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> <METHOD>[ <JSONKWARGS>]\fR
|
||||
.IP
|
||||
set <JAIL> action <ACT> <METHOD>[ <JSONKWARGS>]
|
||||
.IP
|
||||
calls the <METHOD> with
|
||||
<JSONKWARGS> for the action <ACT>
|
||||
for <JAIL>
|
||||
|
@ -376,9 +405,6 @@ gets the value of <PROPERTY> for
|
|||
the action <ACT> for <JAIL>
|
||||
.SH FILES
|
||||
\fI/etc/fail2ban/*\fR
|
||||
.SH AUTHOR
|
||||
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||
.SH "REPORTING BUGS"
|
||||
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||
.SH COPYRIGHT
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
||||
.TH FAIL2BAN-REGEX "1" "March 2016" "fail2ban-regex 0.9.4" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||
.TH FAIL2BAN-REGEX "1" "July 2016" "fail2ban-regex 0.10.0a1" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-regex \- test Fail2ban "failregex" option
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-regex
|
||||
[\fI\,OPTIONS\/\fR] \fI\,<LOG> <REGEX> \/\fR[\fI\,IGNOREREGEX\/\fR]
|
||||
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
|
@ -16,7 +16,7 @@ string
|
|||
a string representing a log line
|
||||
.TP
|
||||
filename
|
||||
path to a log file (\fI\,/var/log/auth.log\/\fP)
|
||||
path to a log file (\fI/var/log/auth.log\fP)
|
||||
.TP
|
||||
"systemd\-journal"
|
||||
search systemd journal (systemd\-python required)
|
||||
|
@ -42,20 +42,23 @@ show program's version number and exit
|
|||
\fB\-h\fR, \fB\-\-help\fR
|
||||
show this help message and exit
|
||||
.TP
|
||||
\fB\-d\fR DATEPATTERN, \fB\-\-datepattern\fR=\fI\,DATEPATTERN\/\fR
|
||||
\fB\-d\fR DATEPATTERN, \fB\-\-datepattern\fR=\fIDATEPATTERN\fR
|
||||
set custom pattern used to match date/times
|
||||
.TP
|
||||
\fB\-e\fR ENCODING, \fB\-\-encoding\fR=\fI\,ENCODING\/\fR
|
||||
\fB\-e\fR ENCODING, \fB\-\-encoding\fR=\fIENCODING\fR
|
||||
File encoding. Default: system locale
|
||||
.TP
|
||||
\fB\-L\fR MAXLINES, \fB\-\-maxlines\fR=\fI\,MAXLINES\/\fR
|
||||
\fB\-r\fR, \fB\-\-raw\fR
|
||||
Raw hosts, don't resolve dns
|
||||
.TP
|
||||
\fB\-L\fR MAXLINES, \fB\-\-maxlines\fR=\fIMAXLINES\fR
|
||||
maxlines for multi\-line regex
|
||||
.TP
|
||||
\fB\-m\fR JOURNALMATCH, \fB\-\-journalmatch\fR=\fI\,JOURNALMATCH\/\fR
|
||||
\fB\-m\fR JOURNALMATCH, \fB\-\-journalmatch\fR=\fIJOURNALMATCH\fR
|
||||
journalctl style matches overriding filter file.
|
||||
"systemd\-journal" only
|
||||
.TP
|
||||
\fB\-l\fR LOG_LEVEL, \fB\-\-log\-level\fR=\fI\,LOG_LEVEL\/\fR
|
||||
\fB\-l\fR LOG_LEVEL, \fB\-\-log\-level\fR=\fILOG_LEVEL\fR
|
||||
Log level for the Fail2Ban logger to use
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
|
|
|
@ -1,24 +1,17 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
||||
.TH FAIL2BAN-SERVER "1" "March 2016" "fail2ban-server v0.9.4" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||
.TH FAIL2BAN-SERVER "1" "July 2016" "fail2ban-server v0.10.0a1" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-server \- start the server
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-server
|
||||
[\fI\,OPTIONS\/\fR]
|
||||
[\fIOPTIONS\fR]
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.9.4 reads log file that contains password failure report
|
||||
Fail2Ban v0.10.0a1 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
|
||||
fail2ban\-client instead. The default behaviour is to start the server
|
||||
in background.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-b\fR
|
||||
start in background
|
||||
.TP
|
||||
\fB\-f\fR
|
||||
start in foreground
|
||||
\fB\-c\fR <DIR>
|
||||
configuration directory
|
||||
.TP
|
||||
\fB\-s\fR <FILE>
|
||||
socket path
|
||||
|
@ -26,17 +19,45 @@ socket path
|
|||
\fB\-p\fR <FILE>
|
||||
pidfile path
|
||||
.TP
|
||||
\fB\-\-loglevel\fR <LEVEL>
|
||||
logging level
|
||||
.HP
|
||||
\fB\-\-logtarget\fR <FILE>|STDOUT|STDERR|SYSLOG
|
||||
.HP
|
||||
\fB\-\-syslogsocket\fR auto|<FILE>
|
||||
.TP
|
||||
\fB\-d\fR
|
||||
dump configuration. For debugging
|
||||
.TP
|
||||
\fB\-i\fR
|
||||
interactive mode
|
||||
.TP
|
||||
\fB\-v\fR
|
||||
increase verbosity
|
||||
.TP
|
||||
\fB\-q\fR
|
||||
decrease verbosity
|
||||
.TP
|
||||
\fB\-x\fR
|
||||
force execution of the server (remove socket file)
|
||||
.TP
|
||||
\fB\-b\fR
|
||||
start server in background (default)
|
||||
.TP
|
||||
\fB\-f\fR
|
||||
start server in foreground
|
||||
.TP
|
||||
\fB\-\-async\fR
|
||||
start server in async mode (for internal usage only, don't read configuration)
|
||||
.TP
|
||||
\fB\-\-timeout\fR
|
||||
timeout to wait for the server (for internal usage only, don't read configuration)
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
display this help message
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
print the version
|
||||
.SH AUTHOR
|
||||
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||
.SH "REPORTING BUGS"
|
||||
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||
.SH COPYRIGHT
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
||||
.TH FAIL2BAN-TESTCASES "1" "March 2016" "fail2ban-testcases 0.9.4" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||
.TH FAIL2BAN-TESTCASES "1" "July 2016" "fail2ban-testcases 0.10.0a1" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-testcases \- run Fail2Ban unit-tests
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-testcases
|
||||
[\fI\,OPTIONS\/\fR] [\fI\,regexps\/\fR]
|
||||
[\fIOPTIONS\fR] [\fIregexps\fR]
|
||||
.SH DESCRIPTION
|
||||
Script to run Fail2Ban tests battery
|
||||
.SH OPTIONS
|
||||
|
@ -15,12 +15,26 @@ show program's version number and exit
|
|||
\fB\-h\fR, \fB\-\-help\fR
|
||||
show this help message and exit
|
||||
.TP
|
||||
\fB\-l\fR LOG_LEVEL, \fB\-\-log\-level\fR=\fI\,LOG_LEVEL\/\fR
|
||||
\fB\-l\fR LOG_LEVEL, \fB\-\-log\-level\fR=\fILOG_LEVEL\fR
|
||||
Log level for the logger to use during running tests
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no\-network\fR
|
||||
Do not run tests that require the network
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-no\-gamin\fR
|
||||
Do not run tests that require the gamin
|
||||
.TP
|
||||
\fB\-m\fR, \fB\-\-memory\-db\fR
|
||||
Run database tests using memory instead of file
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-fast\fR
|
||||
Try to increase speed of the tests, decreasing of wait
|
||||
intervals, memory database
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-ignore\fR
|
||||
negate [regexps] filter to ignore tests matched
|
||||
specified regexps
|
||||
.TP
|
||||
\fB\-t\fR, \fB\-\-log\-traceback\fR
|
||||
Enrich log\-messages with compressed tracebacks
|
||||
.TP
|
||||
|
|
Loading…
Reference in New Issue