diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index ac64fb86..13538c66 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -100,6 +100,10 @@ class Filter(JailThread): def __repr__(self): return "%s(%r)" % (self.__class__.__name__, self.jail) + @property + def jailName(self): + return (self.jail is not None and self.jail.name or "~jailless~") + def clearAllParams(self): """ Clear all lists/dicts parameters (used by reloading) """ @@ -135,7 +139,7 @@ class Filter(JailThread): if "\n" in regex.getRegex() and not self.getMaxLines() > 1: logSys.warning( "Mutliline regex set for jail %r " - "but maxlines not greater than 1", self.jail.name) + "but maxlines not greater than 1", self.jailName) except RegexException as e: logSys.error(e) raise e @@ -420,7 +424,7 @@ class Filter(JailThread): def logIgnoreIp(self, ip, log_ignore, ignore_source="unknown source"): if log_ignore: - logSys.info("[%s] Ignore %s by %s" % (self.jail.name, ip, ignore_source)) + logSys.info("[%s] Ignore %s by %s" % (self.jailName, ip, ignore_source)) def getIgnoreIP(self): return self.__ignoreIpList @@ -491,7 +495,7 @@ class Filter(JailThread): if self.inIgnoreIPList(ip, log_ignore=True): continue logSys.info( - "[%s] Found %s - %s", self.jail.name, ip, datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S") + "[%s] Found %s - %s", self.jailName, ip, datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S") ) tick = FailTicket(ip, unixTime, lines, data=fail) self.failManager.addFailure(tick) diff --git a/fail2ban/server/filtergamin.py b/fail2ban/server/filtergamin.py index a8d03ebd..106e4c0f 100644 --- a/fail2ban/server/filtergamin.py +++ b/fail2ban/server/filtergamin.py @@ -132,7 +132,7 @@ class FilterGamin(FileFilter): Utils.wait_for(lambda: not self.active or self._handleEvents(), self.sleeptime) self.ticks += 1 - logSys.debug(self.jail.name + ": filter terminated") + logSys.debug("[%s] filter terminated", self.jailName) return True def stop(self): diff --git a/fail2ban/server/filterpoll.py b/fail2ban/server/filterpoll.py index d0660f15..abf16e1b 100644 --- a/fail2ban/server/filterpoll.py +++ b/fail2ban/server/filterpoll.py @@ -123,9 +123,7 @@ class FilterPoll(FileFilter): except FailManagerEmpty: self.failManager.cleanup(MyTime.time()) self.__modified = False - logSys.debug( - (self.jail is not None and self.jail.name or "jailless") + - " filter terminated") + logSys.debug("[%s] filter terminated", self.jailName) return True ## diff --git a/fail2ban/server/filterpyinotify.py b/fail2ban/server/filterpyinotify.py index 9b444844..6ddf1691 100644 --- a/fail2ban/server/filterpyinotify.py +++ b/fail2ban/server/filterpyinotify.py @@ -198,7 +198,7 @@ class FilterPyinotify(FileFilter): prcevent, timeout=self.sleeptime) self.__notifier.check_events = self.__check_events self.__notifier.start() - logSys.debug("pyinotifier started for %s.", self.jail.name) + logSys.debug("[%s] filter started (pyinotifier)", self.jailName) return True ## @@ -206,15 +206,22 @@ class FilterPyinotify(FileFilter): def stop(self): super(FilterPyinotify, self).stop() - # Stop the notifier thread self.__notifier.stop() - self.__notifier.join() # to not exit before notifier does - self.__cleanup() # for pedantic ones + + ## + # Wait for exit with cleanup. + + def join(self): + self.__cleanup() + super(FilterPyinotify, self).join() + logSys.debug("[%s] filter terminated (pyinotifier)", self.jailName) ## # Deallocates the resources used by pyinotify. def __cleanup(self): - self.__notifier = None + if self.__notifier: + self.__notifier.join() # to not exit before notifier does + self.__notifier = None self.__monitor = None diff --git a/fail2ban/server/filtersystemd.py b/fail2ban/server/filtersystemd.py index a29085ba..310d15b3 100644 --- a/fail2ban/server/filtersystemd.py +++ b/fail2ban/server/filtersystemd.py @@ -130,7 +130,8 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover self.resetJournalMatches() raise else: - logSys.info("Added journal match for: %r", " ".join(match)) + logSys.info("[%s] Added journal match for: %r", self.jailName, + " ".join(match)) ## # Reset a journal match filter called on removal or failure # @@ -138,7 +139,7 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover def resetJournalMatches(self): self.__journal.flush_matches() - logSys.debug("Flushed all journal matches") + logSys.debug("[%s] Flushed all journal matches", self.jailName) match_copy = self.__matches[:] self.__matches = [] try: @@ -157,14 +158,17 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover def delJournalMatch(self, match=None): # clear all: if match is None: + if not self.__matches: + return del self.__matches[:] # delete by index: elif match in self.__matches: del self.__matches[self.__matches.index(match)] else: - raise ValueError("Match not found") + raise ValueError("Match %r not found" % match) self.resetJournalMatches() - logSys.info("Removed journal match for: %r" % " ".join(match)) + logSys.info("[%s] Removed journal match for: %r", self.jailName, + match if match else '*') ## # Get current journal match filter @@ -214,8 +218,8 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover date = logentry.get('_SOURCE_REALTIME_TIMESTAMP', logentry.get('__REALTIME_TIMESTAMP')) - logSys.debug("Read systemd journal entry: %r" % - "".join([date.isoformat(), logline])) + logSys.debug("[%s] Read systemd journal entry: %s %s", self.jailName, + date.isoformat(), logline) ## use the same type for 1st argument: return ((logline[:0], date.isoformat(), logline), time.mktime(date.timetuple()) + date.microsecond/1.0E6) @@ -302,6 +306,7 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover # incr common error counter: self.commonError() + logSys.debug("[%s] filter terminated", self.jailName) # close journal: try: if self.__journal: diff --git a/fail2ban/server/jail.py b/fail2ban/server/jail.py index aa4a38cc..39fdd959 100644 --- a/fail2ban/server/jail.py +++ b/fail2ban/server/jail.py @@ -257,8 +257,7 @@ class Jail(object): obj.stop() ## wait for end of threads: if join: - if obj.isAlive(): - obj.join() + obj.join() except Exception as e: logSys.error("Stop %r of jail %r failed: %s", obj, self.name, e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG) diff --git a/fail2ban/server/jailthread.py b/fail2ban/server/jailthread.py index 39a86c2b..280b2171 100644 --- a/fail2ban/server/jailthread.py +++ b/fail2ban/server/jailthread.py @@ -53,8 +53,8 @@ class JailThread(Thread): super(JailThread, self).__init__(name=name) ## Should going with main thread also: self.daemon = True - ## Control the state of the thread. - self.active = False + ## Control the state of the thread (None - was not started, True - active, False - stopped). + self.active = None ## Control the idle state of the thread. self.idle = False ## The time the thread sleeps in the loop. @@ -93,3 +93,14 @@ class JailThread(Thread): """Abstract - Called when thread starts, thread stops when returns. """ pass + + def join(self): + """ Safer join, that could be called also for not started (or ended) threads (used for cleanup). + """ + ## if cleanup needed - create derivate and call it before join... + + ## if was really started - should call join: + if self.active is not None: + super(JailThread, self).join() + + diff --git a/fail2ban/server/transmitter.py b/fail2ban/server/transmitter.py index 19cf51ef..2f5be043 100644 --- a/fail2ban/server/transmitter.py +++ b/fail2ban/server/transmitter.py @@ -102,7 +102,7 @@ class Transmitter: self.__commandHandler(cmd) finally: self.__server.reloadJails(*opts, begin=False) - return None + return 'OK' elif len(command) >= 2 and command[0] == "unban": # unban in all jails: value = command[1:]