Merge pull request #1732 from sebres/0.10-ignoreself

0.10 `ignoreself` for ignore own IP addresses
pull/1733/head
Serg G. Brester 2017-03-24 10:12:23 +01:00 committed by GitHub
commit b650503f00
13 changed files with 110 additions and 7 deletions

View File

@ -68,6 +68,10 @@ TODO: implementing of options resp. other tasks from PR #1346
* Samples test case factory extended with filter options - dict in JSON to control
filter options (e. g. mode, etc.):
# filterOptions: {"mode": "aggressive"}
* Introduced new jail option "ignoreself", specifies whether the local resp. own IP addresses
should be ignored (default is true). Fail2ban will not ban a host which matches such addresses.
Option "ignoreip" affects additionally to "ignoreself" and don't need to include the DNS
resp. IPs of the host self.
ver. 0.10.0-alpha-1 (2016/07/14) - ipv6-support-etc

View File

@ -44,10 +44,14 @@ before = paths-debian.conf
# MISCELLANEOUS OPTIONS
#
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
# ban a host which matches an address in this list. Several addresses can be
# defined using space (and/or comma) separator.
ignoreip = 127.0.0.1/8 ::1
# "ignorself" specifies whether the local resp. own IP addresses should be ignored
# (default is true). Fail2ban will not ban a host which matches such addresses.
#ignorself = true
# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
# will not ban a host which matches an address in this list. Several addresses
# can be defined using space (and/or comma) separator.
#ignoreip = 127.0.0.1/8 ::1
# External command that will take an tagged arguments to ignore, e.g. <ip>,
# and return true if the IP is to be ignored. False otherwise.

View File

@ -110,6 +110,7 @@ class JailReader(ConfigReader):
["string", "failregex", None],
["string", "ignoreregex", None],
["string", "ignorecommand", None],
["bool", "ignoreself", None],
["string", "ignoreip", None],
["string", "filter", ""],
["string", "datepattern", None],

View File

@ -81,6 +81,7 @@ protocol = [
["status <JAIL> [FLAVOR]", "gets the current status of <JAIL>, with optional flavor or extended info"],
['', "JAIL CONFIGURATION", ""],
["set <JAIL> idle on|off", "sets the idle state of <JAIL>"],
["set <JAIL> ignoreself true|false", "allows the ignoring of own IP addresses"],
["set <JAIL> addignoreip <IP>", "adds <IP> to the ignore list of <JAIL>"],
["set <JAIL> delignoreip <IP>", "removes <IP> from the ignore list of <JAIL>"],
["set <JAIL> addlogpath <FILE> ['tail']", "adds <FILE> to the monitoring list of <JAIL>, optionally starting at the 'tail' of the file (default 'head')."],
@ -117,6 +118,7 @@ protocol = [
["get <JAIL> logpath", "gets the list of the monitored files for <JAIL>"],
["get <JAIL> logencoding", "gets the encoding of the log files for <JAIL>"],
["get <JAIL> journalmatch", "gets the journal filter match for <JAIL>"],
["get <JAIL> ignoreself", "gets the current value of the ignoring the own IP addresses"],
["get <JAIL> ignoreip", "gets the list of ignored IP addresses for <JAIL>"],
["get <JAIL> ignorecommand", "gets ignorecommand of <JAIL>"],
["get <JAIL> failregex", "gets the list of regular expressions which matches the failures for <JAIL>"],

View File

@ -76,6 +76,8 @@ class Filter(JailThread):
self.setUseDns(useDns)
## The amount of time to look back.
self.__findTime = 600
## Ignore own IPs flag:
self.__ignoreSelf = True
## The ignore IP list.
self.__ignoreIpList = []
## Size of line buffer
@ -413,6 +415,17 @@ class Filter(JailThread):
return ip
##
# Ignore own IP/DNS.
#
@property
def ignoreSelf(self):
return self.__ignoreSelf
@ignoreSelf.setter
def ignoreSelf(self, value):
self.__ignoreSelf = value
##
# Add an IP/DNS to the ignore list.
#
@ -458,6 +471,11 @@ class Filter(JailThread):
def inIgnoreIPList(self, ip, log_ignore=False):
if not isinstance(ip, IPAddr):
ip = IPAddr(ip)
# check own IPs should be ignored and 'ip' is self IP:
if self.__ignoreSelf and ip in DNSUtils.getSelfIPs():
return True
for net in self.__ignoreIpList:
# check if the IP is covered by ignore IP
if ip.isInNet(net):

View File

@ -118,6 +118,42 @@ class DNSUtils:
return ipList
@staticmethod
def getSelfNames():
"""Get own host names of self"""
# try find cached own hostnames (this tuple-key cannot be used elsewhere):
key = ('self','dns')
names = DNSUtils.CACHE_ipToName.get(key)
# get it using different ways (a set with names of localhost, hostname, fully qualified):
if names is None:
names = set(['localhost'])
for hostname in (socket.gethostname, socket.getfqdn):
try:
names |= set([hostname()])
except Exception as e: # pragma: no cover
logSys.warning("Retrieving own hostnames failed: %s", e)
# cache and return :
DNSUtils.CACHE_ipToName.set(key, names)
return names
@staticmethod
def getSelfIPs():
"""Get own IP addresses of self"""
# try find cached own IPs (this tuple-key cannot be used elsewhere):
key = ('self','ips')
ips = DNSUtils.CACHE_nameToIp.get(key)
# get it using different ways (a set with IPs of localhost, hostname, fully qualified):
if ips is None:
ips = set()
for hostname in DNSUtils.getSelfNames():
try:
ips |= set(DNSUtils.textToIp(hostname, 'yes'))
except Exception as e: # pragma: no cover
logSys.warning("Retrieving own IPs of %s failed: %s", hostname, e)
# cache and return :
DNSUtils.CACHE_nameToIp.set(key, ips)
return ips
##
# Class for IP address handling.

View File

@ -308,6 +308,12 @@ class Server:
return self.__jails[name].idle
# Filter
def setIgnoreSelf(self, name, value):
self.__jails[name].filter.ignoreSelf = value
def getIgnoreSelf(self, name):
return self.__jails[name].filter.ignoreSelf
def addIgnoreIP(self, name, ip):
self.__jails[name].filter.addIgnoreIP(ip)

View File

@ -181,6 +181,10 @@ class Transmitter:
raise Exception("Invalid idle option, must be 'on' or 'off'")
return self.__server.getIdleJail(name)
# Filter
elif command[1] == "ignoreself":
value = command[2]
self.__server.setIgnoreSelf(name, value)
return self.__server.getIgnoreSelf(name)
elif command[1] == "addignoreip":
value = command[2]
self.__server.addIgnoreIP(name, value)
@ -341,6 +345,8 @@ class Transmitter:
return self.__server.getLogEncoding(name)
elif command[1] == "journalmatch": # pragma: systemd no cover
return self.__server.getJournalMatch(name)
elif command[1] == "ignoreself":
return self.__server.getIgnoreSelf(name)
elif command[1] == "ignoreip":
return self.__server.getIgnoreIP(name)
elif command[1] == "ignorecommand":

View File

@ -211,7 +211,8 @@ class Utils():
if retcode is None or tout_kill_tree: # Still going...
os.killpg(pgid, signal.SIGKILL) # Kill the process
time.sleep(Utils.DEFAULT_SLEEP_INTERVAL)
retcode = popen.poll()
if retcode is None: # pragma: no cover - too sporadic
retcode = popen.poll()
#logSys.debug("%s -- killed %s ", realCmd, retcode)
if retcode is None and not Utils.pid_exists(pgid): # pragma: no cover
retcode = signal.SIGKILL

View File

@ -780,6 +780,7 @@ class Fail2banServerTest(Fail2banClientServerBase):
"findtime = 10m",
"failregex = ^\s*failure <F-ERRCODE>401|403</F-ERRCODE> from <HOST>",
"datepattern = {^LN-BEG}EPOCH",
"ignoreip = 127.0.0.1/8 ::1", # just to cover ignoreip in jailreader/transmitter
"",
"[test-jail1]", "backend = " + backend, "filter =",
"action = ",

View File

@ -325,6 +325,17 @@ class IgnoreIP(LogCaptureTestCase):
LogCaptureTestCase.setUp(self)
self.jail = DummyJail()
self.filter = FileFilter(self.jail)
self.filter.ignoreSelf = False
def testIgnoreSelfIP(self):
ipList = ("127.0.0.1",)
# test ignoreSelf is false:
for ip in ipList:
self.assertFalse(self.filter.inIgnoreIPList(ip))
# test ignoreSelf with true:
self.filter.ignoreSelf = True
for ip in ipList:
self.assertTrue(self.filter.inIgnoreIPList(ip))
def testIgnoreIPOK(self):
ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99"

View File

@ -449,6 +449,16 @@ class Transmitter(TransmitterBase):
self.transm.proceed(["set", self.jailName, "delignoreip", value]),
(0, [value]))
self.assertEqual(
self.transm.proceed(["get", self.jailName, "ignoreself"]),
(0, True))
self.assertEqual(
self.transm.proceed(["set", self.jailName, "ignoreself", False]),
(0, False))
self.assertEqual(
self.transm.proceed(["get", self.jailName, "ignoreself"]),
(0, False))
def testJailIgnoreCommand(self):
self.setGetTest("ignorecommand", "bin ", jail=self.jailName)

View File

@ -199,11 +199,14 @@ Arguments can be passed to actions to override the default values from the [Init
Values can also be quoted (required when value includes a ","). More that one action can be specified (in separate lines).
.RE
.TP
.B ignoreself
boolean value (default true) indicates the banning of own IP addresses should be prevented
.TP
.B ignoreip
list of IPs not to ban. They can include a CIDR mask too.
list of IPs not to ban. They can include a DNS resp. CIDR mask too. The option affects additionally to \fBignoreself\fR (if true) and don't need to contain own DNS resp. IPs of the running host.
.TP
.B ignorecommand
command that is executed to determine if the current candidate IP for banning should not be banned.
command that is executed to determine if the current candidate IP for banning (or failure-ID for raw IDs) should not be banned. The option affects additionally to \fBignoreself\fR and \fBignoreip\fR and will be first executed if both don't hit.
.br
IP will not be banned if command returns successfully (exit code 0).
Like ACTION FILES, tags like <ip> are can be included in the ignorecommand value and will be substituted before execution. Currently only <ip> is supported however more will be added later.