Skip to content

Instantly share code, notes, and snippets.

@kwirk
Created May 2, 2013 22:34
Show Gist options
  • Save kwirk/5506003 to your computer and use it in GitHub Desktop.
Save kwirk/5506003 to your computer and use it in GitHub Desktop.
fail2ban/fail2ban date detector ideas
diff --git a/fail2ban/server/datedetector.py b/fail2ban/server/datedetector.py
index a29c975..734131d 100644
--- a/fail2ban/server/datedetector.py
+++ b/fail2ban/server/datedetector.py
@@ -29,7 +29,7 @@ __license__ = "GPL"
import time, logging
-from datetemplate import DateStrptime, DateTai64n, DateEpoch, DateISO8601
+from datetemplate import DatePatternRegex, DateTai64n, DateEpoch, DateISO8601
from threading import Lock
# Gets the instance of the logger.
@@ -42,7 +42,7 @@ class DateDetector:
self.__templates = list()
self.__known_names = set()
- def _appendTemplate(self, template):
+ def appendTemplate(self, template):
name = template.getName()
if name in self.__known_names:
raise ValueError("There is already a template with name %s" % name)
@@ -53,120 +53,86 @@ class DateDetector:
self.__lock.acquire()
try:
# standard
- template = DateStrptime()
- template.setName("MONTH Day Hour:Minute:Second")
- template.setRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%b %d %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# asctime
- template = DateStrptime()
- template.setName("WEEKDAY MONTH Day Hour:Minute:Second Year")
- template.setRegex("\S{3} \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2} \d{4}")
+ template = DatePatternRegex()
template.setPattern("%a %b %d %H:%M:%S %Y")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# asctime without year
- template = DateStrptime()
- template.setName("WEEKDAY MONTH Day Hour:Minute:Second")
- template.setRegex("\S{3} \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%a %b %d %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# simple date
- template = DateStrptime()
- template.setName("Year/Month/Day Hour:Minute:Second")
- template.setRegex("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%Y/%m/%d %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# simple date too (from x11vnc)
- template = DateStrptime()
- template.setName("Day/Month/Year Hour:Minute:Second")
- template.setRegex("\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%d/%m/%Y %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# previous one but with year given by 2 digits
# (See http://bugs.debian.org/537610)
- template = DateStrptime()
- template.setName("Day/Month/Year2 Hour:Minute:Second")
- template.setRegex("\d{2}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%d/%m/%y %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# Apache format [31/Oct/2006:09:22:55 -0000]
- template = DateStrptime()
- template.setName("Day/MONTH/Year:Hour:Minute:Second")
- template.setRegex("\d{2}/\S{3}/\d{4}:\d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%d/%b/%Y:%H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# CPanel 05/20/2008:01:57:39
- template = DateStrptime()
- template.setName("Month/Day/Year:Hour:Minute:Second")
- template.setRegex("\d{2}/\d{2}/\d{4}:\d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%m/%d/%Y:%H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# Exim 2006-12-21 06:43:20
- template = DateStrptime()
- template.setName("Year-Month-Day Hour:Minute:Second")
- template.setRegex("\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%Y-%m-%d %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# custom for syslog-ng 2006.12.21 06:43:20
- template = DateStrptime()
- template.setName("Year.Month.Day Hour:Minute:Second")
- template.setRegex("\d{4}.\d{2}.\d{2} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%Y.%m.%d %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# named 26-Jul-2007 15:20:52.252
- template = DateStrptime()
- template.setName("Day-MONTH-Year Hour:Minute:Second[.Millisecond]")
- template.setRegex("\d{2}-\S{3}-\d{4} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%d-%b-%Y %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# 17-07-2008 17:23:25
- template = DateStrptime()
- template.setName("Day-Month-Year Hour:Minute:Second")
- template.setRegex("\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%d-%m-%Y %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# 01-27-2012 16:22:44.252
- template = DateStrptime()
- template.setName("Month-Day-Year Hour:Minute:Second[.Millisecond]")
- template.setRegex("\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}")
+ template = DatePatternRegex()
template.setPattern("%m-%d-%Y %H:%M:%S")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# TAI64N
template = DateTai64n()
template.setName("TAI64N")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# Epoch
template = DateEpoch()
template.setName("Epoch")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# ISO 8601
template = DateISO8601()
template.setName("ISO 8601")
- self._appendTemplate(template)
+ self.appendTemplate(template)
# Only time information in the log
- template = DateStrptime()
- template.setName("Hour:Minute:Second")
- template.setRegex("^\d{2}:\d{2}:\d{2}")
- template.setPattern("%H:%M:%S")
- self._appendTemplate(template)
+ template = DatePatternRegex()
+ template.setPattern("%H:%M:%S", anchor=True)
+ self.appendTemplate(template)
# <09/16/08@05:03:30>
- template = DateStrptime()
- template.setName("<Month/Day/Year@Hour:Minute:Second>")
- template.setRegex("^<\d{2}/\d{2}/\d{2}@\d{2}:\d{2}:\d{2}>")
- template.setPattern("<%m/%d/%y@%H:%M:%S>")
- self._appendTemplate(template)
+ template = DatePatternRegex()
+ template.setPattern("<%m/%d/%y@%H:%M:%S>", anchor=True)
+ self.appendTemplate(template)
# MySQL: 130322 11:46:11
- template = DateStrptime()
- template.setName("MonthDayYear Hour:Minute:Second")
- template.setRegex("^\d{2}\d{2}\d{2} +\d{1,2}:\d{2}:\d{2}")
- template.setPattern("%y%m%d %H:%M:%S")
- self._appendTemplate(template)
+ template = DatePatternRegex()
+ template.setPattern("%y%m%d %H:%M:%S", anchor=True)
+ self.appendTemplate(template)
# Apache Tomcat
- template = DateStrptime()
- template.setName("MONTH Day, Year 12hour:Minute:Second AM/PM")
- template.setRegex("\S{3}\s{1,2}\d{1,2}, \d{4} \d{1,2}:\d{2}:\d{2} [AP]M")
+ template = DatePatternRegex()
template.setPattern("%b %d, %Y %I:%M:%S %p")
- self._appendTemplate(template)
+ self.appendTemplate(template)
finally:
self.__lock.release()
diff --git a/fail2ban/server/datetemplate.py b/fail2ban/server/datetemplate.py
index f77f00c..f378c38 100644
--- a/fail2ban/server/datetemplate.py
+++ b/fail2ban/server/datetemplate.py
@@ -180,6 +180,48 @@ class DateStrptime(DateTemplate):
date[2] = MyTime.gmtime()[2]
return date
+class DatePatternRegex(DateStrptime):
+ _patternRE = r"\%([aAbBdHIjmMpSUwWyY])"
+ _patternName = {
+ 'a': "DAY", 'A': "DAYNAME", 'b': "MON", 'B': "MONTH", 'd': "Day",
+ 'H': "24hour", 'I': "12hour", 'j': "Yearday", 'm': "Month",
+ 'M': "Minute", 'p': "AMPM", 'S': "Second", 'U': "Yearweek",
+ 'w': "Weekday", 'W': "Yearweek", "y": 'Year2', "Y": "Year"}
+ _patternRegex = {
+ 'a': r"\S{3}", 'A': r"\S+", 'b': r"\S{3}", 'B': r"\S+",
+ 'd': r"(?:3[0-1]|[1-2]\d|[ 0]?\d)", 'H': r"(?:2[0-4]|1\d|[ 0]?\d)",
+ 'I': r"(?:1[0-2]|0?\d)",
+ 'j': r"(?:3[0-6][0-6]|[1-2]\d\d|0?\d\d|0{0,2}\d)",
+ 'm': r"(?:1[0-2]|[ 0]?[1-9])", 'M': r"[0-5]\d", 'p': r"[AP]M",
+ 'S': r"(?:6[01]|[0-5]\d)", 'U': r"(?:5[0-3]|[1-4]\d|[ 0]?\d)",
+ 'w': r"[0-6]", 'W': r"(?:5[0-3]|[ 0]?\d)", 'y': r"\d{2}",
+ 'Y': r"\d{4}"}
+
+ def __init__(self):
+ DateTemplate.__init__(self)
+ self.__pattern = ""
+
+ def setPattern(self, pattern, anchor=False, wordBegin=True):
+ self.__pattern = pattern.strip()
+
+ name = re.sub(self._patternRE, r'%(\1)s', pattern) % self._patternName
+ DateStrptime.setName(self, name)
+
+ pattern = re.escape(pattern)
+ regex = re.sub(
+ r"\\" + self._patternRE, r'%(\1)s', pattern) % self._patternRegex
+ if anchor:
+ regex = r"^" + regex
+ DateStrptime.setRegex(self, regex, wordBegin)
+
+ def getPattern(self):
+ return self.__pattern
+
+ def setRegex(self, line):
+ raise NotImplementedError("Regex derived from pattern")
+
+ def setName(self, line):
+ raise NotImplementedError("Name derived from pattern")
class DateTai64n(DateTemplate):
diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py
index d4108dc..8a799c7 100644
--- a/fail2ban/server/filter.py
+++ b/fail2ban/server/filter.py
@@ -32,6 +32,7 @@ from failmanager import FailManager
from ticket import FailTicket
from jailthread import JailThread
from datedetector import DateDetector
+from datetemplate import DatePatternRegex
from mytime import MyTime
from failregex import FailRegex, Regex, RegexException
@@ -196,6 +197,42 @@ class Filter(JailThread):
return self.__findTime
##
+ # Set the date detector pattern
+ #
+ # @param pattern the date template pattern
+
+ def setDatePattern(self, pattern):
+ template = DatePatternRegex()
+ if pattern[0] == "^": # Special extra to enable anchor
+ template.setPattern(pattern[1:], anchor=True)
+ else:
+ template.setPattern(pattern)
+ dateDetector = DateDetector()
+ dateDetector.appendTemplate(template)
+ self.dateDetector = dateDetector
+ logSys.info("Date format set to `%r`: `%s`" %
+ (pattern, template.getName()))
+ logSys.debug("Date format regex: %s" % (template.getRegex()))
+
+ ##
+ # Get the date detector pattern
+ #
+ # @return pattern of the date template pattern
+
+ def getDatePattern(self):
+ templates = self.dateDetector.getTemplates()
+ if len(templates) > 1:
+ return "Default Detectors"
+ elif len(templates) == 1:
+ pattern = templates[0].getPattern()
+ if templates[0].getRegex()[0] == "^":
+ return "^" + pattern
+ else:
+ return pattern
+ else:
+ raise RuntimeError("Oh dear...")
+
+ ##
# Set the maximum retry value.
#
# @param value the retry value
diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py
index 092867b..c4a9674 100644
--- a/fail2ban/server/server.py
+++ b/fail2ban/server/server.py
@@ -193,6 +193,12 @@ class Server:
def getFindTime(self, name):
return self.__jails.getFilter(name).getFindTime()
+ def setDatePattern(self, name, pattern):
+ self.__jails.getFilter(name).setDatePattern(pattern)
+
+ def getDatePattern(self, name):
+ return self.__jails.getFilter(name).getDatePattern()
+
def addFailRegex(self, name, value):
self.__jails.getFilter(name).addFailRegex(value)
diff --git a/fail2ban/server/transmitter.py b/fail2ban/server/transmitter.py
index b293217..6ed4e18 100644
--- a/fail2ban/server/transmitter.py
+++ b/fail2ban/server/transmitter.py
@@ -171,6 +171,10 @@ class Transmitter:
value = command[2]
self.__server.setFindTime(name, int(value))
return self.__server.getFindTime(name)
+ elif command[1] == "datepattern":
+ value = command[2]
+ self.__server.setDatePattern(name, value)
+ return self.__server.getDatePattern(name)
elif command[1] == "maxretry":
value = command[2]
self.__server.setMaxRetry(name, int(value))
@@ -258,6 +262,8 @@ class Transmitter:
return self.__server.getUseDns(name)
elif command[1] == "findtime":
return self.__server.getFindTime(name)
+ elif command[1] == "datepattern":
+ return self.__server.getDatePattern(name)
elif command[1] == "maxretry":
return self.__server.getMaxRetry(name)
elif command[1] == "maxlines":
diff --git a/fail2ban/tests/datedetectortestcase.py b/fail2ban/tests/datedetectortestcase.py
index 534abdb..ffd4925 100644
--- a/fail2ban/tests/datedetectortestcase.py
+++ b/fail2ban/tests/datedetectortestcase.py
@@ -106,7 +106,7 @@ class DateDetectorTest(unittest.TestCase):
self.assertEqual(old_name, n.getName()) # "Sort must be stable"
def testAllUniqueTemplateNames(self):
- self.assertRaises(ValueError, self.__datedetector._appendTemplate,
+ self.assertRaises(ValueError, self.__datedetector.appendTemplate,
self.__datedetector.getTemplates()[0])
def testFullYearMatch_gh130(self):
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment