mirror of https://github.com/fail2ban/fail2ban
ver. 0.9.3 (2015/08/01) - lets-all-stay-friends
---------- - IMPORTANT incompatible changes: * filter.d/roundcube-auth.conf - Changed logpath to 'errors' log (was 'userlogins') * action.d/iptables-common.conf - All calls to iptables command now use -w switch introduced in iptables 1.4.20 (some distribution could have patched their earlier base version as well) to provide this locking mechanism useful under heavy load to avoid contesting on iptables calls. If you need to disable, define 'action.d/iptables-common.local' with empty value for 'lockingopt' in `[Init]` section. * mail-whois-lines, sendmail-geoip-lines and sendmail-whois-lines actions now include by default only the first 1000 log lines in the emails. Adjust <grepopts> to augment the behavior. - Fixes: * reload in interactive mode appends all the jails twice (gh-825) * reload server/jail failed if database used (but was not changed) and some jail active (gh-1072) * filter.d/dovecot.conf - also match unknown user in passwd-file. Thanks Anton Shestakov * Fix fail2ban-regex not parsing journalmatch correctly from filter config * filter.d/asterisk.conf - fix security log support for Asterisk 12+ * filter.d/roundcube-auth.conf - Updated regex to work with 'errors' log (1.0.5 and 1.1.1) - Added regex to work with 'userlogins' log * action.d/sendmail*.conf - use LC_ALL (superseeding LC_TIME) to override locale on systems with customized LC_ALL * performance fix: minimizes connection overhead, close socket only at communication end (gh-1099) * unbanip always deletes ip from database (independent of bantime, also if currently not banned or persistent) * guarantee order of dbfile to be before dbpurgeage (gh-1048) * always set 'dbfile' before other database options (gh-1050) * kill the entire process group of the child process upon timeout (gh-1129). Otherwise could lead to resource exhaustion due to hanging whois processes. * resolve /var/run/fail2ban path in setup.py to help installation on platforms with /var/run -> /run symlink (gh-1142) - New Features: * RETURN iptables target is now a variable: <returntype> * New type of operation: pass2allow, use fail2ban for "knocking", opening a closed port by swapping blocktype and returntype * New filters: - froxlor-auth - Thanks Joern Muehlencord - apache-pass - filter Apache access log for successful authentication * New actions: - shorewall-ipset-proto6 - using proto feature of the Shorewall. Still requires manual pre-configuration of the shorewall. See the action file for detail. * New jails: - pass2allow-ftp - allows FTP traffic after successful HTTP authentication - Enhancements: * action.d/cloudflare.conf - improved documentation on how to allow multiple CF accounts, and jail.conf got new compound action definition action_cf_mwl to submit cloudflare report. * Check access to socket for more detailed logging on error (gh-595) * fail2ban-testcases man page * filter.d/apache-badbots.conf, filter.d/nginx-botsearch.conf - add HEAD method verb * Revamp of Travis and coverage automated testing * Added a space between IP address and the following colon in notification emails for easier text selection * Character detection heuristics for whois output via optional setting in mail-whois*.conf. Thanks Thomas Mayer. Not enabled by default, if _whois_command is set to be %(_whois_convert_charset)s (e.g. in action.d/mail-whois-common.local), it - detects character set of whois output (which is undefined by RFC 3912) via heuristics of the file command - converts whois data to UTF-8 character set with iconv - sends the whois output in UTF-8 character set to mail program - avoids that heirloom mailx creates binary attachment for input with unknown character set -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAlW8IeUACgkQjRFFY3XAJMh0agCfXXoSyOQJpf3j0hA052Yxyhr9 bSIAnA56k7DdZaqT//EvPvCugAEYPWvp =Vo7B -----END PGP SIGNATURE----- Merge tag '0.9.3' into debian ver. 0.9.3 (2015/08/01) - lets-all-stay-friends ---------- - IMPORTANT incompatible changes: * filter.d/roundcube-auth.conf - Changed logpath to 'errors' log (was 'userlogins') * action.d/iptables-common.conf - All calls to iptables command now use -w switch introduced in iptables 1.4.20 (some distribution could have patched their earlier base version as well) to provide this locking mechanism useful under heavy load to avoid contesting on iptables calls. If you need to disable, define 'action.d/iptables-common.local' with empty value for 'lockingopt' in `[Init]` section. * mail-whois-lines, sendmail-geoip-lines and sendmail-whois-lines actions now include by default only the first 1000 log lines in the emails. Adjust <grepopts> to augment the behavior. - Fixes: * reload in interactive mode appends all the jails twice (gh-825) * reload server/jail failed if database used (but was not changed) and some jail active (gh-1072) * filter.d/dovecot.conf - also match unknown user in passwd-file. Thanks Anton Shestakov * Fix fail2ban-regex not parsing journalmatch correctly from filter config * filter.d/asterisk.conf - fix security log support for Asterisk 12+ * filter.d/roundcube-auth.conf - Updated regex to work with 'errors' log (1.0.5 and 1.1.1) - Added regex to work with 'userlogins' log * action.d/sendmail*.conf - use LC_ALL (superseeding LC_TIME) to override locale on systems with customized LC_ALL * performance fix: minimizes connection overhead, close socket only at communication end (gh-1099) * unbanip always deletes ip from database (independent of bantime, also if currently not banned or persistent) * guarantee order of dbfile to be before dbpurgeage (gh-1048) * always set 'dbfile' before other database options (gh-1050) * kill the entire process group of the child process upon timeout (gh-1129). Otherwise could lead to resource exhaustion due to hanging whois processes. * resolve /var/run/fail2ban path in setup.py to help installation on platforms with /var/run -> /run symlink (gh-1142) - New Features: * RETURN iptables target is now a variable: <returntype> * New type of operation: pass2allow, use fail2ban for "knocking", opening a closed port by swapping blocktype and returntype * New filters: - froxlor-auth - Thanks Joern Muehlencord - apache-pass - filter Apache access log for successful authentication * New actions: - shorewall-ipset-proto6 - using proto feature of the Shorewall. Still requires manual pre-configuration of the shorewall. See the action file for detail. * New jails: - pass2allow-ftp - allows FTP traffic after successful HTTP authentication - Enhancements: * action.d/cloudflare.conf - improved documentation on how to allow multiple CF accounts, and jail.conf got new compound action definition action_cf_mwl to submit cloudflare report. * Check access to socket for more detailed logging on error (gh-595) * fail2ban-testcases man page * filter.d/apache-badbots.conf, filter.d/nginx-botsearch.conf - add HEAD method verb * Revamp of Travis and coverage automated testing * Added a space between IP address and the following colon in notification emails for easier text selection * Character detection heuristics for whois output via optional setting in mail-whois*.conf. Thanks Thomas Mayer. Not enabled by default, if _whois_command is set to be %(_whois_convert_charset)s (e.g. in action.d/mail-whois-common.local), it - detects character set of whois output (which is undefined by RFC 3912) via heuristics of the file command - converts whois data to UTF-8 character set with iconv - sends the whois output in UTF-8 character set to mail program - avoids that heirloom mailx creates binary attachment for input with unknown character set * tag '0.9.3': (99 commits) Release changes (too much of manual "labor"! ;)) BF: realpath for /var/run/fail2ban Closes #1142 Changelog entry for killpg fix Changelog entries for Serge's fixes bug fix: option 'dbpurgeage' was never set (always default) by start of fail2ban, because of invalid sorting of options ('dbfile' should be always set before other database options) / closes #1048, closes #1050 BF: guarantee order of dbfile to be before dbpurgeage (Closes #1048) DOC: Changelog for shorewall-ipset-proto6.conf + adjusted its description DOC: moved and adjusted changelog entry from 0.9.2 within 0.9.3 to come TST: test to verify killing stuck children processes BF: kill the entire process group upon timeout (Close #1129) Limit the number of log lines in *-lines.conf actions ipjailmatches is on one line with its description in man jail.conf DOC: Changelog for iptables -w change Remove self.printlog() call Remove literal "TODO" from method's name BF: do not wrap iptables into itself. Thanks Lee Added a space between IP address and the following colon BF: symbiosis-blacklist-allports now also requires iptables-common.conf RF: use <iptables> to take effect of it being a parameter ENH: added lockingopt option for iptables actions, made iptables cmd itself a parameter ...pull/1858/head
commit
bceb35ab34
|
@ -1,4 +1,11 @@
|
|||
|
||||
[run]
|
||||
branch = True
|
||||
omit = /usr*
|
||||
source =
|
||||
config
|
||||
fail2ban
|
||||
|
||||
[report]
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
pragma: systemd no cover
|
||||
|
|
67
.travis.yml
67
.travis.yml
|
@ -1,29 +1,56 @@
|
|||
# vim ft=yaml
|
||||
# travis-ci.org definition for Fail2Ban build
|
||||
# https://travis-ci.org/fail2ban/fail2ban/
|
||||
language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.2"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "pypy"
|
||||
- "pypy3"
|
||||
- 2.6
|
||||
- 2.7
|
||||
- pypy
|
||||
- 3.2
|
||||
- 3.3
|
||||
- 3.4
|
||||
- pypy3
|
||||
before_install:
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then travis_retry sudo apt-get update -qq; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then export F2B_PY_2=true && echo "Set F2B_PY_2"; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 3* || $TRAVIS_PYTHON_VERSION == 'pypy3' ]]; then export F2B_PY_3=true && echo "Set F2B_PY_3"; fi
|
||||
- travis_retry sudo apt-get update -qq
|
||||
# Set this so sudo executes the correct python binary
|
||||
# Anything not using sudo will already have the correct environment
|
||||
- export VENV_BIN="$VIRTUAL_ENV/bin" && echo "VENV_BIN set to $VENV_BIN"
|
||||
install:
|
||||
# Install Python packages / dependencies
|
||||
# coverage
|
||||
- travis_retry pip install coverage
|
||||
# coveralls
|
||||
- travis_retry pip install coveralls
|
||||
# dnspython or dnspython3
|
||||
- if [[ "$F2B_PY_2" ]]; then travis_retry pip install dnspython; fi
|
||||
- if [[ "$F2B_PY_3" ]]; then travis_retry pip install dnspython3; fi
|
||||
# gamin - install manually (not in PyPI) - travis-ci system Python is 2.7
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then travis_retry sudo apt-get install -qq python-gamin && cp /usr/share/pyshared/gamin.py /usr/lib/pyshared/python2.7/_gamin.so $VIRTUAL_ENV/lib/python2.7/site-packages/; fi
|
||||
# pyinotify
|
||||
- travis_retry pip install pyinotify
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then travis_retry pip install dnspython; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 3* || $TRAVIS_PYTHON_VERSION == 'pypy3' ]]; then travis_retry pip install dnspython3; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then travis_retry sudo apt-get install -qq python-gamin; cp /usr/share/pyshared/gamin.py /usr/lib/pyshared/python2.7/_gamin.so $VIRTUAL_ENV/lib/python2.7/site-packages/; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then cd ..; travis_retry pip install -q coveralls; cd -; fi
|
||||
# overcome buggy pypy
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == pypy ]] ; then dpkg --compare-versions $(pypy --version 2>&1 | awk '/PyPy/{print $2;}') ge 2.5.1 || { d=$PWD; cd /tmp; wget http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux64.tar.bz2; tar -xjvf pypy*bz2; cd pypy-*/bin/; export PATH=$PWD:$PATH; cd $d; } ; fi
|
||||
before_script:
|
||||
# Manually execute 2to3 for now
|
||||
- if [[ "$F2B_PY_3" ]]; then ./fail2ban-2to3; 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
|
||||
# Keep the legacy setup.py test approach of checking coverage for python2
|
||||
- if [[ "$F2B_PY_2" ]]; then coverage run setup.py test; fi
|
||||
# Coverage doesn't pick up setup.py test with python3, so run it directly
|
||||
- if [[ "$F2B_PY_3" ]]; then coverage run bin/fail2ban-testcases; fi
|
||||
# Use $VENV_BIN (not python) or else sudo will always run the system's python (2.7)
|
||||
- sudo $VENV_BIN/pip install .
|
||||
after_success:
|
||||
# Coverage config file must be .coveragerc for coveralls
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then cp -v .travis_coveragerc .coveragerc; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then coveralls; fi
|
||||
- coveralls
|
||||
matrix:
|
||||
fast_finish: true
|
||||
# Might be worth looking into
|
||||
#notifications:
|
||||
# email: true
|
||||
# irc:
|
||||
# channels: "irc.freenode.org#fail2ban"
|
||||
# template:
|
||||
# - "%{repository}@%{branch}: %{message} (%{build_url})"
|
||||
# on_success: change
|
||||
# on_failure: change
|
||||
# skip_join: true
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
[run]
|
||||
branch = True
|
||||
omit =
|
||||
/usr/*
|
||||
/home/travis/virtualenv/*
|
||||
fail2ban/server/filtersystemd.py
|
81
ChangeLog
81
ChangeLog
|
@ -6,6 +6,85 @@
|
|||
Fail2Ban: Changelog
|
||||
===================
|
||||
|
||||
ver. 0.9.3 (2015/08/01) - lets-all-stay-friends
|
||||
----------
|
||||
|
||||
- IMPORTANT incompatible changes:
|
||||
* filter.d/roundcube-auth.conf
|
||||
- Changed logpath to 'errors' log (was 'userlogins')
|
||||
* action.d/iptables-common.conf
|
||||
- All calls to iptables command now use -w switch introduced in
|
||||
iptables 1.4.20 (some distribution could have patched their
|
||||
earlier base version as well) to provide this locking mechanism
|
||||
useful under heavy load to avoid contesting on iptables calls.
|
||||
If you need to disable, define 'action.d/iptables-common.local'
|
||||
with empty value for 'lockingopt' in `[Init]` section.
|
||||
* mail-whois-lines, sendmail-geoip-lines and sendmail-whois-lines
|
||||
actions now include by default only the first 1000 log lines in
|
||||
the emails. Adjust <grepopts> to augment the behavior.
|
||||
|
||||
- Fixes:
|
||||
* reload in interactive mode appends all the jails twice (gh-825)
|
||||
* reload server/jail failed if database used (but was not changed) and
|
||||
some jail active (gh-1072)
|
||||
* filter.d/dovecot.conf - also match unknown user in passwd-file.
|
||||
Thanks Anton Shestakov
|
||||
* Fix fail2ban-regex not parsing journalmatch correctly from filter config
|
||||
* filter.d/asterisk.conf - fix security log support for Asterisk 12+
|
||||
* filter.d/roundcube-auth.conf
|
||||
- Updated regex to work with 'errors' log (1.0.5 and 1.1.1)
|
||||
- Added regex to work with 'userlogins' log
|
||||
* action.d/sendmail*.conf - use LC_ALL (superseeding LC_TIME) to override
|
||||
locale on systems with customized LC_ALL
|
||||
* performance fix: minimizes connection overhead, close socket only at
|
||||
communication end (gh-1099)
|
||||
* unbanip always deletes ip from database (independent of bantime, also if
|
||||
currently not banned or persistent)
|
||||
* guarantee order of dbfile to be before dbpurgeage (gh-1048)
|
||||
* always set 'dbfile' before other database options (gh-1050)
|
||||
* kill the entire process group of the child process upon timeout (gh-1129).
|
||||
Otherwise could lead to resource exhaustion due to hanging whois
|
||||
processes.
|
||||
* resolve /var/run/fail2ban path in setup.py to help installation
|
||||
on platforms with /var/run -> /run symlink (gh-1142)
|
||||
|
||||
- New Features:
|
||||
* RETURN iptables target is now a variable: <returntype>
|
||||
* New type of operation: pass2allow, use fail2ban for "knocking",
|
||||
opening a closed port by swapping blocktype and returntype
|
||||
* New filters:
|
||||
- froxlor-auth - Thanks Joern Muehlencord
|
||||
- apache-pass - filter Apache access log for successful authentication
|
||||
* New actions:
|
||||
- shorewall-ipset-proto6 - using proto feature of the Shorewall. Still requires
|
||||
manual pre-configuration of the shorewall. See the action file for detail.
|
||||
* New jails:
|
||||
- pass2allow-ftp - allows FTP traffic after successful HTTP authentication
|
||||
|
||||
- Enhancements:
|
||||
* action.d/cloudflare.conf - improved documentation on how to allow
|
||||
multiple CF accounts, and jail.conf got new compound action
|
||||
definition action_cf_mwl to submit cloudflare report.
|
||||
* Check access to socket for more detailed logging on error (gh-595)
|
||||
* fail2ban-testcases man page
|
||||
* filter.d/apache-badbots.conf, filter.d/nginx-botsearch.conf - add
|
||||
HEAD method verb
|
||||
* Revamp of Travis and coverage automated testing
|
||||
* Added a space between IP address and the following colon
|
||||
in notification emails for easier text selection
|
||||
* Character detection heuristics for whois output via optional setting
|
||||
in mail-whois*.conf. Thanks Thomas Mayer.
|
||||
Not enabled by default, if _whois_command is set to be
|
||||
%(_whois_convert_charset)s (e.g. in action.d/mail-whois-common.local),
|
||||
it
|
||||
- detects character set of whois output (which is undefined by
|
||||
RFC 3912) via heuristics of the file command
|
||||
- converts whois data to UTF-8 character set with iconv
|
||||
- sends the whois output in UTF-8 character set to mail program
|
||||
- avoids that heirloom mailx creates binary attachment for input with
|
||||
unknown character set
|
||||
|
||||
|
||||
ver. 0.9.2 (2015/04/29) - better-quick-now-than-later
|
||||
----------
|
||||
|
||||
|
@ -42,7 +121,7 @@ ver. 0.9.2 (2015/04/29) - better-quick-now-than-later
|
|||
* firewallcmd-* actions: split output into separate lines for grepping (gh-908)
|
||||
* Guard unicode encode/decode issues while storing records in the database.
|
||||
Fixes "binding parameter error (unsupported type)" (gh-973), thanks to kot
|
||||
for reporting
|
||||
for reporting
|
||||
* filter.d/sshd added regex for matching openSUSE ssh authentication failure
|
||||
* filter.d/asterisk.conf:
|
||||
- Dropped "Sending fake auth rejection" failregex since it incorrectly
|
||||
|
|
7
DEVELOP
7
DEVELOP
|
@ -56,9 +56,12 @@ following (note: on Debian-based systems, the script is called
|
|||
`python-coverage`)::
|
||||
|
||||
coverage run bin/fail2ban-testcases
|
||||
coverage report
|
||||
|
||||
Optionally:
|
||||
coverage html
|
||||
|
||||
Then look at htmlcov/index.html and see how much coverage your test cases
|
||||
And then browse htmlcov/index.html and see how much coverage your test cases
|
||||
exert over the code base. Full coverage is a good thing however it may not be
|
||||
complete. Try to ensure tests cover as many independent paths through the
|
||||
code.
|
||||
|
@ -88,7 +91,7 @@ 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.
|
||||
- VM "attacker" which can 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.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/ _|__ _(_) |_ ) |__ __ _ _ _
|
||||
| _/ _` | | |/ /| '_ \/ _` | ' \
|
||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||
v0.9.2 2015/04/29
|
||||
v0.9.3 2015/08/01
|
||||
|
||||
## Fail2Ban: ban hosts that cause multiple authentication errors
|
||||
|
||||
|
@ -37,8 +37,8 @@ Optional:
|
|||
|
||||
To install, just do:
|
||||
|
||||
tar xvfj fail2ban-0.9.2.tar.bz2
|
||||
cd fail2ban-0.9.2
|
||||
tar xvfj fail2ban-0.9.3.tar.bz2
|
||||
cd fail2ban-0.9.3
|
||||
python setup.py install
|
||||
|
||||
This will install Fail2Ban into the python library directory. The executable
|
||||
|
|
14
RELEASE
14
RELEASE
|
@ -61,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.2.tar.bz2
|
||||
tar -C /tmp -jxf dist/fail2ban-0.9.3.tar.bz2
|
||||
|
||||
* clean up current direcory::
|
||||
|
||||
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.2/
|
||||
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.3/
|
||||
|
||||
* Only differences should be files that you don't want distributed.
|
||||
|
||||
|
||||
* Ensure the tests work from the tarball::
|
||||
|
||||
cd /tmp/fail2ban-0.9.2/ && bin/fail2ban-testcases
|
||||
cd /tmp/fail2ban-0.9.3/ && bin/fail2ban-testcases
|
||||
|
||||
* Add/finalize the corresponding entry in the ChangeLog
|
||||
|
||||
* To generate a list of committers use e.g.::
|
||||
|
||||
git shortlog -sn 0.9.2.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g'
|
||||
git shortlog -sn 0.9.3.. | 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.
|
||||
|
@ -101,7 +101,7 @@ Preparation
|
|||
* Tag the release by using a signed (and annotated) tag. Cut/paste
|
||||
release ChangeLog entry as tag annotation::
|
||||
|
||||
git tag -s 0.9.2
|
||||
git tag -s 0.9.3
|
||||
|
||||
Pre Release
|
||||
===========
|
||||
|
@ -185,7 +185,7 @@ Post Release
|
|||
|
||||
Add the following to the top of the ChangeLog::
|
||||
|
||||
ver. 0.9.3 (2014/XX/XXX) - wanna-be-released
|
||||
ver. 0.9.4 (2014/XX/XXX) - wanna-be-released
|
||||
-----------
|
||||
|
||||
- Fixes:
|
||||
|
@ -197,5 +197,5 @@ Add the following to the top of the ChangeLog::
|
|||
Alter the git shortlog command in the previous section to refer to the just
|
||||
released version.
|
||||
|
||||
and adjust fail2ban/version.py to carry .dev suffix to signal
|
||||
and adjust fail2ban/version.py to carry .dev0 suffix to signal
|
||||
a version under development.
|
||||
|
|
1
THANKS
1
THANKS
|
@ -109,6 +109,7 @@ Stefan Tatschner
|
|||
Stephen Gildea
|
||||
Steven Hiscocks
|
||||
TESTOVIK
|
||||
Thomas Mayer
|
||||
Tom Pike
|
||||
Tomas Pihl
|
||||
Tony Lawrence
|
||||
|
|
|
@ -22,8 +22,17 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import sys, string, os, pickle, re, logging, signal
|
||||
import getopt, time, shlex, socket
|
||||
import getopt
|
||||
import logging
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
import shlex
|
||||
import signal
|
||||
import socket
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
|
||||
from fail2ban.version import version
|
||||
from fail2ban.protocol import printFormatted
|
||||
|
@ -144,32 +153,58 @@ class Fail2banClient:
|
|||
return self.__processCmd([["ping"]], False)
|
||||
|
||||
def __processCmd(self, cmd, showRet = True):
|
||||
beautifier = Beautifier()
|
||||
streamRet = True
|
||||
for c in cmd:
|
||||
beautifier.setInputCmd(c)
|
||||
try:
|
||||
client = CSocket(self.__conf["socket"])
|
||||
ret = client.send(c)
|
||||
if ret[0] == 0:
|
||||
logSys.debug("OK : " + `ret[1]`)
|
||||
client = None
|
||||
try:
|
||||
beautifier = Beautifier()
|
||||
streamRet = True
|
||||
for c in cmd:
|
||||
beautifier.setInputCmd(c)
|
||||
try:
|
||||
if not client:
|
||||
client = CSocket(self.__conf["socket"])
|
||||
ret = client.send(c)
|
||||
if ret[0] == 0:
|
||||
logSys.debug("OK : " + `ret[1]`)
|
||||
if showRet:
|
||||
print beautifier.beautify(ret[1])
|
||||
else:
|
||||
logSys.error("NOK: " + `ret[1].args`)
|
||||
if showRet:
|
||||
print beautifier.beautifyError(ret[1])
|
||||
streamRet = False
|
||||
except socket.error:
|
||||
if showRet:
|
||||
print beautifier.beautify(ret[1])
|
||||
else:
|
||||
logSys.error("NOK: " + `ret[1].args`)
|
||||
self.__logSocketError()
|
||||
return False
|
||||
except Exception, e:
|
||||
if showRet:
|
||||
print beautifier.beautifyError(ret[1])
|
||||
streamRet = False
|
||||
except socket.error:
|
||||
if showRet:
|
||||
logSys.error("Unable to contact server. Is it running?")
|
||||
return False
|
||||
except Exception, e:
|
||||
if showRet:
|
||||
logSys.error(e)
|
||||
return False
|
||||
logSys.error(e)
|
||||
return False
|
||||
finally:
|
||||
if client:
|
||||
client.close()
|
||||
return streamRet
|
||||
|
||||
def __logSocketError(self):
|
||||
try:
|
||||
if os.access(self.__conf["socket"], os.F_OK):
|
||||
# This doesn't check if path is a socket,
|
||||
# but socket.error should be raised
|
||||
if os.access(self.__conf["socket"], os.W_OK):
|
||||
# Permissions look good, but socket.error was raised
|
||||
logSys.error("Unable to contact server. Is it running?")
|
||||
else:
|
||||
logSys.error("Permission denied to socket: %s,"
|
||||
" (you must be root)", self.__conf["socket"])
|
||||
else:
|
||||
logSys.error("Failed to access socket path: %s."
|
||||
" Is fail2ban running?",
|
||||
self.__conf["socket"])
|
||||
except Exception as e:
|
||||
logSys.error("Exception while checking socket access: %s",
|
||||
self.__conf["socket"])
|
||||
logSys.error(e)
|
||||
|
||||
##
|
||||
# Process a command line.
|
||||
#
|
||||
|
|
|
@ -29,7 +29,15 @@ __author__ = "Fail2Ban Developers"
|
|||
__copyright__ = "Copyright (c) 2004-2008 Cyril Jaquier, 2012-2014 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import getopt, sys, time, logging, os, locale, shlex, time, urllib
|
||||
import getopt
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
import sys
|
||||
import time
|
||||
import time
|
||||
import urllib
|
||||
from optparse import OptionParser, Option
|
||||
|
||||
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
|
||||
|
@ -297,8 +305,8 @@ class Fail2banRegex(object):
|
|||
"read from %(value)s" % locals()
|
||||
return False
|
||||
elif command[2] == 'addjournalmatch':
|
||||
journalmatch = command[3]
|
||||
self.setJournalMatch(shlex.split(journalmatch))
|
||||
journalmatch = command[3:]
|
||||
self.setJournalMatch(journalmatch)
|
||||
elif command[2] == 'datepattern':
|
||||
datepattern = command[3]
|
||||
self.setDatePattern(datepattern)
|
||||
|
|
|
@ -22,7 +22,9 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import getopt, sys, os
|
||||
import getopt
|
||||
import os
|
||||
import sys
|
||||
|
||||
from fail2ban.version import version
|
||||
from fail2ban.server.server import Server
|
||||
|
|
|
@ -25,7 +25,10 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2012- Yaroslav Halchenko"
|
|||
__license__ = "GPL"
|
||||
|
||||
import logging
|
||||
import unittest, sys, time, os
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
|
||||
# Check if local fail2ban module exists, and use if it exists by
|
||||
# modifying the path. This is such that tests can be used in dev
|
||||
|
|
|
@ -35,6 +35,7 @@ else:
|
|||
from fail2ban.server.actions import ActionBase
|
||||
from fail2ban.version import version as f2bVersion
|
||||
|
||||
|
||||
class BadIPsAction(ActionBase):
|
||||
"""Fail2Ban action which reports bans to badips.com, and also
|
||||
blacklist bad IPs listed on badips.com by using another action's
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#
|
||||
# Author: Mike Rushton
|
||||
#
|
||||
# Referenced from from http://www.normyee.net/blog/2012/02/02/adding-cloudflare-support-to-fail2ban by NORM YEE
|
||||
# IMPORTANT
|
||||
#
|
||||
# To get your Cloudflare API key: https://www.cloudflare.com/my-account
|
||||
# Please set jail.local's permission to 640 because it contains your CF API key.
|
||||
#
|
||||
# This action depends on curl.
|
||||
# Referenced from http://www.normyee.net/blog/2012/02/02/adding-cloudflare-support-to-fail2ban by NORM YEE
|
||||
#
|
||||
# To get your CloudFlare API Key: https://www.cloudflare.com/a/account/my-account
|
||||
|
||||
[Definition]
|
||||
|
||||
|
@ -34,7 +38,8 @@ actioncheck =
|
|||
# <time> unix timestamp of the ban time
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = curl https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
|
||||
actionban = curl -s -o /dev/null https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
|
@ -43,13 +48,19 @@ actionban = curl https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=<cf
|
|||
# <time> unix timestamp of the ban time
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = curl https://www.cloudflare.com/api_json.html -d 'a=nul' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
|
||||
|
||||
actionunban = curl -s -o /dev/null https://www.cloudflare.com/api_json.html -d 'a=nul' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
|
||||
|
||||
[Init]
|
||||
|
||||
# Default Cloudflare API token
|
||||
cftoken =
|
||||
# If you like to use this action with mailing whois lines, you could use the composite action
|
||||
# action_cf_mwl predefined in jail.conf, just define in your jail:
|
||||
#
|
||||
# action = %(action_cf_mwl)s
|
||||
# # Your CF account e-mail
|
||||
# cfemail =
|
||||
# # Your CF API Key
|
||||
# cfapikey =
|
||||
|
||||
# Default Cloudflare username
|
||||
cfuser =
|
||||
cftoken =
|
||||
|
||||
cfuser =
|
||||
|
|
|
@ -17,23 +17,23 @@ before = iptables-common.conf
|
|||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart = iptables -N f2b-<name>
|
||||
iptables -A f2b-<name> -j RETURN
|
||||
iptables -I <chain> -p <protocol> -j f2b-<name>
|
||||
actionstart = <iptables> -N f2b-<name>
|
||||
<iptables> -A f2b-<name> -j <returntype>
|
||||
<iptables> -I <chain> -p <protocol> -j f2b-<name>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -p <protocol> -j f2b-<name>
|
||||
iptables -F f2b-<name>
|
||||
iptables -X f2b-<name>
|
||||
actionstop = <iptables> -D <chain> -p <protocol> -j f2b-<name>
|
||||
<iptables> -F f2b-<name>
|
||||
<iptables> -X f2b-<name>
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
@ -41,7 +41,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
|
@ -49,7 +49,7 @@ actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
|
||||
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -43,3 +43,22 @@ protocol = tcp
|
|||
# REJECT, REJECT --reject-with icmp-port-unreachable
|
||||
# Values: STRING
|
||||
blocktype = REJECT --reject-with icmp-port-unreachable
|
||||
|
||||
# Option: returntype
|
||||
# Note: This is the default rule on "actionstart". This should be RETURN
|
||||
# in all (blocking) actions, except REJECT in allowing actions.
|
||||
# Values: STRING
|
||||
returntype = RETURN
|
||||
|
||||
# Option: lockingopt
|
||||
# Notes.: Option was introduced to iptables to prevent multiple instances from
|
||||
# running concurrently and causing irratic behavior. -w was introduced
|
||||
# in iptables 1.4.20, so might be absent on older systems
|
||||
# See https://github.com/fail2ban/fail2ban/issues/1122
|
||||
# Values: STRING
|
||||
lockingopt = -w
|
||||
|
||||
# Option: iptables
|
||||
# Notes.: Actual command to be executed, including common to all calls options
|
||||
# Values: STRING
|
||||
iptables = iptables <lockingopt>
|
||||
|
|
|
@ -28,13 +28,13 @@ before = iptables-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionstart = ipset --create f2b-<name> iphash
|
||||
iptables -I <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
<iptables> -I <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
actionstop = <iptables> -D <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
ipset --flush f2b-<name>
|
||||
ipset --destroy f2b-<name>
|
||||
|
||||
|
|
|
@ -24,13 +24,13 @@ before = iptables-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionstart = ipset create f2b-<name> hash:ip timeout <bantime>
|
||||
iptables -I <chain> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
<iptables> -I <chain> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
actionstop = <iptables> -D <chain> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
ipset flush f2b-<name>
|
||||
ipset destroy f2b-<name>
|
||||
|
||||
|
|
|
@ -24,13 +24,13 @@ before = iptables-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionstart = ipset create f2b-<name> hash:ip timeout <bantime>
|
||||
iptables -I <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
<iptables> -I <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
actionstop = <iptables> -D <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
|
||||
ipset flush f2b-<name>
|
||||
ipset destroy f2b-<name>
|
||||
|
||||
|
|
|
@ -19,28 +19,28 @@ before = iptables-common.conf
|
|||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart = iptables -N f2b-<name>
|
||||
iptables -A f2b-<name> -j RETURN
|
||||
iptables -I <chain> 1 -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
iptables -N f2b-<name>-log
|
||||
iptables -I f2b-<name>-log -j LOG --log-prefix "$(expr f2b-<name> : '\(.\{1,23\}\)'):DROP " --log-level warning -m limit --limit 6/m --limit-burst 2
|
||||
iptables -A f2b-<name>-log -j <blocktype>
|
||||
actionstart = <iptables> -N f2b-<name>
|
||||
<iptables> -A f2b-<name> -j <returntype>
|
||||
<iptables> -I <chain> 1 -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
<iptables> -N f2b-<name>-log
|
||||
<iptables> -I f2b-<name>-log -j LOG --log-prefix "$(expr f2b-<name> : '\(.\{1,23\}\)'):DROP " --log-level warning -m limit --limit 6/m --limit-burst 2
|
||||
<iptables> -A f2b-<name>-log -j <blocktype>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
iptables -F f2b-<name>
|
||||
iptables -F f2b-<name>-log
|
||||
iptables -X f2b-<name>
|
||||
iptables -X f2b-<name>-log
|
||||
actionstop = <iptables> -D <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
<iptables> -F f2b-<name>
|
||||
<iptables> -F f2b-<name>-log
|
||||
<iptables> -X f2b-<name>
|
||||
<iptables> -X f2b-<name>-log
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck = iptables -n -L f2b-<name>-log >/dev/null
|
||||
actioncheck = <iptables> -n -L f2b-<name>-log >/dev/null
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
@ -48,7 +48,7 @@ actioncheck = iptables -n -L f2b-<name>-log >/dev/null
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = iptables -I f2b-<name> 1 -s <ip> -j f2b-<name>-log
|
||||
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j f2b-<name>-log
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
|
@ -56,7 +56,7 @@ actionban = iptables -I f2b-<name> 1 -s <ip> -j f2b-<name>-log
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = iptables -D f2b-<name> -s <ip> -j f2b-<name>-log
|
||||
actionunban = <iptables> -D f2b-<name> -s <ip> -j f2b-<name>-log
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -14,23 +14,23 @@ before = iptables-common.conf
|
|||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart = iptables -N f2b-<name>
|
||||
iptables -A f2b-<name> -j RETURN
|
||||
iptables -I <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
actionstart = <iptables> -N f2b-<name>
|
||||
<iptables> -A f2b-<name> -j <returntype>
|
||||
<iptables> -I <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
iptables -F f2b-<name>
|
||||
iptables -X f2b-<name>
|
||||
actionstop = <iptables> -D <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
<iptables> -F f2b-<name>
|
||||
<iptables> -X f2b-<name>
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
@ -38,7 +38,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
|
@ -46,7 +46,7 @@ actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
|
||||
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -16,23 +16,23 @@ before = iptables-common.conf
|
|||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart = iptables -N f2b-<name>
|
||||
iptables -A f2b-<name> -j RETURN
|
||||
iptables -I <chain> -m state --state NEW -p <protocol> --dport <port> -j f2b-<name>
|
||||
actionstart = <iptables> -N f2b-<name>
|
||||
<iptables> -A f2b-<name> -j <returntype>
|
||||
<iptables> -I <chain> -m state --state NEW -p <protocol> --dport <port> -j f2b-<name>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -m state --state NEW -p <protocol> --dport <port> -j f2b-<name>
|
||||
iptables -F f2b-<name>
|
||||
iptables -X f2b-<name>
|
||||
actionstop = <iptables> -D <chain> -m state --state NEW -p <protocol> --dport <port> -j f2b-<name>
|
||||
<iptables> -F f2b-<name>
|
||||
<iptables> -X f2b-<name>
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
@ -40,7 +40,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
|
@ -48,7 +48,7 @@ actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
|
||||
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -32,14 +32,14 @@ before = iptables-common.conf
|
|||
# own rules. The 3600 second timeout is independent and acts as a
|
||||
# safeguard in case the fail2ban process dies unexpectedly. The
|
||||
# shorter of the two timeouts actually matters.
|
||||
actionstart = if [ `id -u` -eq 0 ];then iptables -I <chain> -m recent --update --seconds 3600 --name f2b-<name> -j <blocktype>;fi
|
||||
actionstart = if [ `id -u` -eq 0 ];then <iptables> -I <chain> -m recent --update --seconds 3600 --name f2b-<name> -j <blocktype>;fi
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = echo / > /proc/net/xt_recent/f2b-<name>
|
||||
if [ `id -u` -eq 0 ];then iptables -D <chain> -m recent --update --seconds 3600 --name f2b-<name> -j <blocktype>;fi
|
||||
if [ `id -u` -eq 0 ];then <iptables> -D <chain> -m recent --update --seconds 3600 --name f2b-<name> -j <blocktype>;fi
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
|
|
|
@ -14,23 +14,23 @@ before = iptables-common.conf
|
|||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart = iptables -N f2b-<name>
|
||||
iptables -A f2b-<name> -j RETURN
|
||||
iptables -I <chain> -p <protocol> --dport <port> -j f2b-<name>
|
||||
actionstart = <iptables> -N f2b-<name>
|
||||
<iptables> -A f2b-<name> -j <returntype>
|
||||
<iptables> -I <chain> -p <protocol> --dport <port> -j f2b-<name>
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = iptables -D <chain> -p <protocol> --dport <port> -j f2b-<name>
|
||||
iptables -F f2b-<name>
|
||||
iptables -X f2b-<name>
|
||||
actionstop = <iptables> -D <chain> -p <protocol> --dport <port> -j f2b-<name>
|
||||
<iptables> -F f2b-<name>
|
||||
<iptables> -X f2b-<name>
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
@ -38,7 +38,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
|
@ -46,7 +46,7 @@ actionban = iptables -I f2b-<name> 1 -s <ip> -j <blocktype>
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
|
||||
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# Fail2Ban configuration file
|
||||
#
|
||||
# Common settings for mail actions
|
||||
#
|
||||
# Users can override the defaults in mail-whois-common.local
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
# Load customizations if any available
|
||||
after = mail-whois-common.local
|
||||
|
||||
[DEFAULT]
|
||||
#original character set of whois output will be sent to mail program
|
||||
_whois = whois <ip> || echo "missing whois program"
|
||||
|
||||
# use heuristics to convert charset of whois output to a target
|
||||
# character set before sending it to a mail program
|
||||
# make sure you have 'file' and 'iconv' commands installed when opting for that
|
||||
_whois_target_charset = UTF-8
|
||||
_whois_convert_charset = whois <ip> |
|
||||
{ WHOIS_OUTPUT=$(cat) ; WHOIS_CHARSET=$(printf %%b "$WHOIS_OUTPUT" | file -b --mime-encoding -) ; printf %%b "$WHOIS_OUTPUT" | iconv -f $WHOIS_CHARSET -t %(_whois_target_charset)s//TRANSLIT - ; }
|
||||
|
||||
# choose between _whois and _whois_convert_charset in mail-whois-common.local
|
||||
# or other *.local which include mail-whois-common.conf.
|
||||
_whois_command = %(_whois)s
|
||||
#_whois_command = %(_whois_convert_charset)s
|
||||
|
||||
[Init]
|
|
@ -4,6 +4,10 @@
|
|||
# Modified-By: Yaroslav Halchenko to include grepping on IP over log files
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = mail-whois-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
# Option: actionstart
|
||||
|
@ -39,10 +43,10 @@ actioncheck =
|
|||
actionban = printf %%b "Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
`whois <ip> || echo missing whois program`\n\n
|
||||
Here is more information about <ip> :\n
|
||||
`%(_whois_command)s`\n\n
|
||||
Lines containing IP:<ip> in <logpath>\n
|
||||
`grep -E '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
|
||||
`grep -E <grepopts> '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
|
||||
Regards,\n
|
||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
|
||||
|
||||
|
@ -67,3 +71,7 @@ dest = root
|
|||
# Path to the log files which contain relevant lines for the abuser IP
|
||||
#
|
||||
logpath = /dev/null
|
||||
|
||||
# Number of log lines to include in the email
|
||||
#
|
||||
grepopts = -m 1000
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = mail-whois-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
# Option: actionstart
|
||||
|
@ -39,8 +43,8 @@ actioncheck =
|
|||
actionban = printf %%b "Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
`whois <ip> || echo missing whois program`\n
|
||||
Here is more information about <ip> :\n
|
||||
`%(_whois_command)s`\n
|
||||
Regards,\n
|
||||
Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ after = sendmail-common.local
|
|||
# Values: CMD
|
||||
#
|
||||
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started on `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
|
@ -28,7 +28,7 @@ actionstart = printf %%b "Subject: [Fail2Ban] <name>: started on `uname -n`
|
|||
# Values: CMD
|
||||
#
|
||||
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped on `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
|
@ -40,7 +40,7 @@ actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped on `uname -n`
|
|||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck =
|
||||
actioncheck =
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
@ -48,7 +48,7 @@ actioncheck =
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionban =
|
||||
actionban =
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
|
@ -56,7 +56,7 @@ actionban =
|
|||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban =
|
||||
actionunban =
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ before = sendmail-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
Here is more information about <ip> :\n
|
||||
http://bgp.he.net/ip/<ip>
|
||||
http://www.projecthoneypot.org/ip_<ip>
|
||||
http://whois.domaintools.com/<ip>\n\n
|
||||
|
@ -34,7 +34,7 @@ actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
|||
AS:`geoiplookup -f /usr/share/GeoIP/GeoIPASNum.dat "<ip>" | cut -d':' -f2-`
|
||||
hostname: `host -t A <ip> 2>&1`\n\n
|
||||
Lines containing IP:<ip> in <logpath>\n
|
||||
`grep -E '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
|
||||
`grep -E <grepopts> '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
|
||||
Regards,\n
|
||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||
|
||||
|
@ -47,3 +47,7 @@ name = default
|
|||
# Path to the log files which contain relevant lines for the abuser IP
|
||||
#
|
||||
logpath = /dev/null
|
||||
|
||||
# Number of log lines to include in the email
|
||||
#
|
||||
grepopts = -m 1000
|
||||
|
|
|
@ -17,13 +17,13 @@ before = sendmail-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
Here is more information about <ip> :\n
|
||||
`/usr/bin/whois <ip>`\n\n
|
||||
Matches for <name> with <ipjailfailures> failures IP:<ip>\n
|
||||
<ipjailmatches>\n\n
|
||||
|
|
|
@ -17,13 +17,13 @@ before = sendmail-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
Here is more information about <ip> :\n
|
||||
`/usr/bin/whois <ip>`\n\n
|
||||
Matches with <ipfailures> failures IP:<ip>\n
|
||||
<ipmatches>\n\n
|
||||
|
|
|
@ -17,16 +17,16 @@ before = sendmail-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
Here is more information about <ip> :\n
|
||||
`/usr/bin/whois <ip> || echo missing whois program`\n\n
|
||||
Lines containing IP:<ip> in <logpath>\n
|
||||
`grep -E '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
|
||||
`grep -E <grepopts> '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
|
||||
Regards,\n
|
||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||
|
||||
|
@ -40,3 +40,6 @@ name = default
|
|||
#
|
||||
logpath = /dev/null
|
||||
|
||||
# Number of log lines to include in the email
|
||||
#
|
||||
grepopts = -m 1000
|
||||
|
|
|
@ -17,13 +17,13 @@ before = sendmail-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
Here is more information about <ip> :\n
|
||||
`/usr/bin/whois <ip>`\n\n
|
||||
Matches:\n
|
||||
<matches>\n\n
|
||||
|
|
|
@ -17,13 +17,13 @@ before = sendmail-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
The IP <ip> has just been banned by Fail2Ban after
|
||||
<failures> attempts against <name>.\n\n
|
||||
Here is more information about <ip>:\n
|
||||
Here is more information about <ip> :\n
|
||||
`/usr/bin/whois <ip> || echo missing whois program`\n
|
||||
Regards,\n
|
||||
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
|
||||
|
|
|
@ -17,7 +17,7 @@ before = sendmail-common.conf
|
|||
# Values: CMD
|
||||
#
|
||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
Date: `LC_ALL=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
From: <sendername> <<sender>>
|
||||
To: <dest>\n
|
||||
Hi,\n
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
# Fail2Ban configuration file
|
||||
#
|
||||
# Author: Eduardo Diaz
|
||||
#
|
||||
# This is for ipset protocol 6 (and hopefully later) (ipset v6.14).
|
||||
# for shorewall
|
||||
#
|
||||
# Use this setting in jail.conf to modify use this action instead of a
|
||||
# default one
|
||||
#
|
||||
# banaction = shorewall-ipset-proto6
|
||||
#
|
||||
# This requires the program ipset which is normally in package called ipset.
|
||||
#
|
||||
# IPset was a feature introduced in the linux kernel 2.6.39 and 3.0.0
|
||||
# kernels, and you need Shorewall >= 4.5.5 to use this action.
|
||||
#
|
||||
# The default Shorewall configuration is with "BLACKLISTNEWONLY=Yes" (see
|
||||
# file /etc/shorewall/shorewall.conf). This means that when Fail2ban adds a
|
||||
# new shorewall rule to ban an IP address, that rule will affect only new
|
||||
# connections. So if the attacker goes on trying using the same connection
|
||||
# he could even log in. In order to get the same behavior of the iptable
|
||||
# action (so that the ban is immediate) the /etc/shorewall/shorewall.conf
|
||||
# file should me modified with "BLACKLISTNEWONLY=No".
|
||||
#
|
||||
#
|
||||
# Enable shorewall to use a blacklist using iptables creating a file
|
||||
# /etc/shorewall/blrules and adding "DROP net:+f2b-ssh all" and
|
||||
# similar lines for every jail. To enable restoring you ipset you
|
||||
# must set SAVE_IPSETS=Yes in shorewall.conf . You can read more
|
||||
# about ipsets handling in Shorewall at http://shorewall.net/ipsets.html
|
||||
#
|
||||
# To force creation of the ipset in the case that somebody deletes the
|
||||
# ipset create a file /etc/shorewall/initdone and add one line for
|
||||
# every ipset (this files are in Perl) and add 1 at the end of the file.
|
||||
# The example:
|
||||
# system("/usr/sbin/ipset -quiet -exist create f2b-ssh hash:ip timeout 600 ");
|
||||
# 1;
|
||||
#
|
||||
# To destroy the ipset in shorewall you must add to the file /etc/shorewall/stopped
|
||||
# # One line of every ipset
|
||||
# system("/usr/sbin/ipset -quiet destroy f2b-ssh ");
|
||||
# 1; # This must go to the end of the file if not shorewall compilation fails
|
||||
#
|
||||
|
||||
|
||||
[Definition]
|
||||
|
||||
# Option: actionstart
|
||||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart = if ! ipset -quiet -name list f2b-<name> >/dev/null;
|
||||
then ipset -quiet -exist create f2b-<name> hash:ip timeout <bantime>;
|
||||
fi
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop = ipset flush f2b-<name>
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = ipset add f2b-<name> <ip> timeout <bantime> -exist
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: See jail.conf(5) man page
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = ipset del f2b-<name> <ip> -exist
|
||||
|
||||
[Init]
|
||||
|
||||
# Option: bantime
|
||||
# Notes: specifies the bantime in seconds (handled internally rather than by fail2ban)
|
||||
# Values: [ NUM ] Default: 600
|
||||
#
|
||||
bantime = 600
|
|
@ -68,6 +68,7 @@ Matches for %(ip)s for jail %(jailname)s:
|
|||
%(ipjailmatches)s
|
||||
"""
|
||||
|
||||
|
||||
class SMTPAction(ActionBase):
|
||||
"""Fail2Ban action which sends emails to inform on jail starting,
|
||||
stopping and bans.
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# Author: Yaroslav Halchenko
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = iptables-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
|
@ -22,21 +25,21 @@ actionstop =
|
|||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck = iptables -n -L <chain>
|
||||
actioncheck = <iptables> -n -L <chain>
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP.
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = echo 'all' >| /etc/symbiosis/firewall/blacklist.d/<ip>.auto
|
||||
iptables -I <chain> 1 -s <ip> -j <blocktype>
|
||||
<iptables> -I <chain> 1 -s <ip> -j <blocktype>
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP.
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = rm -f /etc/symbiosis/firewall/blacklist.d/<ip>.auto
|
||||
iptables -D <chain> -s <ip> -j <blocktype> || :
|
||||
<iptables> -D <chain> -s <ip> -j <blocktype> || :
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Fail2Ban action for sending xarf Login-Attack messages to IP owner
|
||||
#
|
||||
# IMPORTANT:
|
||||
#
|
||||
# IMPORTANT:
|
||||
#
|
||||
# Emailing a IP owner of abuse is a serious complain. Make sure that it is
|
||||
# serious. Fail2ban developers and network owners recommend you only use this
|
||||
# action for:
|
||||
|
@ -46,7 +46,7 @@ actionban = oifs=${IFS}; IFS=.;SEP_IP=( <ip> ); set -- ${SEP_IP}; ADDRESSES=$(di
|
|||
REPORTID=<time>@`uname -n`
|
||||
TLP=<tlp>
|
||||
PORT=<port>
|
||||
DATE=`LC_TIME=C date --date=@<time> +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
DATE=`LC_ALL=C date --date=@<time> +"%%a, %%d %%h %%Y %%T %%z"`
|
||||
if [ ! -z "$ADDRESSES" ]; then
|
||||
(printf -- %%b "<header>\n<message>\n<report>\n";
|
||||
date '+Note: Local timezone is %%z (%%Z)';
|
||||
|
@ -70,7 +70,7 @@ footer = \n\n--Abuse-bfbb0f920793ac03cb8634bde14d8a1e--
|
|||
report = --Abuse-bfbb0f920793ac03cb8634bde14d8a1e\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nContent-Type: text/plain; charset=utf-8; name=\"report.txt\";\n\n---\nReported-From: $FROM\nCategory: abuse\nReport-ID: $REPORTID\nReport-Type: login-attack\nService: $SERVICE\nVersion: 0.2\nUser-Agent: Fail2ban v0.9\nDate: $DATE\nSource-Type: ip-address\nSource: $IP\nPort: $PORT\nSchema-URL: http://www.x-arf.org/schema/abuse_login-attack_0.1.2.json\nAttachment: text/plain\nOccurances: $FAILURES\nTLP: $TLP\n\n\n--Abuse-bfbb0f920793ac03cb8634bde14d8a1e\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nContent-Type: text/plain; charset=utf8; name=\"logfile.log\";
|
||||
|
||||
# Option: Message
|
||||
# Notes: This can be modified by the users
|
||||
# Notes: This can be modified by the users
|
||||
message = Dear Sir/Madam,\n\nWe have detected abuse from the IP address $IP, which according to abusix.com is on your network. We would appreciate if you would investigate and take action as appropriate.\n\nLog lines are given below, but please ask if you require any further information.\n\n(If you are not the correct person to contact about this please accept our apologies - your e-mail address was extracted from the whois record by an automated process.)\n\n This mail was generated by Fail2Ban in a X-ARF format! You can find more information about x-arf at http://www.x-arf.org/specification.html.\n\nThe recipient address of this report was provided by the Abuse Contact DB by abusix.com. abusix.com does not maintain the content of the database. All information which we pass out, derives from the RIR databases and is processed for ease of use. If you want to change or report non working abuse contacts please contact the appropriate RIR. If you have any further question, contact abusix.com directly via email (info@abusix.com). Information about the Abuse Contact Database can be found here: https://abusix.com/global-reporting/abuse-contact-db\nabusix.com is neither responsible nor liable for the content or accuracy of this message.\n
|
||||
|
||||
# Option: loglines
|
||||
|
@ -97,7 +97,7 @@ mailargs = -f <sender>
|
|||
# Option: tlp
|
||||
# Notes.: Traffic light protocol defining the sharing of this information.
|
||||
# http://www.trusted-introducer.org/ISTLPv11.pdf
|
||||
# green is share to those involved in network security but it is not
|
||||
# green is share to those involved in network security but it is not
|
||||
# to be released to the public.
|
||||
tlp = green
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02|sogou music spider
|
||||
badbots = Atomic_Email_Hunter/4\.0|atSpider/1\.0|autoemailspider|bwh3_user_agent|China Local Browse 2\.6|ContactBot/0\.2|ContentSmartz|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailSpider|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Guestbook Auto Submitter|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 +http\://letscrawl\.com/|Lincoln State Web Browser|LMQueueBot/0\.2|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|MVAClient|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/3\.0 \(compatible; scan4mail \(advanced version\) http\://www\.peterspages\.net/?scan4mail\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|NameOfAgent \(CMS Spider\)|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|ShablastBot 1\.0|snap\.com beta crawler v0|Snapbot/1\.0|Snapbot/1\.0 \(Snap Shots, +http\://www\.snap\.com\)|sogou develop spider|Sogou Orion spider/3\.0\(+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sogou spider|Sogou web spider/3\.0\(+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|VadixBot|WebVulnCrawl\.unknown/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00
|
||||
|
||||
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
|
||||
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Fail2Ban Apache pass filter
|
||||
# This filter is for access.log, NOT for error.log
|
||||
#
|
||||
# The knocking request must have a referer.
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = apache-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
failregex = ^<HOST> - \w+ \[\] "GET <knocking_url> HTTP/1\.[01]" 200 \d+ ".*" "[^-].*"$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
[Init]
|
||||
|
||||
knocking_url = /knocking/
|
||||
|
||||
# Author: Viktor Szépe
|
|
@ -13,6 +13,8 @@ _daemon = asterisk
|
|||
|
||||
__pid_re = (?:\[\d+\])
|
||||
|
||||
iso8601 = \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+[+-]\d{4}
|
||||
|
||||
# All Asterisk log messages begin like this:
|
||||
log_prefix= (?:NOTICE|SECURITY)%(__pid_re)s:?(?:\[C-[\da-f]*\])? \S+:\d*( in \w+:)?
|
||||
|
||||
|
@ -23,7 +25,7 @@ failregex = ^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Registration from '[^']*'
|
|||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Host <HOST> failed MD5 authentication for '[^']*' \([^)]+\)$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Failed to authenticate (user|device) [^@]+@<HOST>\S*$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s hacking attempt detected '<HOST>'$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="[\d-]+",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="\d*",SessionID="0x[\da-f]+",LocalAddress="IPV[46]/(UD|TC)P/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UD|TC)P/<HOST>/\d+"(,Challenge="\w+",ReceivedChallenge="\w+")?(,ReceivedHash="[\da-f]+")?(,ACLName="\w+")?$
|
||||
^(%(__prefix_line)s|\[\]\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|\[\]\s*WARNING%(__pid_re)s:?(?:\[C-[\da-f]*\])? )Ext\. s: "Rejecting unknown SIP connection from <HOST>"$
|
||||
|
||||
ignoreregex =
|
||||
|
|
|
@ -12,7 +12,7 @@ _daemon = (auth|dovecot(-auth)?|auth-worker)
|
|||
failregex = ^%(__prefix_line)s(%(__pam_auth)s(\(dovecot:auth\))?:)?\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=dovecot ruser=\S* rhost=<HOST>(\s+user=\S*)?\s*$
|
||||
^%(__prefix_line)s(pop3|imap)-login: (Info: )?(Aborted login|Disconnected)(: Inactivity)? \(((auth failed, \d+ attempts)( in \d+ secs)?|tried to use (disabled|disallowed) \S+ auth)\):( user=<\S*>,)?( method=\S+,)? rip=<HOST>(, lip=(\d{1,3}\.){3}\d{1,3})?(, TLS( handshaking(: SSL_accept\(\) failed: error:[\dA-F]+:SSL routines:[TLS\d]+_GET_CLIENT_HELLO:unknown protocol)?)?(: Disconnected)?)?(, session=<\S+>)?\s*$
|
||||
^%(__prefix_line)s(Info|dovecot: auth\(default\)|auth-worker\(\d+\)): pam\(\S+,<HOST>\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$
|
||||
^%(__prefix_line)sauth-worker\(\d+\): pam\(\S+,<HOST>\): unknown user\s*$
|
||||
^%(__prefix_line)s(auth|auth-worker\(\d+\)): (pam|passwd-file)\(\S+,<HOST>\): unknown user\s*$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# Fail2Ban configuration file to block repeated failed login attempts to Frolor installation(s)
|
||||
#
|
||||
# Froxlor needs to log to Syslog User (e.g. /var/log/user.log) with one of the following messages
|
||||
# <syslog prefix> Froxlor: [Login Action <HOST>] Unknown user '<USER>' tried to login.
|
||||
# <syslog prefix> Froxlor: [Login Action <HOST>] User '<USER>' tried to login with wrong password.
|
||||
#
|
||||
# Author: Joern Muehlencord
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
# Read common prefixes. If any customizations available -- read them from
|
||||
# common.local
|
||||
before = common.conf
|
||||
|
||||
|
||||
[Definition]
|
||||
|
||||
_daemon = Froxlor
|
||||
|
||||
# Option: failregex
|
||||
# Notes.: regex to match the password failures messages in the logfile. The
|
||||
# host must be matched by a group named "host". The tag "<HOST>" can
|
||||
# be used for standard IP/hostname matching and is only an alias for
|
||||
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
|
||||
# Values: TEXT
|
||||
#
|
||||
failregex = ^%(__prefix_line)s\[Login Action <HOST>\] Unknown user \S* tried to login.$
|
||||
^%(__prefix_line)s\[Login Action <HOST>\] User \S* tried to login with wrong password.$
|
||||
|
||||
|
||||
# Option: ignoreregex
|
||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||
# Values: TEXT
|
||||
#
|
||||
ignoreregex =
|
||||
|
|
@ -8,8 +8,8 @@ before = botsearch-common.conf
|
|||
|
||||
[Definition]
|
||||
|
||||
failregex = ^<HOST> \- \S+ \[\] \"(GET|POST) \/<block> \S+\" 404 .+$
|
||||
^ \[error\] \d+#\d+: \*\d+ (\S+ )?\"\S+\" (failed|is not found) \(2\: No such file or directory\), client\: <HOST>\, server\: \S*\, request: \"(GET|POST) \/<block> \S+\"\, .*?$
|
||||
failregex = ^<HOST> \- \S+ \[\] \"(GET|POST|HEAD) \/<block> \S+\" 404 .+$
|
||||
^ \[error\] \d+#\d+: \*\d+ (\S+ )?\"\S+\" (failed|is not found) \(2\: No such file or directory\), client\: <HOST>\, server\: \S*\, request: \"(GET|POST|HEAD) \/<block> \S+\"\, .*?$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#
|
||||
# Set "UseReverseDNS off" in proftpd.conf to avoid the need for DNS.
|
||||
# See: http://www.proftpd.org/docs/howto/DNS.html
|
||||
# When the default locale for your system is not en_US.UTF-8
|
||||
# on Debian-based systems be sure to add this to /etc/default/proftpd
|
||||
# export LC_TIME="en_US.UTF-8"
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
# Fail2Ban configuration file for roundcube web server
|
||||
#
|
||||
# By default failed logins are printed to 'errors'. The first regex matches those
|
||||
# The second regex matches those printed to 'userlogins'
|
||||
# The userlogins log file can be enabled by setting $config['log_logins'] = true; in config.inc.php
|
||||
#
|
||||
# The logpath in your jail can be updated to userlogins if you wish
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
@ -9,7 +13,8 @@ before = common.conf
|
|||
|
||||
[Definition]
|
||||
|
||||
failregex = ^\s*(\[\])?(%(__hostname)s roundcube: IMAP Error)?: (FAILED login|Login failed) for .*? from <HOST>(\. .* in .*?/rcube_imap\.php on line \d+ \(\S+ \S+\))?$
|
||||
failregex = ^\s*(\[\])?(%(__hostname)s\s*(roundcube:)?\s*(<[\w]+>)? IMAP Error)?: (FAILED login|Login failed) for .*? from <HOST>(\. .* in .*?/rcube_imap\.php on line \d+ \(\S+ \S+\))?$
|
||||
^\[\]:\s*(<[\w]+>)? Failed login for [\w\-\.\+]+(@[\w\-\.\+]+\.[a-zA-Z]{2,6})? from <HOST> in session \w+( \(error: \d\))?$
|
||||
|
||||
ignoreregex =
|
||||
# DEV Notes:
|
||||
|
@ -26,4 +31,4 @@ ignoreregex =
|
|||
# arbitrary user input and IMAP response doesn't inject the wrong IP for
|
||||
# fail2ban
|
||||
#
|
||||
# Author: Teodor Micu & Yaroslav Halchenko & terence namusonge & Daniel Black
|
||||
# Author: Teodor Micu & Yaroslav Halchenko & terence namusonge & Daniel Black & Lee Clemens
|
||||
|
|
|
@ -174,6 +174,10 @@ action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(por
|
|||
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
|
||||
|
||||
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
|
||||
# to the destemail.
|
||||
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
||||
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
||||
|
||||
# Report block via blocklist.de fail2ban reporting service API
|
||||
#
|
||||
|
@ -344,7 +348,7 @@ logpath = %(lighttpd_error_log)s
|
|||
[roundcube-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/roundcube/userlogins
|
||||
logpath = logpath = %(roundcube_errors_log)s
|
||||
|
||||
|
||||
[openwebmail]
|
||||
|
@ -408,6 +412,12 @@ port = 10000
|
|||
logpath = %(syslog_authpriv)s
|
||||
|
||||
|
||||
[froxlor-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
|
||||
|
||||
#
|
||||
# HTTP Proxy servers
|
||||
#
|
||||
|
@ -424,6 +434,7 @@ logpath = /var/log/squid/access.log
|
|||
port = 3128
|
||||
logpath = /var/log/3proxy.log
|
||||
|
||||
|
||||
#
|
||||
# FTP servers
|
||||
#
|
||||
|
@ -756,3 +767,16 @@ port = 2222
|
|||
enabled = false
|
||||
logpath = /var/lib/portsentry/portsentry.history
|
||||
maxretry = 1
|
||||
|
||||
[pass2allow-ftp]
|
||||
# this pass2allow example allows FTP traffic after successful HTTP authentication
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
# knocking_url variable must be overridden to some secret value in filter.d/apache-pass.local
|
||||
filter = apache-pass
|
||||
# access log of the website with HTTP auth
|
||||
logpath = %(apache_access_log)s
|
||||
blocktype = RETURN
|
||||
returntype = DROP
|
||||
bantime = 3600
|
||||
maxretry = 1
|
||||
findtime = 1
|
||||
|
|
|
@ -62,5 +62,7 @@ solidpop3d_log = %(syslog_local0)s
|
|||
|
||||
mysql_log = %(syslog_daemon)s
|
||||
|
||||
roundcube_errors_log = /var/log/roundcube/errors
|
||||
|
||||
# Directory with ignorecommand scripts
|
||||
ignorecommands_dir = /etc/fail2ban/filter.d/ignorecommands
|
||||
|
|
|
@ -35,6 +35,3 @@ exim_main_log = /var/log/exim4/mainlog
|
|||
# was in debian squeezy but not in wheezy
|
||||
# /etc/proftpd/proftpd.conf (SystemLog)
|
||||
proftpd_log = /var/log/proftpd/proftpd.log
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -35,3 +35,5 @@ apache_access_log = /var/log/httpd/*access_log
|
|||
exim_main_log = /var/log/exim/main.log
|
||||
|
||||
mysql_log = /var/lib/mysql/mysqld.log
|
||||
|
||||
roundcube_errors_log = /var/log/roundcubemail/errors
|
||||
|
|
|
@ -37,6 +37,7 @@ Below derived from:
|
|||
logging.NOTICE = logging.INFO + 5
|
||||
logging.addLevelName(logging.NOTICE, 'NOTICE')
|
||||
|
||||
|
||||
# define a new logger function for notice
|
||||
# this is exactly like existing info, critical, debug...etc
|
||||
def _Logger_notice(self, msg, *args, **kwargs):
|
||||
|
@ -53,6 +54,7 @@ def _Logger_notice(self, msg, *args, **kwargs):
|
|||
|
||||
logging.Logger.notice = _Logger_notice
|
||||
|
||||
|
||||
# define a new root level notice function
|
||||
# this is exactly like existing info, critical, debug...etc
|
||||
def _root_notice(msg, *args, **kwargs):
|
||||
|
|
|
@ -32,6 +32,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class ActionReader(DefinitionInitConfigReader):
|
||||
|
||||
_configOpts = [
|
||||
|
|
|
@ -27,6 +27,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
##
|
||||
# Beautify the output of the client.
|
||||
#
|
||||
|
@ -34,18 +35,19 @@ logSys = getLogger(__name__)
|
|||
# converted into user readable messages.
|
||||
|
||||
class Beautifier:
|
||||
|
||||
|
||||
def __init__(self, cmd = None):
|
||||
self.__inputCmd = cmd
|
||||
|
||||
def setInputCmd(self, cmd):
|
||||
self.__inputCmd = cmd
|
||||
|
||||
|
||||
def getInputCmd(self):
|
||||
return self.__inputCmd
|
||||
|
||||
|
||||
def beautify(self, response):
|
||||
logSys.debug("Beautify " + `response` + " with " + `self.__inputCmd`)
|
||||
logSys.debug(
|
||||
"Beautify " + repr(response) + " with " + repr(self.__inputCmd))
|
||||
inC = self.__inputCmd
|
||||
msg = response
|
||||
try:
|
||||
|
@ -102,7 +104,7 @@ class Beautifier:
|
|||
elif response == 4:
|
||||
msg = msg + "DEBUG"
|
||||
else:
|
||||
msg = msg + `response`
|
||||
msg = msg + repr(response)
|
||||
elif inC[1] == "dbfile":
|
||||
if response is None:
|
||||
msg = "Database currently disabled"
|
||||
|
@ -183,13 +185,14 @@ class Beautifier:
|
|||
msg += ", ".join(response)
|
||||
except Exception:
|
||||
logSys.warning("Beautifier error. Please report the error")
|
||||
logSys.error("Beautify " + `response` + " with " + `self.__inputCmd` +
|
||||
" failed")
|
||||
msg = msg + `response`
|
||||
logSys.error("Beautify " + repr(response) + " with "
|
||||
+ repr(self.__inputCmd) + " failed")
|
||||
msg = msg + repr(response)
|
||||
return msg
|
||||
|
||||
def beautifyError(self, response):
|
||||
logSys.debug("Beautify (error) " + `response` + " with " + `self.__inputCmd`)
|
||||
logSys.debug("Beautify (error) " + repr(response) + " with "
|
||||
+ repr(self.__inputCmd))
|
||||
msg = response
|
||||
if isinstance(response, UnknownJailException):
|
||||
msg = "Sorry but the jail '" + response.args[0] + "' does not exist"
|
||||
|
|
|
@ -24,7 +24,8 @@ __author__ = 'Yaroslav Halhenko'
|
|||
__copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko'
|
||||
__license__ = 'GPL'
|
||||
|
||||
import os, sys
|
||||
import os
|
||||
import sys
|
||||
from ..helpers import getLogger
|
||||
|
||||
if sys.version_info >= (3,2): # pragma: no cover
|
||||
|
@ -66,6 +67,7 @@ logLevel = 7
|
|||
|
||||
__all__ = ['SafeConfigParserWithIncludes']
|
||||
|
||||
|
||||
class SafeConfigParserWithIncludes(SafeConfigParser):
|
||||
"""
|
||||
Class adds functionality to SafeConfigParser to handle included
|
||||
|
|
|
@ -24,7 +24,8 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import glob, os
|
||||
import glob
|
||||
import os
|
||||
from ConfigParser import NoOptionError, NoSectionError
|
||||
|
||||
from .configparserinc import SafeConfigParserWithIncludes, logLevel
|
||||
|
@ -33,6 +34,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class ConfigReader():
|
||||
"""Generic config reader class.
|
||||
|
||||
|
@ -135,6 +137,7 @@ class ConfigReader():
|
|||
return self._cfg.getOptions(*args, **kwargs)
|
||||
return {}
|
||||
|
||||
|
||||
class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
||||
"""Unshared config reader (previously ConfigReader).
|
||||
|
||||
|
@ -186,7 +189,7 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
|||
if config_files_read:
|
||||
return True
|
||||
logSys.error("Found no accessible config files for %r under %s",
|
||||
( filename, self.getBaseDir() ))
|
||||
filename, self.getBaseDir())
|
||||
return False
|
||||
else:
|
||||
logSys.error("Found no accessible config files for %r " % filename
|
||||
|
@ -232,10 +235,11 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
|||
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]` + "'")
|
||||
"'. Using default one: '" + repr(option[2]) + "'")
|
||||
values[option[1]] = option[2]
|
||||
return values
|
||||
|
||||
|
||||
class DefinitionInitConfigReader(ConfigReader):
|
||||
"""Config reader for files with options grouped in [Definition] and
|
||||
[Init] sections.
|
||||
|
@ -281,7 +285,7 @@ class DefinitionInitConfigReader(ConfigReader):
|
|||
|
||||
if self.has_section("Init"):
|
||||
for opt in self.options("Init"):
|
||||
if not self._initOpts.has_key(opt):
|
||||
if not opt in self._initOpts:
|
||||
self._initOpts[opt] = self.get("Init", opt)
|
||||
|
||||
def convert(self):
|
||||
|
|
|
@ -31,6 +31,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class Configurator:
|
||||
|
||||
def __init__(self, force_enable=False, share_config=None):
|
||||
|
|
|
@ -26,43 +26,42 @@ __license__ = "GPL"
|
|||
|
||||
#from cPickle import dumps, loads, HIGHEST_PROTOCOL
|
||||
from pickle import dumps, loads, HIGHEST_PROTOCOL
|
||||
import socket, sys
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
# b"" causes SyntaxError in python <= 2.5, so below implements equivalent
|
||||
EMPTY_BYTES = bytes("", encoding="ascii")
|
||||
else:
|
||||
# python 2.x, string type is equivalent to bytes.
|
||||
EMPTY_BYTES = ""
|
||||
from ..protocol import CSPROTO
|
||||
import socket
|
||||
import sys
|
||||
|
||||
class CSocket:
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
END_STRING = bytes("<F2B_END_COMMAND>", encoding='ascii')
|
||||
else:
|
||||
END_STRING = "<F2B_END_COMMAND>"
|
||||
|
||||
def __init__(self, sock = "/var/run/fail2ban/fail2ban.sock"):
|
||||
def __init__(self, sock="/var/run/fail2ban/fail2ban.sock"):
|
||||
# Create an INET, STREAMing socket
|
||||
#self.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.__csock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
#self.csock.connect(("localhost", 2222))
|
||||
self.__csock.connect(sock)
|
||||
|
||||
def __del__(self):
|
||||
self.close(False)
|
||||
|
||||
def send(self, msg):
|
||||
# Convert every list member to string
|
||||
obj = dumps([str(m) for m in msg], HIGHEST_PROTOCOL)
|
||||
self.__csock.send(obj + CSocket.END_STRING)
|
||||
ret = self.receive(self.__csock)
|
||||
self.__csock.send(obj + CSPROTO.END)
|
||||
return self.receive(self.__csock)
|
||||
|
||||
def close(self, sendEnd=True):
|
||||
if not self.__csock:
|
||||
return
|
||||
if sendEnd:
|
||||
self.__csock.sendall(CSPROTO.CLOSE + CSPROTO.END)
|
||||
self.__csock.close()
|
||||
return ret
|
||||
self.__csock = None
|
||||
|
||||
@staticmethod
|
||||
def receive(sock):
|
||||
msg = EMPTY_BYTES
|
||||
while msg.rfind(CSocket.END_STRING) == -1:
|
||||
msg = CSPROTO.EMPTY
|
||||
while msg.rfind(CSPROTO.END) == -1:
|
||||
chunk = sock.recv(6)
|
||||
if chunk == '':
|
||||
raise RuntimeError, "socket connection broken"
|
||||
raise RuntimeError("socket connection broken")
|
||||
msg = msg + chunk
|
||||
return loads(msg)
|
||||
|
|
|
@ -30,6 +30,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class Fail2banReader(ConfigReader):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
@ -52,18 +53,14 @@ class Fail2banReader(ConfigReader):
|
|||
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
|
||||
|
||||
def convert(self):
|
||||
# Ensure logtarget/level set first so any db errors are captured
|
||||
# Also dbfile should be set before all other database options.
|
||||
# So adding order indices into items, to be stripped after sorting, upon return
|
||||
order = {"syslogsocket":0, "loglevel":1, "logtarget":2,
|
||||
"dbfile":50, "dbpurgeage":51}
|
||||
stream = list()
|
||||
for opt in self.__opts:
|
||||
if opt == "loglevel":
|
||||
stream.append(["set", "loglevel", self.__opts[opt]])
|
||||
elif opt == "logtarget":
|
||||
stream.append(["set", "logtarget", self.__opts[opt]])
|
||||
elif opt == "syslogsocket":
|
||||
stream.append(["set", "syslogsocket", self.__opts[opt]])
|
||||
elif opt == "dbfile":
|
||||
stream.append(["set", "dbfile", self.__opts[opt]])
|
||||
elif opt == "dbpurgeage":
|
||||
stream.append(["set", "dbpurgeage", self.__opts[opt]])
|
||||
# Ensure logtarget/level set first so any db errors are captured
|
||||
return sorted(stream, reverse=True)
|
||||
if opt in order:
|
||||
stream.append((order[opt], ["set", opt, self.__opts[opt]]))
|
||||
return [opt[1] for opt in sorted(stream)]
|
||||
|
||||
|
|
|
@ -24,7 +24,8 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import os, shlex
|
||||
import os
|
||||
import shlex
|
||||
|
||||
from .configreader import DefinitionInitConfigReader
|
||||
from ..server.action import CommandAction
|
||||
|
@ -33,6 +34,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class FilterReader(DefinitionInitConfigReader):
|
||||
|
||||
_configOpts = [
|
||||
|
|
|
@ -24,8 +24,10 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import re, glob, os.path
|
||||
import glob
|
||||
import json
|
||||
import os.path
|
||||
import re
|
||||
|
||||
from .configreader import ConfigReaderUnshared, ConfigReader
|
||||
from .filterreader import FilterReader
|
||||
|
@ -35,6 +37,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class JailReader(ConfigReader):
|
||||
|
||||
optionCRE = re.compile("^((?:\w|-|_|\.)+)(?:\[(.*)\])?$")
|
||||
|
|
|
@ -31,6 +31,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class JailsReader(ConfigReader):
|
||||
|
||||
def __init__(self, force_enable=False, **kwargs):
|
||||
|
@ -50,6 +51,7 @@ class JailsReader(ConfigReader):
|
|||
return self.__jails
|
||||
|
||||
def read(self):
|
||||
self.__jails = list()
|
||||
return ConfigReader.read(self, "jail")
|
||||
|
||||
def getOptions(self, section=None):
|
||||
|
|
|
@ -23,12 +23,14 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2012 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
|
||||
#
|
||||
# Jails
|
||||
#
|
||||
class DuplicateJailException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class UnknownJailException(KeyError):
|
||||
pass
|
||||
|
||||
|
|
|
@ -26,11 +26,13 @@ import traceback
|
|||
import re
|
||||
import logging
|
||||
|
||||
|
||||
def formatExceptionInfo():
|
||||
""" Consistently format exception information """
|
||||
cla, exc = sys.exc_info()[:2]
|
||||
return (cla.__name__, str(exc))
|
||||
|
||||
|
||||
#
|
||||
# Following "traceback" functions are adopted from PyMVPA distributed
|
||||
# under MIT/Expat and copyright by PyMVPA developers (i.e. me and
|
||||
|
@ -49,6 +51,7 @@ def mbasename(s):
|
|||
base = os.path.basename(os.path.dirname(s)) + '.' + base
|
||||
return base
|
||||
|
||||
|
||||
class TraceBack(object):
|
||||
"""Customized traceback to be included in debug messages
|
||||
"""
|
||||
|
@ -94,6 +97,7 @@ class TraceBack(object):
|
|||
|
||||
return sftb
|
||||
|
||||
|
||||
class FormatterWithTraceBack(logging.Formatter):
|
||||
"""Custom formatter which expands %(tb) and %(tbc) with tracebacks
|
||||
|
||||
|
@ -108,6 +112,7 @@ class FormatterWithTraceBack(logging.Formatter):
|
|||
record.tbc = record.tb = self._tb()
|
||||
return logging.Formatter.format(self, record)
|
||||
|
||||
|
||||
def getLogger(name):
|
||||
"""Get logging.Logger instance with Fail2Ban logger name convention
|
||||
"""
|
||||
|
@ -115,6 +120,7 @@ def getLogger(name):
|
|||
name = "fail2ban.%s" % name.rpartition(".")[-1]
|
||||
return logging.getLogger(name)
|
||||
|
||||
|
||||
def excepthook(exctype, value, traceback):
|
||||
"""Except hook used to log unhandled exceptions to Fail2Ban log
|
||||
"""
|
||||
|
|
|
@ -29,6 +29,16 @@ import textwrap
|
|||
##
|
||||
# Describes the protocol used to communicate with the server.
|
||||
|
||||
class dotdict(dict):
|
||||
def __getattr__(self, name):
|
||||
return self[name]
|
||||
|
||||
CSPROTO = dotdict({
|
||||
"EMPTY": b"",
|
||||
"END": b"<F2B_END_COMMAND>",
|
||||
"CLOSE": b"<F2B_CLOSE_COMMAND>"
|
||||
})
|
||||
|
||||
protocol = [
|
||||
['', "BASIC", ""],
|
||||
["start", "starts the server and the jails"],
|
||||
|
@ -119,6 +129,7 @@ protocol = [
|
|||
["get <JAIL> action <ACT> <PROPERTY>", "gets the value of <PROPERTY> for the action <ACT> for <JAIL>"],
|
||||
]
|
||||
|
||||
|
||||
##
|
||||
# Prints the protocol in a "man" format. This is used for the
|
||||
# "-h" output of fail2ban-client.
|
||||
|
@ -143,6 +154,7 @@ def printFormatted():
|
|||
line = ' ' * (INDENT + MARGIN) + n.strip()
|
||||
print line
|
||||
|
||||
|
||||
##
|
||||
# Prints the protocol in a "mediawiki" format.
|
||||
|
||||
|
@ -159,6 +171,7 @@ def printWiki():
|
|||
print "| <span style=\"white-space:nowrap;\"><tt>" + m[0] + "</tt></span> || || " + m[1]
|
||||
print "|}"
|
||||
|
||||
|
||||
def __printWikiHeader(section, desc):
|
||||
print
|
||||
print "=== " + section + " ==="
|
||||
|
|
|
@ -21,8 +21,14 @@ __author__ = "Cyril Jaquier and Fail2Ban Contributors"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2012 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import logging, os, subprocess, time, signal, tempfile
|
||||
import threading, re
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
from abc import ABCMeta
|
||||
from collections import MutableMapping
|
||||
|
||||
|
@ -49,6 +55,7 @@ _RETCODE_HINTS = {
|
|||
signame = dict((num, name)
|
||||
for name, num in signal.__dict__.iteritems() if name.startswith("SIG"))
|
||||
|
||||
|
||||
class CallingMap(MutableMapping):
|
||||
"""A Mapping type which returns the result of callable values.
|
||||
|
||||
|
@ -94,6 +101,7 @@ class CallingMap(MutableMapping):
|
|||
def copy(self):
|
||||
return self.__class__(self.data.copy())
|
||||
|
||||
|
||||
class ActionBase(object):
|
||||
"""An abstract base class for actions in Fail2Ban.
|
||||
|
||||
|
@ -176,6 +184,7 @@ class ActionBase(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class CommandAction(ActionBase):
|
||||
"""A action which executes OS shell commands.
|
||||
|
||||
|
@ -400,7 +409,7 @@ class CommandAction(ActionBase):
|
|||
# recursive definitions are bad
|
||||
#logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
|
||||
return False
|
||||
if found_tag in cls._escapedTags or not tags.has_key(found_tag):
|
||||
if found_tag in cls._escapedTags or not found_tag in tags:
|
||||
# Escaped or missing tags - just continue on searching after end of match
|
||||
# Missing tags are ok - cInfo can contain aInfo elements like <HOST> and valid shell
|
||||
# constructs like <STDIN>.
|
||||
|
@ -516,10 +525,10 @@ class CommandAction(ActionBase):
|
|||
realCmd = self.replaceTag(cmd, aInfo)
|
||||
else:
|
||||
realCmd = cmd
|
||||
|
||||
|
||||
# Replace static fields
|
||||
realCmd = self.replaceTag(realCmd, self._properties)
|
||||
|
||||
|
||||
return self.executeCmd(realCmd, self.timeout)
|
||||
|
||||
@staticmethod
|
||||
|
@ -549,14 +558,16 @@ class CommandAction(ActionBase):
|
|||
if not realCmd:
|
||||
logSys.debug("Nothing to do")
|
||||
return True
|
||||
|
||||
|
||||
_cmd_lock.acquire()
|
||||
try: # Try wrapped within another try needed for python version < 2.5
|
||||
stdout = tempfile.TemporaryFile(suffix=".stdout", prefix="fai2ban_")
|
||||
stderr = tempfile.TemporaryFile(suffix=".stderr", prefix="fai2ban_")
|
||||
try:
|
||||
popen = subprocess.Popen(
|
||||
realCmd, stdout=stdout, stderr=stderr, shell=True)
|
||||
realCmd, stdout=stdout, stderr=stderr, shell=True,
|
||||
preexec_fn=os.setsid # so that killpg does not kill our process
|
||||
)
|
||||
stime = time.time()
|
||||
retcode = popen.poll()
|
||||
while time.time() - stime <= timeout and retcode is None:
|
||||
|
@ -565,11 +576,12 @@ class CommandAction(ActionBase):
|
|||
if retcode is None:
|
||||
logSys.error("%s -- timed out after %i seconds." %
|
||||
(realCmd, timeout))
|
||||
os.kill(popen.pid, signal.SIGTERM) # Terminate the process
|
||||
pgid = os.getpgid(popen.pid)
|
||||
os.killpg(pgid, signal.SIGTERM) # Terminate the process
|
||||
time.sleep(0.1)
|
||||
retcode = popen.poll()
|
||||
if retcode is None: # Still going...
|
||||
os.kill(popen.pid, signal.SIGKILL) # Kill the process
|
||||
os.killpg(pgid, signal.SIGKILL) # Kill the process
|
||||
time.sleep(0.1)
|
||||
retcode = popen.poll()
|
||||
except OSError, e:
|
||||
|
@ -602,4 +614,4 @@ class CommandAction(ActionBase):
|
|||
% (retcode, msg % locals()))
|
||||
return False
|
||||
raise RuntimeError("Command execution failed: %s" % realCmd)
|
||||
|
||||
|
||||
|
|
|
@ -24,9 +24,10 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import time, logging
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
if sys.version_info >= (3, 3):
|
||||
import importlib.machinery
|
||||
else:
|
||||
|
@ -46,6 +47,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class Actions(JailThread, Mapping):
|
||||
"""Handles jail actions.
|
||||
|
||||
|
@ -192,13 +194,14 @@ class Actions(JailThread, Mapping):
|
|||
ValueError
|
||||
If `ip` is not banned
|
||||
"""
|
||||
# Always delete ip from database (also if currently not banned)
|
||||
if self._jail.database is not None:
|
||||
self._jail.database.delBan(self._jail, ip)
|
||||
# Find the ticket with the IP.
|
||||
ticket = self.__banManager.getTicketByIP(ip)
|
||||
if ticket is not None:
|
||||
# Unban the IP.
|
||||
self.__unBan(ticket)
|
||||
if self._jail.database is not None:
|
||||
self._jail.database.delBan(self._jail, ticket)
|
||||
else:
|
||||
raise ValueError("IP %s is not banned" % ip)
|
||||
|
||||
|
@ -294,7 +297,7 @@ class Actions(JailThread, Mapping):
|
|||
True if an IP address get banned.
|
||||
"""
|
||||
ticket = self._jail.getFailTicket()
|
||||
if ticket != False:
|
||||
if ticket:
|
||||
aInfo = CallingMap()
|
||||
bTicket = BanManager.createBanTicket(ticket)
|
||||
ip = bTicket.getIP()
|
||||
|
|
|
@ -25,20 +25,20 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
|||
__license__ = "GPL"
|
||||
|
||||
from pickle import dumps, loads, HIGHEST_PROTOCOL
|
||||
import asyncore, asynchat, socket, os, sys, traceback, fcntl
|
||||
import asynchat
|
||||
import asyncore
|
||||
import fcntl
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from ..protocol import CSPROTO
|
||||
from ..helpers import getLogger,formatExceptionInfo
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
# b"" causes SyntaxError in python <= 2.5, so below implements equivalent
|
||||
EMPTY_BYTES = bytes("", encoding="ascii")
|
||||
else:
|
||||
# python 2.x, string type is equivalent to bytes.
|
||||
EMPTY_BYTES = ""
|
||||
|
||||
##
|
||||
# Request handler class.
|
||||
#
|
||||
|
@ -47,17 +47,12 @@ else:
|
|||
|
||||
class RequestHandler(asynchat.async_chat):
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
END_STRING = bytes("<F2B_END_COMMAND>", encoding="ascii")
|
||||
else:
|
||||
END_STRING = "<F2B_END_COMMAND>"
|
||||
|
||||
def __init__(self, conn, transmitter):
|
||||
asynchat.async_chat.__init__(self, conn)
|
||||
self.__transmitter = transmitter
|
||||
self.__buffer = []
|
||||
# Sets the terminator.
|
||||
self.set_terminator(RequestHandler.END_STRING)
|
||||
self.set_terminator(CSPROTO.END)
|
||||
|
||||
def collect_incoming_data(self, data):
|
||||
#logSys.debug("Received raw data: " + str(data))
|
||||
|
@ -69,16 +64,23 @@ class RequestHandler(asynchat.async_chat):
|
|||
# This method is called once we have a complete request.
|
||||
|
||||
def found_terminator(self):
|
||||
# Pop whole buffer
|
||||
message = self.__buffer
|
||||
self.__buffer = []
|
||||
# Joins the buffer items.
|
||||
message = loads(EMPTY_BYTES.join(self.__buffer))
|
||||
message = CSPROTO.EMPTY.join(message)
|
||||
# Closes the channel if close was received
|
||||
if message == CSPROTO.CLOSE:
|
||||
self.close_when_done()
|
||||
return
|
||||
# Deserialize
|
||||
message = loads(message)
|
||||
# Gives the message to the transmitter.
|
||||
message = self.__transmitter.proceed(message)
|
||||
# Serializes the response.
|
||||
message = dumps(message, HIGHEST_PROTOCOL)
|
||||
# Sends the response to the client.
|
||||
self.push(message + RequestHandler.END_STRING)
|
||||
# Closes the channel.
|
||||
self.close_when_done()
|
||||
self.push(message + CSPROTO.END)
|
||||
|
||||
def handle_error(self):
|
||||
e1, e2 = formatExceptionInfo()
|
||||
|
@ -86,6 +88,7 @@ class RequestHandler(asynchat.async_chat):
|
|||
logSys.error(traceback.format_exc().splitlines())
|
||||
self.close()
|
||||
|
||||
|
||||
##
|
||||
# Asynchronous server class.
|
||||
#
|
||||
|
@ -181,6 +184,7 @@ class AsyncServer(asyncore.dispatcher):
|
|||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags|fcntl.FD_CLOEXEC)
|
||||
|
||||
|
||||
##
|
||||
# AsyncServerException is used to wrap communication exceptions.
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
##
|
||||
# Banning Manager.
|
||||
#
|
||||
|
@ -270,20 +271,19 @@ class BanManager:
|
|||
return False
|
||||
finally:
|
||||
self.__lock.release()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Get the size of the ban list.
|
||||
#
|
||||
# @return the size
|
||||
|
||||
|
||||
def size(self):
|
||||
try:
|
||||
self.__lock.acquire()
|
||||
return len(self.__banList)
|
||||
finally:
|
||||
self.__lock.release()
|
||||
|
||||
|
||||
##
|
||||
# Check if a ticket is in the list.
|
||||
#
|
||||
|
|
|
@ -21,11 +21,12 @@ __author__ = "Steven Hiscocks"
|
|||
__copyright__ = "Copyright (c) 2013 Steven Hiscocks"
|
||||
__license__ = "GPL"
|
||||
|
||||
import sys
|
||||
import shutil, time
|
||||
import sqlite3
|
||||
import json
|
||||
import locale
|
||||
import shutil
|
||||
import sqlite3
|
||||
import sys
|
||||
import time
|
||||
from functools import wraps
|
||||
from threading import RLock
|
||||
|
||||
|
@ -45,6 +46,7 @@ if sys.version_info >= (3,):
|
|||
logSys.error('json dumps failed: %s', e)
|
||||
x = '{}'
|
||||
return x
|
||||
|
||||
def _json_loads_safe(x):
|
||||
try:
|
||||
x = json.loads(x.decode(
|
||||
|
@ -63,6 +65,7 @@ else:
|
|||
return x.encode(locale.getpreferredencoding())
|
||||
else:
|
||||
return x
|
||||
|
||||
def _json_dumps_safe(x):
|
||||
try:
|
||||
x = json.dumps(_normalize(x), ensure_ascii=False).decode(
|
||||
|
@ -71,6 +74,7 @@ else:
|
|||
logSys.error('json dumps failed: %s', e)
|
||||
x = '{}'
|
||||
return x
|
||||
|
||||
def _json_loads_safe(x):
|
||||
try:
|
||||
x = _normalize(json.loads(x.decode(
|
||||
|
@ -83,6 +87,7 @@ else:
|
|||
sqlite3.register_adapter(dict, _json_dumps_safe)
|
||||
sqlite3.register_converter("JSON", _json_loads_safe)
|
||||
|
||||
|
||||
def commitandrollback(f):
|
||||
@wraps(f)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
|
@ -91,6 +96,7 @@ def commitandrollback(f):
|
|||
return f(self, self._db.cursor(), *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
class Fail2BanDb(object):
|
||||
"""Fail2Ban database for storing persistent data.
|
||||
|
||||
|
@ -155,6 +161,7 @@ class Fail2BanDb(object):
|
|||
"CREATE INDEX bans_jail_ip ON bans(jail, ip);" \
|
||||
"CREATE INDEX bans_ip ON bans(ip);" \
|
||||
|
||||
|
||||
def __init__(self, filename, purgeAge=24*60*60):
|
||||
try:
|
||||
self._lock = RLock()
|
||||
|
@ -411,19 +418,20 @@ class Fail2BanDb(object):
|
|||
"failures": ticket.getAttempt()}))
|
||||
|
||||
@commitandrollback
|
||||
def delBan(self, cur, jail, ticket):
|
||||
def delBan(self, cur, jail, ip):
|
||||
"""Delete a ban from the database.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
jail : Jail
|
||||
Jail in which the ban has occurred.
|
||||
ticket : BanTicket
|
||||
Ticket of the ban to be removed.
|
||||
ip : str
|
||||
IP to be removed.
|
||||
"""
|
||||
queryArgs = (jail.name, ip);
|
||||
cur.execute(
|
||||
"DELETE FROM bans WHERE jail = ? AND ip = ? AND timeofban = ?",
|
||||
(jail.name, ticket.getIP(), int(round(ticket.getTime()))))
|
||||
"DELETE FROM bans WHERE jail = ? AND ip = ?",
|
||||
queryArgs);
|
||||
|
||||
@commitandrollback
|
||||
def _getBans(self, cur, jail=None, bantime=None, ip=None):
|
||||
|
|
|
@ -29,6 +29,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class DateDetector(object):
|
||||
"""Manages one or more date templates to find a date within a log line.
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ class DateEpoch(DateTemplate):
|
|||
return (float(dateMatch.group()), dateMatch)
|
||||
return None
|
||||
|
||||
|
||||
class DatePatternRegex(DateTemplate):
|
||||
"""Date template, with regex/pattern
|
||||
|
||||
|
@ -236,6 +237,7 @@ class DatePatternRegex(DateTemplate):
|
|||
if value is not None)
|
||||
return reGroupDictStrptime(groupdict), dateMatch
|
||||
|
||||
|
||||
class DateTai64n(DateTemplate):
|
||||
"""A date template which matches TAI64N formate timestamps.
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class FailData:
|
||||
|
||||
def __init__(self):
|
||||
|
|
|
@ -34,6 +34,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class FailManager:
|
||||
|
||||
def __init__(self):
|
||||
|
@ -91,7 +92,7 @@ class FailManager:
|
|||
ip = ticket.getIP()
|
||||
unixTime = ticket.getTime()
|
||||
matches = ticket.getMatches()
|
||||
if self.__failList.has_key(ip):
|
||||
if ip in self.__failList:
|
||||
fData = self.__failList[ip]
|
||||
if fData.getLastReset() < unixTime - self.__maxTime:
|
||||
fData.setLastReset(unixTime)
|
||||
|
@ -136,7 +137,7 @@ class FailManager:
|
|||
self.__lock.release()
|
||||
|
||||
def __delFailure(self, ip):
|
||||
if self.__failList.has_key(ip):
|
||||
if ip in self.__failList:
|
||||
del self.__failList[ip]
|
||||
|
||||
def toBan(self):
|
||||
|
@ -154,5 +155,6 @@ class FailManager:
|
|||
finally:
|
||||
self.__lock.release()
|
||||
|
||||
|
||||
class FailManagerEmpty(Exception):
|
||||
pass
|
||||
|
|
|
@ -21,7 +21,10 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import re, sre_constants, sys
|
||||
import re
|
||||
import sre_constants
|
||||
import sys
|
||||
|
||||
|
||||
##
|
||||
# Regular expression class.
|
||||
|
@ -55,6 +58,7 @@ class Regex:
|
|||
except sre_constants.error:
|
||||
raise RegexException("Unable to compile regular expression '%s'" %
|
||||
regex)
|
||||
|
||||
def __str__(self):
|
||||
return "%s(%r)" % (self.__class__.__name__, self._regex)
|
||||
##
|
||||
|
@ -91,7 +95,6 @@ class Regex:
|
|||
except ValueError:
|
||||
self._matchLineEnd = len(self._matchCache.string)
|
||||
|
||||
|
||||
lineCount1 = self._matchCache.string.count(
|
||||
"\n", 0, self._matchLineStart)
|
||||
lineCount2 = self._matchCache.string.count(
|
||||
|
@ -182,6 +185,7 @@ class Regex:
|
|||
else:
|
||||
return ["".join(line) for line in self._matchedTupleLines]
|
||||
|
||||
|
||||
##
|
||||
# Exception dedicated to the class Regex.
|
||||
|
||||
|
|
|
@ -21,7 +21,12 @@ __author__ = "Cyril Jaquier and Fail2Ban Contributors"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import re, os, fcntl, sys, locale, codecs
|
||||
import codecs
|
||||
import fcntl
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from .failmanager import FailManagerEmpty, FailManager
|
||||
from .ticket import FailTicket
|
||||
|
@ -43,6 +48,7 @@ logSys = getLogger(__name__)
|
|||
# that matches a given regular expression. This class is instantiated by
|
||||
# a Jail object.
|
||||
|
||||
|
||||
class Filter(JailThread):
|
||||
|
||||
##
|
||||
|
@ -81,7 +87,6 @@ class Filter(JailThread):
|
|||
self.dateDetector.addDefaultTemplate()
|
||||
logSys.debug("Created %s" % self)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%r)" % (self.__class__.__name__, self.jail)
|
||||
|
||||
|
@ -104,7 +109,6 @@ class Filter(JailThread):
|
|||
logSys.error(e)
|
||||
raise e
|
||||
|
||||
|
||||
def delFailRegex(self, index):
|
||||
try:
|
||||
del self.__failRegex[index]
|
||||
|
@ -390,7 +394,6 @@ class Filter(JailThread):
|
|||
|
||||
return False
|
||||
|
||||
|
||||
def processLine(self, line, date=None, returnRawHost=False,
|
||||
checkAllRegex=False):
|
||||
"""Split the time portion from log msg and return findFailures on them
|
||||
|
@ -576,7 +579,6 @@ class FileFilter(Filter):
|
|||
# to be overridden by backends
|
||||
pass
|
||||
|
||||
|
||||
##
|
||||
# Delete a log path
|
||||
#
|
||||
|
@ -716,6 +718,7 @@ except ImportError: # pragma: no cover
|
|||
import md5
|
||||
md5sum = md5.new
|
||||
|
||||
|
||||
class FileContainer:
|
||||
|
||||
def __init__(self, filename, encoding, tail = False):
|
||||
|
@ -839,7 +842,9 @@ class JournalFilter(Filter): # pragma: systemd no cover
|
|||
# This class contains only static methods used to handle DNS and IP
|
||||
# addresses.
|
||||
|
||||
import socket, struct
|
||||
import socket
|
||||
import struct
|
||||
|
||||
|
||||
class DNSUtils:
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2012 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import time, fcntl
|
||||
import fcntl
|
||||
import time
|
||||
|
||||
import gamin
|
||||
|
||||
|
@ -35,6 +36,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
##
|
||||
# Log reader class.
|
||||
#
|
||||
|
@ -60,16 +62,14 @@ class FilterGamin(FileFilter):
|
|||
fcntl.fcntl(fd, fcntl.F_SETFD, flags|fcntl.FD_CLOEXEC)
|
||||
logSys.debug("Created FilterGamin")
|
||||
|
||||
|
||||
def callback(self, path, event):
|
||||
logSys.debug("Got event: " + `event` + " for " + path)
|
||||
logSys.debug("Got event: " + repr(event) + " for " + path)
|
||||
if event in (gamin.GAMCreated, gamin.GAMChanged, gamin.GAMExists):
|
||||
logSys.debug("File changed: " + path)
|
||||
self.__modified = True
|
||||
|
||||
self._process_file(path)
|
||||
|
||||
|
||||
def _process_file(self, path):
|
||||
"""Process a given file
|
||||
|
||||
|
@ -121,7 +121,6 @@ class FilterGamin(FileFilter):
|
|||
logSys.debug(self.jail.name + ": filter terminated")
|
||||
return True
|
||||
|
||||
|
||||
def stop(self):
|
||||
super(FilterGamin, self).stop()
|
||||
self.__cleanup()
|
||||
|
|
|
@ -24,7 +24,8 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier; 2012 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import time, os
|
||||
import os
|
||||
import time
|
||||
|
||||
from .failmanager import FailManagerEmpty
|
||||
from .filter import FileFilter
|
||||
|
@ -34,6 +35,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
##
|
||||
# Log reader class.
|
||||
#
|
||||
|
|
|
@ -51,6 +51,7 @@ except Exception, e:
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
##
|
||||
# Log reader class.
|
||||
#
|
||||
|
@ -73,7 +74,6 @@ class FilterPyinotify(FileFilter):
|
|||
self.__watches = dict()
|
||||
logSys.debug("Created FilterPyinotify")
|
||||
|
||||
|
||||
def callback(self, event, origin=''):
|
||||
logSys.debug("%sCallback for Event: %s", origin, event)
|
||||
path = event.pathname
|
||||
|
@ -95,7 +95,6 @@ class FilterPyinotify(FileFilter):
|
|||
|
||||
self._process_file(path)
|
||||
|
||||
|
||||
def _process_file(self, path):
|
||||
"""Process a given file
|
||||
|
||||
|
@ -112,7 +111,6 @@ class FilterPyinotify(FileFilter):
|
|||
self.dateDetector.sortTemplate()
|
||||
self.__modified = False
|
||||
|
||||
|
||||
def _addFileWatcher(self, path):
|
||||
wd = self.__monitor.add_watch(path, pyinotify.IN_MODIFY)
|
||||
self.__watches.update(wd)
|
||||
|
@ -144,7 +142,6 @@ class FilterPyinotify(FileFilter):
|
|||
self._addFileWatcher(path)
|
||||
self._process_file(path)
|
||||
|
||||
|
||||
##
|
||||
# Delete a log path
|
||||
#
|
||||
|
@ -163,7 +160,6 @@ class FilterPyinotify(FileFilter):
|
|||
self.__monitor.rm_watch(wdInt)
|
||||
logSys.debug("Removed monitor for the parent directory %s", path_dir)
|
||||
|
||||
|
||||
##
|
||||
# Main loop.
|
||||
#
|
||||
|
|
|
@ -22,7 +22,8 @@ __author__ = "Steven Hiscocks"
|
|||
__copyright__ = "Copyright (c) 2013 Steven Hiscocks"
|
||||
__license__ = "GPL"
|
||||
|
||||
import datetime, time
|
||||
import datetime
|
||||
import time
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
from systemd import journal
|
||||
|
@ -37,6 +38,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
##
|
||||
# Journal reader class.
|
||||
#
|
||||
|
@ -60,7 +62,6 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
|||
self.setDatePattern(None)
|
||||
logSys.debug("Created FilterSystemd")
|
||||
|
||||
|
||||
##
|
||||
# Add a journal match filters from list structure
|
||||
#
|
||||
|
|
|
@ -23,7 +23,8 @@ __author__ = "Cyril Jaquier, Lee Clemens, Yaroslav Halchenko"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2012 Lee Clemens, 2012 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import Queue, logging
|
||||
import logging
|
||||
import Queue
|
||||
|
||||
from .actions import Actions
|
||||
from ..helpers import getLogger
|
||||
|
@ -31,6 +32,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class Jail:
|
||||
"""Fail2Ban jail, which manages a filter and associated actions.
|
||||
|
||||
|
@ -115,7 +117,6 @@ class Jail:
|
|||
raise RuntimeError(
|
||||
"Failed to initialize any backend for Jail %r" % self.name)
|
||||
|
||||
|
||||
def _initPolling(self):
|
||||
from filterpoll import FilterPoll
|
||||
logSys.info("Jail '%s' uses poller" % self.name)
|
||||
|
|
|
@ -30,6 +30,7 @@ from abc import abstractmethod
|
|||
|
||||
from ..helpers import excepthook
|
||||
|
||||
|
||||
class JailThread(Thread):
|
||||
"""Abstract class for threading elements in Fail2Ban.
|
||||
|
||||
|
@ -59,6 +60,7 @@ class JailThread(Thread):
|
|||
# excepthook workaround for threads, derived from:
|
||||
# http://bugs.python.org/issue1230540#msg91244
|
||||
run = self.run
|
||||
|
||||
def run_with_except_hook(*args, **kwargs):
|
||||
try:
|
||||
run(*args, **kwargs)
|
||||
|
|
|
@ -21,7 +21,9 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import time, datetime
|
||||
import datetime
|
||||
import time
|
||||
|
||||
|
||||
##
|
||||
# MyTime class.
|
||||
|
|
|
@ -25,7 +25,12 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
|||
__license__ = "GPL"
|
||||
|
||||
from threading import Lock, RLock
|
||||
import logging, logging.handlers, sys, os, signal, stat
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
import signal
|
||||
import stat
|
||||
import sys
|
||||
|
||||
from .jails import Jails
|
||||
from .filter import FileFilter, JournalFilter
|
||||
|
@ -43,6 +48,7 @@ except ImportError:
|
|||
# Dont print error here, as database may not even be used
|
||||
Fail2BanDb = None
|
||||
|
||||
|
||||
class Server:
|
||||
|
||||
def __init__(self, daemon = False):
|
||||
|
@ -61,11 +67,10 @@ class Server:
|
|||
'FreeBSD': '/var/run/log',
|
||||
'Linux': '/dev/log',
|
||||
}
|
||||
self.setSyslogSocket("auto")
|
||||
# Set logging level
|
||||
self.setLogLevel("INFO")
|
||||
self.setLogTarget("STDOUT")
|
||||
self.setSyslogSocket("auto")
|
||||
|
||||
|
||||
def __sigTERMhandler(self, signum, frame):
|
||||
logSys.debug("Caught signal %d. Exiting" % signum)
|
||||
|
@ -139,7 +144,6 @@ class Server:
|
|||
finally:
|
||||
self.__loggingLock.release()
|
||||
|
||||
|
||||
def addJail(self, name, backend):
|
||||
self.__jails.add(name, backend, self.__db)
|
||||
if self.__db is not None:
|
||||
|
@ -494,24 +498,27 @@ class Server:
|
|||
return "flushed"
|
||||
|
||||
def setDatabase(self, filename):
|
||||
if len(self.__jails) == 0:
|
||||
if filename.lower() == "none":
|
||||
self.__db = None
|
||||
else:
|
||||
if Fail2BanDb is not None:
|
||||
self.__db = Fail2BanDb(filename)
|
||||
self.__db.delAllJails()
|
||||
else:
|
||||
logSys.error(
|
||||
"Unable to import fail2ban database module as sqlite "
|
||||
"is not available.")
|
||||
else:
|
||||
# if not changed - nothing to do
|
||||
if self.__db and self.__db.filename == filename:
|
||||
return
|
||||
if not self.__db and filename.lower() == 'none':
|
||||
return
|
||||
if len(self.__jails) != 0:
|
||||
raise RuntimeError(
|
||||
"Cannot change database when there are jails present")
|
||||
if filename.lower() == "none":
|
||||
self.__db = None
|
||||
else:
|
||||
if Fail2BanDb is not None:
|
||||
self.__db = Fail2BanDb(filename)
|
||||
self.__db.delAllJails()
|
||||
else:
|
||||
logSys.error(
|
||||
"Unable to import fail2ban database module as sqlite "
|
||||
"is not available.")
|
||||
|
||||
def getDatabase(self):
|
||||
return self.__db
|
||||
|
||||
|
||||
def __createDaemon(self): # pragma: no cover
|
||||
""" Detach a process from the controlling terminal and run it in the
|
||||
|
|
|
@ -28,6 +28,7 @@ locale_time = LocaleTime()
|
|||
timeRE = TimeRE()
|
||||
timeRE['z'] = r"(?P<z>Z|[+-]\d{2}(?::?[0-5]\d)?)"
|
||||
|
||||
|
||||
def reGroupDictStrptime(found_dict):
|
||||
"""Return time from dictionary of strptime fields
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ from ..helpers import getLogger
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class Ticket:
|
||||
|
||||
def __init__(self, ip, time, matches=None):
|
||||
|
|
|
@ -33,6 +33,7 @@ from .. import version
|
|||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
|
||||
class Transmitter:
|
||||
|
||||
##
|
||||
|
@ -51,7 +52,7 @@ class Transmitter:
|
|||
|
||||
def proceed(self, command):
|
||||
# Deserialize object
|
||||
logSys.debug("Command: " + `command`)
|
||||
logSys.debug("Command: " + repr(command))
|
||||
try:
|
||||
ret = self.__commandHandler(command)
|
||||
ack = 0, ret
|
||||
|
@ -138,6 +139,7 @@ class Transmitter:
|
|||
elif name == "dbpurgeage":
|
||||
db = self.__server.getDatabase()
|
||||
if db is None:
|
||||
logSys.warning("dbpurgeage setting was not in effect since no db yet")
|
||||
return None
|
||||
else:
|
||||
db.purgeage = command[1]
|
||||
|
|
|
@ -32,6 +32,7 @@ from ..dummyjail import DummyJail
|
|||
|
||||
from ..utils import CONFIG_DIR
|
||||
|
||||
|
||||
class TestSMTPServer(smtpd.SMTPServer):
|
||||
|
||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||
|
@ -40,6 +41,7 @@ class TestSMTPServer(smtpd.SMTPServer):
|
|||
self.rcpttos = rcpttos
|
||||
self.data = data
|
||||
|
||||
|
||||
class SMTPActionTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -35,6 +35,7 @@ from .utils import LogCaptureTestCase
|
|||
|
||||
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||
|
||||
|
||||
class ExecuteActions(LogCaptureTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -76,7 +77,6 @@ class ExecuteActions(LogCaptureTestCase):
|
|||
self.assertEqual(self.__actions.getBanTime(),127)
|
||||
self.assertRaises(ValueError, self.__actions.removeBannedIP, '127.0.0.1')
|
||||
|
||||
|
||||
def testActionsOutput(self):
|
||||
self.defaultActions()
|
||||
self.__actions.start()
|
||||
|
@ -89,7 +89,6 @@ class ExecuteActions(LogCaptureTestCase):
|
|||
self.assertEqual(self.__actions.status(),[("Currently banned", 0 ),
|
||||
("Total banned", 0 ), ("Banned IP list", [] )])
|
||||
|
||||
|
||||
def testAddActionPython(self):
|
||||
self.__actions.add(
|
||||
"Action", os.path.join(TEST_FILES_DIR, "action.d/action.py"),
|
||||
|
|
|
@ -24,11 +24,14 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import os
|
||||
import time
|
||||
import tempfile
|
||||
|
||||
from ..server.action import CommandAction, CallingMap
|
||||
|
||||
from .utils import LogCaptureTestCase
|
||||
from .utils import pid_exists
|
||||
|
||||
class CommandActionTest(LogCaptureTestCase):
|
||||
|
||||
|
@ -110,7 +113,6 @@ class CommandActionTest(LogCaptureTestCase):
|
|||
{'ipjailmatches': "some >char< should \< be[ escap}ed&\n"}),
|
||||
"some \\>char\\< should \\\\\\< be\\[ escap\\}ed\\&\n")
|
||||
|
||||
|
||||
# Recursive
|
||||
aInfo["ABC"] = "<xyz>"
|
||||
self.assertEqual(
|
||||
|
@ -202,6 +204,44 @@ class CommandActionTest(LogCaptureTestCase):
|
|||
or self._is_logged('sleep 60 -- timed out after 3 seconds'))
|
||||
self.assertTrue(self._is_logged('sleep 60 -- killed with SIGTERM'))
|
||||
|
||||
def testExecuteTimeoutWithNastyChildren(self):
|
||||
# temporary file for a nasty kid shell script
|
||||
tmpFilename = tempfile.mktemp(".sh", "fail2ban_")
|
||||
# Create a nasty script which would hang there for a while
|
||||
with open(tmpFilename, 'w') as f:
|
||||
f.write("""#!/bin/bash
|
||||
trap : HUP EXIT TERM
|
||||
|
||||
echo "$$" > %s.pid
|
||||
echo "my pid $$ . sleeping lo-o-o-ong"
|
||||
sleep 10000
|
||||
""" % tmpFilename)
|
||||
|
||||
def getnastypid():
|
||||
with open(tmpFilename + '.pid') as f:
|
||||
return int(f.read())
|
||||
|
||||
# First test if can kill the bastard
|
||||
self.assertRaises(
|
||||
RuntimeError, CommandAction.executeCmd, 'bash %s' % tmpFilename, timeout=.1)
|
||||
# Verify that the proccess itself got killed
|
||||
self.assertFalse(pid_exists(getnastypid())) # process should have been killed
|
||||
self.assertTrue(self._is_logged('timed out'))
|
||||
self.assertTrue(self._is_logged('killed with SIGTERM'))
|
||||
|
||||
# A bit evolved case even though, previous test already tests killing children processes
|
||||
self.assertRaises(
|
||||
RuntimeError, CommandAction.executeCmd, 'out=`bash %s`; echo ALRIGHT' % tmpFilename,
|
||||
timeout=.2)
|
||||
# Verify that the proccess itself got killed
|
||||
self.assertFalse(pid_exists(getnastypid()))
|
||||
self.assertTrue(self._is_logged('timed out'))
|
||||
self.assertTrue(self._is_logged('killed with SIGTERM'))
|
||||
|
||||
os.unlink(tmpFilename)
|
||||
os.unlink(tmpFilename + '.pid')
|
||||
|
||||
|
||||
def testCaptureStdOutErr(self):
|
||||
CommandAction.executeCmd('echo "How now brown cow"')
|
||||
self.assertTrue(self._is_logged("'How now brown cow\\n'"))
|
||||
|
|
|
@ -29,6 +29,7 @@ import unittest
|
|||
from ..server.banmanager import BanManager
|
||||
from ..server.ticket import BanTicket
|
||||
|
||||
|
||||
class AddFailure(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Call before every test case."""
|
||||
|
|
|
@ -21,7 +21,13 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import os, glob, shutil, tempfile, unittest, re, logging
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
from ..client.configreader import ConfigReaderUnshared
|
||||
from ..client import configparserinc
|
||||
from ..client.jailreader import JailReader
|
||||
|
@ -39,6 +45,7 @@ STOCK = os.path.exists(os.path.join('config','fail2ban.conf'))
|
|||
|
||||
IMPERFECT_CONFIG = os.path.join(os.path.dirname(__file__), 'config')
|
||||
|
||||
|
||||
class ConfigReaderTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -71,12 +78,10 @@ option = %s
|
|||
os.unlink("%s/%s" % (self.d, fname))
|
||||
self.assertTrue(self.c.read('c')) # we still should have some
|
||||
|
||||
|
||||
def _getoption(self, f='c'):
|
||||
self.assertTrue(self.c.read(f)) # we got some now
|
||||
return self.c.getOptions('section', [("int", 'option')])['option']
|
||||
|
||||
|
||||
def testInaccessibleFile(self):
|
||||
f = os.path.join(self.d, "d.conf") # inaccessible file
|
||||
self._write('d.conf', 0)
|
||||
|
@ -91,7 +96,6 @@ option = %s
|
|||
# raise unittest.SkipTest("Skipping on %s -- access rights are not enforced" % platform)
|
||||
pass
|
||||
|
||||
|
||||
def testOptionalDotDDir(self):
|
||||
self.assertFalse(self.c.read('c')) # nothing is there yet
|
||||
self._write("c.conf", "1")
|
||||
|
@ -153,6 +157,7 @@ c = d ;in line comment
|
|||
self.assertEqual(self.c.get('DEFAULT', 'b'), 'a')
|
||||
self.assertEqual(self.c.get('DEFAULT', 'c'), 'd')
|
||||
|
||||
|
||||
class JailReaderTest(LogCaptureTestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -179,15 +184,19 @@ class JailReaderTest(LogCaptureTestCase):
|
|||
self.assertTrue(self._is_logged("Found no accessible config files for 'filter.d/catchallthebadies' under %s" % IMPERFECT_CONFIG))
|
||||
self.assertTrue(self._is_logged('Unable to read the filter'))
|
||||
|
||||
def TODOtestJailActionBrokenDef(self):
|
||||
jail = JailReader('brokenactiondef', basedir=IMPERFECT_CONFIG, share_config = self.__share_cfg)
|
||||
def testJailActionBrokenDef(self):
|
||||
jail = JailReader('brokenactiondef', basedir=IMPERFECT_CONFIG,
|
||||
share_config=self.__share_cfg)
|
||||
self.assertTrue(jail.read())
|
||||
self.assertFalse(jail.getOptions())
|
||||
self.assertTrue(jail.isEnabled())
|
||||
self.printLog()
|
||||
self.assertTrue(self._is_logged('Error in action definition joho[foo'))
|
||||
self.assertTrue(self._is_logged('Caught exception: While reading action joho[foo we should have got 1 or 2 groups. Got: 0'))
|
||||
|
||||
# This unittest has been deactivated for some time...
|
||||
# self.assertTrue(self._is_logged(
|
||||
# 'Caught exception: While reading action joho[foo we should have got 1 or 2 groups. Got: 0'))
|
||||
# let's test for what is actually logged and handle changes in the future
|
||||
self.assertTrue(self._is_logged(
|
||||
"Caught exception: 'NoneType' object has no attribute 'endswith'"))
|
||||
|
||||
if STOCK:
|
||||
def testStockSSHJail(self):
|
||||
|
@ -218,7 +227,6 @@ class JailReaderTest(LogCaptureTestCase):
|
|||
|
||||
#self.assertRaises(ValueError, JailReader.extractOptions ,'mail-how[')
|
||||
|
||||
|
||||
# Empty option
|
||||
option = "abc[]"
|
||||
expected = ('abc', {})
|
||||
|
@ -312,7 +320,6 @@ class FilterReaderTest(unittest.TestCase):
|
|||
output[-1][-1] = "5"
|
||||
self.assertEqual(sorted(filterReader.convert()), sorted(output))
|
||||
|
||||
|
||||
def testFilterReaderSubstitionDefault(self):
|
||||
output = [['set', 'jailname', 'addfailregex', 'to=sweet@example.com fromip=<IP>']]
|
||||
filterReader = FilterReader('substition', "jailname", {})
|
||||
|
@ -355,6 +362,7 @@ class FilterReaderTest(unittest.TestCase):
|
|||
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):
|
||||
|
@ -474,7 +482,6 @@ class JailsReaderTest(LogCaptureTestCase):
|
|||
self.assertTrue('Init' in actionReader.sections(),
|
||||
msg="Action file %r is lacking [Init] section" % actionConfig)
|
||||
|
||||
|
||||
def testReadStockJailConf(self):
|
||||
jails = JailsReader(basedir=CONFIG_DIR, share_config=self.__share_cfg) # we are running tests from root project dir atm
|
||||
self.assertTrue(jails.read()) # opens fine
|
||||
|
@ -601,7 +608,6 @@ class JailsReaderTest(LogCaptureTestCase):
|
|||
msg="Found no %s command among %s"
|
||||
% (target_command, str(commands)) )
|
||||
|
||||
|
||||
def testStockConfigurator(self):
|
||||
configurator = Configurator()
|
||||
configurator.setBaseDir(CONFIG_DIR)
|
||||
|
@ -616,6 +622,22 @@ class JailsReaderTest(LogCaptureTestCase):
|
|||
configurator.getOptions()
|
||||
configurator.convertToProtocol()
|
||||
commands = configurator.getConfigStream()
|
||||
|
||||
# verify that dbfile comes before dbpurgeage
|
||||
def find_set(option):
|
||||
for i, e in enumerate(commands):
|
||||
if e[0] == 'set' and e[1] == option:
|
||||
return i
|
||||
raise ValueError("Did not find command 'set %s' among commands %s"
|
||||
% (option, commands))
|
||||
|
||||
# Set up of logging should come first
|
||||
self.assertEqual(find_set('syslogsocket'), 0)
|
||||
self.assertEqual(find_set('loglevel'), 1)
|
||||
self.assertEqual(find_set('logtarget'), 2)
|
||||
# then dbfile should be before dbpurgeage
|
||||
self.assertTrue(find_set('dbpurgeage') > find_set('dbfile'))
|
||||
|
||||
# and there is logging information left to be passed into the
|
||||
# server
|
||||
self.assertEqual(sorted(commands),
|
||||
|
|
|
@ -42,6 +42,7 @@ from .utils import LogCaptureTestCase
|
|||
|
||||
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||
|
||||
|
||||
class DatabaseTest(LogCaptureTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -211,7 +212,7 @@ class DatabaseTest(LogCaptureTestCase):
|
|||
def testDelBan(self):
|
||||
self.testAddBan()
|
||||
ticket = self.db.getBans(jail=self.jail)[0]
|
||||
self.db.delBan(self.jail, ticket)
|
||||
self.db.delBan(self.jail, ticket.getIP())
|
||||
self.assertEqual(len(self.db.getBans(jail=self.jail)), 0)
|
||||
|
||||
def testGetBansWithTime(self):
|
||||
|
@ -305,7 +306,7 @@ class DatabaseTest(LogCaptureTestCase):
|
|||
def testActionWithDB(self):
|
||||
# test action together with database functionality
|
||||
self.testAddJail() # Jail required
|
||||
self.jail.database = self.db;
|
||||
self.jail.database = self.db
|
||||
actions = Actions(self.jail)
|
||||
actions.add(
|
||||
"action_checkainfo",
|
||||
|
@ -317,7 +318,6 @@ class DatabaseTest(LogCaptureTestCase):
|
|||
actions._Actions__checkBan()
|
||||
self.assertTrue(self._is_logged("ban ainfo %s, %s, %s, %s" % (True, True, True, True)))
|
||||
|
||||
|
||||
def testPurge(self):
|
||||
if Fail2BanDb is None: # pragma: no cover
|
||||
return
|
||||
|
|
|
@ -32,6 +32,7 @@ from ..server.datedetector import DateDetector
|
|||
from ..server.datetemplate import DateTemplate
|
||||
from .utils import setUpMyTime, tearDownMyTime
|
||||
|
||||
|
||||
class DateDetectorTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -26,6 +26,7 @@ from threading import Lock
|
|||
|
||||
from ..server.actions import Actions
|
||||
|
||||
|
||||
class DummyJail(object):
|
||||
"""A simple 'jail' to suck in all the tickets generated by Filter's
|
||||
"""
|
||||
|
|
|
@ -29,6 +29,7 @@ import unittest
|
|||
from ..server.failmanager import FailManager, FailManagerEmpty
|
||||
from ..server.ticket import FailTicket
|
||||
|
||||
|
||||
class AddFailure(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -100,7 +101,7 @@ class AddFailure(unittest.TestCase):
|
|||
self.assertEqual(
|
||||
ticket_repr,
|
||||
'FailTicket: ip=193.168.0.128 time=1167605999.0 #attempts=5 matches=[]')
|
||||
self.assertFalse(ticket == False)
|
||||
self.assertFalse(not ticket)
|
||||
# and some get/set-ers otherwise not tested
|
||||
ticket.setTime(1000002000.0)
|
||||
self.assertEqual(ticket.getTime(), 1000002000.0)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
from fail2ban.server.action import ActionBase
|
||||
|
||||
|
||||
class TestAction(ActionBase):
|
||||
|
||||
def __init__(self, jail, name, opt1, opt2=None):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
from fail2ban.server.action import ActionBase
|
||||
|
||||
|
||||
class TestAction(ActionBase):
|
||||
|
||||
def ban(self, aInfo):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
from fail2ban.server.action import ActionBase
|
||||
|
||||
|
||||
class TestAction(ActionBase):
|
||||
|
||||
def __init__(self, jail, name):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
from fail2ban.server.action import ActionBase
|
||||
|
||||
|
||||
class TestAction(ActionBase):
|
||||
|
||||
def ban(self, aInfo):
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue