mirror of https://github.com/fail2ban/fail2ban
Merge branch '0.10' into 0.11
commit
6198b4566c
|
@ -55,6 +55,12 @@ socket = /var/run/fail2ban/fail2ban.sock
|
||||||
#
|
#
|
||||||
pidfile = /var/run/fail2ban/fail2ban.pid
|
pidfile = /var/run/fail2ban/fail2ban.pid
|
||||||
|
|
||||||
|
# Option: allowipv6
|
||||||
|
# Notes.: Allows IPv6 interface:
|
||||||
|
# Default: auto
|
||||||
|
# Values: [ auto yes (on, true, 1) no (off, false, 0) ] Default: auto
|
||||||
|
#allowipv6 = auto
|
||||||
|
|
||||||
# Options: dbfile
|
# Options: dbfile
|
||||||
# Notes.: Set the file for the fail2ban persistent data to be stored.
|
# Notes.: Set the file for the fail2ban persistent data to be stored.
|
||||||
# A value of ":memory:" means database is only stored in memory
|
# A value of ":memory:" means database is only stored in memory
|
||||||
|
|
|
@ -53,6 +53,7 @@ class Fail2banReader(ConfigReader):
|
||||||
opts = [["string", "loglevel", "INFO" ],
|
opts = [["string", "loglevel", "INFO" ],
|
||||||
["string", "logtarget", "STDERR"],
|
["string", "logtarget", "STDERR"],
|
||||||
["string", "syslogsocket", "auto"],
|
["string", "syslogsocket", "auto"],
|
||||||
|
["string", "allowipv6", "auto"],
|
||||||
["string", "dbfile", "/var/lib/fail2ban/fail2ban.sqlite3"],
|
["string", "dbfile", "/var/lib/fail2ban/fail2ban.sqlite3"],
|
||||||
["int", "dbmaxmatches", None],
|
["int", "dbmaxmatches", None],
|
||||||
["string", "dbpurgeage", "1d"]]
|
["string", "dbpurgeage", "1d"]]
|
||||||
|
@ -74,6 +75,7 @@ class Fail2banReader(ConfigReader):
|
||||||
# Also dbfile should be set before all other database options.
|
# Also dbfile should be set before all other database options.
|
||||||
# So adding order indices into items, to be stripped after sorting, upon return
|
# So adding order indices into items, to be stripped after sorting, upon return
|
||||||
order = {"thread":0, "syslogsocket":11, "loglevel":12, "logtarget":13,
|
order = {"thread":0, "syslogsocket":11, "loglevel":12, "logtarget":13,
|
||||||
|
"allowipv6": 14,
|
||||||
"dbfile":50, "dbmaxmatches":51, "dbpurgeage":51}
|
"dbfile":50, "dbmaxmatches":51, "dbpurgeage":51}
|
||||||
stream = list()
|
stream = list()
|
||||||
for opt in self.__opts:
|
for opt in self.__opts:
|
||||||
|
|
|
@ -35,6 +35,7 @@ __license__ = "GPL"
|
||||||
|
|
||||||
import getopt
|
import getopt
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import os
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
|
@ -329,26 +330,33 @@ class Fail2banRegex(object):
|
||||||
regex = regextype + 'regex'
|
regex = regextype + 'regex'
|
||||||
# try to check - we've case filter?[options...]?:
|
# try to check - we've case filter?[options...]?:
|
||||||
basedir = self._opts.config
|
basedir = self._opts.config
|
||||||
|
fltName = value
|
||||||
fltFile = None
|
fltFile = None
|
||||||
fltOpt = {}
|
fltOpt = {}
|
||||||
if regextype == 'fail':
|
if regextype == 'fail':
|
||||||
fltName, fltOpt = extractOptions(value)
|
if re.search(r'^/{0,3}[\w/_\-.]+(?:\[.*\])?$', value):
|
||||||
if fltName is not None:
|
try:
|
||||||
if "." in fltName[~5:]:
|
fltName, fltOpt = extractOptions(value)
|
||||||
tryNames = (fltName,)
|
if "." in fltName[~5:]:
|
||||||
else:
|
tryNames = (fltName,)
|
||||||
tryNames = (fltName, fltName + '.conf', fltName + '.local')
|
|
||||||
for fltFile in tryNames:
|
|
||||||
if not "/" in fltFile:
|
|
||||||
if os.path.basename(basedir) == 'filter.d':
|
|
||||||
fltFile = os.path.join(basedir, fltFile)
|
|
||||||
else:
|
|
||||||
fltFile = os.path.join(basedir, 'filter.d', fltFile)
|
|
||||||
else:
|
else:
|
||||||
basedir = os.path.dirname(fltFile)
|
tryNames = (fltName, fltName + '.conf', fltName + '.local')
|
||||||
if os.path.isfile(fltFile):
|
for fltFile in tryNames:
|
||||||
break
|
if not "/" in fltFile:
|
||||||
fltFile = None
|
if os.path.basename(basedir) == 'filter.d':
|
||||||
|
fltFile = os.path.join(basedir, fltFile)
|
||||||
|
else:
|
||||||
|
fltFile = os.path.join(basedir, 'filter.d', fltFile)
|
||||||
|
else:
|
||||||
|
basedir = os.path.dirname(fltFile)
|
||||||
|
if os.path.isfile(fltFile):
|
||||||
|
break
|
||||||
|
fltFile = None
|
||||||
|
except Exception as e:
|
||||||
|
output("ERROR: Wrong filter name or options: %s" % (str(e),))
|
||||||
|
output(" while parsing: %s" % (value,))
|
||||||
|
if self._verbose: raise(e)
|
||||||
|
return False
|
||||||
# if it is filter file:
|
# if it is filter file:
|
||||||
if fltFile is not None:
|
if fltFile is not None:
|
||||||
if (basedir == self._opts.config
|
if (basedir == self._opts.config
|
||||||
|
|
|
@ -140,9 +140,10 @@ class JailReader(ConfigReader):
|
||||||
# Read filter
|
# Read filter
|
||||||
flt = self.__opts["filter"]
|
flt = self.__opts["filter"]
|
||||||
if flt:
|
if flt:
|
||||||
filterName, filterOpt = extractOptions(flt)
|
try:
|
||||||
if not filterName:
|
filterName, filterOpt = extractOptions(flt)
|
||||||
raise JailDefError("Invalid filter definition %r" % flt)
|
except ValueError as e:
|
||||||
|
raise JailDefError("Invalid filter definition %r: %s" % (flt, e))
|
||||||
self.__filter = FilterReader(
|
self.__filter = FilterReader(
|
||||||
filterName, self.__name, filterOpt,
|
filterName, self.__name, filterOpt,
|
||||||
share_config=self.share_config, basedir=self.getBaseDir())
|
share_config=self.share_config, basedir=self.getBaseDir())
|
||||||
|
@ -174,10 +175,10 @@ class JailReader(ConfigReader):
|
||||||
if not act: # skip empty actions
|
if not act: # skip empty actions
|
||||||
continue
|
continue
|
||||||
# join with previous line if needed (consider possible new-line):
|
# join with previous line if needed (consider possible new-line):
|
||||||
actName, actOpt = extractOptions(act)
|
try:
|
||||||
prevln = ''
|
actName, actOpt = extractOptions(act)
|
||||||
if not actName:
|
except ValueError as e:
|
||||||
raise JailDefError("Invalid action definition %r" % act)
|
raise JailDefError("Invalid action definition %r: %s" % (act, e))
|
||||||
if actName.endswith(".py"):
|
if actName.endswith(".py"):
|
||||||
self.__actions.append([
|
self.__actions.append([
|
||||||
"set",
|
"set",
|
||||||
|
|
|
@ -371,7 +371,7 @@ OPTION_CRE = re.compile(r"^([^\[]+)(?:\[(.*)\])?\s*$", re.DOTALL)
|
||||||
# since v0.10 separator extended with `]\s*[` for support of multiple option groups, syntax
|
# since v0.10 separator extended with `]\s*[` for support of multiple option groups, syntax
|
||||||
# `action = act[p1=...][p2=...]`
|
# `action = act[p1=...][p2=...]`
|
||||||
OPTION_EXTRACT_CRE = re.compile(
|
OPTION_EXTRACT_CRE = re.compile(
|
||||||
r'([\w\-_\.]+)=(?:"([^"]*)"|\'([^\']*)\'|([^,\]]*))(?:,|\]\s*\[|$)', re.DOTALL)
|
r'\s*([\w\-_\.]+)=(?:"([^"]*)"|\'([^\']*)\'|([^,\]]*))(?:,|\]\s*\[|$|(?P<wrngA>.+))|,?\s*$|(?P<wrngB>.+)', re.DOTALL)
|
||||||
# split by new-line considering possible new-lines within options [...]:
|
# split by new-line considering possible new-lines within options [...]:
|
||||||
OPTION_SPLIT_CRE = re.compile(
|
OPTION_SPLIT_CRE = re.compile(
|
||||||
r'(?:[^\[\s]+(?:\s*\[\s*(?:[\w\-_\.]+=(?:"[^"]*"|\'[^\']*\'|[^,\]]*)\s*(?:,|\]\s*\[)?\s*)*\])?\s*|\S+)(?=\n\s*|\s+|$)', re.DOTALL)
|
r'(?:[^\[\s]+(?:\s*\[\s*(?:[\w\-_\.]+=(?:"[^"]*"|\'[^\']*\'|[^,\]]*)\s*(?:,|\]\s*\[)?\s*)*\])?\s*|\S+)(?=\n\s*|\s+|$)', re.DOTALL)
|
||||||
|
@ -379,13 +379,19 @@ OPTION_SPLIT_CRE = re.compile(
|
||||||
def extractOptions(option):
|
def extractOptions(option):
|
||||||
match = OPTION_CRE.match(option)
|
match = OPTION_CRE.match(option)
|
||||||
if not match:
|
if not match:
|
||||||
# TODO proper error handling
|
raise ValueError("unexpected option syntax")
|
||||||
return None, None
|
|
||||||
option_name, optstr = match.groups()
|
option_name, optstr = match.groups()
|
||||||
option_opts = dict()
|
option_opts = dict()
|
||||||
if optstr:
|
if optstr:
|
||||||
for optmatch in OPTION_EXTRACT_CRE.finditer(optstr):
|
for optmatch in OPTION_EXTRACT_CRE.finditer(optstr):
|
||||||
|
if optmatch.group("wrngA"):
|
||||||
|
raise ValueError("unexpected syntax at %d after option %r: %s" % (
|
||||||
|
optmatch.start("wrngA"), optmatch.group(1), optmatch.group("wrngA")[0:25]))
|
||||||
|
if optmatch.group("wrngB"):
|
||||||
|
raise ValueError("expected option, wrong syntax at %d: %s" % (
|
||||||
|
optmatch.start("wrngB"), optmatch.group("wrngB")[0:25]))
|
||||||
opt = optmatch.group(1)
|
opt = optmatch.group(1)
|
||||||
|
if not opt: continue
|
||||||
value = [
|
value = [
|
||||||
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()
|
||||||
|
|
|
@ -169,27 +169,31 @@ class DNSUtils:
|
||||||
DNSUtils.CACHE_ipToName.set(key, name)
|
DNSUtils.CACHE_ipToName.set(key, name)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
# key find cached own hostnames (this tuple-key cannot be used elsewhere):
|
||||||
|
_getSelfNames_key = ('self','dns')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getSelfNames():
|
def getSelfNames():
|
||||||
"""Get own host names of self"""
|
"""Get own host names of self"""
|
||||||
# try find cached own hostnames (this tuple-key cannot be used elsewhere):
|
# try find cached own hostnames:
|
||||||
key = ('self','dns')
|
names = DNSUtils.CACHE_ipToName.get(DNSUtils._getSelfNames_key)
|
||||||
names = DNSUtils.CACHE_ipToName.get(key)
|
|
||||||
# get it using different ways (a set with names of localhost, hostname, fully qualified):
|
# get it using different ways (a set with names of localhost, hostname, fully qualified):
|
||||||
if names is None:
|
if names is None:
|
||||||
names = set([
|
names = set([
|
||||||
'localhost', DNSUtils.getHostname(False), DNSUtils.getHostname(True)
|
'localhost', DNSUtils.getHostname(False), DNSUtils.getHostname(True)
|
||||||
]) - set(['']) # getHostname can return ''
|
]) - set(['']) # getHostname can return ''
|
||||||
# cache and return :
|
# cache and return :
|
||||||
DNSUtils.CACHE_ipToName.set(key, names)
|
DNSUtils.CACHE_ipToName.set(DNSUtils._getSelfNames_key, names)
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
# key to find cached own IPs (this tuple-key cannot be used elsewhere):
|
||||||
|
_getSelfIPs_key = ('self','ips')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getSelfIPs():
|
def getSelfIPs():
|
||||||
"""Get own IP addresses of self"""
|
"""Get own IP addresses of self"""
|
||||||
# try find cached own IPs (this tuple-key cannot be used elsewhere):
|
# to find cached own IPs:
|
||||||
key = ('self','ips')
|
ips = DNSUtils.CACHE_nameToIp.get(DNSUtils._getSelfIPs_key)
|
||||||
ips = DNSUtils.CACHE_nameToIp.get(key)
|
|
||||||
# get it using different ways (a set with IPs of localhost, hostname, fully qualified):
|
# get it using different ways (a set with IPs of localhost, hostname, fully qualified):
|
||||||
if ips is None:
|
if ips is None:
|
||||||
ips = set()
|
ips = set()
|
||||||
|
@ -199,13 +203,30 @@ class DNSUtils:
|
||||||
except Exception as e: # pragma: no cover
|
except Exception as e: # pragma: no cover
|
||||||
logSys.warning("Retrieving own IPs of %s failed: %s", hostname, e)
|
logSys.warning("Retrieving own IPs of %s failed: %s", hostname, e)
|
||||||
# cache and return :
|
# cache and return :
|
||||||
DNSUtils.CACHE_nameToIp.set(key, ips)
|
DNSUtils.CACHE_nameToIp.set(DNSUtils._getSelfIPs_key, ips)
|
||||||
return ips
|
return ips
|
||||||
|
|
||||||
|
_IPv6IsAllowed = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setIPv6IsAllowed(value):
|
||||||
|
DNSUtils._IPv6IsAllowed = value
|
||||||
|
logSys.debug("IPv6 is %s", ('on' if value else 'off') if value is not None else 'auto')
|
||||||
|
return value
|
||||||
|
|
||||||
|
# key to find cached value of IPv6 allowance (this tuple-key cannot be used elsewhere):
|
||||||
|
_IPv6IsAllowed_key = ('self','ipv6-allowed')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def IPv6IsAllowed():
|
def IPv6IsAllowed():
|
||||||
# return os.path.exists("/proc/net/if_inet6") || any((':' in ip) for ip in DNSUtils.getSelfIPs())
|
if DNSUtils._IPv6IsAllowed is not None:
|
||||||
return any((':' in ip.ntoa) for ip in DNSUtils.getSelfIPs())
|
return DNSUtils._IPv6IsAllowed
|
||||||
|
v = DNSUtils.CACHE_nameToIp.get(DNSUtils._IPv6IsAllowed_key)
|
||||||
|
if v is not None:
|
||||||
|
return v
|
||||||
|
v = any((':' in ip.ntoa) for ip in DNSUtils.getSelfIPs())
|
||||||
|
DNSUtils.CACHE_nameToIp.set(DNSUtils._IPv6IsAllowed_key, v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -34,7 +34,7 @@ import sys
|
||||||
|
|
||||||
from .observer import Observers, ObserverThread
|
from .observer import Observers, ObserverThread
|
||||||
from .jails import Jails
|
from .jails import Jails
|
||||||
from .filter import FileFilter, JournalFilter
|
from .filter import DNSUtils, FileFilter, JournalFilter
|
||||||
from .transmitter import Transmitter
|
from .transmitter import Transmitter
|
||||||
from .asyncserver import AsyncServer, AsyncServerException
|
from .asyncserver import AsyncServer, AsyncServerException
|
||||||
from .. import version
|
from .. import version
|
||||||
|
@ -293,6 +293,11 @@ class Server:
|
||||||
for name in self.__jails.keys():
|
for name in self.__jails.keys():
|
||||||
self.delJail(name, stop=False, join=True)
|
self.delJail(name, stop=False, join=True)
|
||||||
|
|
||||||
|
def clearCaches(self):
|
||||||
|
# we need to clear caches, to be able to recognize new IPs/families etc:
|
||||||
|
DNSUtils.CACHE_nameToIp.clear()
|
||||||
|
DNSUtils.CACHE_ipToName.clear()
|
||||||
|
|
||||||
def reloadJails(self, name, opts, begin):
|
def reloadJails(self, name, opts, begin):
|
||||||
if begin:
|
if begin:
|
||||||
# begin reload:
|
# begin reload:
|
||||||
|
@ -314,6 +319,8 @@ class Server:
|
||||||
if "--restart" in opts:
|
if "--restart" in opts:
|
||||||
self.stopJail(name)
|
self.stopJail(name)
|
||||||
else:
|
else:
|
||||||
|
# invalidate caches by reload
|
||||||
|
self.clearCaches()
|
||||||
# first unban all ips (will be not restored after (re)start):
|
# first unban all ips (will be not restored after (re)start):
|
||||||
if "--unban" in opts:
|
if "--unban" in opts:
|
||||||
self.setUnbanIP()
|
self.setUnbanIP()
|
||||||
|
@ -803,6 +810,11 @@ class Server:
|
||||||
logSys.info("flush performed on %s" % self.__logTarget)
|
logSys.info("flush performed on %s" % self.__logTarget)
|
||||||
return "flushed"
|
return "flushed"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setIPv6IsAllowed(value):
|
||||||
|
value = _as_bool(value) if value != 'auto' else None
|
||||||
|
return DNSUtils.setIPv6IsAllowed(value)
|
||||||
|
|
||||||
def setThreadOptions(self, value):
|
def setThreadOptions(self, value):
|
||||||
for o, v in value.iteritems():
|
for o, v in value.iteritems():
|
||||||
if o == 'stacksize':
|
if o == 'stacksize':
|
||||||
|
|
|
@ -173,6 +173,11 @@ class Transmitter:
|
||||||
return self.__server.getSyslogSocket()
|
return self.__server.getSyslogSocket()
|
||||||
else:
|
else:
|
||||||
raise Exception("Failed to change syslog socket")
|
raise Exception("Failed to change syslog socket")
|
||||||
|
elif name == "allowipv6":
|
||||||
|
value = command[1]
|
||||||
|
self.__server.setIPv6IsAllowed(value)
|
||||||
|
if self.__quiet: return
|
||||||
|
return value
|
||||||
#Thread
|
#Thread
|
||||||
elif name == "thread":
|
elif name == "thread":
|
||||||
value = command[1]
|
value = command[1]
|
||||||
|
|
|
@ -381,13 +381,16 @@ class JailReaderTest(LogCaptureTestCase):
|
||||||
self.assertEqual(('mail.who_is', {'a':'cat', 'b':'dog'}), extractOptions("mail.who_is[a=cat,b=dog]"))
|
self.assertEqual(('mail.who_is', {'a':'cat', 'b':'dog'}), extractOptions("mail.who_is[a=cat,b=dog]"))
|
||||||
self.assertEqual(('mail--ho_is', {}), extractOptions("mail--ho_is"))
|
self.assertEqual(('mail--ho_is', {}), extractOptions("mail--ho_is"))
|
||||||
|
|
||||||
self.assertEqual(('mail--ho_is', {}), extractOptions("mail--ho_is['s']"))
|
|
||||||
#print(self.getLog())
|
|
||||||
#self.assertLogged("Invalid argument ['s'] in ''s''")
|
|
||||||
|
|
||||||
self.assertEqual(('mail', {'a': ','}), extractOptions("mail[a=',']"))
|
self.assertEqual(('mail', {'a': ','}), extractOptions("mail[a=',']"))
|
||||||
|
self.assertEqual(('mail', {'a': 'b'}), extractOptions("mail[a=b, ]"))
|
||||||
|
|
||||||
#self.assertRaises(ValueError, extractOptions ,'mail-how[')
|
self.assertRaises(ValueError, extractOptions ,'mail-how[')
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, extractOptions, """mail[a="test with interim (wrong) "" quotes"]""")
|
||||||
|
self.assertRaises(ValueError, extractOptions, """mail[a='test with interim (wrong) '' quotes']""")
|
||||||
|
self.assertRaises(ValueError, extractOptions, """mail[a='x, y, z', b=x, y, z]""")
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, extractOptions, """mail['s']""")
|
||||||
|
|
||||||
# Empty option
|
# Empty option
|
||||||
option = "abc[]"
|
option = "abc[]"
|
||||||
|
@ -752,9 +755,9 @@ class JailsReaderTest(LogCaptureTestCase):
|
||||||
['add', 'tz_correct', 'auto'],
|
['add', 'tz_correct', 'auto'],
|
||||||
['start', 'tz_correct'],
|
['start', 'tz_correct'],
|
||||||
['config-error',
|
['config-error',
|
||||||
"Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo'"],
|
"Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo': unexpected option syntax"],
|
||||||
['config-error',
|
['config-error',
|
||||||
"Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test'"],
|
"Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test': unexpected option syntax"],
|
||||||
['config-error',
|
['config-error',
|
||||||
"Jail 'missingaction' skipped, because of wrong configuration: Unable to read action 'noactionfileforthisaction'"],
|
"Jail 'missingaction' skipped, because of wrong configuration: Unable to read action 'noactionfileforthisaction'"],
|
||||||
['config-error',
|
['config-error',
|
||||||
|
@ -975,6 +978,7 @@ class JailsReaderTest(LogCaptureTestCase):
|
||||||
['set', 'syslogsocket', 'auto'],
|
['set', 'syslogsocket', 'auto'],
|
||||||
['set', 'loglevel', "INFO"],
|
['set', 'loglevel', "INFO"],
|
||||||
['set', 'logtarget', '/var/log/fail2ban.log'],
|
['set', 'logtarget', '/var/log/fail2ban.log'],
|
||||||
|
['set', 'allowipv6', 'auto'],
|
||||||
['set', 'dbfile', '/var/lib/fail2ban/fail2ban.sqlite3'],
|
['set', 'dbfile', '/var/lib/fail2ban/fail2ban.sqlite3'],
|
||||||
['set', 'dbmaxmatches', 10],
|
['set', 'dbmaxmatches', 10],
|
||||||
['set', 'dbpurgeage', '1d'],
|
['set', 'dbpurgeage', '1d'],
|
||||||
|
|
|
@ -141,6 +141,12 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
||||||
))
|
))
|
||||||
self.assertLogged("Unable to compile regular expression")
|
self.assertLogged("Unable to compile regular expression")
|
||||||
|
|
||||||
|
def testWrongFilterOptions(self):
|
||||||
|
self.assertFalse(_test_exec(
|
||||||
|
"test", "flt[a='x,y,z',b=z,y,x]"
|
||||||
|
))
|
||||||
|
self.assertLogged("Wrong filter name or options", "wrong syntax at 14: y,x", all=True)
|
||||||
|
|
||||||
def testDirectFound(self):
|
def testDirectFound(self):
|
||||||
self.assertTrue(_test_exec(
|
self.assertTrue(_test_exec(
|
||||||
"--datepattern", r"^(?:%a )?%b %d %H:%M:%S(?:\.%f)?(?: %ExY)?",
|
"--datepattern", r"^(?:%a )?%b %d %H:%M:%S(?:\.%f)?(?: %ExY)?",
|
||||||
|
|
|
@ -35,7 +35,7 @@ import platform
|
||||||
from ..server.failregex import Regex, FailRegex, RegexException
|
from ..server.failregex import Regex, FailRegex, RegexException
|
||||||
from ..server import actions as _actions
|
from ..server import actions as _actions
|
||||||
from ..server.server import Server
|
from ..server.server import Server
|
||||||
from ..server.ipdns import IPAddr
|
from ..server.ipdns import DNSUtils, IPAddr
|
||||||
from ..server.jail import Jail
|
from ..server.jail import Jail
|
||||||
from ..server.jailthread import JailThread
|
from ..server.jailthread import JailThread
|
||||||
from ..server.ticket import BanTicket
|
from ..server.ticket import BanTicket
|
||||||
|
@ -175,6 +175,19 @@ class Transmitter(TransmitterBase):
|
||||||
def testVersion(self):
|
def testVersion(self):
|
||||||
self.assertEqual(self.transm.proceed(["version"]), (0, version.version))
|
self.assertEqual(self.transm.proceed(["version"]), (0, version.version))
|
||||||
|
|
||||||
|
def testSetIPv6(self):
|
||||||
|
try:
|
||||||
|
self.assertEqual(self.transm.proceed(["set", "allowipv6", 'yes']), (0, 'yes'))
|
||||||
|
self.assertTrue(DNSUtils.IPv6IsAllowed())
|
||||||
|
self.assertLogged("IPv6 is on"); self.pruneLog()
|
||||||
|
self.assertEqual(self.transm.proceed(["set", "allowipv6", 'no']), (0, 'no'))
|
||||||
|
self.assertFalse(DNSUtils.IPv6IsAllowed())
|
||||||
|
self.assertLogged("IPv6 is off"); self.pruneLog()
|
||||||
|
finally:
|
||||||
|
# restore back to auto:
|
||||||
|
self.assertEqual(self.transm.proceed(["set", "allowipv6", "auto"]), (0, "auto"))
|
||||||
|
self.assertLogged("IPv6 is auto"); self.pruneLog()
|
||||||
|
|
||||||
def testSleep(self):
|
def testSleep(self):
|
||||||
if not unittest.F2B.fast:
|
if not unittest.F2B.fast:
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
|
|
|
@ -320,6 +320,7 @@ def initTests(opts):
|
||||||
|
|
||||||
# precache all invalid ip's (TEST-NET-1, ..., TEST-NET-3 according to RFC 5737):
|
# precache all invalid ip's (TEST-NET-1, ..., TEST-NET-3 according to RFC 5737):
|
||||||
c = DNSUtils.CACHE_ipToName
|
c = DNSUtils.CACHE_ipToName
|
||||||
|
c.clear = lambda: logSys.warn('clear CACHE_ipToName is disabled in test suite')
|
||||||
# increase max count and max time (too many entries, long time testing):
|
# increase max count and max time (too many entries, long time testing):
|
||||||
c.setOptions(maxCount=10000, maxTime=5*60)
|
c.setOptions(maxCount=10000, maxTime=5*60)
|
||||||
for i in xrange(256):
|
for i in xrange(256):
|
||||||
|
@ -337,6 +338,7 @@ def initTests(opts):
|
||||||
c.set('8.8.4.4', 'dns.google')
|
c.set('8.8.4.4', 'dns.google')
|
||||||
# precache all dns to ip's used in test cases:
|
# precache all dns to ip's used in test cases:
|
||||||
c = DNSUtils.CACHE_nameToIp
|
c = DNSUtils.CACHE_nameToIp
|
||||||
|
c.clear = lambda: logSys.warn('clear CACHE_nameToIp is disabled in test suite')
|
||||||
for i in (
|
for i in (
|
||||||
('999.999.999.999', set()),
|
('999.999.999.999', set()),
|
||||||
('abcdef.abcdef', set()),
|
('abcdef.abcdef', set()),
|
||||||
|
|
|
@ -151,6 +151,11 @@ PID filename. Default: /var/run/fail2ban/fail2ban.pid
|
||||||
.br
|
.br
|
||||||
This is used to store the process ID of the fail2ban server.
|
This is used to store the process ID of the fail2ban server.
|
||||||
.TP
|
.TP
|
||||||
|
.B allowipv6
|
||||||
|
option to allow IPv6 interface - auto, yes (on, true, 1) or no (off, false, 0). Default: auto
|
||||||
|
.br
|
||||||
|
This value can be used to declare fail2ban whether IPv6 is allowed or not.
|
||||||
|
.TP
|
||||||
.B dbfile
|
.B dbfile
|
||||||
Database filename. Default: /var/lib/fail2ban/fail2ban.sqlite3
|
Database filename. Default: /var/lib/fail2ban/fail2ban.sqlite3
|
||||||
.br
|
.br
|
||||||
|
|
Loading…
Reference in New Issue