mirror of https://github.com/fail2ban/fail2ban
What aught to be a bugfix release delayed into a featured release 0.9.1
ver. 0.9.1 (2014/10/29) - better, faster, stronger ---------- - Refactoring (IMPORTANT -- Please review your setup and configuration): * iptables-common.conf replaced iptables-blocktype.conf (iptables-blocktype.local should still be read) and now also provides defaults for the chain, port, protocol and name tags - Fixes: * start of file2ban aborted (on slow hosts, systemd considers the server has been timed out and kills him), see gh-824 * UTF-8 fixes in pure-ftp thanks to Johannes Weberhofer. Closes gh-806. * systemd backend error on bad utf-8 in python3 * badips.py action error when logging HTTP error raised with badips request * fail2ban-regex failed to work in python3 due to space/tab mix * recidive regex samples incorrect log level * journalmatch for recidive incorrect PRIORITY * loglevel couldn't be changed in fail2ban.conf * Handle case when no sqlite library is available for persistent database * Only reban once per IP from database on fail2ban restart * Nginx filter to support missing server_name. Closes gh-676 * fail2ban-regex assertion error caused by miscount missed lines with multiline regex * Fix actions failing to execute for Python 3.4.0. Workaround for http://bugs.python.org/issue21207 * Database now returns persistent bans on restart (bantime < 0) * Recursive action tags now fully processed. Fixes issue with bsd-ipfw action * Fixed TypeError with "ipfailures" and "ipjailfailures" action tags. Thanks Serg G. Brester * Correct times for non-timezone date times formats during DST * Pass a copy of, not original, aInfo into actions to avoid side-effects * Per-distribution paths to the exim's main log * Ignored IPs are no longer banned when being restored from persistent database * Manually unbanned IPs are now removed from persistent database, such they wont be banned again when Fail2Ban is restarted * Pass "bantime" parameter to the actions in default jail's action definition(s) * filters.d/sieve.conf - fixed typo in _daemon. Thanks Jisoo Park * cyrus-imap -- also catch also failed logins via secured (imaps/pop3s). Regression was introduced while strengthening failregex in 0.8.11 (bd175f) Debian bug #755173 * postfix-sasl - added journalmatch. Thanks Luc Maisonobe * postfix* - match with a new daemon string (postfix/submission/smtpd). Closes gh-804 . Thanks Paul Traina * apache - added filter for AH01630 client denied by server configuration. - New features: - New filters: - monit Thanks Jason H Martin - directadmin Thanks niorg - apache-shellshock Thanks Eugene Hopkinson (SlowRiot) - New actions: - symbiosis-blacklist-allports for Bytemark symbiosis firewall - fail2ban-client can fetch the running server version - Added Cloudflare API action - Enhancements * Start performance of fail2ban-client (and tests) increased, start time and cpu usage rapidly reduced. Introduced a shared storage logic, to bypass reading lots of config files (see gh-824). Thanks to Joost Molenaar for good catch (reported gh-820). * Fail2ban-regex - add print-all-matched option. Closes gh-652 * Suppress fail2ban-client warnings for non-critical config options * Match non "Bye Bye" disconnect messages for sshd locked account regex * courier-smtp filter: - match lines with user names - match lines containing "535 Authentication failed" attempts * Add <chain> tag to iptables-ipsets * Realign fail2ban log output with white space to improve readability. Does not affect SYSLOG output * Log unhandled exceptions * cyrus-imap: catch "user not found" attempts * Add support for Portsentry -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAlRO9sEACgkQjRFFY3XAJMi/5wCgktRXWZyyjT/vBWPqYGbpjT0x 29UAnAxPZaUBBuzenJ5ROMNA7Xbrmzoq =Fd3J -----END PGP SIGNATURE----- Merge tag '0.9.1' into debian What aught to be a bugfix release delayed into a featured release 0.9.1 ver. 0.9.1 (2014/10/29) - better, faster, stronger ---------- - Refactoring (IMPORTANT -- Please review your setup and configuration): * iptables-common.conf replaced iptables-blocktype.conf (iptables-blocktype.local should still be read) and now also provides defaults for the chain, port, protocol and name tags - Fixes: * start of file2ban aborted (on slow hosts, systemd considers the server has been timed out and kills him), see gh-824 * UTF-8 fixes in pure-ftp thanks to Johannes Weberhofer. Closes gh-806. * systemd backend error on bad utf-8 in python3 * badips.py action error when logging HTTP error raised with badips request * fail2ban-regex failed to work in python3 due to space/tab mix * recidive regex samples incorrect log level * journalmatch for recidive incorrect PRIORITY * loglevel couldn't be changed in fail2ban.conf * Handle case when no sqlite library is available for persistent database * Only reban once per IP from database on fail2ban restart * Nginx filter to support missing server_name. Closes gh-676 * fail2ban-regex assertion error caused by miscount missed lines with multiline regex * Fix actions failing to execute for Python 3.4.0. Workaround for http://bugs.python.org/issue21207 * Database now returns persistent bans on restart (bantime < 0) * Recursive action tags now fully processed. Fixes issue with bsd-ipfw action * Fixed TypeError with "ipfailures" and "ipjailfailures" action tags. Thanks Serg G. Brester * Correct times for non-timezone date times formats during DST * Pass a copy of, not original, aInfo into actions to avoid side-effects * Per-distribution paths to the exim's main log * Ignored IPs are no longer banned when being restored from persistent database * Manually unbanned IPs are now removed from persistent database, such they wont be banned again when Fail2Ban is restarted * Pass "bantime" parameter to the actions in default jail's action definition(s) * filters.d/sieve.conf - fixed typo in _daemon. Thanks Jisoo Park * cyrus-imap -- also catch also failed logins via secured (imaps/pop3s). Regression was introduced while strengthening failregex in 0.8.11 (bd175f) Debian bug #755173 * postfix-sasl - added journalmatch. Thanks Luc Maisonobe * postfix* - match with a new daemon string (postfix/submission/smtpd). Closes gh-804 . Thanks Paul Traina * apache - added filter for AH01630 client denied by server configuration. - New features: - New filters: - monit Thanks Jason H Martin - directadmin Thanks niorg - apache-shellshock Thanks Eugene Hopkinson (SlowRiot) - New actions: - symbiosis-blacklist-allports for Bytemark symbiosis firewall - fail2ban-client can fetch the running server version - Added Cloudflare API action - Enhancements * Start performance of fail2ban-client (and tests) increased, start time and cpu usage rapidly reduced. Introduced a shared storage logic, to bypass reading lots of config files (see gh-824). Thanks to Joost Molenaar for good catch (reported gh-820). * Fail2ban-regex - add print-all-matched option. Closes gh-652 * Suppress fail2ban-client warnings for non-critical config options * Match non "Bye Bye" disconnect messages for sshd locked account regex * courier-smtp filter: - match lines with user names - match lines containing "535 Authentication failed" attempts * Add <chain> tag to iptables-ipsets * Realign fail2ban log output with white space to improve readability. Does not affect SYSLOG output * Log unhandled exceptions * cyrus-imap: catch "user not found" attempts * Add support for Portsentry * tag '0.9.1': (36 commits) ENH: additional versioning changes Refreshed manpages ENH: fail early in generate-man + provide PYTHONPATH upstairs Changes for the 0.9.1 release versioning Populated MANIFEST with more entries which were preiously missed or duplicated. Sorted within each "section" Add portsentry to changelog ConfigReader.touch renamed into protected _create_unshared DOC: documentation about available vagrantfile setup Added myself into THANKS DOC: adjust docs in mytime to place docs into docstrings ENH: do use @staticmethod (we are well beyond support of 2.4 now) testExecuteTimeout fixed: give a test still 1 second, because system could be too busy coverage: no cover (for failed except) fix: fail2ban-regex with filter file failed (after merging #824, because test case missing); test case for 'readexplicit' added; ENH: remove obsolete code for python < 2.6 (we support >= 2.6) DOC: very minor (tabs/spaces) We better check that installation doesn't cause any errors as well code review, change log entries added; reset share/cache storage (if we use 'reload' in client with interactive mode) normalize tabs/spaces in docstrings; ...pull/856/head
commit
b1d7c3f3ff
|
@ -16,6 +16,8 @@ install:
|
|||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then cd ..; pip install -q coveralls; cd -; fi
|
||||
script:
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then coverage run --rcfile=.travis_coveragerc setup.py test; else python setup.py test; fi
|
||||
# test installation
|
||||
- sudo python setup.py install
|
||||
after_success:
|
||||
# Coverage config file must be .coveragerc for coveralls
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then cp -v .travis_coveragerc .coveragerc; fi
|
||||
|
|
11
ChangeLog
11
ChangeLog
|
@ -4,10 +4,10 @@
|
|||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||
|
||||
================================================================================
|
||||
Fail2Ban (version 0.9.0.dev) 2014/xx/xx
|
||||
Fail2Ban (version 0.9.1) 2014/10/29
|
||||
================================================================================
|
||||
|
||||
ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
|
||||
ver. 0.9.1 (2014/10/29) - better, faster, stronger
|
||||
----------
|
||||
|
||||
- Refactoring (IMPORTANT -- Please review your setup and configuration):
|
||||
|
@ -16,6 +16,8 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
|
|||
provides defaults for the chain, port, protocol and name tags
|
||||
|
||||
- Fixes:
|
||||
* start of file2ban aborted (on slow hosts, systemd considers the server has
|
||||
been timed out and kills him), see gh-824
|
||||
* UTF-8 fixes in pure-ftp thanks to Johannes Weberhofer. Closes gh-806.
|
||||
* systemd backend error on bad utf-8 in python3
|
||||
* badips.py action error when logging HTTP error raised with badips request
|
||||
|
@ -64,6 +66,10 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
|
|||
- Added Cloudflare API action
|
||||
|
||||
- Enhancements
|
||||
* Start performance of fail2ban-client (and tests) increased, start time
|
||||
and cpu usage rapidly reduced. Introduced a shared storage logic, to
|
||||
bypass reading lots of config files (see gh-824).
|
||||
Thanks to Joost Molenaar for good catch (reported gh-820).
|
||||
* Fail2ban-regex - add print-all-matched option. Closes gh-652
|
||||
* Suppress fail2ban-client warnings for non-critical config options
|
||||
* Match non "Bye Bye" disconnect messages for sshd locked account regex
|
||||
|
@ -75,6 +81,7 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
|
|||
not affect SYSLOG output
|
||||
* Log unhandled exceptions
|
||||
* cyrus-imap: catch "user not found" attempts
|
||||
* Add support for Portsentry
|
||||
|
||||
ver. 0.9.0 (2014/03/14) - beta
|
||||
----------
|
||||
|
|
12
DEVELOP
12
DEVELOP
|
@ -81,6 +81,18 @@ some quick commands::
|
|||
status test
|
||||
|
||||
|
||||
Testing with vagrant
|
||||
--------------------
|
||||
|
||||
Testing can now be done inside a vagrant VM. Vagrantfile provided in
|
||||
source code repository established two VMs:
|
||||
|
||||
- VM "secure" which can be used for testing fail2ban code.
|
||||
- VM "attacker" which hcan be used to perform attack against our "secure" VM.
|
||||
|
||||
Both VMs are sharing the 192.168.200/24 network. If you are using this network
|
||||
take a look into the Vagrantfile and change the IP.
|
||||
|
||||
|
||||
Coding Standards
|
||||
================
|
||||
|
|
348
MANIFEST
348
MANIFEST
|
@ -1,11 +1,14 @@
|
|||
README.md
|
||||
README.Solaris
|
||||
ChangeLog
|
||||
TODO
|
||||
THANKS
|
||||
CONTRIBUTING.md
|
||||
COPYING
|
||||
ChangeLog
|
||||
DEVELOP
|
||||
FILTERS
|
||||
README.Solaris
|
||||
README.md
|
||||
RELEASE
|
||||
THANKS
|
||||
TODO
|
||||
Vagrantfile
|
||||
fail2ban-2to3
|
||||
fail2ban-testcases-all
|
||||
fail2ban-testcases-all-python3
|
||||
|
@ -14,109 +17,108 @@ bin/fail2ban-server
|
|||
bin/fail2ban-testcases
|
||||
bin/fail2ban-regex
|
||||
doc/run-rootless.txt
|
||||
fail2ban/client/configreader.py
|
||||
fail2ban/client/configparserinc.py
|
||||
fail2ban/client/jailreader.py
|
||||
fail2ban/client/fail2banreader.py
|
||||
fail2ban/client/jailsreader.py
|
||||
fail2ban/client/beautifier.py
|
||||
fail2ban/client/filterreader.py
|
||||
fail2ban/client/actionreader.py
|
||||
fail2ban/client/__init__.py
|
||||
fail2ban/client/actionreader.py
|
||||
fail2ban/client/beautifier.py
|
||||
fail2ban/client/configparserinc.py
|
||||
fail2ban/client/configreader.py
|
||||
fail2ban/client/configurator.py
|
||||
fail2ban/client/csocket.py
|
||||
fail2ban/server/asyncserver.py
|
||||
fail2ban/server/database.py
|
||||
fail2ban/server/filter.py
|
||||
fail2ban/server/filterpyinotify.py
|
||||
fail2ban/server/filtergamin.py
|
||||
fail2ban/server/filterpoll.py
|
||||
fail2ban/server/filtersystemd.py
|
||||
fail2ban/server/iso8601.py
|
||||
fail2ban/server/server.py
|
||||
fail2ban/client/fail2banreader.py
|
||||
fail2ban/client/filterreader.py
|
||||
fail2ban/client/jailreader.py
|
||||
fail2ban/client/jailsreader.py
|
||||
fail2ban/server/__init__.py
|
||||
fail2ban/server/action.py
|
||||
fail2ban/server/actions.py
|
||||
fail2ban/server/asyncserver.py
|
||||
fail2ban/server/banmanager.py
|
||||
fail2ban/server/database.py
|
||||
fail2ban/server/datedetector.py
|
||||
fail2ban/server/datetemplate.py
|
||||
fail2ban/server/faildata.py
|
||||
fail2ban/server/failmanager.py
|
||||
fail2ban/server/datedetector.py
|
||||
fail2ban/server/jailthread.py
|
||||
fail2ban/server/transmitter.py
|
||||
fail2ban/server/action.py
|
||||
fail2ban/server/ticket.py
|
||||
fail2ban/server/failregex.py
|
||||
fail2ban/server/filter.py
|
||||
fail2ban/server/filtergamin.py
|
||||
fail2ban/server/filterpoll.py
|
||||
fail2ban/server/filterpyinotify.py
|
||||
fail2ban/server/filtersystemd.py
|
||||
fail2ban/server/iso8601.py
|
||||
fail2ban/server/jail.py
|
||||
fail2ban/server/jails.py
|
||||
fail2ban/server/__init__.py
|
||||
fail2ban/server/banmanager.py
|
||||
fail2ban/server/datetemplate.py
|
||||
fail2ban/server/jailthread.py
|
||||
fail2ban/server/mytime.py
|
||||
fail2ban/server/failregex.py
|
||||
fail2ban/server/database.py
|
||||
fail2ban/tests/banmanagertestcase.py
|
||||
fail2ban/tests/failmanagertestcase.py
|
||||
fail2ban/tests/clientreadertestcase.py
|
||||
fail2ban/tests/filtertestcase.py
|
||||
fail2ban/server/server.py
|
||||
fail2ban/server/strptime.py
|
||||
fail2ban/server/ticket.py
|
||||
fail2ban/server/transmitter.py
|
||||
fail2ban/tests/__init__.py
|
||||
fail2ban/tests/dummyjail.py
|
||||
fail2ban/tests/samplestestcase.py
|
||||
fail2ban/tests/datedetectortestcase.py
|
||||
fail2ban/tests/action_d/__init__.py
|
||||
fail2ban/tests/action_d/test_badips.py
|
||||
fail2ban/tests/action_d/test_smtp.py
|
||||
fail2ban/tests/actionstestcase.py
|
||||
fail2ban/tests/actiontestcase.py
|
||||
fail2ban/tests/servertestcase.py
|
||||
fail2ban/tests/sockettestcase.py
|
||||
fail2ban/tests/utils.py
|
||||
fail2ban/tests/misctestcase.py
|
||||
fail2ban/tests/databasetestcase.py
|
||||
fail2ban/tests/config/jail.conf
|
||||
fail2ban/tests/banmanagertestcase.py
|
||||
fail2ban/tests/clientreadertestcase.py
|
||||
fail2ban/tests/config/action.d/brokenaction.conf
|
||||
fail2ban/tests/config/fail2ban.conf
|
||||
fail2ban/tests/config/filter.d/simple.conf
|
||||
fail2ban/tests/config/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/config/paths-debian.conf
|
||||
fail2ban/tests/config/filter.d/simple.conf
|
||||
fail2ban/tests/config/action.d/brokenaction.conf
|
||||
fail2ban/tests/files/config/apache-auth/digest/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/digest/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/digest_time/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/digest_time/.htpasswd
|
||||
fail2ban/tests/databasetestcase.py
|
||||
fail2ban/tests/datedetectortestcase.py
|
||||
fail2ban/tests/dummyjail.py
|
||||
fail2ban/tests/failmanagertestcase.py
|
||||
fail2ban/tests/files/action.d/action.py
|
||||
fail2ban/tests/files/action.d/action_errors.py
|
||||
fail2ban/tests/files/action.d/action_modifyainfo.py
|
||||
fail2ban/tests/files/action.d/action_noAction.py
|
||||
fail2ban/tests/files/action.d/action_nomethod.py
|
||||
fail2ban/tests/files/config/apache-auth/README
|
||||
fail2ban/tests/files/config/apache-auth/basic/authz_owner/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/basic/authz_owner/cant_get_me.html
|
||||
fail2ban/tests/files/config/apache-auth/basic/authz_owner/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/basic/authz_owner/cant_get_me.html
|
||||
fail2ban/tests/files/config/apache-auth/basic/file/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/basic/file/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/digest.py
|
||||
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/digest/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/digest/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/digest_anon/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/digest_anon/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/README
|
||||
fail2ban/tests/files/config/apache-auth/digest_time/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/digest_time/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htaccess
|
||||
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htpasswd
|
||||
fail2ban/tests/files/config/apache-auth/noentry/.htaccess
|
||||
fail2ban/tests/files/database_v1.db
|
||||
fail2ban/tests/files/ignorecommand.py
|
||||
fail2ban/tests/files/filter.d/substition.conf
|
||||
fail2ban/tests/files/filter.d/testcase-common.conf
|
||||
fail2ban/tests/files/filter.d/testcase01.conf
|
||||
fail2ban/tests/files/testcase01.log
|
||||
fail2ban/tests/files/testcase02.log
|
||||
fail2ban/tests/files/testcase03.log
|
||||
fail2ban/tests/files/testcase04.log
|
||||
fail2ban/tests/files/testcase-usedns.log
|
||||
fail2ban/tests/files/testcase-journal.log
|
||||
fail2ban/tests/files/testcase-multiline.log
|
||||
fail2ban/tests/files/logs/bsd/syslog-plain.txt
|
||||
fail2ban/tests/files/logs/bsd/syslog-v.txt
|
||||
fail2ban/tests/files/logs/bsd/syslog-vv.txt
|
||||
fail2ban/tests/files/ignorecommand.py
|
||||
fail2ban/tests/files/logs/3proxy
|
||||
fail2ban/tests/files/logs/apache-auth
|
||||
fail2ban/tests/files/logs/apache-badbots
|
||||
fail2ban/tests/files/logs/apache-botscripts
|
||||
fail2ban/tests/files/logs/apache-botsearch
|
||||
fail2ban/tests/files/logs/apache-modsecurity
|
||||
fail2ban/tests/files/logs/apache-nohome
|
||||
fail2ban/tests/files/logs/apache-noscript
|
||||
fail2ban/tests/files/logs/apache-overflows
|
||||
fail2ban/tests/files/logs/apache-shellshock
|
||||
fail2ban/tests/files/logs/assp
|
||||
fail2ban/tests/files/logs/asterisk
|
||||
fail2ban/tests/files/logs/bsd/syslog-plain.txt
|
||||
fail2ban/tests/files/logs/bsd/syslog-v.txt
|
||||
fail2ban/tests/files/logs/bsd/syslog-vv.txt
|
||||
fail2ban/tests/files/logs/counter-strike
|
||||
fail2ban/tests/files/logs/courier-auth
|
||||
fail2ban/tests/files/logs/courier-smtp
|
||||
fail2ban/tests/files/logs/cyrus-imap
|
||||
fail2ban/tests/files/logs/directadmin
|
||||
fail2ban/tests/files/logs/dovecot
|
||||
fail2ban/tests/files/logs/dropbear
|
||||
fail2ban/tests/files/logs/ejabberd-auth
|
||||
|
@ -126,42 +128,60 @@ fail2ban/tests/files/logs/freeswitch
|
|||
fail2ban/tests/files/logs/groupoffice
|
||||
fail2ban/tests/files/logs/gssftpd
|
||||
fail2ban/tests/files/logs/guacamole
|
||||
fail2ban/tests/files/logs/horde
|
||||
fail2ban/tests/files/logs/kerio
|
||||
fail2ban/tests/files/logs/lighttpd-auth
|
||||
fail2ban/tests/files/logs/monit
|
||||
fail2ban/tests/files/logs/mysqld-auth
|
||||
fail2ban/tests/files/logs/nagios
|
||||
fail2ban/tests/files/logs/nsd
|
||||
fail2ban/tests/files/logs/perdition
|
||||
fail2ban/tests/files/logs/php-url-fopen
|
||||
fail2ban/tests/files/logs/postfix-sasl
|
||||
fail2ban/tests/files/logs/named-refused
|
||||
fail2ban/tests/files/logs/nginx-http-auth
|
||||
fail2ban/tests/files/logs/nsd
|
||||
fail2ban/tests/files/logs/openwebmail
|
||||
fail2ban/tests/files/logs/oracleims
|
||||
fail2ban/tests/files/logs/pam-generic
|
||||
fail2ban/tests/files/logs/perdition
|
||||
fail2ban/tests/files/logs/php-url-fopen
|
||||
fail2ban/tests/files/logs/portsentry
|
||||
fail2ban/tests/files/logs/postfix
|
||||
fail2ban/tests/files/logs/postfix-sasl
|
||||
fail2ban/tests/files/logs/proftpd
|
||||
fail2ban/tests/files/logs/pure-ftpd
|
||||
fail2ban/tests/files/logs/qmail
|
||||
fail2ban/tests/files/logs/recidive
|
||||
fail2ban/tests/files/logs/roundcube-auth
|
||||
fail2ban/tests/files/logs/selinux-ssh
|
||||
fail2ban/tests/files/logs/sendmail-auth
|
||||
fail2ban/tests/files/logs/sendmail-reject
|
||||
fail2ban/tests/files/logs/sendmail-spam
|
||||
fail2ban/tests/files/logs/sieve
|
||||
fail2ban/tests/files/logs/squid
|
||||
fail2ban/tests/files/logs/stunnel
|
||||
fail2ban/tests/files/logs/suhosin
|
||||
fail2ban/tests/files/logs/sogo-auth
|
||||
fail2ban/tests/files/logs/solid-pop3d
|
||||
fail2ban/tests/files/logs/squid
|
||||
fail2ban/tests/files/logs/squirrelmail
|
||||
fail2ban/tests/files/logs/sshd
|
||||
fail2ban/tests/files/logs/sshd-ddos
|
||||
fail2ban/tests/files/logs/stunnel
|
||||
fail2ban/tests/files/logs/suhosin
|
||||
fail2ban/tests/files/logs/tine20
|
||||
fail2ban/tests/files/logs/uwimap-auth
|
||||
fail2ban/tests/files/logs/vsftpd
|
||||
fail2ban/tests/files/logs/webmin-auth
|
||||
fail2ban/tests/files/logs/wuftpd
|
||||
fail2ban/tests/files/logs/uwimap-auth
|
||||
fail2ban/tests/files/logs/xinetd-fail
|
||||
fail2ban/tests/config/jail.conf
|
||||
fail2ban/tests/config/fail2ban.conf
|
||||
fail2ban/tests/config/filter.d/simple.conf
|
||||
fail2ban/tests/config/action.d/brokenaction.conf
|
||||
fail2ban/tests/files/testcase-journal.log
|
||||
fail2ban/tests/files/testcase-multiline.log
|
||||
fail2ban/tests/files/testcase-usedns.log
|
||||
fail2ban/tests/files/testcase01.log
|
||||
fail2ban/tests/files/testcase02.log
|
||||
fail2ban/tests/files/testcase03.log
|
||||
fail2ban/tests/files/testcase04.log
|
||||
fail2ban/tests/filtertestcase.py
|
||||
fail2ban/tests/misctestcase.py
|
||||
fail2ban/tests/samplestestcase.py
|
||||
fail2ban/tests/servertestcase.py
|
||||
fail2ban/tests/sockettestcase.py
|
||||
fail2ban/tests/utils.py
|
||||
setup.py
|
||||
setup.cfg
|
||||
fail2ban/__init__.py
|
||||
|
@ -169,126 +189,136 @@ fail2ban/exceptions.py
|
|||
fail2ban/helpers.py
|
||||
fail2ban/version.py
|
||||
fail2ban/protocol.py
|
||||
setup.py
|
||||
setup.cfg
|
||||
kill-server
|
||||
config/jail.conf
|
||||
config/action.d/apf.conf
|
||||
config/action.d/badips.conf
|
||||
config/action.d/badips.py
|
||||
config/action.d/blocklist_de.conf
|
||||
config/action.d/bsd-ipfw.conf
|
||||
config/action.d/cloudflare.conf
|
||||
config/action.d/complain.conf
|
||||
config/action.d/dshield.conf
|
||||
config/action.d/dummy.conf
|
||||
config/action.d/firewallcmd-ipset.conf
|
||||
config/action.d/firewallcmd-new.conf
|
||||
config/action.d/hostsdeny.conf
|
||||
config/action.d/ipfilter.conf
|
||||
config/action.d/ipfw.conf
|
||||
config/action.d/iptables-allports.conf
|
||||
config/action.d/iptables-common.conf
|
||||
config/action.d/iptables-ipset-proto4.conf
|
||||
config/action.d/iptables-ipset-proto6-allports.conf
|
||||
config/action.d/iptables-ipset-proto6.conf
|
||||
config/action.d/iptables-multiport-log.conf
|
||||
config/action.d/iptables-multiport.conf
|
||||
config/action.d/iptables-new.conf
|
||||
config/action.d/iptables-xt_recent-echo.conf
|
||||
config/action.d/iptables.conf
|
||||
config/action.d/mail-buffered.conf
|
||||
config/action.d/mail-whois-lines.conf
|
||||
config/action.d/mail-whois.conf
|
||||
config/action.d/mail.conf
|
||||
config/action.d/mynetwatchman.conf
|
||||
config/action.d/osx-afctl.conf
|
||||
config/action.d/osx-ipfw.conf
|
||||
config/action.d/pf.conf
|
||||
config/action.d/route.conf
|
||||
config/action.d/sendmail-buffered.conf
|
||||
config/action.d/sendmail-common.conf
|
||||
config/action.d/sendmail-whois-ipjailmatches.conf
|
||||
config/action.d/sendmail-whois-ipmatches.conf
|
||||
config/action.d/sendmail-whois-lines.conf
|
||||
config/action.d/sendmail-whois-matches.conf
|
||||
config/action.d/sendmail-whois.conf
|
||||
config/action.d/sendmail.conf
|
||||
config/action.d/shorewall.conf
|
||||
config/action.d/smtp.py
|
||||
config/action.d/symbiosis-blacklist-allports.conf
|
||||
config/action.d/ufw.conf
|
||||
config/action.d/xarf-login-attack.conf
|
||||
config/fail2ban.conf
|
||||
config/filter.d/common.conf
|
||||
config/filter.d/3proxy.conf
|
||||
config/filter.d/apache-auth.conf
|
||||
config/filter.d/apache-badbots.conf
|
||||
config/filter.d/apache-botsearch.conf
|
||||
config/filter.d/apache-common.conf
|
||||
config/filter.d/apache-modsecurity.conf
|
||||
config/filter.d/apache-nohome.conf
|
||||
config/filter.d/apache-noscript.conf
|
||||
config/filter.d/apache-overflows.conf
|
||||
config/filter.d/nginx-http-auth.conf
|
||||
config/filter.d/apache-shellshock.conf
|
||||
config/filter.d/assp.conf
|
||||
config/filter.d/asterisk.conf
|
||||
config/filter.d/common.conf
|
||||
config/filter.d/counter-strike.conf
|
||||
config/filter.d/courier-auth.conf
|
||||
config/filter.d/courier-smtp.conf
|
||||
config/filter.d/cyrus-imap.conf
|
||||
config/filter.d/directadmin.conf
|
||||
config/filter.d/dovecot.conf
|
||||
config/filter.d/dropbear.conf
|
||||
config/filter.d/ejabberd-auth.conf
|
||||
config/filter.d/exim-common.conf
|
||||
config/filter.d/exim-spam.conf
|
||||
config/filter.d/exim.conf
|
||||
config/filter.d/freeswitch.conf
|
||||
config/filter.d/groupoffice.conf
|
||||
config/filter.d/gssftpd.conf
|
||||
config/filter.d/kerio.conf
|
||||
config/filter.d/guacamole.conf
|
||||
config/filter.d/horde.conf
|
||||
config/filter.d/suhosin.conf
|
||||
config/filter.d/kerio.conf
|
||||
config/filter.d/lighttpd-auth.conf
|
||||
config/filter.d/monit.conf
|
||||
config/filter.d/mysqld-auth.conf
|
||||
config/filter.d/nagios.conf
|
||||
config/filter.d/named-refused.conf
|
||||
config/filter.d/nginx-http-auth.conf
|
||||
config/filter.d/nsd.conf
|
||||
config/filter.d/openwebmail.conf
|
||||
config/filter.d/oracleims.conf
|
||||
config/filter.d/pam-generic.conf
|
||||
config/filter.d/pam-generic.conf
|
||||
config/filter.d/pam-generic.conf
|
||||
config/filter.d/perdition.conf
|
||||
config/filter.d/php-url-fopen.conf
|
||||
config/filter.d/php-url-fopen.conf
|
||||
config/filter.d/php-url-fopen.conf
|
||||
config/filter.d/portsentry.conf
|
||||
config/filter.d/postfix-sasl.conf
|
||||
config/filter.d/postfix-sasl.conf
|
||||
config/filter.d/pam-generic.conf
|
||||
config/filter.d/php-url-fopen.conf
|
||||
config/filter.d/postfix-sasl.conf
|
||||
config/filter.d/postfix.conf
|
||||
config/filter.d/proftpd.conf
|
||||
config/filter.d/pure-ftpd.conf
|
||||
config/filter.d/qmail.conf
|
||||
config/filter.d/pam-generic.conf
|
||||
config/filter.d/php-url-fopen.conf
|
||||
config/filter.d/postfix-sasl.conf
|
||||
config/filter.d/recidive.conf
|
||||
config/filter.d/roundcube-auth.conf
|
||||
config/filter.d/selinux-common.conf
|
||||
config/filter.d/selinux-ssh.conf
|
||||
config/filter.d/sendmail-auth.conf
|
||||
config/filter.d/sendmail-reject.conf
|
||||
config/filter.d/sendmail-spam.conf
|
||||
config/filter.d/sieve.conf
|
||||
config/filter.d/sogo-auth.conf
|
||||
config/filter.d/solid-pop3d.conf
|
||||
config/filter.d/squid.conf
|
||||
config/filter.d/sshd.conf
|
||||
config/filter.d/squirrelmail.conf
|
||||
config/filter.d/sshd-ddos.conf
|
||||
config/filter.d/sshd.conf
|
||||
config/filter.d/stunnel.conf
|
||||
config/filter.d/suhosin.conf
|
||||
config/filter.d/tine20.conf
|
||||
config/filter.d/uwimap-auth.conf
|
||||
config/filter.d/vsftpd.conf
|
||||
config/filter.d/webmin-auth.conf
|
||||
config/filter.d/wuftpd.conf
|
||||
config/filter.d/xinetd-fail.conf
|
||||
config/filter.d/asterisk.conf
|
||||
config/filter.d/dovecot.conf
|
||||
config/filter.d/dropbear.conf
|
||||
config/filter.d/lighttpd-auth.conf
|
||||
config/filter.d/recidive.conf
|
||||
config/filter.d/roundcube-auth.conf
|
||||
config/filter.d/assp.conf
|
||||
config/filter.d/sogo-auth.conf
|
||||
config/filter.d/mysqld-auth.conf
|
||||
config/filter.d/selinux-common.conf
|
||||
config/filter.d/selinux-ssh.conf
|
||||
config/filter.d/3proxy.conf
|
||||
config/filter.d/apache-common.conf
|
||||
config/filter.d/exim-common.conf
|
||||
config/filter.d/exim-spam.conf
|
||||
config/filter.d/freeswitch.conf
|
||||
config/filter.d/groupoffice.conf
|
||||
config/filter.d/perdition.conf
|
||||
config/filter.d/uwimap-auth.conf
|
||||
config/filter.d/courier-auth.conf
|
||||
config/filter.d/courier-smtp.conf
|
||||
config/filter.d/ejabberd-auth.conf
|
||||
config/filter.d/guacamole.conf
|
||||
config/filter.d/sendmail-spam.conf
|
||||
config/action.d/apf.conf
|
||||
config/action.d/blocklist_de.conf
|
||||
config/action.d/osx-afctl.conf
|
||||
config/action.d/osx-ipfw.conf
|
||||
config/action.d/sendmail-common.conf
|
||||
config/action.d/badips.conf
|
||||
config/action.d/bsd-ipfw.conf
|
||||
config/action.d/dummy.conf
|
||||
config/action.d/firewallcmd-new.conf
|
||||
config/action.d/firewallcmd-ipset.conf
|
||||
config/action.d/iptables-ipset-proto6-allports.conf
|
||||
config/action.d/iptables-common.conf
|
||||
config/action.d/iptables-ipset-proto4.conf
|
||||
config/action.d/iptables-ipset-proto6.conf
|
||||
config/action.d/iptables-xt_recent-echo.conf
|
||||
config/action.d/route.conf
|
||||
config/action.d/complain.conf
|
||||
config/action.d/dshield.conf
|
||||
config/action.d/hostsdeny.conf
|
||||
config/action.d/ipfw.conf
|
||||
config/action.d/ipfilter.conf
|
||||
config/action.d/iptables.conf
|
||||
config/action.d/iptables-allports.conf
|
||||
config/action.d/iptables-multiport.conf
|
||||
config/action.d/iptables-multiport-log.conf
|
||||
config/action.d/iptables-new.conf
|
||||
config/action.d/mail.conf
|
||||
config/action.d/mail-buffered.conf
|
||||
config/action.d/mail-whois.conf
|
||||
config/action.d/mail-whois-lines.conf
|
||||
config/action.d/mynetwatchman.conf
|
||||
config/action.d/pf.conf
|
||||
config/action.d/sendmail.conf
|
||||
config/action.d/sendmail-buffered.conf
|
||||
config/action.d/sendmail-whois-ipmatches.conf
|
||||
config/action.d/sendmail-whois.conf
|
||||
config/action.d/sendmail-whois-lines.conf
|
||||
config/action.d/shorewall.conf
|
||||
config/action.d/xarf-login-attack.conf
|
||||
config/action.d/ufw.conf
|
||||
config/fail2ban.conf
|
||||
doc/run-rootless.txt
|
||||
config/jail.conf
|
||||
config/paths-common.conf
|
||||
config/paths-debian.conf
|
||||
config/paths-fedora.conf
|
||||
config/paths-freebsd.conf
|
||||
config/paths-osx.conf
|
||||
man/fail2ban-client.1
|
||||
man/fail2ban.1
|
||||
man/jail.conf.5
|
||||
|
@ -306,6 +336,8 @@ files/solaris-fail2ban.xml
|
|||
files/solaris-svc-fail2ban
|
||||
files/suse-initd
|
||||
files/fail2ban-logrotate
|
||||
files/fail2ban.upstart
|
||||
files/logwatch/fail2ban
|
||||
files/cacti/fail2ban_stats.sh
|
||||
files/cacti/cacti_host_template_fail2ban.xml
|
||||
files/cacti/README
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
include ChangeLog COPYING DEVELOP FILTERS README.* THANKS TODO
|
||||
include ChangeLog COPYING DEVELOP FILTERS README.* THANKS TODO CONTRIBUTING* Vagrantfile
|
||||
graft doc
|
||||
graft files
|
||||
recursive-include config *.conf *.py
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/ _|__ _(_) |_ ) |__ __ _ _ _
|
||||
| _/ _` | | |/ /| '_ \/ _` | ' \
|
||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||
v0.9.0 2014/03/14
|
||||
v0.9.1 2014/10/29
|
||||
|
||||
## Fail2Ban: ban hosts that cause multiple authentication errors
|
||||
|
||||
|
@ -36,8 +36,8 @@ Optional:
|
|||
|
||||
To install, just do:
|
||||
|
||||
tar xvfj fail2ban-0.9.0.tar.bz2
|
||||
cd fail2ban-0.9.0
|
||||
tar xvfj fail2ban-0.9.1.tar.bz2
|
||||
cd fail2ban-0.9.1
|
||||
python setup.py install
|
||||
|
||||
This will install Fail2Ban into the python library directory. The executable
|
||||
|
|
14
RELEASE
14
RELEASE
|
@ -47,6 +47,10 @@ Preparation
|
|||
|
||||
* Ensure the MANIFEST is complete
|
||||
|
||||
ad-hoc bash script to run in a clean clone:
|
||||
|
||||
find -type f | grep -v -e '\.git' -e '/doc/' -e '\.travis' -e MANIFEST | sed -e 's,^\./,,g' | while read f; do grep -ne "^$f\$" MANIFEST >/dev/null || echo "$f" ; done
|
||||
|
||||
* Run::
|
||||
|
||||
python setup.py sdist
|
||||
|
@ -57,24 +61,24 @@ Preparation
|
|||
|
||||
* Which indicates that testcases/files/logs/mysqld.log has been moved or is a directory::
|
||||
|
||||
tar -C /tmp -jxf dist/fail2ban-0.9.0.tar.bz2
|
||||
tar -C /tmp -jxf dist/fail2ban-0.9.1.tar.bz2
|
||||
|
||||
* clean up current direcory::
|
||||
|
||||
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.0/
|
||||
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.1/
|
||||
|
||||
* Only differences should be files that you don't want distributed.
|
||||
|
||||
|
||||
* Ensure the tests work from the tarball::
|
||||
|
||||
cd /tmp/fail2ban-0.9.0/ && export PYTHONPATH=`pwd` && bin/fail2ban-testcases
|
||||
cd /tmp/fail2ban-0.9.1/ && export PYTHONPATH=`pwd` && bin/fail2ban-testcases
|
||||
|
||||
* Add/finalize the corresponding entry in the ChangeLog
|
||||
|
||||
* To generate a list of committers use e.g.::
|
||||
|
||||
git shortlog -sn 0.8.12.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g'
|
||||
git shortlog -sn 0.9.1.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g'
|
||||
|
||||
* Ensure the top of the ChangeLog has the right version and current date.
|
||||
* Ensure the top entry of the ChangeLog has the right version and current date.
|
||||
|
@ -181,7 +185,7 @@ Post Release
|
|||
|
||||
Add the following to the top of the ChangeLog::
|
||||
|
||||
ver. 0.9.1 (2014/XX/XXX) - wanna-be-released
|
||||
ver. 0.9.2 (2014/XX/XXX) - wanna-be-released
|
||||
-----------
|
||||
|
||||
- Fixes:
|
||||
|
|
1
THANKS
1
THANKS
|
@ -26,6 +26,7 @@ Christian Rauch
|
|||
Christophe Carles
|
||||
Christoph Haas
|
||||
Christos Psonis
|
||||
craneworks
|
||||
Cyril Jaquier
|
||||
Daniel B. Cid
|
||||
Daniel B.
|
||||
|
|
|
@ -409,6 +409,7 @@ class Fail2banClient:
|
|||
# TODO: get away from stew of return codes and exception
|
||||
# handling -- handle via exceptions
|
||||
try:
|
||||
self.__configurator.Reload()
|
||||
self.__configurator.readAll()
|
||||
ret = self.__configurator.getOptions(jail)
|
||||
self.__configurator.convertToProtocol()
|
||||
|
@ -418,12 +419,11 @@ class Fail2banClient:
|
|||
ret = False
|
||||
return ret
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def dumpConfig(cmd):
|
||||
for c in cmd:
|
||||
print c
|
||||
return True
|
||||
dumpConfig = staticmethod(dumpConfig)
|
||||
|
||||
|
||||
class ServerExecutionException(Exception):
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# Fail2Ban filter for failure attempts in Counter Strike-1.6
|
||||
#
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
||||
failregex = \/<HOST> Port\: [0-9]+ (TCP|UDP) Blocked$
|
||||
|
||||
# Author: Pacop <pacoparu@gmail.com>
|
||||
|
|
@ -719,3 +719,8 @@ banaction = iptables-allports
|
|||
enabled = false
|
||||
logpath = /var/log/directadmin/login.log
|
||||
port = 2222
|
||||
|
||||
[portsentry]
|
||||
enabled = false
|
||||
logpath = /var/lib/portsentry/portsentry.history
|
||||
maxretry = 1
|
|
@ -26,7 +26,7 @@ __license__ = "GPL"
|
|||
|
||||
import os
|
||||
|
||||
from .configreader import ConfigReader, DefinitionInitConfigReader
|
||||
from .configreader import DefinitionInitConfigReader
|
||||
from ..helpers import getLogger
|
||||
|
||||
# Gets the instance of the logger.
|
||||
|
@ -47,15 +47,19 @@ class ActionReader(DefinitionInitConfigReader):
|
|||
DefinitionInitConfigReader.__init__(
|
||||
self, file_, jailName, initOpts, **kwargs)
|
||||
|
||||
def setFile(self, fileName):
|
||||
self.__file = fileName
|
||||
DefinitionInitConfigReader.setFile(self, os.path.join("action.d", fileName))
|
||||
|
||||
def getFile(self):
|
||||
return self.__file
|
||||
|
||||
def setName(self, name):
|
||||
self._name = name
|
||||
|
||||
def getName(self):
|
||||
return self._name
|
||||
|
||||
def read(self):
|
||||
return ConfigReader.read(self, os.path.join("action.d", self._file))
|
||||
|
||||
def convert(self):
|
||||
head = ["set", self._jailName]
|
||||
stream = list()
|
||||
|
|
|
@ -62,6 +62,7 @@ else: # pragma: no cover
|
|||
|
||||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
logLevel = 7
|
||||
|
||||
__all__ = ['SafeConfigParserWithIncludes']
|
||||
|
||||
|
@ -98,30 +99,73 @@ after = 1.conf
|
|||
|
||||
if sys.version_info >= (3,2):
|
||||
# overload constructor only for fancy new Python3's
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, share_config=None, *args, **kwargs):
|
||||
kwargs = kwargs.copy()
|
||||
kwargs['interpolation'] = BasicInterpolationWithName()
|
||||
kwargs['inline_comment_prefixes'] = ";"
|
||||
super(SafeConfigParserWithIncludes, self).__init__(
|
||||
*args, **kwargs)
|
||||
self._cfg_share = share_config
|
||||
|
||||
#@staticmethod
|
||||
def getIncludes(resource, seen = []):
|
||||
else:
|
||||
def __init__(self, share_config=None, *args, **kwargs):
|
||||
SafeConfigParser.__init__(self, *args, **kwargs)
|
||||
self._cfg_share = share_config
|
||||
|
||||
@property
|
||||
def share_config(self):
|
||||
return self._cfg_share
|
||||
|
||||
def _getSharedSCPWI(self, filename):
|
||||
SCPWI = SafeConfigParserWithIncludes
|
||||
# read single one, add to return list, use sharing if possible:
|
||||
if self._cfg_share:
|
||||
# cache/share each file as include (ex: filter.d/common could be included in each filter config):
|
||||
hashv = 'inc:'+(filename if not isinstance(filename, list) else '\x01'.join(filename))
|
||||
cfg, i = self._cfg_share.get(hashv, (None, None))
|
||||
if cfg is None:
|
||||
cfg = SCPWI(share_config=self._cfg_share)
|
||||
i = cfg.read(filename, get_includes=False)
|
||||
self._cfg_share[hashv] = (cfg, i)
|
||||
elif logSys.getEffectiveLevel() <= logLevel:
|
||||
logSys.log(logLevel, " Shared file: %s", filename)
|
||||
else:
|
||||
# don't have sharing:
|
||||
cfg = SCPWI()
|
||||
i = cfg.read(filename, get_includes=False)
|
||||
return (cfg, i)
|
||||
|
||||
def _getIncludes(self, filenames, seen=[]):
|
||||
if not isinstance(filenames, list):
|
||||
filenames = [ filenames ]
|
||||
# retrieve or cache include paths:
|
||||
if self._cfg_share:
|
||||
# cache/share include list:
|
||||
hashv = 'inc-path:'+('\x01'.join(filenames))
|
||||
fileNamesFull = self._cfg_share.get(hashv)
|
||||
if fileNamesFull is None:
|
||||
fileNamesFull = []
|
||||
for filename in filenames:
|
||||
fileNamesFull += self.__getIncludesUncached(filename, seen)
|
||||
self._cfg_share[hashv] = fileNamesFull
|
||||
return fileNamesFull
|
||||
# don't have sharing:
|
||||
fileNamesFull = []
|
||||
for filename in filenames:
|
||||
fileNamesFull += self.__getIncludesUncached(filename, seen)
|
||||
return fileNamesFull
|
||||
|
||||
def __getIncludesUncached(self, resource, seen=[]):
|
||||
"""
|
||||
Given 1 config resource returns list of included files
|
||||
(recursively) with the original one as well
|
||||
Simple loops are taken care about
|
||||
"""
|
||||
|
||||
# Use a short class name ;)
|
||||
SCPWI = SafeConfigParserWithIncludes
|
||||
|
||||
parser = SafeConfigParser()
|
||||
try:
|
||||
if sys.version_info >= (3,2): # pragma: no cover
|
||||
parser.read(resource, encoding='utf-8')
|
||||
else:
|
||||
parser.read(resource)
|
||||
parser, i = self._getSharedSCPWI(resource)
|
||||
if not i:
|
||||
return []
|
||||
except UnicodeDecodeError, e:
|
||||
logSys.error("Error decoding config file '%s': %s" % (resource, e))
|
||||
return []
|
||||
|
@ -141,22 +185,60 @@ after = 1.conf
|
|||
if r in seen:
|
||||
continue
|
||||
s = seen + [resource]
|
||||
option_list += SCPWI.getIncludes(r, s)
|
||||
option_list += self._getIncludes(r, s)
|
||||
# combine lists
|
||||
return newFiles[0][1] + [resource] + newFiles[1][1]
|
||||
#print "Includes list for " + resource + " is " + `resources`
|
||||
getIncludes = staticmethod(getIncludes)
|
||||
|
||||
def get_defaults(self):
|
||||
return self._defaults
|
||||
|
||||
def read(self, filenames):
|
||||
fileNamesFull = []
|
||||
def get_sections(self):
|
||||
return self._sections
|
||||
|
||||
def read(self, filenames, get_includes=True):
|
||||
if not isinstance(filenames, list):
|
||||
filenames = [ filenames ]
|
||||
for filename in filenames:
|
||||
fileNamesFull += SafeConfigParserWithIncludes.getIncludes(filename)
|
||||
logSys.debug("Reading files: %s" % fileNamesFull)
|
||||
# retrieve (and cache) includes:
|
||||
fileNamesFull = []
|
||||
if get_includes:
|
||||
fileNamesFull += self._getIncludes(filenames)
|
||||
else:
|
||||
fileNamesFull = filenames
|
||||
|
||||
if not fileNamesFull:
|
||||
return []
|
||||
|
||||
logSys.info(" Loading files: %s", fileNamesFull)
|
||||
|
||||
if get_includes or len(fileNamesFull) > 1:
|
||||
# read multiple configs:
|
||||
ret = []
|
||||
alld = self.get_defaults()
|
||||
alls = self.get_sections()
|
||||
for filename in fileNamesFull:
|
||||
# read single one, add to return list, use sharing if possible:
|
||||
cfg, i = self._getSharedSCPWI(filename)
|
||||
if i:
|
||||
ret += i
|
||||
# merge defaults and all sections to self:
|
||||
alld.update(cfg.get_defaults())
|
||||
for n, s in cfg.get_sections().iteritems():
|
||||
if isinstance(s, dict):
|
||||
s2 = alls.get(n)
|
||||
if isinstance(s2, dict):
|
||||
s2.update(s)
|
||||
else:
|
||||
alls[n] = s.copy()
|
||||
else:
|
||||
alls[n] = s
|
||||
|
||||
return ret
|
||||
|
||||
# read one config :
|
||||
if logSys.getEffectiveLevel() <= logLevel:
|
||||
logSys.log(logLevel, " Reading file: %s", fileNamesFull[0])
|
||||
# read file(s) :
|
||||
if sys.version_info >= (3,2): # pragma: no cover
|
||||
return SafeConfigParser.read(self, fileNamesFull, encoding='utf-8')
|
||||
else:
|
||||
return SafeConfigParser.read(self, fileNamesFull)
|
||||
|
||||
|
|
|
@ -27,24 +27,127 @@ __license__ = "GPL"
|
|||
import glob, os
|
||||
from ConfigParser import NoOptionError, NoSectionError
|
||||
|
||||
from .configparserinc import SafeConfigParserWithIncludes
|
||||
from .configparserinc import SafeConfigParserWithIncludes, logLevel
|
||||
from ..helpers import getLogger
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
class ConfigReader(SafeConfigParserWithIncludes):
|
||||
class ConfigReader():
|
||||
"""Generic config reader class.
|
||||
|
||||
A caching adapter which automatically reuses already shared configuration.
|
||||
"""
|
||||
|
||||
def __init__(self, use_config=None, share_config=None, **kwargs):
|
||||
# use given shared config if possible (see read):
|
||||
self._cfg_share = None
|
||||
self._cfg = None
|
||||
if use_config is not None:
|
||||
self._cfg = use_config
|
||||
# share config if possible:
|
||||
if share_config is not None:
|
||||
self._cfg_share = share_config
|
||||
self._cfg_share_kwargs = kwargs
|
||||
self._cfg_share_basedir = None
|
||||
elif self._cfg is None:
|
||||
self._cfg = ConfigReaderUnshared(**kwargs)
|
||||
|
||||
def setBaseDir(self, basedir):
|
||||
if self._cfg:
|
||||
self._cfg.setBaseDir(basedir)
|
||||
else:
|
||||
self._cfg_share_basedir = basedir
|
||||
|
||||
def getBaseDir(self):
|
||||
if self._cfg:
|
||||
return self._cfg.getBaseDir()
|
||||
else:
|
||||
return self._cfg_share_basedir
|
||||
|
||||
@property
|
||||
def share_config(self):
|
||||
return self._cfg_share
|
||||
|
||||
def read(self, name, once=True):
|
||||
""" Overloads a default (not shared) read of config reader.
|
||||
|
||||
To prevent mutiple reads of config files with it includes, reads into
|
||||
the config reader, if it was not yet cached/shared by 'name'.
|
||||
"""
|
||||
# already shared ?
|
||||
if not self._cfg:
|
||||
self._create_unshared(name)
|
||||
# performance feature - read once if using shared config reader:
|
||||
if once and self._cfg.read_cfg_files is not None:
|
||||
return self._cfg.read_cfg_files
|
||||
|
||||
# load:
|
||||
logSys.info("Loading configs for %s under %s ", name, self._cfg.getBaseDir())
|
||||
ret = self._cfg.read(name)
|
||||
|
||||
# save already read and return:
|
||||
self._cfg.read_cfg_files = ret
|
||||
return ret
|
||||
|
||||
def _create_unshared(self, name=''):
|
||||
""" Allocates and share a config file by it name.
|
||||
|
||||
Automatically allocates unshared or reuses shared handle by given 'name' and
|
||||
init arguments inside a given shared storage.
|
||||
"""
|
||||
if not self._cfg and self._cfg_share is not None:
|
||||
self._cfg = self._cfg_share.get(name)
|
||||
if not self._cfg:
|
||||
self._cfg = ConfigReaderUnshared(share_config=self._cfg_share, **self._cfg_share_kwargs)
|
||||
if self._cfg_share_basedir is not None:
|
||||
self._cfg.setBaseDir(self._cfg_share_basedir)
|
||||
self._cfg_share[name] = self._cfg
|
||||
else:
|
||||
self._cfg = ConfigReaderUnshared(**self._cfg_share_kwargs)
|
||||
|
||||
def sections(self):
|
||||
if self._cfg is not None:
|
||||
return self._cfg.sections()
|
||||
return []
|
||||
|
||||
def has_section(self, sec):
|
||||
if self._cfg is not None:
|
||||
return self._cfg.has_section(sec)
|
||||
return False
|
||||
|
||||
def options(self, *args):
|
||||
if self._cfg is not None:
|
||||
return self._cfg.options(*args)
|
||||
return {}
|
||||
|
||||
def get(self, sec, opt):
|
||||
if self._cfg is not None:
|
||||
return self._cfg.get(sec, opt)
|
||||
return None
|
||||
|
||||
def getOptions(self, *args, **kwargs):
|
||||
if self._cfg is not None:
|
||||
return self._cfg.getOptions(*args, **kwargs)
|
||||
return {}
|
||||
|
||||
class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
||||
"""Unshared config reader (previously ConfigReader).
|
||||
|
||||
Do not use this class (internal not shared/cached represenation).
|
||||
Use ConfigReader instead.
|
||||
"""
|
||||
|
||||
DEFAULT_BASEDIR = '/etc/fail2ban'
|
||||
|
||||
def __init__(self, basedir=None):
|
||||
SafeConfigParserWithIncludes.__init__(self)
|
||||
def __init__(self, basedir=None, *args, **kwargs):
|
||||
SafeConfigParserWithIncludes.__init__(self, *args, **kwargs)
|
||||
self.read_cfg_files = None
|
||||
self.setBaseDir(basedir)
|
||||
self.__opts = None
|
||||
|
||||
def setBaseDir(self, basedir):
|
||||
if basedir is None:
|
||||
basedir = ConfigReader.DEFAULT_BASEDIR # stock system location
|
||||
basedir = ConfigReaderUnshared.DEFAULT_BASEDIR # stock system location
|
||||
self._basedir = basedir.rstrip('/')
|
||||
|
||||
def getBaseDir(self):
|
||||
|
@ -55,7 +158,7 @@ class ConfigReader(SafeConfigParserWithIncludes):
|
|||
raise ValueError("Base configuration directory %s does not exist "
|
||||
% self._basedir)
|
||||
basename = os.path.join(self._basedir, filename)
|
||||
logSys.info("Reading configs for %s under %s " % (basename, self._basedir))
|
||||
logSys.debug("Reading configs for %s under %s " , filename, self._basedir)
|
||||
config_files = [ basename + ".conf" ]
|
||||
|
||||
# possible further customizations under a .conf.d directory
|
||||
|
@ -71,14 +174,14 @@ class ConfigReader(SafeConfigParserWithIncludes):
|
|||
|
||||
if len(config_files):
|
||||
# at least one config exists and accessible
|
||||
logSys.debug("Reading config files: " + ', '.join(config_files))
|
||||
logSys.debug("Reading config files: %s", ', '.join(config_files))
|
||||
config_files_read = SafeConfigParserWithIncludes.read(self, config_files)
|
||||
missed = [ cf for cf in config_files if cf not in config_files_read ]
|
||||
if missed:
|
||||
logSys.error("Could not read config files: " + ', '.join(missed))
|
||||
logSys.error("Could not read config files: %s", ', '.join(missed))
|
||||
if config_files_read:
|
||||
return True
|
||||
logSys.error("Found no accessible config files for %r under %s" %
|
||||
logSys.error("Found no accessible config files for %r under %s",
|
||||
( filename, self.getBaseDir() ))
|
||||
return False
|
||||
else:
|
||||
|
@ -98,7 +201,7 @@ class ConfigReader(SafeConfigParserWithIncludes):
|
|||
# 1 -> the name of the option
|
||||
# 2 -> the default value for the option
|
||||
|
||||
def getOptions(self, sec, options, pOptions = None):
|
||||
def getOptions(self, sec, options, pOptions=None):
|
||||
values = dict()
|
||||
for option in options:
|
||||
try:
|
||||
|
@ -121,10 +224,8 @@ class ConfigReader(SafeConfigParserWithIncludes):
|
|||
logSys.warning("'%s' not defined in '%s'. Using default one: %r"
|
||||
% (option[1], sec, option[2]))
|
||||
values[option[1]] = option[2]
|
||||
else:
|
||||
logSys.debug(
|
||||
"Non essential option '%s' not defined in '%s'.",
|
||||
option[1], sec)
|
||||
elif logSys.getEffectiveLevel() <= logLevel:
|
||||
logSys.log(logLevel, "Non essential option '%s' not defined in '%s'.", option[1], sec)
|
||||
except ValueError:
|
||||
logSys.warning("Wrong value for '" + option[1] + "' in '" + sec +
|
||||
"'. Using default one: '" + `option[2]` + "'")
|
||||
|
@ -133,12 +234,12 @@ class ConfigReader(SafeConfigParserWithIncludes):
|
|||
|
||||
class DefinitionInitConfigReader(ConfigReader):
|
||||
"""Config reader for files with options grouped in [Definition] and
|
||||
[Init] sections.
|
||||
[Init] sections.
|
||||
|
||||
Is a base class for readers of filters and actions, where definitions
|
||||
in jails might provide custom values for options defined in [Init]
|
||||
section.
|
||||
"""
|
||||
Is a base class for readers of filters and actions, where definitions
|
||||
in jails might provide custom values for options defined in [Init]
|
||||
section.
|
||||
"""
|
||||
|
||||
_configOpts = []
|
||||
|
||||
|
@ -166,7 +267,9 @@ class DefinitionInitConfigReader(ConfigReader):
|
|||
|
||||
# needed for fail2ban-regex that doesn't need fancy directories
|
||||
def readexplicit(self):
|
||||
return SafeConfigParserWithIncludes.read(self, self._file)
|
||||
if not self._cfg:
|
||||
self._create_unshared(self._file)
|
||||
return SafeConfigParserWithIncludes.read(self._cfg, self._file)
|
||||
|
||||
def getOptions(self, pOpts):
|
||||
self._opts = ConfigReader.getOptions(
|
||||
|
|
|
@ -33,12 +33,20 @@ logSys = getLogger(__name__)
|
|||
|
||||
class Configurator:
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, force_enable=False, share_config=None):
|
||||
self.__settings = dict()
|
||||
self.__streams = dict()
|
||||
self.__fail2ban = Fail2banReader()
|
||||
self.__jails = JailsReader()
|
||||
|
||||
# always share all config readers:
|
||||
if share_config is None:
|
||||
share_config = dict()
|
||||
self.__share_config = share_config
|
||||
self.__fail2ban = Fail2banReader(share_config=share_config)
|
||||
self.__jails = JailsReader(force_enable=force_enable, share_config=share_config)
|
||||
|
||||
def Reload(self):
|
||||
# clear all shared handlers:
|
||||
self.__share_config.clear()
|
||||
|
||||
def setBaseDir(self, folderName):
|
||||
self.__fail2ban.setBaseDir(folderName)
|
||||
self.__jails.setBaseDir(folderName)
|
||||
|
|
|
@ -57,7 +57,7 @@ class CSocket:
|
|||
self.__csock.close()
|
||||
return ret
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def receive(sock):
|
||||
msg = EMPTY_BYTES
|
||||
while msg.rfind(CSocket.END_STRING) == -1:
|
||||
|
@ -66,4 +66,3 @@ class CSocket:
|
|||
raise RuntimeError, "socket connection broken"
|
||||
msg = msg + chunk
|
||||
return loads(msg)
|
||||
receive = staticmethod(receive)
|
||||
|
|
|
@ -26,7 +26,7 @@ __license__ = "GPL"
|
|||
|
||||
import os, shlex
|
||||
|
||||
from .configreader import ConfigReader, DefinitionInitConfigReader
|
||||
from .configreader import DefinitionInitConfigReader
|
||||
from ..server.action import CommandAction
|
||||
from ..helpers import getLogger
|
||||
|
||||
|
@ -40,8 +40,12 @@ class FilterReader(DefinitionInitConfigReader):
|
|||
["string", "failregex", ""],
|
||||
]
|
||||
|
||||
def read(self):
|
||||
return ConfigReader.read(self, os.path.join("filter.d", self._file))
|
||||
def setFile(self, fileName):
|
||||
self.__file = fileName
|
||||
DefinitionInitConfigReader.setFile(self, os.path.join("filter.d", fileName))
|
||||
|
||||
def getFile(self):
|
||||
return self.__file
|
||||
|
||||
def convert(self):
|
||||
stream = list()
|
||||
|
|
|
@ -27,7 +27,7 @@ __license__ = "GPL"
|
|||
import re, glob, os.path
|
||||
import json
|
||||
|
||||
from .configreader import ConfigReader
|
||||
from .configreader import ConfigReaderUnshared, ConfigReader
|
||||
from .filterreader import FilterReader
|
||||
from .actionreader import ActionReader
|
||||
from ..helpers import getLogger
|
||||
|
@ -111,7 +111,7 @@ class JailReader(ConfigReader):
|
|||
filterName, filterOpt = JailReader.extractOptions(
|
||||
self.__opts["filter"])
|
||||
self.__filter = FilterReader(
|
||||
filterName, self.__name, filterOpt, basedir=self.getBaseDir())
|
||||
filterName, self.__name, filterOpt, share_config=self.share_config, basedir=self.getBaseDir())
|
||||
ret = self.__filter.read()
|
||||
if ret:
|
||||
self.__filter.getOptions(self.__opts)
|
||||
|
@ -141,7 +141,7 @@ class JailReader(ConfigReader):
|
|||
else:
|
||||
action = ActionReader(
|
||||
actName, self.__name, actOpt,
|
||||
basedir=self.getBaseDir())
|
||||
share_config=self.share_config, basedir=self.getBaseDir())
|
||||
ret = action.read()
|
||||
if ret:
|
||||
action.getOptions(self.__opts)
|
||||
|
@ -213,14 +213,14 @@ class JailReader(ConfigReader):
|
|||
if self.__filter:
|
||||
stream.extend(self.__filter.convert())
|
||||
for action in self.__actions:
|
||||
if isinstance(action, ConfigReader):
|
||||
if isinstance(action, (ConfigReaderUnshared, ConfigReader)):
|
||||
stream.extend(action.convert())
|
||||
else:
|
||||
stream.append(action)
|
||||
stream.insert(0, ["add", self.__name, backend])
|
||||
return stream
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def extractOptions(option):
|
||||
match = JailReader.optionCRE.match(option)
|
||||
if not match:
|
||||
|
@ -235,4 +235,3 @@ class JailReader(ConfigReader):
|
|||
val for val in optmatch.group(2,3,4) if val is not None][0]
|
||||
option_opts[opt.strip()] = value.strip()
|
||||
return option_name, option_opts
|
||||
extractOptions = staticmethod(extractOptions)
|
||||
|
|
|
@ -68,9 +68,10 @@ class JailsReader(ConfigReader):
|
|||
for sec in sections:
|
||||
if sec == 'INCLUDES':
|
||||
continue
|
||||
jail = JailReader(sec, basedir=self.getBaseDir(),
|
||||
force_enable=self.__force_enable)
|
||||
jail.read()
|
||||
# use the cfg_share for filter/action caching and the same config for all
|
||||
# jails (use_config=...), therefore don't read it here:
|
||||
jail = JailReader(sec, force_enable=self.__force_enable,
|
||||
share_config=self.share_config, use_config=self._cfg)
|
||||
ret = jail.getOptions()
|
||||
if ret:
|
||||
if jail.isEnabled():
|
||||
|
|
|
@ -149,12 +149,8 @@ class AsyncServer(asyncore.dispatcher):
|
|||
self.__init = True
|
||||
# TODO Add try..catch
|
||||
# There's a bug report for Python 2.6/3.0 that use_poll=True yields some 2.5 incompatibilities:
|
||||
if sys.version_info >= (2, 6): # if python 2.6 or greater...
|
||||
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
|
||||
asyncore.loop(use_poll = False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
||||
else: # pragma: no cover
|
||||
logSys.debug("NOT Python 2.6/3.* - asyncore.loop() using poll")
|
||||
asyncore.loop(use_poll = True)
|
||||
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
|
||||
asyncore.loop(use_poll=False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
||||
|
||||
##
|
||||
# Stops the communication server.
|
||||
|
@ -175,12 +171,11 @@ class AsyncServer(asyncore.dispatcher):
|
|||
|
||||
# @param sock: socket file.
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def __markCloseOnExec(sock):
|
||||
fd = sock.fileno()
|
||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags|fcntl.FD_CLOEXEC)
|
||||
__markCloseOnExec = staticmethod(__markCloseOnExec)
|
||||
|
||||
##
|
||||
# AsyncServerException is used to wrap communication exceptions.
|
||||
|
|
|
@ -126,7 +126,7 @@ class BanManager:
|
|||
# @param ticket the FailTicket
|
||||
# @return a BanTicket
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def createBanTicket(ticket):
|
||||
ip = ticket.getIP()
|
||||
#lastTime = ticket.getTime()
|
||||
|
@ -134,7 +134,6 @@ class BanManager:
|
|||
banTicket = BanTicket(ip, lastTime, ticket.getMatches())
|
||||
banTicket.setAttempt(ticket.getAttempt())
|
||||
return banTicket
|
||||
createBanTicket = staticmethod(createBanTicket)
|
||||
|
||||
##
|
||||
# Add a ban ticket.
|
||||
|
|
|
@ -838,7 +838,7 @@ class DNSUtils:
|
|||
|
||||
IP_CRE = re.compile("^(?:\d{1,3}\.){3}\d{1,3}$")
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def dnsToIp(dns):
|
||||
""" Convert a DNS into an IP address using the Python socket module.
|
||||
Thanks to Kevin Drapel.
|
||||
|
@ -853,9 +853,8 @@ class DNSUtils:
|
|||
logSys.warning("Socket error raised trying to resolve hostname %s: %s"
|
||||
% (dns, e))
|
||||
return list()
|
||||
dnsToIp = staticmethod(dnsToIp)
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def searchIP(text):
|
||||
""" Search if an IP address if directly available and return
|
||||
it.
|
||||
|
@ -865,9 +864,8 @@ class DNSUtils:
|
|||
return match
|
||||
else:
|
||||
return None
|
||||
searchIP = staticmethod(searchIP)
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def isValidIP(string):
|
||||
""" Return true if str is a valid IP
|
||||
"""
|
||||
|
@ -877,9 +875,8 @@ class DNSUtils:
|
|||
return True
|
||||
except socket.error:
|
||||
return False
|
||||
isValidIP = staticmethod(isValidIP)
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def textToIp(text, useDns):
|
||||
""" Return the IP of DNS found in a given text.
|
||||
"""
|
||||
|
@ -901,9 +898,8 @@ class DNSUtils:
|
|||
text, ipList)
|
||||
|
||||
return ipList
|
||||
textToIp = staticmethod(textToIp)
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def cidr(i, n):
|
||||
""" Convert an IP address string with a CIDR mask into a 32-bit
|
||||
integer.
|
||||
|
@ -911,18 +907,15 @@ class DNSUtils:
|
|||
# 32-bit IPv4 address mask
|
||||
MASK = 0xFFFFFFFFL
|
||||
return ~(MASK >> n) & MASK & DNSUtils.addr2bin(i)
|
||||
cidr = staticmethod(cidr)
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def addr2bin(string):
|
||||
""" Convert a string IPv4 address into an unsigned integer.
|
||||
"""
|
||||
return struct.unpack("!L", socket.inet_aton(string))[0]
|
||||
addr2bin = staticmethod(addr2bin)
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def bin2addr(addr):
|
||||
""" Convert a numeric IPv4 address into string n.n.n.n form.
|
||||
"""
|
||||
return socket.inet_ntoa(struct.pack("!L", addr))
|
||||
bin2addr = staticmethod(bin2addr)
|
||||
|
|
|
@ -26,65 +26,71 @@ import time, datetime
|
|||
##
|
||||
# MyTime class.
|
||||
#
|
||||
# This class is a wrapper around time.time() and time.gmtime(). When
|
||||
# performing unit test, it is very useful to get a fixed value from these
|
||||
# functions.
|
||||
# Thus, time.time() and time.gmtime() should never be called directly.
|
||||
# This wrapper should be called instead. The API are equivalent.
|
||||
|
||||
class MyTime:
|
||||
|
||||
"""A wrapper around time module primarily for testing purposes
|
||||
|
||||
This class is a wrapper around time.time() and time.gmtime(). When
|
||||
performing unit test, it is very useful to get a fixed value from
|
||||
these functions. Thus, time.time() and time.gmtime() should never
|
||||
be called directly. This wrapper should be called instead. The API
|
||||
are equivalent.
|
||||
"""
|
||||
|
||||
myTime = None
|
||||
|
||||
##
|
||||
# Sets the current time.
|
||||
#
|
||||
# Use None in order to always get the real current time.
|
||||
#
|
||||
# @param t the time to set or None
|
||||
|
||||
#@staticmethod
|
||||
|
||||
@staticmethod
|
||||
def setTime(t):
|
||||
"""Set current time.
|
||||
|
||||
Use None in order to always get the real current time.
|
||||
|
||||
@param t the time to set or None
|
||||
"""
|
||||
|
||||
MyTime.myTime = t
|
||||
setTime = staticmethod(setTime)
|
||||
|
||||
##
|
||||
# Equivalent to time.time()
|
||||
#
|
||||
# @return time.time() if setTime was called with None
|
||||
|
||||
#@staticmethod
|
||||
|
||||
@staticmethod
|
||||
def time():
|
||||
"""Decorate time.time() for the purpose of testing mocking
|
||||
|
||||
@return time.time() if setTime was called with None
|
||||
"""
|
||||
|
||||
if MyTime.myTime is None:
|
||||
return time.time()
|
||||
else:
|
||||
return MyTime.myTime
|
||||
time = staticmethod(time)
|
||||
|
||||
##
|
||||
# Equivalent to time.gmtime()
|
||||
#
|
||||
# @return time.gmtime() if setTime was called with None
|
||||
|
||||
#@staticmethod
|
||||
|
||||
@staticmethod
|
||||
def gmtime():
|
||||
"""Decorate time.gmtime() for the purpose of testing mocking
|
||||
|
||||
@return time.gmtime() if setTime was called with None
|
||||
"""
|
||||
if MyTime.myTime is None:
|
||||
return time.gmtime()
|
||||
else:
|
||||
return time.gmtime(MyTime.myTime)
|
||||
gmtime = staticmethod(gmtime)
|
||||
|
||||
#@staticmethod
|
||||
@staticmethod
|
||||
def now():
|
||||
"""Decorate datetime.now() for the purpose of testing mocking
|
||||
|
||||
@return datetime.now() if setTime was called with None
|
||||
"""
|
||||
if MyTime.myTime is None:
|
||||
return datetime.datetime.now()
|
||||
else:
|
||||
return datetime.datetime.fromtimestamp(MyTime.myTime)
|
||||
now = staticmethod(now)
|
||||
|
||||
@staticmethod
|
||||
def localtime(x=None):
|
||||
"""Decorate time.localtime() for the purpose of testing mocking
|
||||
|
||||
@return time.localtime() if setTime was called with None
|
||||
"""
|
||||
if MyTime.myTime is None or x is not None:
|
||||
return time.localtime(x)
|
||||
else:
|
||||
return time.localtime(MyTime.myTime)
|
||||
localtime = staticmethod(localtime)
|
||||
|
|
|
@ -186,8 +186,10 @@ class CommandActionTest(LogCaptureTestCase):
|
|||
# Should take a minute
|
||||
self.assertRaises(
|
||||
RuntimeError, CommandAction.executeCmd, 'sleep 60', timeout=2)
|
||||
self.assertAlmostEqual(time.time() - stime, 2, places=0)
|
||||
self.assertTrue(self._is_logged('sleep 60 -- timed out after 2 seconds'))
|
||||
# give a test still 1 second, because system could be too busy
|
||||
self.assertTrue(time.time() >= stime + 2 and time.time() <= stime + 3)
|
||||
self.assertTrue(self._is_logged('sleep 60 -- timed out after 2 seconds')
|
||||
or self._is_logged('sleep 60 -- timed out after 3 seconds'))
|
||||
self.assertTrue(self._is_logged('sleep 60 -- killed with SIGTERM'))
|
||||
|
||||
def testCaptureStdOutErr(self):
|
||||
|
|
|
@ -21,9 +21,9 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import os, glob, shutil, tempfile, unittest
|
||||
|
||||
from ..client.configreader import ConfigReader
|
||||
import os, glob, shutil, tempfile, unittest, re, logging
|
||||
from ..client.configreader import ConfigReaderUnshared
|
||||
from ..client import configparserinc
|
||||
from ..client.jailreader import JailReader
|
||||
from ..client.filterreader import FilterReader
|
||||
from ..client.jailsreader import JailsReader
|
||||
|
@ -44,7 +44,7 @@ class ConfigReaderTest(unittest.TestCase):
|
|||
def setUp(self):
|
||||
"""Call before every test case."""
|
||||
self.d = tempfile.mkdtemp(prefix="f2b-temp")
|
||||
self.c = ConfigReader(basedir=self.d)
|
||||
self.c = ConfigReaderUnshared(basedir=self.d)
|
||||
|
||||
def tearDown(self):
|
||||
"""Call after every test case."""
|
||||
|
@ -334,6 +334,80 @@ class FilterReaderTest(unittest.TestCase):
|
|||
filterReader.getOptions(None)
|
||||
self.assertRaises(ValueError, FilterReader.convert, filterReader)
|
||||
|
||||
def testFilterReaderExplicit(self):
|
||||
# read explicit uses absolute path:
|
||||
path_ = os.path.abspath(os.path.join(TEST_FILES_DIR, "filter.d"))
|
||||
filterReader = FilterReader(os.path.join(path_, "testcase01.conf"), "testcase01", {})
|
||||
self.assertEqual(filterReader.readexplicit(),
|
||||
[os.path.join(path_, "testcase-common.conf"), os.path.join(path_, "testcase01.conf")]
|
||||
)
|
||||
try:
|
||||
filterReader.getOptions(None)
|
||||
# from included common
|
||||
filterReader.get('Definition', '__prefix_line')
|
||||
# from testcase01
|
||||
filterReader.get('Definition', 'failregex')
|
||||
filterReader.get('Definition', 'ignoreregex')
|
||||
except Exception, e: # pragma: no cover - failed if reachable
|
||||
self.fail('unexpected options after readexplicit: %s' % (e))
|
||||
|
||||
class JailsReaderTestCache(LogCaptureTestCase):
|
||||
|
||||
def _readWholeConf(self, basedir, force_enable=False, share_config=None):
|
||||
# read whole configuration like a file2ban-client ...
|
||||
configurator = Configurator(force_enable=force_enable, share_config=share_config)
|
||||
configurator.setBaseDir(basedir)
|
||||
configurator.readEarly()
|
||||
configurator.getEarlyOptions()
|
||||
configurator.readAll()
|
||||
# from here we test a cache with all includes / before / after :
|
||||
self.assertTrue(configurator.getOptions(None))
|
||||
|
||||
def _getLoggedReadCount(self, filematch):
|
||||
cnt = 0
|
||||
for s in self.getLog().rsplit('\n'):
|
||||
if re.match(r"^\s*Reading files?: .*/"+filematch, s):
|
||||
cnt += 1
|
||||
return cnt
|
||||
|
||||
def testTestJailConfCache(self):
|
||||
saved_ll = configparserinc.logLevel
|
||||
configparserinc.logLevel = logging.DEBUG
|
||||
basedir = tempfile.mkdtemp("fail2ban_conf")
|
||||
try:
|
||||
shutil.rmtree(basedir)
|
||||
shutil.copytree(CONFIG_DIR, basedir)
|
||||
shutil.copy(CONFIG_DIR + '/jail.conf', basedir + '/jail.local')
|
||||
shutil.copy(CONFIG_DIR + '/fail2ban.conf', basedir + '/fail2ban.local')
|
||||
|
||||
# common sharing handle for this test:
|
||||
share_cfg = dict()
|
||||
|
||||
# read whole configuration like a file2ban-client ...
|
||||
self._readWholeConf(basedir, share_config=share_cfg)
|
||||
# how many times jail.local was read:
|
||||
cnt = self._getLoggedReadCount('jail.local')
|
||||
# if cnt > 1:
|
||||
# self.printLog()
|
||||
self.assertTrue(cnt == 1, "Unexpected count by reading of jail files, cnt = %s" % cnt)
|
||||
|
||||
# read whole configuration like a file2ban-client, again ...
|
||||
# but this time force enable all jails, to check filter and action cached also:
|
||||
self._readWholeConf(basedir, force_enable=True, share_config=share_cfg)
|
||||
cnt = self._getLoggedReadCount(r'jail\.local')
|
||||
# still one (no more reads):
|
||||
self.assertTrue(cnt == 1, "Unexpected count by second reading of jail files, cnt = %s" % cnt)
|
||||
|
||||
# same with filter:
|
||||
cnt = self._getLoggedReadCount(r'filter\.d/common\.conf')
|
||||
self.assertTrue(cnt == 1, "Unexpected count by reading of filter files, cnt = %s" % cnt)
|
||||
# same with action:
|
||||
cnt = self._getLoggedReadCount(r'action\.d/iptables-common\.conf')
|
||||
self.assertTrue(cnt == 1, "Unexpected count by reading of action files, cnt = %s" % cnt)
|
||||
finally:
|
||||
shutil.rmtree(basedir)
|
||||
configparserinc.logLevel = saved_ll
|
||||
|
||||
|
||||
class JailsReaderTest(LogCaptureTestCase):
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ class DateDetectorTest(unittest.TestCase):
|
|||
(False, "23-Jan-2005 21:59:59.02"),
|
||||
(False, "23-Jan-2005 21:59:59 +0100"),
|
||||
(False, "23-01-2005 21:59:59"),
|
||||
(True, "1106513999"), # Portsetry
|
||||
(False, "01-23-2005 21:59:59.252"), # reported on f2b, causes Feb29 fix to break
|
||||
(False, "@4000000041f4104f00000000"), # TAI64N
|
||||
(False, "2005-01-23T20:59:59.252Z"), #ISO 8601 (UTC)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# failJSON: { "time": "2014-06-27T17:51:19", "match": true , "host": "192.168.56.1" }
|
||||
1403884279 - 06/27/2014 17:51:19 Host: 192.168.56.1/192.168.56.1 Port: 1 TCP Blocked
|
||||
# failJSON: { "time": "2014-06-27T17:51:19", "match": true , "host": "192.168.56.1" }
|
||||
1403884279 - 06/27/2014 17:51:19 Host: 192.168.56.1/192.168.56.1 Port: 1 UDP Blocked
|
|
@ -24,11 +24,7 @@ __license__ = "GPL"
|
|||
|
||||
import unittest, sys, os, fileinput, re, time, datetime, inspect
|
||||
|
||||
if sys.version_info >= (2, 6):
|
||||
import json
|
||||
else:
|
||||
import simplejson as json
|
||||
next = lambda x: x.next()
|
||||
import json
|
||||
|
||||
from ..server.filter import Filter
|
||||
from ..client.filterreader import FilterReader
|
||||
|
|
|
@ -25,6 +25,7 @@ __license__ = "GPL"
|
|||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
from StringIO import StringIO
|
||||
|
@ -111,6 +112,7 @@ def gatherTests(regexps=None, no_network=False):
|
|||
tests.addTest(unittest.makeSuite(clientreadertestcase.JailReaderTest))
|
||||
tests.addTest(unittest.makeSuite(clientreadertestcase.FilterReaderTest))
|
||||
tests.addTest(unittest.makeSuite(clientreadertestcase.JailsReaderTest))
|
||||
tests.addTest(unittest.makeSuite(clientreadertestcase.JailsReaderTestCache))
|
||||
# CSocket and AsyncServer
|
||||
tests.addTest(unittest.makeSuite(sockettestcase.Socket))
|
||||
# Misc helpers
|
||||
|
@ -204,6 +206,8 @@ class LogCaptureTestCase(unittest.TestCase):
|
|||
# Let's log everything into a string
|
||||
self._log = StringIO()
|
||||
logSys.handlers = [logging.StreamHandler(self._log)]
|
||||
if self._old_level < logging.DEBUG: # so if HEAVYDEBUG etc -- show them!
|
||||
logSys.handlers += self._old_handlers
|
||||
logSys.setLevel(getattr(logging, 'DEBUG'))
|
||||
|
||||
def tearDown(self):
|
||||
|
@ -216,5 +220,8 @@ class LogCaptureTestCase(unittest.TestCase):
|
|||
def _is_logged(self, s):
|
||||
return s in self._log.getvalue()
|
||||
|
||||
def getLog(self):
|
||||
return self._log.getvalue()
|
||||
|
||||
def printLog(self):
|
||||
print(self._log.getvalue())
|
||||
|
|
|
@ -24,4 +24,4 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko, Steven Hiscocks, Daniel Black"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2014 Yaroslav Halchenko, 2013-2013 Steven Hiscocks, Daniel Black"
|
||||
__license__ = "GPL-v2+"
|
||||
|
||||
version = "0.9.0.dev"
|
||||
version = "0.9.1"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.41.2.
|
||||
.TH FAIL2BAN-CLIENT "1" "March 2014" "fail2ban-client v0.9.0" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
|
||||
.TH FAIL2BAN-CLIENT "1" "October 2014" "fail2ban-client v0.9.1" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-client \- configure and control the server
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-client
|
||||
[\fIOPTIONS\fR] \fI<COMMAND>\fR
|
||||
[\fI\,OPTIONS\/\fR] \fI\,<COMMAND>\/\fR
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.9.0 reads log file that contains password failure report
|
||||
Fail2Ban v0.9.1 reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
|
@ -35,10 +35,10 @@ decrease verbosity
|
|||
force execution of the server (remove socket file)
|
||||
.TP
|
||||
\fB\-b\fR
|
||||
start the server in background mode (default)
|
||||
start server in background (default)
|
||||
.TP
|
||||
\fB\-f\fR
|
||||
start the server in foreground mode (note that the client forks once itself)
|
||||
start server in foreground (note that the client forks once itself)
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
display this help message
|
||||
|
@ -217,9 +217,8 @@ for <JAIL>
|
|||
\fBset <JAIL> maxlines <LINES>\fR
|
||||
sets the number of <LINES> to
|
||||
buffer for regex search for <JAIL>
|
||||
.IP
|
||||
set <JAIL> addaction <ACT>[ <PYTHONFILE> <JSONKWARGS>]
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> addaction <ACT>[ <PYTHONFILE> <JSONKWARGS>]\fR
|
||||
adds a new action named <NAME> for
|
||||
<JAIL>. Optionally for a Python
|
||||
based action, a <PYTHONFILE> and
|
||||
|
@ -231,45 +230,38 @@ removes the action <ACT> from
|
|||
<JAIL>
|
||||
.IP
|
||||
COMMAND ACTION CONFIGURATION
|
||||
.IP
|
||||
set <JAIL> action <ACT> actionstart <CMD>
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionstart <CMD>\fR
|
||||
sets the start command <CMD> of
|
||||
the action <ACT> for <JAIL>
|
||||
.IP
|
||||
set <JAIL> action <ACT> actionstop <CMD> sets the stop command <CMD> of the
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionstop <CMD> sets the stop command <CMD> of the\fR
|
||||
action <ACT> for <JAIL>
|
||||
.IP
|
||||
set <JAIL> action <ACT> actioncheck <CMD>
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actioncheck <CMD>\fR
|
||||
sets the check command <CMD> of
|
||||
the action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionban <CMD>\fR
|
||||
sets the ban command <CMD> of the
|
||||
action <ACT> for <JAIL>
|
||||
.IP
|
||||
set <JAIL> action <ACT> actionunban <CMD>
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> actionunban <CMD>\fR
|
||||
sets the unban command <CMD> of
|
||||
the action <ACT> for <JAIL>
|
||||
.IP
|
||||
set <JAIL> action <ACT> timeout <TIMEOUT>
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> timeout <TIMEOUT>\fR
|
||||
sets <TIMEOUT> as the command
|
||||
timeout in seconds for the action
|
||||
<ACT> for <JAIL>
|
||||
.IP
|
||||
GENERAL ACTION CONFIGURATION
|
||||
.IP
|
||||
set <JAIL> action <ACT> <PROPERTY> <VALUE>
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> <PROPERTY> <VALUE>\fR
|
||||
sets the <VALUE> of <PROPERTY> for
|
||||
the action <ACT> for <JAIL>
|
||||
.IP
|
||||
set <JAIL> action <ACT> <METHOD>[ <JSONKWARGS>]
|
||||
.IP
|
||||
.TP
|
||||
\fBset <JAIL> action <ACT> <METHOD>[ <JSONKWARGS>]\fR
|
||||
calls the <METHOD> with
|
||||
<JSONKWARGS> for the action <ACT>
|
||||
for <JAIL>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.41.2.
|
||||
.TH FAIL2BAN-REGEX "1" "March 2014" "fail2ban-regex 0.9.0" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
|
||||
.TH FAIL2BAN-REGEX "1" "October 2014" "fail2ban-regex 0.9.1" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-regex \- test Fail2ban "failregex" option
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-regex
|
||||
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
|
||||
[\fI\,OPTIONS\/\fR] \fI\,<LOG> <REGEX> \/\fR[\fI\,IGNOREREGEX\/\fR]
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
|
@ -16,7 +16,7 @@ string
|
|||
a string representing a log line
|
||||
.TP
|
||||
filename
|
||||
path to a log file (\fI/var/log/auth.log\fP)
|
||||
path to a log file (\fI\,/var/log/auth.log\/\fP)
|
||||
.TP
|
||||
"systemd\-journal"
|
||||
search systemd journal (systemd\-python required)
|
||||
|
@ -42,20 +42,20 @@ show program's version number and exit
|
|||
\fB\-h\fR, \fB\-\-help\fR
|
||||
show this help message and exit
|
||||
.TP
|
||||
\fB\-d\fR DATEPATTERN, \fB\-\-datepattern\fR=\fIDATEPATTERN\fR
|
||||
\fB\-d\fR DATEPATTERN, \fB\-\-datepattern\fR=\fI\,DATEPATTERN\/\fR
|
||||
set custom pattern used to match date/times
|
||||
.TP
|
||||
\fB\-e\fR ENCODING, \fB\-\-encoding\fR=\fIENCODING\fR
|
||||
\fB\-e\fR ENCODING, \fB\-\-encoding\fR=\fI\,ENCODING\/\fR
|
||||
File encoding. Default: system locale
|
||||
.TP
|
||||
\fB\-L\fR MAXLINES, \fB\-\-maxlines\fR=\fIMAXLINES\fR
|
||||
\fB\-L\fR MAXLINES, \fB\-\-maxlines\fR=\fI\,MAXLINES\/\fR
|
||||
maxlines for multi\-line regex
|
||||
.TP
|
||||
\fB\-m\fR JOURNALMATCH, \fB\-\-journalmatch\fR=\fIJOURNALMATCH\fR
|
||||
\fB\-m\fR JOURNALMATCH, \fB\-\-journalmatch\fR=\fI\,JOURNALMATCH\/\fR
|
||||
journalctl style matches overriding filter file.
|
||||
"systemd\-journal" only
|
||||
.TP
|
||||
\fB\-l\fR LOG_LEVEL, \fB\-\-log\-level\fR=\fILOG_LEVEL\fR
|
||||
\fB\-l\fR LOG_LEVEL, \fB\-\-log\-level\fR=\fI\,LOG_LEVEL\/\fR
|
||||
Log level for the Fail2Ban logger to use
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
|
@ -70,6 +70,9 @@ Do not print any missed lines
|
|||
\fB\-\-print\-no\-ignored\fR
|
||||
Do not print any ignored lines
|
||||
.TP
|
||||
\fB\-\-print\-all\-matched\fR
|
||||
Print all matched lines
|
||||
.TP
|
||||
\fB\-\-print\-all\-missed\fR
|
||||
Print all missed lines, no matter how many
|
||||
.TP
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.41.2.
|
||||
.TH FAIL2BAN-SERVER "1" "March 2014" "fail2ban-server v0.9.0" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.4.
|
||||
.TH FAIL2BAN-SERVER "1" "October 2014" "fail2ban-server v0.9.1" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-server \- start the server
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-server
|
||||
[\fIOPTIONS\fR]
|
||||
[\fI\,OPTIONS\/\fR]
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.9.0 reads log file that contains password failure report
|
||||
Fail2Ban v0.9.1 reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
.PP
|
||||
Only use this command for debugging purpose. Start the server with
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
export PYTHONPATH=..
|
||||
|
||||
# fail2ban-client
|
||||
echo -n "Generating fail2ban-client "
|
||||
help2man --section=1 --no-info --include=fail2ban-client.h2m --output fail2ban-client.1 ../bin/fail2ban-client
|
||||
|
|
Loading…
Reference in New Issue