fix sporadic time related errors after fail2ban restart resp. reload jail:

- ValueError: need more than N values to unpack
- empty banip from restoreCurrentBans, etc.
pull/1460/head
sebres 2017-01-23 11:45:29 +01:00
parent 0636b3247d
commit 8c54675750
4 changed files with 54 additions and 23 deletions

View File

@ -80,7 +80,10 @@ class RequestHandler(asynchat.async_chat):
# Deserialize
message = loads(message)
# Gives the message to the transmitter.
message = self.__transmitter.proceed(message)
if self.__transmitter:
message = self.__transmitter.proceed(message)
else:
message = ['SHUTDOWN']
# Serializes the response.
message = dumps(message, HIGHEST_PROTOCOL)
# Sends the response to the client.
@ -228,6 +231,13 @@ class AsyncServer(asyncore.dispatcher):
##
# Stops the communication server.
def stop_communication(self):
logSys.debug("Stop communication")
self.__transmitter = None
##
# Stops the server.
def stop(self):
self.close()

View File

@ -643,7 +643,6 @@ class Fail2BanDb(object):
cur = self._db.cursor()
return cur.execute(query, queryArgs)
@commitandrollback
def _getCurrentBans(self, cur, jail = None, ip = None, forbantime=None, fromtime=None):
if fromtime is None:
fromtime = MyTime.time()
@ -666,20 +665,29 @@ class Fail2BanDb(object):
cur = self._db.cursor()
return cur.execute(query, queryArgs)
def getCurrentBans(self, jail = None, ip = None, forbantime=None, fromtime=None):
@commitandrollback
def getCurrentBans(self, cur, jail = None, ip = None, forbantime=None, fromtime=None):
tickets = []
ticket = None
results = list(self._getCurrentBans(jail=jail, ip=ip, forbantime=forbantime, fromtime=fromtime))
if results:
for banip, timeofban, bantime, bancount, data in results:
# logSys.debug('restore ticket %r, %r, %r', banip, timeofban, data)
ticket = FailTicket(banip, timeofban, data=data)
# logSys.debug('restored ticket: %r', ticket)
ticket.setBanTime(bantime)
ticket.setBanCount(bancount)
tickets.append(ticket)
for ticket in self._getCurrentBans(cur, jail=jail, ip=ip,
forbantime=forbantime, fromtime=fromtime
):
# can produce unpack error (database may return sporadical wrong-empty row):
try:
banip, timeofban, bantime, bancount, data = ticket
# additionally check for empty values:
if banip is None or banip == "": # pragma: no cover
raise ValueError('unexpected value %r' % (banip,))
except ValueError as e: # pragma: no cover
logSys.debug("get current bans: ignore row %r - %s", ticket, e)
continue
# logSys.debug('restore ticket %r, %r, %r', banip, timeofban, data)
ticket = FailTicket(banip, timeofban, data=data)
# logSys.debug('restored ticket: %r', ticket)
ticket.setBanTime(bantime)
ticket.setBanCount(bancount)
tickets.append(ticket)
return tickets if ip is None else ticket

View File

@ -274,8 +274,9 @@ class Jail(object):
if not self.getBanTimeExtra('increment'):
forbantime = self.actions.getBanTime()
for ticket in self.database.getCurrentBans(jail=self, forbantime=forbantime):
#logSys.debug('restored ticket: %s', ticket)
if not self.filter.inIgnoreIPList(ticket.getIP(), log_ignore=True):
try:
#logSys.debug('restored ticket: %s', ticket)
if self.filter.inIgnoreIPList(ticket.getIP(), log_ignore=True): continue
# mark ticked was restored from database - does not put it again into db:
ticket.restored = True
# correct start time / ban time (by the same end of ban):
@ -287,8 +288,12 @@ class Jail(object):
if btm != -1 and btm <= 0:
continue
self.putFailTicket(ticket)
except Exception as e: # pragma: no cover
logSys.error('Restore ticket failed: %s', e,
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
except Exception as e: # pragma: no cover
logSys.error('%s', e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
logSys.error('Restore bans failed: %s', e,
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
def start(self):
"""Start the jail, by starting filter and actions threads.

View File

@ -159,17 +159,16 @@ class Server:
self.__asyncServer.start(sock, force)
except AsyncServerException as e:
logSys.error("Could not start server: %s", e)
# Removes the PID file.
try:
logSys.debug("Remove PID file %s", pidfile)
os.remove(pidfile)
except (OSError, IOError) as e: # pragma: no cover
logSys.error("Unable to remove PID file: %s", e)
# Stop observer and exit
if Observers.Main is not None:
Observers.Main.stop()
Observers.Main = None
logSys.info("Exiting Fail2ban")
# Stop (if not yet already executed):
self.quit()
def quit(self):
# Give observer a small chance to complete its work before exit
@ -183,8 +182,7 @@ class Server:
# are exiting)
# See https://github.com/fail2ban/fail2ban/issues/7
if self.__asyncServer is not None:
self.__asyncServer.stop()
self.__asyncServer = None
self.__asyncServer.stop_communication()
# Now stop all the jails
self.stopAllJail()
@ -205,6 +203,16 @@ class Server:
for s, sh in self.__prev_signals.iteritems():
signal.signal(s, sh)
# Stop observer and exit
if Observers.Main is not None:
Observers.Main.stop()
Observers.Main = None
# Stop async
if self.__asyncServer is not None:
self.__asyncServer.stop()
self.__asyncServer = None
logSys.info("Exiting Fail2ban")
# Prevent to call quit twice:
self.quit = lambda: False