better handling of default date templates (bounds, replacement using own expressions `...{DATE}...`, etc.)

pull/2087/head
sebres 2018-03-09 13:54:04 +01:00
parent ce6ca0029a
commit 2e533a3a3a
2 changed files with 53 additions and 31 deletions

View File

@ -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)

View File

@ -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.