mirror of https://github.com/fail2ban/fail2ban
Merge branch '0.10' into 0.11
commit
64217fe018
|
@ -22,7 +22,7 @@ jobs:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, '3.10.0-beta.1', pypy2, pypy3]
|
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, '3.10.0-rc.2', pypy2, pypy3]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -726,7 +726,7 @@ class Filter(JailThread):
|
||||||
# incr common error counter:
|
# incr common error counter:
|
||||||
self.commonError()
|
self.commonError()
|
||||||
|
|
||||||
def commonError(self):
|
def commonError(self, reason="common", exc=None):
|
||||||
# incr error counter, stop processing (going idle) after 100th error :
|
# incr error counter, stop processing (going idle) after 100th error :
|
||||||
self._errors += 1
|
self._errors += 1
|
||||||
# sleep a little bit (to get around time-related errors):
|
# sleep a little bit (to get around time-related errors):
|
||||||
|
|
|
@ -122,7 +122,7 @@ class FilterPoll(FileFilter):
|
||||||
logSys.error("Caught unhandled exception in main cycle: %r", e,
|
logSys.error("Caught unhandled exception in main cycle: %r", e,
|
||||||
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||||
# incr common error counter:
|
# incr common error counter:
|
||||||
self.commonError()
|
self.commonError("unhandled", e)
|
||||||
logSys.debug("[%s] filter terminated", self.jailName)
|
logSys.debug("[%s] filter terminated", self.jailName)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ class FilterPyinotify(FileFilter):
|
||||||
return
|
return
|
||||||
found = {}
|
found = {}
|
||||||
minTime = 60
|
minTime = 60
|
||||||
for path, (retardTM, isDir) in self.__pending.iteritems():
|
for path, (retardTM, isDir) in list(self.__pending.items()):
|
||||||
if ntm - self.__pendingChkTime < retardTM:
|
if ntm - self.__pendingChkTime < retardTM:
|
||||||
if minTime > retardTM: minTime = retardTM
|
if minTime > retardTM: minTime = retardTM
|
||||||
continue
|
continue
|
||||||
|
@ -188,7 +188,7 @@ class FilterPyinotify(FileFilter):
|
||||||
self._refreshWatcher(path, isDir=isDir)
|
self._refreshWatcher(path, isDir=isDir)
|
||||||
if isDir:
|
if isDir:
|
||||||
# check all files belong to this dir:
|
# check all files belong to this dir:
|
||||||
for logpath in self.__watchFiles:
|
for logpath in list(self.__watchFiles):
|
||||||
if logpath.startswith(path + pathsep):
|
if logpath.startswith(path + pathsep):
|
||||||
# if still no file - add to pending, otherwise refresh and process:
|
# if still no file - add to pending, otherwise refresh and process:
|
||||||
if not os.path.isfile(logpath):
|
if not os.path.isfile(logpath):
|
||||||
|
@ -268,11 +268,9 @@ class FilterPyinotify(FileFilter):
|
||||||
|
|
||||||
def _addLogPath(self, path):
|
def _addLogPath(self, path):
|
||||||
self._addFileWatcher(path)
|
self._addFileWatcher(path)
|
||||||
# initial scan:
|
# notify (wake up if in waiting):
|
||||||
if self.active:
|
if self.active:
|
||||||
# we can execute it right now:
|
self.__pendingMinTime = 0
|
||||||
self._process_file(path)
|
|
||||||
else:
|
|
||||||
# retard until filter gets started, isDir=None signals special case: process file only (don't need to refresh monitor):
|
# retard until filter gets started, isDir=None signals special case: process file only (don't need to refresh monitor):
|
||||||
self._addPending(path, ('INITIAL', path), isDir=None)
|
self._addPending(path, ('INITIAL', path), isDir=None)
|
||||||
|
|
||||||
|
@ -287,7 +285,7 @@ class FilterPyinotify(FileFilter):
|
||||||
logSys.error("Failed to remove watch on path: %s", path)
|
logSys.error("Failed to remove watch on path: %s", path)
|
||||||
|
|
||||||
path_dir = dirname(path)
|
path_dir = dirname(path)
|
||||||
for k in self.__watchFiles:
|
for k in list(self.__watchFiles):
|
||||||
if k.startswith(path_dir + pathsep):
|
if k.startswith(path_dir + pathsep):
|
||||||
path_dir = None
|
path_dir = None
|
||||||
break
|
break
|
||||||
|
@ -341,11 +339,16 @@ class FilterPyinotify(FileFilter):
|
||||||
self.__notifier.process_events()
|
self.__notifier.process_events()
|
||||||
|
|
||||||
# wait for events / timeout:
|
# wait for events / timeout:
|
||||||
notify_maxtout = self.__notify_maxtout
|
|
||||||
def __check_events():
|
def __check_events():
|
||||||
return not self.active or self.__notifier.check_events(timeout=notify_maxtout)
|
return (
|
||||||
if Utils.wait_for(__check_events, min(self.sleeptime, self.__pendingMinTime)):
|
not self.active
|
||||||
|
or bool(self.__notifier.check_events(timeout=self.__notify_maxtout))
|
||||||
|
or (self.__pendingMinTime and self.__pending)
|
||||||
|
)
|
||||||
|
wres = Utils.wait_for(__check_events, min(self.sleeptime, self.__pendingMinTime))
|
||||||
|
if wres:
|
||||||
if not self.active: break
|
if not self.active: break
|
||||||
|
if not isinstance(wres, dict):
|
||||||
self.__notifier.read_events()
|
self.__notifier.read_events()
|
||||||
|
|
||||||
self.ticks += 1
|
self.ticks += 1
|
||||||
|
@ -363,7 +366,7 @@ class FilterPyinotify(FileFilter):
|
||||||
logSys.error("Caught unhandled exception in main cycle: %r", e,
|
logSys.error("Caught unhandled exception in main cycle: %r", e,
|
||||||
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||||
# incr common error counter:
|
# incr common error counter:
|
||||||
self.commonError()
|
self.commonError("unhandled", e)
|
||||||
|
|
||||||
logSys.debug("[%s] filter exited (pyinotifier)", self.jailName)
|
logSys.debug("[%s] filter exited (pyinotifier)", self.jailName)
|
||||||
self.__notifier = None
|
self.__notifier = None
|
||||||
|
|
|
@ -61,6 +61,7 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
||||||
# Initialise systemd-journal connection
|
# Initialise systemd-journal connection
|
||||||
self.__journal = journal.Reader(**jrnlargs)
|
self.__journal = journal.Reader(**jrnlargs)
|
||||||
self.__matches = []
|
self.__matches = []
|
||||||
|
self.__nextUpdateTM = 0
|
||||||
self.setDatePattern(None)
|
self.setDatePattern(None)
|
||||||
logSys.debug("Created FilterSystemd")
|
logSys.debug("Created FilterSystemd")
|
||||||
|
|
||||||
|
@ -285,6 +286,7 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
||||||
except OSError:
|
except OSError:
|
||||||
pass # Reading failure, so safe to ignore
|
pass # Reading failure, so safe to ignore
|
||||||
|
|
||||||
|
line = None
|
||||||
while self.active:
|
while self.active:
|
||||||
# wait for records (or for timeout in sleeptime seconds):
|
# wait for records (or for timeout in sleeptime seconds):
|
||||||
try:
|
try:
|
||||||
|
@ -326,15 +328,22 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
||||||
if self.ticks % 10 == 0:
|
if self.ticks % 10 == 0:
|
||||||
self.performSvc()
|
self.performSvc()
|
||||||
# update position in log (time and iso string):
|
# update position in log (time and iso string):
|
||||||
if self.jail.database is not None:
|
if (line and self.jail.database and (
|
||||||
|
self.ticks % 10 == 0
|
||||||
|
or MyTime.time() >= self.__nextUpdateTM
|
||||||
|
or not self.active
|
||||||
|
)
|
||||||
|
):
|
||||||
self.jail.database.updateJournal(self.jail, 'systemd-journal', line[1], line[0][1])
|
self.jail.database.updateJournal(self.jail, 'systemd-journal', line[1], line[0][1])
|
||||||
|
self.__nextUpdateTM = MyTime.time() + Utils.DEFAULT_SLEEP_TIME * 5
|
||||||
|
line = None
|
||||||
except Exception as e: # pragma: no cover
|
except Exception as e: # pragma: no cover
|
||||||
if not self.active: # if not active - error by stop...
|
if not self.active: # if not active - error by stop...
|
||||||
break
|
break
|
||||||
logSys.error("Caught unhandled exception in main cycle: %r", e,
|
logSys.error("Caught unhandled exception in main cycle: %r", e,
|
||||||
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||||
# incr common error counter:
|
# incr common error counter:
|
||||||
self.commonError()
|
self.commonError("unhandled", e)
|
||||||
|
|
||||||
logSys.debug("[%s] filter terminated", self.jailName)
|
logSys.debug("[%s] filter terminated", self.jailName)
|
||||||
|
|
||||||
|
|
|
@ -979,6 +979,10 @@ class CommonMonitorTestCase(unittest.TestCase):
|
||||||
super(CommonMonitorTestCase, self).setUp()
|
super(CommonMonitorTestCase, self).setUp()
|
||||||
self._failTotal = 0
|
self._failTotal = 0
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(CommonMonitorTestCase, self).tearDown()
|
||||||
|
self.assertFalse(hasattr(self, "_unexpectedError"))
|
||||||
|
|
||||||
def waitFailTotal(self, count, delay=1):
|
def waitFailTotal(self, count, delay=1):
|
||||||
"""Wait up to `delay` sec to assure that expected failure `count` reached
|
"""Wait up to `delay` sec to assure that expected failure `count` reached
|
||||||
"""
|
"""
|
||||||
|
@ -1004,6 +1008,16 @@ class CommonMonitorTestCase(unittest.TestCase):
|
||||||
last_ticks = self.filter.ticks
|
last_ticks = self.filter.ticks
|
||||||
return Utils.wait_for(lambda: self.filter.ticks >= last_ticks + ticks, _maxWaitTime(delay))
|
return Utils.wait_for(lambda: self.filter.ticks >= last_ticks + ticks, _maxWaitTime(delay))
|
||||||
|
|
||||||
|
def commonFltError(self, reason="common", exc=None):
|
||||||
|
""" Mock-up for default common error handler to find catched unhandled exceptions
|
||||||
|
could occur in filters
|
||||||
|
"""
|
||||||
|
self._commonFltError(reason, exc)
|
||||||
|
if reason == "unhandled":
|
||||||
|
DefLogSys.critical("Caught unhandled exception in main cycle of %r : %r", self.filter, exc, exc_info=True)
|
||||||
|
self._unexpectedError = True
|
||||||
|
# self.assertNotEqual(reason, "unhandled")
|
||||||
|
|
||||||
|
|
||||||
def get_monitor_failures_testcase(Filter_):
|
def get_monitor_failures_testcase(Filter_):
|
||||||
"""Generator of TestCase's for different filters/backends
|
"""Generator of TestCase's for different filters/backends
|
||||||
|
@ -1026,6 +1040,8 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
self.file = open(self.name, 'a')
|
self.file = open(self.name, 'a')
|
||||||
self.jail = DummyJail()
|
self.jail = DummyJail()
|
||||||
self.filter = Filter_(self.jail)
|
self.filter = Filter_(self.jail)
|
||||||
|
# mock-up common error to find catched unhandled exceptions:
|
||||||
|
self._commonFltError, self.filter.commonError = self.filter.commonError, self.commonFltError
|
||||||
self.filter.addLogPath(self.name, autoSeek=False)
|
self.filter.addLogPath(self.name, autoSeek=False)
|
||||||
# speedup search using exact date pattern:
|
# speedup search using exact date pattern:
|
||||||
self.filter.setDatePattern(r'^(?:%a )?%b %d %H:%M:%S(?:\.%f)?(?: %ExY)?')
|
self.filter.setDatePattern(r'^(?:%a )?%b %d %H:%M:%S(?:\.%f)?(?: %ExY)?')
|
||||||
|
@ -1324,6 +1340,8 @@ def get_monitor_failures_journal_testcase(Filter_): # pragma: systemd no cover
|
||||||
def _initFilter(self, **kwargs):
|
def _initFilter(self, **kwargs):
|
||||||
self._getRuntimeJournal() # check journal available
|
self._getRuntimeJournal() # check journal available
|
||||||
self.filter = Filter_(self.jail, **kwargs)
|
self.filter = Filter_(self.jail, **kwargs)
|
||||||
|
# mock-up common error to find catched unhandled exceptions:
|
||||||
|
self._commonFltError, self.filter.commonError = self.filter.commonError, self.commonFltError
|
||||||
self.filter.addJournalMatch([
|
self.filter.addJournalMatch([
|
||||||
"SYSLOG_IDENTIFIER=fail2ban-testcases",
|
"SYSLOG_IDENTIFIER=fail2ban-testcases",
|
||||||
"TEST_FIELD=1",
|
"TEST_FIELD=1",
|
||||||
|
|
Loading…
Reference in New Issue