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`
|
added new parameter `__date_ambit`
|
||||||
* gentoo-initd fixed --pidfile bug: `--pidfile` is option of start-stop-daemon,
|
* gentoo-initd fixed --pidfile bug: `--pidfile` is option of start-stop-daemon,
|
||||||
not argument of fail2ban (see gh-1434)
|
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 Features:
|
||||||
* New Actions:
|
* New Actions:
|
||||||
- action.d/firewallcmd-rich-rules and action.d/firewallcmd-rich-logging (gh-1367)
|
- action.d/firewallcmd-rich-rules and action.d/firewallcmd-rich-logging (gh-1367)
|
||||||
|
|
||||||
- Enhancements:
|
- Enhancements:
|
||||||
* Extreme speedup of all sqlite database operations (gh-1436),
|
* Extreme speedup of all sqlite database operations (gh-1436),
|
||||||
by using of following sqlite options:
|
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
|
- (temp_store = MEMORY) temporary tables and indices are kept in memory
|
||||||
* journald journalmatch for pure-ftpd (gh-1362)
|
* journald journalmatch for pure-ftpd (gh-1362)
|
||||||
* Add additional regex filter for dovecot ldap authentication failures (gh-1370)
|
* 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
|
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/dshield.conf
|
||||||
config/action.d/dummy.conf
|
config/action.d/dummy.conf
|
||||||
config/action.d/firewallcmd-allports.conf
|
config/action.d/firewallcmd-allports.conf
|
||||||
|
config/action.d/firewallcmd-common.conf
|
||||||
config/action.d/firewallcmd-ipset.conf
|
config/action.d/firewallcmd-ipset.conf
|
||||||
config/action.d/firewallcmd-multiport.conf
|
config/action.d/firewallcmd-multiport.conf
|
||||||
config/action.d/firewallcmd-new.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/hostsdeny.conf
|
||||||
config/action.d/ipfilter.conf
|
config/action.d/ipfilter.conf
|
||||||
config/action.d/ipfw.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/iptables-xt_recent-echo.conf
|
||||||
config/action.d/mail-buffered.conf
|
config/action.d/mail-buffered.conf
|
||||||
config/action.d/mail.conf
|
config/action.d/mail.conf
|
||||||
|
config/action.d/mail-whois-common.conf
|
||||||
config/action.d/mail-whois.conf
|
config/action.d/mail-whois.conf
|
||||||
config/action.d/mail-whois-lines.conf
|
config/action.d/mail-whois-lines.conf
|
||||||
config/action.d/mynetwatchman.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-lines.conf
|
||||||
config/action.d/sendmail-whois-matches.conf
|
config/action.d/sendmail-whois-matches.conf
|
||||||
config/action.d/shorewall.conf
|
config/action.d/shorewall.conf
|
||||||
|
config/action.d/shorewall-ipset-proto6.conf
|
||||||
config/action.d/smtp.py
|
config/action.d/smtp.py
|
||||||
config/action.d/symbiosis-blacklist-allports.conf
|
config/action.d/symbiosis-blacklist-allports.conf
|
||||||
config/action.d/ufw.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-nohome.conf
|
||||||
config/filter.d/apache-noscript.conf
|
config/filter.d/apache-noscript.conf
|
||||||
config/filter.d/apache-overflows.conf
|
config/filter.d/apache-overflows.conf
|
||||||
|
config/filter.d/apache-pass.conf
|
||||||
config/filter.d/apache-shellshock.conf
|
config/filter.d/apache-shellshock.conf
|
||||||
config/filter.d/assp.conf
|
config/filter.d/assp.conf
|
||||||
config/filter.d/asterisk.conf
|
config/filter.d/asterisk.conf
|
||||||
|
@ -79,17 +85,18 @@ config/filter.d/cyrus-imap.conf
|
||||||
config/filter.d/directadmin.conf
|
config/filter.d/directadmin.conf
|
||||||
config/filter.d/dovecot.conf
|
config/filter.d/dovecot.conf
|
||||||
config/filter.d/dropbear.conf
|
config/filter.d/dropbear.conf
|
||||||
|
config/filter.d/drupal-auth.conf
|
||||||
config/filter.d/ejabberd-auth.conf
|
config/filter.d/ejabberd-auth.conf
|
||||||
config/filter.d/exim-common.conf
|
config/filter.d/exim-common.conf
|
||||||
config/filter.d/exim.conf
|
config/filter.d/exim.conf
|
||||||
config/filter.d/exim-spam.conf
|
config/filter.d/exim-spam.conf
|
||||||
config/filter.d/freeswitch.conf
|
config/filter.d/freeswitch.conf
|
||||||
|
config/filter.d/froxlor-auth.conf
|
||||||
config/filter.d/groupoffice.conf
|
config/filter.d/groupoffice.conf
|
||||||
config/filter.d/gssftpd.conf
|
config/filter.d/gssftpd.conf
|
||||||
config/filter.d/guacamole.conf
|
config/filter.d/guacamole.conf
|
||||||
config/filter.d/haproxy-http-auth.conf
|
config/filter.d/haproxy-http-auth.conf
|
||||||
config/filter.d/horde.conf
|
config/filter.d/horde.conf
|
||||||
config/filter.d/ignorecommands
|
|
||||||
config/filter.d/ignorecommands/apache-fakegooglebot
|
config/filter.d/ignorecommands/apache-fakegooglebot
|
||||||
config/filter.d/kerio.conf
|
config/filter.d/kerio.conf
|
||||||
config/filter.d/lighttpd-auth.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/selinux-ssh.conf
|
||||||
config/filter.d/sendmail-auth.conf
|
config/filter.d/sendmail-auth.conf
|
||||||
config/filter.d/sendmail-reject.conf
|
config/filter.d/sendmail-reject.conf
|
||||||
config/filter.d/sendmail-spam.conf
|
|
||||||
config/filter.d/sieve.conf
|
config/filter.d/sieve.conf
|
||||||
config/filter.d/sogo-auth.conf
|
config/filter.d/sogo-auth.conf
|
||||||
config/filter.d/solid-pop3d.conf
|
config/filter.d/solid-pop3d.conf
|
||||||
|
@ -148,7 +154,6 @@ config/paths-osx.conf
|
||||||
CONTRIBUTING.md
|
CONTRIBUTING.md
|
||||||
COPYING
|
COPYING
|
||||||
DEVELOP
|
DEVELOP
|
||||||
doc/run-rootless.txt
|
|
||||||
fail2ban-2to3
|
fail2ban-2to3
|
||||||
fail2ban/client/actionreader.py
|
fail2ban/client/actionreader.py
|
||||||
fail2ban/client/beautifier.py
|
fail2ban/client/beautifier.py
|
||||||
|
@ -185,7 +190,6 @@ fail2ban/server/filterpyinotify.py
|
||||||
fail2ban/server/filtersystemd.py
|
fail2ban/server/filtersystemd.py
|
||||||
fail2ban/server/__init__.py
|
fail2ban/server/__init__.py
|
||||||
fail2ban/server/ipdns.py
|
fail2ban/server/ipdns.py
|
||||||
fail2ban/server/iso8601.py
|
|
||||||
fail2ban/server/jail.py
|
fail2ban/server/jail.py
|
||||||
fail2ban/server/jails.py
|
fail2ban/server/jails.py
|
||||||
fail2ban/server/jailthread.py
|
fail2ban/server/jailthread.py
|
||||||
|
@ -203,21 +207,19 @@ fail2ban/tests/action_d/test_smtp.py
|
||||||
fail2ban/tests/actionstestcase.py
|
fail2ban/tests/actionstestcase.py
|
||||||
fail2ban/tests/actiontestcase.py
|
fail2ban/tests/actiontestcase.py
|
||||||
fail2ban/tests/banmanagertestcase.py
|
fail2ban/tests/banmanagertestcase.py
|
||||||
fail2ban/tests/clientreadertestcase.py
|
|
||||||
fail2ban/tests/clientbeautifiertestcase.py
|
fail2ban/tests/clientbeautifiertestcase.py
|
||||||
|
fail2ban/tests/clientreadertestcase.py
|
||||||
fail2ban/tests/config/action.d/brokenaction.conf
|
fail2ban/tests/config/action.d/brokenaction.conf
|
||||||
fail2ban/tests/config/fail2ban.conf
|
fail2ban/tests/config/fail2ban.conf
|
||||||
fail2ban/tests/config/filter.d/simple.conf
|
fail2ban/tests/config/filter.d/simple.conf
|
||||||
fail2ban/tests/config/filter.d/test.conf
|
fail2ban/tests/config/filter.d/test.conf
|
||||||
fail2ban/tests/config/filter.d/test.local
|
fail2ban/tests/config/filter.d/test.local
|
||||||
|
fail2ban/tests/config/filter.d/zzz-generic-example.conf
|
||||||
fail2ban/tests/config/jail.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/databasetestcase.py
|
||||||
fail2ban/tests/datedetectortestcase.py
|
fail2ban/tests/datedetectortestcase.py
|
||||||
fail2ban/tests/dummyjail.py
|
fail2ban/tests/dummyjail.py
|
||||||
|
fail2ban/tests/fail2banclienttestcase.py
|
||||||
fail2ban/tests/fail2banregextestcase.py
|
fail2ban/tests/fail2banregextestcase.py
|
||||||
fail2ban/tests/failmanagertestcase.py
|
fail2ban/tests/failmanagertestcase.py
|
||||||
fail2ban/tests/files/action.d/action_checkainfo.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/3proxy
|
||||||
fail2ban/tests/files/logs/apache-auth
|
fail2ban/tests/files/logs/apache-auth
|
||||||
fail2ban/tests/files/logs/apache-badbots
|
fail2ban/tests/files/logs/apache-badbots
|
||||||
fail2ban/tests/files/logs/apache-botscripts
|
|
||||||
fail2ban/tests/files/logs/apache-botsearch
|
fail2ban/tests/files/logs/apache-botsearch
|
||||||
fail2ban/tests/files/logs/apache-fakegooglebot
|
fail2ban/tests/files/logs/apache-fakegooglebot
|
||||||
fail2ban/tests/files/logs/apache-modsecurity
|
fail2ban/tests/files/logs/apache-modsecurity
|
||||||
fail2ban/tests/files/logs/apache-nohome
|
fail2ban/tests/files/logs/apache-nohome
|
||||||
fail2ban/tests/files/logs/apache-noscript
|
fail2ban/tests/files/logs/apache-noscript
|
||||||
fail2ban/tests/files/logs/apache-overflows
|
fail2ban/tests/files/logs/apache-overflows
|
||||||
|
fail2ban/tests/files/logs/apache-pass
|
||||||
fail2ban/tests/files/logs/apache-shellshock
|
fail2ban/tests/files/logs/apache-shellshock
|
||||||
fail2ban/tests/files/logs/assp
|
fail2ban/tests/files/logs/assp
|
||||||
fail2ban/tests/files/logs/asterisk
|
fail2ban/tests/files/logs/asterisk
|
||||||
|
@ -270,10 +272,12 @@ fail2ban/tests/files/logs/cyrus-imap
|
||||||
fail2ban/tests/files/logs/directadmin
|
fail2ban/tests/files/logs/directadmin
|
||||||
fail2ban/tests/files/logs/dovecot
|
fail2ban/tests/files/logs/dovecot
|
||||||
fail2ban/tests/files/logs/dropbear
|
fail2ban/tests/files/logs/dropbear
|
||||||
|
fail2ban/tests/files/logs/drupal-auth
|
||||||
fail2ban/tests/files/logs/ejabberd-auth
|
fail2ban/tests/files/logs/ejabberd-auth
|
||||||
fail2ban/tests/files/logs/exim
|
fail2ban/tests/files/logs/exim
|
||||||
fail2ban/tests/files/logs/exim-spam
|
fail2ban/tests/files/logs/exim-spam
|
||||||
fail2ban/tests/files/logs/freeswitch
|
fail2ban/tests/files/logs/freeswitch
|
||||||
|
fail2ban/tests/files/logs/froxlor-auth
|
||||||
fail2ban/tests/files/logs/groupoffice
|
fail2ban/tests/files/logs/groupoffice
|
||||||
fail2ban/tests/files/logs/gssftpd
|
fail2ban/tests/files/logs/gssftpd
|
||||||
fail2ban/tests/files/logs/guacamole
|
fail2ban/tests/files/logs/guacamole
|
||||||
|
@ -309,7 +313,6 @@ fail2ban/tests/files/logs/screensharingd
|
||||||
fail2ban/tests/files/logs/selinux-ssh
|
fail2ban/tests/files/logs/selinux-ssh
|
||||||
fail2ban/tests/files/logs/sendmail-auth
|
fail2ban/tests/files/logs/sendmail-auth
|
||||||
fail2ban/tests/files/logs/sendmail-reject
|
fail2ban/tests/files/logs/sendmail-reject
|
||||||
fail2ban/tests/files/logs/sendmail-spam
|
|
||||||
fail2ban/tests/files/logs/sieve
|
fail2ban/tests/files/logs/sieve
|
||||||
fail2ban/tests/files/logs/sogo-auth
|
fail2ban/tests/files/logs/sogo-auth
|
||||||
fail2ban/tests/files/logs/solid-pop3d
|
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/webmin-auth
|
||||||
fail2ban/tests/files/logs/wuftpd
|
fail2ban/tests/files/logs/wuftpd
|
||||||
fail2ban/tests/files/logs/xinetd-fail
|
fail2ban/tests/files/logs/xinetd-fail
|
||||||
|
fail2ban/tests/files/logs/zzz-generic-example
|
||||||
fail2ban/tests/files/testcase01.log
|
fail2ban/tests/files/testcase01.log
|
||||||
fail2ban/tests/files/testcase02.log
|
fail2ban/tests/files/testcase02.log
|
||||||
fail2ban/tests/files/testcase03.log
|
fail2ban/tests/files/testcase03.log
|
||||||
|
@ -356,6 +360,8 @@ files/gentoo-confd
|
||||||
files/gentoo-initd
|
files/gentoo-initd
|
||||||
files/ipmasq-ZZZzzz_fail2ban.rul
|
files/ipmasq-ZZZzzz_fail2ban.rul
|
||||||
files/logwatch/fail2ban
|
files/logwatch/fail2ban
|
||||||
|
files/logwatch/fail2ban-0.8.log
|
||||||
|
files/logwatch/fail2ban-0.9.log
|
||||||
files/macosx-initd
|
files/macosx-initd
|
||||||
files/monit/fail2ban
|
files/monit/fail2ban
|
||||||
files/nagios/check_fail2ban
|
files/nagios/check_fail2ban
|
||||||
|
@ -373,6 +379,8 @@ man/fail2ban-regex.1
|
||||||
man/fail2ban-regex.h2m
|
man/fail2ban-regex.h2m
|
||||||
man/fail2ban-server.1
|
man/fail2ban-server.1
|
||||||
man/fail2ban-server.h2m
|
man/fail2ban-server.h2m
|
||||||
|
man/fail2ban-testcases.1
|
||||||
|
man/fail2ban-testcases.h2m
|
||||||
man/generate-man
|
man/generate-man
|
||||||
man/jail.conf.5
|
man/jail.conf.5
|
||||||
README.md
|
README.md
|
||||||
|
|
2
RELEASE
2
RELEASE
|
@ -190,7 +190,7 @@ Post Release
|
||||||
|
|
||||||
Add the following to the top of the ChangeLog::
|
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:
|
- Fixes:
|
||||||
|
|
|
@ -122,7 +122,7 @@ if verbosity > 1: # pragma: no cover
|
||||||
if verbosity > 3:
|
if verbosity > 3:
|
||||||
fmt = ' | %(module)15.15s-%(levelno)-2d: %(funcName)-20.20s |' + fmt
|
fmt = ' | %(module)15.15s-%(levelno)-2d: %(funcName)-20.20s |' + fmt
|
||||||
if verbosity > 2:
|
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:
|
else:
|
||||||
fmt = ' %(asctime)-15s %(thread)X %(levelname)-5.5s' + fmt
|
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 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 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 "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 =
|
ignoreregex =
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ after = exim-common.local
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
host_info = H=([\w.-]+ )?(\(\S+\) )?\[<HOST>\](:\d+)? (I=\[\S+\]:\d+ )?(U=\S+ )?(P=e?smtp )?
|
host_info = (?:H=([\w.-]+ )?(?:\(\S+\) )?)?\[<HOST>\](?::\d+)? (?:I=\[\S+\](:\d+)? )?(?:U=\S+ )?(?:P=e?smtp )?
|
||||||
pid = ( \[\d+\])?
|
pid = (?: \[\d+\])?
|
||||||
|
|
||||||
# DEV Notes:
|
# DEV Notes:
|
||||||
# From exim source code: ./src/receive.c:add_host_info_for_log
|
# From exim source code: ./src/receive.c:add_host_info_for_log
|
||||||
|
|
|
@ -14,13 +14,13 @@ before = exim-common.conf
|
||||||
[Definition]
|
[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*$
|
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 \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 %(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 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 call from \S+ %(host_info)sdropped: 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 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>\]\:\d+ I=\[\S*\]\:\d+ D=\d+s(| C=\S*)\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>\]\:\d+ I=\[\S*\]\:\d+ closed by DROP in ACL\s*$
|
^%(pid)s \S+ SMTP connection from (?:\S* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$
|
||||||
|
|
||||||
ignoreregex =
|
ignoreregex =
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ from ..version import version
|
||||||
from .csocket import CSocket
|
from .csocket import CSocket
|
||||||
from .beautifier import Beautifier
|
from .beautifier import Beautifier
|
||||||
from .fail2bancmdline import Fail2banCmdLine, ServerExecutionException, ExitException, \
|
from .fail2bancmdline import Fail2banCmdLine, ServerExecutionException, ExitException, \
|
||||||
logSys, PRODUCTION, exit, output
|
logSys, exit, output
|
||||||
|
|
||||||
PROMPT = "fail2ban> "
|
PROMPT = "fail2ban> "
|
||||||
|
|
||||||
|
@ -227,11 +227,11 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
||||||
# prepare: read config, check configuration is valid, etc.:
|
# prepare: read config, check configuration is valid, etc.:
|
||||||
if phase is not None:
|
if phase is not None:
|
||||||
phase['start'] = True
|
phase['start'] = True
|
||||||
logSys.debug('-- client phase %s', phase)
|
logSys.debug(' client phase %s', phase)
|
||||||
stream = self.__prepareStartServer()
|
stream = self.__prepareStartServer()
|
||||||
if phase is not None:
|
if phase is not None:
|
||||||
phase['ready'] = phase['start'] = (True if stream else False)
|
phase['ready'] = phase['start'] = (True if stream else False)
|
||||||
logSys.debug('-- client phase %s', phase)
|
logSys.debug(' client phase %s', phase)
|
||||||
if not stream:
|
if not stream:
|
||||||
return False
|
return False
|
||||||
# configure server with config stream:
|
# configure server with config stream:
|
||||||
|
@ -361,19 +361,16 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
||||||
|
|
||||||
# Interactive mode
|
# Interactive mode
|
||||||
if self._conf.get("interactive", False):
|
if self._conf.get("interactive", False):
|
||||||
# no readline in test:
|
try:
|
||||||
if PRODUCTION: # pragma: no cover
|
import readline
|
||||||
try:
|
except ImportError:
|
||||||
import readline
|
raise ServerExecutionException("Readline not available")
|
||||||
except ImportError:
|
|
||||||
raise ServerExecutionException("Readline not available")
|
|
||||||
try:
|
try:
|
||||||
ret = True
|
ret = True
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
ret = self.__processCommand(args)
|
ret = self.__processCommand(args)
|
||||||
if ret:
|
if ret:
|
||||||
if PRODUCTION: # pragma: no cover
|
readline.parse_and_bind("tab: complete")
|
||||||
readline.parse_and_bind("tab: complete")
|
|
||||||
self.dispInteractive()
|
self.dispInteractive()
|
||||||
while True:
|
while True:
|
||||||
cmd = input_command()
|
cmd = input_command()
|
||||||
|
@ -411,11 +408,9 @@ class Fail2banClient(Fail2banCmdLine, Thread):
|
||||||
signal.signal(s, sh)
|
signal.signal(s, sh)
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Wonderful visual :)
|
|
||||||
#
|
|
||||||
|
|
||||||
class _VisualWait:
|
class _VisualWait:
|
||||||
|
"""Small progress indication (as "wonderful visual") during waiting process
|
||||||
|
"""
|
||||||
pos = 0
|
pos = 0
|
||||||
delta = 1
|
delta = 1
|
||||||
def __init__(self, maxpos=10):
|
def __init__(self, maxpos=10):
|
||||||
|
@ -427,6 +422,8 @@ class _VisualWait:
|
||||||
sys.stdout.write('\r'+(' '*(35+self.maxpos))+'\r')
|
sys.stdout.write('\r'+(' '*(35+self.maxpos))+'\r')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
def heartbeat(self):
|
def heartbeat(self):
|
||||||
|
"""Show or step for progress indicator
|
||||||
|
"""
|
||||||
if not self.pos:
|
if not self.pos:
|
||||||
sys.stdout.write("\nINFO [#" + (' '*self.maxpos) + "] Waiting on the server...\r\x1b[8C")
|
sys.stdout.write("\nINFO [#" + (' '*self.maxpos) + "] Waiting on the server...\r\x1b[8C")
|
||||||
self.pos += self.delta
|
self.pos += self.delta
|
||||||
|
@ -441,6 +438,8 @@ class _VisualWait:
|
||||||
elif self.pos < 2:
|
elif self.pos < 2:
|
||||||
self.delta = 1
|
self.delta = 1
|
||||||
class _NotVisualWait:
|
class _NotVisualWait:
|
||||||
|
"""Mockup for invisible progress indication (not verbose)
|
||||||
|
"""
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
@ -449,6 +448,8 @@ class _NotVisualWait:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def VisualWait(verbose, *args, **kwargs):
|
def VisualWait(verbose, *args, **kwargs):
|
||||||
|
"""Wonderful visual progress indication (if verbose)
|
||||||
|
"""
|
||||||
return _VisualWait(*args, **kwargs) if verbose > 1 else _NotVisualWait()
|
return _VisualWait(*args, **kwargs) if verbose > 1 else _NotVisualWait()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ PRODUCTION = True
|
||||||
|
|
||||||
MAX_WAITTIME = 30
|
MAX_WAITTIME = 30
|
||||||
|
|
||||||
|
|
||||||
class Fail2banCmdLine():
|
class Fail2banCmdLine():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -83,9 +84,6 @@ class Fail2banCmdLine():
|
||||||
output("Copyright (c) 2004-2008 Cyril Jaquier, 2008- Fail2Ban Contributors")
|
output("Copyright (c) 2004-2008 Cyril Jaquier, 2008- Fail2Ban Contributors")
|
||||||
output("Copyright of modifications held by their respective authors.")
|
output("Copyright of modifications held by their respective authors.")
|
||||||
output("Licensed under the GNU General Public License v2 (GPL).")
|
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):
|
def dispUsage(self):
|
||||||
""" Prints Fail2Ban command line options and exits
|
""" Prints Fail2Ban command line options and exits
|
||||||
|
@ -187,7 +185,7 @@ class Fail2banCmdLine():
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
return ret
|
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
|
if initial and PRODUCTION: # pragma: no cover - can't test
|
||||||
verbose = self._conf["verbose"]
|
verbose = self._conf["verbose"]
|
||||||
|
@ -259,14 +257,26 @@ class Fail2banCmdLine():
|
||||||
output(c)
|
output(c)
|
||||||
return True
|
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
|
@staticmethod
|
||||||
def exit(code=0): # pragma: no cover - can't test
|
def _exit(code=0):
|
||||||
logSys.debug("Exit with code %s", code)
|
if hasattr(os, '_exit') and os._exit:
|
||||||
if os._exit:
|
|
||||||
os._exit(code)
|
os._exit(code)
|
||||||
else:
|
else:
|
||||||
sys.exit(code)
|
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:
|
# global exit handler:
|
||||||
exit = Fail2banCmdLine.exit
|
exit = Fail2banCmdLine.exit
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ class Fail2banServer(Fail2banCmdLine):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def startServerDirect(conf, daemon=True):
|
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
|
from ..server.server import Server
|
||||||
server = None
|
server = None
|
||||||
try:
|
try:
|
||||||
|
@ -79,7 +79,7 @@ class Fail2banServer(Fail2banCmdLine):
|
||||||
frk = not conf["async"] and PRODUCTION
|
frk = not conf["async"] and PRODUCTION
|
||||||
if frk: # pragma: no cover
|
if frk: # pragma: no cover
|
||||||
pid = os.fork()
|
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:
|
if pid == 0:
|
||||||
args = list()
|
args = list()
|
||||||
args.append(SERVER)
|
args.append(SERVER)
|
||||||
|
|
|
@ -27,6 +27,9 @@ __license__ = "GPL"
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
def output(s):
|
def output(s):
|
||||||
|
"""Default output handler for printing protocol.
|
||||||
|
Used to ease mocking in the test cases.
|
||||||
|
"""
|
||||||
print(s)
|
print(s)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -88,6 +88,11 @@ class Server:
|
||||||
logSys.debug("Caught signal %d. Flushing logs" % signum)
|
logSys.debug("Caught signal %d. Flushing logs" % signum)
|
||||||
self.flushLogs()
|
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={}):
|
def start(self, sock, pidfile, force=False, observer=True, conf={}):
|
||||||
# First set the mask to only allow access to owner
|
# First set the mask to only allow access to owner
|
||||||
os.umask(0077)
|
os.umask(0077)
|
||||||
|
@ -121,9 +126,10 @@ class Server:
|
||||||
|
|
||||||
# Install signal handlers
|
# Install signal handlers
|
||||||
if _thread_name() == '_MainThread':
|
if _thread_name() == '_MainThread':
|
||||||
for s in (signal.SIGTERM, signal.SIGINT, signal.SIGUSR1):
|
for s in (signal.SIGTERM, signal.SIGINT):
|
||||||
self.__prev_signals[s] = signal.getsignal(s)
|
self._rebindSignal(s, self.__sigTERMhandler)
|
||||||
signal.signal(s, self.__sigTERMhandler if s != signal.SIGUSR1 else self.__sigUSR1handler)
|
self._rebindSignal(signal.SIGUSR1, self.__sigUSR1handler)
|
||||||
|
|
||||||
# Ensure unhandled exceptions are logged
|
# Ensure unhandled exceptions are logged
|
||||||
sys.excepthook = excepthook
|
sys.excepthook = excepthook
|
||||||
|
|
||||||
|
@ -389,7 +395,7 @@ class Server:
|
||||||
return self.__jails[name].getBanTimeExtra(opt)
|
return self.__jails[name].getBanTimeExtra(opt)
|
||||||
|
|
||||||
def isStarted(self):
|
def isStarted(self):
|
||||||
self.__asyncServer.isActive()
|
return self.__asyncServer is not None and self.__asyncServer.isActive()
|
||||||
|
|
||||||
def isAlive(self, jailnum=None):
|
def isAlive(self, jailnum=None):
|
||||||
if jailnum is not None and len(self.__jails) != jailnum:
|
if jailnum is not None and len(self.__jails) != jailnum:
|
||||||
|
@ -437,7 +443,7 @@ class Server:
|
||||||
getLogger("fail2ban").setLevel(getattr(logging, value))
|
getLogger("fail2ban").setLevel(getattr(logging, value))
|
||||||
self.__logLevel = value
|
self.__logLevel = value
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ValueError("Invalid log level")
|
raise ValueError("Invalid log level %r" % value)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the logging level.
|
# Get the logging level.
|
||||||
|
@ -512,14 +518,14 @@ class Server:
|
||||||
# Is known to be thrown after logging was shutdown once
|
# Is known to be thrown after logging was shutdown once
|
||||||
# with older Pythons -- seems to be safe to ignore there
|
# with older Pythons -- seems to be safe to ignore there
|
||||||
# At least it was still failing on 2.6.2-0ubuntu1 (jaunty)
|
# At least it was still failing on 2.6.2-0ubuntu1 (jaunty)
|
||||||
if (2,6,3) <= sys.version_info < (3,) or \
|
if (2, 6, 3) <= sys.version_info < (3,) or \
|
||||||
(3,2) <= sys.version_info:
|
(3, 2) <= sys.version_info:
|
||||||
raise
|
raise
|
||||||
# tell the handler to use this format
|
# tell the handler to use this format
|
||||||
hdlr.setFormatter(formatter)
|
hdlr.setFormatter(formatter)
|
||||||
logger.addHandler(hdlr)
|
logger.addHandler(hdlr)
|
||||||
# Does not display this message at startup.
|
# 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("Start Fail2ban v%s", version.version)
|
||||||
logSys.info(
|
logSys.info(
|
||||||
"Changed logging target to %s for Fail2ban v%s"
|
"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
|
# 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
|
# child process, and this makes sure that it is effect even if the parent
|
||||||
# terminates quickly.
|
# terminates quickly.
|
||||||
for s in (signal.SIGHUP,):
|
self._rebindSignal(signal.SIGHUP, signal.SIG_IGN)
|
||||||
self.__prev_signals[s] = signal.getsignal(s)
|
|
||||||
signal.signal(s, signal.SIG_IGN)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Fork a child process so the parent can exit. This will return control
|
# Fork a child process so the parent can exit. This will return control
|
||||||
|
|
|
@ -31,25 +31,30 @@ import time
|
||||||
import signal
|
import signal
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from os.path import join as pjoin, isdir, isfile, exists, dirname
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
|
|
||||||
from ..client import fail2banclient, fail2banserver, fail2bancmdline
|
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 ..client.fail2banserver import Fail2banServer, exec_command_line as _exec_server
|
||||||
from .. import protocol
|
from .. import protocol
|
||||||
from ..server import server
|
from ..server import server
|
||||||
from ..server.utils import Utils
|
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_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"
|
CLIENT = "fail2ban-client"
|
||||||
SERVER = "fail2ban-server"
|
SERVER = "fail2ban-server"
|
||||||
BIN = os.path.dirname(Fail2banServer.getServerPath())
|
BIN = dirname(Fail2banServer.getServerPath())
|
||||||
|
|
||||||
MAX_WAITTIME = 30 if not unittest.F2B.fast else 5
|
MAX_WAITTIME = 30 if not unittest.F2B.fast else 5
|
||||||
|
|
||||||
|
@ -57,7 +62,7 @@ MAX_WAITTIME = 30 if not unittest.F2B.fast else 5
|
||||||
# Several wrappers and settings for proper testing:
|
# Several wrappers and settings for proper testing:
|
||||||
#
|
#
|
||||||
|
|
||||||
fail2bancmdline.MAX_WAITTIME = MAX_WAITTIME-1
|
fail2bancmdline.MAX_WAITTIME = MAX_WAITTIME - 1
|
||||||
|
|
||||||
fail2bancmdline.logSys = \
|
fail2bancmdline.logSys = \
|
||||||
fail2banclient.logSys = \
|
fail2banclient.logSys = \
|
||||||
|
@ -72,63 +77,68 @@ fail2banclient.output = \
|
||||||
fail2banserver.output = \
|
fail2banserver.output = \
|
||||||
protocol.output = _test_output
|
protocol.output = _test_output
|
||||||
|
|
||||||
def _test_exit(code=0):
|
|
||||||
logSys.debug("Exit with code %s", code)
|
#
|
||||||
if code == 0:
|
# Mocking .exit so we could test its correct operation.
|
||||||
raise ExitException()
|
# Two custom exceptions will be assessed to be raised in the tests
|
||||||
else:
|
#
|
||||||
raise FailExitException()
|
|
||||||
fail2bancmdline.exit = \
|
class ExitException(fail2bancmdline.ExitException):
|
||||||
fail2banclient.exit = \
|
"""Exception upon a normal exit"""
|
||||||
fail2banserver.exit = _test_exit
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FailExitException(fail2bancmdline.ExitException):
|
||||||
|
"""Exception upon abnormal exit"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
INTERACT = []
|
INTERACT = []
|
||||||
|
|
||||||
|
|
||||||
def _test_input_command(*args):
|
def _test_input_command(*args):
|
||||||
if len(INTERACT):
|
if len(INTERACT):
|
||||||
#logSys.debug('--- interact command: %r', INTERACT[0])
|
#logSys.debug('--- interact command: %r', INTERACT[0])
|
||||||
return INTERACT.pop(0)
|
return INTERACT.pop(0)
|
||||||
else:
|
else:
|
||||||
return "exit"
|
return "exit"
|
||||||
|
|
||||||
fail2banclient.input_command = _test_input_command
|
fail2banclient.input_command = _test_input_command
|
||||||
|
|
||||||
# prevents change logging params, log capturing, etc:
|
# prevents change logging params, log capturing, etc:
|
||||||
fail2bancmdline.PRODUCTION = \
|
fail2bancmdline.PRODUCTION = \
|
||||||
fail2banclient.PRODUCTION = \
|
|
||||||
fail2banserver.PRODUCTION = False
|
fail2banserver.PRODUCTION = False
|
||||||
|
|
||||||
|
|
||||||
class ExitException(fail2bancmdline.ExitException):
|
def _out_file(fn):
|
||||||
pass
|
"""Helper which outputs content of the file at HEAVYDEBUG loglevels"""
|
||||||
class FailExitException(fail2bancmdline.ExitException):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _out_file(fn): # pragma: no cover
|
|
||||||
logSys.debug('---- ' + fn + ' ----')
|
logSys.debug('---- ' + fn + ' ----')
|
||||||
for line in fileinput.input(fn):
|
for line in fileinput.input(fn):
|
||||||
line = line.rstrip('\n')
|
line = line.rstrip('\n')
|
||||||
logSys.debug(line)
|
logSys.debug(line)
|
||||||
logSys.debug('-'*30)
|
logSys.debug('-'*30)
|
||||||
|
|
||||||
|
|
||||||
def _start_params(tmp, use_stock=False, logtarget="/dev/null"):
|
def _start_params(tmp, use_stock=False, logtarget="/dev/null"):
|
||||||
cfg = tmp+"/config"
|
cfg = pjoin(tmp, "config")
|
||||||
if use_stock and STOCK:
|
if use_stock and STOCK:
|
||||||
# copy config (sub-directories as alias):
|
# copy config (sub-directories as alias):
|
||||||
def ig_dirs(dir, files):
|
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)
|
shutil.copytree(STOCK_CONF_DIR, cfg, ignore=ig_dirs)
|
||||||
os.symlink(STOCK_CONF_DIR+"/action.d", cfg+"/action.d")
|
os.symlink(pjoin(STOCK_CONF_DIR, "action.d"), pjoin(cfg, "action.d"))
|
||||||
os.symlink(STOCK_CONF_DIR+"/filter.d", cfg+"/filter.d")
|
os.symlink(pjoin(STOCK_CONF_DIR, "filter.d"), pjoin(cfg, "filter.d"))
|
||||||
# replace fail2ban params (database with memory):
|
# replace fail2ban params (database with memory):
|
||||||
r = re.compile(r'^dbfile\s*=')
|
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')
|
line = line.rstrip('\n')
|
||||||
if r.match(line):
|
if r.match(line):
|
||||||
line = "dbfile = :memory:"
|
line = "dbfile = :memory:"
|
||||||
print(line)
|
print(line)
|
||||||
# replace jail params (polling as backend to be fast in initialize):
|
# replace jail params (polling as backend to be fast in initialize):
|
||||||
r = re.compile(r'^backend\s*=')
|
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')
|
line = line.rstrip('\n')
|
||||||
if r.match(line):
|
if r.match(line):
|
||||||
line = "backend = polling"
|
line = "backend = polling"
|
||||||
|
@ -136,77 +146,83 @@ def _start_params(tmp, use_stock=False, logtarget="/dev/null"):
|
||||||
else:
|
else:
|
||||||
# just empty config directory without anything (only fail2ban.conf/jail.conf):
|
# just empty config directory without anything (only fail2ban.conf/jail.conf):
|
||||||
os.mkdir(cfg)
|
os.mkdir(cfg)
|
||||||
f = open(cfg+"/fail2ban.conf", "w")
|
f = open(pjoin(cfg, "fail2ban.conf"), "w")
|
||||||
f.write('\n'.join((
|
f.write('\n'.join((
|
||||||
"[Definition]",
|
"[Definition]",
|
||||||
"loglevel = INFO",
|
"loglevel = INFO",
|
||||||
"logtarget = " + logtarget,
|
"logtarget = " + logtarget,
|
||||||
"syslogsocket = auto",
|
"syslogsocket = auto",
|
||||||
"socket = "+tmp+"/f2b.sock",
|
"socket = " + pjoin(tmp, "f2b.sock"),
|
||||||
"pidfile = "+tmp+"/f2b.pid",
|
"pidfile = " + pjoin(tmp, "f2b.pid"),
|
||||||
"backend = polling",
|
"backend = polling",
|
||||||
"dbfile = :memory:",
|
"dbfile = :memory:",
|
||||||
"dbpurgeage = 1d",
|
"dbpurgeage = 1d",
|
||||||
"",
|
"",
|
||||||
)))
|
)))
|
||||||
f.close()
|
f.close()
|
||||||
f = open(cfg+"/jail.conf", "w")
|
f = open(pjoin(cfg, "jail.conf"), "w")
|
||||||
f.write('\n'.join((
|
f.write('\n'.join((
|
||||||
"[INCLUDES]", "",
|
"[INCLUDES]", "",
|
||||||
"[DEFAULT]", "",
|
"[DEFAULT]", "",
|
||||||
"",
|
"",
|
||||||
)))
|
)))
|
||||||
f.close()
|
f.close()
|
||||||
if logSys.level < logging.DEBUG: # if HEAVYDEBUG
|
if logSys.level < logging.DEBUG: # if HEAVYDEBUG
|
||||||
_out_file(cfg+"/fail2ban.conf")
|
_out_file(pjoin(cfg, "fail2ban.conf"))
|
||||||
_out_file(cfg+"/jail.conf")
|
_out_file(pjoin(cfg, "jail.conf"))
|
||||||
# parameters (sock/pid and config, increase verbosity, set log, etc.):
|
# parameters (sock/pid and config, increase verbosity, set log, etc.):
|
||||||
return ("-c", cfg, "-s", tmp+"/f2b.sock", "-p", tmp+"/f2b.pid",
|
return (
|
||||||
"-vv", "--logtarget", logtarget, "--loglevel", "DEBUG", "--syslogsocket", "auto",
|
"-c", cfg, "-s", pjoin(tmp, "f2b.sock"), "-p", pjoin(tmp, "f2b.pid"),
|
||||||
"--timeout", str(fail2bancmdline.MAX_WAITTIME),
|
"-vv", "--logtarget", logtarget, "--loglevel", "DEBUG", "--syslogsocket", "auto",
|
||||||
|
"--timeout", str(fail2bancmdline.MAX_WAITTIME),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _kill_srv(pidfile): # pragma: no cover
|
|
||||||
def _pid_exists(pid):
|
def _kill_srv(pidfile):
|
||||||
try:
|
logSys.debug("cleanup: %r", (pidfile, isdir(pidfile)))
|
||||||
os.kill(pid, 0)
|
if isdir(pidfile):
|
||||||
return True
|
|
||||||
except OSError:
|
|
||||||
return False
|
|
||||||
logSys.debug("-- cleanup: %r", (pidfile, os.path.isdir(pidfile)))
|
|
||||||
if os.path.isdir(pidfile):
|
|
||||||
piddir = pidfile
|
piddir = pidfile
|
||||||
pidfile = piddir + "/f2b.pid"
|
pidfile = pjoin(piddir, "f2b.pid")
|
||||||
if not os.path.isfile(pidfile):
|
if not isfile(pidfile): # pragma: no cover
|
||||||
pidfile = piddir + "/fail2ban.pid"
|
pidfile = pjoin(piddir, "fail2ban.pid")
|
||||||
if not os.path.isfile(pidfile):
|
|
||||||
logSys.debug("--- cleanup: no pidfile for %r", piddir)
|
if not isfile(pidfile):
|
||||||
|
logSys.debug("cleanup: no pidfile for %r", piddir)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
f = pid = None
|
f = pid = None
|
||||||
try:
|
try:
|
||||||
logSys.debug("--- cleanup pidfile: %r", pidfile)
|
logSys.debug("cleanup pidfile: %r", pidfile)
|
||||||
f = open(pidfile)
|
f = open(pidfile)
|
||||||
pid = f.read().split()[1]
|
pid = f.read()
|
||||||
|
pid = re.match(r'\S+', pid).group()
|
||||||
pid = int(pid)
|
pid = int(pid)
|
||||||
logSys.debug("--- cleanup pid: %r", pid)
|
except Exception as e: # pragma: no cover
|
||||||
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:
|
|
||||||
logSys.debug(e)
|
logSys.debug(e)
|
||||||
|
return False
|
||||||
finally:
|
finally:
|
||||||
if f is not None:
|
if f is not None:
|
||||||
f.close()
|
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
|
return True
|
||||||
|
|
||||||
|
|
||||||
def with_kill_srv(f):
|
def with_kill_srv(f):
|
||||||
"""Helper to decorate tests which receive in the last argument tmpdir to pass to kill_srv
|
"""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):
|
class Fail2banClientServerBase(LogCaptureTestCase):
|
||||||
|
|
||||||
|
_orig_exit = Fail2banCmdLine._exit
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
LogCaptureTestCase.setUp(self)
|
LogCaptureTestCase.setUp(self)
|
||||||
|
Fail2banCmdLine._exit = staticmethod(self._test_exit)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Call after every test case."""
|
"""Call after every test case."""
|
||||||
|
Fail2banCmdLine._exit = self._orig_exit
|
||||||
LogCaptureTestCase.tearDown(self)
|
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):
|
def _wait_for_srv(self, tmp, ready=True, startparams=None):
|
||||||
try:
|
try:
|
||||||
sock = tmp+"/f2b.sock"
|
sock = pjoin(tmp, "f2b.sock")
|
||||||
# wait for server (socket):
|
# 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:
|
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:
|
if ready:
|
||||||
# wait for communication with worker ready:
|
# wait for communication with worker ready:
|
||||||
ret = Utils.wait_for(lambda: "Server ready" in self.getLog(), MAX_WAITTIME)
|
ret = Utils.wait_for(lambda: "Server ready" in self.getLog(), MAX_WAITTIME)
|
||||||
if not ret:
|
if not ret:
|
||||||
raise Exception('Unexpected: Server ready was not found.\nStart failed: %r' % (startparams,))
|
raise Exception(
|
||||||
except: # pragma: no cover
|
'Unexpected: Server ready was not found.\nStart failed: %r'
|
||||||
log = tmp+"/f2b.log"
|
% (startparams,)
|
||||||
if os.path.isfile(log):
|
)
|
||||||
|
except: # pragma: no cover
|
||||||
|
log = pjoin(tmp, "f2b.log")
|
||||||
|
if isfile(log):
|
||||||
_out_file(log)
|
_out_file(log)
|
||||||
else:
|
else:
|
||||||
logSys.debug("No log file %s to examine details of error", log)
|
logSys.debug("No log file %s to examine details of error", log)
|
||||||
raise
|
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)))
|
# Common tests
|
||||||
self.assertTrue(os.path.isfile(os.path.join(os.path.join(BIN), SERVER)))
|
#
|
||||||
|
def _testStartForeground(self, tmp, startparams, phase):
|
||||||
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):
|
|
||||||
# start and wait to end (foreground):
|
# start and wait to end (foreground):
|
||||||
logSys.debug("-- start of test worker")
|
logSys.debug("start of test worker")
|
||||||
phase['start'] = True
|
phase['start'] = True
|
||||||
self.assertRaises(fail2bancmdline.ExitException, _exec_client,
|
self.execSuccess(("-f",) + startparams, "start")
|
||||||
(CLIENT, "-f") + startparams + ("start",))
|
|
||||||
# end :
|
# end :
|
||||||
phase['end'] = True
|
phase['end'] = True
|
||||||
logSys.debug("-- end of test worker")
|
logSys.debug("end of test worker")
|
||||||
|
|
||||||
@with_tmpdir
|
@with_tmpdir
|
||||||
def testClientStartForeground(self, tmp):
|
def testStartForeground(self, tmp):
|
||||||
|
# intended to be ran only in subclasses
|
||||||
th = None
|
th = None
|
||||||
|
phase = dict()
|
||||||
try:
|
try:
|
||||||
# started directly here, so prevent overwrite test cases logger with "INHERITED"
|
# started directly here, so prevent overwrite test cases logger with "INHERITED"
|
||||||
startparams = _start_params(tmp, logtarget="INHERITED")
|
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||||
# because foreground block execution - start it in thread:
|
# because foreground block execution - start it in thread:
|
||||||
phase = dict()
|
th = Thread(
|
||||||
th = Thread(name="_TestCaseWorker",
|
name="_TestCaseWorker",
|
||||||
target=Fail2banClientTest._testClientStartForeground, args=(self, tmp, startparams, phase))
|
target=self._testStartForeground,
|
||||||
|
args=(tmp, startparams, phase)
|
||||||
|
)
|
||||||
th.daemon = True
|
th.daemon = True
|
||||||
th.start()
|
th.start()
|
||||||
try:
|
try:
|
||||||
|
@ -415,25 +327,149 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
||||||
self._wait_for_srv(tmp, True, startparams=startparams)
|
self._wait_for_srv(tmp, True, startparams=startparams)
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
# several commands to server:
|
# several commands to server:
|
||||||
self.assertRaises(ExitException, _exec_client,
|
self.execSuccess(startparams, "ping")
|
||||||
(CLIENT,) + startparams + ("ping",))
|
self.execFailed(startparams, "~~unknown~cmd~failed~~")
|
||||||
self.assertRaises(FailExitException, _exec_client,
|
self.execSuccess(startparams, "echo", "TEST-ECHO")
|
||||||
(CLIENT,) + startparams + ("~~unknown~cmd~failed~~",))
|
|
||||||
self.assertRaises(ExitException, _exec_client,
|
|
||||||
(CLIENT,) + startparams + ("echo", "TEST-ECHO",))
|
|
||||||
finally:
|
finally:
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
# stop:
|
# stop:
|
||||||
self.assertRaises(ExitException, _exec_client,
|
self.execSuccess(startparams, "stop")
|
||||||
(CLIENT,) + startparams + ("stop",))
|
|
||||||
# wait for end:
|
# wait for end:
|
||||||
Utils.wait_for(lambda: phase.get('end', None) is not None, MAX_WAITTIME)
|
Utils.wait_for(lambda: phase.get('end', None) is not None, MAX_WAITTIME)
|
||||||
self.assertTrue(phase.get('end', None))
|
self.assertTrue(phase.get('end', None))
|
||||||
self.assertLogged("Shutdown successful", "Exiting Fail2ban")
|
self.assertLogged("Shutdown successful", "Exiting Fail2ban")
|
||||||
finally:
|
finally:
|
||||||
_kill_srv(tmp)
|
|
||||||
if th:
|
if th:
|
||||||
th.join()
|
# 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_tmpdir
|
||||||
@with_kill_srv
|
@with_kill_srv
|
||||||
|
@ -442,34 +478,33 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
||||||
startparams = _start_params(tmp, logtarget="INHERITED")
|
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||||
|
|
||||||
## wrong config directory
|
## wrong config directory
|
||||||
self.assertRaises(FailExitException, _exec_client,
|
self.execFailed((),
|
||||||
(CLIENT, "--async", "-c", tmp+"/miss", "start",))
|
"--async", "-c", pjoin(tmp, "miss"), "start")
|
||||||
self.assertLogged("Base configuration directory " + tmp+"/miss" + " does not exist")
|
self.assertLogged("Base configuration directory " + pjoin(tmp, "miss") + " does not exist")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
|
|
||||||
## wrong socket
|
## wrong socket
|
||||||
self.assertRaises(FailExitException, _exec_client,
|
self.execFailed((),
|
||||||
(CLIENT, "--async", "-c", tmp+"/config", "-s", tmp+"/miss/f2b.sock", "start",))
|
"--async", "-c", pjoin(tmp, "config"), "-s", pjoin(tmp, "miss/f2b.sock"), "start")
|
||||||
self.assertLogged("There is no directory " + tmp+"/miss" + " to contain the socket file")
|
self.assertLogged("There is no directory " + pjoin(tmp, "miss") + " to contain the socket file")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
|
|
||||||
## not running
|
## not running
|
||||||
self.assertRaises(FailExitException, _exec_client,
|
self.execFailed((),
|
||||||
(CLIENT, "-c", tmp+"/config", "-s", tmp+"/f2b.sock", "reload",))
|
"-c", pjoin(tmp, "config"), "-s", pjoin(tmp, "f2b.sock"), "reload")
|
||||||
self.assertLogged("Could not find server")
|
self.assertLogged("Could not find server")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
|
|
||||||
## already exists:
|
## already exists:
|
||||||
open(tmp+"/f2b.sock", 'a').close()
|
open(pjoin(tmp, "f2b.sock"), 'a').close()
|
||||||
self.assertRaises(FailExitException, _exec_client,
|
self.execFailed((),
|
||||||
(CLIENT, "--async", "-c", tmp+"/config", "-s", tmp+"/f2b.sock", "start",))
|
"--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.assertLogged("Fail2ban seems to be in unexpected state (not running but the socket exists)")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
os.remove(tmp+"/f2b.sock")
|
os.remove(pjoin(tmp, "f2b.sock"))
|
||||||
|
|
||||||
## wrong option:
|
## wrong option:
|
||||||
self.assertRaises(FailExitException, _exec_client,
|
self.execFailed((), "-s")
|
||||||
(CLIENT, "-s",))
|
|
||||||
self.assertLogged("Usage: ")
|
self.assertLogged("Usage: ")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
|
|
||||||
|
@ -487,9 +522,16 @@ class Fail2banClientTest(Fail2banClientServerBase):
|
||||||
|
|
||||||
class Fail2banServerTest(Fail2banClientServerBase):
|
class Fail2banServerTest(Fail2banClientServerBase):
|
||||||
|
|
||||||
def testServerUsage(self):
|
def execSuccess(self, startparams, *args):
|
||||||
self.assertRaises(ExitException, _exec_server,
|
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("Usage: " + SERVER)
|
||||||
self.assertLogged("Report bugs to ")
|
self.assertLogged("Report bugs to ")
|
||||||
|
|
||||||
|
@ -497,9 +539,9 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
||||||
@with_kill_srv
|
@with_kill_srv
|
||||||
def testServerStartBackground(self, tmp):
|
def testServerStartBackground(self, tmp):
|
||||||
# to prevent fork of test-cases process, start server in background via command:
|
# 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):
|
# 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)
|
logSys.debug('Start %s ...', cmd)
|
||||||
cmd = cmd + startparams + ("-b",)
|
cmd = cmd + startparams + ("-b",)
|
||||||
ret = Utils.executeCmd(cmd, timeout=MAX_WAITTIME, shell=False, output=True)
|
ret = Utils.executeCmd(cmd, timeout=MAX_WAITTIME, shell=False, output=True)
|
||||||
|
@ -509,68 +551,15 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
||||||
self.assertLogged("Server ready")
|
self.assertLogged("Server ready")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
try:
|
try:
|
||||||
self.assertRaises(ExitException, _exec_server,
|
self.execSuccess(startparams, "echo", "TEST-ECHO")
|
||||||
(SERVER,) + startparams + ("echo", "TEST-ECHO",))
|
self.execFailed(startparams, "~~unknown~cmd~failed~~")
|
||||||
self.assertRaises(FailExitException, _exec_server,
|
|
||||||
(SERVER,) + startparams + ("~~unknown~cmd~failed~~",))
|
|
||||||
finally:
|
finally:
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
# stop:
|
# stop:
|
||||||
self.assertRaises(ExitException, _exec_server,
|
self.execSuccess(startparams, "stop")
|
||||||
(SERVER,) + startparams + ("stop",))
|
|
||||||
self.assertLogged("Shutdown successful")
|
self.assertLogged("Shutdown successful")
|
||||||
self.assertLogged("Exit with code 0")
|
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_tmpdir
|
||||||
@with_kill_srv
|
@with_kill_srv
|
||||||
def testServerFailStart(self, tmp):
|
def testServerFailStart(self, tmp):
|
||||||
|
@ -578,21 +567,48 @@ class Fail2banServerTest(Fail2banClientServerBase):
|
||||||
startparams = _start_params(tmp, logtarget="INHERITED")
|
startparams = _start_params(tmp, logtarget="INHERITED")
|
||||||
|
|
||||||
## wrong config directory
|
## wrong config directory
|
||||||
self.assertRaises(FailExitException, _exec_server,
|
self.execFailed((),
|
||||||
(SERVER, "-c", tmp+"/miss",))
|
"-c", pjoin(tmp, "miss"))
|
||||||
self.assertLogged("Base configuration directory " + tmp+"/miss" + " does not exist")
|
self.assertLogged("Base configuration directory " + pjoin(tmp, "miss") + " does not exist")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
|
|
||||||
## wrong socket
|
## wrong socket
|
||||||
self.assertRaises(FailExitException, _exec_server,
|
self.execFailed((),
|
||||||
(SERVER, "-c", tmp+"/config", "-x", "-s", tmp+"/miss/f2b.sock",))
|
"-c", pjoin(tmp, "config"), "-x", "-s", pjoin(tmp, "miss/f2b.sock"))
|
||||||
self.assertLogged("There is no directory " + tmp+"/miss" + " to contain the socket file")
|
self.assertLogged("There is no directory " + pjoin(tmp, "miss") + " to contain the socket file")
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
|
|
||||||
## already exists:
|
## already exists:
|
||||||
open(tmp+"/f2b.sock", 'a').close()
|
open(pjoin(tmp, "f2b.sock"), 'a').close()
|
||||||
self.assertRaises(FailExitException, _exec_server,
|
self.execFailed((),
|
||||||
(SERVER, "-c", tmp+"/config", "-s", tmp+"/f2b.sock",))
|
"-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.assertLogged("Fail2ban seems to be in unexpected state (not running but the socket exists)")
|
||||||
self.pruneLog()
|
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'.
|
[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" }
|
# 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'.
|
[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
|
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" }
|
# 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
|
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" }
|
# 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
|
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" }
|
# 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
|
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" }
|
# 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
|
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" }
|
# failJSON: { "time": "2016-03-21T04:33:13", "match": true , "host": "206.214.71.53" }
|
||||||
|
|
|
@ -159,6 +159,11 @@ class Transmitter(TransmitterBase):
|
||||||
self.server = TestServer()
|
self.server = TestServer()
|
||||||
super(Transmitter, self).setUp()
|
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):
|
def testStopServer(self):
|
||||||
self.assertEqual(self.transm.proceed(["stop"]), (0, None))
|
self.assertEqual(self.transm.proceed(["stop"]), (0, None))
|
||||||
|
|
||||||
|
@ -1014,6 +1019,7 @@ class LoggingTests(LogCaptureTestCase):
|
||||||
server = TestServer()
|
server = TestServer()
|
||||||
try:
|
try:
|
||||||
server.start(sock_name, pidfile_name, force=False)
|
server.start(sock_name, pidfile_name, force=False)
|
||||||
|
self.assertFalse(server.isStarted())
|
||||||
self.assertLogged("Server already running")
|
self.assertLogged("Server already running")
|
||||||
finally:
|
finally:
|
||||||
server.quit()
|
server.quit()
|
||||||
|
|
|
@ -54,10 +54,9 @@ if not CONFIG_DIR:
|
||||||
else:
|
else:
|
||||||
CONFIG_DIR = '/etc/fail2ban'
|
CONFIG_DIR = '/etc/fail2ban'
|
||||||
|
|
||||||
# In not installed env (setup, test-cases) use fail2ban modules from main directory:
|
# During the test cases (or setup) use fail2ban modules from main directory:
|
||||||
if 1 or os.environ.get('PYTHONPATH', None) is None:
|
os.putenv('PYTHONPATH', os.path.dirname(os.path.dirname(os.path.dirname(
|
||||||
os.putenv('PYTHONPATH', os.path.dirname(os.path.dirname(os.path.dirname(
|
os.path.abspath(__file__)))))
|
||||||
os.path.abspath(__file__)))))
|
|
||||||
|
|
||||||
class F2B(optparse.Values):
|
class F2B(optparse.Values):
|
||||||
def __init__(self, opts={}):
|
def __init__(self, opts={}):
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||||
.TH FAIL2BAN-CLIENT "1" "March 2016" "fail2ban-client v0.9.4" "User Commands"
|
.TH FAIL2BAN-CLIENT "1" "July 2016" "fail2ban-client v0.10.0a1" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-client \- configure and control the server
|
fail2ban-client \- configure and control the server
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-client
|
.B fail2ban-client
|
||||||
[\fI\,OPTIONS\/\fR] \fI\,<COMMAND>\/\fR
|
[\fIOPTIONS\fR] \fI<COMMAND>\fR
|
||||||
.SH DESCRIPTION
|
.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.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
|
@ -19,6 +19,13 @@ socket path
|
||||||
\fB\-p\fR <FILE>
|
\fB\-p\fR <FILE>
|
||||||
pidfile path
|
pidfile path
|
||||||
.TP
|
.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
|
\fB\-d\fR
|
||||||
dump configuration. For debugging
|
dump configuration. For debugging
|
||||||
.TP
|
.TP
|
||||||
|
@ -38,7 +45,13 @@ force execution of the server (remove socket file)
|
||||||
start server in background (default)
|
start server in background (default)
|
||||||
.TP
|
.TP
|
||||||
\fB\-f\fR
|
\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
|
.TP
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
display this help message
|
display this help message
|
||||||
|
@ -52,8 +65,12 @@ BASIC
|
||||||
\fBstart\fR
|
\fBstart\fR
|
||||||
starts the server and the jails
|
starts the server and the jails
|
||||||
.TP
|
.TP
|
||||||
|
\fBrestart\fR
|
||||||
|
restarts the server
|
||||||
|
.TP
|
||||||
\fBreload\fR
|
\fBreload\fR
|
||||||
reloads the configuration
|
reloads the configuration without
|
||||||
|
restart
|
||||||
.TP
|
.TP
|
||||||
\fBreload <JAIL>\fR
|
\fBreload <JAIL>\fR
|
||||||
reloads the jail <JAIL>
|
reloads the jail <JAIL>
|
||||||
|
@ -69,6 +86,10 @@ server
|
||||||
\fBping\fR
|
\fBping\fR
|
||||||
tests if the server is alive
|
tests if the server is alive
|
||||||
.TP
|
.TP
|
||||||
|
\fBecho\fR
|
||||||
|
for internal usage, returns back
|
||||||
|
and outputs a given string
|
||||||
|
.TP
|
||||||
\fBhelp\fR
|
\fBhelp\fR
|
||||||
return this output
|
return this output
|
||||||
.TP
|
.TP
|
||||||
|
@ -227,8 +248,9 @@ for <JAIL>
|
||||||
\fBset <JAIL> maxlines <LINES>\fR
|
\fBset <JAIL> maxlines <LINES>\fR
|
||||||
sets the number of <LINES> to
|
sets the number of <LINES> to
|
||||||
buffer for regex search for <JAIL>
|
buffer for regex search for <JAIL>
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> addaction <ACT>[ <PYTHONFILE> <JSONKWARGS>]\fR
|
set <JAIL> addaction <ACT>[ <PYTHONFILE> <JSONKWARGS>]
|
||||||
|
.IP
|
||||||
adds a new action named <ACT> for
|
adds a new action named <ACT> for
|
||||||
<JAIL>. Optionally for a Python
|
<JAIL>. Optionally for a Python
|
||||||
based action, a <PYTHONFILE> and
|
based action, a <PYTHONFILE> and
|
||||||
|
@ -240,38 +262,45 @@ removes the action <ACT> from
|
||||||
<JAIL>
|
<JAIL>
|
||||||
.IP
|
.IP
|
||||||
COMMAND ACTION CONFIGURATION
|
COMMAND ACTION CONFIGURATION
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> action <ACT> actionstart <CMD>\fR
|
set <JAIL> action <ACT> actionstart <CMD>
|
||||||
|
.IP
|
||||||
sets the start command <CMD> of
|
sets the start command <CMD> of
|
||||||
the action <ACT> for <JAIL>
|
the action <ACT> for <JAIL>
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> action <ACT> actionstop <CMD> sets the stop command <CMD> of the\fR
|
set <JAIL> action <ACT> actionstop <CMD> sets the stop command <CMD> of the
|
||||||
|
.IP
|
||||||
action <ACT> for <JAIL>
|
action <ACT> for <JAIL>
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> action <ACT> actioncheck <CMD>\fR
|
set <JAIL> action <ACT> actioncheck <CMD>
|
||||||
|
.IP
|
||||||
sets the check command <CMD> of
|
sets the check command <CMD> of
|
||||||
the action <ACT> for <JAIL>
|
the action <ACT> for <JAIL>
|
||||||
.TP
|
.TP
|
||||||
\fBset <JAIL> action <ACT> actionban <CMD>\fR
|
\fBset <JAIL> action <ACT> actionban <CMD>\fR
|
||||||
sets the ban command <CMD> of the
|
sets the ban command <CMD> of the
|
||||||
action <ACT> for <JAIL>
|
action <ACT> for <JAIL>
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> action <ACT> actionunban <CMD>\fR
|
set <JAIL> action <ACT> actionunban <CMD>
|
||||||
|
.IP
|
||||||
sets the unban command <CMD> of
|
sets the unban command <CMD> of
|
||||||
the action <ACT> for <JAIL>
|
the action <ACT> for <JAIL>
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> action <ACT> timeout <TIMEOUT>\fR
|
set <JAIL> action <ACT> timeout <TIMEOUT>
|
||||||
|
.IP
|
||||||
sets <TIMEOUT> as the command
|
sets <TIMEOUT> as the command
|
||||||
timeout in seconds for the action
|
timeout in seconds for the action
|
||||||
<ACT> for <JAIL>
|
<ACT> for <JAIL>
|
||||||
.IP
|
.IP
|
||||||
GENERAL ACTION CONFIGURATION
|
GENERAL ACTION CONFIGURATION
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> action <ACT> <PROPERTY> <VALUE>\fR
|
set <JAIL> action <ACT> <PROPERTY> <VALUE>
|
||||||
|
.IP
|
||||||
sets the <VALUE> of <PROPERTY> for
|
sets the <VALUE> of <PROPERTY> for
|
||||||
the action <ACT> for <JAIL>
|
the action <ACT> for <JAIL>
|
||||||
.TP
|
.IP
|
||||||
\fBset <JAIL> action <ACT> <METHOD>[ <JSONKWARGS>]\fR
|
set <JAIL> action <ACT> <METHOD>[ <JSONKWARGS>]
|
||||||
|
.IP
|
||||||
calls the <METHOD> with
|
calls the <METHOD> with
|
||||||
<JSONKWARGS> for the action <ACT>
|
<JSONKWARGS> for the action <ACT>
|
||||||
for <JAIL>
|
for <JAIL>
|
||||||
|
@ -376,9 +405,6 @@ gets the value of <PROPERTY> for
|
||||||
the action <ACT> for <JAIL>
|
the action <ACT> for <JAIL>
|
||||||
.SH FILES
|
.SH FILES
|
||||||
\fI/etc/fail2ban/*\fR
|
\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"
|
.SH "REPORTING BUGS"
|
||||||
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||||
.TH FAIL2BAN-REGEX "1" "March 2016" "fail2ban-regex 0.9.4" "User Commands"
|
.TH FAIL2BAN-REGEX "1" "July 2016" "fail2ban-regex 0.10.0a1" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-regex \- test Fail2ban "failregex" option
|
fail2ban-regex \- test Fail2ban "failregex" option
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-regex
|
.B fail2ban-regex
|
||||||
[\fI\,OPTIONS\/\fR] \fI\,<LOG> <REGEX> \/\fR[\fI\,IGNOREREGEX\/\fR]
|
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Fail2Ban reads log file that contains password failure report
|
Fail2Ban reads log file that contains password failure report
|
||||||
and bans the corresponding IP addresses using firewall rules.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
|
@ -16,7 +16,7 @@ string
|
||||||
a string representing a log line
|
a string representing a log line
|
||||||
.TP
|
.TP
|
||||||
filename
|
filename
|
||||||
path to a log file (\fI\,/var/log/auth.log\/\fP)
|
path to a log file (\fI/var/log/auth.log\fP)
|
||||||
.TP
|
.TP
|
||||||
"systemd\-journal"
|
"systemd\-journal"
|
||||||
search systemd journal (systemd\-python required)
|
search systemd journal (systemd\-python required)
|
||||||
|
@ -42,20 +42,23 @@ show program's version number and exit
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
show this help message and exit
|
show this help message and exit
|
||||||
.TP
|
.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
|
set custom pattern used to match date/times
|
||||||
.TP
|
.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
|
File encoding. Default: system locale
|
||||||
.TP
|
.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
|
maxlines for multi\-line regex
|
||||||
.TP
|
.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.
|
journalctl style matches overriding filter file.
|
||||||
"systemd\-journal" only
|
"systemd\-journal" only
|
||||||
.TP
|
.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
|
Log level for the Fail2Ban logger to use
|
||||||
.TP
|
.TP
|
||||||
\fB\-v\fR, \fB\-\-verbose\fR
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
|
|
@ -1,24 +1,17 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||||
.TH FAIL2BAN-SERVER "1" "March 2016" "fail2ban-server v0.9.4" "User Commands"
|
.TH FAIL2BAN-SERVER "1" "July 2016" "fail2ban-server v0.10.0a1" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-server \- start the server
|
fail2ban-server \- start the server
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-server
|
.B fail2ban-server
|
||||||
[\fI\,OPTIONS\/\fR]
|
[\fIOPTIONS\fR]
|
||||||
.SH DESCRIPTION
|
.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.
|
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
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
\fB\-b\fR
|
\fB\-c\fR <DIR>
|
||||||
start in background
|
configuration directory
|
||||||
.TP
|
|
||||||
\fB\-f\fR
|
|
||||||
start in foreground
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR <FILE>
|
\fB\-s\fR <FILE>
|
||||||
socket path
|
socket path
|
||||||
|
@ -26,17 +19,45 @@ socket path
|
||||||
\fB\-p\fR <FILE>
|
\fB\-p\fR <FILE>
|
||||||
pidfile path
|
pidfile path
|
||||||
.TP
|
.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
|
\fB\-x\fR
|
||||||
force execution of the server (remove socket file)
|
force execution of the server (remove socket file)
|
||||||
.TP
|
.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
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
display this help message
|
display this help message
|
||||||
.TP
|
.TP
|
||||||
\fB\-V\fR, \fB\-\-version\fR
|
\fB\-V\fR, \fB\-\-version\fR
|
||||||
print the version
|
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"
|
.SH "REPORTING BUGS"
|
||||||
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
|
||||||
.TH FAIL2BAN-TESTCASES "1" "March 2016" "fail2ban-testcases 0.9.4" "User Commands"
|
.TH FAIL2BAN-TESTCASES "1" "July 2016" "fail2ban-testcases 0.10.0a1" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-testcases \- run Fail2Ban unit-tests
|
fail2ban-testcases \- run Fail2Ban unit-tests
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-testcases
|
.B fail2ban-testcases
|
||||||
[\fI\,OPTIONS\/\fR] [\fI\,regexps\/\fR]
|
[\fIOPTIONS\fR] [\fIregexps\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Script to run Fail2Ban tests battery
|
Script to run Fail2Ban tests battery
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
|
@ -15,12 +15,26 @@ show program's version number and exit
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
show this help message and exit
|
show this help message and exit
|
||||||
.TP
|
.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
|
Log level for the logger to use during running tests
|
||||||
.TP
|
.TP
|
||||||
\fB\-n\fR, \fB\-\-no\-network\fR
|
\fB\-n\fR, \fB\-\-no\-network\fR
|
||||||
Do not run tests that require the network
|
Do not run tests that require the network
|
||||||
.TP
|
.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
|
\fB\-t\fR, \fB\-\-log\-traceback\fR
|
||||||
Enrich log\-messages with compressed tracebacks
|
Enrich log\-messages with compressed tracebacks
|
||||||
.TP
|
.TP
|
||||||
|
|
Loading…
Reference in New Issue