From 2e533a3a3a4f9eda488f84d370c4731fa5f54dd0 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 9 Mar 2018 13:54:04 +0100 Subject: [PATCH] better handling of default date templates (bounds, replacement using own expressions `...{DATE}...`, etc.) --- fail2ban/server/datedetector.py | 70 +++++++++++++++++++-------------- fail2ban/server/datetemplate.py | 14 ++++++- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/fail2ban/server/datedetector.py b/fail2ban/server/datedetector.py index 13d70699..2e85b940 100644 --- a/fail2ban/server/datedetector.py +++ b/fail2ban/server/datedetector.py @@ -109,9 +109,6 @@ class DateDetectorCache(object): """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 # at start of a line (safety+performance feature): name = template.name @@ -126,60 +123,74 @@ class DateDetectorCache(object): # add template: self.__tmpcache[1].append(template) - def _addDefaultTemplate(self): - """Add resp. cache Fail2Ban's default set of date templates. - """ - self.__tmpcache = [], [] + DEFAULT_TEMPLATES = [ # 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 # simple date: 2005/01/23 21:59:59 # 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: # 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 # http://bugs.debian.org/798923 # 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 # and with optional year given by 2 digits: 23/01/05 21:59:59 # (See http://bugs.debian.org/537610) # 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: # [31/Oct/2006:09:22:55 -0000] # 26-Jul-2007 15:20:52 # named 26-Jul-2007 15:20:52.252 # 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 - self._cacheTemplate("%m/%d/%ExY:%H:%M:%S") + "%m/%d/%ExY:%H:%M:%S", # 01-27-2012 16:22:44.252 # 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") - self._cacheTemplate("%m-%d-%ExY %k:%M:%S(?:\.%f)?") + "%m-%d-%ExY %k:%M:%S(?:\.%f)?", # Epoch - self._cacheTemplate('EPOCH') + "EPOCH", # Only time information in the log - self._cacheTemplate("{^LN-BEG}%H:%M:%S") + "{^LN-BEG}%H:%M:%S", # <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 - self._cacheTemplate("%Exy%Exm%Exd ?%H:%M:%S") + "%Exy%Exm%Exd ?%H:%M:%S", # 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 - self._cacheTemplate("^%b-%d-%Exy %k:%M:%S") + "^%b-%d-%Exy %k:%M:%S", # 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): # 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 - self._cacheTemplate("(?:%z )?(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?") + "(?:%z )?(?:%a )?%b %d %k:%M:%S(?:\.%f)?(?: %ExY)?", # 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] del self.__tmpcache @@ -269,8 +280,7 @@ class DateDetector(object): self.addDefaultTemplate(flt) return elif "{DATE}" in key: - self.addDefaultTemplate( - lambda template: not template.flags & DateTemplate.LINE_BEGIN, pattern) + self.addDefaultTemplate(preMatch=pattern, allDefaults=False) return else: template = _getPatternTemplate(pattern, key) @@ -283,18 +293,20 @@ class DateDetector(object): logSys.debug(" date pattern regex for %r: %s", 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. """ 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: 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 preMatch is not None: # get cached or create a copy with modified name/pattern, using preMatch replacement for {DATE}: 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): self._appendTemplate(template, ignoreDup=ignoreDup) diff --git a/fail2ban/server/datetemplate.py b/fail2ban/server/datetemplate.py index 49fa0c66..606ba6ec 100644 --- a/fail2ban/server/datetemplate.py +++ b/fail2ban/server/datetemplate.py @@ -37,8 +37,10 @@ RE_GROUPED = re.compile(r'(?