mirror of https://github.com/fail2ban/fail2ban
Merge branch '0.9' into py3
Conflicts: .travis.yml MANIFEST bin/fail2ban-regex fail2ban/server/filter.py fail2ban/tests/servertestcase.py setup.pypull/171/head
commit
fa0f8f9e6d
10
.travis.yml
10
.travis.yml
|
@ -7,12 +7,16 @@ python:
|
||||||
- "2.7"
|
- "2.7"
|
||||||
- "3.2"
|
- "3.2"
|
||||||
- "3.3"
|
- "3.3"
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update -qq
|
||||||
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
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then sudo apt-get install -qq python-gamin; fi
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; 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:
|
||||||
- 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
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then export PYTHONPATH="$PYTHONPATH:/usr/share/pyshared:/usr/lib/pyshared/python2.7"; fi
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then coverage run --rcfile=.travis_coveragerc bin/fail2ban-testcases; else python bin/fail2ban-testcases; fi
|
||||||
after_script:
|
after_script:
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.[6-7] ]] || [[ $TRAVIS_PYTHON_VERSION == 3.3 ]]; then coveralls; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then coveralls; fi
|
||||||
|
|
|
@ -4,4 +4,3 @@ branch = True
|
||||||
omit =
|
omit =
|
||||||
/usr/*
|
/usr/*
|
||||||
/home/travis/virtualenv/*
|
/home/travis/virtualenv/*
|
||||||
server/filtergamin.py
|
|
||||||
|
|
14
ChangeLog
14
ChangeLog
|
@ -4,9 +4,21 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Fail2Ban (version 0.8.8) 2012/12/06
|
Fail2Ban (version 0.9.0a) 20??/??/??
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
ver. 0.9.0 (20??/??/??) - alpha
|
||||||
|
----------
|
||||||
|
|
||||||
|
Will carry all fixes in 0.8.x series and new features and enhancements
|
||||||
|
|
||||||
|
- Fixes:
|
||||||
|
- New features:
|
||||||
|
Steven Hiscocks
|
||||||
|
* Multiline failregex. Close gh-54
|
||||||
|
- Enhancements:
|
||||||
|
|
||||||
ver. 0.8.8 (2012/12/06) - stable
|
ver. 0.8.8 (2012/12/06) - stable
|
||||||
----------
|
----------
|
||||||
- Fixes:
|
- Fixes:
|
||||||
|
|
12
DEVELOP
12
DEVELOP
|
@ -24,9 +24,9 @@ Request feature. You can find more details on the Fail2Ban wiki
|
||||||
Testing
|
Testing
|
||||||
=======
|
=======
|
||||||
|
|
||||||
Existing tests can be run by executing `fail2ban-testcases`. This has options
|
Existing tests can be run by executing `bin/fail2ban-testcases`. This has
|
||||||
like --log-level that will probably be useful. `fail2ban-testcases --help` for
|
options like --log-level that will probably be useful.
|
||||||
full options.
|
`bin/fail2ban-testcases --help` forfull options.
|
||||||
|
|
||||||
Test cases should cover all usual cases, all exception cases and all inside
|
Test cases should cover all usual cases, all exception cases and all inside
|
||||||
/ outside boundary conditions.
|
/ outside boundary conditions.
|
||||||
|
@ -39,7 +39,7 @@ Install the package python-coverage to visualise your test coverage. Run the
|
||||||
following (note: on Debian-based systems, the script is called
|
following (note: on Debian-based systems, the script is called
|
||||||
`python-coverage`):
|
`python-coverage`):
|
||||||
|
|
||||||
coverage run fail2ban-testcases
|
coverage run bin/fail2ban-testcases
|
||||||
coverage html
|
coverage html
|
||||||
|
|
||||||
Then look at htmlcov/index.html and see how much coverage your test cases
|
Then look at htmlcov/index.html and see how much coverage your test cases
|
||||||
|
@ -249,7 +249,7 @@ Takes care about executing start/check/ban/unban/stop commands
|
||||||
Releasing
|
Releasing
|
||||||
=========
|
=========
|
||||||
|
|
||||||
# Ensure the version is correct in ./common/version.py
|
# Ensure the version is correct in ./fail2ban/version.py
|
||||||
|
|
||||||
# Add/finalize the corresponding entry in the ChangeLog
|
# Add/finalize the corresponding entry in the ChangeLog
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ Releasing
|
||||||
|
|
||||||
# Run the following and update the wiki with output:
|
# Run the following and update the wiki with output:
|
||||||
|
|
||||||
python -c 'import common.protocol; common.protocol.printWiki()'
|
python -c 'import fail2ban.protocol; fail2ban.protocol.printWiki()'
|
||||||
|
|
||||||
# Email users and development list of release
|
# Email users and development list of release
|
||||||
|
|
||||||
|
|
113
MANIFEST
113
MANIFEST
|
@ -5,65 +5,66 @@ THANKS
|
||||||
COPYING
|
COPYING
|
||||||
DEVELOP
|
DEVELOP
|
||||||
doc/run-rootless.txt
|
doc/run-rootless.txt
|
||||||
fail2ban-client
|
|
||||||
fail2ban-server
|
|
||||||
fail2ban-testcases
|
|
||||||
fail2ban-regex
|
|
||||||
fail2ban-2to3
|
fail2ban-2to3
|
||||||
client/configreader.py
|
bin/fail2ban-client
|
||||||
client/configparserinc.py
|
bin/fail2ban-server
|
||||||
client/jailreader.py
|
bin/fail2ban-testcases
|
||||||
client/fail2banreader.py
|
bin/fail2ban-regex
|
||||||
client/jailsreader.py
|
fail2ban/client/configreader.py
|
||||||
client/beautifier.py
|
fail2ban/client/configparserinc.py
|
||||||
client/filterreader.py
|
fail2ban/client/jailreader.py
|
||||||
client/actionreader.py
|
fail2ban/client/fail2banreader.py
|
||||||
client/__init__.py
|
fail2ban/client/jailsreader.py
|
||||||
client/configurator.py
|
fail2ban/client/beautifier.py
|
||||||
client/csocket.py
|
fail2ban/client/filterreader.py
|
||||||
server/asyncserver.py
|
fail2ban/client/actionreader.py
|
||||||
server/filter.py
|
fail2ban/client/__init__.py
|
||||||
server/filterpyinotify.py
|
fail2ban/client/configurator.py
|
||||||
server/filtergamin.py
|
fail2ban/client/csocket.py
|
||||||
server/filterpoll.py
|
fail2ban/server/asyncserver.py
|
||||||
server/iso8601.py
|
fail2ban/server/filter.py
|
||||||
server/server.py
|
fail2ban/server/filterpyinotify.py
|
||||||
server/actions.py
|
fail2ban/server/filtergamin.py
|
||||||
server/faildata.py
|
fail2ban/server/filterpoll.py
|
||||||
server/failmanager.py
|
fail2ban/server/iso8601.py
|
||||||
server/datedetector.py
|
fail2ban/server/server.py
|
||||||
server/jailthread.py
|
fail2ban/server/actions.py
|
||||||
server/transmitter.py
|
fail2ban/server/faildata.py
|
||||||
server/action.py
|
fail2ban/server/failmanager.py
|
||||||
server/ticket.py
|
fail2ban/server/datedetector.py
|
||||||
server/jail.py
|
fail2ban/server/jailthread.py
|
||||||
server/jails.py
|
fail2ban/server/transmitter.py
|
||||||
server/__init__.py
|
fail2ban/server/action.py
|
||||||
server/banmanager.py
|
fail2ban/server/ticket.py
|
||||||
server/datetemplate.py
|
fail2ban/server/jail.py
|
||||||
server/mytime.py
|
fail2ban/server/jails.py
|
||||||
server/failregex.py
|
fail2ban/server/__init__.py
|
||||||
testcases/files/testcase-usedns.log
|
fail2ban/server/banmanager.py
|
||||||
testcases/banmanagertestcase.py
|
fail2ban/server/datetemplate.py
|
||||||
testcases/failmanagertestcase.py
|
fail2ban/server/mytime.py
|
||||||
testcases/clientreadertestcase.py
|
fail2ban/server/failregex.py
|
||||||
testcases/filtertestcase.py
|
fail2ban/tests/banmanagertestcase.py
|
||||||
testcases/__init__.py
|
fail2ban/tests/failmanagertestcase.py
|
||||||
testcases/datedetectortestcase.py
|
fail2ban/tests/clientreadertestcase.py
|
||||||
testcases/actiontestcase.py
|
fail2ban/tests/filtertestcase.py
|
||||||
testcases/servertestcase.py
|
fail2ban/tests/__init__.py
|
||||||
testcases/sockettestcase.py
|
fail2ban/tests/datedetectortestcase.py
|
||||||
testcases/files/testcase01.log
|
fail2ban/tests/actiontestcase.py
|
||||||
testcases/files/testcase02.log
|
fail2ban/tests/servertestcase.py
|
||||||
testcases/files/testcase03.log
|
fail2ban/tests/sockettestcase.py
|
||||||
testcases/files/testcase04.log
|
fail2ban/tests/utils.py
|
||||||
|
fail2ban/tests/files/testcase01.log
|
||||||
|
fail2ban/tests/files/testcase02.log
|
||||||
|
fail2ban/tests/files/testcase03.log
|
||||||
|
fail2ban/tests/files/testcase04.log
|
||||||
|
fail2ban/tests/files/testcase-usedns.log
|
||||||
setup.py
|
setup.py
|
||||||
setup.cfg
|
setup.cfg
|
||||||
common/__init__.py
|
fail2ban/__init__.py
|
||||||
common/exceptions.py
|
fail2ban/exceptions.py
|
||||||
common/helpers.py
|
fail2ban/helpers.py
|
||||||
common/version.py
|
fail2ban/version.py
|
||||||
common/protocol.py
|
fail2ban/protocol.py
|
||||||
config/jail.conf
|
config/jail.conf
|
||||||
config/filter.d/common.conf
|
config/filter.d/common.conf
|
||||||
config/filter.d/apache-auth.conf
|
config/filter.d/apache-auth.conf
|
||||||
|
|
2
README
2
README
|
@ -4,7 +4,7 @@
|
||||||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Fail2Ban (version 0.8.8) 2012/07/31
|
Fail2Ban (version 0.9.0a0) 20??/??/??
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
Fail2Ban scans log files like /var/log/pwdfail and bans IP that makes too many
|
Fail2Ban scans log files like /var/log/pwdfail and bans IP that makes too many
|
||||||
|
|
|
@ -25,19 +25,11 @@ __license__ = "GPL"
|
||||||
import sys, string, os, pickle, re, logging, signal
|
import sys, string, os, pickle, re, logging, signal
|
||||||
import getopt, time, shlex, socket
|
import getopt, time, shlex, socket
|
||||||
|
|
||||||
# Inserts our own modules path first in the list
|
from fail2ban.version import version
|
||||||
# fix for bug #343821
|
from fail2ban.protocol import printFormatted
|
||||||
try:
|
from fail2ban.client.csocket import CSocket
|
||||||
from common.version import version
|
from fail2ban.client.configurator import Configurator
|
||||||
except ImportError, e:
|
from fail2ban.client.beautifier import Beautifier
|
||||||
sys.path.insert(1, "/usr/share/fail2ban")
|
|
||||||
from common.version import version
|
|
||||||
|
|
||||||
# Now we can import the rest of modules
|
|
||||||
from common.protocol import printFormatted
|
|
||||||
from client.csocket import CSocket
|
|
||||||
from client.configurator import Configurator
|
|
||||||
from client.beautifier import Beautifier
|
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client")
|
logSys = logging.getLogger("fail2ban.client")
|
|
@ -23,19 +23,12 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2012 Yaroslav Halchenko"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import getopt, sys, time, logging, os, locale
|
import getopt, sys, time, logging, os, locale
|
||||||
|
|
||||||
# Inserts our own modules path first in the list
|
|
||||||
# fix for bug #343821
|
|
||||||
try:
|
|
||||||
from common.version import version
|
|
||||||
except ImportError, e:
|
|
||||||
sys.path.insert(1, "/usr/share/fail2ban")
|
|
||||||
from common.version import version
|
|
||||||
|
|
||||||
from client.configparserinc import SafeConfigParserWithIncludes
|
|
||||||
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
|
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
|
||||||
from server.filter import Filter
|
|
||||||
from server.failregex import RegexException
|
from fail2ban.version import version
|
||||||
|
from fail2ban.client.configparserinc import SafeConfigParserWithIncludes
|
||||||
|
from fail2ban.server.filter import Filter
|
||||||
|
from fail2ban.server.failregex import RegexException
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.regex")
|
logSys = logging.getLogger("fail2ban.regex")
|
||||||
|
@ -116,6 +109,7 @@ class Fail2banRegex:
|
||||||
print " -h, --help display this help message"
|
print " -h, --help display this help message"
|
||||||
print " -V, --version print the version"
|
print " -V, --version print the version"
|
||||||
print " -v, --verbose verbose output"
|
print " -v, --verbose verbose output"
|
||||||
|
print " -l INT, --maxlines=INT set maxlines for multi-line regex default: 1"
|
||||||
print
|
print
|
||||||
print "Log:"
|
print "Log:"
|
||||||
print " string a string representing a log line"
|
print " string a string representing a log line"
|
||||||
|
@ -146,6 +140,14 @@ class Fail2banRegex:
|
||||||
self.__verbose = True
|
self.__verbose = True
|
||||||
elif opt[0] in ["-e", "--encoding"]:
|
elif opt[0] in ["-e", "--encoding"]:
|
||||||
self.encoding = opt[1]
|
self.encoding = opt[1]
|
||||||
|
elif opt[0] in ["-l", "--maxlines"]:
|
||||||
|
try:
|
||||||
|
self.__filter.setMaxLines(int(opt[1]))
|
||||||
|
except ValueError:
|
||||||
|
print "Invlaid value for maxlines: %s" % (
|
||||||
|
opt[1])
|
||||||
|
fail2banRegex.dispUsage()
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
#@staticmethod
|
#@staticmethod
|
||||||
def logIsFile(value):
|
def logIsFile(value):
|
||||||
|
@ -323,8 +325,8 @@ if __name__ == "__main__":
|
||||||
fail2banRegex = Fail2banRegex()
|
fail2banRegex = Fail2banRegex()
|
||||||
# Reads the command line options.
|
# Reads the command line options.
|
||||||
try:
|
try:
|
||||||
cmdOpts = 'e:hVcv'
|
cmdOpts = 'hVcvl:e:'
|
||||||
cmdLongOpts = ['encoding=', 'help', 'version', 'verbose']
|
cmdLongOpts = ['help', 'version', 'verbose', 'maxlines=', 'encoding=']
|
||||||
optList, args = getopt.getopt(sys.argv[1:], cmdOpts, cmdLongOpts)
|
optList, args = getopt.getopt(sys.argv[1:], cmdOpts, cmdLongOpts)
|
||||||
except getopt.GetoptError:
|
except getopt.GetoptError:
|
||||||
fail2banRegex.dispUsage()
|
fail2banRegex.dispUsage()
|
|
@ -24,15 +24,8 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import getopt, sys, logging, os
|
import getopt, sys, logging, os
|
||||||
|
|
||||||
# Inserts our own modules path first in the list
|
from fail2ban.version import version
|
||||||
# fix for bug #343821
|
from fail2ban.server.server import Server
|
||||||
try:
|
|
||||||
from common.version import version
|
|
||||||
except ImportError, e:
|
|
||||||
sys.path.insert(1, "/usr/share/fail2ban")
|
|
||||||
from common.version import version
|
|
||||||
|
|
||||||
from server.server import Server
|
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban")
|
logSys = logging.getLogger("fail2ban")
|
|
@ -27,18 +27,23 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import unittest, logging, sys, time, os
|
import unittest, logging, sys, time, os
|
||||||
|
|
||||||
from common.version import version
|
# Check if local fail2ban module exists, and use if it exists by
|
||||||
from testcases import banmanagertestcase
|
# modifying the path. This is such that tests can be used in dev
|
||||||
from testcases import clientreadertestcase
|
# environment.
|
||||||
from testcases import failmanagertestcase
|
if os.path.exists("fail2ban/__init__.py"):
|
||||||
from testcases import filtertestcase
|
sys.path.insert(0, ".")
|
||||||
from testcases import servertestcase
|
from fail2ban.version import version
|
||||||
from testcases import datedetectortestcase
|
from fail2ban.tests import banmanagertestcase
|
||||||
from testcases import actiontestcase
|
from fail2ban.tests import clientreadertestcase
|
||||||
from testcases import sockettestcase
|
from fail2ban.tests import failmanagertestcase
|
||||||
|
from fail2ban.tests import filtertestcase
|
||||||
|
from fail2ban.tests import servertestcase
|
||||||
|
from fail2ban.tests import datedetectortestcase
|
||||||
|
from fail2ban.tests import actiontestcase
|
||||||
|
from fail2ban.tests import sockettestcase
|
||||||
|
|
||||||
from testcases.utils import FormatterWithTraceBack
|
from fail2ban.tests.utils import FormatterWithTraceBack
|
||||||
from server.mytime import MyTime
|
from fail2ban.server.mytime import MyTime
|
||||||
|
|
||||||
from optparse import OptionParser, Option
|
from optparse import OptionParser, Option
|
||||||
|
|
||||||
|
@ -147,6 +152,7 @@ tests.addTest(unittest.makeSuite(banmanagertestcase.AddFailure))
|
||||||
# ClientReaders
|
# ClientReaders
|
||||||
tests.addTest(unittest.makeSuite(clientreadertestcase.ConfigReaderTest))
|
tests.addTest(unittest.makeSuite(clientreadertestcase.ConfigReaderTest))
|
||||||
tests.addTest(unittest.makeSuite(clientreadertestcase.JailReaderTest))
|
tests.addTest(unittest.makeSuite(clientreadertestcase.JailReaderTest))
|
||||||
|
tests.addTest(unittest.makeSuite(clientreadertestcase.FilterReaderTest))
|
||||||
tests.addTest(unittest.makeSuite(clientreadertestcase.JailsReaderTest))
|
tests.addTest(unittest.makeSuite(clientreadertestcase.JailsReaderTest))
|
||||||
# CSocket and AsyncServer
|
# CSocket and AsyncServer
|
||||||
tests.addTest(unittest.makeSuite(sockettestcase.Socket))
|
tests.addTest(unittest.makeSuite(sockettestcase.Socket))
|
||||||
|
@ -168,20 +174,20 @@ tests.addTest(unittest.makeSuite(datedetectortestcase.DateDetectorTest))
|
||||||
# Extensive use-tests of different available filters backends
|
# Extensive use-tests of different available filters backends
|
||||||
#
|
#
|
||||||
|
|
||||||
from server.filterpoll import FilterPoll
|
from fail2ban.server.filterpoll import FilterPoll
|
||||||
filters = [FilterPoll] # always available
|
filters = [FilterPoll] # always available
|
||||||
|
|
||||||
# Additional filters available only if external modules are available
|
# Additional filters available only if external modules are available
|
||||||
# yoh: Since I do not know better way for parametric tests
|
# yoh: Since I do not know better way for parametric tests
|
||||||
# with good old unittest
|
# with good old unittest
|
||||||
try:
|
try:
|
||||||
from server.filtergamin import FilterGamin
|
from fail2ban.server.filtergamin import FilterGamin
|
||||||
filters.append(FilterGamin)
|
filters.append(FilterGamin)
|
||||||
except Exception, e: # pragma: no cover
|
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 fail2ban.server.filterpyinotify import FilterPyinotify
|
||||||
filters.append(FilterPyinotify)
|
filters.append(FilterPyinotify)
|
||||||
except Exception, e: # pragma: no cover
|
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
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Fail2Ban configuration file for unsuccesfull MySQL authentication attempts
|
||||||
|
#
|
||||||
|
# Authors: Artur Penttinen
|
||||||
|
# Yaroslav O. Halchenko
|
||||||
|
#
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
# Read common prefixes. If any customizations available -- read them from
|
||||||
|
# common.local
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
#_daemon = mysqld
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: regex to match the password failures messages in the logfile. The
|
||||||
|
# host must be matched by a group named "host". The tag "<HOST>" can
|
||||||
|
# be used for standard IP/hostname matching and is only an alias for
|
||||||
|
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
|
||||||
|
# Values: TEXT
|
||||||
|
# 130322 11:26:54 [Warning] Access denied for user 'root'@'127.0.0.1' (using password: YES)
|
||||||
|
failregex = Access denied for user '\w+'@'<HOST>' (to database '[^']*'|\(using password: (YES|NO)\))*\s*$
|
||||||
|
|
||||||
|
# Option: ignoreregex
|
||||||
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
ignoreregex =
|
|
@ -352,6 +352,19 @@ action = iptables-multiport[name=asterisk-udp, port="5060,5061", protocol=udp]
|
||||||
logpath = /var/log/asterisk/messages
|
logpath = /var/log/asterisk/messages
|
||||||
maxretry = 10
|
maxretry = 10
|
||||||
|
|
||||||
|
# To log wrong MySQL access attempts add to /etc/my.cnf:
|
||||||
|
# log-error=/var/log/mysqld.log
|
||||||
|
# log-warning = 2
|
||||||
|
[mysqld-iptables]
|
||||||
|
|
||||||
|
enabled = false
|
||||||
|
filter = mysqld-auth
|
||||||
|
action = iptables[name=mysql, port=3306, protocol=tcp]
|
||||||
|
sendmail-whois[name=MySQL, dest=root, sender=fail2ban@example.com]
|
||||||
|
logpath = /var/log/mysqld.log
|
||||||
|
maxretry = 5
|
||||||
|
|
||||||
|
|
||||||
# Jail for more extended banning of persistent abusers
|
# Jail for more extended banning of persistent abusers
|
||||||
# !!! WARNING !!!
|
# !!! WARNING !!!
|
||||||
# Make sure that your loglevel specified in fail2ban.conf/.local
|
# Make sure that your loglevel specified in fail2ban.conf/.local
|
||||||
|
|
|
@ -9,7 +9,7 @@ for python in /usr/{,local/}bin/python2.[0-9]{,.*}{,-dbg}
|
||||||
do
|
do
|
||||||
[ -e "$python" ] || continue
|
[ -e "$python" ] || continue
|
||||||
echo "Testing using $python"
|
echo "Testing using $python"
|
||||||
$python ./fail2ban-testcases "$@" || failed+=" $python"
|
$python bin/fail2ban-testcases "$@" || failed+=" $python"
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ ! -z "$failed" ]; then
|
if [ ! -z "$failed" ]; then
|
||||||
|
|
|
@ -31,7 +31,7 @@ import logging
|
||||||
from configreader import ConfigReader
|
from configreader import ConfigReader
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class ActionReader(ConfigReader):
|
class ActionReader(ConfigReader):
|
||||||
|
|
|
@ -23,10 +23,10 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from common.exceptions import UnknownJailException, DuplicateJailException
|
from fail2ban.exceptions import UnknownJailException, DuplicateJailException
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Beautify the output of the client.
|
# Beautify the output of the client.
|
|
@ -31,7 +31,7 @@ import logging, os
|
||||||
from ConfigParser import SafeConfigParser
|
from ConfigParser import SafeConfigParser
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SafeConfigParserWithIncludes(SafeConfigParser):
|
class SafeConfigParserWithIncludes(SafeConfigParser):
|
||||||
"""
|
"""
|
|
@ -32,7 +32,7 @@ from configparserinc import SafeConfigParserWithIncludes
|
||||||
from ConfigParser import NoOptionError, NoSectionError
|
from ConfigParser import NoOptionError, NoSectionError
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class ConfigReader(SafeConfigParserWithIncludes):
|
class ConfigReader(SafeConfigParserWithIncludes):
|
||||||
|
|
|
@ -33,7 +33,7 @@ from fail2banreader import Fail2banReader
|
||||||
from jailsreader import JailsReader
|
from jailsreader import JailsReader
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Configurator:
|
class Configurator:
|
||||||
|
|
|
@ -31,7 +31,7 @@ import logging
|
||||||
from configreader import ConfigReader
|
from configreader import ConfigReader
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Fail2banReader(ConfigReader):
|
class Fail2banReader(ConfigReader):
|
||||||
|
|
|
@ -31,7 +31,7 @@ import logging
|
||||||
from configreader import ConfigReader
|
from configreader import ConfigReader
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class FilterReader(ConfigReader):
|
class FilterReader(ConfigReader):
|
||||||
|
|
|
@ -34,7 +34,7 @@ from filterreader import FilterReader
|
||||||
from actionreader import ActionReader
|
from actionreader import ActionReader
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class JailReader(ConfigReader):
|
class JailReader(ConfigReader):
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ class JailReader(ConfigReader):
|
||||||
["string", "logencoding", "auto"],
|
["string", "logencoding", "auto"],
|
||||||
["string", "backend", "auto"],
|
["string", "backend", "auto"],
|
||||||
["int", "maxretry", 3],
|
["int", "maxretry", 3],
|
||||||
|
["int", "maxlines", 1],
|
||||||
["int", "findtime", 600],
|
["int", "findtime", 600],
|
||||||
["int", "bantime", 600],
|
["int", "bantime", 600],
|
||||||
["string", "usedns", "warn"],
|
["string", "usedns", "warn"],
|
||||||
|
@ -123,6 +124,8 @@ class JailReader(ConfigReader):
|
||||||
backend = self.__opts[opt]
|
backend = self.__opts[opt]
|
||||||
elif opt == "maxretry":
|
elif opt == "maxretry":
|
||||||
stream.append(["set", self.__name, "maxretry", self.__opts[opt]])
|
stream.append(["set", self.__name, "maxretry", self.__opts[opt]])
|
||||||
|
elif opt == "maxlines":
|
||||||
|
stream.append(["set", self.__name, "maxlines", self.__opts[opt]])
|
||||||
elif opt == "ignoreip":
|
elif opt == "ignoreip":
|
||||||
for ip in self.__opts[opt].split():
|
for ip in self.__opts[opt].split():
|
||||||
# Do not send a command if the rule is empty.
|
# Do not send a command if the rule is empty.
|
|
@ -32,7 +32,7 @@ from configreader import ConfigReader
|
||||||
from jailreader import JailReader
|
from jailreader import JailReader
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class JailsReader(ConfigReader):
|
class JailsReader(ConfigReader):
|
||||||
|
|
|
@ -68,6 +68,7 @@ protocol = [
|
||||||
["set <JAIL> banip <IP>", "manually Ban <IP> for <JAIL>"],
|
["set <JAIL> banip <IP>", "manually Ban <IP> for <JAIL>"],
|
||||||
["set <JAIL> unbanip <IP>", "manually Unban <IP> in <JAIL>"],
|
["set <JAIL> unbanip <IP>", "manually Unban <IP> in <JAIL>"],
|
||||||
["set <JAIL> maxretry <RETRY>", "sets the number of failures <RETRY> before banning the host for <JAIL>"],
|
["set <JAIL> maxretry <RETRY>", "sets the number of failures <RETRY> before banning the host for <JAIL>"],
|
||||||
|
["set <JAIL> maxlines <LINES>", "sets the number of <LINES> to buffer for regex search for <JAIL>"],
|
||||||
["set <JAIL> addaction <ACT>", "adds a new action named <NAME> for <JAIL>"],
|
["set <JAIL> addaction <ACT>", "adds a new action named <NAME> for <JAIL>"],
|
||||||
["set <JAIL> delaction <ACT>", "removes the action <NAME> from <JAIL>"],
|
["set <JAIL> delaction <ACT>", "removes the action <NAME> from <JAIL>"],
|
||||||
["set <JAIL> setcinfo <ACT> <KEY> <VALUE>", "sets <VALUE> for <KEY> of the action <NAME> for <JAIL>"],
|
["set <JAIL> setcinfo <ACT> <KEY> <VALUE>", "sets <VALUE> for <KEY> of the action <NAME> for <JAIL>"],
|
||||||
|
@ -87,6 +88,7 @@ protocol = [
|
||||||
["get <JAIL> bantime", "gets the time a host is banned for <JAIL>"],
|
["get <JAIL> bantime", "gets the time a host is banned for <JAIL>"],
|
||||||
["get <JAIL> usedns", "gets the usedns setting for <JAIL>"],
|
["get <JAIL> usedns", "gets the usedns setting for <JAIL>"],
|
||||||
["get <JAIL> maxretry", "gets the number of failures allowed for <JAIL>"],
|
["get <JAIL> maxretry", "gets the number of failures allowed for <JAIL>"],
|
||||||
|
["get <JAIL> maxlines", "gets the number of lines to buffer for <JAIL>"],
|
||||||
["get <JAIL> addaction", "gets the last action which has been added for <JAIL>"],
|
["get <JAIL> addaction", "gets the last action which has been added for <JAIL>"],
|
||||||
["get <JAIL> actionstart <ACT>", "gets the start command for the action <ACT> for <JAIL>"],
|
["get <JAIL> actionstart <ACT>", "gets the start command for the action <ACT> for <JAIL>"],
|
||||||
["get <JAIL> actionstop <ACT>", "gets the stop command for the action <ACT> for <JAIL>"],
|
["get <JAIL> actionstop <ACT>", "gets the stop command for the action <ACT> for <JAIL>"],
|
|
@ -32,7 +32,7 @@ import threading
|
||||||
#from subprocess import call
|
#from subprocess import call
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.actions.action")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Create a lock for running system commands
|
# Create a lock for running system commands
|
||||||
_cmd_lock = threading.Lock()
|
_cmd_lock = threading.Lock()
|
|
@ -34,7 +34,7 @@ from mytime import MyTime
|
||||||
import time, logging
|
import time, logging
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.actions")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Execute commands.
|
# Execute commands.
|
|
@ -28,11 +28,12 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from pickle import dumps, loads, HIGHEST_PROTOCOL
|
from pickle import dumps, loads, HIGHEST_PROTOCOL
|
||||||
from common import helpers
|
|
||||||
import asyncore, asynchat, socket, os, logging, sys, traceback
|
import asyncore, asynchat, socket, os, logging, sys, traceback
|
||||||
|
|
||||||
|
from fail2ban import helpers
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.server")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Request handler class.
|
# Request handler class.
|
|
@ -33,7 +33,7 @@ from mytime import MyTime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.action")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Banning Manager.
|
# Banning Manager.
|
|
@ -33,7 +33,7 @@ from datetemplate import DateStrptime, DateTai64n, DateEpoch, DateISO8601
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.filter.datedetector")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class DateDetector:
|
class DateDetector:
|
||||||
|
|
||||||
|
@ -155,6 +155,12 @@ class DateDetector:
|
||||||
template.setRegex("^<\d{2}/\d{2}/\d{2}@\d{2}:\d{2}:\d{2}>")
|
template.setRegex("^<\d{2}/\d{2}/\d{2}@\d{2}:\d{2}:\d{2}>")
|
||||||
template.setPattern("<%m/%d/%y@%H:%M:%S>")
|
template.setPattern("<%m/%d/%y@%H:%M:%S>")
|
||||||
self._appendTemplate(template)
|
self._appendTemplate(template)
|
||||||
|
# MySQL: 130322 11:46:11
|
||||||
|
template = DateStrptime()
|
||||||
|
template.setName("MonthDayYear Hour:Minute:Second")
|
||||||
|
template.setRegex("^\d{2}\d{2}\d{2} +\d{1,2}:\d{2}:\d{2}")
|
||||||
|
template.setPattern("%y%m%d %H:%M:%S")
|
||||||
|
self._appendTemplate(template)
|
||||||
finally:
|
finally:
|
||||||
self.__lock.release()
|
self.__lock.release()
|
||||||
|
|
|
@ -33,7 +33,7 @@ from mytime import MyTime
|
||||||
import iso8601
|
import iso8601
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logSys = logging.getLogger("fail2ban.datetemplate")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DateTemplate:
|
class DateTemplate:
|
|
@ -30,7 +30,7 @@ __license__ = "GPL"
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class FailData:
|
class FailData:
|
||||||
|
|
|
@ -33,7 +33,7 @@ from threading import Lock
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.filter")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class FailManager:
|
class FailManager:
|
||||||
|
|
|
@ -48,10 +48,15 @@ class Regex:
|
||||||
# Perform shortcuts expansions.
|
# Perform shortcuts expansions.
|
||||||
# Replace "<HOST>" with default regular expression for host.
|
# Replace "<HOST>" with default regular expression for host.
|
||||||
regex = regex.replace("<HOST>", "(?:::f{4,6}:)?(?P<host>[\w\-.^_]+)")
|
regex = regex.replace("<HOST>", "(?:::f{4,6}:)?(?P<host>[\w\-.^_]+)")
|
||||||
|
# Replace "<SKIPLINES>" with regular expression for multiple lines.
|
||||||
|
regexSplit = regex.split("<SKIPLINES>")
|
||||||
|
regex = regexSplit[0]
|
||||||
|
for n, regexLine in enumerate(regexSplit[1:]):
|
||||||
|
regex += "\n(?P<skiplines%i>(?:(.*\n)*?))" % n + regexLine
|
||||||
if regex.lstrip() == '':
|
if regex.lstrip() == '':
|
||||||
raise RegexException("Cannot add empty regex")
|
raise RegexException("Cannot add empty regex")
|
||||||
try:
|
try:
|
||||||
self._regexObj = re.compile(regex)
|
self._regexObj = re.compile(regex, re.MULTILINE)
|
||||||
self._regex = regex
|
self._regex = regex
|
||||||
except sre_constants.error:
|
except sre_constants.error:
|
||||||
raise RegexException("Unable to compile regular expression '%s'" %
|
raise RegexException("Unable to compile regular expression '%s'" %
|
||||||
|
@ -76,6 +81,19 @@ class Regex:
|
||||||
|
|
||||||
def search(self, value):
|
def search(self, value):
|
||||||
self._matchCache = self._regexObj.search(value)
|
self._matchCache = self._regexObj.search(value)
|
||||||
|
if self.hasMatched():
|
||||||
|
# Find start of the first line where the match was found
|
||||||
|
try:
|
||||||
|
self._matchLineStart = self._matchCache.string.rindex(
|
||||||
|
"\n", 0, self._matchCache.start() +1 ) + 1
|
||||||
|
except ValueError:
|
||||||
|
self._matchLineStart = 0
|
||||||
|
# Find end of the last line where the match was found
|
||||||
|
try:
|
||||||
|
self._matchLineEnd = self._matchCache.string.index(
|
||||||
|
"\n", self._matchCache.end() - 1) + 1
|
||||||
|
except ValueError:
|
||||||
|
self._matchLineEnd = len(self._matchCache.string)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Checks if the previous call to search() matched.
|
# Checks if the previous call to search() matched.
|
||||||
|
@ -88,6 +106,54 @@ class Regex:
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns skipped lines.
|
||||||
|
#
|
||||||
|
# This returns skipped lines captured by the <SKIPLINES> tag.
|
||||||
|
# @return list of skipped lines
|
||||||
|
|
||||||
|
def getSkippedLines(self):
|
||||||
|
if not self._matchCache:
|
||||||
|
return []
|
||||||
|
skippedLines = ""
|
||||||
|
n = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
skippedLines += self._matchCache.group("skiplines%i" % n)
|
||||||
|
n += 1
|
||||||
|
except IndexError:
|
||||||
|
break
|
||||||
|
return skippedLines.splitlines(True)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns unmatched lines.
|
||||||
|
#
|
||||||
|
# This returns unmatched lines including captured by the <SKIPLINES> tag.
|
||||||
|
# @return list of unmatched lines
|
||||||
|
|
||||||
|
def getUnmatchedLines(self):
|
||||||
|
if not self.hasMatched():
|
||||||
|
return []
|
||||||
|
unmatchedLines = (
|
||||||
|
self._matchCache.string[:self._matchLineStart].splitlines(True)
|
||||||
|
+ self.getSkippedLines()
|
||||||
|
+ self._matchCache.string[self._matchLineEnd:].splitlines(True))
|
||||||
|
return unmatchedLines
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns matched lines.
|
||||||
|
#
|
||||||
|
# This returns matched lines by excluding those captured
|
||||||
|
# by the <SKIPLINES> tag.
|
||||||
|
# @return list of matched lines
|
||||||
|
|
||||||
|
def getMatchedLines(self):
|
||||||
|
if not self.hasMatched():
|
||||||
|
return []
|
||||||
|
matchedLines = self._matchCache.string[
|
||||||
|
self._matchLineStart:self._matchLineEnd].splitlines(True)
|
||||||
|
return [line for line in matchedLines
|
||||||
|
if line not in self.getSkippedLines()]
|
||||||
|
|
||||||
##
|
##
|
||||||
# Exception dedicated to the class Regex.
|
# Exception dedicated to the class Regex.
|
|
@ -38,7 +38,7 @@ from failregex import FailRegex, Regex, RegexException
|
||||||
import logging, re, os, fcntl, time, sys, locale, codecs
|
import logging, re, os, fcntl, time, sys, locale, codecs
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.filter")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Log reader class.
|
# Log reader class.
|
||||||
|
@ -71,6 +71,12 @@ class Filter(JailThread):
|
||||||
self.__findTime = 6000
|
self.__findTime = 6000
|
||||||
## The ignore IP list.
|
## The ignore IP list.
|
||||||
self.__ignoreIpList = []
|
self.__ignoreIpList = []
|
||||||
|
## Size of line buffer
|
||||||
|
self.__lineBufferSize = 1
|
||||||
|
## Line buffer
|
||||||
|
self.__lineBuffer = []
|
||||||
|
## Store last time stamp, applicable for multi-line
|
||||||
|
self.__lastTimeLine = ""
|
||||||
|
|
||||||
self.dateDetector = DateDetector()
|
self.dateDetector = DateDetector()
|
||||||
self.dateDetector.addDefaultTemplate()
|
self.dateDetector.addDefaultTemplate()
|
||||||
|
@ -206,6 +212,23 @@ class Filter(JailThread):
|
||||||
def getMaxRetry(self):
|
def getMaxRetry(self):
|
||||||
return self.failManager.getMaxRetry()
|
return self.failManager.getMaxRetry()
|
||||||
|
|
||||||
|
##
|
||||||
|
# Set the maximum line buffer size.
|
||||||
|
#
|
||||||
|
# @param value the line buffer size
|
||||||
|
|
||||||
|
def setMaxLines(self, value):
|
||||||
|
self.__lineBufferSize = max(1, value)
|
||||||
|
logSys.info("Set maxLines = %i" % self.__lineBufferSize)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Get the maximum line buffer size.
|
||||||
|
#
|
||||||
|
# @return the line buffer size
|
||||||
|
|
||||||
|
def getMaxLines(self):
|
||||||
|
return self.__lineBufferSize
|
||||||
|
|
||||||
##
|
##
|
||||||
# Main loop.
|
# Main loop.
|
||||||
#
|
#
|
||||||
|
@ -295,14 +318,17 @@ class Filter(JailThread):
|
||||||
if timeMatch:
|
if timeMatch:
|
||||||
# Lets split into time part and log part of the line
|
# Lets split into time part and log part of the line
|
||||||
timeLine = timeMatch.group()
|
timeLine = timeMatch.group()
|
||||||
|
self.__lastTimeLine = timeLine
|
||||||
# Lets leave the beginning in as well, so if there is no
|
# Lets leave the beginning in as well, so if there is no
|
||||||
# anchore at the beginning of the time regexp, we don't
|
# anchore at the beginning of the time regexp, we don't
|
||||||
# at least allow injection. Should be harmless otherwise
|
# at least allow injection. Should be harmless otherwise
|
||||||
logLine = line[:timeMatch.start()] + line[timeMatch.end():]
|
logLine = line[:timeMatch.start()] + line[timeMatch.end():]
|
||||||
else:
|
else:
|
||||||
timeLine = line
|
timeLine = self.__lastTimeLine or line
|
||||||
logLine = line
|
logLine = line
|
||||||
return self.findFailure(timeLine, logLine)
|
self.__lineBuffer = ((self.__lineBuffer +
|
||||||
|
[logLine])[-self.__lineBufferSize:])
|
||||||
|
return self.findFailure(timeLine, "".join(self.__lineBuffer))
|
||||||
|
|
||||||
def processLineAndAdd(self, line):
|
def processLineAndAdd(self, line):
|
||||||
"""Processes the line for failures and populates failManager
|
"""Processes the line for failures and populates failManager
|
||||||
|
@ -345,14 +371,15 @@ class Filter(JailThread):
|
||||||
|
|
||||||
def findFailure(self, timeLine, logLine):
|
def findFailure(self, timeLine, logLine):
|
||||||
failList = list()
|
failList = list()
|
||||||
# Checks if we must ignore this line.
|
|
||||||
if self.ignoreLine(logLine):
|
|
||||||
# The ignoreregex matched. Return.
|
|
||||||
return failList
|
|
||||||
# Iterates over all the regular expressions.
|
# Iterates over all the regular expressions.
|
||||||
for failRegex in self.__failRegex:
|
for failRegex in self.__failRegex:
|
||||||
failRegex.search(logLine)
|
failRegex.search(logLine)
|
||||||
if failRegex.hasMatched():
|
if failRegex.hasMatched():
|
||||||
|
# Checks if we must ignore this match.
|
||||||
|
if self.ignoreLine("".join(failRegex.getMatchedLines())):
|
||||||
|
# The ignoreregex matched. Remove ignored match.
|
||||||
|
self.__lineBuffer = failRegex.getUnmatchedLines()
|
||||||
|
continue
|
||||||
# The failregex matched.
|
# The failregex matched.
|
||||||
date = self.dateDetector.getUnixTime(timeLine)
|
date = self.dateDetector.getUnixTime(timeLine)
|
||||||
if date == None:
|
if date == None:
|
||||||
|
@ -362,6 +389,7 @@ class Filter(JailThread):
|
||||||
"in order to get support for this format."
|
"in order to get support for this format."
|
||||||
% (logLine, timeLine))
|
% (logLine, timeLine))
|
||||||
else:
|
else:
|
||||||
|
self.__lineBuffer = failRegex.getUnmatchedLines()
|
||||||
try:
|
try:
|
||||||
host = failRegex.getHost()
|
host = failRegex.getHost()
|
||||||
ipMatch = DNSUtils.textToIp(host, self.__useDns)
|
ipMatch = DNSUtils.textToIp(host, self.__useDns)
|
|
@ -30,7 +30,7 @@ from mytime import MyTime
|
||||||
import time, logging, gamin
|
import time, logging, gamin
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.filter")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Log reader class.
|
# Log reader class.
|
|
@ -33,7 +33,7 @@ from mytime import MyTime
|
||||||
import time, logging, os
|
import time, logging, os
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.filter")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Log reader class.
|
# Log reader class.
|
|
@ -38,7 +38,7 @@ if not hasattr(pyinotify, '__version__') \
|
||||||
from os.path import dirname, sep as pathsep
|
from os.path import dirname, sep as pathsep
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.filter")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Log reader class.
|
# Log reader class.
|
|
@ -28,7 +28,7 @@ import Queue, logging
|
||||||
from actions import Actions
|
from actions import Actions
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.jail")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Jail:
|
class Jail:
|
||||||
|
|
|
@ -21,7 +21,7 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2013- Yaroslav Halchenko"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2013- Yaroslav Halchenko"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from common.exceptions import DuplicateJailException, UnknownJailException
|
from fail2ban.exceptions import DuplicateJailException, UnknownJailException
|
||||||
|
|
||||||
from jail import Jail
|
from jail import Jail
|
||||||
from threading import Lock
|
from threading import Lock
|
|
@ -31,7 +31,7 @@ from threading import Thread
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.server")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class JailThread(Thread):
|
class JailThread(Thread):
|
||||||
|
|
|
@ -32,11 +32,11 @@ from jails import Jails
|
||||||
from transmitter import Transmitter
|
from transmitter import Transmitter
|
||||||
from asyncserver import AsyncServer
|
from asyncserver import AsyncServer
|
||||||
from asyncserver import AsyncServerException
|
from asyncserver import AsyncServerException
|
||||||
from common import version
|
from fail2ban import version
|
||||||
import logging, logging.handlers, sys, os, signal
|
import logging, logging.handlers, sys, os, signal
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.server")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
|
|
||||||
|
@ -223,6 +223,12 @@ class Server:
|
||||||
def getMaxRetry(self, name):
|
def getMaxRetry(self, name):
|
||||||
return self.__jails.getFilter(name).getMaxRetry()
|
return self.__jails.getFilter(name).getMaxRetry()
|
||||||
|
|
||||||
|
def setMaxLines(self, name, value):
|
||||||
|
self.__jails.getFilter(name).setMaxLines(value)
|
||||||
|
|
||||||
|
def getMaxLines(self, name):
|
||||||
|
return self.__jails.getFilter(name).getMaxLines()
|
||||||
|
|
||||||
# Action
|
# Action
|
||||||
def addAction(self, name, value):
|
def addAction(self, name, value):
|
||||||
self.__jails.getAction(name).addAction(value)
|
self.__jails.getAction(name).addAction(value)
|
||||||
|
@ -326,7 +332,7 @@ class Server:
|
||||||
logLevel = logging.WARNING
|
logLevel = logging.WARNING
|
||||||
elif value == 3:
|
elif value == 3:
|
||||||
logLevel = logging.INFO
|
logLevel = logging.INFO
|
||||||
logging.getLogger("fail2ban").setLevel(logLevel)
|
logging.getLogger(__name__).parent.parent.setLevel(logLevel)
|
||||||
finally:
|
finally:
|
||||||
self.__loggingLock.release()
|
self.__loggingLock.release()
|
||||||
|
|
||||||
|
@ -375,9 +381,10 @@ class Server:
|
||||||
return False
|
return False
|
||||||
# Removes previous handlers -- in reverse order since removeHandler
|
# Removes previous handlers -- in reverse order since removeHandler
|
||||||
# alter the list in-place and that can confuses the iterable
|
# alter the list in-place and that can confuses the iterable
|
||||||
for handler in logging.getLogger("fail2ban").handlers[::-1]:
|
logger = logging.getLogger(__name__).parent.parent
|
||||||
|
for handler in logger.handlers[::-1]:
|
||||||
# Remove the handler.
|
# Remove the handler.
|
||||||
logging.getLogger("fail2ban").removeHandler(handler)
|
logger.removeHandler(handler)
|
||||||
# And try to close -- it might be closed already
|
# And try to close -- it might be closed already
|
||||||
try:
|
try:
|
||||||
handler.flush()
|
handler.flush()
|
||||||
|
@ -390,7 +397,7 @@ class Server:
|
||||||
# with older Pythons -- seems to be safe to ignore there
|
# with older Pythons -- seems to be safe to ignore there
|
||||||
# tell the handler to use this format
|
# tell the handler to use this format
|
||||||
hdlr.setFormatter(formatter)
|
hdlr.setFormatter(formatter)
|
||||||
logging.getLogger("fail2ban").addHandler(hdlr)
|
logger.addHandler(hdlr)
|
||||||
# Does not display this message at startup.
|
# Does not display this message at startup.
|
||||||
if not self.__logTarget == None:
|
if not self.__logTarget == None:
|
||||||
logSys.info("Changed logging target to %s for Fail2ban v%s" %
|
logSys.info("Changed logging target to %s for Fail2ban v%s" %
|
|
@ -30,7 +30,7 @@ __license__ = "GPL"
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Ticket:
|
class Ticket:
|
||||||
|
|
|
@ -30,7 +30,7 @@ __license__ = "GPL"
|
||||||
import logging, time
|
import logging, time
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = logging.getLogger("fail2ban.comm")
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Transmitter:
|
class Transmitter:
|
||||||
|
|
||||||
|
@ -175,6 +175,10 @@ class Transmitter:
|
||||||
value = command[2]
|
value = command[2]
|
||||||
self.__server.setMaxRetry(name, int(value))
|
self.__server.setMaxRetry(name, int(value))
|
||||||
return self.__server.getMaxRetry(name)
|
return self.__server.getMaxRetry(name)
|
||||||
|
elif command[1] == "maxlines":
|
||||||
|
value = command[2]
|
||||||
|
self.__server.setMaxLines(name, int(value))
|
||||||
|
return self.__server.getMaxLines(name)
|
||||||
# command
|
# command
|
||||||
elif command[1] == "bantime":
|
elif command[1] == "bantime":
|
||||||
value = command[2]
|
value = command[2]
|
||||||
|
@ -256,6 +260,8 @@ class Transmitter:
|
||||||
return self.__server.getFindTime(name)
|
return self.__server.getFindTime(name)
|
||||||
elif command[1] == "maxretry":
|
elif command[1] == "maxretry":
|
||||||
return self.__server.getMaxRetry(name)
|
return self.__server.getMaxRetry(name)
|
||||||
|
elif command[1] == "maxlines":
|
||||||
|
return self.__server.getMaxLines(name)
|
||||||
# Action
|
# Action
|
||||||
elif command[1] == "bantime":
|
elif command[1] == "bantime":
|
||||||
return self.__server.getBanTime(name)
|
return self.__server.getBanTime(name)
|
|
@ -29,9 +29,10 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import unittest, time
|
import unittest, time
|
||||||
import logging, sys
|
import logging, sys
|
||||||
from server.action import Action
|
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
from fail2ban.server.action import Action
|
||||||
|
|
||||||
class ExecuteAction(unittest.TestCase):
|
class ExecuteAction(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
|
@ -28,8 +28,9 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from server.banmanager import BanManager
|
|
||||||
from server.ticket import BanTicket
|
from fail2ban.server.banmanager import BanManager
|
||||||
|
from fail2ban.server.ticket import BanTicket
|
||||||
|
|
||||||
class AddFailure(unittest.TestCase):
|
class AddFailure(unittest.TestCase):
|
||||||
|
|
|
@ -22,10 +22,18 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import os, shutil, tempfile, unittest
|
import os, shutil, tempfile, unittest
|
||||||
from client.configreader import ConfigReader
|
|
||||||
from client.jailreader import JailReader
|
from fail2ban.client.configreader import ConfigReader
|
||||||
from client.jailsreader import JailsReader
|
from fail2ban.client.jailreader import JailReader
|
||||||
from client.configurator import Configurator
|
from fail2ban.client.filterreader import FilterReader
|
||||||
|
from fail2ban.client.jailsreader import JailsReader
|
||||||
|
from fail2ban.client.configurator import Configurator
|
||||||
|
|
||||||
|
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||||
|
if os.path.exists('config/fail2ban.conf'):
|
||||||
|
CONFIG_DIR='config'
|
||||||
|
else:
|
||||||
|
CONFIG_DIR='/etc/fail2ban'
|
||||||
|
|
||||||
class ConfigReaderTest(unittest.TestCase):
|
class ConfigReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -98,7 +106,7 @@ option = %s
|
||||||
class JailReaderTest(unittest.TestCase):
|
class JailReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
def testStockSSHJail(self):
|
def testStockSSHJail(self):
|
||||||
jail = JailReader('ssh-iptables', basedir='config') # we are running tests from root project dir atm
|
jail = JailReader('ssh-iptables', basedir=CONFIG_DIR) # we are running tests from root project dir atm
|
||||||
self.assertTrue(jail.read())
|
self.assertTrue(jail.read())
|
||||||
self.assertTrue(jail.getOptions())
|
self.assertTrue(jail.getOptions())
|
||||||
self.assertFalse(jail.isEnabled())
|
self.assertFalse(jail.isEnabled())
|
||||||
|
@ -110,6 +118,36 @@ class JailReaderTest(unittest.TestCase):
|
||||||
result = JailReader.splitAction(action)
|
result = JailReader.splitAction(action)
|
||||||
self.assertEquals(expected, result)
|
self.assertEquals(expected, result)
|
||||||
|
|
||||||
|
class FilterReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def testConvert(self):
|
||||||
|
output = [['set', 'testcase01', 'addfailregex',
|
||||||
|
"^\\s*(?:\\S+ )?(?:kernel: \\[\\d+\\.\\d+\\] )?(?:@vserver_\\S+ )"
|
||||||
|
"?(?:(?:\\[\\d+\\])?:\\s+[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?|"
|
||||||
|
"[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?(?:\\[\\d+\\])?:)?\\s*(?:"
|
||||||
|
"error: PAM: )?Authentication failure for .* from <HOST>\\s*$"],
|
||||||
|
['set', 'testcase01', 'addfailregex',
|
||||||
|
"^\\s*(?:\\S+ )?(?:kernel: \\[\\d+\\.\\d+\\] )?(?:@vserver_\\S+ )"
|
||||||
|
"?(?:(?:\\[\\d+\\])?:\\s+[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?|"
|
||||||
|
"[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?(?:\\[\\d+\\])?:)?\\s*(?:"
|
||||||
|
"error: PAM: )?User not known to the underlying authentication mo"
|
||||||
|
"dule for .* from <HOST>\\s*$"],
|
||||||
|
['set', 'testcase01', 'addfailregex',
|
||||||
|
"^\\s*(?:\\S+ )?(?:kernel: \\[\\d+\\.\\d+\\] )?(?:@vserver_\\S+ )"
|
||||||
|
"?(?:(?:\\[\\d+\\])?:\\s+[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?|"
|
||||||
|
"[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?(?:\\[\\d+\\])?:)?\\s*(?:"
|
||||||
|
"error: PAM: )?User not known to the\\nunderlying authentication."
|
||||||
|
"+$<SKIPLINES>^.+ module for .* from <HOST>\\s*$"],
|
||||||
|
['set', 'testcase01', 'addignoreregex',
|
||||||
|
"^.+ john from host 192.168.1.1\\s*$"]]
|
||||||
|
filterReader = FilterReader("testcase01", "testcase01")
|
||||||
|
filterReader.setBaseDir(TEST_FILES_DIR)
|
||||||
|
filterReader.read()
|
||||||
|
#filterReader.getOptions(["failregex", "ignoreregex"])
|
||||||
|
filterReader.getOptions(None)
|
||||||
|
|
||||||
|
self.assertEquals(filterReader.convert(), output)
|
||||||
|
|
||||||
class JailsReaderTest(unittest.TestCase):
|
class JailsReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
def testProvidingBadBasedir(self):
|
def testProvidingBadBasedir(self):
|
||||||
|
@ -118,7 +156,7 @@ class JailsReaderTest(unittest.TestCase):
|
||||||
self.assertRaises(ValueError, reader.read)
|
self.assertRaises(ValueError, reader.read)
|
||||||
|
|
||||||
def testReadStockJailConf(self):
|
def testReadStockJailConf(self):
|
||||||
jails = JailsReader(basedir='config') # we are running tests from root project dir atm
|
jails = JailsReader(basedir=CONFIG_DIR) # we are running tests from root project dir atm
|
||||||
self.assertTrue(jails.read()) # opens fine
|
self.assertTrue(jails.read()) # opens fine
|
||||||
self.assertTrue(jails.getOptions()) # reads fine
|
self.assertTrue(jails.getOptions()) # reads fine
|
||||||
comm_commands = jails.convert()
|
comm_commands = jails.convert()
|
||||||
|
@ -129,7 +167,7 @@ class JailsReaderTest(unittest.TestCase):
|
||||||
def testReadStockJailConfForceEnabled(self):
|
def testReadStockJailConfForceEnabled(self):
|
||||||
# more of a smoke test to make sure that no obvious surprises
|
# more of a smoke test to make sure that no obvious surprises
|
||||||
# on users' systems when enabling shipped jails
|
# on users' systems when enabling shipped jails
|
||||||
jails = JailsReader(basedir='config', force_enable=True) # we are running tests from root project dir atm
|
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True) # we are running tests from root project dir atm
|
||||||
self.assertTrue(jails.read()) # opens fine
|
self.assertTrue(jails.read()) # opens fine
|
||||||
self.assertTrue(jails.getOptions()) # reads fine
|
self.assertTrue(jails.getOptions()) # reads fine
|
||||||
comm_commands = jails.convert()
|
comm_commands = jails.convert()
|
||||||
|
@ -151,8 +189,8 @@ class JailsReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
def testConfigurator(self):
|
def testConfigurator(self):
|
||||||
configurator = Configurator()
|
configurator = Configurator()
|
||||||
configurator.setBaseDir('config')
|
configurator.setBaseDir(CONFIG_DIR)
|
||||||
self.assertEqual(configurator.getBaseDir(), 'config')
|
self.assertEqual(configurator.getBaseDir(), CONFIG_DIR)
|
||||||
|
|
||||||
configurator.readEarly()
|
configurator.readEarly()
|
||||||
opts = configurator.getEarlyOptions()
|
opts = configurator.getEarlyOptions()
|
||||||
|
@ -165,4 +203,4 @@ class JailsReaderTest(unittest.TestCase):
|
||||||
# otherwise just a code smoke test)
|
# otherwise just a code smoke test)
|
||||||
configurator._Configurator__jails.setBaseDir('/tmp')
|
configurator._Configurator__jails.setBaseDir('/tmp')
|
||||||
self.assertEqual(configurator._Configurator__jails.getBaseDir(), '/tmp')
|
self.assertEqual(configurator._Configurator__jails.getBaseDir(), '/tmp')
|
||||||
self.assertEqual(configurator.getBaseDir(), 'config')
|
self.assertEqual(configurator.getBaseDir(), CONFIG_DIR)
|
|
@ -28,8 +28,9 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from server.datedetector import DateDetector
|
|
||||||
from server.datetemplate import DateTemplate
|
from fail2ban.server.datedetector import DateDetector
|
||||||
|
from fail2ban.server.datetemplate import DateTemplate
|
||||||
|
|
||||||
class DateDetectorTest(unittest.TestCase):
|
class DateDetectorTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -84,6 +85,7 @@ class DateDetectorTest(unittest.TestCase):
|
||||||
"2005-01-23T21:59:59.252Z", #ISO 8601
|
"2005-01-23T21:59:59.252Z", #ISO 8601
|
||||||
"2005-01-23T21:59:59-05:00Z", #ISO 8601 with TZ
|
"2005-01-23T21:59:59-05:00Z", #ISO 8601 with TZ
|
||||||
"<01/23/05@21:59:59>",
|
"<01/23/05@21:59:59>",
|
||||||
|
"050123 21:59:59", # MySQL
|
||||||
):
|
):
|
||||||
log = sdate + "[sshd] error: PAM: Authentication failure"
|
log = sdate + "[sshd] error: PAM: Authentication failure"
|
||||||
# exclude
|
# exclude
|
|
@ -28,8 +28,9 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest, socket, time, pickle
|
import unittest, socket, time, pickle
|
||||||
from server.failmanager import FailManager, FailManagerEmpty
|
|
||||||
from server.ticket import FailTicket
|
from fail2ban.server.failmanager import FailManager, FailManagerEmpty
|
||||||
|
from fail2ban.server.ticket import FailTicket
|
||||||
|
|
||||||
class AddFailure(unittest.TestCase):
|
class AddFailure(unittest.TestCase):
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Generic configuration items (to be used as interpolations) in other
|
||||||
|
# filters or actions configurations
|
||||||
|
#
|
||||||
|
# Author: Yaroslav Halchenko
|
||||||
|
#
|
||||||
|
# $Revision$
|
||||||
|
#
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
|
||||||
|
# Daemon definition is to be specialized (if needed) in .conf file
|
||||||
|
_daemon = \S*
|
||||||
|
|
||||||
|
#
|
||||||
|
# Shortcuts for easier comprehension of the failregex
|
||||||
|
#
|
||||||
|
# PID.
|
||||||
|
# EXAMPLES: [123]
|
||||||
|
__pid_re = (?:\[\d+\])
|
||||||
|
|
||||||
|
# Daemon name (with optional source_file:line or whatever)
|
||||||
|
# EXAMPLES: pam_rhosts_auth, [sshd], pop(pam_unix)
|
||||||
|
__daemon_re = [\[\(]?%(_daemon)s(?:\(\S+\))?[\]\)]?:?
|
||||||
|
|
||||||
|
# Combinations of daemon name and PID
|
||||||
|
# EXAMPLES: sshd[31607], pop(pam_unix)[4920]
|
||||||
|
__daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:)
|
||||||
|
|
||||||
|
# Some messages have a kernel prefix with a timestamp
|
||||||
|
# EXAMPLES: kernel: [769570.846956]
|
||||||
|
__kernel_prefix = kernel: \[\d+\.\d+\]
|
||||||
|
|
||||||
|
__hostname = \S+
|
||||||
|
|
||||||
|
#
|
||||||
|
# Common line prefixes (beginnings) which could be used in filters
|
||||||
|
#
|
||||||
|
# [hostname] [vserver tag] daemon_id spaces
|
||||||
|
# this can be optional (for instance if we match named native log files)
|
||||||
|
__prefix_line = \s*(?:%(__hostname)s )?(?:%(__kernel_prefix)s )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s*
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Cyril Jaquier
|
||||||
|
#
|
||||||
|
# $Revision$
|
||||||
|
#
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
# Read common prefixes. If any customizations available -- read them from
|
||||||
|
# common.local
|
||||||
|
before = testcase-common.conf
|
||||||
|
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
_daemon = sshd
|
||||||
|
|
||||||
|
# Option: failregex
|
||||||
|
# Notes.: regex to match the password failures messages in the logfile. The
|
||||||
|
# host must be matched by a group named "host". The tag "<HOST>" can
|
||||||
|
# be used for standard IP/hostname matching and is only an alias for
|
||||||
|
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
failregex = ^%(__prefix_line)s(?:error: PAM: )?Authentication failure for .* from <HOST>\s*$
|
||||||
|
^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$
|
||||||
|
^%(__prefix_line)s(?:error: PAM: )?User not known to the\nunderlying authentication.+$<SKIPLINES>^.+ module for .* from <HOST>\s*$
|
||||||
|
|
||||||
|
# Option: ignoreregex
|
||||||
|
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||||
|
# Values: TEXT
|
||||||
|
#
|
||||||
|
ignoreregex = ^.+ john from host 192.168.1.1\s*$
|
|
@ -0,0 +1,6 @@
|
||||||
|
130324 0:04:00 [Warning] Access denied for user 'root'@'192.168.1.35' (using password: NO)
|
||||||
|
130324 8:24:09 [Warning] Access denied for user 'root'@'220.95.238.171' (using password: NO)
|
||||||
|
130324 17:56:13 [Warning] Access denied for user 'root'@'61.160.223.112' (using password: NO)
|
||||||
|
130324 17:56:14 [Warning] Access denied for user 'root'@'61.160.223.112' (using password: YES)
|
||||||
|
130324 19:01:39 [Warning] Access denied for user 'root'@'61.147.108.35' (using password: NO)
|
||||||
|
130324 19:01:40 [Warning] Access denied for user 'root'@'61.147.108.35' (using password: YES)
|
|
@ -0,0 +1,35 @@
|
||||||
|
Aug 14 11:58:58 yyyy rsyncd[9874]: connect from example.com (192.0.43.10)
|
||||||
|
Aug 14 11:58:58 yyyy rsyncd[23864]: connect from example.com (192.0.43.10)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[23864]: rsync on xxx/ from example.com (192.0.43.10)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[23864]: building file list
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[28101]: connect from irrelevant (192.0.43.11)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[28101]: rsync on xxx/ from irrelevant (192.0.43.11)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[28101]: building file list
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[28101]: sent 294382 bytes received 781 bytes total size 29221543998
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[18067]: sent 2833586339 bytes received 65115 bytes total size 29221543998
|
||||||
|
Aug 14 11:59:58 yyyy smartd[2635]: Device: /dev/sdb [SAT], SMART Usage Attribute: 194 Temperature_Celsius changed from 116 to 115
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[1762]: connect from irrelevant (192.0.43.11)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[1762]: rsync on xxx/ from irrelevant (192.0.43.11)
|
||||||
|
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[1762]: building file list
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[1762]: sent 294382 bytes received 781 bytes total size 29221543998
|
||||||
|
Aug 14 11:59:58 yyyy sendmail[30222]: r0NNNlC0030222: from=<bounce-25497-9881290652-user=example.com@example.com>, size=6420, class=0, nrcpts=1, msgid=<0.0.9881290652.3772024cf8879cycvau18081.0@example.com>, bodytype=8BITMIME, proto=ESMTP, daemon=MTA, relay=[192.0.43.15] (may be forged)
|
||||||
|
Aug 14 11:59:58 yyyy smartd[2635]: Device: /dev/sda [SAT], starting scheduled Short Self-Test.
|
||||||
|
Aug 14 11:59:58 yyyy smartd[2635]: Device: /dev/sdb [SAT], SMART Usage Attribute: 194 Temperature_Celsius changed from 115 to 116
|
||||||
|
Aug 14 11:59:58 yyyy smartd[2635]: Device: /dev/sdb [SAT], starting scheduled Short Self-Test.
|
||||||
|
Aug 14 11:59:58 yyyy smartd[2635]: Device: /dev/sda [SAT], previous self-test completed without error
|
||||||
|
Aug 14 11:59:58 yyyy smartd[2635]: Device: /dev/sdb [SAT], previous self-test completed without error
|
||||||
|
|
||||||
|
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[7788]: connect from irrelevant (192.0.43.11)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[7788]: rsync on xxx/ from irrelevant (192.0.43.11)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[7788]: building file list
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[21919]: sent 2836906453 bytes received 6768 bytes total size 29221543998
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[23864]: rsync error: timeout in data send/receive (code 30) at io.c(137) [sender=3.0.9]
|
||||||
|
Aug 14 11:59:58 yyyy spamd[19119]: spamd: result: Y 11 - AWL,BAYES_50,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HTML_MESSAGE,RCVD_IN_BRBL_LASTEXT,RCVD_IN_PSBL,RCVD_IN_RP_RNBL,RDNS_NONE,URIBL_BLACK,URIBL_DBL_SPAM scantime=1.2,size=6910,user=sa-milt,uid=499,required_score=5.0,rhost=localhost,raddr=127.0.0.1,rport=57429,mid=<0.0.9881290652.3772024cf8879cycvau18081.0@example.com>,bayes=0.536244,autolearn=no
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[5534]: connect from irrelevant (192.0.43.11)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[5534]: rsync on xxx/ from irrelevant (192.0.43.11)
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[5534]: building file list
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[7788]: rsync error: Received SIGINT
|
||||||
|
Aug 14 11:59:58 yyyy rsyncd[5534]: sent 294382 bytes received 781 bytes total size 29221543998
|
||||||
|
Aug 14 11:59:59 yyyy rsyncd[9874]: rsync error: timeout in data send/receive (code 30) at io.c(137) [sender=3.0.9]
|
|
@ -1,15 +1,15 @@
|
||||||
Sep 21 22:03:07 [sshd] Invalid user toto from 212.41.96.185
|
Sep 21 22:03:07 [sshd] Invalid user toto from 212.41.96.185
|
||||||
1124012400 [sshd] Invalid user fuck from 212.41.96.185
|
1124012400 [sshd] Invalid user duck from 212.41.96.185
|
||||||
Sep 21 21:03:38 [sshd] Invalid user toto from 212.41.96.185
|
Sep 21 21:03:38 [sshd] Invalid user toto from 212.41.96.185
|
||||||
1124012500 [sshd] Invalid user fuck from 212.41.96.185
|
1124012500 [sshd] Invalid user duck from 212.41.96.185
|
||||||
Sep 21 21:03:46 [sshd] Invalid user toto from 212.41.96.185
|
Sep 21 21:03:46 [sshd] Invalid user toto from 212.41.96.185
|
||||||
Aug 14 11:58:48 [sshd] Invalid user fuck from 212.41.96.185
|
Aug 14 11:58:48 [sshd] Invalid user duck from 212.41.96.185
|
||||||
Aug 14 11:59:58 [sshd] Invalid user toto from 212.41.96.185
|
Aug 14 11:59:58 [sshd] Invalid user toto from 212.41.96.185
|
||||||
Sep 21 21:04:03 [sshd] Invalid user fuck from 212.41.96.185
|
Sep 21 21:04:03 [sshd] Invalid user duck from 212.41.96.185
|
||||||
- Last output repeated twice -
|
- Last output repeated twice -
|
||||||
2005/08/14 11:57:00 [sshd] Invalid user toto from 212.41.96.186
|
2005/08/14 11:57:00 [sshd] Invalid user toto from 212.41.96.186
|
||||||
2005/08/14 11:58:00 [sshd] Invalid user fuck from 212.41.96.186
|
2005/08/14 11:58:00 [sshd] Invalid user duck from 212.41.96.186
|
||||||
2005/08/14 11:59:00 [sshd] Invalid user toto from 212.41.96.186
|
2005/08/14 11:59:00 [sshd] Invalid user toto from 212.41.96.186
|
||||||
2005/08/14 12:00:00 [sshd] Invalid user fuck from 212.41.96.186
|
2005/08/14 12:00:00 [sshd] Invalid user duck from 212.41.96.186
|
||||||
- Last output repeated twice -
|
- Last output repeated twice -
|
||||||
Sep 21 21:09:01 [sshd] Invalid user toto from 212.41.96.185
|
Sep 21 21:09:01 [sshd] Invalid user toto from 212.41.96.185
|
|
@ -28,11 +28,13 @@ import sys
|
||||||
import time
|
import time
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from server.jail import Jail
|
from fail2ban.server.jail import Jail
|
||||||
from server.filterpoll import FilterPoll
|
from fail2ban.server.filterpoll import FilterPoll
|
||||||
from server.filter import FileFilter, DNSUtils
|
from fail2ban.server.filter import FileFilter, DNSUtils
|
||||||
from server.failmanager import FailManager
|
from fail2ban.server.failmanager import FailManager
|
||||||
from server.failmanager import FailManagerEmpty
|
from fail2ban.server.failmanager import FailManagerEmpty
|
||||||
|
|
||||||
|
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||||
|
|
||||||
#
|
#
|
||||||
# Useful helpers
|
# Useful helpers
|
||||||
|
@ -179,7 +181,7 @@ class IgnoreIP(unittest.TestCase):
|
||||||
|
|
||||||
class LogFile(unittest.TestCase):
|
class LogFile(unittest.TestCase):
|
||||||
|
|
||||||
FILENAME = "testcases/files/testcase01.log"
|
FILENAME = os.path.join(TEST_FILES_DIR, "testcase01.log")
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
|
@ -519,11 +521,12 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
|
|
||||||
class GetFailures(unittest.TestCase):
|
class GetFailures(unittest.TestCase):
|
||||||
|
|
||||||
FILENAME_01 = "testcases/files/testcase01.log"
|
FILENAME_01 = os.path.join(TEST_FILES_DIR, "testcase01.log")
|
||||||
FILENAME_02 = "testcases/files/testcase02.log"
|
FILENAME_02 = os.path.join(TEST_FILES_DIR, "testcase02.log")
|
||||||
FILENAME_03 = "testcases/files/testcase03.log"
|
FILENAME_03 = os.path.join(TEST_FILES_DIR, "testcase03.log")
|
||||||
FILENAME_04 = "testcases/files/testcase04.log"
|
FILENAME_04 = os.path.join(TEST_FILES_DIR, "testcase04.log")
|
||||||
FILENAME_USEDNS = "testcases/files/testcase-usedns.log"
|
FILENAME_USEDNS = os.path.join(TEST_FILES_DIR, "testcase-usedns.log")
|
||||||
|
FILENAME_MULTILINE = os.path.join(TEST_FILES_DIR, "testcase-multiline.log")
|
||||||
|
|
||||||
# so that they could be reused by other tests
|
# so that they could be reused by other tests
|
||||||
FAILURES_01 = ('193.168.0.128', 3, 1124013599.0,
|
FAILURES_01 = ('193.168.0.128', 3, 1124013599.0,
|
||||||
|
@ -629,6 +632,53 @@ class GetFailures(unittest.TestCase):
|
||||||
|
|
||||||
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
||||||
|
|
||||||
|
def testGetFailuresMultiLine(self):
|
||||||
|
output = [("192.0.43.10", 2, 1124013599.0),
|
||||||
|
("192.0.43.11", 1, 1124013598.0)]
|
||||||
|
self.filter.addLogPath(GetFailures.FILENAME_MULTILINE)
|
||||||
|
self.filter.addFailRegex("^.*rsyncd\[(?P<pid>\d+)\]: connect from .+ \(<HOST>\)$<SKIPLINES>^.+ rsyncd\[(?P=pid)\]: rsync error: .*$")
|
||||||
|
self.filter.setMaxLines(100)
|
||||||
|
self.filter.setMaxRetry(1)
|
||||||
|
|
||||||
|
self.filter.getFailures(GetFailures.FILENAME_MULTILINE)
|
||||||
|
|
||||||
|
_assert_correct_last_attempt(self, self.filter, output.pop())
|
||||||
|
_assert_correct_last_attempt(self, self.filter, output.pop())
|
||||||
|
|
||||||
|
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
||||||
|
|
||||||
|
def testGetFailuresMultiLineIgnoreRegex(self):
|
||||||
|
output = [("192.0.43.10", 2, 1124013599.0)]
|
||||||
|
self.filter.addLogPath(GetFailures.FILENAME_MULTILINE)
|
||||||
|
self.filter.addFailRegex("^.*rsyncd\[(?P<pid>\d+)\]: connect from .+ \(<HOST>\)$<SKIPLINES>^.+ rsyncd\[(?P=pid)\]: rsync error: .*$")
|
||||||
|
self.filter.addIgnoreRegex("rsync error: Received SIGINT")
|
||||||
|
self.filter.setMaxLines(100)
|
||||||
|
self.filter.setMaxRetry(1)
|
||||||
|
|
||||||
|
self.filter.getFailures(GetFailures.FILENAME_MULTILINE)
|
||||||
|
|
||||||
|
_assert_correct_last_attempt(self, self.filter, output.pop())
|
||||||
|
|
||||||
|
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
||||||
|
|
||||||
|
def testGetFailuresMultiLineMultiRegex(self):
|
||||||
|
output = [("192.0.43.10", 2, 1124013599.0),
|
||||||
|
("192.0.43.11", 1, 1124013598.0),
|
||||||
|
("192.0.43.15", 1, 1124013598.0)]
|
||||||
|
self.filter.addLogPath(GetFailures.FILENAME_MULTILINE)
|
||||||
|
self.filter.addFailRegex("^.*rsyncd\[(?P<pid>\d+)\]: connect from .+ \(<HOST>\)$<SKIPLINES>^.+ rsyncd\[(?P=pid)\]: rsync error: .*$")
|
||||||
|
self.filter.addFailRegex("^.* sendmail\[.*, msgid=<(?P<msgid>[^>]+).*relay=\[<HOST>\].*$<SKIPLINES>^.+ spamd: result: Y \d+ .*,mid=<(?P=msgid)>(,bayes=[.\d]+)?(,autolearn=\S+)?\s*$")
|
||||||
|
self.filter.setMaxLines(100)
|
||||||
|
self.filter.setMaxRetry(1)
|
||||||
|
|
||||||
|
self.filter.getFailures(GetFailures.FILENAME_MULTILINE)
|
||||||
|
|
||||||
|
_assert_correct_last_attempt(self, self.filter, output.pop())
|
||||||
|
_assert_correct_last_attempt(self, self.filter, output.pop())
|
||||||
|
_assert_correct_last_attempt(self, self.filter, output.pop())
|
||||||
|
|
||||||
|
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
||||||
|
|
||||||
class DNSUtilsTests(unittest.TestCase):
|
class DNSUtilsTests(unittest.TestCase):
|
||||||
|
|
||||||
def testUseDns(self):
|
def testUseDns(self):
|
|
@ -28,8 +28,11 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest, socket, time, tempfile, os, locale
|
import unittest, socket, time, tempfile, os, locale
|
||||||
from server.server import Server
|
|
||||||
from common.exceptions import UnknownJailException
|
from fail2ban.server.server import Server
|
||||||
|
from fail2ban.exceptions import UnknownJailException
|
||||||
|
|
||||||
|
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||||
|
|
||||||
class StartStop(unittest.TestCase):
|
class StartStop(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -279,14 +282,14 @@ class Transmitter(TransmitterBase):
|
||||||
self.jailAddDelTest(
|
self.jailAddDelTest(
|
||||||
"logpath",
|
"logpath",
|
||||||
[
|
[
|
||||||
"testcases/files/testcase01.log",
|
os.path.join(TEST_FILES_DIR, "testcase01.log"),
|
||||||
"testcases/files/testcase02.log",
|
os.path.join(TEST_FILES_DIR, "testcase02.log"),
|
||||||
"testcases/files/testcase03.log",
|
os.path.join(TEST_FILES_DIR, "testcase03.log"),
|
||||||
],
|
],
|
||||||
self.jailName
|
self.jailName
|
||||||
)
|
)
|
||||||
# Try duplicates
|
# Try duplicates
|
||||||
value = "testcases/files/testcase04.log"
|
value = os.path.join(TEST_FILES_DIR, "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]))
|
|
@ -28,8 +28,9 @@ __copyright__ = "Copyright (c) 2013 Steven Hiscocks"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest, time, tempfile, os, threading
|
import unittest, time, tempfile, os, threading
|
||||||
from server.asyncserver import AsyncServer, AsyncServerException
|
|
||||||
from client.csocket import CSocket
|
from fail2ban.server.asyncserver import AsyncServer, AsyncServerException
|
||||||
|
from fail2ban.client.csocket import CSocket
|
||||||
|
|
||||||
class Socket(unittest.TestCase):
|
class Socket(unittest.TestCase):
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
# $Revision$
|
# $Revision$
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
__author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2012 Yaroslav Halchenko"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
version = "0.8.8"
|
version = "0.9.0a0"
|
|
@ -0,0 +1,104 @@
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
This plugin checks if the fail2ban server is running and how many IPs are currently banned.
|
||||||
|
You can use this plugin to monitor all the jails or just a specific jail.
|
||||||
|
|
||||||
|
|
||||||
|
How to use
|
||||||
|
----------
|
||||||
|
Just have to run the following command:
|
||||||
|
$ ./check_fail2ban --help
|
||||||
|
|
||||||
|
If you need to use this script with NRPE you just have to do the
|
||||||
|
following steps:
|
||||||
|
|
||||||
|
1 allow your user to run the script with the sudo rights. Just add
|
||||||
|
something like that in your /etc/sudoers (use visudo) :
|
||||||
|
nagios ALL=(ALL) NOPASSWD: /<path-to>/check_fail2ban
|
||||||
|
|
||||||
|
2 then just add this kind of line in your NRPE config file :
|
||||||
|
command[check_fail2ban]=/usr/bin/sudo /<path-to>/check_fail2ban
|
||||||
|
|
||||||
|
3 don't forget to restart your NRPE daemon
|
||||||
|
|
||||||
|
/!\ be careful to let no one able to update the check_fail2ban ;)
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Notes (from f2ban.txt)
|
||||||
|
-----
|
||||||
|
It seems that Fail2ban is currently not working, please login and check
|
||||||
|
|
||||||
|
HELP:
|
||||||
|
|
||||||
|
1.) stop the Service
|
||||||
|
/etc/init.d/fail2ban stop
|
||||||
|
|
||||||
|
2.) delete the socket if available
|
||||||
|
rm /tmp/fail2ban.sock
|
||||||
|
|
||||||
|
3.) start the Service
|
||||||
|
/etc/init.d/fail2ban start
|
||||||
|
|
||||||
|
4.) check if fail2ban is working
|
||||||
|
fail2ban-client ping
|
||||||
|
Answer should be "pong"
|
||||||
|
|
||||||
|
5.) if the answer is not "pong" run away or CRY FOR HELP ;-)
|
||||||
|
|
||||||
|
|
||||||
|
Help
|
||||||
|
----
|
||||||
|
|
||||||
|
Usage: /<path-to>/check_fail2ban [-p] [-D "CHECK FAIL2BAN ACTIVITY"] [-v] [-c 2] [-w 1] [-s /<path-to>/socket] [-P /usr/bin/fail2ban-client]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help
|
||||||
|
Print detailed help screen
|
||||||
|
-V, --version
|
||||||
|
Print version information
|
||||||
|
-D, --display=STRING
|
||||||
|
To modify the output display
|
||||||
|
default is "CHECK FAIL2BAN ACTIVITY"
|
||||||
|
-P, --path-fail2ban_client=STRING
|
||||||
|
Specify the path to the tw_cli binary
|
||||||
|
default value is /usr/bin/fail2ban-client
|
||||||
|
-c, --critical=INT
|
||||||
|
Specify a critical threshold
|
||||||
|
default is 2
|
||||||
|
-w, --warning=INT
|
||||||
|
Specify a warning threshold
|
||||||
|
default is 1
|
||||||
|
-s, --socket=STRING
|
||||||
|
Specify a socket path
|
||||||
|
default is unset
|
||||||
|
-p, --perfdata
|
||||||
|
If you want to activate the perfdata output
|
||||||
|
-v, --verbose
|
||||||
|
Show details for command-line debugging (Nagios may truncate the output)
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
# for a specific jail
|
||||||
|
$ ./check_fail2ban --verbose -p -j ssh -w 1 -c 5 -P /usr/bin/fail2ban-client
|
||||||
|
DEBUG : fail2ban_client_path: /usr/bin/fail2ban-client
|
||||||
|
DEBUG : /usr/bin/fail2ban-client exists and is executable
|
||||||
|
DEBUG : final fail2ban command: /usr/bin/fail2ban-client
|
||||||
|
DEBUG : warning threshold : 1, critical threshold : 5
|
||||||
|
DEBUG : it seems the connection with the fail2ban server is ok
|
||||||
|
CHECK FAIL2BAN ACTIVITY - OK - 0 current banned IP(s) for the specific jail ssh | currentBannedIP=0
|
||||||
|
|
||||||
|
# for all the current jails
|
||||||
|
$ ./check_fail2ban --verbose -p -w 1 -c 5 -P /usr/bin/fail2ban-client
|
||||||
|
DEBUG : fail2ban_client_path: /usr/bin/fail2ban-client
|
||||||
|
DEBUG : /usr/bin/fail2ban-client exists and is executable
|
||||||
|
DEBUG : final fail2ban command: /usr/bin/fail2ban-client
|
||||||
|
DEBUG : warning threshold : 1, critical threshold : 5
|
||||||
|
DEBUG : it seems the connection with the fail2ban server is ok
|
||||||
|
DEBUG : jails list: apache, ssh-ddos, ssh
|
||||||
|
DEBUG : the jail apache has currently 0 banned IPs
|
||||||
|
DEBUG : the jail ssh-ddos has currently 0 banned IPs
|
||||||
|
DEBUG : the jail ssh has currently 0 banned IPs
|
||||||
|
CHECK FAIL2BAN ACTIVITY - OK - 3 detected jails with 0 current banned IP(s) | currentBannedIP=0
|
|
@ -1,105 +1,346 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
# -------------------------------------------------------
|
||||||
|
# -=- <check_fail2ban> -=-
|
||||||
|
# -------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Usage: ./check_fail2ban
|
# Description : This plugin checks if the fail2ban server is running
|
||||||
###############################################################################################
|
# and how many IPs are currently banned.
|
||||||
# Description:
|
|
||||||
# This plugin will check the status of Fail2ban.
|
|
||||||
#
|
|
||||||
# Created: 2008-10-25 (Sebastian Mueller)
|
|
||||||
#
|
|
||||||
# Changes: 2008-10-26 fixed some issues (Sebastian Mueller)
|
|
||||||
# Changes: 2009-01-25 add the second check, when server is not replying and the
|
|
||||||
# process is hang-up (Sebastian Mueller)
|
|
||||||
#
|
|
||||||
# please visit my website http://www.elchtest.eu or my personal WIKI http://wiki.elchtest.eu
|
|
||||||
#
|
|
||||||
################################################################################################
|
|
||||||
# if you have any questions, send a mail to linux@krabbe-offline.de
|
|
||||||
#
|
|
||||||
# this script is for my personal use. read the script before running/using it!!!
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# YOU HAVE BEEN WARNED. THIS MAY DESTROY YOUR MACHINE. I ACCEPT NO RESPONSIBILITY.
|
# inspired by the work of Sebastian Mueller - http://www.elchtest.eu
|
||||||
###############################################################################################
|
#
|
||||||
|
#
|
||||||
|
# Version : 0.1
|
||||||
|
# -------------------------------------------------------
|
||||||
|
# In :
|
||||||
|
# - see the How to use section
|
||||||
|
#
|
||||||
|
# Out :
|
||||||
|
# - only print on the standard output
|
||||||
|
#
|
||||||
|
# Features :
|
||||||
|
# - perfdata output
|
||||||
|
# - works with only a specific jail
|
||||||
|
#
|
||||||
|
# Fix Me/Todo :
|
||||||
|
# - too many things ;) but let me know what do you think about it
|
||||||
|
#
|
||||||
|
# ####################################################################
|
||||||
|
|
||||||
|
# ####################################################################
|
||||||
|
# GPL v2
|
||||||
|
# This program 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.
|
||||||
|
#
|
||||||
|
# This program 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 this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
# ####################################################################
|
||||||
|
|
||||||
|
# ####################################################################
|
||||||
|
# How to use :
|
||||||
|
# ------------
|
||||||
|
#
|
||||||
|
# Just have to run the following command:
|
||||||
|
# $ ./check_fail2ban --help
|
||||||
|
#
|
||||||
|
# If you need to use this script with NRPE you just have to do the
|
||||||
|
# following steps:
|
||||||
|
#
|
||||||
|
# 1 allow your user to run the script with the sudo rights. Just add
|
||||||
|
# something like that in your /etc/sudoers (use visudo) :
|
||||||
|
# nagios ALL=(ALL) NOPASSWD: /<path-to>/check_fail2ban
|
||||||
|
#
|
||||||
|
# 2 then just add this kind of line in your NRPE config file :
|
||||||
|
# command[check_fail2ban]=/usr/bin/sudo /<path-to>/check_fail2ban
|
||||||
|
#
|
||||||
|
# 3 don't forget to restart your NRPE daemon
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# /!\ be careful to let no one able to update the check_fail2ban ;)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# ####################################################################
|
||||||
|
|
||||||
|
# ####################################################################
|
||||||
|
# Changelog :
|
||||||
|
# -----------
|
||||||
|
#
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# Date:12/03/2013 Version:0.1 Author:Erwan Ben Souiden
|
||||||
|
# >> creation
|
||||||
|
# ####################################################################
|
||||||
|
|
||||||
|
# ####################################################################
|
||||||
|
# Don't touch anything under this line!
|
||||||
|
# You shall not pass - Gandalf is watching you
|
||||||
|
# ####################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Getopt::Long qw(:config no_ignore_case);
|
||||||
|
|
||||||
|
# Generic variables
|
||||||
|
# -----------------
|
||||||
|
my $version = '0.1';
|
||||||
|
my $author = 'Erwan Labynocle Ben Souiden';
|
||||||
|
my $a_mail = 'erwan@aleikoum.net';
|
||||||
|
my $script_name = 'check_fail2ban';
|
||||||
|
my $verbose_value = 0;
|
||||||
|
my $version_value = 0;
|
||||||
|
my $more_value = 0;
|
||||||
|
my $help_value = 0;
|
||||||
|
my $perfdata_value = 0;
|
||||||
|
my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
|
||||||
|
|
||||||
|
# Plugin default variables
|
||||||
|
# ------------------------
|
||||||
|
my $display = 'CHECK FAIL2BAN ACTIVITY';
|
||||||
|
my ($critical,$warning) = (2,1);
|
||||||
|
my $fail2ban_client_path = '/usr/bin/fail2ban-client';
|
||||||
|
my $fail2ban_socket = '';
|
||||||
|
my $jail_specific = '';
|
||||||
|
|
||||||
|
GetOptions (
|
||||||
|
'P=s' => \ $fail2ban_client_path,
|
||||||
|
'path-fail2ban_client=s' => \ $fail2ban_client_path,
|
||||||
|
'j=s' => \ $jail_specific,
|
||||||
|
'jail=s' => \ $jail_specific,
|
||||||
|
'w=i' => \ $warning,
|
||||||
|
'warning=i' => \ $warning,
|
||||||
|
'socket=s' => \ $fail2ban_socket,
|
||||||
|
'S=s' => \ $fail2ban_socket,
|
||||||
|
'c=i' => \ $critical,
|
||||||
|
'critical=i' => \ $critical,
|
||||||
|
'V' => \ $version_value,
|
||||||
|
'version' => \ $version_value,
|
||||||
|
'h' => \ $help_value,
|
||||||
|
'H' => \ $help_value,
|
||||||
|
'help' => \ $help_value,
|
||||||
|
'display=s' => \ $display,
|
||||||
|
'D=s' => \ $display,
|
||||||
|
'perfdata' => \ $perfdata_value,
|
||||||
|
'p' => \ $perfdata_value,
|
||||||
|
'v' => \ $verbose_value,
|
||||||
|
'verbose' => \ $verbose_value
|
||||||
|
);
|
||||||
|
|
||||||
|
print_usage() if ($help_value);
|
||||||
|
print_version() if ($version_value);
|
||||||
|
|
||||||
|
|
||||||
SECOND_CHECK=0
|
# Syntax check of your specified options
|
||||||
STATE_OK=0
|
# --------------------------------------
|
||||||
STATE_CRITICAL=2
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# Read the Status from fail2ban-client
|
|
||||||
######################################################################
|
|
||||||
check_processes_fail2ban()
|
|
||||||
{
|
|
||||||
|
|
||||||
F2B=`sudo -u root fail2ban-client ping | awk -F " " '{print $3}'`
|
|
||||||
exit_fail2ban=0
|
|
||||||
|
|
||||||
if [[ $F2B = "pong" ]]; then
|
|
||||||
exit_fail2ban=$STATE_OK
|
|
||||||
else
|
|
||||||
exit_fail2ban=$STATE_CRITICAL
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
print "DEBUG : fail2ban_client_path: $fail2ban_client_path\n" if ($verbose_value);
|
||||||
|
if (($fail2ban_client_path eq "")) {
|
||||||
|
print $display.'- one or more following arguments are missing: fail2ban_client_path'."\n";
|
||||||
|
exit $ERRORS{"UNKNOWN"};
|
||||||
}
|
}
|
||||||
######################################################################
|
|
||||||
# first check in the Background, PID will be killed when no response
|
|
||||||
# after 10 seconds, might be possible, otherwise the script will be
|
|
||||||
# present in your memory all the time
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
check_processes_fail2ban &
|
if(! -x $fail2ban_client_path) {
|
||||||
pid=$!
|
print $display.' - '.$fail2ban_client_path.' is not executable by you'."\n";
|
||||||
|
exit $ERRORS{"UNKNOWN"};
|
||||||
|
}
|
||||||
|
print "DEBUG : $fail2ban_client_path exists and is executable\n" if ($verbose_value);
|
||||||
|
|
||||||
typeset -i i=0
|
my $fail2ban_cmd = $fail2ban_client_path;
|
||||||
while ps $pid >/dev/null
|
$fail2ban_cmd .= " -s $fail2ban_socket" if ($fail2ban_socket);
|
||||||
do
|
|
||||||
sleep 1
|
|
||||||
i=$i+1
|
|
||||||
if [ $i -ge 10 ]
|
|
||||||
then
|
|
||||||
kill $pid
|
|
||||||
SECOND_CHECK=1
|
|
||||||
exit_fail2ban=$STATE_CRITICAL
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
######################################################################
|
print "DEBUG : final fail2ban command: $fail2ban_cmd\n" if ($verbose_value);
|
||||||
# when the Server response (does not mean the FAIL2BAN is working)
|
|
||||||
# in the first step, then it will run again and test the Service
|
print "DEBUG : warning threshold : $warning, critical threshold : $critical\n" if ($verbose_value);
|
||||||
# and provide the real status
|
if (($critical < 0) or ($warning < 0) or ($critical < $warning)) {
|
||||||
######################################################################
|
print $display.' - the thresholds must be integers and the critical threshold higher or equal than the warning threshold'."\n";
|
||||||
|
exit $ERRORS{"UNKNOWN"};
|
||||||
|
}
|
||||||
|
|
||||||
|
# Core script
|
||||||
|
# -----------
|
||||||
|
my ($how_many_jail,$how_many_banned,$return_print,$plugstate) = (0,0,"","OK");
|
||||||
|
|
||||||
|
|
||||||
if [ $SECOND_CHECK -eq 0 ]; then
|
### Test the connection to the fail2ban server
|
||||||
check_processes_fail2ban
|
my @command_output = `$fail2ban_cmd ping`;
|
||||||
elif [ $SECOND_CHECK -eq 1 ]; then
|
my $return_code = $?;
|
||||||
exit_fail2ban=$STATE_CRITICAL
|
if ($return_code) {
|
||||||
fi
|
print $display.'CRITICAL - non-zero exit code during testing fail2ban-client ping, check if the server is running and if you have the good permissions';
|
||||||
|
exit $ERRORS{"CRITICAL"};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "DEBUG : it seems the connection with the fail2ban server is ok\n" if ($verbose_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### Only if you specify one jail
|
||||||
|
if ($jail_specific) {
|
||||||
|
my $current_ban_number = currently_ban("$fail2ban_cmd","$jail_specific");
|
||||||
|
if ($current_ban_number == -1) {
|
||||||
|
print $display.' - CRITICAL - impossible to retrieve info about the jail '.$jail_specific;
|
||||||
|
exit $ERRORS{"CRITICAL"};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$how_many_banned = int($current_ban_number);
|
||||||
|
$return_print = $how_many_banned.' current banned IP(s) for the specific jail '.$jail_specific;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
### To analyze all the jail
|
||||||
|
else {
|
||||||
|
# Retrieve the jails list
|
||||||
|
my @jail_list = obtain_jail_list("$fail2ban_cmd");
|
||||||
|
if ($jail_list[0] eq "-1") {
|
||||||
|
print $display.' - CRITICAL - impossible to retrieve the jail list'."\n";
|
||||||
|
exit $ERRORS{"CRITICAL"};
|
||||||
|
}
|
||||||
|
|
||||||
######################################################################
|
foreach (@jail_list) {
|
||||||
# Main Menu
|
$how_many_jail ++;
|
||||||
######################################################################
|
|
||||||
|
my $jail_name = $_;
|
||||||
|
$jail_name =~ tr/ //ds;
|
||||||
|
|
||||||
|
my $current_ban_number = currently_ban("$fail2ban_cmd","$jail_name");
|
||||||
|
if ($current_ban_number == -1) {
|
||||||
|
print "DEBUG : problem to parse the current banned IPs for jail $jail_name\n" if ($verbose_value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "DEBUG : the jail $jail_name has currently $current_ban_number banned IPs\n" if ($verbose_value);
|
||||||
|
$how_many_banned += int($current_ban_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$return_print = $how_many_jail.' detected jails with '.$how_many_banned.' current banned IP(s)';
|
||||||
|
}
|
||||||
|
|
||||||
|
### Final
|
||||||
|
$plugstate = "CRITICAL" if ($how_many_banned >= $critical);
|
||||||
|
$plugstate = "WARNING" if (($how_many_banned >= $warning) && ($how_many_banned < $critical));
|
||||||
|
|
||||||
|
$return_print = $display." - ".$plugstate." - ".$return_print;
|
||||||
|
$return_print .= " | currentBannedIP=$how_many_banned" if ($perfdata_value);
|
||||||
|
|
||||||
|
print $return_print;
|
||||||
|
exit $ERRORS{"$plugstate"};
|
||||||
|
|
||||||
|
|
||||||
final_exit=$exit_fail2ban
|
# ####################################################################
|
||||||
if [ $final_exit -eq 0 ]; then
|
# function 1 : display the help
|
||||||
echo "SYSTEM OK - Fail2ban is working normally"
|
# -----------------------------
|
||||||
exitstatus=$STATE_OK
|
sub print_usage {
|
||||||
elif [ $final_exit -ne "0" ]; then
|
print <<EOT;
|
||||||
echo "SYSTEM WARNING - Fail2Ban is not working"
|
$script_name version $version by $author
|
||||||
######################################################################
|
|
||||||
# If don't have a Nagios Server for monitoring, remove the comment and
|
|
||||||
# add your Mail Address. You can check it with a Cron Job once an hour.
|
|
||||||
# put a txt file on your server and describe how to fix the issue, this
|
|
||||||
# could be attached to the mail.
|
|
||||||
######################################################################
|
|
||||||
# mutt -s "FAIL2BAN NOT WORKING" your@example.com < /home/f2ban.txt
|
|
||||||
|
|
||||||
exitstatus=$STATE_CRITICAL
|
This plugin checks if the fail2ban server is running and how many IPs are currently banned.
|
||||||
fi
|
You can use this plugin to monitor all the jails or just a specific jail.
|
||||||
exit $exitstatus
|
|
||||||
|
Usage: /<path-to>/$script_name [-p] [-D "$display"] [-v] [-c 2] [-w 1] [-s /<path-to>/socket] [-P /usr/bin/fail2ban-client]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help
|
||||||
|
Print detailed help screen
|
||||||
|
-V, --version
|
||||||
|
Print version information
|
||||||
|
-D, --display=STRING
|
||||||
|
To modify the output display
|
||||||
|
default is "CHECK FAIL2BAN ACTIVITY"
|
||||||
|
-P, --path-fail2ban_client=STRING
|
||||||
|
Specify the path to the tw_cli binary
|
||||||
|
default value is /usr/bin/fail2ban-client
|
||||||
|
-c, --critical=INT
|
||||||
|
Specify a critical threshold
|
||||||
|
default is 2
|
||||||
|
-w, --warning=INT
|
||||||
|
Specify a warning threshold
|
||||||
|
default is 1
|
||||||
|
-s, --socket=STRING
|
||||||
|
Specify a socket path
|
||||||
|
default is unset
|
||||||
|
-p, --perfdata
|
||||||
|
If you want to activate the perfdata output
|
||||||
|
-v, --verbose
|
||||||
|
Show details for command-line debugging (Nagios may truncate the output)
|
||||||
|
|
||||||
|
Send email to $a_mail if you have questions
|
||||||
|
regarding use of this software. To submit patches or suggest improvements,
|
||||||
|
send email to $a_mail
|
||||||
|
This plugin has been created by $author
|
||||||
|
|
||||||
|
Hope you will enjoy it ;)
|
||||||
|
|
||||||
|
Remember :
|
||||||
|
This program 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.
|
||||||
|
|
||||||
|
This program 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 this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
EOT
|
||||||
|
exit $ERRORS{"UNKNOWN"};
|
||||||
|
}
|
||||||
|
|
||||||
|
# function 2 : display version information
|
||||||
|
# ----------------------------------------
|
||||||
|
sub print_version {
|
||||||
|
print <<EOT;
|
||||||
|
$script_name version $version
|
||||||
|
EOT
|
||||||
|
exit $ERRORS{"UNKNOWN"};
|
||||||
|
}
|
||||||
|
|
||||||
|
# function 3 : return the jail list
|
||||||
|
# ---------------------------------
|
||||||
|
sub obtain_jail_list {
|
||||||
|
my ($fail2ban_client_path) = @_;
|
||||||
|
|
||||||
|
my @command_output = `$fail2ban_client_path status`;
|
||||||
|
my $return_code = $?;
|
||||||
|
if ($return_code) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @jail_list;
|
||||||
|
foreach (@command_output) {
|
||||||
|
if ($_=~/^.*Jail list:\t+(.*)/) {
|
||||||
|
print "DEBUG : jails list: $1\n" if ($verbose_value);
|
||||||
|
@jail_list = split(/,/, $1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return @jail_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
# function 4 : return how many IP are currently ban for a given jail
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
sub currently_ban {
|
||||||
|
my ($fail2ban_client_path,$jail_name) = @_;
|
||||||
|
|
||||||
|
my @command_output = `$fail2ban_client_path status $jail_name`;
|
||||||
|
my $return_code = $?;
|
||||||
|
if ($return_code) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (@command_output) {
|
||||||
|
if ($_=~/^.*Currently banned:\t+(.*)/) {
|
||||||
|
my $current_count = $1;
|
||||||
|
$current_count =~ tr/ //ds;
|
||||||
|
return $current_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
It seems that Fail2ban is currently not working, please login and check
|
|
||||||
|
|
||||||
HELP:
|
|
||||||
|
|
||||||
1.) stop the Service
|
|
||||||
/etc/init.d/fail2ban stop
|
|
||||||
|
|
||||||
2.) delete the socket if available
|
|
||||||
rm /tmp/fail2ban.sock
|
|
||||||
|
|
||||||
3.) start the Service
|
|
||||||
/etc/init.d/fail2ban start
|
|
||||||
|
|
||||||
4.) check if fail2ban is working
|
|
||||||
fail2ban-client ping
|
|
||||||
Answer should be "pong"
|
|
||||||
|
|
||||||
5.) if the answer is not "pong" run away or CRY FOR HELP ;-)
|
|
|
@ -1,6 +1,3 @@
|
||||||
[install]
|
|
||||||
install-purelib=/usr/share/fail2ban
|
|
||||||
|
|
||||||
[sdist]
|
[sdist]
|
||||||
formats=bztar
|
formats=bztar
|
||||||
|
|
||||||
|
|
23
setup.py
23
setup.py
|
@ -32,11 +32,12 @@ except ImportError:
|
||||||
# python 2.x
|
# python 2.x
|
||||||
from distutils.command.build_py import build_py
|
from distutils.command.build_py import build_py
|
||||||
from distutils.command.build_scripts import build_scripts
|
from distutils.command.build_scripts import build_scripts
|
||||||
from common.version import version
|
|
||||||
from os.path import isfile, join, isdir
|
from os.path import isfile, join, isdir
|
||||||
import sys
|
import sys
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
|
from fail2ban.version import version
|
||||||
|
|
||||||
longdesc = '''
|
longdesc = '''
|
||||||
Fail2Ban scans log files like /var/log/pwdfail or
|
Fail2Ban scans log files like /var/log/pwdfail or
|
||||||
/var/log/apache/error_log and bans IP that makes
|
/var/log/apache/error_log and bans IP that makes
|
||||||
|
@ -47,7 +48,7 @@ commands.'''
|
||||||
setup(
|
setup(
|
||||||
name = "fail2ban",
|
name = "fail2ban",
|
||||||
version = version,
|
version = version,
|
||||||
description = "Ban IPs that make too many password failure",
|
description = "Ban IPs that make too many password failures",
|
||||||
long_description = longdesc,
|
long_description = longdesc,
|
||||||
author = "Cyril Jaquier",
|
author = "Cyril Jaquier",
|
||||||
author_email = "cyril.jaquier@fail2ban.org",
|
author_email = "cyril.jaquier@fail2ban.org",
|
||||||
|
@ -56,15 +57,21 @@ setup(
|
||||||
platforms = "Posix",
|
platforms = "Posix",
|
||||||
cmdclass = {'build_py': build_py, 'build_scripts': build_scripts},
|
cmdclass = {'build_py': build_py, 'build_scripts': build_scripts},
|
||||||
scripts = [
|
scripts = [
|
||||||
'fail2ban-client',
|
'bin/fail2ban-client',
|
||||||
'fail2ban-server',
|
'bin/fail2ban-server',
|
||||||
'fail2ban-regex'
|
'bin/fail2ban-regex',
|
||||||
|
'bin/fail2ban-testcases',
|
||||||
],
|
],
|
||||||
packages = [
|
packages = [
|
||||||
'common',
|
'fail2ban',
|
||||||
'client',
|
'fail2ban.client',
|
||||||
'server'
|
'fail2ban.server',
|
||||||
|
'fail2ban.tests',
|
||||||
],
|
],
|
||||||
|
package_data = {
|
||||||
|
'fail2ban.tests':
|
||||||
|
['files/*.log', 'files/filter.d/*.conf'],
|
||||||
|
},
|
||||||
data_files = [
|
data_files = [
|
||||||
('/etc/fail2ban',
|
('/etc/fail2ban',
|
||||||
glob("config/*.conf")
|
glob("config/*.conf")
|
||||||
|
|
Loading…
Reference in New Issue