mirror of https://github.com/fail2ban/fail2ban
allow to use filter options by fail2ban-regex, example:
fail2ban-regex text.log "sshd[mode=aggressive]"pull/1710/head
parent
8af7a73bfc
commit
6a26602ba8
|
@ -120,6 +120,8 @@ Report bugs to https://github.com/fail2ban/fail2ban/issues
|
||||||
version="%prog " + version)
|
version="%prog " + version)
|
||||||
|
|
||||||
p.add_options([
|
p.add_options([
|
||||||
|
Option("-c", "--config", default='/etc/fail2ban',
|
||||||
|
help="set alternate config directory"),
|
||||||
Option("-d", "--datepattern",
|
Option("-d", "--datepattern",
|
||||||
help="set custom pattern used to match date/times"),
|
help="set custom pattern used to match date/times"),
|
||||||
Option("-e", "--encoding", default=PREFER_ENC,
|
Option("-e", "--encoding", default=PREFER_ENC,
|
||||||
|
@ -271,24 +273,55 @@ class Fail2banRegex(object):
|
||||||
def readRegex(self, value, regextype):
|
def readRegex(self, value, regextype):
|
||||||
assert(regextype in ('fail', 'ignore'))
|
assert(regextype in ('fail', 'ignore'))
|
||||||
regex = regextype + 'regex'
|
regex = regextype + 'regex'
|
||||||
if regextype == 'fail' and (os.path.isfile(value) or os.path.isfile(value + '.conf')):
|
# try to check - we've case filter?[options...]?:
|
||||||
if os.path.basename(os.path.dirname(value)) == 'filter.d':
|
basedir = self._opts.config
|
||||||
|
fltFile = None
|
||||||
|
fltOpt = {}
|
||||||
|
if regextype == 'fail':
|
||||||
|
fltName, fltOpt = JailReader.extractOptions(value)
|
||||||
|
if fltName is not None:
|
||||||
|
if "." in fltName[~5:]:
|
||||||
|
tryNames = (fltName,)
|
||||||
|
else:
|
||||||
|
tryNames = (fltName, fltName + '.conf', fltName + '.local')
|
||||||
|
for fltFile in tryNames:
|
||||||
|
if not "/" in fltFile:
|
||||||
|
if os.path.basename(basedir) == 'filter.d':
|
||||||
|
fltFile = os.path.join(basedir, fltFile)
|
||||||
|
else:
|
||||||
|
fltFile = os.path.join(basedir, 'filter.d', fltFile)
|
||||||
|
else:
|
||||||
|
basedir = os.path.dirname(fltFile)
|
||||||
|
if os.path.isfile(fltFile):
|
||||||
|
break
|
||||||
|
fltFile = None
|
||||||
|
# if it is filter file:
|
||||||
|
if fltFile is not None:
|
||||||
|
if (basedir == self._opts.config
|
||||||
|
or os.path.basename(basedir) == 'filter.d'
|
||||||
|
or ("." not in fltName[~5:] and "/" not in fltName)
|
||||||
|
):
|
||||||
## within filter.d folder - use standard loading algorithm to load filter completely (with .local etc.):
|
## within filter.d folder - use standard loading algorithm to load filter completely (with .local etc.):
|
||||||
basedir = os.path.dirname(os.path.dirname(value))
|
if os.path.basename(basedir) == 'filter.d':
|
||||||
value = os.path.splitext(os.path.basename(value))[0]
|
basedir = os.path.dirname(basedir)
|
||||||
output( "Use %11s filter file : %s, basedir: %s" % (regex, value, basedir) )
|
fltName = os.path.splitext(os.path.basename(fltName))[0]
|
||||||
reader = FilterReader(value, 'fail2ban-regex-jail', {}, share_config=self.share_config, basedir=basedir)
|
output( "Use %11s filter file : %s, basedir: %s" % (regex, fltName, basedir) )
|
||||||
if not reader.read(): # pragma: no cover
|
else:
|
||||||
output( "ERROR: failed to load filter %s" % value )
|
## foreign file - readexplicit this file and includes if possible:
|
||||||
return False
|
output( "Use %11s file : %s" % (regex, fltName) )
|
||||||
else: # pragma: no cover
|
basedir = None
|
||||||
|
if fltOpt:
|
||||||
|
output( "Use filter options : %r" % fltOpt )
|
||||||
|
reader = FilterReader(fltName, 'fail2ban-regex-jail', fltOpt, share_config=self.share_config, basedir=basedir)
|
||||||
|
if basedir is not None: # pragma: no cover
|
||||||
|
ret = reader.read()
|
||||||
|
else:
|
||||||
## foreign file - readexplicit this file and includes if possible:
|
## foreign file - readexplicit this file and includes if possible:
|
||||||
output( "Use %11s file : %s" % (regex, value) )
|
|
||||||
reader = FilterReader(value, 'fail2ban-regex-jail', {}, share_config=self.share_config)
|
|
||||||
reader.setBaseDir(None)
|
reader.setBaseDir(None)
|
||||||
if not reader.readexplicit():
|
ret = reader.readexplicit()
|
||||||
output( "ERROR: failed to read %s" % value )
|
if not ret:
|
||||||
return False
|
output( "ERROR: failed to load filter %s" % value )
|
||||||
|
return False
|
||||||
reader.getOptions(None)
|
reader.getOptions(None)
|
||||||
readercommands = reader.convert()
|
readercommands = reader.convert()
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ logSys = getLogger(__name__)
|
||||||
class JailReader(ConfigReader):
|
class JailReader(ConfigReader):
|
||||||
|
|
||||||
# regex, to extract list of options:
|
# regex, to extract list of options:
|
||||||
optionCRE = re.compile(r"^([\w\-_\.]+)(?:\[(.*)\])?\s*$", re.DOTALL)
|
optionCRE = re.compile(r"^([^\[]+)(?:\[(.*)\])?\s*$", re.DOTALL)
|
||||||
# regex, to iterate over single option in option list, syntax:
|
# regex, to iterate over single option in option list, syntax:
|
||||||
# `action = act[p1="...", p2='...', p3=...]`, where the p3=... not contains `,` or ']'
|
# `action = act[p1="...", p2='...', p3=...]`, where the p3=... not contains `,` or ']'
|
||||||
# since v0.10 separator extended with `]\s*[` for support of multiple option groups, syntax
|
# since v0.10 separator extended with `]\s*[` for support of multiple option groups, syntax
|
||||||
|
|
|
@ -209,7 +209,8 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
||||||
(opts, args, fail2banRegex) = _Fail2banRegex(
|
(opts, args, fail2banRegex) = _Fail2banRegex(
|
||||||
"-l", "notice", # put down log-level, because of too many debug-messages
|
"-l", "notice", # put down log-level, because of too many debug-messages
|
||||||
"-v", "--verbose-date", "--print-all-matched",
|
"-v", "--verbose-date", "--print-all-matched",
|
||||||
Fail2banRegexTest.FILENAME_SSHD, Fail2banRegexTest.FILTER_SSHD
|
"-c", CONFIG_DIR,
|
||||||
|
Fail2banRegexTest.FILENAME_SSHD, "sshd"
|
||||||
)
|
)
|
||||||
self.assertTrue(fail2banRegex.start(args))
|
self.assertTrue(fail2banRegex.start(args))
|
||||||
# test failure line and not-failure lines both presents:
|
# test failure line and not-failure lines both presents:
|
||||||
|
@ -220,7 +221,8 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
||||||
(opts, args, fail2banRegex) = _Fail2banRegex(
|
(opts, args, fail2banRegex) = _Fail2banRegex(
|
||||||
"-l", "notice", # put down log-level, because of too many debug-messages
|
"-l", "notice", # put down log-level, because of too many debug-messages
|
||||||
"--print-all-matched",
|
"--print-all-matched",
|
||||||
Fail2banRegexTest.FILENAME_ZZZ_SSHD, Fail2banRegexTest.FILTER_SSHD
|
"-c", CONFIG_DIR,
|
||||||
|
Fail2banRegexTest.FILENAME_ZZZ_SSHD, "sshd.conf[mode=normal]"
|
||||||
)
|
)
|
||||||
self.assertTrue(fail2banRegex.start(args))
|
self.assertTrue(fail2banRegex.start(args))
|
||||||
# test failure line and all not-failure lines presents:
|
# test failure line and all not-failure lines presents:
|
||||||
|
@ -234,7 +236,8 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
||||||
(opts, args, fail2banRegex) = _Fail2banRegex(
|
(opts, args, fail2banRegex) = _Fail2banRegex(
|
||||||
"-l", "notice", # put down log-level, because of too many debug-messages
|
"-l", "notice", # put down log-level, because of too many debug-messages
|
||||||
"--print-all-matched", "--print-all-missed",
|
"--print-all-matched", "--print-all-missed",
|
||||||
Fail2banRegexTest.FILENAME_ZZZ_SSHD, Fail2banRegexTest.FILTER_ZZZ_SSHD
|
"-c", os.path.dirname(Fail2banRegexTest.FILTER_ZZZ_SSHD),
|
||||||
|
Fail2banRegexTest.FILENAME_ZZZ_SSHD, os.path.basename(Fail2banRegexTest.FILTER_ZZZ_SSHD)
|
||||||
)
|
)
|
||||||
self.assertTrue(fail2banRegex.start(args))
|
self.assertTrue(fail2banRegex.start(args))
|
||||||
# test "failure" line presents (2nd part only, because multiline fewer precise):
|
# test "failure" line presents (2nd part only, because multiline fewer precise):
|
||||||
|
@ -245,10 +248,18 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
||||||
# by the way test of ignoreregex (specified in filter file)...
|
# by the way test of ignoreregex (specified in filter file)...
|
||||||
(opts, args, fail2banRegex) = _Fail2banRegex(
|
(opts, args, fail2banRegex) = _Fail2banRegex(
|
||||||
"-l", "notice", # put down log-level, because of too many debug-messages
|
"-l", "notice", # put down log-level, because of too many debug-messages
|
||||||
Fail2banRegexTest.FILENAME_ZZZ_GEN, Fail2banRegexTest.FILTER_ZZZ_GEN
|
Fail2banRegexTest.FILENAME_ZZZ_GEN, Fail2banRegexTest.FILTER_ZZZ_GEN+"[mode=test]"
|
||||||
)
|
)
|
||||||
self.assertTrue(fail2banRegex.start(args))
|
self.assertTrue(fail2banRegex.start(args))
|
||||||
|
|
||||||
|
def testWrongFilterFile(self):
|
||||||
|
# use test log as filter file to cover eror cases...
|
||||||
|
(opts, args, fail2banRegex) = _Fail2banRegex(
|
||||||
|
"-l", "notice", # put down log-level, because of too many debug-messages
|
||||||
|
Fail2banRegexTest.FILENAME_ZZZ_GEN, Fail2banRegexTest.FILENAME_ZZZ_GEN
|
||||||
|
)
|
||||||
|
self.assertFalse(fail2banRegex.start(args))
|
||||||
|
|
||||||
def _reset(self):
|
def _reset(self):
|
||||||
# reset global warn-counter:
|
# reset global warn-counter:
|
||||||
from ..server.filter import _decode_line_warn
|
from ..server.filter import _decode_line_warn
|
||||||
|
|
Loading…
Reference in New Issue