mirror of https://github.com/fail2ban/fail2ban
Merge branch 'master' into py3
Conflicts: .travis.yml server/datetemplate.py server/server.py testcases/filtertestcase.pypull/128/merge^2
commit
77aa523f22
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
[run]
|
||||||
|
branch = True
|
||||||
|
omit = /usr*
|
|
@ -1,3 +1,8 @@
|
||||||
*~
|
*~
|
||||||
build
|
build
|
||||||
|
dist
|
||||||
*.pyc
|
*.pyc
|
||||||
|
htmlcov
|
||||||
|
.coverage
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
|
|
@ -8,8 +8,11 @@ python:
|
||||||
- "3.2"
|
- "3.2"
|
||||||
- "3.3"
|
- "3.3"
|
||||||
install:
|
install:
|
||||||
- "pip install pyinotify"
|
- pip install pyinotify
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.[6-7] ]] || [[ $TRAVIS_PYTHON_VERSION == 3.3 ]]; then pip install -q coveralls; fi
|
||||||
before_script:
|
before_script:
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then ./fail2ban-2to3; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then ./fail2ban-2to3; fi
|
||||||
script:
|
script:
|
||||||
- python ./fail2ban-testcases
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.[6-7] ]] || [[ $TRAVIS_PYTHON_VERSION == 3.3 ]]; then coverage run --rcfile=.travis_coveragerc fail2ban-testcases; else python ./fail2ban-testcases; fi
|
||||||
|
after_script:
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.[6-7] ]] || [[ $TRAVIS_PYTHON_VERSION == 3.3 ]]; then coveralls; fi
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
[run]
|
||||||
|
branch = True
|
||||||
|
omit =
|
||||||
|
/usr/*
|
||||||
|
/home/travis/virtualenv/*
|
||||||
|
server/filtergamin.py
|
132
DEVELOP
132
DEVELOP
|
@ -24,14 +24,100 @@ Request feature. You can find more details on the Fail2Ban wiki
|
||||||
Testing
|
Testing
|
||||||
=======
|
=======
|
||||||
|
|
||||||
Existing tests can be run by executing `fail2ban-testcases`.
|
Existing tests can be run by executing `fail2ban-testcases`. This has options
|
||||||
|
like --log-level that will probably be useful. `fail2ban-testcases --help` for
|
||||||
|
full options.
|
||||||
|
|
||||||
|
Test cases should cover all usual cases, all exception cases and all inside
|
||||||
|
/ outside boundary conditions.
|
||||||
|
|
||||||
|
Test cases should cover all branches. The coverage tool will help identify
|
||||||
|
missing branches. Also see http://nedbatchelder.com/code/coverage/branch.html
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
Install the package python-coverage to visualise your test coverage. Run the
|
||||||
|
following (note: on Debian-based systems, the script is called
|
||||||
|
`python-coverage`):
|
||||||
|
|
||||||
|
coverage run fail2ban-testcases
|
||||||
|
coverage html
|
||||||
|
|
||||||
|
Then look at htmlcov/index.html and see how much coverage your test cases
|
||||||
|
exert over the codebase. Full coverage is a good thing however it may not be
|
||||||
|
complete. Try to ensure tests cover as many independent paths through the
|
||||||
|
code.
|
||||||
|
|
||||||
|
Manual Execution. To run in a development environment do:
|
||||||
|
|
||||||
|
./fail2ban-client -c config/ -s /tmp/f2b.sock -i start
|
||||||
|
|
||||||
|
some quick commands:
|
||||||
|
|
||||||
|
status
|
||||||
|
add test pyinotify
|
||||||
|
status test
|
||||||
|
set test addaction iptables
|
||||||
|
set test actionban iptables echo <ip> <cidr> >> /tmp/ban
|
||||||
|
set test actionunban iptables echo <ip> <cidr> >> /tmp/unban
|
||||||
|
get test actionban iptables
|
||||||
|
get test actionunban iptables
|
||||||
|
set test banip 192.168.2.2
|
||||||
|
status test
|
||||||
|
|
||||||
|
|
||||||
Documentation about creating tests (when tests are required and some guidelines
|
|
||||||
for creating good tests) will be added soon.
|
|
||||||
|
|
||||||
Coding Standards
|
Coding Standards
|
||||||
================
|
================
|
||||||
Coming Soon.
|
|
||||||
|
Style
|
||||||
|
-----
|
||||||
|
|
||||||
|
Please use tabs for now. Keep to 80 columns, at least for readable text.
|
||||||
|
|
||||||
|
Tests
|
||||||
|
-----
|
||||||
|
|
||||||
|
Add tests. They should test all the code you add in a meaning way.
|
||||||
|
|
||||||
|
Coverage
|
||||||
|
--------
|
||||||
|
|
||||||
|
Test coverage should always increase as you add code.
|
||||||
|
|
||||||
|
You may use "# pragma: no cover" in the code for branches of code that support
|
||||||
|
older versions on python. For all other uses of "pragma: no cover" or
|
||||||
|
"pragma: no branch" document the reason why its not covered. "I haven't written
|
||||||
|
a test case" isn't a sufficient reason.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Ensure this documentation is up to date after changes. Also ensure that the man
|
||||||
|
pages still are accurate. Ensure that there is sufficient documentation for
|
||||||
|
your new features to be used.
|
||||||
|
|
||||||
|
Bugs
|
||||||
|
----
|
||||||
|
|
||||||
|
Remove them and don't add any more.
|
||||||
|
|
||||||
|
Git
|
||||||
|
---
|
||||||
|
|
||||||
|
Use the following tags in your commit messages:
|
||||||
|
|
||||||
|
'BF:' for bug fixes
|
||||||
|
'DOC:' for documentation fixes
|
||||||
|
'ENH:' for enhancements
|
||||||
|
'TST:' for commits concerning tests only (thus not touching the main code-base)
|
||||||
|
|
||||||
|
Multiple tags could be joined with +, e.g. "BF+TST:".
|
||||||
|
|
||||||
|
Adding Actions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
If you add an action.d/*.conf file also add a example in config/jail.conf
|
||||||
|
with enabled=false and maxretry=5 for ssh.
|
||||||
|
|
||||||
|
|
||||||
Design
|
Design
|
||||||
|
@ -127,12 +213,14 @@ FileContainer
|
||||||
.__pos
|
.__pos
|
||||||
Keeps the position pointer
|
Keeps the position pointer
|
||||||
|
|
||||||
|
|
||||||
|
dnsutils.py
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
DNSUtils
|
DNSUtils
|
||||||
|
|
||||||
Utility class for DNS and IP handling
|
Utility class for DNS and IP handling
|
||||||
|
|
||||||
RF-Note: convert to functions within a separate submodule
|
|
||||||
|
|
||||||
|
|
||||||
filter*.py
|
filter*.py
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
@ -156,3 +244,35 @@ action.py
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
Takes care about executing start/check/ban/unban/stop commands
|
Takes care about executing start/check/ban/unban/stop commands
|
||||||
|
|
||||||
|
|
||||||
|
Releasing
|
||||||
|
=========
|
||||||
|
|
||||||
|
# Ensure the version is correct in ./common/version.py
|
||||||
|
|
||||||
|
# Add/finalize the corresponding entry in the ChangeLog
|
||||||
|
|
||||||
|
# Update man pages
|
||||||
|
|
||||||
|
(cd man ; ./generate-man )
|
||||||
|
git commit -m 'update man pages for release' man/*
|
||||||
|
|
||||||
|
# Make sure the tests pass
|
||||||
|
|
||||||
|
./fail2ban-testcases-all
|
||||||
|
|
||||||
|
# Prepare/upload source and rpm binary distributions
|
||||||
|
|
||||||
|
python setup.py check
|
||||||
|
python setup.py sdist
|
||||||
|
python setup.py bdist_rpm
|
||||||
|
python setup.py upload
|
||||||
|
|
||||||
|
# Run the following and update the wiki with output:
|
||||||
|
|
||||||
|
python -c 'import common.protocol; common.protocol.printWiki()'
|
||||||
|
|
||||||
|
# Email users and development list of release
|
||||||
|
|
||||||
|
TODO notifying distributors etc.
|
||||||
|
|
18
MANIFEST
18
MANIFEST
|
@ -3,6 +3,8 @@ ChangeLog
|
||||||
TODO
|
TODO
|
||||||
THANKS
|
THANKS
|
||||||
COPYING
|
COPYING
|
||||||
|
DEVELOP
|
||||||
|
doc/run-rootless.txt
|
||||||
fail2ban-client
|
fail2ban-client
|
||||||
fail2ban-server
|
fail2ban-server
|
||||||
fail2ban-testcases
|
fail2ban-testcases
|
||||||
|
@ -41,6 +43,7 @@ server/banmanager.py
|
||||||
server/datetemplate.py
|
server/datetemplate.py
|
||||||
server/mytime.py
|
server/mytime.py
|
||||||
server/failregex.py
|
server/failregex.py
|
||||||
|
testcases/files/testcase-usedns.log
|
||||||
testcases/banmanagertestcase.py
|
testcases/banmanagertestcase.py
|
||||||
testcases/failmanagertestcase.py
|
testcases/failmanagertestcase.py
|
||||||
testcases/clientreadertestcase.py
|
testcases/clientreadertestcase.py
|
||||||
|
@ -49,6 +52,7 @@ testcases/__init__.py
|
||||||
testcases/datedetectortestcase.py
|
testcases/datedetectortestcase.py
|
||||||
testcases/actiontestcase.py
|
testcases/actiontestcase.py
|
||||||
testcases/servertestcase.py
|
testcases/servertestcase.py
|
||||||
|
testcases/sockettestcase.py
|
||||||
testcases/files/testcase01.log
|
testcases/files/testcase01.log
|
||||||
testcases/files/testcase02.log
|
testcases/files/testcase02.log
|
||||||
testcases/files/testcase03.log
|
testcases/files/testcase03.log
|
||||||
|
@ -56,6 +60,7 @@ testcases/files/testcase04.log
|
||||||
setup.py
|
setup.py
|
||||||
setup.cfg
|
setup.cfg
|
||||||
common/__init__.py
|
common/__init__.py
|
||||||
|
common/exceptions.py
|
||||||
common/helpers.py
|
common/helpers.py
|
||||||
common/version.py
|
common/version.py
|
||||||
common/protocol.py
|
common/protocol.py
|
||||||
|
@ -87,6 +92,17 @@ config/filter.d/vsftpd.conf
|
||||||
config/filter.d/webmin-auth.conf
|
config/filter.d/webmin-auth.conf
|
||||||
config/filter.d/wuftpd.conf
|
config/filter.d/wuftpd.conf
|
||||||
config/filter.d/xinetd-fail.conf
|
config/filter.d/xinetd-fail.conf
|
||||||
|
config/filter.d/asterisk.conf
|
||||||
|
config/filter.d/dovecot.conf
|
||||||
|
config/filter.d/dropbear.conf
|
||||||
|
config/filter.d/lighttpd-auth.conf
|
||||||
|
config/filter.d/recidive.conf
|
||||||
|
config/filter.d/roundcube-auth.conf
|
||||||
|
config/action.d/dummy.conf
|
||||||
|
config/action.d/iptables-ipset-proto4.conf
|
||||||
|
config/action.d/iptables-ipset-proto6.conf
|
||||||
|
config/action.d/iptables-xt_recent-echo.conf
|
||||||
|
config/action.d/route.conf
|
||||||
config/action.d/complain.conf
|
config/action.d/complain.conf
|
||||||
config/action.d/dshield.conf
|
config/action.d/dshield.conf
|
||||||
config/action.d/hostsdeny.conf
|
config/action.d/hostsdeny.conf
|
||||||
|
@ -109,6 +125,8 @@ config/action.d/sendmail-whois-lines.conf
|
||||||
config/action.d/shorewall.conf
|
config/action.d/shorewall.conf
|
||||||
config/fail2ban.conf
|
config/fail2ban.conf
|
||||||
man/fail2ban-client.1
|
man/fail2ban-client.1
|
||||||
|
man/fail2ban.1
|
||||||
|
man/jail.conf.5
|
||||||
man/fail2ban-client.h2m
|
man/fail2ban-client.h2m
|
||||||
man/fail2ban-server.1
|
man/fail2ban-server.1
|
||||||
man/fail2ban-server.h2m
|
man/fail2ban-server.h2m
|
||||||
|
|
14
README
14
README
|
@ -51,10 +51,12 @@ call fail2ban-server directly.
|
||||||
Configuration:
|
Configuration:
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
You can configure Fail2ban using the files in /etc/fail2ban. It is possible to
|
You can configure Fail2Ban using the files in /etc/fail2ban. It is
|
||||||
configure the server using commands sent to it by fail2ban-client. The available
|
possible to configure the server using commands sent to it by
|
||||||
commands are described in the man page of fail2ban-client. Please refer to it or
|
fail2ban-client. The available commands are described in the
|
||||||
to the website: http://www.fail2ban.org
|
fail2ban-client(1) manpage. Also see fail2ban(1) manpage for further
|
||||||
|
references and find even more documentation on the website:
|
||||||
|
http://www.fail2ban.org
|
||||||
|
|
||||||
Contact:
|
Contact:
|
||||||
--------
|
--------
|
||||||
|
@ -91,5 +93,5 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Fail2Ban; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
|
Fail2Ban; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
||||||
Suite 330, Boston, MA 02111-1307 USA
|
Street, Fifth Floor, Boston, MA 02110, USA
|
||||||
|
|
2
THANKS
2
THANKS
|
@ -13,6 +13,7 @@ Christian Rauch
|
||||||
Christoph Haas
|
Christoph Haas
|
||||||
Christos Psonis
|
Christos Psonis
|
||||||
Daniel B. Cid
|
Daniel B. Cid
|
||||||
|
Daniel Black
|
||||||
David Nutter
|
David Nutter
|
||||||
Eric Gerbier
|
Eric Gerbier
|
||||||
Guillaume Delvit
|
Guillaume Delvit
|
||||||
|
@ -38,6 +39,7 @@ Robert Edeker
|
||||||
Russell Odom
|
Russell Odom
|
||||||
Sireyessire
|
Sireyessire
|
||||||
Stephen Gildea
|
Stephen Gildea
|
||||||
|
Steven Hiscocks
|
||||||
Tom Pike
|
Tom Pike
|
||||||
Tyler
|
Tyler
|
||||||
Vaclav Misek
|
Vaclav Misek
|
||||||
|
|
7
TODO
7
TODO
|
@ -13,9 +13,12 @@ Legend:
|
||||||
# partially done
|
# partially done
|
||||||
* done
|
* done
|
||||||
|
|
||||||
- Removed relative imports
|
- Run tests though all filters/examples files - (see sshd example file) as unit
|
||||||
|
test
|
||||||
|
|
||||||
- Cleanup fail2ban-client and fail2ban-server. Move code to server/ and client/
|
* Removed relative imports
|
||||||
|
|
||||||
|
* Cleanup fail2ban-client and fail2ban-server. Move code to server/ and client/
|
||||||
|
|
||||||
- Add timeout to external commands (signal alarm, watchdog thread, etc)
|
- Add timeout to external commands (signal alarm, watchdog thread, etc)
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
class ActionReader(ConfigReader):
|
class ActionReader(ConfigReader):
|
||||||
|
|
||||||
def __init__(self, action, name):
|
def __init__(self, action, name, **kwargs):
|
||||||
ConfigReader.__init__(self)
|
ConfigReader.__init__(self, **kwargs)
|
||||||
self.__file = action[0]
|
self.__file = action[0]
|
||||||
self.__cInfo = action[1]
|
self.__cInfo = action[1]
|
||||||
self.__name = name
|
self.__name = name
|
||||||
|
|
|
@ -27,7 +27,7 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import logging, os
|
import glob, logging, os
|
||||||
from configparserinc import SafeConfigParserWithIncludes
|
from configparserinc import SafeConfigParserWithIncludes
|
||||||
from ConfigParser import NoOptionError, NoSectionError
|
from ConfigParser import NoOptionError, NoSectionError
|
||||||
|
|
||||||
|
@ -36,33 +36,61 @@ logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
class ConfigReader(SafeConfigParserWithIncludes):
|
class ConfigReader(SafeConfigParserWithIncludes):
|
||||||
|
|
||||||
BASE_DIRECTORY = "/etc/fail2ban/"
|
DEFAULT_BASEDIR = '/etc/fail2ban'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, basedir=None):
|
||||||
SafeConfigParserWithIncludes.__init__(self)
|
SafeConfigParserWithIncludes.__init__(self)
|
||||||
|
self.setBaseDir(basedir)
|
||||||
self.__opts = None
|
self.__opts = None
|
||||||
|
|
||||||
#@staticmethod
|
def setBaseDir(self, basedir):
|
||||||
def setBaseDir(folderName):
|
if basedir is None:
|
||||||
path = folderName.rstrip('/')
|
basedir = ConfigReader.DEFAULT_BASEDIR # stock system location
|
||||||
ConfigReader.BASE_DIRECTORY = path + '/'
|
self._basedir = basedir.rstrip('/')
|
||||||
setBaseDir = staticmethod(setBaseDir)
|
|
||||||
|
|
||||||
#@staticmethod
|
def getBaseDir(self):
|
||||||
def getBaseDir():
|
return self._basedir
|
||||||
return ConfigReader.BASE_DIRECTORY
|
|
||||||
getBaseDir = staticmethod(getBaseDir)
|
|
||||||
|
|
||||||
def read(self, filename):
|
def read(self, filename):
|
||||||
basename = ConfigReader.BASE_DIRECTORY + filename
|
if not (os.path.exists(self._basedir) and os.access(self._basedir, os.R_OK | os.X_OK)):
|
||||||
logSys.debug("Reading " + basename)
|
raise ValueError("Base configuration directory %s either does not exist "
|
||||||
bConf = basename + ".conf"
|
"or is not accessible" % self._basedir)
|
||||||
bLocal = basename + ".local"
|
basename = os.path.join(self._basedir, filename)
|
||||||
if os.path.exists(bConf) or os.path.exists(bLocal):
|
logSys.debug("Reading configs for %s under %s " % (basename, self._basedir))
|
||||||
SafeConfigParserWithIncludes.read(self, [bConf, bLocal])
|
config_files = [ basename + ".conf",
|
||||||
|
basename + ".local" ]
|
||||||
|
|
||||||
|
# choose only existing ones
|
||||||
|
config_files = filter(os.path.exists, config_files)
|
||||||
|
|
||||||
|
# possible further customizations under a .conf.d directory
|
||||||
|
config_dir = basename + '.d'
|
||||||
|
if os.path.exists(config_dir):
|
||||||
|
if os.path.isdir(config_dir) and os.access(config_dir, os.X_OK | os.R_OK):
|
||||||
|
# files must carry .conf suffix as well
|
||||||
|
config_files += sorted(glob.glob('%s/*.conf' % config_dir))
|
||||||
|
else:
|
||||||
|
logSys.warn("%s exists but not a directory or not accessible"
|
||||||
|
% config_dir)
|
||||||
|
|
||||||
|
# check if files are accessible, warn if any is not accessible
|
||||||
|
# and remove it from the list
|
||||||
|
config_files_accessible = []
|
||||||
|
for f in config_files:
|
||||||
|
if os.access(f, os.R_OK):
|
||||||
|
config_files_accessible.append(f)
|
||||||
|
else:
|
||||||
|
logSys.warn("%s exists but not accessible - skipping" % f)
|
||||||
|
|
||||||
|
if len(config_files_accessible):
|
||||||
|
# at least one config exists and accessible
|
||||||
|
SafeConfigParserWithIncludes.read(self, config_files_accessible)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logSys.error(bConf + " and " + bLocal + " do not exist")
|
logSys.error("Found no accessible config files for %r " % filename
|
||||||
|
+ (["under %s" % self.getBaseDir(),
|
||||||
|
"among existing ones: " + ', '.join(config_files)][bool(len(config_files))]))
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -94,8 +122,8 @@ class ConfigReader(SafeConfigParserWithIncludes):
|
||||||
values[option[1]] = option[2]
|
values[option[1]] = option[2]
|
||||||
except NoOptionError:
|
except NoOptionError:
|
||||||
if not option[2] == None:
|
if not option[2] == None:
|
||||||
logSys.warn("'%s' not defined in '%s'. Using default value"
|
logSys.warn("'%s' not defined in '%s'. Using default one: %r"
|
||||||
% (option[1], sec))
|
% (option[1], sec, option[2]))
|
||||||
values[option[1]] = option[2]
|
values[option[1]] = option[2]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logSys.warn("Wrong value for '" + option[1] + "' in '" + sec +
|
logSys.warn("Wrong value for '" + option[1] + "' in '" + sec +
|
||||||
|
|
|
@ -43,15 +43,19 @@ class Configurator:
|
||||||
self.__fail2ban = Fail2banReader()
|
self.__fail2ban = Fail2banReader()
|
||||||
self.__jails = JailsReader()
|
self.__jails = JailsReader()
|
||||||
|
|
||||||
#@staticmethod
|
def setBaseDir(self, folderName):
|
||||||
def setBaseDir(folderName):
|
self.__fail2ban.setBaseDir(folderName)
|
||||||
ConfigReader.setBaseDir(folderName)
|
self.__jails.setBaseDir(folderName)
|
||||||
setBaseDir = staticmethod(setBaseDir)
|
|
||||||
|
|
||||||
#@staticmethod
|
def getBaseDir(self):
|
||||||
def getBaseDir():
|
fail2ban_basedir = self.__fail2ban.getBaseDir()
|
||||||
return ConfigReader.getBaseDir()
|
jails_basedir = self.__jails.getBaseDir()
|
||||||
getBaseDir = staticmethod(getBaseDir)
|
if fail2ban_basedir != jails_basedir:
|
||||||
|
logSys.error("fail2ban.conf and jails.conf readers have differing "
|
||||||
|
"basedirs: %r and %r. "
|
||||||
|
"Returning the one for fail2ban.conf"
|
||||||
|
% (fail2ban_basedir, jails_basedir))
|
||||||
|
return fail2ban_basedir
|
||||||
|
|
||||||
def readEarly(self):
|
def readEarly(self):
|
||||||
self.__fail2ban.read()
|
self.__fail2ban.read()
|
||||||
|
|
|
@ -35,8 +35,8 @@ logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
class Fail2banReader(ConfigReader):
|
class Fail2banReader(ConfigReader):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, **kwargs):
|
||||||
ConfigReader.__init__(self)
|
ConfigReader.__init__(self, **kwargs)
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
ConfigReader.read(self, "fail2ban")
|
ConfigReader.read(self, "fail2ban")
|
||||||
|
|
|
@ -35,8 +35,8 @@ logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
class FilterReader(ConfigReader):
|
class FilterReader(ConfigReader):
|
||||||
|
|
||||||
def __init__(self, fileName, name):
|
def __init__(self, fileName, name, **kwargs):
|
||||||
ConfigReader.__init__(self)
|
ConfigReader.__init__(self, **kwargs)
|
||||||
self.__file = fileName
|
self.__file = fileName
|
||||||
self.__name = name
|
self.__name = name
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,11 @@ class JailReader(ConfigReader):
|
||||||
|
|
||||||
actionCRE = re.compile("^((?:\w|-|_|\.)+)(?:\[(.*)\])?$")
|
actionCRE = re.compile("^((?:\w|-|_|\.)+)(?:\[(.*)\])?$")
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name, force_enable=False, **kwargs):
|
||||||
ConfigReader.__init__(self)
|
ConfigReader.__init__(self, **kwargs)
|
||||||
self.__name = name
|
self.__name = name
|
||||||
self.__filter = None
|
self.__filter = None
|
||||||
|
self.__force_enable = force_enable
|
||||||
self.__actions = list()
|
self.__actions = list()
|
||||||
|
|
||||||
def setName(self, value):
|
def setName(self, value):
|
||||||
|
@ -53,10 +54,10 @@ class JailReader(ConfigReader):
|
||||||
return self.__name
|
return self.__name
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
ConfigReader.read(self, "jail")
|
return ConfigReader.read(self, "jail")
|
||||||
|
|
||||||
def isEnabled(self):
|
def isEnabled(self):
|
||||||
return self.__opts["enabled"]
|
return self.__force_enable or self.__opts["enabled"]
|
||||||
|
|
||||||
def getOptions(self):
|
def getOptions(self):
|
||||||
opts = [["bool", "enabled", "false"],
|
opts = [["bool", "enabled", "false"],
|
||||||
|
@ -76,7 +77,8 @@ class JailReader(ConfigReader):
|
||||||
|
|
||||||
if self.isEnabled():
|
if self.isEnabled():
|
||||||
# Read filter
|
# Read filter
|
||||||
self.__filter = FilterReader(self.__opts["filter"], self.__name)
|
self.__filter = FilterReader(self.__opts["filter"], self.__name,
|
||||||
|
basedir=self.getBaseDir())
|
||||||
ret = self.__filter.read()
|
ret = self.__filter.read()
|
||||||
if ret:
|
if ret:
|
||||||
self.__filter.getOptions(self.__opts)
|
self.__filter.getOptions(self.__opts)
|
||||||
|
@ -87,8 +89,10 @@ class JailReader(ConfigReader):
|
||||||
# Read action
|
# Read action
|
||||||
for act in self.__opts["action"].split('\n'):
|
for act in self.__opts["action"].split('\n'):
|
||||||
try:
|
try:
|
||||||
|
if not act: # skip empty actions
|
||||||
|
continue
|
||||||
splitAct = JailReader.splitAction(act)
|
splitAct = JailReader.splitAction(act)
|
||||||
action = ActionReader(splitAct, self.__name)
|
action = ActionReader(splitAct, self.__name, basedir=self.getBaseDir())
|
||||||
ret = action.read()
|
ret = action.read()
|
||||||
if ret:
|
if ret:
|
||||||
action.getOptions(self.__opts)
|
action.getOptions(self.__opts)
|
||||||
|
@ -97,8 +101,10 @@ class JailReader(ConfigReader):
|
||||||
raise AttributeError("Unable to read action")
|
raise AttributeError("Unable to read action")
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
logSys.error("Error in action definition " + act)
|
logSys.error("Error in action definition " + act)
|
||||||
logSys.debug(e)
|
logSys.debug("Caught exception: %s" % (e,))
|
||||||
return False
|
return False
|
||||||
|
if not len(self.__actions):
|
||||||
|
logSys.warn("No actions were defined for %s" % self.__name)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def convert(self):
|
def convert(self):
|
||||||
|
@ -145,12 +151,20 @@ class JailReader(ConfigReader):
|
||||||
def splitAction(action):
|
def splitAction(action):
|
||||||
m = JailReader.actionCRE.match(action)
|
m = JailReader.actionCRE.match(action)
|
||||||
d = dict()
|
d = dict()
|
||||||
if not m.group(2) == None:
|
mgroups = m.groups()
|
||||||
|
if len(mgroups) == 2:
|
||||||
|
action_name, action_opts = mgroups
|
||||||
|
elif len(mgroups) == 1:
|
||||||
|
action_name, action_opts = mgroups[0], None
|
||||||
|
else:
|
||||||
|
raise ValueError("While reading action %s we should have got up to "
|
||||||
|
"2 groups. Got: %r" % (action, mgroups))
|
||||||
|
if not action_opts is None:
|
||||||
# Huge bad hack :( This method really sucks. TODO Reimplement it.
|
# Huge bad hack :( This method really sucks. TODO Reimplement it.
|
||||||
actions = ""
|
actions = ""
|
||||||
escapeChar = None
|
escapeChar = None
|
||||||
allowComma = False
|
allowComma = False
|
||||||
for c in m.group(2):
|
for c in action_opts:
|
||||||
if c in ('"', "'") and not allowComma:
|
if c in ('"', "'") and not allowComma:
|
||||||
# Start
|
# Start
|
||||||
escapeChar = c
|
escapeChar = c
|
||||||
|
@ -175,6 +189,6 @@ class JailReader(ConfigReader):
|
||||||
try:
|
try:
|
||||||
d[p[0].strip()] = p[1].strip()
|
d[p[0].strip()] = p[1].strip()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
logSys.error("Invalid argument %s in '%s'" % (p, m.group(2)))
|
logSys.error("Invalid argument %s in '%s'" % (p, action_opts))
|
||||||
return [m.group(1), d]
|
return [action_name, d]
|
||||||
splitAction = staticmethod(splitAction)
|
splitAction = staticmethod(splitAction)
|
||||||
|
|
|
@ -36,12 +36,20 @@ logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
class JailsReader(ConfigReader):
|
class JailsReader(ConfigReader):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, force_enable=False, **kwargs):
|
||||||
ConfigReader.__init__(self)
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
force_enable : bool, optional
|
||||||
|
Passed to JailReader to force enable the jails.
|
||||||
|
It is for internal use
|
||||||
|
"""
|
||||||
|
ConfigReader.__init__(self, **kwargs)
|
||||||
self.__jails = list()
|
self.__jails = list()
|
||||||
|
self.__force_enable = force_enable
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
ConfigReader.read(self, "jail")
|
return ConfigReader.read(self, "jail")
|
||||||
|
|
||||||
def getOptions(self, section = None):
|
def getOptions(self, section = None):
|
||||||
opts = []
|
opts = []
|
||||||
|
@ -49,7 +57,7 @@ class JailsReader(ConfigReader):
|
||||||
|
|
||||||
if section:
|
if section:
|
||||||
# Get the options of a specific jail.
|
# Get the options of a specific jail.
|
||||||
jail = JailReader(section)
|
jail = JailReader(section, basedir=self.getBaseDir(), force_enable=self.__force_enable)
|
||||||
jail.read()
|
jail.read()
|
||||||
ret = jail.getOptions()
|
ret = jail.getOptions()
|
||||||
if ret:
|
if ret:
|
||||||
|
@ -62,7 +70,7 @@ class JailsReader(ConfigReader):
|
||||||
else:
|
else:
|
||||||
# Get the options of all jails.
|
# Get the options of all jails.
|
||||||
for sec in self.sections():
|
for sec in self.sections():
|
||||||
jail = JailReader(sec)
|
jail = JailReader(sec, basedir=self.getBaseDir(), force_enable=self.__force_enable)
|
||||||
jail.read()
|
jail.read()
|
||||||
ret = jail.getOptions()
|
ret = jail.getOptions()
|
||||||
if ret:
|
if ret:
|
||||||
|
|
|
@ -40,6 +40,7 @@ protocol = [
|
||||||
["stop", "stops all jails and terminate the server"],
|
["stop", "stops all jails and terminate the server"],
|
||||||
["status", "gets the current status of the server"],
|
["status", "gets the current status of the server"],
|
||||||
["ping", "tests if the server is alive"],
|
["ping", "tests if the server is alive"],
|
||||||
|
["help", "return this output"],
|
||||||
['', "LOGGING", ""],
|
['', "LOGGING", ""],
|
||||||
["set loglevel <LEVEL>", "sets logging level to <LEVEL>. 0 is minimal, 4 is debug"],
|
["set loglevel <LEVEL>", "sets logging level to <LEVEL>. 0 is minimal, 4 is debug"],
|
||||||
["get loglevel", "gets the logging level"],
|
["get loglevel", "gets the logging level"],
|
||||||
|
|
|
@ -52,10 +52,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <failtime> unix timestamp of the last failure
|
|
||||||
# <bantime> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = ADDRESSES=`whois <ip> | perl -e 'while (<STDIN>) { next if /^changed|@(ripe|apnic)\.net/io; $m += (/abuse|trouble:|report|spam|security/io?3:0); if (/([a-z0-9_\-\.+]+@[a-z0-9\-]+(\.[[a-z0-9\-]+)+)/io) { while (s/([a-z0-9_\-\.+]+@[a-z0-9\-]+(\.[[a-z0-9\-]+)+)//io) { if ($m) { $a{lc($1)}=$m } else { $b{lc($1)}=$m } } $m=0 } else { $m && --$m } } if (%%a) {print join(",",keys(%%a))} else {print join(",",keys(%%b))}'`
|
actionban = ADDRESSES=`whois <ip> | perl -e 'while (<STDIN>) { next if /^changed|@(ripe|apnic)\.net/io; $m += (/abuse|trouble:|report|spam|security/io?3:0); if (/([a-z0-9_\-\.+]+@[a-z0-9\-]+(\.[[a-z0-9\-]+)+)/io) { while (s/([a-z0-9_\-\.+]+@[a-z0-9\-]+(\.[[a-z0-9\-]+)+)//io) { if ($m) { $a{lc($1)}=$m } else { $b{lc($1)}=$m } } $m=0 } else { $m && --$m } } if (%%a) {print join(",",keys(%%a))} else {print join(",",keys(%%b))}'`
|
||||||
|
@ -67,9 +64,7 @@ actionban = ADDRESSES=`whois <ip> | perl -e 'while (<STDIN>) { next if /^changed
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <bantime> unix timestamp of the ban time
|
|
||||||
# <unbantime> unix timestamp of the unban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
|
@ -54,9 +54,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
# See http://www.dshield.org/specs.html for more on report format/notes
|
# See http://www.dshield.org/specs.html for more on report format/notes
|
||||||
|
@ -91,9 +89,7 @@ actionban = TZONE=`date +%%z | sed 's/\([+-]..\)\(..\)/\1:\2/'`
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = if [ -f <tmpfile>.first ]; then
|
actionunban = if [ -f <tmpfile>.first ]; then
|
||||||
|
@ -116,7 +112,7 @@ actionunban = if [ -f <tmpfile>.first ]; then
|
||||||
port = ???
|
port = ???
|
||||||
|
|
||||||
# Option: userid
|
# Option: userid
|
||||||
# Notes.: Your DSheild user ID. Should be provided either in the jail config or
|
# Notes.: Your DShield user ID. Should be provided either in the jail config or
|
||||||
# in a .local file.
|
# in a .local file.
|
||||||
# Register at https://secure.dshield.org/register.html
|
# Register at https://secure.dshield.org/register.html
|
||||||
# Values: [ NUM ] Default: 0
|
# Values: [ NUM ] Default: 0
|
||||||
|
@ -124,13 +120,13 @@ port = ???
|
||||||
userid = 0
|
userid = 0
|
||||||
|
|
||||||
# Option: myip
|
# Option: myip
|
||||||
# Notes.: TThe target IP for the attack (your public IP). Should be provided
|
# Notes.: The target IP for the attack (your public IP). Should be provided
|
||||||
# either in the jail config or in a .local file unless your PUBLIC IP
|
# either in the jail config or in a .local file unless your PUBLIC IP
|
||||||
# is the first IP assigned to eth0
|
# is the first IP assigned to eth0
|
||||||
# Values: [ an IP address ] Default: Tries to find the IP address of eth0,
|
# Values: [ an IP address ] Default: Tries to find the IP address of eth0,
|
||||||
# which in most cases will be a private IP, and therefore incorrect
|
# which in most cases will be a private IP, and therefore incorrect
|
||||||
#
|
#
|
||||||
myip = `ip -4 addr show dev eth0 | grep inet | head -1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'`
|
myip = `ip -4 addr show dev eth0 | grep inet | head -n 1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'`
|
||||||
|
|
||||||
# Option: protocol
|
# Option: protocol
|
||||||
# Notes.: The protocol over which the attack is happening
|
# Notes.: The protocol over which the attack is happening
|
||||||
|
@ -159,7 +155,6 @@ minreportinterval = 3600
|
||||||
# submit the batch, even if we haven't reached <lines> yet. Note that
|
# submit the batch, even if we haven't reached <lines> yet. Note that
|
||||||
# this is only checked on each ban/unban, and that we always send
|
# this is only checked on each ban/unban, and that we always send
|
||||||
# anything in the buffer on shutdown. Must be greater than
|
# anything in the buffer on shutdown. Must be greater than
|
||||||
# <minreportinterval>.
|
|
||||||
# Values: [ NUM ] Default: 21600 (6 hours)
|
# Values: [ NUM ] Default: 21600 (6 hours)
|
||||||
#
|
#
|
||||||
maxbufferage = 21600
|
maxbufferage = 21600
|
||||||
|
|
|
@ -29,9 +29,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "+<ip>\n" >> /tmp/fail2ban.dummy
|
actionban = printf %%b "+<ip>\n" >> /tmp/fail2ban.dummy
|
||||||
|
@ -39,9 +37,7 @@ actionban = printf %%b "+<ip>\n" >> /tmp/fail2ban.dummy
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = printf %%b "-<ip>\n" >> /tmp/fail2ban.dummy
|
actionunban = printf %%b "-<ip>\n" >> /tmp/fail2ban.dummy
|
||||||
|
|
|
@ -28,9 +28,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = IP=<ip> &&
|
actionban = IP=<ip> &&
|
||||||
|
@ -39,9 +37,7 @@ actionban = IP=<ip> &&
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = IP=<ip> && sed -i.old /ALL:\ $IP/d <file>
|
actionunban = IP=<ip> && sed -i.old /ALL:\ $IP/d <file>
|
||||||
|
|
|
@ -34,9 +34,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo block in quick from <ip>/32 | /sbin/ipf -f -
|
actionban = echo block in quick from <ip>/32 | /sbin/ipf -f -
|
||||||
|
@ -45,9 +43,7 @@ actionban = echo block in quick from <ip>/32 | /sbin/ipf -f -
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
# note -r option used to remove matching rule
|
# note -r option used to remove matching rule
|
||||||
|
|
|
@ -32,9 +32,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = ipfw add deny tcp from <ip> to <localhost> <port>
|
actionban = ipfw add deny tcp from <ip> to <localhost> <port>
|
||||||
|
@ -43,9 +41,7 @@ actionban = ipfw add deny tcp from <ip> to <localhost> <port>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = ipfw delete `ipfw list | grep -i <ip> | awk '{print $1;}'`
|
actionunban = ipfw delete `ipfw list | grep -i <ip> | awk '{print $1;}'`
|
||||||
|
|
|
@ -34,9 +34,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'fail2ban-<name>[ \t]'
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
|
@ -44,16 +42,14 @@ actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ actionstop = iptables -D INPUT -p <protocol> -m multiport --dports <port> -m set
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = ipset --test fail2ban-<name> <ip> || ipset --add fail2ban-<name> <ip>
|
actionban = ipset --test fail2ban-<name> <ip> || ipset --add fail2ban-<name> <ip>
|
||||||
|
@ -46,14 +46,14 @@ actionban = ipset --test fail2ban-<name> <ip> || ipset --add fail2ban-<name> <i
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = ipset --test fail2ban-<name> <ip> && ipset --del fail2ban-<name> <ip>
|
actionunban = ipset --test fail2ban-<name> <ip> && ipset --del fail2ban-<name> <ip>
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the ipset
|
# Default name of the ipset
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ actionstop = iptables -D INPUT -p <protocol> -m multiport --dports <port> -m set
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = ipset add fail2ban-<name> <ip> timeout <bantime> -exist
|
actionban = ipset add fail2ban-<name> <ip> timeout <bantime> -exist
|
||||||
|
@ -46,14 +46,14 @@ actionban = ipset add fail2ban-<name> <ip> timeout <bantime> -exist
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = ipset del fail2ban-<name> <ip> -exist
|
actionunban = ipset del fail2ban-<name> <ip> -exist
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the ipset
|
# Default name of the ipset
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,7 @@ actioncheck = iptables -n -L fail2ban-<name>-log >/dev/null
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j fail2ban-<name>-log
|
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j fail2ban-<name>-log
|
||||||
|
@ -52,16 +50,14 @@ actionban = iptables -I fail2ban-<name> 1 -s <ip> -j fail2ban-<name>-log
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = iptables -D fail2ban-<name> -s <ip> -j fail2ban-<name>-log
|
actionunban = iptables -D fail2ban-<name> -s <ip> -j fail2ban-<name>-log
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'fail2ban-<name>[ \t]'
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
|
@ -42,16 +40,14 @@ actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'fail2ban-<name>[ \t]'
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
|
@ -44,16 +42,14 @@ actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
# Notes.: command executed once at the start of Fail2Ban.
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
# Changing iptables rules requires root priviledges. If fail2ban is
|
# Changing iptables rules requires root privileges. If fail2ban is
|
||||||
# configured to run as root, firewall setup can be performed by
|
# configured to run as root, firewall setup can be performed by
|
||||||
# fail2ban automatically. However, if fail2ban is configured to run as
|
# fail2ban automatically. However, if fail2ban is configured to run as
|
||||||
# a normal user, the configuration must be done by some other means
|
# a normal user, the configuration must be done by some other means
|
||||||
|
@ -46,9 +46,7 @@ actioncheck = test -e /proc/net/xt_recent/fail2ban-<name>
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = echo +<ip> > /proc/net/xt_recent/fail2ban-<name>
|
actionban = echo +<ip> > /proc/net/xt_recent/fail2ban-<name>
|
||||||
|
@ -56,16 +54,14 @@ actionban = echo +<ip> > /proc/net/xt_recent/fail2ban-<name>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = echo -<ip> > /proc/net/xt_recent/fail2ban-<name>
|
actionunban = echo -<ip> > /proc/net/xt_recent/fail2ban-<name>
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,7 @@ actioncheck = iptables -n -L <chain> | grep -q 'fail2ban-<name>[ \t]'
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
|
@ -42,16 +40,14 @@ actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -43,9 +43,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||||
|
@ -62,9 +60,7 @@ actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
|
@ -34,10 +34,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <failtime> unix timestamp of the last failure
|
|
||||||
# <bantime> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Hi,\n
|
actionban = printf %%b "Hi,\n
|
||||||
|
@ -53,16 +50,14 @@ actionban = printf %%b "Hi,\n
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <bantime> unix timestamp of the ban time
|
|
||||||
# <unbantime> unix timestamp of the unban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Hi,\n
|
actionban = printf %%b "Hi,\n
|
||||||
|
@ -50,16 +48,14 @@ actionban = printf %%b "Hi,\n
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Hi,\n
|
actionban = printf %%b "Hi,\n
|
||||||
|
@ -48,16 +46,14 @@ actionban = printf %%b "Hi,\n
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -71,9 +69,7 @@ actionban = MNWLOGIN=`perl -e '$s=shift;$s=~s/([\W])/"%%".uc(sprintf("%%2.2x",or
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
@ -102,13 +98,13 @@ mnwlogin =
|
||||||
mnwpass =
|
mnwpass =
|
||||||
|
|
||||||
# Option: myip
|
# Option: myip
|
||||||
# Notes.: TThe target IP for the attack (your public IP). Should be overridden
|
# Notes.: The target IP for the attack (your public IP). Should be overridden
|
||||||
# either in the jail config or in a .local file unless your PUBLIC IP
|
# either in the jail config or in a .local file unless your PUBLIC IP
|
||||||
# is the first IP assigned to eth0
|
# is the first IP assigned to eth0
|
||||||
# Values: [ an IP address ] Default: Tries to find the IP address of eth0,
|
# Values: [ an IP address ] Default: Tries to find the IP address of eth0,
|
||||||
# which in most cases will be a private IP, and therefore incorrect
|
# which in most cases will be a private IP, and therefore incorrect
|
||||||
#
|
#
|
||||||
myip = `ip -4 addr show dev eth0 | grep inet | head -1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'`
|
myip = `ip -4 addr show dev eth0 | grep inet | head -n 1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'`
|
||||||
|
|
||||||
# Option: protocol
|
# Option: protocol
|
||||||
# Notes.: The protocol over which the attack is happening
|
# Notes.: The protocol over which the attack is happening
|
||||||
|
|
|
@ -52,9 +52,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||||
|
@ -74,16 +72,14 @@ actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
|
@ -64,16 +62,14 @@ actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
|
@ -62,16 +60,14 @@ actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
|
@ -60,16 +58,14 @@ actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban =
|
actionunban =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
# Defaut name of the chain
|
# Default name of the chain
|
||||||
#
|
#
|
||||||
name = default
|
name = default
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,7 @@ actioncheck =
|
||||||
# Option: actionban
|
# Option: actionban
|
||||||
# Notes.: command executed when banning an IP. Take care that the
|
# Notes.: command executed when banning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = shorewall drop <ip>
|
actionban = shorewall drop <ip>
|
||||||
|
@ -46,9 +44,7 @@ actionban = shorewall drop <ip>
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
# command is executed with Fail2Ban user rights.
|
# command is executed with Fail2Ban user rights.
|
||||||
# Tags: <ip> IP address
|
# Tags: See jail.conf(5) man page
|
||||||
# <failures> number of failures
|
|
||||||
# <time> unix timestamp of the ban time
|
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = shorewall allow <ip>
|
actionunban = shorewall allow <ip>
|
||||||
|
|
|
@ -16,7 +16,7 @@ badbots = atSpider/1\.0|autoemailspider|China Local Browse 2\.6|ContentSmartz|Da
|
||||||
# Option: failregex
|
# Option: failregex
|
||||||
# Notes.: Regexp to catch known spambots and software alike. Please verify
|
# Notes.: Regexp to catch known spambots and software alike. Please verify
|
||||||
# that it is your intent to block IPs which were driven by
|
# that it is your intent to block IPs which were driven by
|
||||||
# abovementioned bots.
|
# above mentioned bots.
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
|
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
# Values: TEXT
|
# Values: TEXT
|
||||||
#
|
#
|
||||||
failregex = reject: RCPT from (.*)\[<HOST>\]: 554
|
failregex = reject: RCPT from (.*)\[<HOST>\]: 554
|
||||||
|
reject: RCPT from (.*)\[<HOST>\]: 450 4\.7\.1 : Helo command rejected: Host not found; from=<> to=<> proto=ESMTP helo= *$
|
||||||
|
|
||||||
# Option: ignoreregex
|
# Option: ignoreregex
|
||||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# /etc/fail2ban/filter.d/sogo-auth.conf
|
||||||
|
#
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
# By Arnd Brandes
|
||||||
|
# SOGo
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
# Option: failregex
|
||||||
|
# Filter Ban in /var/log/sogo/sogo.log
|
||||||
|
# Note: the error log may contain multiple hosts, whereas the first one
|
||||||
|
# is the client and all others are poxys. We match the first one, only
|
||||||
|
|
||||||
|
failregex = Login from '<HOST>' for user '.*' might not have worked( - password policy: \d* grace: -?\d* expire: -?\d* bound: -?\d*)?\s*$
|
||||||
|
|
||||||
|
# Option: ignoreregex
|
||||||
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
ignoreregex =
|
|
@ -219,6 +219,20 @@ filter = roundcube-auth
|
||||||
action = iptables[name=RoundCube, port="http,https"]
|
action = iptables[name=RoundCube, port="http,https"]
|
||||||
logpath = /var/log/roundcube/userlogins
|
logpath = /var/log/roundcube/userlogins
|
||||||
|
|
||||||
|
|
||||||
|
# Monitor SOGo groupware server
|
||||||
|
|
||||||
|
[sogo-iptables]
|
||||||
|
|
||||||
|
enabled = false
|
||||||
|
filter = sogo-auth
|
||||||
|
port = http, https
|
||||||
|
# without proxy this would be:
|
||||||
|
# port = 20000
|
||||||
|
|
||||||
|
action = iptables[name=SOGo, port="http,https"]
|
||||||
|
logpath = /var/log/sogo/sogo.log
|
||||||
|
|
||||||
# Ban attackers that try to use PHP's URL-fopen() functionality
|
# Ban attackers that try to use PHP's URL-fopen() functionality
|
||||||
# through GET/POST variables. - Experimental, with more than a year
|
# through GET/POST variables. - Experimental, with more than a year
|
||||||
# of usage in production environments.
|
# of usage in production environments.
|
||||||
|
@ -248,7 +262,7 @@ logpath = /var/log/lighttpd/error.log
|
||||||
maxretry = 2
|
maxretry = 2
|
||||||
|
|
||||||
# Same as above for mod_auth
|
# Same as above for mod_auth
|
||||||
# It catches wrong authentifications
|
# It catches wrong authentications
|
||||||
|
|
||||||
[lighttpd-auth]
|
[lighttpd-auth]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Fail2ban normally requires root priviledges to insert iptables rules
|
Fail2ban normally requires root privileges to insert iptables rules
|
||||||
through calls to /sbin/iptables and also to read the logfiles.
|
through calls to /sbin/iptables and also to read the logfiles.
|
||||||
Fail2ban can run as an unpriviledged user provided that those two
|
Fail2ban can run as an unprivileged user provided that those two
|
||||||
capabilites are preserved. The idea is to run fail2ban as a normal
|
capabilities are preserved. The idea is to run fail2ban as a normal
|
||||||
user (e.g. fail2ban) who belongs to a group which is allowed to read
|
user (e.g. fail2ban) who belongs to a group which is allowed to read
|
||||||
logfiles. The user should also be allowed to write to
|
logfiles. The user should also be allowed to write to
|
||||||
/proc/net/xt_recent/fail2ban-<name> (name is specified in the iptables
|
/proc/net/xt_recent/fail2ban-<name> (name is specified in the iptables
|
||||||
|
@ -20,14 +20,14 @@ Another way to use xt_recent is by inserting the rules by writing to
|
||||||
action. Files in /proc/net/xt_recent/ are protected by normal
|
action. Files in /proc/net/xt_recent/ are protected by normal
|
||||||
filesystem rules, so can be chown'ed and chmod'ed to be writable by a
|
filesystem rules, so can be chown'ed and chmod'ed to be writable by a
|
||||||
certain user. After the necessary iptables rules are inserted (which
|
certain user. After the necessary iptables rules are inserted (which
|
||||||
requires root priviledges), blacklisting can be perfomed by an
|
requires root privileges), blacklisting can be performed by an
|
||||||
unpriviledged user.
|
unprivileged user.
|
||||||
|
|
||||||
Using fail2ban with xt_recent allows smarter filtering than normal
|
Using fail2ban with xt_recent allows smarter filtering than normal
|
||||||
iptables rules with the xt_recent module can provide.
|
iptables rules with the xt_recent module can provide.
|
||||||
|
|
||||||
The disadvantage is that fail2ban cannot perform the setup by itself,
|
The disadvantage is that fail2ban cannot perform the setup by itself,
|
||||||
which would require the priviledge to call /sbin/iptables, and it must
|
which would require the privilege to call /sbin/iptables, and it must
|
||||||
be done through other means.
|
be done through other means.
|
||||||
|
|
||||||
The primary advantage is obvious: it's generally better to run
|
The primary advantage is obvious: it's generally better to run
|
||||||
|
@ -46,7 +46,7 @@ some user and thus allow delisting IPs by helper administrators
|
||||||
without the ability to mess up other iptables rules.
|
without the ability to mess up other iptables rules.
|
||||||
|
|
||||||
The xt_recent-echo jail can be used under the root user without
|
The xt_recent-echo jail can be used under the root user without
|
||||||
further configuration. To run not as root, futher setup is necessary:
|
further configuration. To run not as root, further setup is necessary:
|
||||||
|
|
||||||
- Create user:
|
- Create user:
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,7 @@ class Fail2banClient:
|
||||||
delta = -1
|
delta = -1
|
||||||
elif pos < 2:
|
elif pos < 2:
|
||||||
delta = 1
|
delta = 1
|
||||||
# The server has 30 secondes to start.
|
# The server has 30 seconds to start.
|
||||||
if cnt >= 300:
|
if cnt >= 300:
|
||||||
if self.__conf["verbose"] > 1:
|
if self.__conf["verbose"] > 1:
|
||||||
sys.stdout.write('\n')
|
sys.stdout.write('\n')
|
||||||
|
@ -380,7 +380,9 @@ class Fail2banClient:
|
||||||
if cmd == "exit" or cmd == "quit":
|
if cmd == "exit" or cmd == "quit":
|
||||||
# Exit
|
# Exit
|
||||||
return True
|
return True
|
||||||
if not cmd == "":
|
if cmd == "help":
|
||||||
|
self.dispUsage()
|
||||||
|
elif not cmd == "":
|
||||||
self.__processCommand(shlex.split(cmd))
|
self.__processCommand(shlex.split(cmd))
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
print
|
print
|
||||||
|
@ -418,7 +420,7 @@ class Fail2banClient:
|
||||||
class ServerExecutionException(Exception):
|
class ServerExecutionException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__": # pragma: no cover - can't test main
|
||||||
client = Fail2banClient()
|
client = Fail2banClient()
|
||||||
# Exit with correct return value
|
# Exit with correct return value
|
||||||
if client.start(sys.argv):
|
if client.start(sys.argv):
|
||||||
|
|
|
@ -35,6 +35,9 @@ from testcases import filtertestcase
|
||||||
from testcases import servertestcase
|
from testcases import servertestcase
|
||||||
from testcases import datedetectortestcase
|
from testcases import datedetectortestcase
|
||||||
from testcases import actiontestcase
|
from testcases import actiontestcase
|
||||||
|
from testcases import sockettestcase
|
||||||
|
|
||||||
|
from testcases.utils import FormatterWithTraceBack
|
||||||
from server.mytime import MyTime
|
from server.mytime import MyTime
|
||||||
|
|
||||||
from optparse import OptionParser, Option
|
from optparse import OptionParser, Option
|
||||||
|
@ -51,12 +54,14 @@ def get_opt_parser():
|
||||||
choices=('debug', 'info', 'warn', 'error', 'fatal'),
|
choices=('debug', 'info', 'warn', 'error', 'fatal'),
|
||||||
default=None,
|
default=None,
|
||||||
help="Log level for the logger to use during running tests"),
|
help="Log level for the logger to use during running tests"),
|
||||||
])
|
|
||||||
|
|
||||||
p.add_options([
|
|
||||||
Option('-n', "--no-network", action="store_true",
|
Option('-n', "--no-network", action="store_true",
|
||||||
dest="no_network",
|
dest="no_network",
|
||||||
help="Do not run tests that require the network"),
|
help="Do not run tests that require the network"),
|
||||||
|
Option("-t", "--log-traceback", action='store_true',
|
||||||
|
help="Enrich log-messages with compressed tracebacks"),
|
||||||
|
Option("--full-traceback", action='store_true',
|
||||||
|
help="Either to make the tracebacks full, not compressed (as by default)"),
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|
||||||
return p
|
return p
|
||||||
|
@ -77,10 +82,10 @@ verbosity = {'debug': 3,
|
||||||
'fatal': 0,
|
'fatal': 0,
|
||||||
None: 1}[opts.log_level]
|
None: 1}[opts.log_level]
|
||||||
|
|
||||||
if opts.log_level is not None:
|
if opts.log_level is not None: # pragma: no cover
|
||||||
# so we had explicit settings
|
# so we had explicit settings
|
||||||
logSys.setLevel(getattr(logging, opts.log_level.upper()))
|
logSys.setLevel(getattr(logging, opts.log_level.upper()))
|
||||||
else:
|
else: # pragma: no cover
|
||||||
# suppress the logging but it would leave unittests' progress dots
|
# suppress the logging but it would leave unittests' progress dots
|
||||||
# ticking, unless like with '-l fatal' which would be silent
|
# ticking, unless like with '-l fatal' which would be silent
|
||||||
# unless error occurs
|
# unless error occurs
|
||||||
|
@ -88,18 +93,27 @@ else:
|
||||||
|
|
||||||
# Add the default logging handler
|
# Add the default logging handler
|
||||||
stdout = logging.StreamHandler(sys.stdout)
|
stdout = logging.StreamHandler(sys.stdout)
|
||||||
# Custom log format for the verbose tests runs
|
|
||||||
if verbosity > 1:
|
fmt = ' %(message)s'
|
||||||
stdout.setFormatter(logging.Formatter(' %(asctime)-15s %(thread)s %(message)s'))
|
|
||||||
|
if opts.log_traceback:
|
||||||
|
Formatter = FormatterWithTraceBack
|
||||||
|
fmt = (opts.full_traceback and ' %(tb)s' or ' %(tbc)s') + fmt
|
||||||
else:
|
else:
|
||||||
|
Formatter = logging.Formatter
|
||||||
|
|
||||||
|
# Custom log format for the verbose tests runs
|
||||||
|
if verbosity > 1: # pragma: no cover
|
||||||
|
stdout.setFormatter(Formatter(' %(asctime)-15s %(thread)s' + fmt))
|
||||||
|
else: # pragma: no cover
|
||||||
# just prefix with the space
|
# just prefix with the space
|
||||||
stdout.setFormatter(logging.Formatter(' %(message)s'))
|
stdout.setFormatter(Formatter(fmt))
|
||||||
logSys.addHandler(stdout)
|
logSys.addHandler(stdout)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Let know the version
|
# Let know the version
|
||||||
#
|
#
|
||||||
if not opts.log_level or opts.log_level != 'fatal':
|
if not opts.log_level or opts.log_level != 'fatal': # pragma: no cover
|
||||||
print "Fail2ban %s test suite. Python %s. Please wait..." \
|
print "Fail2ban %s test suite. Python %s. Please wait..." \
|
||||||
% (version, str(sys.version).replace('\n', ''))
|
% (version, str(sys.version).replace('\n', ''))
|
||||||
|
|
||||||
|
@ -107,9 +121,9 @@ if not opts.log_level or opts.log_level != 'fatal':
|
||||||
#
|
#
|
||||||
# Gather the tests
|
# Gather the tests
|
||||||
#
|
#
|
||||||
if not len(regexps):
|
if not len(regexps): # pragma: no cover
|
||||||
tests = unittest.TestSuite()
|
tests = unittest.TestSuite()
|
||||||
else:
|
else: # pragma: no cover
|
||||||
import re
|
import re
|
||||||
class FilteredTestSuite(unittest.TestSuite):
|
class FilteredTestSuite(unittest.TestSuite):
|
||||||
_regexps = [re.compile(r) for r in regexps]
|
_regexps = [re.compile(r) for r in regexps]
|
||||||
|
@ -130,8 +144,12 @@ tests.addTest(unittest.makeSuite(actiontestcase.ExecuteAction))
|
||||||
tests.addTest(unittest.makeSuite(failmanagertestcase.AddFailure))
|
tests.addTest(unittest.makeSuite(failmanagertestcase.AddFailure))
|
||||||
# BanManager
|
# BanManager
|
||||||
tests.addTest(unittest.makeSuite(banmanagertestcase.AddFailure))
|
tests.addTest(unittest.makeSuite(banmanagertestcase.AddFailure))
|
||||||
# ClientReader
|
# ClientReaders
|
||||||
|
tests.addTest(unittest.makeSuite(clientreadertestcase.ConfigReaderTest))
|
||||||
tests.addTest(unittest.makeSuite(clientreadertestcase.JailReaderTest))
|
tests.addTest(unittest.makeSuite(clientreadertestcase.JailReaderTest))
|
||||||
|
tests.addTest(unittest.makeSuite(clientreadertestcase.JailsReaderTest))
|
||||||
|
# CSocket and AsyncServer
|
||||||
|
tests.addTest(unittest.makeSuite(sockettestcase.Socket))
|
||||||
|
|
||||||
# Filter
|
# Filter
|
||||||
if not opts.no_network:
|
if not opts.no_network:
|
||||||
|
@ -159,19 +177,22 @@ filters = [FilterPoll] # always available
|
||||||
try:
|
try:
|
||||||
from server.filtergamin import FilterGamin
|
from server.filtergamin import FilterGamin
|
||||||
filters.append(FilterGamin)
|
filters.append(FilterGamin)
|
||||||
except Exception, e:
|
except Exception, e: # pragma: no cover
|
||||||
print "I: Skipping gamin backend testing. Got exception '%s'" % e
|
print "I: Skipping gamin backend testing. Got exception '%s'" % e
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from server.filterpyinotify import FilterPyinotify
|
from server.filterpyinotify import FilterPyinotify
|
||||||
filters.append(FilterPyinotify)
|
filters.append(FilterPyinotify)
|
||||||
except Exception, e:
|
except Exception, e: # pragma: no cover
|
||||||
print "I: Skipping pyinotify backend testing. Got exception '%s'" % e
|
print "I: Skipping pyinotify backend testing. Got exception '%s'" % e
|
||||||
|
|
||||||
for Filter_ in filters:
|
for Filter_ in filters:
|
||||||
tests.addTest(unittest.makeSuite(
|
tests.addTest(unittest.makeSuite(
|
||||||
filtertestcase.get_monitor_failures_testcase(Filter_)))
|
filtertestcase.get_monitor_failures_testcase(Filter_)))
|
||||||
|
|
||||||
|
# Server test for logging elements which break logging used to support
|
||||||
|
# testcases analysis
|
||||||
|
tests.addTest(unittest.makeSuite(servertestcase.TransmitterLogging))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run the tests
|
# Run the tests
|
||||||
|
@ -189,7 +210,7 @@ try:
|
||||||
|
|
||||||
tests_results = testRunner.run(tests)
|
tests_results = testRunner.run(tests)
|
||||||
|
|
||||||
finally:
|
finally: # pragma: no cover
|
||||||
# Just for the sake of it reset the TZ
|
# Just for the sake of it reset the TZ
|
||||||
# yoh: move all this into setup/teardown methods within tests
|
# yoh: move all this into setup/teardown methods within tests
|
||||||
os.environ.pop('TZ')
|
os.environ.pop('TZ')
|
||||||
|
@ -197,5 +218,5 @@ finally:
|
||||||
os.environ['TZ'] = old_TZ
|
os.environ['TZ'] = old_TZ
|
||||||
time.tzset()
|
time.tzset()
|
||||||
|
|
||||||
if not tests_results.wasSuccessful():
|
if not tests_results.wasSuccessful(): # pragma: no cover
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
|
@ -49,5 +49,5 @@ details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public
|
You should have received a copy of the GNU General Public
|
||||||
License along with Fail2Ban; if not, write to the Free
|
License along with Fail2Ban; if not, write to the Free
|
||||||
Software Foundation, Inc., 59 Temple Place, Suite 330,
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
Boston, MA 02111-1307 USA
|
Boston, MA 02110, USA
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10.
|
||||||
.TH FAIL2BAN-CLIENT "1" "March 2008" "fail2ban-client v0.8.2" "User Commands"
|
.TH FAIL2BAN-CLIENT "1" "March 2013" "fail2ban-client v0.8.8" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-client \- configure and control the server
|
fail2ban-client \- configure and control the server
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-client
|
.B fail2ban-client
|
||||||
[\fIOPTIONS\fR] \fI<COMMAND>\fR
|
[\fIOPTIONS\fR] \fI<COMMAND>\fR
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Fail2Ban v0.8.2 reads log file that contains password failure report
|
Fail2Ban v0.8.8 reads log file that contains password failure report
|
||||||
and bans the corresponding IP addresses using firewall rules.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
|
@ -16,6 +16,9 @@ configuration directory
|
||||||
\fB\-s\fR <FILE>
|
\fB\-s\fR <FILE>
|
||||||
socket path
|
socket path
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-p\fR <FILE>
|
||||||
|
pidfile path
|
||||||
|
.TP
|
||||||
\fB\-d\fR
|
\fB\-d\fR
|
||||||
dump configuration. For debugging
|
dump configuration. For debugging
|
||||||
.TP
|
.TP
|
||||||
|
@ -110,7 +113,7 @@ adds <FILE> to the monitoring list
|
||||||
of <JAIL>
|
of <JAIL>
|
||||||
.TP
|
.TP
|
||||||
\fBset <JAIL> dellogpath <FILE>\fR
|
\fBset <JAIL> dellogpath <FILE>\fR
|
||||||
removes <FILE> to the monitoring
|
removes <FILE> from the monitoring
|
||||||
list of <JAIL>
|
list of <JAIL>
|
||||||
.TP
|
.TP
|
||||||
\fBset <JAIL> addfailregex <REGEX>\fR
|
\fBset <JAIL> addfailregex <REGEX>\fR
|
||||||
|
@ -140,6 +143,15 @@ back for <JAIL>
|
||||||
sets the number of seconds <TIME>
|
sets the number of seconds <TIME>
|
||||||
a host will be banned for <JAIL>
|
a host will be banned for <JAIL>
|
||||||
.TP
|
.TP
|
||||||
|
\fBset <JAIL> usedns <VALUE>\fR
|
||||||
|
sets the usedns mode for <JAIL>
|
||||||
|
.TP
|
||||||
|
\fBset <JAIL> banip <IP>\fR
|
||||||
|
manually Ban <IP> for <JAIL>
|
||||||
|
.TP
|
||||||
|
\fBset <JAIL> unbanip <IP>\fR
|
||||||
|
manually Unban <IP> in <JAIL>
|
||||||
|
.TP
|
||||||
\fBset <JAIL> maxretry <RETRY>\fR
|
\fBset <JAIL> maxretry <RETRY>\fR
|
||||||
sets the number of failures
|
sets the number of failures
|
||||||
<RETRY> before banning the host
|
<RETRY> before banning the host
|
||||||
|
@ -191,14 +203,6 @@ files for <JAIL>
|
||||||
gets the list of ignored IP
|
gets the list of ignored IP
|
||||||
addresses for <JAIL>
|
addresses for <JAIL>
|
||||||
.TP
|
.TP
|
||||||
\fBget <JAIL> timeregex\fR
|
|
||||||
gets the regular expression used
|
|
||||||
for the time detection for <JAIL>
|
|
||||||
.TP
|
|
||||||
\fBget <JAIL> timepattern\fR
|
|
||||||
gets the pattern used for the time
|
|
||||||
detection for <JAIL>
|
|
||||||
.TP
|
|
||||||
\fBget <JAIL> failregex\fR
|
\fBget <JAIL> failregex\fR
|
||||||
gets the list of regular
|
gets the list of regular
|
||||||
expressions which matches the
|
expressions which matches the
|
||||||
|
@ -218,6 +222,9 @@ will look back for failures for
|
||||||
gets the time a host is banned for
|
gets the time a host is banned for
|
||||||
<JAIL>
|
<JAIL>
|
||||||
.TP
|
.TP
|
||||||
|
\fBget <JAIL> usedns\fR
|
||||||
|
gets the usedns setting for <JAIL>
|
||||||
|
.TP
|
||||||
\fBget <JAIL> maxretry\fR
|
\fBget <JAIL> maxretry\fR
|
||||||
gets the number of failures
|
gets the number of failures
|
||||||
allowed for <JAIL>
|
allowed for <JAIL>
|
||||||
|
@ -245,15 +252,19 @@ action <ACT> for <JAIL>
|
||||||
\fBget <JAIL> actionunban <ACT>\fR
|
\fBget <JAIL> actionunban <ACT>\fR
|
||||||
gets the unban command for the
|
gets the unban command for the
|
||||||
action <ACT> for <JAIL>
|
action <ACT> for <JAIL>
|
||||||
|
.TP
|
||||||
|
\fBget <JAIL> cinfo <ACT> <KEY>\fR
|
||||||
|
gets the value for <KEY> for the
|
||||||
|
action <ACT> for <JAIL>
|
||||||
.SH FILES
|
.SH FILES
|
||||||
\fI/etc/fail2ban/*\fR
|
\fI/etc/fail2ban/*\fR
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||||
.SH "REPORTING BUGS"
|
.SH "REPORTING BUGS"
|
||||||
Report bugs on https://github.com/fail2ban/fail2ban/issues
|
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2004-2008 Cyril Jaquier
|
Copyright \(co 2004\-2008 Cyril Jaquier, 2008\- Fail2Ban Contributors
|
||||||
.br
|
.br
|
||||||
Copyright of modifications held by their respective authors.
|
Copyright of modifications held by their respective authors.
|
||||||
Licensed under the GNU General Public License v2 (GPL).
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10.
|
||||||
.TH FAIL2BAN-REGEX "1" "March 2008" "fail2ban-regex v0.8.2" "User Commands"
|
.TH FAIL2BAN-REGEX "1" "March 2013" "fail2ban-regex v0.8.8" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-regex \- test Fail2ban "failregex" option
|
fail2ban-regex \- test Fail2ban "failregex" option
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-regex
|
.B fail2ban-regex
|
||||||
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
|
[\fIOPTIONS\fR] \fI<LOG> <REGEX> \fR[\fIIGNOREREGEX\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Fail2Ban v0.8.2 reads log file that contains password failure report
|
Fail2Ban v0.8.8 reads log file that contains password failure report
|
||||||
and bans the corresponding IP addresses using firewall rules.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
.PP
|
.PP
|
||||||
This tools can test regular expressions for "fail2ban".
|
This tools can test regular expressions for "fail2ban".
|
||||||
|
@ -17,6 +17,9 @@ display this help message
|
||||||
.TP
|
.TP
|
||||||
\fB\-V\fR, \fB\-\-version\fR
|
\fB\-V\fR, \fB\-\-version\fR
|
||||||
print the version
|
print the version
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
verbose output
|
||||||
.SH LOG
|
.SH LOG
|
||||||
.TP
|
.TP
|
||||||
\fBstring\fR
|
\fBstring\fR
|
||||||
|
@ -42,9 +45,9 @@ path to a filter file (filter.d/sshd.conf)
|
||||||
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||||
.SH "REPORTING BUGS"
|
.SH "REPORTING BUGS"
|
||||||
Report bugs on https://github.com/fail2ban/fail2ban/issues
|
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2004-2008 Cyril Jaquier
|
Copyright \(co 2004\-2008 Cyril Jaquier
|
||||||
.br
|
.br
|
||||||
Copyright of modifications held by their respective authors.
|
Copyright of modifications held by their respective authors.
|
||||||
Licensed under the GNU General Public License v2 (GPL).
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10.
|
||||||
.TH FAIL2BAN-SERVER "1" "March 2008" "fail2ban-server v0.8.2" "User Commands"
|
.TH FAIL2BAN-SERVER "1" "March 2013" "fail2ban-server v0.8.8" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-server \- start the server
|
fail2ban-server \- start the server
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B fail2ban-server
|
.B fail2ban-server
|
||||||
[\fIOPTIONS\fR]
|
[\fIOPTIONS\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Fail2Ban v0.8.2 reads log file that contains password failure report
|
Fail2Ban v0.8.8 reads log file that contains password failure report
|
||||||
and bans the corresponding IP addresses using firewall rules.
|
and bans the corresponding IP addresses using firewall rules.
|
||||||
.PP
|
.PP
|
||||||
Only use this command for debugging purpose. Start the server with
|
Only use this command for debugging purpose. Start the server with
|
||||||
|
@ -23,6 +23,9 @@ start in foreground
|
||||||
\fB\-s\fR <FILE>
|
\fB\-s\fR <FILE>
|
||||||
socket path
|
socket path
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-p\fR <FILE>
|
||||||
|
pidfile path
|
||||||
|
.TP
|
||||||
\fB\-x\fR
|
\fB\-x\fR
|
||||||
force execution of the server (remove socket file)
|
force execution of the server (remove socket file)
|
||||||
.TP
|
.TP
|
||||||
|
@ -35,9 +38,9 @@ print the version
|
||||||
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
Written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||||
.SH "REPORTING BUGS"
|
.SH "REPORTING BUGS"
|
||||||
Report bugs on https://github.com/fail2ban/fail2ban/issues
|
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2004-2008 Cyril Jaquier
|
Copyright \(co 2004\-2008 Cyril Jaquier, 2008\- Fail2Ban Contributors
|
||||||
.br
|
.br
|
||||||
Copyright of modifications held by their respective authors.
|
Copyright of modifications held by their respective authors.
|
||||||
Licensed under the GNU General Public License v2 (GPL).
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
.TH FAIL2BAN "1" "March 2013" "Fail2Ban"
|
||||||
|
.SH NAME
|
||||||
|
fail2ban \- a set of server and client programs to limit brute force authentication attempts.
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Fail2Ban consists of a client, server and configuration files to limit
|
||||||
|
brute force authentication attempts.
|
||||||
|
|
||||||
|
The server program \fBfail2ban-server\fR is responsible for monitoring
|
||||||
|
log files and issuing ban/unban commands. It gets configured through
|
||||||
|
a simple protocol by \fBfail2ban-client\fR, which can also read
|
||||||
|
configuration files and issue corresponding configuration commands to
|
||||||
|
the server.
|
||||||
|
|
||||||
|
For details on the configuration of fail2ban see the jail.conf(5)
|
||||||
|
manual page. A jail (as specified in jail.conf) couples filters and
|
||||||
|
actions definitions for any given list of files to get monitored.
|
||||||
|
|
||||||
|
For details on the command-line options of fail2ban-server see the
|
||||||
|
fail2ban-server(1) manual page.
|
||||||
|
|
||||||
|
For details on the command-line options and commands for configuring
|
||||||
|
the server via fail2ban-client see the fail2ban-client(1) manual page.
|
||||||
|
|
||||||
|
For testing regular expressions specified in a filter using the
|
||||||
|
fail2ban-regex program may be of use and its manual page is
|
||||||
|
fail2ban-regex(1).
|
||||||
|
|
||||||
|
.SH FILES
|
||||||
|
\fI/etc/fail2ban/*\fR
|
||||||
|
.SH AUTHOR
|
||||||
|
Manual page written by Daniel Black and Yaroslav Halchenko
|
||||||
|
.SH "REPORTING BUGS"
|
||||||
|
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
|
.SH COPYRIGHT
|
||||||
|
Copyright \(co 2013
|
||||||
|
.br
|
||||||
|
Copyright of modifications held by their respective authors.
|
||||||
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.br
|
||||||
|
fail2ban-server(1)
|
||||||
|
fail2ban-client(1)
|
||||||
|
fail2ban-regex(1)
|
||||||
|
jail.conf(5)
|
|
@ -0,0 +1,168 @@
|
||||||
|
.TH JAIL.CONF "5" "March 2013" "Fail2Ban" "Fail2Ban Configuration"
|
||||||
|
.SH NAME
|
||||||
|
jail.conf \- configuration for the fail2ban server
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.I jail.conf / jail.local
|
||||||
|
|
||||||
|
.I action.d/*.conf action.d/*.local
|
||||||
|
|
||||||
|
.I filter.d/*.conf filter.d/*.local
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Fail2ban has three configuration file types. Action files are the commands for banning and unbanning of IP address,
|
||||||
|
Filter files tell fail2ban how to detect authentication failures, and Jail configurations combine filters with actions into jails.
|
||||||
|
|
||||||
|
There are *.conf files that are distributed by fail2ban and *.local file that contain user customizations.
|
||||||
|
It is recommended that *.conf files should remain unchanged. If needed, customizations should be provided in *.local files.
|
||||||
|
For instance, if you would like to customize the [ssh-iptables-ipset] jail, create a jail.local to extend jail.conf
|
||||||
|
(the configuration for the fail2ban server). The jail.local file will be the following if you only need to enable
|
||||||
|
it:
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fIjail.local\fR
|
||||||
|
[ssh-iptables-ipset]
|
||||||
|
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
.PP
|
||||||
|
Override only the settings you need to change and the rest of the configuration will come from the corresponding
|
||||||
|
*.conf file.
|
||||||
|
|
||||||
|
\fI*.d/\fR
|
||||||
|
.RS
|
||||||
|
In addition to .local, for any .conf file there can be a corresponding
|
||||||
|
\fI.d/\fR directory to contain additional .conf files that will be read after the
|
||||||
|
appropriate .local file. Last parsed file will take precidence over
|
||||||
|
identical entries, parsed alphabetically, e.g.
|
||||||
|
|
||||||
|
.RS
|
||||||
|
\fIjail.d/01_enable.conf\fR - to enable a specific jail
|
||||||
|
.RE
|
||||||
|
.RS
|
||||||
|
\fIjail.d/02_custom_port.conf\fR - containing specific configuration entry to change the port of the jail specified in the configuration
|
||||||
|
.RE
|
||||||
|
.RS
|
||||||
|
\fIfail2ban.d/01_custom_log.conf\fR - containing specific configuration entry to use a different log path.
|
||||||
|
.RE
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.SH DEFAULT
|
||||||
|
The following options are applicable to all jails. Their meaning is described in the default \fIjail.conf\fR file.
|
||||||
|
.TP
|
||||||
|
\fBignoreip\fR
|
||||||
|
.TP
|
||||||
|
\fBbantime\fR
|
||||||
|
.TP
|
||||||
|
\fBfindtime\fR
|
||||||
|
.TP
|
||||||
|
\fBmaxretry\fR
|
||||||
|
.TP
|
||||||
|
\fBbackend\fR
|
||||||
|
.TP
|
||||||
|
\fBusedns\fR
|
||||||
|
|
||||||
|
|
||||||
|
.SH "ACTION FILES"
|
||||||
|
Action files specify which commands are executed to ban and unban an IP address. They are located under \fI/etc/fail2ban/action.d\fR.
|
||||||
|
|
||||||
|
Like with jail.conf files, if you desire local changes create an \fI[actionname].local\fR file in the \fI/etc/fail2ban/action.d\fR directory
|
||||||
|
and override the required settings.
|
||||||
|
|
||||||
|
Action files are ini files that have two sections, \fBDefinition\fR and \fBInit\fR .
|
||||||
|
|
||||||
|
The [Init] section allows for action-specific settings. In \fIjail.conf/jail.local\fR these can be overwritten for a particular jail as options to the jail.
|
||||||
|
|
||||||
|
The following commands can be present in the [Definition] section.
|
||||||
|
.TP
|
||||||
|
\fBactionstart\fR
|
||||||
|
command(s) executed when the jail starts.
|
||||||
|
.TP
|
||||||
|
\fBactionstop\fR
|
||||||
|
command(s) executed when the jail stops.
|
||||||
|
.TP
|
||||||
|
\fBactioncheck\fR
|
||||||
|
the command ran before any other action. It aims to verify if the environment is still ok.
|
||||||
|
.TP
|
||||||
|
\fBactionban\fR
|
||||||
|
command(s) that bans the IP address after \fBmaxretry\fR log lines matches within last \fBfindtime\fR seconds.
|
||||||
|
.TP
|
||||||
|
\fBactionunban\fR
|
||||||
|
command(s) that unbans the IP address after \fBbantime\fR.
|
||||||
|
|
||||||
|
Commands specified in the [Definition] section are executed through a system shell so shell redirection and process control is allowed. The commands should
|
||||||
|
return 0, otherwise error would be logged. Moreover if \fBactioncheck\fR exits with non-0 status, it is taken as indication that firewall status has changed and fail2ban needs to reinitialize itself (i.e. issue \fBactionstop\fR and \fBactionstart\fR commands).
|
||||||
|
|
||||||
|
Tags are enclosed in <>. All the elements of [Init] are tags that are replaced in all action commands. Tags can be added by the
|
||||||
|
\fBfail2ban-client\fR using the setctag command.
|
||||||
|
|
||||||
|
More than a single command is allowed to be specified. Each command needs to be on a separate line and indented with whitespaces without blank lines. The following example defines
|
||||||
|
two commands to be executed.
|
||||||
|
|
||||||
|
actionban = iptables -I fail2ban-<name> --source <ip> -j DROP
|
||||||
|
echo ip=<ip>, match=<match>, time=<time> >> /var/log/fail2ban.log
|
||||||
|
|
||||||
|
.SS "Action Tags"
|
||||||
|
The following tags are substituted in the actionban, actionunban and actioncheck (when called before actionban/actionunban) commands.
|
||||||
|
.TP
|
||||||
|
\fBip\fR
|
||||||
|
An IPv4 ip address to be banned. e.g. 192.168.0.2
|
||||||
|
.TP
|
||||||
|
\fBfailures\fR
|
||||||
|
The number of times the failure occurred in the log file. e.g. 3
|
||||||
|
.TP
|
||||||
|
\fBtime\fR
|
||||||
|
The unix time of the ban. e.g. 1357508484
|
||||||
|
.TP
|
||||||
|
\fBmatches\fR
|
||||||
|
The concatenated string of the log file lines of the matches that generated the ban. Many characters interpreted by shell get escaped.
|
||||||
|
|
||||||
|
.SH FILTER FILES
|
||||||
|
|
||||||
|
Filter definitions are those in \fI/etc/fail2ban/filter.d/*.conf\fR and \fIfilter.d/*.local\fR.
|
||||||
|
|
||||||
|
These are used to identify failed authentication attempts in logs and to extract the host IP address (or hostname if \fBusedns\fR is \fBtrue\fR).
|
||||||
|
|
||||||
|
Like action files, filter files are ini files. The main section is the [Definition] section.
|
||||||
|
|
||||||
|
There are two filter definitions used in the [Definition] section:
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBfailregex\fR
|
||||||
|
is the regex (\fBreg\fRular \fBex\fRpression) that will match failed attempts. The tag <HOST> is used as part of the regex and is itself a regex
|
||||||
|
for IPv4 addresses and hostnames. fail2ban will work out which one of these it actually is.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBignoreregex\fR
|
||||||
|
is the regex to identify log entries that should be ignored by fail2ban, even if they match failregex.
|
||||||
|
|
||||||
|
|
||||||
|
Using Python "string interpolation" mechanisms, other definitions are allowed and can later be used within other definitions as %(defnname)s. For example.
|
||||||
|
|
||||||
|
baduseragents = IE|wget
|
||||||
|
failregex = useragent=%(baduseragents)s
|
||||||
|
|
||||||
|
.PP
|
||||||
|
Filters can also have a section called [INCLUDES]. This is used to read other configuration files.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBbefore\fR
|
||||||
|
indicates that this file is read before the [Definition] section.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBafter\fR
|
||||||
|
indicates that this file is read after the [Definition] section.
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
Fail2ban was originally written by Cyril Jaquier <cyril.jaquier@fail2ban.org>.
|
||||||
|
At the moment it is maintained and further developed by Yaroslav O. Halchenko <debian@onerussian.com> and a number of contributors. See \fBTHANKS\fR file shipped with Fail2Ban for a full list.
|
||||||
|
.
|
||||||
|
Manual page written by Daniel Black and Yaroslav Halchenko.
|
||||||
|
.SH "REPORTING BUGS"
|
||||||
|
Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
|
.SH COPYRIGHT
|
||||||
|
Copyright \(co 2013 Daniel Black
|
||||||
|
.br
|
||||||
|
Copyright of modifications held by their respective authors.
|
||||||
|
Licensed under the GNU General Public License v2 (GPL).
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.br
|
||||||
|
fail2ban-server(1)
|
|
@ -277,8 +277,8 @@ class Action:
|
||||||
# Executes a command with preliminary checks and substitutions.
|
# Executes a command with preliminary checks and substitutions.
|
||||||
#
|
#
|
||||||
# Before executing any commands, executes the "check" command first
|
# Before executing any commands, executes the "check" command first
|
||||||
# in order to check if prerequirements are met. If this check fails,
|
# in order to check if pre-requirements are met. If this check fails,
|
||||||
# it tries to restore a sane environnement before executing the real
|
# it tries to restore a sane environment before executing the real
|
||||||
# command.
|
# command.
|
||||||
# Replaces "aInfo" and "cInfo" in the query too.
|
# Replaces "aInfo" and "cInfo" in the query too.
|
||||||
#
|
#
|
||||||
|
|
|
@ -77,7 +77,8 @@ class Actions(JailThread):
|
||||||
for action in self.__actions:
|
for action in self.__actions:
|
||||||
if action.getName() == name:
|
if action.getName() == name:
|
||||||
self.__actions.remove(action)
|
self.__actions.remove(action)
|
||||||
break
|
return
|
||||||
|
raise KeyError("Invalid Action name: %s" % name)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns an action.
|
# Returns an action.
|
||||||
|
@ -91,7 +92,7 @@ class Actions(JailThread):
|
||||||
for action in self.__actions:
|
for action in self.__actions:
|
||||||
if action.getName() == name:
|
if action.getName() == name:
|
||||||
return action
|
return action
|
||||||
raise KeyError
|
raise KeyError("Invalid Action name")
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns the last defined action.
|
# Returns the last defined action.
|
||||||
|
@ -131,7 +132,7 @@ class Actions(JailThread):
|
||||||
# Unban the IP.
|
# Unban the IP.
|
||||||
self.__unBan(ticket)
|
self.__unBan(ticket)
|
||||||
return ip
|
return ip
|
||||||
return 'None'
|
raise ValueError("IP %s is not banned" % ip)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Main loop.
|
# Main loop.
|
||||||
|
|
|
@ -148,7 +148,7 @@ class AsyncServer(asyncore.dispatcher):
|
||||||
if sys.version_info >= (2, 6): # if python 2.6 or greater...
|
if sys.version_info >= (2, 6): # if python 2.6 or greater...
|
||||||
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
|
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
|
||||||
asyncore.loop(use_poll = False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
asyncore.loop(use_poll = False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
||||||
else:
|
else: # pragma: no cover
|
||||||
logSys.debug("NOT Python 2.6/3.* - asyncore.loop() using poll")
|
logSys.debug("NOT Python 2.6/3.* - asyncore.loop() using poll")
|
||||||
asyncore.loop(use_poll = True)
|
asyncore.loop(use_poll = True)
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ class BanManager:
|
||||||
def addBanTicket(self, ticket):
|
def addBanTicket(self, ticket):
|
||||||
try:
|
try:
|
||||||
self.__lock.acquire()
|
self.__lock.acquire()
|
||||||
if not self.__inBanList(ticket):
|
if not self._inBanList(ticket):
|
||||||
self.__banList.append(ticket)
|
self.__banList.append(ticket)
|
||||||
self.__banTotal += 1
|
self.__banTotal += 1
|
||||||
return True
|
return True
|
||||||
|
@ -177,7 +177,7 @@ class BanManager:
|
||||||
# @param ticket the ticket
|
# @param ticket the ticket
|
||||||
# @return True if a ticket already exists
|
# @return True if a ticket already exists
|
||||||
|
|
||||||
def __inBanList(self, ticket):
|
def _inBanList(self, ticket):
|
||||||
for i in self.__banList:
|
for i in self.__banList:
|
||||||
if ticket.getIP() == i.getIP():
|
if ticket.getIP() == i.getIP():
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -50,8 +50,11 @@ class DateTemplate:
|
||||||
def getName(self):
|
def getName(self):
|
||||||
return self.__name
|
return self.__name
|
||||||
|
|
||||||
def setRegex(self, regex):
|
def setRegex(self, regex, wordBegin=True):
|
||||||
self.__regex = regex.strip()
|
regex = regex.strip()
|
||||||
|
if (wordBegin and not re.search(r'^\^', regex)):
|
||||||
|
regex = r'\b' + regex
|
||||||
|
self.__regex = regex
|
||||||
self.__cRegex = re.compile(regex)
|
self.__cRegex = re.compile(regex)
|
||||||
|
|
||||||
def getRegex(self):
|
def getRegex(self):
|
||||||
|
@ -158,6 +161,7 @@ class DateStrptime(DateTemplate):
|
||||||
"pattern" % (opattern, e))
|
"pattern" % (opattern, e))
|
||||||
if date[0] < 2000:
|
if date[0] < 2000:
|
||||||
# There is probably no year field in the logs
|
# There is probably no year field in the logs
|
||||||
|
# NOTE: Possibly makes week/year day incorrect
|
||||||
date[0] = MyTime.gmtime()[0]
|
date[0] = MyTime.gmtime()[0]
|
||||||
# Bug fix for #1241756
|
# Bug fix for #1241756
|
||||||
# If the date is greater than the current time, we suppose
|
# If the date is greater than the current time, we suppose
|
||||||
|
@ -166,10 +170,12 @@ class DateStrptime(DateTemplate):
|
||||||
logSys.debug(
|
logSys.debug(
|
||||||
u"Correcting deduced year from %d to %d since %f > %f" %
|
u"Correcting deduced year from %d to %d since %f > %f" %
|
||||||
(date[0], date[0]-1, time.mktime(tuple(date)), MyTime.time()))
|
(date[0], date[0]-1, time.mktime(tuple(date)), MyTime.time()))
|
||||||
|
# NOTE: Possibly makes week/year day incorrect
|
||||||
date[0] -= 1
|
date[0] -= 1
|
||||||
elif date[1] == 1 and date[2] == 1:
|
elif date[1] == 1 and date[2] == 1:
|
||||||
# If it is Jan 1st, it is either really Jan 1st or there
|
# If it is Jan 1st, it is either really Jan 1st or there
|
||||||
# is neither month nor day in the log.
|
# is neither month nor day in the log.
|
||||||
|
# NOTE: Possibly makes week/year day incorrect
|
||||||
date[1] = MyTime.gmtime()[1]
|
date[1] = MyTime.gmtime()[1]
|
||||||
date[2] = MyTime.gmtime()[2]
|
date[2] = MyTime.gmtime()[2]
|
||||||
return date
|
return date
|
||||||
|
@ -180,7 +186,8 @@ class DateTai64n(DateTemplate):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
DateTemplate.__init__(self)
|
DateTemplate.__init__(self)
|
||||||
# We already know the format for TAI64N
|
# We already know the format for TAI64N
|
||||||
self.setRegex("@[0-9a-f]{24}")
|
# yoh: we should not add an additional front anchor
|
||||||
|
self.setRegex("@[0-9a-f]{24}", wordBegin=False)
|
||||||
|
|
||||||
def getDate(self, line):
|
def getDate(self, line):
|
||||||
date = None
|
date = None
|
||||||
|
|
|
@ -105,9 +105,17 @@ class FailManager:
|
||||||
fData.setLastReset(unixTime)
|
fData.setLastReset(unixTime)
|
||||||
fData.setLastTime(unixTime)
|
fData.setLastTime(unixTime)
|
||||||
self.__failList[ip] = fData
|
self.__failList[ip] = fData
|
||||||
logSys.debug("Currently have failures from %d IPs: %s"
|
|
||||||
% (len(self.__failList), self.__failList.keys()))
|
|
||||||
self.__failTotal += 1
|
self.__failTotal += 1
|
||||||
|
|
||||||
|
if logSys.getEffectiveLevel() <= logging.DEBUG:
|
||||||
|
# yoh: Since composing this list might be somewhat time consuming
|
||||||
|
# in case of having many active failures, it should be ran only
|
||||||
|
# if debug level is "low" enough
|
||||||
|
failures_summary = ', '.join(['%s:%d' % (k, v.getRetry())
|
||||||
|
for k,v in self.__failList.iteritems()])
|
||||||
|
logSys.debug("Total # of detected failures: %d. Current failures from %d IPs (IP:count): %s"
|
||||||
|
% (self.__failTotal, len(self.__failList), failures_summary))
|
||||||
finally:
|
finally:
|
||||||
self.__lock.release()
|
self.__lock.release()
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ logSys = logging.getLogger("fail2ban.filter")
|
||||||
# Log reader class.
|
# Log reader class.
|
||||||
#
|
#
|
||||||
# This class reads a log file and detects login failures or anything else
|
# This class reads a log file and detects login failures or anything else
|
||||||
# that matches a given regular expression. This class is instanciated by
|
# that matches a given regular expression. This class is instantiated by
|
||||||
# a Jail object.
|
# a Jail object.
|
||||||
|
|
||||||
class Filter(JailThread):
|
class Filter(JailThread):
|
||||||
|
@ -93,6 +93,7 @@ class Filter(JailThread):
|
||||||
self.__failRegex.append(regex)
|
self.__failRegex.append(regex)
|
||||||
except RegexException, e:
|
except RegexException, e:
|
||||||
logSys.error(e)
|
logSys.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def delFailRegex(self, index):
|
def delFailRegex(self, index):
|
||||||
|
@ -117,7 +118,7 @@ class Filter(JailThread):
|
||||||
# Add the regular expression which matches the failure.
|
# Add the regular expression which matches the failure.
|
||||||
#
|
#
|
||||||
# The regular expression can also match any other pattern than failures
|
# The regular expression can also match any other pattern than failures
|
||||||
# and thus can be used for many purporse.
|
# and thus can be used for many purpose.
|
||||||
# @param value the regular expression
|
# @param value the regular expression
|
||||||
|
|
||||||
def addIgnoreRegex(self, value):
|
def addIgnoreRegex(self, value):
|
||||||
|
@ -126,6 +127,7 @@ class Filter(JailThread):
|
||||||
self.__ignoreRegex.append(regex)
|
self.__ignoreRegex.append(regex)
|
||||||
except RegexException, e:
|
except RegexException, e:
|
||||||
logSys.error(e)
|
logSys.error(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
def delIgnoreRegex(self, index):
|
def delIgnoreRegex(self, index):
|
||||||
try:
|
try:
|
||||||
|
@ -211,7 +213,7 @@ class Filter(JailThread):
|
||||||
# file has been modified and looks for failures.
|
# file has been modified and looks for failures.
|
||||||
# @return True when the thread exits nicely
|
# @return True when the thread exits nicely
|
||||||
|
|
||||||
def run(self):
|
def run(self): # pragma: no cover
|
||||||
raise Exception("run() is abstract")
|
raise Exception("run() is abstract")
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -226,7 +228,7 @@ class Filter(JailThread):
|
||||||
self.failManager.addFailure(FailTicket(ip, unixTime))
|
self.failManager.addFailure(FailTicket(ip, unixTime))
|
||||||
|
|
||||||
# Perform the banning of the IP now.
|
# Perform the banning of the IP now.
|
||||||
try:
|
try: # pragma: no branch - exception is the only way out
|
||||||
while True:
|
while True:
|
||||||
ticket = self.failManager.toBan()
|
ticket = self.failManager.toBan()
|
||||||
self.jail.putFailTicket(ticket)
|
self.jail.putFailTicket(ticket)
|
||||||
|
@ -368,7 +370,7 @@ class Filter(JailThread):
|
||||||
failList.append([ip, date])
|
failList.append([ip, date])
|
||||||
# We matched a regex, it is enough to stop.
|
# We matched a regex, it is enough to stop.
|
||||||
break
|
break
|
||||||
except RegexException, e:
|
except RegexException, e: # pragma: no cover - unsure if reachable
|
||||||
logSys.error(e)
|
logSys.error(e)
|
||||||
return failList
|
return failList
|
||||||
|
|
||||||
|
@ -410,7 +412,7 @@ class FileFilter(Filter):
|
||||||
|
|
||||||
def _addLogPath(self, path):
|
def _addLogPath(self, path):
|
||||||
# nothing to do by default
|
# nothing to do by default
|
||||||
# to be overriden by backends
|
# to be overridden by backends
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -429,7 +431,7 @@ class FileFilter(Filter):
|
||||||
|
|
||||||
def _delLogPath(self, path):
|
def _delLogPath(self, path):
|
||||||
# nothing to do by default
|
# nothing to do by default
|
||||||
# to be overriden by backends
|
# to be overridden by backends
|
||||||
pass
|
pass
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -495,10 +497,19 @@ class FileFilter(Filter):
|
||||||
# Try to open log file.
|
# Try to open log file.
|
||||||
try:
|
try:
|
||||||
container.open()
|
container.open()
|
||||||
except Exception, e:
|
# see http://python.org/dev/peps/pep-3151/
|
||||||
|
except IOError, e:
|
||||||
logSys.error("Unable to open %s" % filename)
|
logSys.error("Unable to open %s" % filename)
|
||||||
logSys.exception(e)
|
logSys.exception(e)
|
||||||
return False
|
return False
|
||||||
|
except OSError, e: # pragma: no cover - requires race condition to tigger this
|
||||||
|
logSys.error("Error opening %s" % filename)
|
||||||
|
logSys.exception(e)
|
||||||
|
return False
|
||||||
|
except OSError, e: # pragma: no cover - Requires implemention error in FileContainer to generate
|
||||||
|
logSys.error("Internal errror in FileContainer open method - please report as a bug to https://github.com/fail2ban/fail2ban/issues")
|
||||||
|
logSys.exception(e)
|
||||||
|
return False
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
line = container.readline()
|
line = container.readline()
|
||||||
|
@ -525,7 +536,7 @@ class FileFilter(Filter):
|
||||||
try:
|
try:
|
||||||
import hashlib
|
import hashlib
|
||||||
md5sum = hashlib.md5
|
md5sum = hashlib.md5
|
||||||
except ImportError:
|
except ImportError: # pragma: no cover
|
||||||
# hashlib was introduced in Python 2.5. For compatibility with those
|
# hashlib was introduced in Python 2.5. For compatibility with those
|
||||||
# elderly Pythons, import from md5
|
# elderly Pythons, import from md5
|
||||||
import md5
|
import md5
|
||||||
|
@ -576,7 +587,7 @@ class FileContainer:
|
||||||
stats = os.fstat(self.__handler.fileno())
|
stats = os.fstat(self.__handler.fileno())
|
||||||
# Compare hash and inode
|
# Compare hash and inode
|
||||||
if self.__hash != myHash or self.__ino != stats.st_ino:
|
if self.__hash != myHash or self.__ino != stats.st_ino:
|
||||||
logSys.info("Log rotation detected for %s" % self.__filename)
|
logSys.debug("Log rotation detected for %s" % self.__filename)
|
||||||
self.__hash = myHash
|
self.__hash = myHash
|
||||||
self.__ino = stats.st_ino
|
self.__ino = stats.st_ino
|
||||||
self.__pos = 0
|
self.__pos = 0
|
||||||
|
|
|
@ -39,7 +39,7 @@ logSys = logging.getLogger("fail2ban.filter")
|
||||||
# Log reader class.
|
# Log reader class.
|
||||||
#
|
#
|
||||||
# This class reads a log file and detects login failures or anything else
|
# This class reads a log file and detects login failures or anything else
|
||||||
# that matches a given regular expression. This class is instanciated by
|
# that matches a given regular expression. This class is instantiated by
|
||||||
# a Jail object.
|
# a Jail object.
|
||||||
|
|
||||||
class FilterPoll(FileFilter):
|
class FilterPoll(FileFilter):
|
||||||
|
|
|
@ -63,16 +63,17 @@ class FilterPyinotify(FileFilter):
|
||||||
logSys.debug("Created FilterPyinotify")
|
logSys.debug("Created FilterPyinotify")
|
||||||
|
|
||||||
|
|
||||||
def callback(self, event):
|
def callback(self, event, origin=''):
|
||||||
|
logSys.debug("%sCallback for Event: %s", origin, event)
|
||||||
path = event.pathname
|
path = event.pathname
|
||||||
if event.mask & pyinotify.IN_CREATE:
|
if event.mask & pyinotify.IN_CREATE:
|
||||||
# skip directories altogether
|
# skip directories altogether
|
||||||
if event.mask & pyinotify.IN_ISDIR:
|
if event.mask & pyinotify.IN_ISDIR:
|
||||||
logSys.debug("Ignoring creation of directory %s" % path)
|
logSys.debug("Ignoring creation of directory %s", path)
|
||||||
return
|
return
|
||||||
# check if that is a file we care about
|
# check if that is a file we care about
|
||||||
if not path in self.__watches:
|
if not path in self.__watches:
|
||||||
logSys.debug("Ignoring creation of %s we do not monitor" % path)
|
logSys.debug("Ignoring creation of %s we do not monitor", path)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# we need to substitute the watcher with a new one, so first
|
# we need to substitute the watcher with a new one, so first
|
||||||
|
@ -104,7 +105,7 @@ class FilterPyinotify(FileFilter):
|
||||||
def _addFileWatcher(self, path):
|
def _addFileWatcher(self, path):
|
||||||
wd = self.__monitor.add_watch(path, pyinotify.IN_MODIFY)
|
wd = self.__monitor.add_watch(path, pyinotify.IN_MODIFY)
|
||||||
self.__watches.update(wd)
|
self.__watches.update(wd)
|
||||||
logSys.debug("Added file watcher for %s" % path)
|
logSys.debug("Added file watcher for %s", path)
|
||||||
# process the file since we did get even
|
# process the file since we did get even
|
||||||
self._process_file(path)
|
self._process_file(path)
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ class FilterPyinotify(FileFilter):
|
||||||
wd = self.__monitor.rm_watch(wdInt)
|
wd = self.__monitor.rm_watch(wdInt)
|
||||||
if wd[wdInt]:
|
if wd[wdInt]:
|
||||||
del self.__watches[path]
|
del self.__watches[path]
|
||||||
logSys.debug("Removed file watcher for %s" % path)
|
logSys.debug("Removed file watcher for %s", path)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -130,7 +131,7 @@ class FilterPyinotify(FileFilter):
|
||||||
# we need to watch also the directory for IN_CREATE
|
# we need to watch also the directory for IN_CREATE
|
||||||
self.__watches.update(
|
self.__watches.update(
|
||||||
self.__monitor.add_watch(path_dir, pyinotify.IN_CREATE))
|
self.__monitor.add_watch(path_dir, pyinotify.IN_CREATE))
|
||||||
logSys.debug("Added monitor for the parent directory %s" % path_dir)
|
logSys.debug("Added monitor for the parent directory %s", path_dir)
|
||||||
|
|
||||||
self._addFileWatcher(path)
|
self._addFileWatcher(path)
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ class FilterPyinotify(FileFilter):
|
||||||
# since there is no other monitored file under this directory
|
# since there is no other monitored file under this directory
|
||||||
wdInt = self.__watches.pop(path_dir)
|
wdInt = self.__watches.pop(path_dir)
|
||||||
_ = self.__monitor.rm_watch(wdInt)
|
_ = self.__monitor.rm_watch(wdInt)
|
||||||
logSys.debug("Removed monitor for the parent directory %s" % path_dir)
|
logSys.debug("Removed monitor for the parent directory %s", path_dir)
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -165,7 +166,7 @@ class FilterPyinotify(FileFilter):
|
||||||
self.__notifier = pyinotify.ThreadedNotifier(self.__monitor,
|
self.__notifier = pyinotify.ThreadedNotifier(self.__monitor,
|
||||||
ProcessPyinotify(self))
|
ProcessPyinotify(self))
|
||||||
self.__notifier.start()
|
self.__notifier.start()
|
||||||
logSys.debug("pyinotifier started for %s." % self.jail.getName())
|
logSys.debug("pyinotifier started for %s.", self.jail.getName())
|
||||||
# TODO: verify that there is nothing really to be done for
|
# TODO: verify that there is nothing really to be done for
|
||||||
# idle jails
|
# idle jails
|
||||||
return True
|
return True
|
||||||
|
@ -201,5 +202,4 @@ class ProcessPyinotify(pyinotify.ProcessEvent):
|
||||||
|
|
||||||
# just need default, since using mask on watch to limit events
|
# just need default, since using mask on watch to limit events
|
||||||
def process_default(self, event):
|
def process_default(self, event):
|
||||||
logSys.debug("Callback for Event: %s" % event)
|
self.__FileFilter.callback(event, origin='Default ')
|
||||||
self.__FileFilter.callback(event)
|
|
||||||
|
|
|
@ -382,7 +382,7 @@ class Server:
|
||||||
try:
|
try:
|
||||||
handler.flush()
|
handler.flush()
|
||||||
handler.close()
|
handler.close()
|
||||||
except ValueError:
|
except (ValueError, KeyError):
|
||||||
if (2,6) <= sys.version_info < (3,) or \
|
if (2,6) <= sys.version_info < (3,) or \
|
||||||
(3,2) <= sys.version_info:
|
(3,2) <= sys.version_info:
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -112,14 +112,18 @@ class Transmitter:
|
||||||
return self.__server.getLogLevel()
|
return self.__server.getLogLevel()
|
||||||
elif name == "logtarget":
|
elif name == "logtarget":
|
||||||
value = command[1]
|
value = command[1]
|
||||||
self.__server.setLogTarget(value)
|
if self.__server.setLogTarget(value):
|
||||||
return self.__server.getLogTarget()
|
return self.__server.getLogTarget()
|
||||||
|
else:
|
||||||
|
raise Exception("Failed to change log target")
|
||||||
# Jail
|
# Jail
|
||||||
elif command[1] == "idle":
|
elif command[1] == "idle":
|
||||||
if command[2] == "on":
|
if command[2] == "on":
|
||||||
self.__server.setIdleJail(name, True)
|
self.__server.setIdleJail(name, True)
|
||||||
elif command[2] == "off":
|
elif command[2] == "off":
|
||||||
self.__server.setIdleJail(name, False)
|
self.__server.setIdleJail(name, False)
|
||||||
|
else:
|
||||||
|
raise Exception("Invalid idle option, must be 'yes' or 'no'")
|
||||||
return self.__server.getIdleJail(name)
|
return self.__server.getIdleJail(name)
|
||||||
# Filter
|
# Filter
|
||||||
elif command[1] == "addignoreip":
|
elif command[1] == "addignoreip":
|
||||||
|
@ -193,7 +197,7 @@ class Transmitter:
|
||||||
elif command[1] == "setcinfo":
|
elif command[1] == "setcinfo":
|
||||||
act = command[2]
|
act = command[2]
|
||||||
key = command[3]
|
key = command[3]
|
||||||
value = command[4]
|
value = " ".join(command[4:])
|
||||||
self.__server.setCInfo(name, act, key, value)
|
self.__server.setCInfo(name, act, key, value)
|
||||||
return self.__server.getCInfo(name, act, key)
|
return self.__server.getCInfo(name, act, key)
|
||||||
elif command[1] == "delcinfo":
|
elif command[1] == "delcinfo":
|
||||||
|
@ -203,27 +207,27 @@ class Transmitter:
|
||||||
return None
|
return None
|
||||||
elif command[1] == "actionstart":
|
elif command[1] == "actionstart":
|
||||||
act = command[2]
|
act = command[2]
|
||||||
value = command[3]
|
value = " ".join(command[3:])
|
||||||
self.__server.setActionStart(name, act, value)
|
self.__server.setActionStart(name, act, value)
|
||||||
return self.__server.getActionStart(name, act)
|
return self.__server.getActionStart(name, act)
|
||||||
elif command[1] == "actionstop":
|
elif command[1] == "actionstop":
|
||||||
act = command[2]
|
act = command[2]
|
||||||
value = command[3]
|
value = " ".join(command[3:])
|
||||||
self.__server.setActionStop(name, act, value)
|
self.__server.setActionStop(name, act, value)
|
||||||
return self.__server.getActionStop(name, act)
|
return self.__server.getActionStop(name, act)
|
||||||
elif command[1] == "actioncheck":
|
elif command[1] == "actioncheck":
|
||||||
act = command[2]
|
act = command[2]
|
||||||
value = command[3]
|
value = " ".join(command[3:])
|
||||||
self.__server.setActionCheck(name, act, value)
|
self.__server.setActionCheck(name, act, value)
|
||||||
return self.__server.getActionCheck(name, act)
|
return self.__server.getActionCheck(name, act)
|
||||||
elif command[1] == "actionban":
|
elif command[1] == "actionban":
|
||||||
act = command[2]
|
act = command[2]
|
||||||
value = command[3]
|
value = " ".join(command[3:])
|
||||||
self.__server.setActionBan(name, act, value)
|
self.__server.setActionBan(name, act, value)
|
||||||
return self.__server.getActionBan(name, act)
|
return self.__server.getActionBan(name, act)
|
||||||
elif command[1] == "actionunban":
|
elif command[1] == "actionunban":
|
||||||
act = command[2]
|
act = command[2]
|
||||||
value = command[3]
|
value = " ".join(command[3:])
|
||||||
self.__server.setActionUnban(name, act, value)
|
self.__server.setActionUnban(name, act, value)
|
||||||
return self.__server.getActionUnban(name, act)
|
return self.__server.getActionUnban(name, act)
|
||||||
raise Exception("Invalid command (no set action or not yet implemented)")
|
raise Exception("Invalid command (no set action or not yet implemented)")
|
||||||
|
@ -281,7 +285,7 @@ class Transmitter:
|
||||||
def status(self, command):
|
def status(self, command):
|
||||||
if len(command) == 0:
|
if len(command) == 0:
|
||||||
return self.__server.status()
|
return self.__server.status()
|
||||||
else:
|
elif len(command) == 1:
|
||||||
name = command[0]
|
name = command[0]
|
||||||
return self.__server.statusJail(name)
|
return self.__server.statusJail(name)
|
||||||
raise Exception("Invalid command (no status)")
|
raise Exception("Invalid command (no status)")
|
||||||
|
|
|
@ -3,3 +3,11 @@ install-purelib=/usr/share/fail2ban
|
||||||
|
|
||||||
[sdist]
|
[sdist]
|
||||||
formats=bztar
|
formats=bztar
|
||||||
|
|
||||||
|
[bdist_rpm]
|
||||||
|
release = 1
|
||||||
|
packager = Yaroslav Halchenko <debian@onerussian.com>, Daniel Black <grooverdan@users.sourceforge.net>
|
||||||
|
doc_files = DEVELOP
|
||||||
|
README
|
||||||
|
THANKS
|
||||||
|
doc/run-rootless.txt
|
||||||
|
|
9
setup.py
9
setup.py
|
@ -67,6 +67,9 @@ setup(
|
||||||
),
|
),
|
||||||
('/var/run/fail2ban',
|
('/var/run/fail2ban',
|
||||||
''
|
''
|
||||||
|
),
|
||||||
|
('/usr/share/doc/fail2ban',
|
||||||
|
['README', 'DEVELOP', 'doc/run-rootless.txt']
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -83,12 +86,6 @@ elements = {
|
||||||
[
|
[
|
||||||
"fail2ban.py"
|
"fail2ban.py"
|
||||||
],
|
],
|
||||||
"/usr/lib/fail2ban/firewall/":
|
|
||||||
[
|
|
||||||
"iptables.py",
|
|
||||||
"ipfwadm.py",
|
|
||||||
"ipfw.py"
|
|
||||||
],
|
|
||||||
"/usr/lib/fail2ban/":
|
"/usr/lib/fail2ban/":
|
||||||
[
|
[
|
||||||
"version.py",
|
"version.py",
|
||||||
|
|
|
@ -49,11 +49,11 @@ class AddFailure(unittest.TestCase):
|
||||||
self.assertFalse(self.__banManager.addBanTicket(self.__ticket))
|
self.assertFalse(self.__banManager.addBanTicket(self.__ticket))
|
||||||
self.assertEqual(self.__banManager.size(), 1)
|
self.assertEqual(self.__banManager.size(), 1)
|
||||||
|
|
||||||
def _testInListOK(self):
|
def testInListOK(self):
|
||||||
ticket = BanTicket('193.168.0.128', 1167605999.0)
|
ticket = BanTicket('193.168.0.128', 1167605999.0)
|
||||||
self.assertTrue(self.__banManager.inBanList(ticket))
|
self.assertTrue(self.__banManager._inBanList(ticket))
|
||||||
|
|
||||||
def _testInListNOK(self):
|
def testInListNOK(self):
|
||||||
ticket = BanTicket('111.111.1.111', 1167605999.0)
|
ticket = BanTicket('111.111.1.111', 1167605999.0)
|
||||||
self.assertFalse(self.__banManager.inBanList(ticket))
|
self.assertFalse(self.__banManager._inBanList(ticket))
|
||||||
|
|
||||||
|
|
|
@ -17,26 +17,92 @@
|
||||||
# along with Fail2Ban; if not, write to the Free Software
|
# along with Fail2Ban; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
__author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
||||||
#
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
||||||
# $Revision$
|
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
|
||||||
__version__ = "$Revision$"
|
|
||||||
__date__ = "$Date$"
|
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest
|
import os, shutil, tempfile, unittest
|
||||||
|
from client.configreader import ConfigReader
|
||||||
from client.jailreader import JailReader
|
from client.jailreader import JailReader
|
||||||
|
from client.jailsreader import JailsReader
|
||||||
|
from client.configurator import Configurator
|
||||||
|
|
||||||
class JailReaderTest(unittest.TestCase):
|
class ConfigReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
|
self.d = tempfile.mkdtemp(prefix="f2b-temp")
|
||||||
|
self.c = ConfigReader(basedir=self.d)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Call after every test case."""
|
"""Call after every test case."""
|
||||||
|
shutil.rmtree(self.d)
|
||||||
|
|
||||||
|
def _write(self, fname, value):
|
||||||
|
# verify if we don't need to create .d directory
|
||||||
|
if os.path.sep in fname:
|
||||||
|
d = os.path.dirname(fname)
|
||||||
|
d_ = os.path.join(self.d, d)
|
||||||
|
if not os.path.exists(d_):
|
||||||
|
os.makedirs(d_)
|
||||||
|
open("%s/%s" % (self.d, fname), "w").write("""
|
||||||
|
[section]
|
||||||
|
option = %s
|
||||||
|
""" % value)
|
||||||
|
|
||||||
|
def _remove(self, fname):
|
||||||
|
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)
|
||||||
|
self.assertEqual(self._getoption('d'), 0)
|
||||||
|
os.chmod(f, 0)
|
||||||
|
self.assertFalse(self.c.read('d')) # should not be readable BUT present
|
||||||
|
|
||||||
|
|
||||||
|
def testOptionalDotDDir(self):
|
||||||
|
self.assertFalse(self.c.read('c')) # nothing is there yet
|
||||||
|
self._write("c.conf", "1")
|
||||||
|
self.assertEqual(self._getoption(), 1)
|
||||||
|
self._write("c.conf", "2") # overwrite
|
||||||
|
self.assertEqual(self._getoption(), 2)
|
||||||
|
self._write("c.local", "3") # add override in .local
|
||||||
|
self.assertEqual(self._getoption(), 3)
|
||||||
|
self._write("c.d/98.conf", "998") # add 1st override in .d/
|
||||||
|
self.assertEqual(self._getoption(), 998)
|
||||||
|
self._write("c.d/90.conf", "990") # add previously sorted override in .d/
|
||||||
|
self.assertEqual(self._getoption(), 998) # should stay the same
|
||||||
|
self._write("c.d/99.conf", "999") # now override in a way without sorting we possibly get a failure
|
||||||
|
self.assertEqual(self._getoption(), 999)
|
||||||
|
self._remove("c.d/99.conf")
|
||||||
|
self.assertEqual(self._getoption(), 998)
|
||||||
|
self._remove("c.d/98.conf")
|
||||||
|
self.assertEqual(self._getoption(), 990)
|
||||||
|
self._remove("c.d/90.conf")
|
||||||
|
self.assertEqual(self._getoption(), 3)
|
||||||
|
self._remove("c.conf") # we allow to stay without .conf
|
||||||
|
self.assertEqual(self._getoption(), 3)
|
||||||
|
self._write("c.conf", "1")
|
||||||
|
self._remove("c.local")
|
||||||
|
self.assertEqual(self._getoption(), 1)
|
||||||
|
|
||||||
|
|
||||||
|
class JailReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def testStockSSHJail(self):
|
||||||
|
jail = JailReader('ssh-iptables', basedir='config') # we are running tests from root project dir atm
|
||||||
|
self.assertTrue(jail.read())
|
||||||
|
self.assertTrue(jail.getOptions())
|
||||||
|
self.assertFalse(jail.isEnabled())
|
||||||
|
self.assertEqual(jail.getName(), 'ssh-iptables')
|
||||||
|
|
||||||
def testSplitAction(self):
|
def testSplitAction(self):
|
||||||
action = "mail-whois[name=SSH]"
|
action = "mail-whois[name=SSH]"
|
||||||
|
@ -44,3 +110,59 @@ class JailReaderTest(unittest.TestCase):
|
||||||
result = JailReader.splitAction(action)
|
result = JailReader.splitAction(action)
|
||||||
self.assertEquals(expected, result)
|
self.assertEquals(expected, result)
|
||||||
|
|
||||||
|
class JailsReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def testProvidingBadBasedir(self):
|
||||||
|
if not os.path.exists('/XXX'):
|
||||||
|
reader = JailsReader(basedir='/XXX')
|
||||||
|
self.assertRaises(ValueError, reader.read)
|
||||||
|
|
||||||
|
def testReadStockJailConf(self):
|
||||||
|
jails = JailsReader(basedir='config') # we are running tests from root project dir atm
|
||||||
|
self.assertTrue(jails.read()) # opens fine
|
||||||
|
self.assertTrue(jails.getOptions()) # reads fine
|
||||||
|
comm_commands = jails.convert()
|
||||||
|
# by default None of the jails is enabled and we get no
|
||||||
|
# commands to communicate to the server
|
||||||
|
self.assertEqual(comm_commands, [])
|
||||||
|
|
||||||
|
def testReadStockJailConfForceEnabled(self):
|
||||||
|
# more of a smoke test to make sure that no obvious surprises
|
||||||
|
# on users' systems when enabling shipped jails
|
||||||
|
jails = JailsReader(basedir='config', force_enable=True) # we are running tests from root project dir atm
|
||||||
|
self.assertTrue(jails.read()) # opens fine
|
||||||
|
self.assertTrue(jails.getOptions()) # reads fine
|
||||||
|
comm_commands = jails.convert()
|
||||||
|
|
||||||
|
# by default we have lots of jails ;)
|
||||||
|
self.assertTrue(len(comm_commands))
|
||||||
|
|
||||||
|
# and we know even some of them by heart
|
||||||
|
for j in ['ssh-iptables', 'recidive']:
|
||||||
|
# by default we have 'auto' backend ATM
|
||||||
|
self.assertTrue(['add', j, 'auto'] in comm_commands)
|
||||||
|
# and warn on useDNS
|
||||||
|
self.assertTrue(['set', j, 'usedns', 'warn'] in comm_commands)
|
||||||
|
self.assertTrue(['start', j] in comm_commands)
|
||||||
|
# last commands should be the 'start' commands
|
||||||
|
self.assertEqual(comm_commands[-1][0], 'start')
|
||||||
|
# TODO: make sure that all of the jails have actions assigned,
|
||||||
|
# otherwise it makes little to no sense
|
||||||
|
|
||||||
|
def testConfigurator(self):
|
||||||
|
configurator = Configurator()
|
||||||
|
configurator.setBaseDir('config')
|
||||||
|
self.assertEqual(configurator.getBaseDir(), 'config')
|
||||||
|
|
||||||
|
configurator.readEarly()
|
||||||
|
opts = configurator.getEarlyOptions()
|
||||||
|
# our current default settings
|
||||||
|
self.assertEqual(opts['socket'], '/var/run/fail2ban/fail2ban.sock')
|
||||||
|
self.assertEqual(opts['pidfile'], '/var/run/fail2ban/fail2ban.pid')
|
||||||
|
|
||||||
|
# and if we force change configurator's fail2ban's baseDir
|
||||||
|
# there should be an error message (test visually ;) --
|
||||||
|
# otherwise just a code smoke test)
|
||||||
|
configurator._Configurator__jails.setBaseDir('/tmp')
|
||||||
|
self.assertEqual(configurator._Configurator__jails.getBaseDir(), '/tmp')
|
||||||
|
self.assertEqual(configurator.getBaseDir(), 'config')
|
||||||
|
|
|
@ -51,30 +51,44 @@ class DateDetectorTest(unittest.TestCase):
|
||||||
|
|
||||||
def testGetTime(self):
|
def testGetTime(self):
|
||||||
log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure"
|
log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure"
|
||||||
date = [2005, 1, 23, 21, 59, 59, 1, 23, -1]
|
date = [2005, 1, 23, 21, 59, 59, 6, 23, -1]
|
||||||
dateUnix = 1106513999.0
|
dateUnix = 1106513999.0
|
||||||
|
# yoh: testing only up to 6 elements, since the day of the week
|
||||||
self.assertEqual(self.__datedetector.getTime(log), date)
|
# is not correctly determined atm, since year is not present
|
||||||
|
# in the log entry. Since this doesn't effect the operation
|
||||||
|
# of fail2ban -- we just ignore incorrect day of the week
|
||||||
|
self.assertEqual(self.__datedetector.getTime(log)[:6], date[:6])
|
||||||
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
||||||
|
|
||||||
def testVariousTimes(self):
|
def testVariousTimes(self):
|
||||||
"""Test detection of various common date/time formats f2b should understand
|
"""Test detection of various common date/time formats f2b should understand
|
||||||
"""
|
"""
|
||||||
date = [2005, 1, 23, 21, 59, 59, 1, 23, -1]
|
date = [2005, 1, 23, 21, 59, 59, 6, 23, -1]
|
||||||
dateUnix = 1106513999.0
|
dateUnix = 1106513999.0
|
||||||
|
|
||||||
for sdate in (
|
for sdate in (
|
||||||
"Jan 23 21:59:59",
|
"Jan 23 21:59:59",
|
||||||
|
"Sun Jan 23 21:59:59 2005",
|
||||||
|
"Sun Jan 23 21:59:59",
|
||||||
|
"2005/01/23 21:59:59",
|
||||||
"2005.01.23 21:59:59",
|
"2005.01.23 21:59:59",
|
||||||
"23/01/2005 21:59:59",
|
"23/01/2005 21:59:59",
|
||||||
|
"23/01/05 21:59:59",
|
||||||
|
"23/Jan/2005:21:59:59",
|
||||||
|
"01/23/2005:21:59:59",
|
||||||
|
"2005-01-23 21:59:59",
|
||||||
|
"23-Jan-2005 21:59:59",
|
||||||
|
"23-01-2005 21:59:59",
|
||||||
"01-23-2005 21:59:59.252", # reported on f2b, causes Feb29 fix to break
|
"01-23-2005 21:59:59.252", # reported on f2b, causes Feb29 fix to break
|
||||||
|
"@4000000041f4104f00000000", # TAI64N
|
||||||
|
"2005-01-23T21:59:59.252Z", #ISO 8601
|
||||||
|
"2005-01-23T21:59:59-05:00Z", #ISO 8601 with TZ
|
||||||
|
"<01/23/05@21:59:59>",
|
||||||
):
|
):
|
||||||
log = sdate + "[sshd] error: PAM: Authentication failure"
|
log = sdate + "[sshd] error: PAM: Authentication failure"
|
||||||
# exclude
|
# exclude
|
||||||
|
|
||||||
# TODO (Yarik is confused): figure out why for above it is
|
# yoh: on [:6] see in above test
|
||||||
# "1" as day of the week which would be Tue, although it
|
|
||||||
# was Sun
|
|
||||||
self.assertEqual(self.__datedetector.getTime(log)[:6], date[:6])
|
self.assertEqual(self.__datedetector.getTime(log)[:6], date[:6])
|
||||||
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
|
||||||
|
|
||||||
|
@ -89,6 +103,27 @@ class DateDetectorTest(unittest.TestCase):
|
||||||
self.assertRaises(ValueError, self.__datedetector._appendTemplate,
|
self.assertRaises(ValueError, self.__datedetector._appendTemplate,
|
||||||
self.__datedetector.getTemplates()[0])
|
self.__datedetector.getTemplates()[0])
|
||||||
|
|
||||||
|
def testFullYearMatch_gh130(self):
|
||||||
|
# see https://github.com/fail2ban/fail2ban/pull/130
|
||||||
|
# yoh: unfortunately this test is not really effective to reproduce the
|
||||||
|
# situation but left in place to assure consistent behavior
|
||||||
|
m1 = [2012, 10, 11, 2, 37, 17]
|
||||||
|
self.assertEqual(
|
||||||
|
self.__datedetector.getTime('2012/10/11 02:37:17 [error] 18434#0')[:6],
|
||||||
|
m1)
|
||||||
|
self.__datedetector.sortTemplate()
|
||||||
|
# confuse it with year being at the end
|
||||||
|
for i in xrange(10):
|
||||||
|
self.assertEqual(
|
||||||
|
self.__datedetector.getTime('11/10/2012 02:37:17 [error] 18434#0')[:6],
|
||||||
|
m1)
|
||||||
|
self.__datedetector.sortTemplate()
|
||||||
|
# and now back to the original
|
||||||
|
self.assertEqual(
|
||||||
|
self.__datedetector.getTime('2012/10/11 02:37:17 [error] 18434#0')[:6],
|
||||||
|
m1)
|
||||||
|
|
||||||
|
|
||||||
# def testDefaultTempate(self):
|
# def testDefaultTempate(self):
|
||||||
# self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
# self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
||||||
# self.__datedetector.setDefaultPattern("%b %d %H:%M:%S")
|
# self.__datedetector.setDefaultPattern("%b %d %H:%M:%S")
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
# per https://github.com/fail2ban/fail2ban/issues/125
|
||||||
|
# and https://github.com/fail2ban/fail2ban/issues/126
|
||||||
|
Feb 21 09:21:54 xxx postfix/smtpd[14398]: NOQUEUE: reject: RCPT from example.com[192.0.43.10]: 450 4.7.1 : Helo command rejected: Host not found; from=<> to=<> proto=ESMTP helo=
|
|
@ -0,0 +1,17 @@
|
||||||
|
# yoh: Kept original apache log lines as well, just in case they might come useful
|
||||||
|
# for (testing) multiline regular expressions which would further constraint
|
||||||
|
# SOGo log lines
|
||||||
|
Mar 24 08:58:32 sogod [26818]: <0x0xb8537990[LDAPSource]> <NSException: 0xb87c3008> NAME:LDAPException REASON:operation bind failed: Invalid credentials (0x31) INFO:{login = "uid=hack0r,ou=users,dc=mail,dc=example,dc=org"; }
|
||||||
|
Mar 24 08:58:32 sogod [26818]: SOGoRootPage Login from '173.194.44.31' for user 'hack0r' might not have worked - password policy: 65535 grace: -1 expire: -1 bound: 0
|
||||||
|
173.194.44.31 - - [24/Mar/2013:08:58:32 GMT] "POST /SOGo/connect HTTP/1.1" 403 34/38 0.311 - - 2M
|
||||||
|
Mar 24 08:58:40 sogod [26818]: <0x0xb8537990[LDAPSource]> <NSException: 0xb87bb8d8> NAME:LDAPException REASON:operation bind failed: Invalid credentials (0x31) INFO:{login = "uid=kiddy,ou=users,dc=mail,dc=example,dc=org"; }
|
||||||
|
Mar 24 08:58:40 sogod [26818]: SOGoRootPage Login from '173.194.44.31' for user 'kiddy' might not have worked - password policy: 65535 grace: -1 expire: -1 bound: 0
|
||||||
|
173.194.44.31 - - [24/Mar/2013:08:58:40 GMT] "POST /SOGo/connect HTTP/1.1" 403 34/37 0.007 - - 32K
|
||||||
|
Mar 24 08:58:50 sogod [26818]: <0x0xb8537990[LDAPSource]> <NSException: 0xb87c27f8> NAME:LDAPException REASON:operation bind failed: Invalid credentials (0x31) INFO:{login = "uid=plsBanMe,ou=users,dc=mail,dc=example,dc=org"; }
|
||||||
|
Mar 24 08:58:50 sogod [26818]: SOGoRootPage Login from '173.194.44.31' for user 'plsBanMe' might not have worked - password policy: 65535 grace: -1 expire: -1 bound: 0
|
||||||
|
173.194.44.31 - - [24/Mar/2013:08:58:50 GMT] "POST /SOGo/connect HTTP/1.1" 403 34/40 0.008 - - 0
|
||||||
|
Mar 24 08:58:59 sogod [26818]: <0x0xb8537990[LDAPSource]> <NSException: 0xb87be830> NAME:LDAPException REASON:operation bind failed: Invalid credentials (0x31) INFO:{login = "uid=root,ou=users,dc=mail,dc=example,dc=org"; }
|
||||||
|
Mar 24 08:58:59 sogod [26818]: SOGoRootPage Login from '173.194.44.31' for user 'root' might not have worked - password policy: 65535 grace: -1 expire: -1 bound: 0
|
||||||
|
173.194.44.31 - - [24/Mar/2013:08:58:59 GMT] "POST /SOGo/connect HTTP/1.1" 403 34/36 0.007 - - 0
|
||||||
|
Mar 24 08:59:04 sogod [26818]: <0x0xb8537990[LDAPSource]> <NSException: 0xb87bc088> NAME:LDAPException REASON:operation bind failed: Invalid credentials (0x31) INFO:{login = "uid=admin,ou=users,dc=mail,dc=example,dc=org"; }
|
||||||
|
Mar 24 08:59:04 sogod [26818]: SOGoRootPage Login from '173.194.44.31' for user 'admin' might not have worked - password policy: 65535 grace: -1 expire: -1 bound: 0
|
|
@ -38,11 +38,17 @@ from server.failmanager import FailManagerEmpty
|
||||||
# Useful helpers
|
# Useful helpers
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# yoh: per Steven Hiscocks's insight while troubleshooting
|
||||||
|
# https://github.com/fail2ban/fail2ban/issues/103#issuecomment-15542836
|
||||||
|
# adding a sufficiently large buffer might help to guarantee that
|
||||||
|
# writes happen atomically.
|
||||||
|
# Overload also for python3 to use utf-8 encoding by default
|
||||||
if sys.version_info >= (3,):
|
if sys.version_info >= (3,):
|
||||||
def open_(filename, mode):
|
def open_(filename, mode):
|
||||||
return open(filename, mode, encoding='utf-8', errors='ignore')
|
return open(filename, mode, 50000, encoding='utf-8', errors='ignore')
|
||||||
else:
|
else:
|
||||||
open_ = open
|
def open_(filename, mode):
|
||||||
|
return open(filename, mode, 50000)
|
||||||
|
|
||||||
def _killfile(f, name):
|
def _killfile(f, name):
|
||||||
try:
|
try:
|
||||||
|
@ -54,6 +60,11 @@ def _killfile(f, name):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# there might as well be the .bak file
|
||||||
|
if os.path.exists(name + '.bak'):
|
||||||
|
_killfile(None, name + '.bak')
|
||||||
|
|
||||||
|
|
||||||
def _sleep_4_poll():
|
def _sleep_4_poll():
|
||||||
"""PollFilter relies on file timestamps - so we might need to
|
"""PollFilter relies on file timestamps - so we might need to
|
||||||
sleep to guarantee that they differ
|
sleep to guarantee that they differ
|
||||||
|
@ -105,26 +116,29 @@ def _copy_lines_between_files(fin, fout, n=None, skip=0, mode='a', terminal_line
|
||||||
|
|
||||||
Returns open fout
|
Returns open fout
|
||||||
"""
|
"""
|
||||||
if sys.version_info[:2] <= (2,4):
|
if sys.version_info[:2] <= (2,4): # pragma: no cover
|
||||||
# on old Python st_mtime is int, so we should give at least 1 sec so
|
# on old Python st_mtime is int, so we should give at least 1 sec so
|
||||||
# polling filter could detect the change
|
# polling filter could detect the change
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
if isinstance(fin, str):
|
if isinstance(fin, str): # pragma: no branch - only used with str in test cases
|
||||||
fin = open_(fin, 'r')
|
fin = open_(fin, 'r')
|
||||||
if isinstance(fout, str):
|
|
||||||
fout = open_(fout, mode)
|
|
||||||
# Skip
|
# Skip
|
||||||
for i in xrange(skip):
|
for i in xrange(skip):
|
||||||
_ = fin.readline()
|
_ = fin.readline()
|
||||||
# Read/Write
|
# Read
|
||||||
i = 0
|
i = 0
|
||||||
|
lines = []
|
||||||
while n is None or i < n:
|
while n is None or i < n:
|
||||||
l = fin.readline()
|
l = fin.readline()
|
||||||
if terminal_line is not None and l == terminal_line:
|
if terminal_line is not None and l == terminal_line:
|
||||||
break
|
break
|
||||||
fout.write(l)
|
lines.append(l)
|
||||||
fout.flush()
|
|
||||||
i += 1
|
i += 1
|
||||||
|
# Write: all at once and flush
|
||||||
|
if isinstance(fout, str):
|
||||||
|
fout = open_(fout, mode)
|
||||||
|
fout.write('\n'.join(lines))
|
||||||
|
fout.flush()
|
||||||
# to give other threads possibly some time to crunch
|
# to give other threads possibly some time to crunch
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
return fout
|
return fout
|
||||||
|
@ -330,11 +344,17 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
"""Generator of TestCase's for different filters/backends
|
"""Generator of TestCase's for different filters/backends
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# add Filter_'s name so we could easily identify bad cows
|
||||||
|
testclass_name = tempfile.mktemp(
|
||||||
|
'fail2ban', 'monitorfailures_%s' % (Filter_.__name__,))
|
||||||
|
|
||||||
class MonitorFailures(unittest.TestCase):
|
class MonitorFailures(unittest.TestCase):
|
||||||
|
count = 0
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
self.filter = self.name = 'NA'
|
self.filter = self.name = 'NA'
|
||||||
_, self.name = tempfile.mkstemp('fail2ban', 'monitorfailures')
|
self.name = '%s-%d' % (testclass_name, self.count)
|
||||||
|
MonitorFailures.count += 1 # so we have unique filenames across tests
|
||||||
self.file = open_(self.name, 'a')
|
self.file = open_(self.name, 'a')
|
||||||
self.jail = DummyJail()
|
self.jail = DummyJail()
|
||||||
self.filter = Filter_(self.jail)
|
self.filter = Filter_(self.jail)
|
||||||
|
@ -357,12 +377,9 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
self.filter.join() # wait for the thread to terminate
|
self.filter.join() # wait for the thread to terminate
|
||||||
#print "D: KILLING THE FILE"
|
#print "D: KILLING THE FILE"
|
||||||
_killfile(self.file, self.name)
|
_killfile(self.file, self.name)
|
||||||
|
#time.sleep(0.2) # Give FS time to ack the removal
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "MonitorFailures%s(%s)" \
|
|
||||||
% (Filter_, hasattr(self, 'name') and self.name or 'tempfile')
|
|
||||||
|
|
||||||
def isFilled(self, delay=2.):
|
def isFilled(self, delay=2.):
|
||||||
"""Wait up to `delay` sec to assure that it was modified or not
|
"""Wait up to `delay` sec to assure that it was modified or not
|
||||||
"""
|
"""
|
||||||
|
@ -385,7 +402,7 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
return not self.isFilled(delay)
|
return not self.isFilled(delay)
|
||||||
|
|
||||||
def assert_correct_last_attempt(self, failures, count=None):
|
def assert_correct_last_attempt(self, failures, count=None):
|
||||||
self.assertTrue(self.isFilled(10)) # give Filter a chance to react
|
self.assertTrue(self.isFilled(20)) # give Filter a chance to react
|
||||||
_assert_correct_last_attempt(self, self.jail, failures, count=count)
|
_assert_correct_last_attempt(self, self.jail, failures, count=count)
|
||||||
|
|
||||||
|
|
||||||
|
@ -437,9 +454,10 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
# if we move file into a new location while it has been open already
|
# if we move file into a new location while it has been open already
|
||||||
self.file = _copy_lines_between_files(GetFailures.FILENAME_01, self.name,
|
self.file = _copy_lines_between_files(GetFailures.FILENAME_01, self.name,
|
||||||
n=14, mode='w')
|
n=14, mode='w')
|
||||||
self.assertTrue(self.isEmpty(2))
|
# Poll might need more time
|
||||||
|
self.assertTrue(self.isEmpty(4 + int(isinstance(self.filter, FilterPoll))*2))
|
||||||
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
||||||
self.assertEqual(self.filter.failManager.getFailTotal(), 2) # Fails with Poll from time to time
|
self.assertEqual(self.filter.failManager.getFailTotal(), 2)
|
||||||
|
|
||||||
# move aside, but leaving the handle still open...
|
# move aside, but leaving the handle still open...
|
||||||
os.rename(self.name, self.name + '.bak')
|
os.rename(self.name, self.name + '.bak')
|
||||||
|
@ -494,7 +512,8 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
# yoh: not sure why count here is not 9... TODO
|
# yoh: not sure why count here is not 9... TODO
|
||||||
self.assert_correct_last_attempt(GetFailures.FAILURES_01)#, count=9)
|
self.assert_correct_last_attempt(GetFailures.FAILURES_01)#, count=9)
|
||||||
|
|
||||||
|
MonitorFailures.__name__ = "MonitorFailures<%s>(%s)" \
|
||||||
|
% (Filter_.__name__, testclass_name) # 'tempfile')
|
||||||
return MonitorFailures
|
return MonitorFailures
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import unittest, socket, time, tempfile, os, locale
|
import unittest, socket, time, tempfile, os, locale
|
||||||
from server.server import Server
|
from server.server import Server
|
||||||
|
from common.exceptions import UnknownJailException
|
||||||
|
|
||||||
class StartStop(unittest.TestCase):
|
class StartStop(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -49,27 +50,29 @@ class StartStop(unittest.TestCase):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.__server.stopJail(name)
|
self.__server.stopJail(name)
|
||||||
|
|
||||||
|
class TestServer(Server):
|
||||||
|
def setLogLevel(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
def setLogTarget(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
class Transmitter(unittest.TestCase):
|
class TransmitterBase(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
self.__server = Server()
|
self.transm = self.server._Server__transm
|
||||||
self.__transm = self.__server._Server__transm
|
|
||||||
self.__server.setLogTarget("/dev/null")
|
|
||||||
self.__server.setLogLevel(0)
|
|
||||||
sock_fd, sock_name = tempfile.mkstemp('fail2ban.sock', 'transmitter')
|
sock_fd, sock_name = tempfile.mkstemp('fail2ban.sock', 'transmitter')
|
||||||
os.close(sock_fd)
|
os.close(sock_fd)
|
||||||
pidfile_fd, pidfile_name = tempfile.mkstemp(
|
pidfile_fd, pidfile_name = tempfile.mkstemp(
|
||||||
'fail2ban.pid', 'transmitter')
|
'fail2ban.pid', 'transmitter')
|
||||||
os.close(pidfile_fd)
|
os.close(pidfile_fd)
|
||||||
self.__server.start(sock_name, pidfile_name, force=False)
|
self.server.start(sock_name, pidfile_name, force=False)
|
||||||
self.jailName = "TestJail1"
|
self.jailName = "TestJail1"
|
||||||
self.__server.addJail(self.jailName, "auto")
|
self.server.addJail(self.jailName, "auto")
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Call after every test case."""
|
"""Call after every test case."""
|
||||||
self.__server.quit()
|
self.server.quit()
|
||||||
|
|
||||||
def setGetTest(self, cmd, inValue, outValue=None, jail=None):
|
def setGetTest(self, cmd, inValue, outValue=None, jail=None):
|
||||||
setCmd = ["set", cmd, inValue]
|
setCmd = ["set", cmd, inValue]
|
||||||
|
@ -80,8 +83,8 @@ class Transmitter(unittest.TestCase):
|
||||||
if outValue is None:
|
if outValue is None:
|
||||||
outValue = inValue
|
outValue = inValue
|
||||||
|
|
||||||
self.assertEqual(self.__transm.proceed(setCmd), (0, outValue))
|
self.assertEqual(self.transm.proceed(setCmd), (0, outValue))
|
||||||
self.assertEqual(self.__transm.proceed(getCmd), (0, outValue))
|
self.assertEqual(self.transm.proceed(getCmd), (0, outValue))
|
||||||
|
|
||||||
def setGetTestNOK(self, cmd, inValue, jail=None):
|
def setGetTestNOK(self, cmd, inValue, jail=None):
|
||||||
setCmd = ["set", cmd, inValue]
|
setCmd = ["set", cmd, inValue]
|
||||||
|
@ -91,30 +94,30 @@ class Transmitter(unittest.TestCase):
|
||||||
getCmd.insert(1, jail)
|
getCmd.insert(1, jail)
|
||||||
|
|
||||||
# Get initial value before trying invalid value
|
# Get initial value before trying invalid value
|
||||||
initValue = self.__transm.proceed(getCmd)[1]
|
initValue = self.transm.proceed(getCmd)[1]
|
||||||
self.assertEqual(self.__transm.proceed(setCmd)[0], 1)
|
self.assertEqual(self.transm.proceed(setCmd)[0], 1)
|
||||||
# Check after failed set that value is same as previous
|
# Check after failed set that value is same as previous
|
||||||
self.assertEqual(self.__transm.proceed(getCmd), (0, initValue))
|
self.assertEqual(self.transm.proceed(getCmd), (0, initValue))
|
||||||
|
|
||||||
def jailAddDelTest(self, cmd, values, jail):
|
def jailAddDelTest(self, cmd, values, jail):
|
||||||
cmdAdd = "add" + cmd
|
cmdAdd = "add" + cmd
|
||||||
cmdDel = "del" + cmd
|
cmdDel = "del" + cmd
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", jail, cmd]), (0, []))
|
self.transm.proceed(["get", jail, cmd]), (0, []))
|
||||||
for n, value in enumerate(values):
|
for n, value in enumerate(values):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", jail, cmdAdd, value]),
|
self.transm.proceed(["set", jail, cmdAdd, value]),
|
||||||
(0, values[:n+1]))
|
(0, values[:n+1]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", jail, cmd]),
|
self.transm.proceed(["get", jail, cmd]),
|
||||||
(0, values[:n+1]))
|
(0, values[:n+1]))
|
||||||
for n, value in enumerate(values):
|
for n, value in enumerate(values):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", jail, cmdDel, value]),
|
self.transm.proceed(["set", jail, cmdDel, value]),
|
||||||
(0, values[n+1:]))
|
(0, values[n+1:]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", jail, cmd]),
|
self.transm.proceed(["get", jail, cmd]),
|
||||||
(0, values[n+1:]))
|
(0, values[n+1:]))
|
||||||
|
|
||||||
def jailAddDelRegexTest(self, cmd, inValues, outValues, jail):
|
def jailAddDelRegexTest(self, cmd, inValues, outValues, jail):
|
||||||
|
@ -125,87 +128,95 @@ class Transmitter(unittest.TestCase):
|
||||||
outValues = inValues
|
outValues = inValues
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", jail, cmd]), (0, []))
|
self.transm.proceed(["get", jail, cmd]), (0, []))
|
||||||
for n, value in enumerate(inValues):
|
for n, value in enumerate(inValues):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", jail, cmdAdd, value]),
|
self.transm.proceed(["set", jail, cmdAdd, value]),
|
||||||
(0, outValues[:n+1]))
|
(0, outValues[:n+1]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", jail, cmd]),
|
self.transm.proceed(["get", jail, cmd]),
|
||||||
(0, outValues[:n+1]))
|
(0, outValues[:n+1]))
|
||||||
for n, value in enumerate(inValues):
|
for n, value in enumerate(inValues):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", jail, cmdDel, 0]), # First item
|
self.transm.proceed(["set", jail, cmdDel, 0]), # First item
|
||||||
(0, outValues[n+1:]))
|
(0, outValues[n+1:]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", jail, cmd]),
|
self.transm.proceed(["get", jail, cmd]),
|
||||||
(0, outValues[n+1:]))
|
(0, outValues[n+1:]))
|
||||||
|
|
||||||
|
class Transmitter(TransmitterBase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.server = TestServer()
|
||||||
|
super(Transmitter, self).setUp()
|
||||||
|
|
||||||
|
def testStopServer(self):
|
||||||
|
self.assertEqual(self.transm.proceed(["stop"]), (0, None))
|
||||||
|
|
||||||
def testPing(self):
|
def testPing(self):
|
||||||
self.assertEqual(self.__transm.proceed(["ping"]), (0, "pong"))
|
self.assertEqual(self.transm.proceed(["ping"]), (0, "pong"))
|
||||||
|
|
||||||
def testSleep(self):
|
def testSleep(self):
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
self.assertEqual(self.__transm.proceed(["sleep", "1"]), (0, None))
|
self.assertEqual(self.transm.proceed(["sleep", "1"]), (0, None))
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
# Approx 1 second delay
|
# Approx 1 second delay
|
||||||
self.assertAlmostEqual(t1 - t0, 1, places=2)
|
self.assertAlmostEqual(t1 - t0, 1, places=2)
|
||||||
|
|
||||||
def testLogTarget(self):
|
|
||||||
logTargets = []
|
|
||||||
for _ in xrange(3):
|
|
||||||
tmpFile = tempfile.mkstemp("fail2ban", "transmitter")
|
|
||||||
logTargets.append(tmpFile[1])
|
|
||||||
os.close(tmpFile[0])
|
|
||||||
for logTarget in logTargets:
|
|
||||||
self.setGetTest("logtarget", logTarget)
|
|
||||||
|
|
||||||
# If path is invalid, do not change logtarget
|
|
||||||
value = "/this/path/should/not/exist"
|
|
||||||
self.assertEqual(
|
|
||||||
self.__transm.proceed(["set", "logtarget", value]),
|
|
||||||
(0, logTarget)) #NOTE: Shouldn't this return 1
|
|
||||||
self.assertEqual(
|
|
||||||
self.__transm.proceed(["get", "logtarget"]), (0, logTargets[-1]))
|
|
||||||
|
|
||||||
self.__transm.proceed(["set", "/dev/null"])
|
|
||||||
for logTarget in logTargets:
|
|
||||||
os.remove(logTarget)
|
|
||||||
|
|
||||||
def testLogLevel(self):
|
|
||||||
self.setGetTest("loglevel", "4", 4)
|
|
||||||
self.setGetTest("loglevel", "2", 2)
|
|
||||||
self.setGetTest("loglevel", "-1", -1)
|
|
||||||
self.setGetTestNOK("loglevel", "Bird")
|
|
||||||
|
|
||||||
def testAddJail(self):
|
def testAddJail(self):
|
||||||
jail2 = "TestJail2"
|
jail2 = "TestJail2"
|
||||||
jail3 = "TestJail3"
|
jail3 = "TestJail3"
|
||||||
jail4 = "TestJail4"
|
jail4 = "TestJail4"
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["add", jail2, "polling"]), (0, jail2))
|
self.transm.proceed(["add", jail2, "polling"]), (0, jail2))
|
||||||
self.assertEqual(self.__transm.proceed(["add", jail3]), (0, jail3))
|
self.assertEqual(self.transm.proceed(["add", jail3]), (0, jail3))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["add", jail4, "invalid backend"])[0], 1)
|
self.transm.proceed(["add", jail4, "invalid backend"])[0], 1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["add", jail4, "auto"]), (0, jail4))
|
self.transm.proceed(["add", jail4, "auto"]), (0, jail4))
|
||||||
# Duplicate Jail
|
# Duplicate Jail
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["add", self.jailName, "polling"])[0], 1)
|
self.transm.proceed(["add", self.jailName, "polling"])[0], 1)
|
||||||
# All name is reserved
|
# All name is reserved
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["add", "all", "polling"])[0], 1)
|
self.transm.proceed(["add", "all", "polling"])[0], 1)
|
||||||
|
|
||||||
|
def testStartStopJail(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["start", self.jailName]), (0, None))
|
||||||
|
time.sleep(1)
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["stop", self.jailName]), (0, None))
|
||||||
|
self.assertRaises(
|
||||||
|
UnknownJailException, self.server.isAlive, self.jailName)
|
||||||
|
|
||||||
|
def testStartStopAllJail(self):
|
||||||
|
self.server.addJail("TestJail2", "auto")
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["start", self.jailName]), (0, None))
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["start", "TestJail2"]), (0, None))
|
||||||
|
# yoh: workaround for gh-146. I still think that there is some
|
||||||
|
# race condition and missing locking somewhere, but for now
|
||||||
|
# giving it a small delay reliably helps to proceed with tests
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.assertEqual(self.transm.proceed(["stop", "all"]), (0, None))
|
||||||
|
time.sleep(1)
|
||||||
|
self.assertRaises(
|
||||||
|
UnknownJailException, self.server.isAlive, self.jailName)
|
||||||
|
self.assertRaises(
|
||||||
|
UnknownJailException, self.server.isAlive, "TestJail2")
|
||||||
|
|
||||||
def testJailIdle(self):
|
def testJailIdle(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "idle", "on"]),
|
self.transm.proceed(["set", self.jailName, "idle", "on"]),
|
||||||
(0, True))
|
(0, True))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "idle", "off"]),
|
self.transm.proceed(["set", self.jailName, "idle", "off"]),
|
||||||
(0, False))
|
(0, False))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "idle", "CAT"])[0],
|
self.transm.proceed(["set", self.jailName, "idle", "CAT"])[0],
|
||||||
0) #NOTE: Should this return 1
|
1)
|
||||||
|
|
||||||
def testJailFindTime(self):
|
def testJailFindTime(self):
|
||||||
self.setGetTest("findtime", "120", 120, jail=self.jailName)
|
self.setGetTest("findtime", "120", 120, jail=self.jailName)
|
||||||
|
@ -227,30 +238,29 @@ class Transmitter(unittest.TestCase):
|
||||||
# Safe default should be "no"
|
# Safe default should be "no"
|
||||||
value = "Fish"
|
value = "Fish"
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "usedns", value]),
|
self.transm.proceed(["set", self.jailName, "usedns", value]),
|
||||||
(0, "no"))
|
(0, "no"))
|
||||||
|
|
||||||
def testJailBanIP(self):
|
def testJailBanIP(self):
|
||||||
self.__server.startJail(self.jailName) # Jail must be started
|
self.server.startJail(self.jailName) # Jail must be started
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "banip", "127.0.0.1"]),
|
self.transm.proceed(["set", self.jailName, "banip", "127.0.0.1"]),
|
||||||
(0, "127.0.0.1"))
|
(0, "127.0.0.1"))
|
||||||
time.sleep(1) # Give chance to ban
|
time.sleep(1) # Give chance to ban
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "banip", "Badger"]),
|
self.transm.proceed(["set", self.jailName, "banip", "Badger"]),
|
||||||
(0, "Badger")) #NOTE: Is IP address validated? Is DNS Lookup done?
|
(0, "Badger")) #NOTE: Is IP address validated? Is DNS Lookup done?
|
||||||
time.sleep(1) # Give chance to ban
|
time.sleep(1) # Give chance to ban
|
||||||
# Unban IP
|
# Unban IP
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, "unbanip", "127.0.0.1"]),
|
["set", self.jailName, "unbanip", "127.0.0.1"]),
|
||||||
(0, "127.0.0.1"))
|
(0, "127.0.0.1"))
|
||||||
# Unban IP which isn't banned
|
# Unban IP which isn't banned
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, "unbanip", "192.168.1.1"]),
|
["set", self.jailName, "unbanip", "192.168.1.1"])[0],1)
|
||||||
(0, "None")) #NOTE: Should this return 1?
|
|
||||||
|
|
||||||
def testJailMaxRetry(self):
|
def testJailMaxRetry(self):
|
||||||
self.setGetTest("maxretry", "5", 5, jail=self.jailName)
|
self.setGetTest("maxretry", "5", 5, jail=self.jailName)
|
||||||
|
@ -278,22 +288,22 @@ class Transmitter(unittest.TestCase):
|
||||||
# Try duplicates
|
# Try duplicates
|
||||||
value = "testcases/files/testcase04.log"
|
value = "testcases/files/testcase04.log"
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "addlogpath", value]),
|
self.transm.proceed(["set", self.jailName, "addlogpath", value]),
|
||||||
(0, [value]))
|
(0, [value]))
|
||||||
# Will silently ignore duplicate
|
# Will silently ignore duplicate
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "addlogpath", value]),
|
self.transm.proceed(["set", self.jailName, "addlogpath", value]),
|
||||||
(0, [value]))
|
(0, [value]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", self.jailName, "logpath"]),
|
self.transm.proceed(["get", self.jailName, "logpath"]),
|
||||||
(0, [value]))
|
(0, [value]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "dellogpath", value]),
|
self.transm.proceed(["set", self.jailName, "dellogpath", value]),
|
||||||
(0, []))
|
(0, []))
|
||||||
|
|
||||||
# Invalid file
|
# Invalid file
|
||||||
value = "this_file_shouldn't_exist"
|
value = "this_file_shouldn't_exist"
|
||||||
result = self.__transm.proceed(
|
result = self.transm.proceed(
|
||||||
["set", self.jailName, "addlogpath", value])
|
["set", self.jailName, "addlogpath", value])
|
||||||
self.assertTrue(isinstance(result[1], IOError))
|
self.assertTrue(isinstance(result[1], IOError))
|
||||||
|
|
||||||
|
@ -311,18 +321,18 @@ class Transmitter(unittest.TestCase):
|
||||||
# Try duplicates
|
# Try duplicates
|
||||||
value = "127.0.0.1"
|
value = "127.0.0.1"
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "addignoreip", value]),
|
self.transm.proceed(["set", self.jailName, "addignoreip", value]),
|
||||||
(0, [value]))
|
(0, [value]))
|
||||||
# Will allow duplicate
|
# Will allow duplicate
|
||||||
#NOTE: Should duplicates be allowed, or silent ignore like logpath?
|
#NOTE: Should duplicates be allowed, or silent ignore like logpath?
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "addignoreip", value]),
|
self.transm.proceed(["set", self.jailName, "addignoreip", value]),
|
||||||
(0, [value, value]))
|
(0, [value, value]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", self.jailName, "ignoreip"]),
|
self.transm.proceed(["get", self.jailName, "ignoreip"]),
|
||||||
(0, [value, value]))
|
(0, [value, value]))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "delignoreip", value]),
|
self.transm.proceed(["set", self.jailName, "delignoreip", value]),
|
||||||
(0, [value]))
|
(0, [value]))
|
||||||
|
|
||||||
def testJailRegex(self):
|
def testJailRegex(self):
|
||||||
|
@ -341,11 +351,11 @@ class Transmitter(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, "addfailregex", "No host regex"]),
|
["set", self.jailName, "addfailregex", "No host regex"])[0],
|
||||||
(0, [])) #NOTE: Shouldn't this return 1?
|
1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, "addfailregex", 654])[0],
|
["set", self.jailName, "addfailregex", 654])[0],
|
||||||
1)
|
1)
|
||||||
|
|
||||||
|
@ -365,21 +375,25 @@ class Transmitter(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
|
["set", self.jailName, "addignoreregex", "Invalid [regex"])[0],
|
||||||
|
1)
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(
|
||||||
["set", self.jailName, "addignoreregex", 50])[0],
|
["set", self.jailName, "addignoreregex", 50])[0],
|
||||||
1)
|
1)
|
||||||
|
|
||||||
def testStatus(self):
|
def testStatus(self):
|
||||||
jails = [self.jailName]
|
jails = [self.jailName]
|
||||||
self.assertEqual(self.__transm.proceed(["status"]),
|
self.assertEqual(self.transm.proceed(["status"]),
|
||||||
(0, [('Number of jail', len(jails)), ('Jail list', ", ".join(jails))]))
|
(0, [('Number of jail', len(jails)), ('Jail list', ", ".join(jails))]))
|
||||||
self.__server.addJail("TestJail2", "auto")
|
self.server.addJail("TestJail2", "auto")
|
||||||
jails.append("TestJail2")
|
jails.append("TestJail2")
|
||||||
self.assertEqual(self.__transm.proceed(["status"]),
|
self.assertEqual(self.transm.proceed(["status"]),
|
||||||
(0, [('Number of jail', len(jails)), ('Jail list', ", ".join(jails))]))
|
(0, [('Number of jail', len(jails)), ('Jail list', ", ".join(jails))]))
|
||||||
|
|
||||||
def testJailStatus(self):
|
def testJailStatus(self):
|
||||||
self.assertEqual(self.__transm.proceed(["status", self.jailName]),
|
self.assertEqual(self.transm.proceed(["status", self.jailName]),
|
||||||
(0,
|
(0,
|
||||||
[
|
[
|
||||||
('filter', [
|
('filter', [
|
||||||
|
@ -414,37 +428,90 @@ class Transmitter(unittest.TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "addaction", action]),
|
self.transm.proceed(["set", self.jailName, "addaction", action]),
|
||||||
|
(0, action))
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["get", self.jailName, "addaction", action]),
|
||||||
(0, action))
|
(0, action))
|
||||||
for cmd, value in zip(cmdList, cmdValueList):
|
for cmd, value in zip(cmdList, cmdValueList):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, cmd, action, value]),
|
["set", self.jailName, cmd, action, value]),
|
||||||
(0, value))
|
(0, value))
|
||||||
for cmd, value in zip(cmdList, cmdValueList):
|
for cmd, value in zip(cmdList, cmdValueList):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["get", self.jailName, cmd, action]),
|
self.transm.proceed(["get", self.jailName, cmd, action]),
|
||||||
(0, value))
|
(0, value))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, "setcinfo", action, "KEY", "VALUE"]),
|
["set", self.jailName, "setcinfo", action, "KEY", "VALUE"]),
|
||||||
(0, "VALUE"))
|
(0, "VALUE"))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["get", self.jailName, "cinfo", action, "KEY"]),
|
["get", self.jailName, "cinfo", action, "KEY"]),
|
||||||
(0, "VALUE"))
|
(0, "VALUE"))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["get", self.jailName, "cinfo", action, "InvalidKey"])[0],
|
["get", self.jailName, "cinfo", action, "InvalidKey"])[0],
|
||||||
1)
|
1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, "delcinfo", action, "KEY"]),
|
["set", self.jailName, "delcinfo", action, "KEY"]),
|
||||||
(0, None))
|
(0, None))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(["set", self.jailName, "delaction", action]),
|
self.transm.proceed(["set", self.jailName, "delaction", action]),
|
||||||
(0, None))
|
(0, None))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.__transm.proceed(
|
self.transm.proceed(
|
||||||
["set", self.jailName, "delaction", "Doesn't exist"]),
|
["set", self.jailName, "delaction", "Doesn't exist"])[0],1)
|
||||||
(0, None)) #NOTE: Should this return 1?
|
|
||||||
|
def testNOK(self):
|
||||||
|
self.assertEqual(self.transm.proceed(["INVALID", "COMMAND"])[0],1)
|
||||||
|
|
||||||
|
def testSetNOK(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["set", "INVALID", "COMMAND"])[0],1)
|
||||||
|
|
||||||
|
def testGetNOK(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["get", "INVALID", "COMMAND"])[0],1)
|
||||||
|
|
||||||
|
def testStatusNOK(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self.transm.proceed(["status", "INVALID", "COMMAND"])[0],1)
|
||||||
|
|
||||||
|
class TransmitterLogging(TransmitterBase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.server = Server()
|
||||||
|
self.server.setLogTarget("/dev/null")
|
||||||
|
self.server.setLogLevel(0)
|
||||||
|
super(TransmitterLogging, self).setUp()
|
||||||
|
|
||||||
|
def testLogTarget(self):
|
||||||
|
logTargets = []
|
||||||
|
for _ in xrange(3):
|
||||||
|
tmpFile = tempfile.mkstemp("fail2ban", "transmitter")
|
||||||
|
logTargets.append(tmpFile[1])
|
||||||
|
os.close(tmpFile[0])
|
||||||
|
for logTarget in logTargets:
|
||||||
|
self.setGetTest("logtarget", logTarget)
|
||||||
|
|
||||||
|
# If path is invalid, do not change logtarget
|
||||||
|
value = "/this/path/should/not/exist"
|
||||||
|
self.setGetTestNOK("logtarget", value)
|
||||||
|
|
||||||
|
self.transm.proceed(["set", "/dev/null"])
|
||||||
|
for logTarget in logTargets:
|
||||||
|
os.remove(logTarget)
|
||||||
|
|
||||||
|
self.setGetTest("logtarget", "STDOUT")
|
||||||
|
self.setGetTest("logtarget", "STDERR")
|
||||||
|
self.setGetTest("logtarget", "SYSLOG")
|
||||||
|
|
||||||
|
def testLogLevel(self):
|
||||||
|
self.setGetTest("loglevel", "4", 4)
|
||||||
|
self.setGetTest("loglevel", "2", 2)
|
||||||
|
self.setGetTest("loglevel", "-1", -1)
|
||||||
|
self.setGetTest("loglevel", "0", 0)
|
||||||
|
self.setGetTestNOK("loglevel", "Bird")
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
|
||||||
|
# vi: set ft=python sts=4 ts=4 sw=4 noet :
|
||||||
|
|
||||||
|
# This file is part of Fail2Ban.
|
||||||
|
#
|
||||||
|
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Fail2Ban is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Fail2Ban; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
# Author: Steven Hiscocks
|
||||||
|
#
|
||||||
|
# $Revision$
|
||||||
|
|
||||||
|
__author__ = "Steven Hiscocks"
|
||||||
|
__version__ = "$Revision$"
|
||||||
|
__date__ = "$Date$"
|
||||||
|
__copyright__ = "Copyright (c) 2013 Steven Hiscocks"
|
||||||
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
import unittest, time, tempfile, os, threading
|
||||||
|
from server.asyncserver import AsyncServer, AsyncServerException
|
||||||
|
from client.csocket import CSocket
|
||||||
|
|
||||||
|
class Socket(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Call before every test case."""
|
||||||
|
self.server = AsyncServer(self)
|
||||||
|
sock_fd, sock_name = tempfile.mkstemp('fail2ban.sock', 'socket')
|
||||||
|
os.close(sock_fd)
|
||||||
|
os.remove(sock_name)
|
||||||
|
self.sock_name = sock_name
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""Call after every test case."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def proceed(message):
|
||||||
|
"""Test transmitter proceed method which just returns first arg"""
|
||||||
|
return message
|
||||||
|
|
||||||
|
def testSocket(self):
|
||||||
|
serverThread = threading.Thread(
|
||||||
|
target=self.server.start, args=(self.sock_name, False))
|
||||||
|
serverThread.daemon = True
|
||||||
|
serverThread.start()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
client = CSocket(self.sock_name)
|
||||||
|
testMessage = ["A", "test", "message"]
|
||||||
|
self.assertEqual(client.send(testMessage), testMessage)
|
||||||
|
|
||||||
|
self.server.stop()
|
||||||
|
serverThread.join(1)
|
||||||
|
self.assertFalse(os.path.exists(self.sock_name))
|
||||||
|
|
||||||
|
def testSocketForce(self):
|
||||||
|
open(self.sock_name, 'w').close() # Create sock file
|
||||||
|
# Try to start without force
|
||||||
|
self.assertRaises(
|
||||||
|
AsyncServerException, self.server.start, self.sock_name, False)
|
||||||
|
|
||||||
|
# Try agin with force set
|
||||||
|
serverThread = threading.Thread(
|
||||||
|
target=self.server.start, args=(self.sock_name, True))
|
||||||
|
serverThread.daemon = True
|
||||||
|
serverThread.start()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
self.server.stop()
|
||||||
|
serverThread.join(1)
|
||||||
|
self.assertFalse(os.path.exists(self.sock_name))
|
|
@ -0,0 +1,101 @@
|
||||||
|
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
|
||||||
|
# vi: set ft=python sts=4 ts=4 sw=4 noet :
|
||||||
|
|
||||||
|
# This file is part of Fail2Ban.
|
||||||
|
#
|
||||||
|
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Fail2Ban is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Fail2Ban; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = "Yaroslav Halchenko"
|
||||||
|
__copyright__ = "Copyright (c) 2013 Yaroslav Halchenko"
|
||||||
|
__license__ = "GPL"
|
||||||
|
|
||||||
|
import logging, os, re, traceback
|
||||||
|
from os.path import basename, dirname
|
||||||
|
|
||||||
|
#
|
||||||
|
# Following "traceback" functions are adopted from PyMVPA distributed
|
||||||
|
# under MIT/Expat and copyright by PyMVPA developers (i.e. me and
|
||||||
|
# Michael). Hereby I re-license derivative work on these pieces under GPL
|
||||||
|
# to stay in line with the main Fail2Ban license
|
||||||
|
#
|
||||||
|
def mbasename(s):
|
||||||
|
"""Custom function to include directory name if filename is too common
|
||||||
|
|
||||||
|
Also strip .py at the end
|
||||||
|
"""
|
||||||
|
base = basename(s)
|
||||||
|
if base.endswith('.py'):
|
||||||
|
base = base[:-3]
|
||||||
|
if base in set(['base', '__init__']):
|
||||||
|
base = basename(dirname(s)) + '.' + base
|
||||||
|
return base
|
||||||
|
|
||||||
|
class TraceBack(object):
|
||||||
|
"""Customized traceback to be included in debug messages
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, compress=False):
|
||||||
|
"""Initialize TrackBack metric
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
compress : bool
|
||||||
|
if True then prefix common with previous invocation gets
|
||||||
|
replaced with ...
|
||||||
|
"""
|
||||||
|
self.__prev = ""
|
||||||
|
self.__compress = compress
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
ftb = traceback.extract_stack(limit=100)[:-2]
|
||||||
|
entries = [[mbasename(x[0]), str(x[1])] for x in ftb]
|
||||||
|
entries = [ e for e in entries
|
||||||
|
if not e[0] in ['unittest', 'logging.__init__' ]]
|
||||||
|
|
||||||
|
# lets make it more consize
|
||||||
|
entries_out = [entries[0]]
|
||||||
|
for entry in entries[1:]:
|
||||||
|
if entry[0] == entries_out[-1][0]:
|
||||||
|
entries_out[-1][1] += ',%s' % entry[1]
|
||||||
|
else:
|
||||||
|
entries_out.append(entry)
|
||||||
|
sftb = '>'.join(['%s:%s' % (mbasename(x[0]),
|
||||||
|
x[1]) for x in entries_out])
|
||||||
|
if self.__compress:
|
||||||
|
# lets remove part which is common with previous invocation
|
||||||
|
prev_next = sftb
|
||||||
|
common_prefix = os.path.commonprefix((self.__prev, sftb))
|
||||||
|
common_prefix2 = re.sub('>[^>]*$', '', common_prefix)
|
||||||
|
|
||||||
|
if common_prefix2 != "":
|
||||||
|
sftb = '...' + sftb[len(common_prefix2):]
|
||||||
|
self.__prev = prev_next
|
||||||
|
|
||||||
|
return sftb
|
||||||
|
|
||||||
|
class FormatterWithTraceBack(logging.Formatter):
|
||||||
|
"""Custom formatter which expands %(tb) and %(tbc) with tracebacks
|
||||||
|
|
||||||
|
TODO: might need locking in case of compressed tracebacks
|
||||||
|
"""
|
||||||
|
def __init__(self, fmt, *args, **kwargs):
|
||||||
|
logging.Formatter.__init__(self, fmt=fmt, *args, **kwargs)
|
||||||
|
compress = '%(tbc)s' in fmt
|
||||||
|
self._tb = TraceBack(compress=compress)
|
||||||
|
|
||||||
|
def format(self, record):
|
||||||
|
record.tbc = record.tb = self._tb()
|
||||||
|
return logging.Formatter.format(self, record)
|
Loading…
Reference in New Issue