mirror of https://github.com/fail2ban/fail2ban
failregex: introduced capturing alternate groups, for example non-empty values of `alt_user_1`, `alt_user_2` will overwrite `user` if it is empty (or `alt_host` -> `host`, etc.)
parent
8028d3940d
commit
5603055a58
|
@ -89,6 +89,11 @@ def mapTag2Opt(tag):
|
|||
except KeyError:
|
||||
return tag.lower()
|
||||
|
||||
|
||||
# alternate names to be merged, e. g. alt_user_1 -> user ...
|
||||
ALTNAME_PRE = 'alt_'
|
||||
ALTNAME_CRE = re.compile(r'^' + ALTNAME_PRE + r'(.*)(?:_\d+)?$')
|
||||
|
||||
##
|
||||
# Regular expression class.
|
||||
#
|
||||
|
@ -114,6 +119,14 @@ class Regex:
|
|||
try:
|
||||
self._regexObj = re.compile(regex, re.MULTILINE if multiline else 0)
|
||||
self._regex = regex
|
||||
self._altValues = {}
|
||||
for k in filter(
|
||||
lambda k: len(k) > len(ALTNAME_PRE) and k.startswith(ALTNAME_PRE),
|
||||
self._regexObj.groupindex
|
||||
):
|
||||
n = ALTNAME_CRE.match(k).group(1)
|
||||
self._altValues[k] = n
|
||||
self._altValues = list(self._altValues.items()) if len(self._altValues) else None
|
||||
except sre_constants.error:
|
||||
raise RegexException("Unable to compile regular expression '%s'" %
|
||||
regex)
|
||||
|
@ -248,7 +261,16 @@ class Regex:
|
|||
#
|
||||
|
||||
def getGroups(self):
|
||||
return self._matchCache.groupdict()
|
||||
if not self._altValues:
|
||||
return self._matchCache.groupdict()
|
||||
# merge alternate values (e. g. 'alt_user_1' -> 'user' or 'alt_host' -> 'host'):
|
||||
fail = self._matchCache.groupdict()
|
||||
#fail = fail.copy()
|
||||
for k,n in self._altValues:
|
||||
v = fail.get(k)
|
||||
if v and not fail.get(n):
|
||||
fail[n] = v
|
||||
return fail
|
||||
|
||||
##
|
||||
# Returns skipped lines.
|
||||
|
|
|
@ -692,43 +692,46 @@ class Filter(JailThread):
|
|||
|
||||
# Iterates over all the regular expressions.
|
||||
for failRegexIndex, failRegex in enumerate(self.__failRegex):
|
||||
if logSys.getEffectiveLevel() <= logging.HEAVYDEBUG: # pragma: no cover
|
||||
logSys.log(5, " Looking for failregex %d - %r", failRegexIndex, failRegex.getRegex())
|
||||
failRegex.search(self.__lineBuffer, orgBuffer)
|
||||
if not failRegex.hasMatched():
|
||||
continue
|
||||
# The failregex matched.
|
||||
logSys.log(7, " Matched failregex %d: %s", failRegexIndex, failRegex.getGroups())
|
||||
# Checks if we must ignore this match.
|
||||
if self.ignoreLine(failRegex.getMatchedTupleLines()) \
|
||||
is not None:
|
||||
# The ignoreregex matched. Remove ignored match.
|
||||
self.__lineBuffer = failRegex.getUnmatchedTupleLines()
|
||||
logSys.log(7, " Matched ignoreregex and was ignored")
|
||||
if not self.checkAllRegex:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
if date is None:
|
||||
logSys.warning(
|
||||
"Found a match for %r but no valid date/time "
|
||||
"found for %r. Please try setting a custom "
|
||||
"date pattern (see man page jail.conf(5)). "
|
||||
"If format is complex, please "
|
||||
"file a detailed issue on"
|
||||
" https://github.com/fail2ban/fail2ban/issues "
|
||||
"in order to get support for this format.",
|
||||
"\n".join(failRegex.getMatchedLines()), timeText)
|
||||
continue
|
||||
self.__lineBuffer = failRegex.getUnmatchedTupleLines()
|
||||
# retrieve failure-id, host, etc from failure match:
|
||||
try:
|
||||
if logSys.getEffectiveLevel() <= logging.HEAVYDEBUG: # pragma: no cover
|
||||
logSys.log(5, " Looking for failregex %d - %r", failRegexIndex, failRegex.getRegex())
|
||||
failRegex.search(self.__lineBuffer, orgBuffer)
|
||||
if not failRegex.hasMatched():
|
||||
continue
|
||||
# current failure data (matched group dict):
|
||||
fail = failRegex.getGroups()
|
||||
# The failregex matched.
|
||||
logSys.log(7, " Matched failregex %d: %s", failRegexIndex, fail)
|
||||
# Checks if we must ignore this match.
|
||||
if self.ignoreLine(failRegex.getMatchedTupleLines()) \
|
||||
is not None:
|
||||
# The ignoreregex matched. Remove ignored match.
|
||||
self.__lineBuffer = failRegex.getUnmatchedTupleLines()
|
||||
logSys.log(7, " Matched ignoreregex and was ignored")
|
||||
if not self.checkAllRegex:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
if date is None:
|
||||
logSys.warning(
|
||||
"Found a match for %r but no valid date/time "
|
||||
"found for %r. Please try setting a custom "
|
||||
"date pattern (see man page jail.conf(5)). "
|
||||
"If format is complex, please "
|
||||
"file a detailed issue on"
|
||||
" https://github.com/fail2ban/fail2ban/issues "
|
||||
"in order to get support for this format.",
|
||||
"\n".join(failRegex.getMatchedLines()), timeText)
|
||||
continue
|
||||
# we should check all regex (bypass on multi-line, otherwise too complex):
|
||||
if not self.checkAllRegex or self.getMaxLines() > 1:
|
||||
self.__lineBuffer = failRegex.getUnmatchedTupleLines()
|
||||
# merge data if multi-line failure:
|
||||
raw = returnRawHost
|
||||
if preGroups:
|
||||
fail = preGroups.copy()
|
||||
fail.update(failRegex.getGroups())
|
||||
else:
|
||||
fail = failRegex.getGroups()
|
||||
currFail, fail = fail, preGroups.copy()
|
||||
fail.update(currFail)
|
||||
# first try to check we have mlfid case (caching of connection id by multi-line):
|
||||
mlfid = fail.get('mlfid')
|
||||
if mlfid is not None:
|
||||
|
|
|
@ -144,6 +144,7 @@ def testSampleRegexsFactory(name, basedir):
|
|||
regexsUsedRe = set()
|
||||
|
||||
# process each test-file (note: array filenames can grow during processing):
|
||||
faildata = {}
|
||||
i = 0
|
||||
while i < len(filenames):
|
||||
filename = filenames[i]; i += 1;
|
||||
|
@ -195,6 +196,7 @@ def testSampleRegexsFactory(name, basedir):
|
|||
regexList = flt.getFailRegex()
|
||||
|
||||
try:
|
||||
fail = {}
|
||||
ret = flt.processLine(line)
|
||||
if not ret:
|
||||
# Bypass if filter constraint specified:
|
||||
|
@ -246,8 +248,8 @@ def testSampleRegexsFactory(name, basedir):
|
|||
regexsUsedIdx.add(failregex)
|
||||
regexsUsedRe.add(regexList[failregex])
|
||||
except AssertionError as e: # pragma: no cover
|
||||
raise AssertionError("%s: %s on: %s:%i, line:\n%s" % (
|
||||
fltName, e, logFile.filename(), logFile.filelineno(), line))
|
||||
raise AssertionError("%s: %s on: %s:%i, line:\n%s\nfaildata:%r, fail:%r" % (
|
||||
fltName, e, logFile.filename(), logFile.filelineno(), line, faildata, fail))
|
||||
|
||||
# check missing samples for regex using each filter-options combination:
|
||||
for fltName, flt in self._filters.iteritems():
|
||||
|
|
Loading…
Reference in New Issue