mirror of https://github.com/fail2ban/fail2ban
Merge remote-tracking branch 'remotes/upstream/master' into sebres:ban-time-incr;
normalize code to python >= 2.6;pull/716/head
commit
361c220846
|
@ -95,6 +95,7 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
|
||||||
not affect SYSLOG output
|
not affect SYSLOG output
|
||||||
* Log unhandled exceptions
|
* Log unhandled exceptions
|
||||||
* cyrus-imap: catch "user not found" attempts
|
* cyrus-imap: catch "user not found" attempts
|
||||||
|
* Add support for Portsentry
|
||||||
|
|
||||||
ver. 0.9.0 (2014/03/14) - beta
|
ver. 0.9.0 (2014/03/14) - beta
|
||||||
----------
|
----------
|
||||||
|
|
12
DEVELOP
12
DEVELOP
|
@ -81,6 +81,18 @@ some quick commands::
|
||||||
status test
|
status test
|
||||||
|
|
||||||
|
|
||||||
|
Testing with vagrant
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Testing can now be done inside a vagrant VM. Vagrantfile provided in
|
||||||
|
source code repository established two VMs:
|
||||||
|
|
||||||
|
- VM "secure" which can be used for testing fail2ban code.
|
||||||
|
- VM "attacker" which hcan be used to perform attack against our "secure" VM.
|
||||||
|
|
||||||
|
Both VMs are sharing the 192.168.200/24 network. If you are using this network
|
||||||
|
take a look into the Vagrantfile and change the IP.
|
||||||
|
|
||||||
|
|
||||||
Coding Standards
|
Coding Standards
|
||||||
================
|
================
|
||||||
|
|
1
THANKS
1
THANKS
|
@ -26,6 +26,7 @@ Christian Rauch
|
||||||
Christophe Carles
|
Christophe Carles
|
||||||
Christoph Haas
|
Christoph Haas
|
||||||
Christos Psonis
|
Christos Psonis
|
||||||
|
craneworks
|
||||||
Cyril Jaquier
|
Cyril Jaquier
|
||||||
Daniel B. Cid
|
Daniel B. Cid
|
||||||
Daniel B.
|
Daniel B.
|
||||||
|
|
|
@ -419,12 +419,11 @@ class Fail2banClient:
|
||||||
ret = False
|
ret = False
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def dumpConfig(cmd):
|
def dumpConfig(cmd):
|
||||||
for c in cmd:
|
for c in cmd:
|
||||||
print c
|
print c
|
||||||
return True
|
return True
|
||||||
dumpConfig = staticmethod(dumpConfig)
|
|
||||||
|
|
||||||
|
|
||||||
class ServerExecutionException(Exception):
|
class ServerExecutionException(Exception):
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Fail2Ban filter for failure attempts in Counter Strike-1.6
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
failregex = \/<HOST> Port\: [0-9]+ (TCP|UDP) Blocked$
|
||||||
|
|
||||||
|
# Author: Pacop <pacoparu@gmail.com>
|
||||||
|
|
|
@ -757,3 +757,8 @@ banaction = iptables-allports
|
||||||
enabled = false
|
enabled = false
|
||||||
logpath = /var/log/directadmin/login.log
|
logpath = /var/log/directadmin/login.log
|
||||||
port = 2222
|
port = 2222
|
||||||
|
|
||||||
|
[portsentry]
|
||||||
|
enabled = false
|
||||||
|
logpath = /var/lib/portsentry/portsentry.history
|
||||||
|
maxretry = 1
|
||||||
|
|
|
@ -77,7 +77,7 @@ class ConfigReader():
|
||||||
"""
|
"""
|
||||||
# already shared ?
|
# already shared ?
|
||||||
if not self._cfg:
|
if not self._cfg:
|
||||||
self.touch(name)
|
self._create_unshared(name)
|
||||||
# performance feature - read once if using shared config reader:
|
# performance feature - read once if using shared config reader:
|
||||||
if once and self._cfg.read_cfg_files is not None:
|
if once and self._cfg.read_cfg_files is not None:
|
||||||
return self._cfg.read_cfg_files
|
return self._cfg.read_cfg_files
|
||||||
|
@ -90,7 +90,7 @@ class ConfigReader():
|
||||||
self._cfg.read_cfg_files = ret
|
self._cfg.read_cfg_files = ret
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def touch(self, name=''):
|
def _create_unshared(self, name=''):
|
||||||
""" Allocates and share a config file by it name.
|
""" Allocates and share a config file by it name.
|
||||||
|
|
||||||
Automatically allocates unshared or reuses shared handle by given 'name' and
|
Automatically allocates unshared or reuses shared handle by given 'name' and
|
||||||
|
@ -268,7 +268,7 @@ class DefinitionInitConfigReader(ConfigReader):
|
||||||
# needed for fail2ban-regex that doesn't need fancy directories
|
# needed for fail2ban-regex that doesn't need fancy directories
|
||||||
def readexplicit(self):
|
def readexplicit(self):
|
||||||
if not self._cfg:
|
if not self._cfg:
|
||||||
self.touch(self._file)
|
self._create_unshared(self._file)
|
||||||
return SafeConfigParserWithIncludes.read(self._cfg, self._file)
|
return SafeConfigParserWithIncludes.read(self._cfg, self._file)
|
||||||
|
|
||||||
def getOptions(self, pOpts):
|
def getOptions(self, pOpts):
|
||||||
|
|
|
@ -57,7 +57,7 @@ class CSocket:
|
||||||
self.__csock.close()
|
self.__csock.close()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def receive(sock):
|
def receive(sock):
|
||||||
msg = EMPTY_BYTES
|
msg = EMPTY_BYTES
|
||||||
while msg.rfind(CSocket.END_STRING) == -1:
|
while msg.rfind(CSocket.END_STRING) == -1:
|
||||||
|
@ -66,4 +66,3 @@ class CSocket:
|
||||||
raise RuntimeError, "socket connection broken"
|
raise RuntimeError, "socket connection broken"
|
||||||
msg = msg + chunk
|
msg = msg + chunk
|
||||||
return loads(msg)
|
return loads(msg)
|
||||||
receive = staticmethod(receive)
|
|
||||||
|
|
|
@ -229,7 +229,7 @@ class JailReader(ConfigReader):
|
||||||
stream.insert(0, ["add", self.__name, backend])
|
stream.insert(0, ["add", self.__name, backend])
|
||||||
return stream
|
return stream
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def extractOptions(option):
|
def extractOptions(option):
|
||||||
match = JailReader.optionCRE.match(option)
|
match = JailReader.optionCRE.match(option)
|
||||||
if not match:
|
if not match:
|
||||||
|
@ -244,4 +244,3 @@ class JailReader(ConfigReader):
|
||||||
val for val in optmatch.group(2,3,4) if val is not None][0]
|
val for val in optmatch.group(2,3,4) if val is not None][0]
|
||||||
option_opts[opt.strip()] = value.strip()
|
option_opts[opt.strip()] = value.strip()
|
||||||
return option_name, option_opts
|
return option_name, option_opts
|
||||||
extractOptions = staticmethod(extractOptions)
|
|
||||||
|
|
|
@ -149,12 +149,8 @@ class AsyncServer(asyncore.dispatcher):
|
||||||
self.__init = True
|
self.__init = True
|
||||||
# TODO Add try..catch
|
# TODO Add try..catch
|
||||||
# There's a bug report for Python 2.6/3.0 that use_poll=True yields some 2.5 incompatibilities:
|
# There's a bug report for Python 2.6/3.0 that use_poll=True yields some 2.5 incompatibilities:
|
||||||
if sys.version_info >= (2, 6): # if python 2.6 or greater...
|
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
|
||||||
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
|
asyncore.loop(use_poll=False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
||||||
asyncore.loop(use_poll = False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
|
||||||
else: # pragma: no cover
|
|
||||||
logSys.debug("NOT Python 2.6/3.* - asyncore.loop() using poll")
|
|
||||||
asyncore.loop(use_poll = True)
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Stops the communication server.
|
# Stops the communication server.
|
||||||
|
@ -175,12 +171,11 @@ class AsyncServer(asyncore.dispatcher):
|
||||||
|
|
||||||
# @param sock: socket file.
|
# @param sock: socket file.
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def __markCloseOnExec(sock):
|
def __markCloseOnExec(sock):
|
||||||
fd = sock.fileno()
|
fd = sock.fileno()
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags|fcntl.FD_CLOEXEC)
|
fcntl.fcntl(fd, fcntl.F_SETFD, flags|fcntl.FD_CLOEXEC)
|
||||||
__markCloseOnExec = staticmethod(__markCloseOnExec)
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# AsyncServerException is used to wrap communication exceptions.
|
# AsyncServerException is used to wrap communication exceptions.
|
||||||
|
|
|
@ -126,7 +126,7 @@ class BanManager:
|
||||||
# @param ticket the FailTicket
|
# @param ticket the FailTicket
|
||||||
# @return a BanTicket
|
# @return a BanTicket
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def createBanTicket(ticket):
|
def createBanTicket(ticket):
|
||||||
ip = ticket.getIP()
|
ip = ticket.getIP()
|
||||||
# if ticked was restored from database - set time of original restored ticket:
|
# if ticked was restored from database - set time of original restored ticket:
|
||||||
|
@ -138,7 +138,6 @@ class BanManager:
|
||||||
banTicket = BanTicket(ip, lastTime, ticket.getMatches())
|
banTicket = BanTicket(ip, lastTime, ticket.getMatches())
|
||||||
banTicket.setAttempt(ticket.getAttempt())
|
banTicket.setAttempt(ticket.getAttempt())
|
||||||
return banTicket
|
return banTicket
|
||||||
createBanTicket = staticmethod(createBanTicket)
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Add a ban ticket.
|
# Add a ban ticket.
|
||||||
|
|
|
@ -932,7 +932,7 @@ class DNSUtils:
|
||||||
|
|
||||||
IP_CRE = re.compile("^(?:\d{1,3}\.){3}\d{1,3}$")
|
IP_CRE = re.compile("^(?:\d{1,3}\.){3}\d{1,3}$")
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def dnsToIp(dns):
|
def dnsToIp(dns):
|
||||||
""" Convert a DNS into an IP address using the Python socket module.
|
""" Convert a DNS into an IP address using the Python socket module.
|
||||||
Thanks to Kevin Drapel.
|
Thanks to Kevin Drapel.
|
||||||
|
@ -947,9 +947,8 @@ class DNSUtils:
|
||||||
logSys.warning("Socket error raised trying to resolve hostname %s: %s"
|
logSys.warning("Socket error raised trying to resolve hostname %s: %s"
|
||||||
% (dns, e))
|
% (dns, e))
|
||||||
return list()
|
return list()
|
||||||
dnsToIp = staticmethod(dnsToIp)
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def searchIP(text):
|
def searchIP(text):
|
||||||
""" Search if an IP address if directly available and return
|
""" Search if an IP address if directly available and return
|
||||||
it.
|
it.
|
||||||
|
@ -959,9 +958,8 @@ class DNSUtils:
|
||||||
return match
|
return match
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
searchIP = staticmethod(searchIP)
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def isValidIP(string):
|
def isValidIP(string):
|
||||||
""" Return true if str is a valid IP
|
""" Return true if str is a valid IP
|
||||||
"""
|
"""
|
||||||
|
@ -971,9 +969,8 @@ class DNSUtils:
|
||||||
return True
|
return True
|
||||||
except socket.error:
|
except socket.error:
|
||||||
return False
|
return False
|
||||||
isValidIP = staticmethod(isValidIP)
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def textToIp(text, useDns):
|
def textToIp(text, useDns):
|
||||||
""" Return the IP of DNS found in a given text.
|
""" Return the IP of DNS found in a given text.
|
||||||
"""
|
"""
|
||||||
|
@ -995,9 +992,8 @@ class DNSUtils:
|
||||||
text, ipList)
|
text, ipList)
|
||||||
|
|
||||||
return ipList
|
return ipList
|
||||||
textToIp = staticmethod(textToIp)
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def cidr(i, n):
|
def cidr(i, n):
|
||||||
""" Convert an IP address string with a CIDR mask into a 32-bit
|
""" Convert an IP address string with a CIDR mask into a 32-bit
|
||||||
integer.
|
integer.
|
||||||
|
@ -1005,18 +1001,15 @@ class DNSUtils:
|
||||||
# 32-bit IPv4 address mask
|
# 32-bit IPv4 address mask
|
||||||
MASK = 0xFFFFFFFFL
|
MASK = 0xFFFFFFFFL
|
||||||
return ~(MASK >> n) & MASK & DNSUtils.addr2bin(i)
|
return ~(MASK >> n) & MASK & DNSUtils.addr2bin(i)
|
||||||
cidr = staticmethod(cidr)
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def addr2bin(string):
|
def addr2bin(string):
|
||||||
""" Convert a string IPv4 address into an unsigned integer.
|
""" Convert a string IPv4 address into an unsigned integer.
|
||||||
"""
|
"""
|
||||||
return struct.unpack("!L", socket.inet_aton(string))[0]
|
return struct.unpack("!L", socket.inet_aton(string))[0]
|
||||||
addr2bin = staticmethod(addr2bin)
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def bin2addr(addr):
|
def bin2addr(addr):
|
||||||
""" Convert a numeric IPv4 address into string n.n.n.n form.
|
""" Convert a numeric IPv4 address into string n.n.n.n form.
|
||||||
"""
|
"""
|
||||||
return socket.inet_ntoa(struct.pack("!L", addr))
|
return socket.inet_ntoa(struct.pack("!L", addr))
|
||||||
bin2addr = staticmethod(bin2addr)
|
|
||||||
|
|
|
@ -26,89 +26,95 @@ import time, datetime, re
|
||||||
##
|
##
|
||||||
# MyTime class.
|
# MyTime class.
|
||||||
#
|
#
|
||||||
# This class is a wrapper around time.time() and time.gmtime(). When
|
|
||||||
# performing unit test, it is very useful to get a fixed value from these
|
|
||||||
# functions.
|
|
||||||
# Thus, time.time() and time.gmtime() should never be called directly.
|
|
||||||
# This wrapper should be called instead. The API are equivalent.
|
|
||||||
|
|
||||||
class MyTime:
|
class MyTime:
|
||||||
|
"""A wrapper around time module primarily for testing purposes
|
||||||
|
|
||||||
|
This class is a wrapper around time.time() and time.gmtime(). When
|
||||||
|
performing unit test, it is very useful to get a fixed value from
|
||||||
|
these functions. Thus, time.time() and time.gmtime() should never
|
||||||
|
be called directly. This wrapper should be called instead. The API
|
||||||
|
are equivalent.
|
||||||
|
"""
|
||||||
|
|
||||||
myTime = None
|
myTime = None
|
||||||
|
|
||||||
##
|
@staticmethod
|
||||||
# Sets the current time.
|
|
||||||
#
|
|
||||||
# Use None in order to always get the real current time.
|
|
||||||
#
|
|
||||||
# @param t the time to set or None
|
|
||||||
|
|
||||||
#@staticmethod
|
|
||||||
def setTime(t):
|
def setTime(t):
|
||||||
|
"""Set current time.
|
||||||
|
|
||||||
|
Use None in order to always get the real current time.
|
||||||
|
|
||||||
|
@param t the time to set or None
|
||||||
|
"""
|
||||||
|
|
||||||
MyTime.myTime = t
|
MyTime.myTime = t
|
||||||
setTime = staticmethod(setTime)
|
|
||||||
|
@staticmethod
|
||||||
##
|
|
||||||
# Equivalent to time.time()
|
|
||||||
#
|
|
||||||
# @return time.time() if setTime was called with None
|
|
||||||
|
|
||||||
#@staticmethod
|
|
||||||
def time():
|
def time():
|
||||||
|
"""Decorate time.time() for the purpose of testing mocking
|
||||||
|
|
||||||
|
@return time.time() if setTime was called with None
|
||||||
|
"""
|
||||||
|
|
||||||
if MyTime.myTime is None:
|
if MyTime.myTime is None:
|
||||||
return time.time()
|
return time.time()
|
||||||
else:
|
else:
|
||||||
return MyTime.myTime
|
return MyTime.myTime
|
||||||
time = staticmethod(time)
|
|
||||||
|
@staticmethod
|
||||||
##
|
|
||||||
# Equivalent to time.gmtime()
|
|
||||||
#
|
|
||||||
# @return time.gmtime() if setTime was called with None
|
|
||||||
|
|
||||||
#@staticmethod
|
|
||||||
def gmtime():
|
def gmtime():
|
||||||
|
"""Decorate time.gmtime() for the purpose of testing mocking
|
||||||
|
|
||||||
|
@return time.gmtime() if setTime was called with None
|
||||||
|
"""
|
||||||
if MyTime.myTime is None:
|
if MyTime.myTime is None:
|
||||||
return time.gmtime()
|
return time.gmtime()
|
||||||
else:
|
else:
|
||||||
return time.gmtime(MyTime.myTime)
|
return time.gmtime(MyTime.myTime)
|
||||||
gmtime = staticmethod(gmtime)
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def now():
|
def now():
|
||||||
|
"""Decorate datetime.now() for the purpose of testing mocking
|
||||||
|
|
||||||
|
@return datetime.now() if setTime was called with None
|
||||||
|
"""
|
||||||
if MyTime.myTime is None:
|
if MyTime.myTime is None:
|
||||||
return datetime.datetime.now()
|
return datetime.datetime.now()
|
||||||
else:
|
else:
|
||||||
return datetime.datetime.fromtimestamp(MyTime.myTime)
|
return datetime.datetime.fromtimestamp(MyTime.myTime)
|
||||||
now = staticmethod(now)
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def localtime(x=None):
|
def localtime(x=None):
|
||||||
|
"""Decorate time.localtime() for the purpose of testing mocking
|
||||||
|
|
||||||
|
@return time.localtime() if setTime was called with None
|
||||||
|
"""
|
||||||
if MyTime.myTime is None or x is not None:
|
if MyTime.myTime is None or x is not None:
|
||||||
return time.localtime(x)
|
return time.localtime(x)
|
||||||
else:
|
else:
|
||||||
return time.localtime(MyTime.myTime)
|
return time.localtime(MyTime.myTime)
|
||||||
localtime = staticmethod(localtime)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Wraps string expression like "1h 2m 3s" into number contains seconds (3723).
|
|
||||||
# The string expression will be evaluated as mathematical expression, spaces between each groups
|
|
||||||
# will be wrapped to "+" operand (only if any operand does not specified between).
|
|
||||||
# Because of case insensitivity and overwriting with minutes ("m" or "mm"), the short replacement for month
|
|
||||||
# are "mo" or "mon".
|
|
||||||
# Ex: 1hour+30min = 5400
|
|
||||||
# 0d 1h 30m = 5400
|
|
||||||
# 1year-6mo = 15778800
|
|
||||||
# 6 months = 15778800
|
|
||||||
# warn: month is not 30 days, it is a year in seconds / 12, the leap years will be respected also:
|
|
||||||
# >>>> float(Test.str2seconds("1month")) / 60 / 60 / 24
|
|
||||||
# 30.4375
|
|
||||||
# >>>> float(Test.str2seconds("1year")) / 60 / 60 / 24
|
|
||||||
# 365.25
|
|
||||||
#
|
|
||||||
# @returns number (calculated seconds from expression "val")
|
|
||||||
|
|
||||||
#@staticmethod
|
@staticmethod
|
||||||
def str2seconds(val):
|
def str2seconds(val):
|
||||||
|
"""Wraps string expression like "1h 2m 3s" into number contains seconds (3723).
|
||||||
|
The string expression will be evaluated as mathematical expression, spaces between each groups
|
||||||
|
will be wrapped to "+" operand (only if any operand does not specified between).
|
||||||
|
Because of case insensitivity and overwriting with minutes ("m" or "mm"), the short replacement for month
|
||||||
|
are "mo" or "mon".
|
||||||
|
Ex: 1hour+30min = 5400
|
||||||
|
0d 1h 30m = 5400
|
||||||
|
1year-6mo = 15778800
|
||||||
|
6 months = 15778800
|
||||||
|
warn: month is not 30 days, it is a year in seconds / 12, the leap years will be respected also:
|
||||||
|
>>>> float(Test.str2seconds("1month")) / 60 / 60 / 24
|
||||||
|
30.4375
|
||||||
|
>>>> float(Test.str2seconds("1year")) / 60 / 60 / 24
|
||||||
|
365.25
|
||||||
|
|
||||||
|
@returns number (calculated seconds from expression "val")
|
||||||
|
"""
|
||||||
if isinstance(val, (int, long, float, complex)):
|
if isinstance(val, (int, long, float, complex)):
|
||||||
return val
|
return val
|
||||||
# replace together standing abbreviations, example '1d12h' -> '1d 12h':
|
# replace together standing abbreviations, example '1d12h' -> '1d 12h':
|
||||||
|
@ -122,4 +128,3 @@ class MyTime:
|
||||||
val = re.sub(r"(?i)(?<=[\d\s])(%s)\b" % rexp, "*"+str(rpl), val)
|
val = re.sub(r"(?i)(?<=[\d\s])(%s)\b" % rexp, "*"+str(rpl), val)
|
||||||
val = re.sub(r"(\d)\s+(\d)", r"\1+\2", val);
|
val = re.sub(r"(\d)\s+(\d)", r"\1+\2", val);
|
||||||
return eval(val)
|
return eval(val)
|
||||||
str2seconds = staticmethod(str2seconds)
|
|
|
@ -86,6 +86,7 @@ class DateDetectorTest(unittest.TestCase):
|
||||||
(False, "23-Jan-2005 21:59:59.02"),
|
(False, "23-Jan-2005 21:59:59.02"),
|
||||||
(False, "23-Jan-2005 21:59:59 +0100"),
|
(False, "23-Jan-2005 21:59:59 +0100"),
|
||||||
(False, "23-01-2005 21:59:59"),
|
(False, "23-01-2005 21:59:59"),
|
||||||
|
(True, "1106513999"), # Portsetry
|
||||||
(False, "01-23-2005 21:59:59.252"), # reported on f2b, causes Feb29 fix to break
|
(False, "01-23-2005 21:59:59.252"), # reported on f2b, causes Feb29 fix to break
|
||||||
(False, "@4000000041f4104f00000000"), # TAI64N
|
(False, "@4000000041f4104f00000000"), # TAI64N
|
||||||
(False, "2005-01-23T20:59:59.252Z"), #ISO 8601 (UTC)
|
(False, "2005-01-23T20:59:59.252Z"), #ISO 8601 (UTC)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# failJSON: { "time": "2014-06-27T17:51:19", "match": true , "host": "192.168.56.1" }
|
||||||
|
1403884279 - 06/27/2014 17:51:19 Host: 192.168.56.1/192.168.56.1 Port: 1 TCP Blocked
|
||||||
|
# failJSON: { "time": "2014-06-27T17:51:19", "match": true , "host": "192.168.56.1" }
|
||||||
|
1403884279 - 06/27/2014 17:51:19 Host: 192.168.56.1/192.168.56.1 Port: 1 UDP Blocked
|
|
@ -24,11 +24,7 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import unittest, sys, os, fileinput, re, time, datetime, inspect
|
import unittest, sys, os, fileinput, re, time, datetime, inspect
|
||||||
|
|
||||||
if sys.version_info >= (2, 6):
|
import json
|
||||||
import json
|
|
||||||
else:
|
|
||||||
import simplejson as json
|
|
||||||
next = lambda x: x.next()
|
|
||||||
|
|
||||||
from ..server.filter import Filter
|
from ..server.filter import Filter
|
||||||
from ..client.filterreader import FilterReader
|
from ..client.filterreader import FilterReader
|
||||||
|
|
Loading…
Reference in New Issue