build replacement of `<HOST>` substitution corresponding parameter `usedns` - dns-part will be added only if `usedns` is not `no`;

new replacement for `<ADDR>` in opposition to `<HOST>`, for separate usage of 2 address groups only (regardless of `usedns`), `ip4` and `ip6` together, without host (dns)
pull/1557/head
sebres 2016-09-08 15:38:36 +02:00
parent 8c26cada27
commit d2ddc59c40
4 changed files with 22 additions and 14 deletions

View File

@ -106,7 +106,7 @@ class JailReader(ConfigReader):
["int", "maxretry", None], ["int", "maxretry", None],
["string", "findtime", None], ["string", "findtime", None],
["string", "bantime", None], ["string", "bantime", None],
["string", "usedns", None], ["string", "usedns", None], # be sure usedns is before all regex(s) in stream
["string", "failregex", None], ["string", "failregex", None],
["string", "ignoreregex", None], ["string", "ignoreregex", None],
["string", "ignorecommand", None], ["string", "ignorecommand", None],

View File

@ -40,11 +40,11 @@ class Regex:
# avoid construction of invalid object. # avoid construction of invalid object.
# @param value the regular expression # @param value the regular expression
def __init__(self, regex): def __init__(self, regex, **kwargs):
self._matchCache = None self._matchCache = None
# Perform shortcuts expansions. # Perform shortcuts expansions.
# Resolve "<HOST>" tag using default regular expression for host: # Resolve "<HOST>" tag using default regular expression for host:
regex = Regex._resolveHostTag(regex) regex = Regex._resolveHostTag(regex, **kwargs)
# Replace "<SKIPLINES>" with regular expression for multiple lines. # Replace "<SKIPLINES>" with regular expression for multiple lines.
regexSplit = regex.split("<SKIPLINES>") regexSplit = regex.split("<SKIPLINES>")
regex = regexSplit[0] regex = regexSplit[0]
@ -69,22 +69,29 @@ class Regex:
# @return the replaced regular expression as string # @return the replaced regular expression as string
@staticmethod @staticmethod
def _resolveHostTag(regex): def _resolveHostTag(regex, useDns="yes"):
# 3 groups instead of <HOST> - separated ipv4, ipv6 and host
regex = regex.replace("<HOST>",
r"""(?:(?:::f{4,6}:)?(?P<ip4>(?:\d{1,3}\.){3}\d{1,3})|\[?(?P<ip6>(?:[0-9a-fA-F]{1,4}::?|::){1,7}(?:[0-9a-fA-F]{1,4}|(?<=:):))\]?|(?P<dns>[\w\-.^_]*\w))""")
# separated ipv4: # separated ipv4:
r_host = []
r = r"""(?:::f{4,6}:)?(?P<ip4>(?:\d{1,3}\.){3}\d{1,3})""" r = r"""(?:::f{4,6}:)?(?P<ip4>(?:\d{1,3}\.){3}\d{1,3})"""
regex = regex.replace("<IP4>", r); # self closed regex = regex.replace("<IP4>", r); # self closed
regex = regex.replace("<F-IP4/>", r); # closed regex = regex.replace("<F-IP4/>", r); # closed
r_host.append(r)
# separated ipv6: # separated ipv6:
r = r"""(?P<ip6>(?:[0-9a-fA-F]{1,4}::?|::){1,7}(?:[0-9a-fA-F]{1,4}?|(?<=:):))""" r = r"""(?P<ip6>(?:[0-9a-fA-F]{1,4}::?|::){1,7}(?:[0-9a-fA-F]{1,4}?|(?<=:):))"""
regex = regex.replace("<IP6>", r); # self closed regex = regex.replace("<IP6>", r); # self closed
regex = regex.replace("<F-IP6/>", r); # closed regex = regex.replace("<F-IP6/>", r); # closed
r_host.append(r"""\[?%s\]?""" % (r,)); # enclose ipv6 in optional [] in host-regex
# 2 address groups instead of <ADDR> - in opposition to `<HOST>`,
# for separate usage of 2 address groups only (regardless of `usedns`), `ip4` and `ip6` together
regex = regex.replace("<ADDR>", "(?:%s)" % ("|".join(r_host),))
# separated dns: # separated dns:
r = r"""(?P<dns>[\w\-.^_]*\w)""" r = r"""(?P<dns>[\w\-.^_]*\w)"""
regex = regex.replace("<DNS>", r); # self closed regex = regex.replace("<DNS>", r); # self closed
regex = regex.replace("<F-DNS/>", r); # closed regex = regex.replace("<F-DNS/>", r); # closed
if useDns not in ("no",):
r_host.append(r)
# 3 groups instead of <HOST> - separated ipv4, ipv6 and host (dns)
regex = regex.replace("<HOST>", "(?:%s)" % ("|".join(r_host),))
# default failure-id as no space tag: # default failure-id as no space tag:
regex = regex.replace("<F-ID/>", r"""(?P<fid>\S+)"""); # closed regex = regex.replace("<F-ID/>", r"""(?P<fid>\S+)"""); # closed
# default failure port, like 80 or http : # default failure port, like 80 or http :
@ -249,9 +256,9 @@ class FailRegex(Regex):
# avoid construction of invalid object. # avoid construction of invalid object.
# @param value the regular expression # @param value the regular expression
def __init__(self, regex): def __init__(self, regex, **kwargs):
# Initializes the parent. # Initializes the parent.
Regex.__init__(self, regex) Regex.__init__(self, regex, **kwargs)
# Check for group "dns", "ip4", "ip6", "fid" # Check for group "dns", "ip4", "ip6", "fid"
if not [grp for grp in FAILURE_ID_GROPS if grp in self._regexObj.groupindex]: if not [grp for grp in FAILURE_ID_GROPS if grp in self._regexObj.groupindex]:
raise RegexException("No failure-id group in '%s'" % self._regex) raise RegexException("No failure-id group in '%s'" % self._regex)

View File

@ -134,12 +134,12 @@ class Filter(JailThread):
def addFailRegex(self, value): def addFailRegex(self, value):
try: try:
regex = FailRegex(value) regex = FailRegex(value, useDns=self.__useDns)
self.__failRegex.append(regex) self.__failRegex.append(regex)
if "\n" in regex.getRegex() and not self.getMaxLines() > 1: if "\n" in regex.getRegex() and not self.getMaxLines() > 1:
logSys.warning( logSys.warning(
"Mutliline regex set for jail '%s' " "Mutliline regex set for jail %r "
"but maxlines not greater than 1") "but maxlines not greater than 1", self.jail.name)
except RegexException as e: except RegexException as e:
logSys.error(e) logSys.error(e)
raise e raise e
@ -176,7 +176,7 @@ class Filter(JailThread):
def addIgnoreRegex(self, value): def addIgnoreRegex(self, value):
try: try:
regex = Regex(value) regex = Regex(value, useDns=self.__useDns)
self.__ignoreRegex.append(regex) self.__ignoreRegex.append(regex)
except RegexException as e: except RegexException as e:
logSys.error(e) logSys.error(e)

View File

@ -58,7 +58,7 @@ SERVER = "fail2ban-server"
BIN = dirname(Fail2banServer.getServerPath()) BIN = dirname(Fail2banServer.getServerPath())
MAX_WAITTIME = 30 if not unittest.F2B.fast else 5 MAX_WAITTIME = 30 if not unittest.F2B.fast else 5
MID_WAITTIME = MAX_WAITTIME / 2.5 MID_WAITTIME = MAX_WAITTIME
## ##
# Several wrappers and settings for proper testing: # Several wrappers and settings for proper testing:
@ -681,6 +681,7 @@ class Fail2banServerTest(Fail2banClientServerBase):
_write_file(pjoin(cfg, "jail.conf"), "w", _write_file(pjoin(cfg, "jail.conf"), "w",
"[INCLUDES]", "", "[INCLUDES]", "",
"[DEFAULT]", "", "[DEFAULT]", "",
"usedns = no",
"maxretry = 3", "maxretry = 3",
"findtime = 10m", "findtime = 10m",
"failregex = ^\s*failure (401|403) from <HOST>", "failregex = ^\s*failure (401|403) from <HOST>",