diff --git a/ChangeLog b/ChangeLog index a81e6e9a..4deaf2de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,7 @@ ver. 1.0.1-dev-1 (20??/??/??) - development nightly edition ### Fixes * [stability] prevent race condition - no ban if filter (backend) is continuously busy if too many messages will be found in log, e. g. initial scan of large log-file or journal (gh-2660) +* pyinotify-backend sporadically avoided initial scanning of log-file by start * python 3.9 compatibility (and Travis CI support) * restoring a large number (500+ depending on files ulimit) of current bans when using PyPy fixed * manual ban is written to database, so can be restored by restart (gh-2647) diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index 7547ba4b..40682bf3 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -329,8 +329,10 @@ class Actions(JailThread, Mapping): logSys.debug("Actions: leave idle mode") continue # wait for ban (stop if gets inactive): - bancnt = Utils.wait_for(lambda: not self.active or self.__checkBan(), self.sleeptime) - cnt += bancnt + bancnt = 0 + if Utils.wait_for(lambda: not self.active or self._jail.hasFailTickets, self.sleeptime): + bancnt = self.__checkBan() + cnt += bancnt # unban if nothing is banned not later than banned tickets >= banPrecedence if not bancnt or cnt >= self.banPrecedence: if self.active: diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index 4e65dd2c..8cf2be5b 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -458,10 +458,10 @@ class Filter(JailThread): logSys.info( "[%s] Attempt %s - %s", self.jailName, ip, datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S") ) - self.failManager.addFailure(ticket, len(matches) or 1) - + attempts = self.failManager.addFailure(ticket, len(matches) or 1) # Perform the ban if this attempt is resulted to: - self.performBan(ip) + if attempts >= self.failManager.getMaxRetry(): + self.performBan(ip) return 1 diff --git a/fail2ban/server/filterpyinotify.py b/fail2ban/server/filterpyinotify.py index 185305ca..6d0172da 100644 --- a/fail2ban/server/filterpyinotify.py +++ b/fail2ban/server/filterpyinotify.py @@ -271,7 +271,13 @@ class FilterPyinotify(FileFilter): def _addLogPath(self, path): self._addFileWatcher(path) - self._process_file(path) + # initial scan: + if self.active: + # we can execute it right now: + self._process_file(path) + else: + # retard until filter gets started: + self._addPending(path, ('INITIAL', path)) ## # Delete a log path diff --git a/fail2ban/server/jail.py b/fail2ban/server/jail.py index ce9968a8..673b6454 100644 --- a/fail2ban/server/jail.py +++ b/fail2ban/server/jail.py @@ -196,6 +196,12 @@ class Jail(object): ("Actions", self.actions.status(flavor=flavor)), ] + @property + def hasFailTickets(self): + """Retrieve whether queue has tickets to ban. + """ + return not self.__queue.empty() + def putFailTicket(self, ticket): """Add a fail ticket to the jail. diff --git a/fail2ban/tests/dummyjail.py b/fail2ban/tests/dummyjail.py index 9bd1bcaf..fdeced8f 100644 --- a/fail2ban/tests/dummyjail.py +++ b/fail2ban/tests/dummyjail.py @@ -54,6 +54,10 @@ class DummyJail(Jail): with self.lock: return bool(self.queue) + @property + def hasFailTickets(self): + return bool(self.queue) + def putFailTicket(self, ticket): with self.lock: self.queue.append(ticket)