mirror of https://github.com/fail2ban/fail2ban
extend `ignorecommand` to use actions-similar replacement (ticket-based now, so capable to interpolate all possible tags)
parent
11c1bf0149
commit
9b6d17d07e
|
@ -50,6 +50,8 @@ ver. 0.10.4-dev-1 (20??/??/??) - development edition
|
|||
* systemd: fixed type error on option `journalflags`: an integer is required (gh-2125);
|
||||
|
||||
### New Features
|
||||
* `ignorecommand` extended to use actions-similar replacement (capable to interpolate
|
||||
all possible tags like `<ip-host>`, `<family>`, `<fid>`, `F-USER` etc.)
|
||||
|
||||
### Enhancements
|
||||
* `filter.d/dovecot.conf`: extended with tags F-USER (and alternatives) to collect user-logins (gh-2168)
|
||||
|
|
|
@ -30,6 +30,7 @@ import re
|
|||
import sys
|
||||
import time
|
||||
|
||||
from .actions import Actions
|
||||
from .failmanager import FailManagerEmpty, FailManager
|
||||
from .ipdns import DNSUtils, IPAddr
|
||||
from .ticket import FailTicket
|
||||
|
@ -418,11 +419,12 @@ class Filter(JailThread):
|
|||
def addBannedIP(self, ip):
|
||||
if not isinstance(ip, IPAddr):
|
||||
ip = IPAddr(ip)
|
||||
if self.inIgnoreIPList(ip, log_ignore=False):
|
||||
logSys.warning('Requested to manually ban an ignored IP %s. User knows best. Proceeding to ban it.', ip)
|
||||
|
||||
unixTime = MyTime.time()
|
||||
self.failManager.addFailure(FailTicket(ip, unixTime), self.failManager.getMaxRetry())
|
||||
ticket = FailTicket(ip, unixTime)
|
||||
if self._inIgnoreIPList(ip, ticket, log_ignore=False):
|
||||
logSys.warning('Requested to manually ban an ignored IP %s. User knows best. Proceeding to ban it.', ip)
|
||||
self.failManager.addFailure(ticket, self.failManager.getMaxRetry())
|
||||
|
||||
# Perform the banning of the IP now.
|
||||
try: # pragma: no branch - exception is the only way out
|
||||
|
@ -487,13 +489,19 @@ class Filter(JailThread):
|
|||
#
|
||||
# Check if the given IP address matches an IP address/DNS or a CIDR
|
||||
# mask in the ignore list.
|
||||
# @param ip IP address object
|
||||
# @param ip IP address object or ticket
|
||||
# @return True if IP address is in ignore list
|
||||
|
||||
def inIgnoreIPList(self, ip, log_ignore=True):
|
||||
if not isinstance(ip, IPAddr):
|
||||
ticket = None
|
||||
if isinstance(ip, FailTicket):
|
||||
ticket = ip
|
||||
ip = ticket.getIP()
|
||||
elif not isinstance(ip, IPAddr):
|
||||
ip = IPAddr(ip)
|
||||
return self._inIgnoreIPList(ip, ticket, log_ignore)
|
||||
|
||||
def _inIgnoreIPList(self, ip, ticket, log_ignore=True):
|
||||
# check own IPs should be ignored and 'ip' is self IP:
|
||||
if self.__ignoreSelf and ip in DNSUtils.getSelfIPs():
|
||||
self.logIgnoreIp(ip, log_ignore, ignore_source="ignoreself rule")
|
||||
|
@ -506,7 +514,11 @@ class Filter(JailThread):
|
|||
return True
|
||||
|
||||
if self.__ignoreCommand:
|
||||
command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip } )
|
||||
if ticket:
|
||||
aInfo = Actions.ActionInfo(ticket, self.jail)
|
||||
command = CommandAction.replaceDynamicTags(self.__ignoreCommand, aInfo)
|
||||
else:
|
||||
command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip })
|
||||
logSys.debug('ignore command: %s', command)
|
||||
ret, ret_ignore = CommandAction.executeCmd(command, success_codes=(0, 1))
|
||||
ret_ignore = ret and ret_ignore == 0
|
||||
|
@ -549,12 +561,12 @@ class Filter(JailThread):
|
|||
fail = element[3]
|
||||
logSys.debug("Processing line with time:%s and ip:%s",
|
||||
unixTime, ip)
|
||||
if self.inIgnoreIPList(ip):
|
||||
tick = FailTicket(ip, unixTime, data=fail)
|
||||
if self._inIgnoreIPList(ip, tick):
|
||||
continue
|
||||
logSys.info(
|
||||
"[%s] Found %s - %s", self.jailName, ip, datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S")
|
||||
)
|
||||
tick = FailTicket(ip, unixTime, data=fail)
|
||||
self.failManager.addFailure(tick)
|
||||
# reset (halve) error counter (successfully processed line):
|
||||
if self._errors:
|
||||
|
|
|
@ -38,7 +38,7 @@ except ImportError:
|
|||
|
||||
from ..server.jail import Jail
|
||||
from ..server.filterpoll import FilterPoll
|
||||
from ..server.filter import Filter, FileFilter, FileContainer
|
||||
from ..server.filter import FailTicket, Filter, FileFilter, FileContainer
|
||||
from ..server.failmanager import FailManagerEmpty
|
||||
from ..server.ipdns import DNSUtils, IPAddr
|
||||
from ..server.mytime import MyTime
|
||||
|
@ -408,6 +408,24 @@ class IgnoreIP(LogCaptureTestCase):
|
|||
self.pruneLog()
|
||||
self.assertFalse(self.filter.inIgnoreIPList(""))
|
||||
self.assertLogged("usage: ignorecommand IP", "returned 10", all=True)
|
||||
|
||||
def testIgnoreCommandForTicket(self):
|
||||
# by host of IP (2001:db8::1 and 2001:db8::ffff map to "test-host" and "test-other" in the test-suite):
|
||||
self.filter.setIgnoreCommand('if [ "<ip-host>" = "test-host" ]; then exit 0; fi; exit 1')
|
||||
self.pruneLog()
|
||||
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("2001:db8::1")))
|
||||
self.assertLogged("returned successfully 0")
|
||||
self.pruneLog()
|
||||
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("2001:db8::ffff")))
|
||||
self.assertLogged("returned successfully 1")
|
||||
# by user-name (ignore tester):
|
||||
self.filter.setIgnoreCommand('if [ "<F-USER>" = "tester" ]; then exit 0; fi; exit 1')
|
||||
self.pruneLog()
|
||||
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("tester", data={'user': 'tester'})))
|
||||
self.assertLogged("returned successfully 0")
|
||||
self.pruneLog()
|
||||
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("root", data={'user': 'root'})))
|
||||
self.assertLogged("returned successfully 1", all=True)
|
||||
|
||||
def testIgnoreCauseOK(self):
|
||||
ip = "93.184.216.34"
|
||||
|
|
|
@ -316,6 +316,7 @@ def initTests(opts):
|
|||
c.set('203.0.113.%s' % i, None)
|
||||
c.set('2001:db8::%s' %i, 'test-host')
|
||||
# some legal ips used in our test cases (prevent slow dns-resolving and failures if will be changed later):
|
||||
c.set('2001:db8::ffff', 'test-other')
|
||||
c.set('87.142.124.10', 'test-host')
|
||||
if unittest.F2B.no_network: # pragma: no cover
|
||||
# precache all wrong dns to ip's used in test cases:
|
||||
|
|
Loading…
Reference in New Issue