diff --git a/ChangeLog b/ChangeLog index 756a2378..72879788 100644 --- a/ChangeLog +++ b/ChangeLog @@ -61,6 +61,8 @@ ver. 0.10.4-dev-1 (20??/??/??) - development edition ----------- ### Fixes +* `action.d/hostsdeny.conf`: fix parameter in config (dynamic parameters stating with '_' are protected + and don't allowed in command-actions), see gh-2114; ### New Features diff --git a/config/action.d/hostsdeny.conf b/config/action.d/hostsdeny.conf index 4277fed8..2a93c82b 100644 --- a/config/action.d/hostsdeny.conf +++ b/config/action.d/hostsdeny.conf @@ -31,7 +31,7 @@ actioncheck = # Tags: See jail.conf(5) man page # Values: CMD # -actionban = printf %%b ": <_ip_value>\n" >> +actionban = printf %%b ": \n" >> # Option: actionunban # Notes.: command executed when unbanning an IP. Take care that the @@ -39,7 +39,7 @@ actionban = printf %%b ": <_ip_value>\n" >> # Tags: See jail.conf(5) man page # Values: CMD # -actionunban = IP=$(echo "<_ip_value>" | sed 's/[][\.]/\\\0/g') && sed -i "/^: $IP$/d" +actionunban = IP=$(echo "" | sed 's/[][\.]/\\\0/g') && sed -i "/^: $IP$/d" [Init] @@ -56,7 +56,7 @@ file = /etc/hosts.deny daemon_list = ALL # internal variable IP (to differentiate the IPv4 and IPv6 syntax, where it is enclosed in brackets): -_ip_value = +ip_value = [Init?family=inet6] -_ip_value = [] +ip_value = [] diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index 720f7e1d..d9c56852 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -419,7 +419,7 @@ class Filter(JailThread): def addBannedIP(self, ip): if not isinstance(ip, IPAddr): ip = IPAddr(ip) - if self.inIgnoreIPList(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() @@ -491,12 +491,13 @@ class Filter(JailThread): # @param ip IP address object # @return True if IP address is in ignore list - def inIgnoreIPList(self, ip, log_ignore=False): + def inIgnoreIPList(self, ip, log_ignore=True): 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(): + self.logIgnoreIp(ip, log_ignore, ignore_source="ignoreself rule") return True for net in self.__ignoreIpList: @@ -549,7 +550,7 @@ class Filter(JailThread): fail = element[3] logSys.debug("Processing line with time:%s and ip:%s", unixTime, ip) - if self.inIgnoreIPList(ip, log_ignore=True): + if self.inIgnoreIPList(ip): continue logSys.info( "[%s] Found %s - %s", self.jailName, ip, datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S") diff --git a/fail2ban/tests/filtertestcase.py b/fail2ban/tests/filtertestcase.py index 253ae111..2c1e42be 100644 --- a/fail2ban/tests/filtertestcase.py +++ b/fail2ban/tests/filtertestcase.py @@ -337,16 +337,20 @@ class IgnoreIP(LogCaptureTestCase): # test ignoreSelf is false: for ip in ipList: self.assertFalse(self.filter.inIgnoreIPList(ip)) + self.assertNotLogged("[%s] Ignore %s by %s" % (self.jail.name, ip, "ignoreself rule")) # test ignoreSelf with true: self.filter.ignoreSelf = True + self.pruneLog() for ip in ipList: self.assertTrue(self.filter.inIgnoreIPList(ip)) + self.assertLogged("[%s] Ignore %s by %s" % (self.jail.name, ip, "ignoreself rule")) def testIgnoreIPOK(self): ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99" for ip in ipList: self.filter.addIgnoreIP(ip) self.assertTrue(self.filter.inIgnoreIPList(ip)) + self.assertLogged("[%s] Ignore %s by %s" % (self.jail.name, ip, "ip")) def testIgnoreIPNOK(self): ipList = "", "999.999.999.999", "abcdef.abcdef", "192.168.0." diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 16f0c3aa..0f8ec9e2 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1219,8 +1219,6 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'stop': ( '`echo "[j-dummy] dummy /tmp/fail2ban.dummy -- stopped"`', ), - 'ip4-check': (), - 'ip6-check': (), 'ip4-ban': ( '`echo "[j-dummy] dummy /tmp/fail2ban.dummy -- banned 192.0.2.1 (family: inet4)"`', ), @@ -1234,6 +1232,22 @@ class ServerConfigReaderTests(LogCaptureTestCase): '`echo "[j-dummy] dummy /tmp/fail2ban.dummy -- unbanned 2001:db8:: (family: inet6)"`', ), }), + # hostsdeny -- + ('j-hostsdeny', 'hostsdeny[name=%(__name__)s, actionstop="rm ", file="/tmp/fail2ban.dummy"]', { + 'ip4': ('family: inet4',), 'ip6': ('family: inet6',), + 'ip4-ban': ( + r'''`printf %b "ALL: 192.0.2.1\n" >> /tmp/fail2ban.dummy`''', + ), + 'ip4-unban': ( + r'''`IP=$(echo "192.0.2.1" | sed 's/[][\.]/\\\0/g') && sed -i "/^ALL: $IP$/d" /tmp/fail2ban.dummy`''', + ), + 'ip6-ban': ( + r'''`printf %b "ALL: [2001:db8::]\n" >> /tmp/fail2ban.dummy`''', + ), + 'ip6-unban': ( + r'''`IP=$(echo "[2001:db8::]" | sed 's/[][\.]/\\\0/g') && sed -i "/^ALL: $IP$/d" /tmp/fail2ban.dummy`''', + ), + }), # iptables-multiport -- ('j-w-iptables-mp', 'iptables-multiport[name=%(__name__)s, bantime="10m", port="http,https", protocol="tcp", chain=""]', { 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), @@ -1345,8 +1359,6 @@ class ServerConfigReaderTests(LogCaptureTestCase): "`ipset flush f2b-j-w-iptables-ipset6`", "`ipset destroy f2b-j-w-iptables-ipset6`", ), - 'ip4-check': (), - 'ip6-check': (), 'ip4-ban': ( r"`ipset add f2b-j-w-iptables-ipset 192.0.2.1 timeout 600 -exist`", ), @@ -1383,8 +1395,6 @@ class ServerConfigReaderTests(LogCaptureTestCase): "`ipset flush f2b-j-w-iptables-ipset-ap6`", "`ipset destroy f2b-j-w-iptables-ipset-ap6`", ), - 'ip4-check': (), - 'ip6-check': (), 'ip4-ban': ( r"`ipset add f2b-j-w-iptables-ipset-ap 192.0.2.1 timeout 600 -exist`", ), @@ -1692,8 +1702,6 @@ class ServerConfigReaderTests(LogCaptureTestCase): "`ipset flush f2b-j-w-fwcmd-ipset6`", "`ipset destroy f2b-j-w-fwcmd-ipset6`", ), - 'ip4-check': (), - 'ip6-check': (), 'ip4-ban': ( r"`ipset add f2b-j-w-fwcmd-ipset 192.0.2.1 timeout 600 -exist`", ), @@ -1730,8 +1738,6 @@ class ServerConfigReaderTests(LogCaptureTestCase): "`ipset flush f2b-j-w-fwcmd-ipset-ap6`", "`ipset destroy f2b-j-w-fwcmd-ipset-ap6`", ), - 'ip4-check': (), - 'ip6-check': (), 'ip4-ban': ( r"`ipset add f2b-j-w-fwcmd-ipset-ap 192.0.2.1 timeout 600 -exist`", ), @@ -1780,31 +1786,31 @@ class ServerConfigReaderTests(LogCaptureTestCase): action.start() if tests.get('start'): self.assertLogged(*tests['start'], all=True) - else: + elif tests.get('ip4-start') and tests.get('ip6-start'): self.assertNotLogged(*tests['ip4-start']+tests['ip6-start'], all=True) # test ban ip4 : self.pruneLog('# === ban-ipv4 ===') action.ban(aInfos['ipv4']) if tests.get('ip4-start'): self.assertLogged(*tests['ip4-start'], all=True) if tests.get('ip6-start'): self.assertNotLogged(*tests['ip6-start'], all=True) - self.assertLogged(*tests['ip4-check']+tests['ip4-ban'], all=True) + self.assertLogged(*tests.get('ip4-check',())+tests['ip4-ban'], all=True) self.assertNotLogged(*tests['ip6'], all=True) # test unban ip4 : self.pruneLog('# === unban ipv4 ===') action.unban(aInfos['ipv4']) - self.assertLogged(*tests['ip4-check']+tests['ip4-unban'], all=True) + self.assertLogged(*tests.get('ip4-check',())+tests['ip4-unban'], all=True) self.assertNotLogged(*tests['ip6'], all=True) # test ban ip6 : self.pruneLog('# === ban ipv6 ===') action.ban(aInfos['ipv6']) if tests.get('ip6-start'): self.assertLogged(*tests['ip6-start'], all=True) if tests.get('ip4-start'): self.assertNotLogged(*tests['ip4-start'], all=True) - self.assertLogged(*tests['ip6-check']+tests['ip6-ban'], all=True) + self.assertLogged(*tests.get('ip6-check',())+tests['ip6-ban'], all=True) self.assertNotLogged(*tests['ip4'], all=True) # test unban ip6 : self.pruneLog('# === unban ipv6 ===') action.unban(aInfos['ipv6']) - self.assertLogged(*tests['ip6-check']+tests['ip6-unban'], all=True) + self.assertLogged(*tests.get('ip6-check',())+tests['ip6-unban'], all=True) self.assertNotLogged(*tests['ip4'], all=True) # test flush for actions should supported this: if tests.get('flush'): @@ -1814,7 +1820,7 @@ class ServerConfigReaderTests(LogCaptureTestCase): # test stop : self.pruneLog('# === stop ===') action.stop() - self.assertLogged(*tests['stop'], all=True) + if tests.get('stop'): self.assertLogged(*tests['stop'], all=True) def _executeMailCmd(self, realCmd, timeout=60): # replace pipe to mail with pipe to cat: