mirror of https://github.com/fail2ban/fail2ban
Move handling of unicode decoding to FileContainer readline
Also print warning for unicode decode failure, leaving as str in python2 and ignoring erroneous characters in python3pull/128/merge^2
parent
7e1819ed65
commit
d23d365be2
|
@ -289,12 +289,6 @@ class Filter(JailThread):
|
||||||
def processLine(self, line):
|
def processLine(self, line):
|
||||||
"""Split the time portion from log msg and return findFailures on them
|
"""Split the time portion from log msg and return findFailures on them
|
||||||
"""
|
"""
|
||||||
if not isinstance(line, unicode):
|
|
||||||
try:
|
|
||||||
# Decode line to UTF-8
|
|
||||||
line = line.decode('utf-8')
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
pass
|
|
||||||
timeMatch = self.dateDetector.matchTime(line)
|
timeMatch = self.dateDetector.matchTime(line)
|
||||||
if timeMatch:
|
if timeMatch:
|
||||||
# Lets split into time part and log part of the line
|
# Lets split into time part and log part of the line
|
||||||
|
@ -485,7 +479,7 @@ class FileFilter(Filter):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
line = container.readline()
|
line = container.readline()
|
||||||
if (line == "") or not self._isActive():
|
if not line or not self._isActive():
|
||||||
# The jail reached the bottom or has been stopped
|
# The jail reached the bottom or has been stopped
|
||||||
break
|
break
|
||||||
self.processLineAndAdd(line)
|
self.processLineAndAdd(line)
|
||||||
|
@ -521,18 +515,12 @@ class FileContainer:
|
||||||
self.__tail = tail
|
self.__tail = tail
|
||||||
self.__handler = None
|
self.__handler = None
|
||||||
# Try to open the file. Raises an exception if an error occured.
|
# Try to open the file. Raises an exception if an error occured.
|
||||||
if sys.version_info >= (3,):
|
handler = open(filename, 'rb')
|
||||||
handler = open(filename, encoding='utf-8', errors='ignore')
|
|
||||||
else:
|
|
||||||
handler = open(filename)
|
|
||||||
stats = os.fstat(handler.fileno())
|
stats = os.fstat(handler.fileno())
|
||||||
self.__ino = stats.st_ino
|
self.__ino = stats.st_ino
|
||||||
try:
|
try:
|
||||||
firstLine = handler.readline()
|
firstLine = handler.readline()
|
||||||
# Computes the MD5 of the first line.
|
# Computes the MD5 of the first line.
|
||||||
if isinstance(firstLine, unicode):
|
|
||||||
self.__hash = md5sum(firstLine.encode('utf-8')).digest()
|
|
||||||
else:
|
|
||||||
self.__hash = md5sum(firstLine).digest()
|
self.__hash = md5sum(firstLine).digest()
|
||||||
# Start at the beginning of file if tail mode is off.
|
# Start at the beginning of file if tail mode is off.
|
||||||
if tail:
|
if tail:
|
||||||
|
@ -547,19 +535,12 @@ class FileContainer:
|
||||||
return self.__filename
|
return self.__filename
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
if sys.version_info >= (3,):
|
self.__handler = open(self.__filename, 'rb')
|
||||||
self.__handler = open(
|
|
||||||
self.__filename, encoding='utf-8', errors='ignore')
|
|
||||||
else:
|
|
||||||
self.__handler = open(self.__filename)
|
|
||||||
# Set the file descriptor to be FD_CLOEXEC
|
# Set the file descriptor to be FD_CLOEXEC
|
||||||
fd = self.__handler.fileno()
|
fd = self.__handler.fileno()
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFD, fd | fcntl.FD_CLOEXEC)
|
fcntl.fcntl(fd, fcntl.F_SETFD, fd | fcntl.FD_CLOEXEC)
|
||||||
firstLine = self.__handler.readline()
|
firstLine = self.__handler.readline()
|
||||||
# Computes the MD5 of the first line.
|
# Computes the MD5 of the first line.
|
||||||
if isinstance(firstLine, unicode):
|
|
||||||
myHash = md5sum(firstLine.encode('utf-8')).digest()
|
|
||||||
else:
|
|
||||||
myHash = md5sum(firstLine).digest()
|
myHash = md5sum(firstLine).digest()
|
||||||
stats = os.fstat(self.__handler.fileno())
|
stats = os.fstat(self.__handler.fileno())
|
||||||
# Compare hash and inode
|
# Compare hash and inode
|
||||||
|
@ -574,7 +555,14 @@ class FileContainer:
|
||||||
def readline(self):
|
def readline(self):
|
||||||
if self.__handler == None:
|
if self.__handler == None:
|
||||||
return ""
|
return ""
|
||||||
return self.__handler.readline()
|
line = self.__handler.readline()
|
||||||
|
try:
|
||||||
|
line = line.decode('utf-8', 'strict')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
logSys.warn("Error decoding line to utf-8: %s" % `line`)
|
||||||
|
if sys.version_info >= (3,): # In python3, must be unicode
|
||||||
|
line = line.decode('utf-8', 'ignore')
|
||||||
|
return line
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if not self.__handler == None:
|
if not self.__handler == None:
|
||||||
|
|
|
@ -508,7 +508,7 @@ class GetFailures(unittest.TestCase):
|
||||||
|
|
||||||
# so that they could be reused by other tests
|
# so that they could be reused by other tests
|
||||||
FAILURES_01 = ('193.168.0.128', 3, 1124013599.0,
|
FAILURES_01 = ('193.168.0.128', 3, 1124013599.0,
|
||||||
['Aug 14 11:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128\n']*3)
|
[u'Aug 14 11:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128\n']*3)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
|
@ -532,7 +532,7 @@ class GetFailures(unittest.TestCase):
|
||||||
|
|
||||||
def testGetFailures02(self):
|
def testGetFailures02(self):
|
||||||
output = ('141.3.81.106', 4, 1124013539.0,
|
output = ('141.3.81.106', 4, 1124013539.0,
|
||||||
['Aug 14 11:%d:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2\n'
|
[u'Aug 14 11:%d:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2\n'
|
||||||
% m for m in 53, 54, 57, 58])
|
% m for m in 53, 54, 57, 58])
|
||||||
|
|
||||||
self.filter.addLogPath(GetFailures.FILENAME_02)
|
self.filter.addLogPath(GetFailures.FILENAME_02)
|
||||||
|
@ -565,11 +565,11 @@ class GetFailures(unittest.TestCase):
|
||||||
def testGetFailuresUseDNS(self):
|
def testGetFailuresUseDNS(self):
|
||||||
# We should still catch failures with usedns = no ;-)
|
# We should still catch failures with usedns = no ;-)
|
||||||
output_yes = ('192.0.43.10', 2, 1124013539.0,
|
output_yes = ('192.0.43.10', 2, 1124013539.0,
|
||||||
['Aug 14 11:54:59 i60p295 sshd[12365]: Failed publickey for roehl from example.com port 51332 ssh2\n',
|
[u'Aug 14 11:54:59 i60p295 sshd[12365]: Failed publickey for roehl from example.com port 51332 ssh2\n',
|
||||||
'Aug 14 11:58:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:192.0.43.10 port 51332 ssh2\n'])
|
u'Aug 14 11:58:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:192.0.43.10 port 51332 ssh2\n'])
|
||||||
|
|
||||||
output_no = ('192.0.43.10', 1, 1124013539.0,
|
output_no = ('192.0.43.10', 1, 1124013539.0,
|
||||||
['Aug 14 11:58:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:192.0.43.10 port 51332 ssh2\n'])
|
[u'Aug 14 11:58:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:192.0.43.10 port 51332 ssh2\n'])
|
||||||
|
|
||||||
# Actually no exception would be raised -- it will be just set to 'no'
|
# Actually no exception would be raised -- it will be just set to 'no'
|
||||||
#self.assertRaises(ValueError,
|
#self.assertRaises(ValueError,
|
||||||
|
|
Loading…
Reference in New Issue