mirror of https://github.com/fail2ban/fail2ban
code review and few new test cases
parent
5ca275876b
commit
697da99f8f
|
@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
|||
__license__ = "GPL"
|
||||
|
||||
import time, logging
|
||||
import os, datetime
|
||||
import os
|
||||
import sys
|
||||
if sys.version_info >= (3, 3):
|
||||
import importlib.machinery
|
||||
|
@ -322,21 +322,16 @@ class Actions(JailThread, Mapping):
|
|||
|
||||
if btime != -1:
|
||||
bendtime = aInfo["time"] + btime
|
||||
logtime = (datetime.timedelta(seconds=int(btime)),
|
||||
datetime.datetime.fromtimestamp(bendtime).strftime("%Y-%m-%d %H:%M:%S"))
|
||||
# check ban is not too old :
|
||||
if bendtime < MyTime.time():
|
||||
logSys.info('[%s] Ignore %s, expired bantime - %s', self._jail.name, ip, logtime[1])
|
||||
logSys.info('[%s] Ignore %s, expired bantime', self._jail.name, ip)
|
||||
return False
|
||||
else:
|
||||
logtime = ('permanent', 'infinite')
|
||||
|
||||
if self.__banManager.addBanTicket(bTicket):
|
||||
# report ticket to observer, to check time should be increased and hereafter observer writes ban to database (asynchronous)
|
||||
if Observers.Main is not None and not bTicket.getRestored():
|
||||
Observers.Main.add('banFound', bTicket, self._jail, btime)
|
||||
logSys.notice("[%s] %sBan %s (%s # %s -> %s)", self._jail.name, ('' if not bTicket.getRestored() else 'Restore '),
|
||||
aInfo["ip"], (bTicket.getBanCount() if bTicket.getRestored() else '_'), *logtime)
|
||||
logSys.notice("[%s] %sBan %s", self._jail.name, ('' if not bTicket.getRestored() else 'Restore '), aInfo["ip"])
|
||||
# do actions :
|
||||
for name, action in self._actions.iteritems():
|
||||
try:
|
||||
|
@ -349,8 +344,7 @@ class Actions(JailThread, Mapping):
|
|||
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
return True
|
||||
else:
|
||||
logSys.notice("[%s] %s already banned (%d # %s -> %s)" % ((self._jail.name,
|
||||
aInfo["ip"], bTicket.getBanCount()) + logtime))
|
||||
logSys.notice("[%s] %s already banned" % (self._jail.name, aInfo["ip"]))
|
||||
return False
|
||||
|
||||
def __checkUnBan(self):
|
||||
|
|
|
@ -98,7 +98,7 @@ class DateTemplate(object):
|
|||
return dateMatch
|
||||
|
||||
@abstractmethod
|
||||
def getDate(self, line, dateMatch = None):
|
||||
def getDate(self, line, dateMatch=None):
|
||||
"""Abstract method, which should return the date for a log line
|
||||
|
||||
This should return the date for a log line, typically taking the
|
||||
|
@ -134,7 +134,7 @@ class DateEpoch(DateTemplate):
|
|||
DateTemplate.__init__(self)
|
||||
self.regex = "(?:^|(?P<square>(?<=^\[))|(?P<selinux>(?<=audit\()))\d{10}(?:\.\d{3,6})?(?(selinux)(?=:\d+\))(?(square)(?=\])))"
|
||||
|
||||
def getDate(self, line, dateMatch = None):
|
||||
def getDate(self, line, dateMatch=None):
|
||||
"""Method to return the date for a log line.
|
||||
|
||||
Parameters
|
||||
|
@ -212,7 +212,7 @@ class DatePatternRegex(DateTemplate):
|
|||
def name(self, value):
|
||||
raise NotImplementedError("Name derived from pattern")
|
||||
|
||||
def getDate(self, line, dateMatch = None):
|
||||
def getDate(self, line, dateMatch=None):
|
||||
"""Method to return the date for a log line.
|
||||
|
||||
This uses a custom version of strptime, using the named groups
|
||||
|
@ -253,7 +253,7 @@ class DateTai64n(DateTemplate):
|
|||
# yoh: we should not add an additional front anchor
|
||||
self.setRegex("@[0-9a-f]{24}", wordBegin=False)
|
||||
|
||||
def getDate(self, line, dateMatch = None):
|
||||
def getDate(self, line, dateMatch=None):
|
||||
"""Method to return the date for a log line.
|
||||
|
||||
Parameters
|
||||
|
|
|
@ -275,7 +275,6 @@ class Jail:
|
|||
self.putFailTicket(ticket)
|
||||
except Exception as e: # pragma: no cover
|
||||
logSys.error('%s', e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
#logSys.error('%s', e, exc_info=True)
|
||||
|
||||
def start(self):
|
||||
"""Start the jail, by starting filter and actions threads.
|
||||
|
|
|
@ -108,9 +108,9 @@ class MyTime:
|
|||
1year-6mo = 15778800
|
||||
6 months = 15778800
|
||||
warn: month is not 30 days, it is a year in seconds / 12, the leap years will be respected also:
|
||||
>>>> float(Test.str2seconds("1month")) / 60 / 60 / 24
|
||||
>>>> float(str2seconds("1month")) / 60 / 60 / 24
|
||||
30.4375
|
||||
>>>> float(Test.str2seconds("1year")) / 60 / 60 / 24
|
||||
>>>> float(str2seconds("1year")) / 60 / 60 / 24
|
||||
365.25
|
||||
|
||||
@returns number (calculated seconds from expression "val")
|
||||
|
@ -121,9 +121,9 @@ class MyTime:
|
|||
val = re.sub(r"(?i)(?<=[a-z])(\d)", r" \1", val)
|
||||
# replace abbreviation with expression:
|
||||
for rexp, rpl in (
|
||||
(r"days?|da|dd?", 24*60*60), (r"week?|wee?|ww?", 7*24*60*60), (r"months?|mon?", (365*3+366)*24*60*60/4/12),
|
||||
(r"days?|da|dd?", 24*60*60), (r"weeks?|wee?|ww?", 7*24*60*60), (r"months?|mon?", (365*3+366)*24*60*60/4/12),
|
||||
(r"years?|yea?|yy?", (365*3+366)*24*60*60/4),
|
||||
(r"seconds?|sec?|ss?", 1), (r"minutes?|min?|mm?", 60), (r"hours?|ho|hh?", 60*60),
|
||||
(r"seconds?|sec?|ss?", 1), (r"minutes?|min?|mm?", 60), (r"hours?|hou?|hh?", 60*60),
|
||||
):
|
||||
val = re.sub(r"(?i)(?<=[\d\s])(%s)\b" % rexp, "*"+str(rpl), val)
|
||||
val = re.sub(r"(\d)\s+(\d)", r"\1+\2", val);
|
||||
|
|
|
@ -389,7 +389,6 @@ class ObserverThread(JailThread):
|
|||
|
||||
except Exception as e:
|
||||
logSys.error('%s', e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
#logSys.error('%s', e, exc_info=True)
|
||||
|
||||
|
||||
class BanTimeIncr:
|
||||
|
@ -438,7 +437,6 @@ class ObserverThread(JailThread):
|
|||
break
|
||||
except Exception as e:
|
||||
logSys.error('%s', e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
#logSys.error('%s', e, exc_info=True)
|
||||
return banTime
|
||||
|
||||
def banFound(self, ticket, jail, btime):
|
||||
|
@ -480,7 +478,6 @@ class ObserverThread(JailThread):
|
|||
jail.database.addBan(jail, ticket)
|
||||
except Exception as e:
|
||||
logSys.error('%s', e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
#logSys.error('%s', e, exc_info=True)
|
||||
|
||||
# Global observer initial created in server (could be later rewriten via singleton)
|
||||
class _Observers:
|
||||
|
|
|
@ -34,6 +34,7 @@ from StringIO import StringIO
|
|||
|
||||
from ..helpers import formatExceptionInfo, mbasename, TraceBack, FormatterWithTraceBack, getLogger
|
||||
from ..server.datetemplate import DatePatternRegex
|
||||
from ..server.mytime import MyTime
|
||||
|
||||
|
||||
class HelpersTest(unittest.TestCase):
|
||||
|
@ -211,3 +212,20 @@ class CustomDateFormatsTest(unittest.TestCase):
|
|||
self.assertEqual(
|
||||
date,
|
||||
datetime.datetime(2007, 1, 25, 16, 0))
|
||||
|
||||
class MyTimeTest(unittest.TestCase):
|
||||
|
||||
def testStr2Seconds(self):
|
||||
# several formats / write styles:
|
||||
str2sec = MyTime.str2seconds
|
||||
self.assertEqual(str2sec('1y6mo30w15d12h35m25s'), 66821725)
|
||||
self.assertEqual(str2sec('2yy 3mo 4ww 10dd 5hh 30mm 20ss'), 74307620)
|
||||
self.assertEqual(str2sec('2 years 3 months 4 weeks 10 days 5 hours 30 minutes 20 seconds'), 74307620)
|
||||
self.assertEqual(str2sec('1 year + 1 month - 1 week + 1 day'), 33669000)
|
||||
self.assertEqual(str2sec('2 * 0.5 yea + 1*1 mon - 3*1/3 wee + 2/2 day - (2*12 hou 3*20 min 80 sec) '), 33578920.0)
|
||||
self.assertEqual(str2sec('2*.5y+1*1mo-3*1/3w+2/2d-(2*12h3*20m80s) '), 33578920.0)
|
||||
self.assertEqual(str2sec('1ye -2mo -3we -4da -5ho -6mi -7se'), 24119633)
|
||||
# month and year in days :
|
||||
self.assertEqual(float(str2sec("1 month")) / 60 / 60 / 24, 30.4375)
|
||||
self.assertEqual(float(str2sec("1 year")) / 60 / 60 / 24, 365.25)
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ class BanTimeIncr(LogCaptureTestCase):
|
|||
arr = arr[0:multcnt-1] + ([arr[multcnt-2]] * (11-multcnt))
|
||||
self.assertEqual(
|
||||
[a.calcBanTime(600, i) for i in xrange(1, 11)],
|
||||
arr
|
||||
arr
|
||||
)
|
||||
a.setBanTimeExtra('maxtime', '1d')
|
||||
# change factor :
|
||||
|
@ -377,20 +377,20 @@ class BanTimeIncrDB(unittest.TestCase):
|
|||
self.assertEqual(len(restored_tickets), 2)
|
||||
self.assertEqual(restored_tickets[0].getIP(), ip)
|
||||
|
||||
# purge remove 1st ip
|
||||
# purge remove 1st ip
|
||||
self.db._purgeAge = -48*60*60
|
||||
self.db.purge()
|
||||
restored_tickets = self.db.getCurrentBans(fromtime=stime)
|
||||
self.assertEqual(len(restored_tickets), 1)
|
||||
self.assertEqual(restored_tickets[0].getIP(), ip+'1')
|
||||
|
||||
# this should purge all bans, bips and logs - nothing should be found now
|
||||
# this should purge all bans, bips and logs - nothing should be found now
|
||||
self.db._purgeAge = -240*60*60
|
||||
self.db.purge()
|
||||
restored_tickets = self.db.getCurrentBans(fromtime=stime)
|
||||
self.assertEqual(restored_tickets, [])
|
||||
|
||||
# two separate jails :
|
||||
# two separate jails :
|
||||
jail1 = DummyJail(backend='polling')
|
||||
jail1.database = self.db
|
||||
self.db.addJail(jail1)
|
||||
|
@ -418,14 +418,14 @@ class BanTimeIncrDB(unittest.TestCase):
|
|||
str(restored_tickets[0]),
|
||||
'FailTicket: ip=%s time=%s bantime=%s bancount=2 #attempts=0 matches=[]' % (ip, stime-6000, 12000)
|
||||
)
|
||||
# get last ban values for this ip separately for each jail:
|
||||
# get last ban values for this ip separately for each jail:
|
||||
for row in self.db.getBan(ip, jail1):
|
||||
self.assertEqual(row, (1, stime, 6000))
|
||||
break
|
||||
for row in self.db.getBan(ip, jail2):
|
||||
self.assertEqual(row, (2, stime-6000, 12000))
|
||||
break
|
||||
# get max values for this ip (over all jails):
|
||||
# get max values for this ip (over all jails):
|
||||
for row in self.db.getBan(ip, overalljails=True):
|
||||
self.assertEqual(row, (3, stime, 18000))
|
||||
break
|
||||
|
@ -477,7 +477,7 @@ class BanTimeIncrDB(unittest.TestCase):
|
|||
obs.add('failureFound', failManager, jail, ticket)
|
||||
obs.wait_empty(5)
|
||||
self.assertEqual(ticket.getBanCount(), 0)
|
||||
# check still not ban :
|
||||
# check still not ban :
|
||||
self.assertTrue(not jail.getFailTicket())
|
||||
# add manually 4th times banned (added to bips - make ip bad):
|
||||
ticket.setBanCount(4)
|
||||
|
@ -493,11 +493,14 @@ class BanTimeIncrDB(unittest.TestCase):
|
|||
obs.add('failureFound', failManager, self.jail, ticket)
|
||||
obs.wait_empty(5)
|
||||
# wait until ticket transfered from failmanager into jail:
|
||||
to = int(MyTime.time())+30
|
||||
while True:
|
||||
ticket2 = jail.getFailTicket()
|
||||
if ticket2:
|
||||
break
|
||||
time.sleep(0.1)
|
||||
if MyTime.time() > to: # pragma: no cover
|
||||
raise RuntimeError('unexpected timeout: wait 30 seconds instead of few ms.')
|
||||
# check ticket and failure count:
|
||||
self.assertFalse(not ticket2)
|
||||
self.assertEqual(ticket2.getAttempt(), failManager.getMaxRetry())
|
||||
|
@ -509,7 +512,7 @@ class BanTimeIncrDB(unittest.TestCase):
|
|||
self.assertEqual(ticket2.getBanTime(), 160)
|
||||
self.assertEqual(ticket2.getBanCount(), 5)
|
||||
|
||||
# check prolonged in database also :
|
||||
# check prolonged in database also :
|
||||
restored_tickets = self.db.getCurrentBans(jail=jail, fromtime=stime)
|
||||
self.assertEqual(len(restored_tickets), 1)
|
||||
self.assertEqual(restored_tickets[0].getBanTime(), 160)
|
||||
|
|
|
@ -121,6 +121,7 @@ def gatherTests(regexps=None, no_network=False):
|
|||
tests.addTest(unittest.makeSuite(misctestcase.SetupTest))
|
||||
tests.addTest(unittest.makeSuite(misctestcase.TestsUtilsTest))
|
||||
tests.addTest(unittest.makeSuite(misctestcase.CustomDateFormatsTest))
|
||||
tests.addTest(unittest.makeSuite(misctestcase.MyTimeTest))
|
||||
# Database
|
||||
tests.addTest(unittest.makeSuite(databasetestcase.DatabaseTest))
|
||||
# Observer
|
||||
|
|
Loading…
Reference in New Issue