fail2ban-regex: stop endless logging on closed streams (redirected pipes like `... | head -n 100`), exit if stdout channel is closed

pull/2630/head
sebres 2020-02-03 20:09:13 +01:00
parent 12b3ac684a
commit 9c7bd80807
2 changed files with 36 additions and 0 deletions

View File

@ -709,6 +709,7 @@ class Fail2banRegex(object):
def exec_command_line(*args):
logging.exitOnIOError = True
parser = get_opt_parser()
(opts, args) = parser.parse_args(*args)
errors = []

View File

@ -208,6 +208,25 @@ class FormatterWithTraceBack(logging.Formatter):
return logging.Formatter.format(self, record)
logging.exitOnIOError = False
def __stopOnIOError(logSys=None, logHndlr=None): # pragma: no cover
if logSys and len(logSys.handlers):
logSys.removeHandler(logSys.handlers[0])
if logHndlr:
logHndlr.close = lambda: None
logging.StreamHandler.flush = lambda self: None
#sys.excepthook = lambda *args: None
if logging.exitOnIOError:
try:
sys.stderr.close()
except:
pass
sys.exit(0)
try:
BrokenPipeError
except NameError: # pragma: 3.x no cover
BrokenPipeError = IOError
__origLog = logging.Logger._log
def __safeLog(self, level, msg, args, **kwargs):
"""Safe log inject to avoid possible errors by unsafe log-handlers,
@ -223,6 +242,10 @@ def __safeLog(self, level, msg, args, **kwargs):
try:
# if isEnabledFor(level) already called...
__origLog(self, level, msg, args, **kwargs)
except (BrokenPipeError, IOError) as e: # pragma: no cover
if e.errno == 32: # closed / broken pipe
__stopOnIOError(self)
raise
except Exception as e: # pragma: no cover - unreachable if log-handler safe in this python-version
try:
for args in (
@ -237,6 +260,18 @@ def __safeLog(self, level, msg, args, **kwargs):
pass
logging.Logger._log = __safeLog
__origLogFlush = logging.StreamHandler.flush
def __safeLogFlush(self):
"""Safe flush inject stopping endless logging on closed streams (redirected pipe).
"""
try:
__origLogFlush(self)
except (BrokenPipeError, IOError) as e: # pragma: no cover
if e.errno == 32: # closed / broken pipe
__stopOnIOError(None, self)
raise
logging.StreamHandler.flush = __safeLogFlush
def getLogger(name):
"""Get logging.Logger instance with Fail2Ban logger name convention
"""