diff --git a/fail2ban/server/datetemplate.py b/fail2ban/server/datetemplate.py index cd4592c7..49fa0c66 100644 --- a/fail2ban/server/datetemplate.py +++ b/fail2ban/server/datetemplate.py @@ -199,12 +199,15 @@ class DateEpoch(DateTemplate): DateTemplate.__init__(self) self.name = "Epoch" self._longFrm = longFrm; + self._grpIdx = 1 epochRE = r"\d{10,11}\b(?:\.\d{3,6})?" if longFrm: self.name = "LongEpoch"; - epochRE = r"\d{10,11}(?:\d{3}(?:\d{3})?)?" + epochRE = r"\d{10,11}(?:\d{3}(?:\.\d{1,6}|\d{3})?)?" if pattern: - regex = RE_EPOCH_PATTERN.sub(lambda v: "(%s)" % epochRE, pattern) + # pattern should capture/cut out the whole match: + regex = "(" + RE_EPOCH_PATTERN.sub(lambda v: "(%s)" % epochRE, pattern) + ")" + self._grpIdx = 2 self.setRegex(regex) elif not lineBeginOnly: regex = r"((?:^|(?P(?<=^\[))|(?P(?<=\baudit\()))%s)(?:(?(selinux)(?=:\d+\)))|(?(square)(?=\])))" % epochRE @@ -231,10 +234,10 @@ class DateEpoch(DateTemplate): if not dateMatch: dateMatch = self.matchDate(line) if dateMatch: - v = dateMatch.group(1) + v = dateMatch.group(self._grpIdx) # extract part of format which represents seconds since epoch if self._longFrm and len(v) >= 13: - if len(v) >= 16: + if len(v) >= 16 and '.' not in v: v = float(v) / 1000000 else: v = float(v) / 1000 diff --git a/fail2ban/tests/datedetectortestcase.py b/fail2ban/tests/datedetectortestcase.py index 69473c9d..36471489 100644 --- a/fail2ban/tests/datedetectortestcase.py +++ b/fail2ban/tests/datedetectortestcase.py @@ -103,7 +103,7 @@ class DateDetectorTest(LogCaptureTestCase): def testGetEpochPattern(self): self.__datedetector = DateDetector() - self.__datedetector.appendTemplate('\|\s{LEPOCH}(?=\s\|)') + self.__datedetector.appendTemplate('(?<=\|\s){LEPOCH}(?=\s\|)') # correct short/long epoch time, using all variants: for fact in (1, 1000, 1000000): for dateUnix in (1138049999, 32535244799): diff --git a/fail2ban/tests/fail2banregextestcase.py b/fail2ban/tests/fail2banregextestcase.py index f3a51773..148d774c 100644 --- a/fail2ban/tests/fail2banregextestcase.py +++ b/fail2ban/tests/fail2banregextestcase.py @@ -290,6 +290,17 @@ class Fail2banRegexTest(LogCaptureTestCase): self.assertTrue(fail2banRegex.start(args)) self.assertLogged('Lines: 1 lines, 0 ignored, 1 matched, 0 missed') + def testRegexEpochPatterns(self): + (opts, args, fail2banRegex) = _Fail2banRegex( + "-r", "-d", "^\[{LEPOCH}\]\s+", "--maxlines", "5", + "[1516469849] 192.0.2.1 FAIL: failure\n" + "[1516469849551] 192.0.2.2 FAIL: failure\n" + "[1516469849551000] 192.0.2.3 FAIL: failure\n" + "[1516469849551.000] 192.0.2.4 FAIL: failure", + r"^ FAIL\b" + ) + self.assertTrue(fail2banRegex.start(args)) + self.assertLogged('Lines: 4 lines, 0 ignored, 4 matched, 0 missed') def testWrongFilterFile(self): # use test log as filter file to cover eror cases...