mirror of https://github.com/fail2ban/fail2ban
better handling of default date templates (bounds, replacement using own expressions `...{DATE}...`, etc.)
parent
ce6ca0029a
commit
2e533a3a3a
|
@ -109,9 +109,6 @@ class DateDetectorCache(object):
|
||||||
"""Cache Fail2Ban's default template.
|
"""Cache Fail2Ban's default template.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(template, str):
|
|
||||||
# exact given template with word begin-end boundary:
|
|
||||||
template = _getPatternTemplate(template)
|
|
||||||
# if not already line-begin anchored, additional template, that prefers datetime
|
# if not already line-begin anchored, additional template, that prefers datetime
|
||||||
# at start of a line (safety+performance feature):
|
# at start of a line (safety+performance feature):
|
||||||
name = template.name
|
name = template.name
|
||||||
|
@ -126,60 +123,74 @@ class DateDetectorCache(object):
|
||||||
# add template:
|
# add template:
|
||||||
self.__tmpcache[1].append(template)
|
self.__tmpcache[1].append(template)
|
||||||
|
|
||||||
def _addDefaultTemplate(self):
|
DEFAULT_TEMPLATES = [
|
||||||
"""Add resp. cache Fail2Ban's default set of date templates.
|
|
||||||
"""
|
|
||||||
self.__tmpcache = [], []
|
|
||||||
# ISO 8601, simple date, optional subsecond and timezone:
|
# ISO 8601, simple date, optional subsecond and timezone:
|
||||||
# 2005-01-23T21:59:59.981746, 2005-01-23 21:59:59, 2005-01-23 8:59:59
|
# 2005-01-23T21:59:59.981746, 2005-01-23 21:59:59, 2005-01-23 8:59:59
|
||||||
# simple date: 2005/01/23 21:59:59
|
# simple date: 2005/01/23 21:59:59
|
||||||
# custom for syslog-ng 2006.12.21 06:43:20
|
# custom for syslog-ng 2006.12.21 06:43:20
|
||||||
self._cacheTemplate("%ExY(?P<_sep>[-/.])%m(?P=_sep)%d(?:T| ?)%H:%M:%S(?:[.,]%f)?(?:\s*%z)?")
|
"%ExY(?P<_sep>[-/.])%m(?P=_sep)%d(?:T| ?)%H:%M:%S(?:[.,]%f)?(?:\s*%z)?",
|
||||||
# asctime with optional day, subsecond and/or year:
|
# asctime with optional day, subsecond and/or year:
|
||||||
# Sun Jan 23 21:59:59.011 2005
|
# Sun Jan 23 21:59:59.011 2005
|
||||||
self._cacheTemplate("(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?")
|
"(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?",
|
||||||
# asctime with optional day, subsecond and/or year coming after day
|
# asctime with optional day, subsecond and/or year coming after day
|
||||||
# http://bugs.debian.org/798923
|
# http://bugs.debian.org/798923
|
||||||
# Sun Jan 23 2005 21:59:59.011
|
# Sun Jan 23 2005 21:59:59.011
|
||||||
self._cacheTemplate("(?:%a )?%b %d %ExY %k:%M:%S(?:\.%f)?")
|
"(?:%a )?%b %d %ExY %k:%M:%S(?:\.%f)?",
|
||||||
# simple date too (from x11vnc): 23/01/2005 21:59:59
|
# simple date too (from x11vnc): 23/01/2005 21:59:59
|
||||||
# and with optional year given by 2 digits: 23/01/05 21:59:59
|
# and with optional year given by 2 digits: 23/01/05 21:59:59
|
||||||
# (See http://bugs.debian.org/537610)
|
# (See http://bugs.debian.org/537610)
|
||||||
# 17-07-2008 17:23:25
|
# 17-07-2008 17:23:25
|
||||||
self._cacheTemplate("%d(?P<_sep>[-/])%m(?P=_sep)(?:%ExY|%Exy) %k:%M:%S")
|
"%d(?P<_sep>[-/])%m(?P=_sep)(?:%ExY|%Exy) %k:%M:%S",
|
||||||
# Apache format optional time zone:
|
# Apache format optional time zone:
|
||||||
# [31/Oct/2006:09:22:55 -0000]
|
# [31/Oct/2006:09:22:55 -0000]
|
||||||
# 26-Jul-2007 15:20:52
|
# 26-Jul-2007 15:20:52
|
||||||
# named 26-Jul-2007 15:20:52.252
|
# named 26-Jul-2007 15:20:52.252
|
||||||
# roundcube 26-Jul-2007 15:20:52 +0200
|
# roundcube 26-Jul-2007 15:20:52 +0200
|
||||||
self._cacheTemplate("%d(?P<_sep>[-/])%b(?P=_sep)%ExY[ :]?%H:%M:%S(?:\.%f)?(?: %z)?")
|
"%d(?P<_sep>[-/])%b(?P=_sep)%ExY[ :]?%H:%M:%S(?:\.%f)?(?: %z)?",
|
||||||
# CPanel 05/20/2008:01:57:39
|
# CPanel 05/20/2008:01:57:39
|
||||||
self._cacheTemplate("%m/%d/%ExY:%H:%M:%S")
|
"%m/%d/%ExY:%H:%M:%S",
|
||||||
# 01-27-2012 16:22:44.252
|
# 01-27-2012 16:22:44.252
|
||||||
# subseconds explicit to avoid possible %m<->%d confusion
|
# subseconds explicit to avoid possible %m<->%d confusion
|
||||||
# with previous ("%d-%m-%ExY %k:%M:%S" by "%d(?P<_sep>[-/])%m(?P=_sep)(?:%ExY|%Exy) %k:%M:%S")
|
# with previous ("%d-%m-%ExY %k:%M:%S" by "%d(?P<_sep>[-/])%m(?P=_sep)(?:%ExY|%Exy) %k:%M:%S")
|
||||||
self._cacheTemplate("%m-%d-%ExY %k:%M:%S(?:\.%f)?")
|
"%m-%d-%ExY %k:%M:%S(?:\.%f)?",
|
||||||
# Epoch
|
# Epoch
|
||||||
self._cacheTemplate('EPOCH')
|
"EPOCH",
|
||||||
# Only time information in the log
|
# Only time information in the log
|
||||||
self._cacheTemplate("{^LN-BEG}%H:%M:%S")
|
"{^LN-BEG}%H:%M:%S",
|
||||||
# <09/16/08@05:03:30>
|
# <09/16/08@05:03:30>
|
||||||
self._cacheTemplate("^<%m/%d/%Exy@%H:%M:%S>")
|
"^<%m/%d/%Exy@%H:%M:%S>",
|
||||||
# MySQL: 130322 11:46:11
|
# MySQL: 130322 11:46:11
|
||||||
self._cacheTemplate("%Exy%Exm%Exd ?%H:%M:%S")
|
"%Exy%Exm%Exd ?%H:%M:%S",
|
||||||
# Apache Tomcat
|
# Apache Tomcat
|
||||||
self._cacheTemplate("%b %d, %ExY %I:%M:%S %p")
|
"%b %d, %ExY %I:%M:%S %p",
|
||||||
# ASSP: Apr-27-13 02:33:06
|
# ASSP: Apr-27-13 02:33:06
|
||||||
self._cacheTemplate("^%b-%d-%Exy %k:%M:%S")
|
"^%b-%d-%Exy %k:%M:%S",
|
||||||
# 20050123T215959, 20050123 215959, 20050123 85959
|
# 20050123T215959, 20050123 215959, 20050123 85959
|
||||||
self._cacheTemplate("%ExY%Exm%Exd(?:T| ?)%ExH%ExM%ExS(?:[.,]%f)?(?:\s*%z)?")
|
"%ExY%Exm%Exd(?:T| ?)%ExH%ExM%ExS(?:[.,]%f)?(?:\s*%z)?",
|
||||||
# prefixed with optional named time zone (monit):
|
# prefixed with optional named time zone (monit):
|
||||||
# PDT Apr 16 21:05:29
|
# PDT Apr 16 21:05:29
|
||||||
self._cacheTemplate("(?:%Z )?(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?")
|
"(?:%Z )?(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?",
|
||||||
# +00:00 Jan 23 21:59:59.011 2005
|
# +00:00 Jan 23 21:59:59.011 2005
|
||||||
self._cacheTemplate("(?:%z )?(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?")
|
"(?:%z )?(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?",
|
||||||
# TAI64N
|
# TAI64N
|
||||||
self._cacheTemplate("TAI64N")
|
"TAI64N",
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def defaultTemplates(self):
|
||||||
|
if isinstance(DateDetectorCache.DEFAULT_TEMPLATES[0], str):
|
||||||
|
for i, dt in enumerate(DateDetectorCache.DEFAULT_TEMPLATES):
|
||||||
|
dt = _getPatternTemplate(dt)
|
||||||
|
DateDetectorCache.DEFAULT_TEMPLATES[i] = dt
|
||||||
|
return DateDetectorCache.DEFAULT_TEMPLATES
|
||||||
|
|
||||||
|
def _addDefaultTemplate(self):
|
||||||
|
"""Add resp. cache Fail2Ban's default set of date templates.
|
||||||
|
"""
|
||||||
|
self.__tmpcache = [], []
|
||||||
|
# cache default templates:
|
||||||
|
for dt in self.defaultTemplates:
|
||||||
|
self._cacheTemplate(dt)
|
||||||
#
|
#
|
||||||
self.__templates = self.__tmpcache[0] + self.__tmpcache[1]
|
self.__templates = self.__tmpcache[0] + self.__tmpcache[1]
|
||||||
del self.__tmpcache
|
del self.__tmpcache
|
||||||
|
@ -269,8 +280,7 @@ class DateDetector(object):
|
||||||
self.addDefaultTemplate(flt)
|
self.addDefaultTemplate(flt)
|
||||||
return
|
return
|
||||||
elif "{DATE}" in key:
|
elif "{DATE}" in key:
|
||||||
self.addDefaultTemplate(
|
self.addDefaultTemplate(preMatch=pattern, allDefaults=False)
|
||||||
lambda template: not template.flags & DateTemplate.LINE_BEGIN, pattern)
|
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
template = _getPatternTemplate(pattern, key)
|
template = _getPatternTemplate(pattern, key)
|
||||||
|
@ -283,18 +293,20 @@ class DateDetector(object):
|
||||||
logSys.debug(" date pattern regex for %r: %s",
|
logSys.debug(" date pattern regex for %r: %s",
|
||||||
getattr(template, 'pattern', ''), template.regex)
|
getattr(template, 'pattern', ''), template.regex)
|
||||||
|
|
||||||
def addDefaultTemplate(self, filterTemplate=None, preMatch=None):
|
def addDefaultTemplate(self, filterTemplate=None, preMatch=None, allDefaults=True):
|
||||||
"""Add Fail2Ban's default set of date templates.
|
"""Add Fail2Ban's default set of date templates.
|
||||||
"""
|
"""
|
||||||
ignoreDup = len(self.__templates) > 0
|
ignoreDup = len(self.__templates) > 0
|
||||||
for template in DateDetector._defCache.templates:
|
for template in (
|
||||||
|
DateDetector._defCache.templates if allDefaults else DateDetector._defCache.defaultTemplates
|
||||||
|
):
|
||||||
# filter if specified:
|
# filter if specified:
|
||||||
if filterTemplate is not None and not filterTemplate(template): continue
|
if filterTemplate is not None and not filterTemplate(template): continue
|
||||||
# if exact pattern available - create copy of template, contains replaced {DATE} with default regex:
|
# if exact pattern available - create copy of template, contains replaced {DATE} with default regex:
|
||||||
if preMatch is not None:
|
if preMatch is not None:
|
||||||
# get cached or create a copy with modified name/pattern, using preMatch replacement for {DATE}:
|
# get cached or create a copy with modified name/pattern, using preMatch replacement for {DATE}:
|
||||||
template = _getAnchoredTemplate(template,
|
template = _getAnchoredTemplate(template,
|
||||||
wrap=lambda s: RE_DATE_PREMATCH.sub(lambda m: s, preMatch))
|
wrap=lambda s: RE_DATE_PREMATCH.sub(lambda m: DateTemplate.unboundPattern(s), preMatch))
|
||||||
# append date detector template (ignore duplicate if some was added before default):
|
# append date detector template (ignore duplicate if some was added before default):
|
||||||
self._appendTemplate(template, ignoreDup=ignoreDup)
|
self._appendTemplate(template, ignoreDup=ignoreDup)
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,10 @@ RE_GROUPED = re.compile(r'(?<!(?:\(\?))(?<!\\)\((?!\?)')
|
||||||
RE_GROUP = ( re.compile(r'^((?:\(\?\w+\))?\^?(?:\(\?\w+\))?)(.*?)(\$?)$'), r"\1(\2)\3" )
|
RE_GROUP = ( re.compile(r'^((?:\(\?\w+\))?\^?(?:\(\?\w+\))?)(.*?)(\$?)$'), r"\1(\2)\3" )
|
||||||
|
|
||||||
RE_EXLINE_BOUND_BEG = re.compile(r'^\{\^LN-BEG\}')
|
RE_EXLINE_BOUND_BEG = re.compile(r'^\{\^LN-BEG\}')
|
||||||
|
RE_EXSANC_BOUND_BEG = re.compile(r'^\(\?:\^\|\\b\|\\W\)')
|
||||||
|
RE_EXEANC_BOUND_BEG = re.compile(r'\(\?=\\b\|\\W\|\$\)$')
|
||||||
RE_NO_WRD_BOUND_BEG = re.compile(r'^\(*(?:\(\?\w+\))?(?:\^|\(*\*\*|\(\?:\^)')
|
RE_NO_WRD_BOUND_BEG = re.compile(r'^\(*(?:\(\?\w+\))?(?:\^|\(*\*\*|\(\?:\^)')
|
||||||
RE_NO_WRD_BOUND_END = re.compile(r'(?<!\\)(?:\$\)?|\*\*\)*)$')
|
RE_NO_WRD_BOUND_END = re.compile(r'(?<!\\)(?:\$\)?|\\b|\\s|\*\*\)*)$')
|
||||||
RE_DEL_WRD_BOUNDS = ( re.compile(r'^\(*(?:\(\?\w+\))?\(*\*\*|(?<!\\)\*\*\)*$'),
|
RE_DEL_WRD_BOUNDS = ( re.compile(r'^\(*(?:\(\?\w+\))?\(*\*\*|(?<!\\)\*\*\)*$'),
|
||||||
lambda m: m.group().replace('**', '') )
|
lambda m: m.group().replace('**', '') )
|
||||||
|
|
||||||
|
@ -131,7 +133,7 @@ class DateTemplate(object):
|
||||||
# remove possible special pattern "**" in front and end of regex:
|
# remove possible special pattern "**" in front and end of regex:
|
||||||
regex = RE_DEL_WRD_BOUNDS[0].sub(RE_DEL_WRD_BOUNDS[1], regex)
|
regex = RE_DEL_WRD_BOUNDS[0].sub(RE_DEL_WRD_BOUNDS[1], regex)
|
||||||
self._regex = regex
|
self._regex = regex
|
||||||
logSys.debug(' constructed regex %s', regex)
|
logSys.log(7, ' constructed regex %s', regex)
|
||||||
self._cRegex = None
|
self._cRegex = None
|
||||||
|
|
||||||
regex = property(getRegex, setRegex, doc=
|
regex = property(getRegex, setRegex, doc=
|
||||||
|
@ -182,6 +184,14 @@ class DateTemplate(object):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError("getDate() is abstract")
|
raise NotImplementedError("getDate() is abstract")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unboundPattern(pattern):
|
||||||
|
return RE_EXEANC_BOUND_BEG.sub('',
|
||||||
|
RE_EXSANC_BOUND_BEG.sub('',
|
||||||
|
RE_EXLINE_BOUND_BEG.sub('', pattern)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DateEpoch(DateTemplate):
|
class DateEpoch(DateTemplate):
|
||||||
"""A date template which searches for Unix timestamps.
|
"""A date template which searches for Unix timestamps.
|
||||||
|
|
Loading…
Reference in New Issue