mirror of https://github.com/fail2ban/fail2ban
Merge branch '0.10' into f2b-perfom-prepare-716-cs-0.10
commit
4c1bcac0c7
21
ChangeLog
21
ChangeLog
|
@ -72,14 +72,33 @@ ver. 0.9.5 (2016/XX/XXX) - wanna-be-released
|
|||
- failregex of previous monit version merged as single expression.
|
||||
* filter.d/postfix.conf, filter.d/postfix-sasl.conf
|
||||
- extended failregex daemon part, matching also `postfix/smtps/smtpd` now (gh-1391)
|
||||
* fixed a grave bug within tags substitutions because of incorrect detection of recursion
|
||||
in case of multiple inline substitutions of the same tag (affected actions: `bsd-ipfw`, etc).
|
||||
Now tracks the actual list of the already substituted tags (per tag instead of single list)
|
||||
* filter.d/common.conf
|
||||
- unexpected extra regex-space in generic `__prefix_line` (gh-1405)
|
||||
- all optional spaces normalized in `common.conf`, test covered now
|
||||
- generic `__prefix_line` extended with optional brackets for the date ambit (gh-1421),
|
||||
added new parameter `__date_ambit`
|
||||
* gentoo-initd fixed --pidfile bug: `--pidfile` is option of start-stop-daemon,
|
||||
not argument of fail2ban (see gh-1434)
|
||||
* filter.d/asterisk.conf - fix security log support for PJSIP and Asterisk 13+
|
||||
|
||||
- New Features:
|
||||
* New Actions:
|
||||
- action.d/firewallcmd-rich-rules and action.d/firewallcmd-rich-logging (gh-1367)
|
||||
|
||||
- Enhancements:
|
||||
* Extreme speedup of all sqlite database operations (gh-1436),
|
||||
by using of following sqlite options:
|
||||
- (synchronous = OFF) write data through OS without syncing
|
||||
- (journal_mode = MEMORY) use memory for the transaction logging
|
||||
- (temp_store = MEMORY) temporary tables and indices are kept in memory
|
||||
* journald journalmatch for pure-ftpd (gh-1362)
|
||||
* Add additional regex filter for dovecot ldap authentication failures (gh-1370)
|
||||
* added additional regex filters for exim (gh-1371)
|
||||
* filter.d/exim*conf
|
||||
- added additional regexes (gh-1371)
|
||||
- made port entry optional
|
||||
|
||||
|
||||
ver. 0.9.4 (2016/03/08) - for-you-ladies
|
||||
|
|
2
MANIFEST
2
MANIFEST
|
@ -167,7 +167,6 @@ fail2ban/client/jailreader.py
|
|||
fail2ban/client/jailsreader.py
|
||||
fail2ban/exceptions.py
|
||||
fail2ban/helpers.py
|
||||
fail2ban/ipdns.py
|
||||
fail2ban/__init__.py
|
||||
fail2ban/protocol.py
|
||||
fail2ban/server/action.py
|
||||
|
@ -185,6 +184,7 @@ fail2ban/server/filter.py
|
|||
fail2ban/server/filterpyinotify.py
|
||||
fail2ban/server/filtersystemd.py
|
||||
fail2ban/server/__init__.py
|
||||
fail2ban/server/ipdns.py
|
||||
fail2ban/server/iso8601.py
|
||||
fail2ban/server/jail.py
|
||||
fail2ban/server/jails.py
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
|
||||
# vi: set ft=python sts=4 ts=4 sw=4 noet :
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
|
||||
# vi: set ft=python sts=4 ts=4 sw=4 noet :
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
|
||||
# vi: set ft=python sts=4 ts=4 sw=4 noet :
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
|
||||
# vi: set ft=python sts=4 ts=4 sw=4 noet :
|
||||
"""Script to run Fail2Ban tests battery
|
||||
|
|
|
@ -80,14 +80,17 @@ class BadIPsAction(ActionBase):
|
|||
If invalid `category`, `score`, `banaction` or `updateperiod`.
|
||||
"""
|
||||
|
||||
TIMEOUT = 10
|
||||
_badips = "http://www.badips.com"
|
||||
def _Request(self, url, **argv):
|
||||
return Request(url, headers={'User-Agent': self.agent}, **argv)
|
||||
|
||||
def __init__(self, jail, name, category, score=3, age="24h", key=None,
|
||||
banaction=None, bancategory=None, bankey=None, updateperiod=900, agent="Fail2Ban"):
|
||||
banaction=None, bancategory=None, bankey=None, updateperiod=900, agent="Fail2Ban",
|
||||
timeout=TIMEOUT):
|
||||
super(BadIPsAction, self).__init__(jail, name)
|
||||
|
||||
self.timeout = timeout
|
||||
self.agent = agent
|
||||
self.category = category
|
||||
self.score = score
|
||||
|
@ -119,7 +122,7 @@ class BadIPsAction(ActionBase):
|
|||
"""
|
||||
try:
|
||||
response = urlopen(
|
||||
self._Request("/".join([self._badips, "get", "categories"])), None, 3)
|
||||
self._Request("/".join([self._badips, "get", "categories"])), timeout=self.timeout)
|
||||
except HTTPError as response:
|
||||
messages = json.loads(response.read().decode('utf-8'))
|
||||
self._logSys.error(
|
||||
|
@ -173,7 +176,7 @@ class BadIPsAction(ActionBase):
|
|||
urlencode({'age': age})])
|
||||
if key:
|
||||
url = "&".join([url, urlencode({'key': key})])
|
||||
response = urlopen(self._Request(url))
|
||||
response = urlopen(self._Request(url), timeout=self.timeout)
|
||||
except HTTPError as response:
|
||||
messages = json.loads(response.read().decode('utf-8'))
|
||||
self._logSys.error(
|
||||
|
@ -358,7 +361,7 @@ class BadIPsAction(ActionBase):
|
|||
url = "/".join([self._badips, "add", self.category, aInfo['ip']])
|
||||
if self.key:
|
||||
url = "?".join([url, urlencode({'key': self.key})])
|
||||
response = urlopen(self._Request(url))
|
||||
response = urlopen(self._Request(url), timeout=self.timeout)
|
||||
except HTTPError as response:
|
||||
messages = json.loads(response.read().decode('utf-8'))
|
||||
self._logSys.error(
|
||||
|
|
|
@ -6,34 +6,26 @@
|
|||
|
||||
[INCLUDES]
|
||||
|
||||
before = iptables-common.conf
|
||||
before = firewallcmd-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
actionstart = firewall-cmd --direct --add-chain ipv4 filter f2b-<name>
|
||||
firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 1000 -j RETURN
|
||||
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -j f2b-<name>
|
||||
actionstart = firewall-cmd --direct --add-chain <family> filter f2b-<name>
|
||||
firewall-cmd --direct --add-rule <family> filter f2b-<name> 1000 -j RETURN
|
||||
firewall-cmd --direct --add-rule <family> filter <chain> 0 -j f2b-<name>
|
||||
|
||||
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -j f2b-<name>
|
||||
firewall-cmd --direct --remove-rules ipv4 filter f2b-<name>
|
||||
firewall-cmd --direct --remove-chain ipv4 filter f2b-<name>
|
||||
actionstop = firewall-cmd --direct --remove-rule <family> filter <chain> 0 -j f2b-<name>
|
||||
firewall-cmd --direct --remove-rules <family> filter f2b-<name>
|
||||
firewall-cmd --direct --remove-chain <family> filter f2b-<name>
|
||||
|
||||
|
||||
# Example actioncheck: firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-recidive$'
|
||||
|
||||
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-<name>$'
|
||||
actioncheck = firewall-cmd --direct --get-chains <family> filter | sed -e 's, ,\n,g' | grep -q '^f2b-<name>$'
|
||||
|
||||
actionban = firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
actionban = firewall-cmd --direct --add-rule <family> filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
actionunban = firewall-cmd --direct --remove-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
[Init]
|
||||
|
||||
# Default name of the chain
|
||||
#
|
||||
name = default
|
||||
|
||||
chain = INPUT_direct
|
||||
actionunban = firewall-cmd --direct --remove-rule <family> filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
# DEV NOTES:
|
||||
#
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
# Fail2Ban configuration file
|
||||
#
|
||||
# Author: Donald Yandt
|
||||
#
|
||||
|
||||
[Init]
|
||||
|
||||
# Option: name
|
||||
# Notes Default name of the chain
|
||||
# Values: STRING
|
||||
name = default
|
||||
|
||||
# Option port
|
||||
# Notes Can also use port numbers separated by a comma and in rich-rules comma and/or space.
|
||||
# Value STRING Default: 1:65535
|
||||
port = 1:65535
|
||||
|
||||
# Option: protocol
|
||||
# Notes [ tcp | udp | icmp | all ]
|
||||
# Values: STRING Default: tcp
|
||||
protocol = tcp
|
||||
|
||||
# Option: family(ipv4)
|
||||
# Notes specifies the socket address family type
|
||||
# Values: STRING
|
||||
family = ipv4
|
||||
|
||||
# Option: chain
|
||||
# Notes specifies the firewalld chain to which the Fail2Ban rules should be
|
||||
# added
|
||||
# Values: STRING Default: INPUT_direct
|
||||
chain = INPUT_direct
|
||||
|
||||
# Option: zone
|
||||
# Notes use command firewall-cmd --get-active-zones to see a list of all active zones. See firewalld man pages for more information on zones
|
||||
# Values: STRING Default: public
|
||||
zone = public
|
||||
|
||||
# Option: service
|
||||
# Notes use command firewall-cmd --get-services to see a list of services available
|
||||
# Examples services: amanda-client amanda-k5-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns freeipa-ldap freeipa-ldaps
|
||||
# freeipa-replication ftp high-availability http https imaps ipp ipp-client ipsec iscsi-target kadmin kerberos
|
||||
# kpasswd ldap ldaps libvirt libvirt-tls mdns mosh mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s
|
||||
# postgresql privoxy proxy-dhcp puppetmaster radius rpc-bind rsyncd samba samba-client sane smtp squid ssh synergy
|
||||
# telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server
|
||||
# Values: STRING Default: ssh
|
||||
service = ssh
|
||||
|
||||
# Option: rejecttype (ipv4)
|
||||
# Notes See iptables/firewalld man pages for ipv4 reject types.
|
||||
# Values: STRING
|
||||
rejecttype = icmp-port-unreachable
|
||||
|
||||
# Option: blocktype (ipv4/ipv6)
|
||||
# Notes See iptables/firewalld man pages for jump targets. Common values are REJECT,
|
||||
# REJECT --reject-with icmp-port-unreachable, DROP
|
||||
# Values: STRING
|
||||
blocktype = REJECT --reject-with <rejecttype>
|
||||
|
||||
# Option: rich-blocktype (ipv4/ipv6)
|
||||
# Notes See firewalld man pages for jump targets. Common values are reject,
|
||||
# reject type="icmp-port-unreachable", drop
|
||||
# Values: STRING
|
||||
rich-blocktype = reject type='<rejecttype>'
|
||||
|
||||
[Init?family=inet6]
|
||||
|
||||
# Option: family(ipv6)
|
||||
# Notes specifies the socket address family type
|
||||
# Values: STRING
|
||||
family = ipv6
|
||||
|
||||
# Option: rejecttype (ipv6)
|
||||
# Note: See iptables/firewalld man pages for ipv6 reject types.
|
||||
# Values: STRING
|
||||
rejecttype = icmp6-port-unreachable
|
|
@ -14,20 +14,20 @@
|
|||
|
||||
[INCLUDES]
|
||||
|
||||
before = iptables-common.conf
|
||||
before = firewallcmd-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
actionstart = ipset create fail2ban-<name> hash:ip timeout <bantime>
|
||||
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
|
||||
actionstart = ipset create <ipmset> hash:ip timeout <bantime>
|
||||
firewall-cmd --direct --add-rule <family> filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set <ipmset> src -j <blocktype>
|
||||
|
||||
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
|
||||
ipset flush fail2ban-<name>
|
||||
ipset destroy fail2ban-<name>
|
||||
actionstop = firewall-cmd --direct --remove-rule <family> filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set <ipmset> src -j <blocktype>
|
||||
ipset flush <ipmset>
|
||||
ipset destroy <ipmset>
|
||||
|
||||
actionban = ipset add fail2ban-<name> <ip> timeout <bantime> -exist
|
||||
actionban = ipset add <ipmset> <ip> timeout <bantime> -exist
|
||||
|
||||
actionunban = ipset del fail2ban-<name> <ip> -exist
|
||||
actionunban = ipset del <ipmset> <ip> -exist
|
||||
|
||||
[Init]
|
||||
|
||||
|
@ -44,6 +44,12 @@ chain = INPUT_direct
|
|||
|
||||
bantime = 600
|
||||
|
||||
ipmset = f2b-<name>
|
||||
|
||||
[Init?family=inet6]
|
||||
|
||||
ipmset = f2b-<name>6
|
||||
|
||||
|
||||
# DEV NOTES:
|
||||
#
|
||||
|
|
|
@ -5,59 +5,22 @@
|
|||
|
||||
[INCLUDES]
|
||||
|
||||
before = iptables-common.conf
|
||||
before = firewallcmd-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
actionstart = firewall-cmd --direct --add-chain ipv4 filter f2b-<name>
|
||||
firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 1000 -j RETURN
|
||||
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -m conntrack --ctstate NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
actionstart = firewall-cmd --direct --add-chain <family> filter f2b-<name>
|
||||
firewall-cmd --direct --add-rule <family> filter f2b-<name> 1000 -j RETURN
|
||||
firewall-cmd --direct --add-rule <family> filter <chain> 0 -m conntrack --ctstate NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
|
||||
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -m conntrack --ctstate NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
firewall-cmd --direct --remove-rules ipv4 filter f2b-<name>
|
||||
firewall-cmd --direct --remove-chain ipv4 filter f2b-<name>
|
||||
actionstop = firewall-cmd --direct --remove-rule <family> filter <chain> 0 -m conntrack --ctstate NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
firewall-cmd --direct --remove-rules <family> filter f2b-<name>
|
||||
firewall-cmd --direct --remove-chain <family> filter f2b-<name>
|
||||
|
||||
# Example actioncheck: firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-apache-modsecurity$'
|
||||
|
||||
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-<name>$'
|
||||
actioncheck = firewall-cmd --direct --get-chains <family> filter | sed -e 's, ,\n,g' | grep -q '^f2b-<name>$'
|
||||
|
||||
actionban = firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
actionunban = firewall-cmd --direct --remove-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
[Init]
|
||||
|
||||
# Default name of the chain
|
||||
name = default
|
||||
|
||||
chain = INPUT_direct
|
||||
|
||||
# Could also use port numbers separated by a comma.
|
||||
port = 1:65535
|
||||
|
||||
|
||||
# Option: protocol
|
||||
# Values: [ tcp | udp | icmp | all ]
|
||||
|
||||
protocol = tcp
|
||||
|
||||
|
||||
|
||||
# DEV NOTES:
|
||||
#
|
||||
# Author: Donald Yandt
|
||||
# Uses "FirewallD" instead of the "iptables daemon".
|
||||
#
|
||||
#
|
||||
# Output:
|
||||
# actionstart:
|
||||
# $ firewall-cmd --direct --add-chain ipv4 filter f2b-apache-modsecurity
|
||||
# success
|
||||
# $ firewall-cmd --direct --add-rule ipv4 filter f2b-apache-modsecurity 1000 -j RETURN
|
||||
# success
|
||||
# $ sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 0 -m state --state NEW -p tcp -m multiport --dports 80,443 -j f2b-apache-modsecurity
|
||||
# success
|
||||
# actioncheck:
|
||||
# $ firewall-cmd --direct --get-chains ipv4 filter f2b-apache-modsecurity | sed -e 's, ,\n,g' | grep -q '^f2b-apache-modsecurity$'
|
||||
# f2b-apache-modsecurity
|
||||
actionban = firewall-cmd --direct --add-rule <family> filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
actionunban = firewall-cmd --direct --remove-rule <family> filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
|
|
@ -4,32 +4,23 @@
|
|||
|
||||
[INCLUDES]
|
||||
|
||||
before = iptables-common.conf
|
||||
before = firewallcmd-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
actionstart = firewall-cmd --direct --add-chain ipv4 filter f2b-<name>
|
||||
firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 1000 -j RETURN
|
||||
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
actionstart = firewall-cmd --direct --add-chain <family> filter f2b-<name>
|
||||
firewall-cmd --direct --add-rule <family> filter f2b-<name> 1000 -j RETURN
|
||||
firewall-cmd --direct --add-rule <family> filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
|
||||
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
firewall-cmd --direct --remove-rules ipv4 filter f2b-<name>
|
||||
firewall-cmd --direct --remove-chain ipv4 filter f2b-<name>
|
||||
actionstop = firewall-cmd --direct --remove-rule <family> filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
|
||||
firewall-cmd --direct --remove-rules <family> filter f2b-<name>
|
||||
firewall-cmd --direct --remove-chain <family> filter f2b-<name>
|
||||
|
||||
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | grep -q 'f2b-<name>$'
|
||||
actioncheck = firewall-cmd --direct --get-chains <family> filter | grep -q 'f2b-<name>$'
|
||||
|
||||
actionban = firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
actionban = firewall-cmd --direct --add-rule <family> filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
actionunban = firewall-cmd --direct --remove-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
[Init]
|
||||
|
||||
# Option: chain
|
||||
# Notes specifies the iptables chain to which the fail2ban rules should be
|
||||
# added
|
||||
# Values: [ STRING ]
|
||||
#
|
||||
chain = INPUT_direct
|
||||
actionunban = firewall-cmd --direct --remove-rule <family> filter f2b-<name> 0 -s <ip> -j <blocktype>
|
||||
|
||||
# DEV NOTES:
|
||||
#
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
# firewall-cmd [--zone=<zone>] --list-all
|
||||
# firewall-cmd [--zone=zone] --query-rich-rule='rule'
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = firewallcmd-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
actionstart =
|
||||
|
@ -26,40 +30,22 @@ actioncheck =
|
|||
# you can also use zones and/or service names.
|
||||
#
|
||||
# zone example:
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='ipv4' source address='<ip>' port port='<port>' protocol='<protocol>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <blocktype>"
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='<family>' source address='<ip>' port port='<port>' protocol='<protocol>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <rich-blocktype>"
|
||||
#
|
||||
# service name example:
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='ipv4' source address='<ip>' service name='<service>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <blocktype>"
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='<family>' source address='<ip>' service name='<service>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <rich-blocktype>"
|
||||
#
|
||||
# Because rich rules can only handle single or a range of ports we must split ports and execute the command for each port. Ports can be single and ranges seperated by a comma or space for an example: http, https, 22-60, 18 smtp
|
||||
|
||||
actionban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --add-rich-rule="rule family='ipv4' source address='<ip>' port port='$p' protocol='<protocol>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <blocktype>"; done
|
||||
actionban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --add-rich-rule="rule family='<family>' source address='<ip>' port port='$p' protocol='<protocol>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <rich-blocktype>"; done
|
||||
|
||||
actionunban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --remove-rich-rule="rule family='ipv4' source address='<ip>' port port='$p' protocol='<protocol>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <blocktype>"; done
|
||||
actionunban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --remove-rich-rule="rule family='<family>' source address='<ip>' port port='$p' protocol='<protocol>' log prefix='f2b-<name>' level='<level>' limit value='<rate>/m' <rich-blocktype>"; done
|
||||
|
||||
[Init]
|
||||
|
||||
name = default
|
||||
|
||||
# log levels are "emerg", "alert", "crit", "error", "warning", "notice", "info" or "debug"
|
||||
level = info
|
||||
|
||||
# log rate per minute
|
||||
rate = 1
|
||||
|
||||
zone = public
|
||||
|
||||
# use command firewall-cmd --get-services to see a list of services available
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# amanda-client amanda-k5-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns freeipa-ldap freeipa-ldaps
|
||||
# freeipa-replication ftp high-availability http https imaps ipp ipp-client ipsec iscsi-target kadmin kerberos
|
||||
# kpasswd ldap ldaps libvirt libvirt-tls mdns mosh mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s
|
||||
# postgresql privoxy proxy-dhcp puppetmaster radius rpc-bind rsyncd samba samba-client sane smtp squid ssh synergy
|
||||
# telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server
|
||||
|
||||
service = ssh
|
||||
|
||||
# reject types: 'icmp-net-unreachable', 'icmp-host-unreachable', 'icmp-port-unreachable', 'icmp-proto-unreachable',
|
||||
# 'icmp-net-prohibited', 'icmp-host-prohibited', 'icmp-admin-prohibited' or 'tcp-reset'
|
||||
|
||||
blocktype = reject type='icmp-port-unreachable'
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
# firewall-cmd [--zone=<zone>] --list-all
|
||||
# firewall-cmd [--zone=zone] --query-rich-rule='rule'
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = firewallcmd-common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
actionstart =
|
||||
|
@ -24,34 +28,15 @@ actioncheck =
|
|||
#you can also use zones and/or service names.
|
||||
#
|
||||
# zone example:
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='ipv4' source address='<ip>' port port='<port>' protocol='<protocol>' <blocktype>"
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='ipv4' source address='<ip>' port port='<port>' protocol='<protocol>' <rich-blocktype>"
|
||||
#
|
||||
# service name example:
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='ipv4' source address='<ip>' service name='<service>' <blocktype>"
|
||||
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='ipv4' source address='<ip>' service name='<service>' <rich-blocktype>"
|
||||
#
|
||||
# Because rich rules can only handle single or a range of ports we must split ports and execute the command for each port. Ports can be single and ranges seperated by a comma or space for an example: http, https, 22-60, 18 smtp
|
||||
|
||||
actionban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --add-rich-rule="rule family='ipv4' source address='<ip>' port port='$p' protocol='<protocol>' <blocktype>"; done
|
||||
actionban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --add-rich-rule="rule family='<family>' source address='<ip>' port port='$p' protocol='<protocol>' <rich-blocktype>"; done
|
||||
|
||||
actionunban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --remove-rich-rule="rule family='ipv4' source address='<ip>' port port='$p' protocol='<protocol>' <blocktype>"; done
|
||||
actionunban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --remove-rich-rule="rule family='<family>' source address='<ip>' port port='$p' protocol='<protocol>' <rich-blocktype>"; done
|
||||
|
||||
[Init]
|
||||
|
||||
name = default
|
||||
|
||||
zone = public
|
||||
|
||||
# use command firewall-cmd --get-services to see a list of services available
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# amanda-client amanda-k5-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns freeipa-ldap freeipa-ldaps
|
||||
# freeipa-replication ftp high-availability http https imaps ipp ipp-client ipsec iscsi-target kadmin kerberos
|
||||
# kpasswd ldap ldaps libvirt libvirt-tls mdns mosh mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s
|
||||
# postgresql privoxy proxy-dhcp puppetmaster radius rpc-bind rsyncd samba samba-client sane smtp squid ssh synergy
|
||||
# telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server
|
||||
|
||||
service = ssh
|
||||
|
||||
# reject types: 'icmp-net-unreachable', 'icmp-host-unreachable', 'icmp-port-unreachable', 'icmp-proto-unreachable',
|
||||
# 'icmp-net-prohibited', 'icmp-host-prohibited', 'icmp-admin-prohibited' or 'tcp-reset'
|
||||
|
||||
blocktype = reject type='icmp-port-unreachable'
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
# we don't enable PF automatically; to enable run pfctl -e
|
||||
# or add `pf_enable="YES"` to /etc/rc.conf (tested on FreeBSD)
|
||||
actionstart = echo "table <<tablename>-<name>> persist counters" | pfctl -f-
|
||||
echo "block proto <protocol> from <<tablename>-<name>> to any port <port>" | pfctl -f-
|
||||
echo "block proto <protocol> from <<tablename>-<name>> to <actiontype>" | pfctl -f-
|
||||
|
||||
|
||||
# Option: actionstop
|
||||
|
@ -71,9 +71,20 @@ tablename = f2b
|
|||
#
|
||||
protocol = tcp
|
||||
|
||||
# Option: port
|
||||
# Notes.: the port to block, defaults to any
|
||||
# Values: [ STRING ]
|
||||
#
|
||||
port = any
|
||||
|
||||
|
||||
# Option: actiontype
|
||||
# Notes.: defines additions to the blocking rule
|
||||
# Values: leave empty to block all attempts from the host
|
||||
# Default: Value of the multiport
|
||||
actiontype = <multiport>
|
||||
|
||||
# Option: allports
|
||||
# Notes.: default addition to block all ports
|
||||
# Usage.: use in jail config: "banaction = pf[actiontype=<allports>]"
|
||||
allports = any
|
||||
|
||||
# Option: multiport
|
||||
# Notes.: addition to block access only to specific ports
|
||||
# Usage.: use in jail config: "banaction = pf[actiontype=<multiport>]"
|
||||
multiport = any port <port>
|
||||
|
|
|
@ -16,17 +16,18 @@ __pid_re = (?:\[\d+\])
|
|||
iso8601 = \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+[+-]\d{4}
|
||||
|
||||
# All Asterisk log messages begin like this:
|
||||
log_prefix= (?:NOTICE|SECURITY)%(__pid_re)s:?(?:\[C-[\da-f]*\])? \S+:\d*( in \w+:)?
|
||||
log_prefix= (?:NOTICE|SECURITY|WARNING)%(__pid_re)s:?(?:\[C-[\da-f]*\])? [^:]+:\d*( in \w+:)?
|
||||
|
||||
failregex = ^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Registration from '[^']*' failed for '<HOST>(:\d+)?' - (Wrong password|Username/auth name mismatch|No matching peer found|Not a local domain|Device does not match ACL|Peer is not supposed to register|ACL error \(permit/deny\)|Not a local domain)$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Call from '[^']*' \(<HOST>:\d+\) to extension '[^']*' rejected because extension not found in context
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Host <HOST> failed to authenticate as '[^']*'$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s No registration for peer '[^']*' \(from <HOST>\)$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Host <HOST> failed MD5 authentication for '[^']*' \([^)]+\)$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Failed to authenticate (user|device) [^@]+@<HOST>\S*$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s hacking attempt detected '<HOST>'$
|
||||
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="([\d-]+|%(iso8601)s)",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="(\d*|<unknown>)",SessionID=".+",LocalAddress="IPV[46]/(UDP|TCP|WS)/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UDP|TCP|WS)/<HOST>/\d+"(,Challenge="[\w/]+")?(,ReceivedChallenge="\w+")?(,Response="\w+",ExpectedResponse="\w*")?(,ReceivedHash="[\da-f]+")?(,ACLName="\w+")?$
|
||||
^(%(__prefix_line)s|\[\]\s*WARNING%(__pid_re)s:?(?:\[C-[\da-f]*\])? )Ext\. s: "Rejecting unknown SIP connection from <HOST>"$
|
||||
failregex = ^%(__prefix_line)s%(log_prefix)s Registration from '[^']*' failed for '<HOST>(:\d+)?' - (Wrong password|Username/auth name mismatch|No matching peer found|Not a local domain|Device does not match ACL|Peer is not supposed to register|ACL error \(permit/deny\)|Not a local domain)$
|
||||
^%(__prefix_line)s%(log_prefix)s Call from '[^']*' \(<HOST>:\d+\) to extension '[^']*' rejected because extension not found in context
|
||||
^%(__prefix_line)s%(log_prefix)s Host <HOST> failed to authenticate as '[^']*'$
|
||||
^%(__prefix_line)s%(log_prefix)s No registration for peer '[^']*' \(from <HOST>\)$
|
||||
^%(__prefix_line)s%(log_prefix)s Host <HOST> failed MD5 authentication for '[^']*' \([^)]+\)$
|
||||
^%(__prefix_line)s%(log_prefix)s Failed to authenticate (user|device) [^@]+@<HOST>\S*$
|
||||
^%(__prefix_line)s%(log_prefix)s hacking attempt detected '<HOST>'$
|
||||
^%(__prefix_line)s%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="([\d-]+|%(iso8601)s)",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="(\d*|<unknown>)",SessionID=".+",LocalAddress="IPV[46]/(UDP|TCP|WS)/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UDP|TCP|WS)/<HOST>/\d+"(,Challenge="[\w/]+")?(,ReceivedChallenge="\w+")?(,Response="\w+",ExpectedResponse="\w*")?(,ReceivedHash="[\da-f]+")?(,ACLName="\w+")?$
|
||||
^%(__prefix_line)s%(log_prefix)s "Rejecting unknown SIP connection from <HOST>"$
|
||||
^%(__prefix_line)s%(log_prefix)s Request from '[^']*' failed for '<HOST>(?::\d+)?' \(callid: \w*\) - No matching endpoint found$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ __daemon_re = [\[\(]?%(_daemon)s(?:\(\S+\))?[\]\)]?:?
|
|||
|
||||
# extra daemon info
|
||||
# EXAMPLE: [ID 800047 auth.info]
|
||||
__daemon_extra_re = (?:\[ID \d+ \S+\])
|
||||
__daemon_extra_re = \[ID \d+ \S+\]
|
||||
|
||||
# Combinations of daemon name and PID
|
||||
# EXAMPLES: sshd[31607], pop(pam_unix)[4920]
|
||||
|
@ -44,14 +44,18 @@ __md5hex = (?:[\da-f]{2}:){15}[\da-f]{2}
|
|||
|
||||
# bsdverbose is where syslogd is started with -v or -vv and results in <4.3> or
|
||||
# <auth.info> appearing before the host as per testcases/files/logs/bsd/*.
|
||||
__bsd_syslog_verbose = (<[^.]+\.[^.]+>)
|
||||
__bsd_syslog_verbose = <[^.]+\.[^.]+>
|
||||
|
||||
__vserver = @vserver_\S+
|
||||
|
||||
__date_ambit = (?:\[\])
|
||||
|
||||
# Common line prefixes (beginnings) which could be used in filters
|
||||
#
|
||||
# [bsdverbose]? [hostname] [vserver tag] daemon_id spaces
|
||||
#
|
||||
# This can be optional (for instance if we match named native log files)
|
||||
__prefix_line = \s*%(__bsd_syslog_verbose)s?\s*(?:%(__hostname)s )?(?:%(__kernel_prefix)s )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s%(__daemon_extra_re)s?\s*
|
||||
__prefix_line = %(__date_ambit)s?\s*(?:%(__bsd_syslog_verbose)s\s+)?(?:%(__hostname)s\s+)?(?:%(__kernel_prefix)s\s+)?(?:%(__vserver)s\s+)?(?:%(__daemon_combs_re)s\s+)?(?:%(__daemon_extra_re)s\s+)?
|
||||
|
||||
# PAM authentication mechanism check for failures, e.g.: pam_unix, pam_sss,
|
||||
# pam_ldap
|
||||
|
|
|
@ -13,7 +13,7 @@ before = common.conf
|
|||
_daemon = courieresmtpd
|
||||
|
||||
failregex = ^%(__prefix_line)serror,relay=<HOST>,.*: 550 User (<.*> )?unknown\.?$
|
||||
^%(__prefix_line)serror,relay=<HOST>,msg="535 Authentication failed\.",cmd:( AUTH \S+)?( [0-9a-zA-Z\+/=]+)?$
|
||||
^%(__prefix_line)serror,relay=<HOST>,msg="535 Authentication failed\.",cmd:( AUTH \S+)?( [0-9a-zA-Z\+/=]+)?(?: \S+)$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ after = exim-common.local
|
|||
|
||||
[Definition]
|
||||
|
||||
host_info = H=([\w.-]+ )?(\(\S+\) )?\[<HOST>\](:\d+)? (I=\[\S+\]:\d+ )?(U=\S+ )?(P=e?smtp )?
|
||||
pid = ( \[\d+\])?
|
||||
host_info = (?:H=([\w.-]+ )?(?:\(\S+\) )?)?\[<HOST>\](?::\d+)? (?:I=\[\S+\](:\d+)? )?(?:U=\S+ )?(?:P=e?smtp )?
|
||||
pid = (?: \[\d+\])?
|
||||
|
||||
# DEV Notes:
|
||||
# From exim source code: ./src/receive.c:add_host_info_for_log
|
||||
|
|
|
@ -14,13 +14,13 @@ before = exim-common.conf
|
|||
[Definition]
|
||||
|
||||
failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$
|
||||
^%(pid)s \w+ authenticator failed for (\S+ )?\(\S+\) \[<HOST>\](:\d+)?( I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$
|
||||
^%(pid)s %(host_info)sF=(<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (relay not permitted|Sender verify failed|Unknown user)\s*$
|
||||
^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (connection from|"\S+") %(host_info)s(next )?input=".*"\s*$
|
||||
^%(pid)s SMTP call from \S+ \[<HOST>\](:\d+)? (I=\[\S+\](:\d+)? )?dropped: too many nonmail commands \(last was "\S+"\)\s*$
|
||||
^%(pid)s SMTP protocol error in "AUTH \S*(| \S*)" H=(|\S* )(|\(\S*\) )\[<HOST>\]\:\d+ I=\[\S*\]\:\d+ AUTH command used when not advertised\s*$
|
||||
^%(pid)s no MAIL in SMTP connection from (|\S* )(|\(\S*\) )\[<HOST>\]\:\d+ I=\[\S*\]\:\d+ D=\d+s(| C=\S*)\s*$
|
||||
^%(pid)s \S+ SMTP connection from (|\S* )(|\(\S*\) )\[<HOST>\]\:\d+ I=\[\S*\]\:\d+ closed by DROP in ACL\s*$
|
||||
^%(pid)s \w+ authenticator failed for (\S+ )?\(\S+\) \[<HOST>\](?::\d+)?(?: I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$
|
||||
^%(pid)s %(host_info)sF=(?:<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user)\s*$
|
||||
^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (?:connection from|"\S+") %(host_info)s(?:next )?input=".*"\s*$
|
||||
^%(pid)s SMTP call from \S+ %(host_info)sdropped: too many nonmail commands \(last was "\S+"\)\s*$
|
||||
^%(pid)s SMTP protocol error in "AUTH \S*(?: \S*)?" %(host_info)sAUTH command used when not advertised\s*$
|
||||
^%(pid)s no MAIL in SMTP connection from (?:\S* )?(?:\(\S*\) )?%(host_info)sD=\d+s(?: C=\S*)?\s*$
|
||||
^%(pid)s \S+ SMTP connection from (?:\S* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# Inspired by https://isc.sans.edu/forums/diary/When+Google+isnt+Google/15968/
|
||||
#
|
||||
# Written in Python to reuse built-in Python batteries and not depend on
|
||||
|
|
|
@ -22,7 +22,7 @@ _daemon = nsd
|
|||
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
|
||||
# Values: TEXT
|
||||
|
||||
failregex = ^\[\]%(__prefix_line)sinfo: ratelimit block .* query <HOST> TYPE255$
|
||||
^\[\]%(__prefix_line)sinfo: .* <HOST> refused, no acl matches\.$
|
||||
failregex = ^%(__prefix_line)sinfo: ratelimit block .* query <HOST> TYPE255$
|
||||
^%(__prefix_line)sinfo: .* <HOST> refused, no acl matches\.$
|
||||
|
||||
ignoreregex =
|
||||
|
|
|
@ -94,6 +94,7 @@ backend = auto
|
|||
# but it will be logged as a warning.
|
||||
# no: if a hostname is encountered, will not be used for banning,
|
||||
# but it will be logged as info.
|
||||
# raw: use raw value (no hostname), allow use it for no-host filters/actions (example user)
|
||||
usedns = warn
|
||||
|
||||
# "logencoding" specifies the encoding of the log files handled by the jail
|
||||
|
|
|
@ -44,7 +44,9 @@ class CSocket:
|
|||
|
||||
def send(self, msg):
|
||||
# Convert every list member to string
|
||||
obj = dumps([str(m) for m in msg], HIGHEST_PROTOCOL)
|
||||
obj = dumps(map(
|
||||
lambda m: str(m) if not isinstance(m, (list, dict, set)) else m, msg),
|
||||
HIGHEST_PROTOCOL)
|
||||
self.__csock.send(obj + CSPROTO.END)
|
||||
return self.receive(self.__csock)
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/python
|
||||
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
|
||||
# vi: set ft=python sts=4 ts=4 sw=4 noet :
|
||||
#
|
||||
|
@ -126,6 +125,8 @@ Report bugs to https://github.com/fail2ban/fail2ban/issues
|
|||
help="set custom pattern used to match date/times"),
|
||||
Option("-e", "--encoding",
|
||||
help="File encoding. Default: system locale"),
|
||||
Option("-r", "--raw", action='store_true',
|
||||
help="Raw hosts, don't resolve dns"),
|
||||
Option("-L", "--maxlines", type=int, default=0,
|
||||
help="maxlines for multi-line regex"),
|
||||
Option("-m", "--journalmatch",
|
||||
|
@ -239,6 +240,7 @@ class Fail2banRegex(object):
|
|||
self.encoding = opts.encoding
|
||||
else:
|
||||
self.encoding = locale.getpreferredencoding()
|
||||
self.raw = True if opts.raw else False
|
||||
|
||||
def decode_line(self, line):
|
||||
return FileContainer.decode_line('<LOG>', self.encoding, line)
|
||||
|
@ -342,7 +344,7 @@ class Fail2banRegex(object):
|
|||
orgLineBuffer = self._filter._Filter__lineBuffer
|
||||
fullBuffer = len(orgLineBuffer) >= self._filter.getMaxLines()
|
||||
try:
|
||||
line, ret = self._filter.processLine(line, date, checkAllRegex=True)
|
||||
line, ret = self._filter.processLine(line, date, checkAllRegex=True, returnRawHost=self.raw)
|
||||
for match in ret:
|
||||
# Append True/False flag depending if line was matched by
|
||||
# more than one regex
|
||||
|
|
|
@ -34,7 +34,7 @@ from .filterreader import FilterReader
|
|||
from .actionreader import ActionReader
|
||||
from ..version import version
|
||||
from ..helpers import getLogger
|
||||
from ..helpers import splitcommaspace
|
||||
from ..helpers import splitwords
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = getLogger(__name__)
|
||||
|
@ -42,9 +42,14 @@ logSys = getLogger(__name__)
|
|||
|
||||
class JailReader(ConfigReader):
|
||||
|
||||
# regex, to extract list of options:
|
||||
optionCRE = re.compile("^((?:\w|-|_|\.)+)(?:\[(.*)\])?$")
|
||||
# regex, to iterate over single option in option list, syntax:
|
||||
# `action = act[p1="...", p2='...', p3=...]`, where the p3=... not contains `,` or ']'
|
||||
# since v0.10 separator extended with `]\s*[` for support of multiple option groups, syntax
|
||||
# `action = act[p1=...][p2=...]`
|
||||
optionExtractRE = re.compile(
|
||||
r'([\w\-_\.]+)=(?:"([^"]*)"|\'([^\']*)\'|([^,]*))(?:,|$)')
|
||||
r'([\w\-_\.]+)=(?:"([^"]*)"|\'([^\']*)\'|([^,\]]*))(?:,|\]\s*\[|$)')
|
||||
|
||||
def __init__(self, name, force_enable=False, **kwargs):
|
||||
ConfigReader.__init__(self, **kwargs)
|
||||
|
@ -214,7 +219,7 @@ class JailReader(ConfigReader):
|
|||
elif opt == "maxretry":
|
||||
stream.append(["set", self.__name, "maxretry", value])
|
||||
elif opt == "ignoreip":
|
||||
for ip in splitcommaspace(value):
|
||||
for ip in splitwords(value):
|
||||
stream.append(["set", self.__name, "addignoreip", ip])
|
||||
elif opt == "findtime":
|
||||
stream.append(["set", self.__name, "findtime", value])
|
||||
|
|
|
@ -133,15 +133,15 @@ def excepthook(exctype, value, traceback):
|
|||
"Unhandled exception in Fail2Ban:", exc_info=True)
|
||||
return sys.__excepthook__(exctype, value, traceback)
|
||||
|
||||
def splitcommaspace(s):
|
||||
"""Helper to split on any comma or space
|
||||
def splitwords(s):
|
||||
"""Helper to split words on any comma, space, or a new line
|
||||
|
||||
Returns empty list if input is empty (or None) and filters
|
||||
out empty entries
|
||||
"""
|
||||
if not s:
|
||||
return []
|
||||
return filter(bool, re.split('[ ,]', s))
|
||||
return filter(bool, map(str.strip, re.split('[ ,\n]+', s)))
|
||||
|
||||
|
||||
class BgService(object):
|
||||
|
|
|
@ -46,9 +46,13 @@ _cmd_lock = threading.Lock()
|
|||
# Todo: make it configurable resp. automatically set, ex.: `[ -f /proc/net/if_inet6 ] && echo 'yes' || echo 'no'`:
|
||||
allowed_ipv6 = True
|
||||
|
||||
# max tag replacement count:
|
||||
MAX_TAG_REPLACE_COUNT = 10
|
||||
|
||||
# compiled RE for tag name (replacement name)
|
||||
TAG_CRE = re.compile(r'<([^ <>]+)>')
|
||||
|
||||
|
||||
class CallingMap(MutableMapping):
|
||||
"""A Mapping type which returns the result of callable values.
|
||||
|
||||
|
@ -229,8 +233,8 @@ class CommandAction(ActionBase):
|
|||
def __setattr__(self, name, value):
|
||||
if not name.startswith('_') and not callable(value):
|
||||
# special case for some pasrameters:
|
||||
if name == 'timeout':
|
||||
value = MyTime.str2seconds(value)
|
||||
if name in ('timeout', 'bantime'):
|
||||
value = str(MyTime.str2seconds(value))
|
||||
# parameters changed - clear properties and substitution cache:
|
||||
self.__properties = None
|
||||
self.__substCache.clear()
|
||||
|
@ -356,27 +360,28 @@ class CommandAction(ActionBase):
|
|||
tags = inptags.copy()
|
||||
t = TAG_CRE
|
||||
# repeat substitution while embedded-recursive (repFlag is True)
|
||||
done = cls._escapedTags.copy()
|
||||
while True:
|
||||
repFlag = False
|
||||
# substitute each value:
|
||||
for tag in tags.iterkeys():
|
||||
if tag in cls._escapedTags:
|
||||
# Escaped so won't match
|
||||
continue
|
||||
# ignore escaped or already done:
|
||||
if tag in done: continue
|
||||
value = str(tags[tag])
|
||||
# search and replace all tags within value, that can be interpolated using other tags:
|
||||
m = t.search(value)
|
||||
done = []
|
||||
refCounts = {}
|
||||
#logSys.log(5, 'TAG: %s, value: %s' % (tag, value))
|
||||
while m:
|
||||
found_tag = m.group(1)
|
||||
#logSys.log(5, 'found: %s' % found_tag)
|
||||
if found_tag == tag or found_tag in done:
|
||||
if found_tag == tag or refCounts.get(found_tag, 1) > MAX_TAG_REPLACE_COUNT:
|
||||
# recursive definitions are bad
|
||||
#logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
|
||||
raise ValueError(
|
||||
"properties contain self referencing definitions "
|
||||
"and cannot be resolved, fail tag: %s value: %s" % (tag, value))
|
||||
"and cannot be resolved, fail tag: %s, found: %s in %s, value: %s" %
|
||||
(tag, found_tag, refCounts, value))
|
||||
repl = None
|
||||
if found_tag not in cls._escapedTags:
|
||||
repl = tags.get(found_tag + '?' + conditional)
|
||||
|
@ -390,7 +395,9 @@ class CommandAction(ActionBase):
|
|||
continue
|
||||
value = value.replace('<%s>' % found_tag, repl)
|
||||
#logSys.log(5, 'value now: %s' % value)
|
||||
done.append(found_tag)
|
||||
# increment reference count:
|
||||
refCounts[found_tag] = refCounts.get(found_tag, 0) + 1
|
||||
# the next match for replace:
|
||||
m = t.search(value, m.start())
|
||||
#logSys.log(5, 'TAG: %s, newvalue: %s' % (tag, value))
|
||||
# was substituted?
|
||||
|
@ -399,6 +406,9 @@ class CommandAction(ActionBase):
|
|||
if t.search(value):
|
||||
repFlag = True
|
||||
tags[tag] = value
|
||||
# no more sub tags (and no possible composite), add this tag to done set (just to be faster):
|
||||
if '<' not in value: done.add(tag)
|
||||
# stop interpolation, if no replacements anymore:
|
||||
if not repFlag:
|
||||
break
|
||||
return tags
|
||||
|
|
|
@ -42,7 +42,6 @@ from .banmanager import BanManager
|
|||
from .jailthread import JailThread
|
||||
from .action import ActionBase, CommandAction, CallingMap
|
||||
from .mytime import MyTime
|
||||
from .filter import IPAddr
|
||||
from .utils import Utils
|
||||
from ..helpers import getLogger
|
||||
|
||||
|
|
|
@ -182,8 +182,23 @@ class Fail2BanDb(object):
|
|||
filename, e.args[0])
|
||||
raise
|
||||
|
||||
# differentiate pypy: switch journal mode later (save it during the upgrade),
|
||||
# to prevent errors like "database table is locked":
|
||||
try:
|
||||
import __pypy__
|
||||
pypy = True
|
||||
except ImportError:
|
||||
pypy = False
|
||||
|
||||
cur = self._db.cursor()
|
||||
cur.execute("PRAGMA foreign_keys = ON;")
|
||||
cur.execute("PRAGMA foreign_keys = ON")
|
||||
# speedup: write data through OS without syncing (no wait):
|
||||
cur.execute("PRAGMA synchronous = OFF")
|
||||
# speedup: transaction log in memory, alternate using OFF (disable, rollback will be impossible):
|
||||
if not pypy:
|
||||
cur.execute("PRAGMA journal_mode = MEMORY")
|
||||
# speedup: temporary tables and indices are kept in memory:
|
||||
cur.execute("PRAGMA temp_store = MEMORY")
|
||||
|
||||
try:
|
||||
cur.execute("SELECT version FROM fail2banDb LIMIT 1")
|
||||
|
@ -203,6 +218,9 @@ class Fail2BanDb(object):
|
|||
Fail2BanDb.__version__, version, newversion)
|
||||
raise RuntimeError('Failed to fully update')
|
||||
finally:
|
||||
# pypy: set journal mode after possible upgrade db:
|
||||
if pypy:
|
||||
cur.execute("PRAGMA journal_mode = MEMORY")
|
||||
cur.close()
|
||||
|
||||
@property
|
||||
|
@ -245,13 +263,14 @@ class Fail2BanDb(object):
|
|||
|
||||
A timestamped backup is also created prior to attempting the update.
|
||||
"""
|
||||
self._dbBackupFilename = self.filename + '.' + time.strftime('%Y%m%d-%H%M%S', MyTime.gmtime())
|
||||
shutil.copyfile(self.filename, self._dbBackupFilename)
|
||||
logSys.info("Database backup created: %s", self._dbBackupFilename)
|
||||
if version > Fail2BanDb.__version__:
|
||||
raise NotImplementedError(
|
||||
"Attempt to travel to future version of database ...how did you get here??")
|
||||
|
||||
self._dbBackupFilename = self.filename + '.' + time.strftime('%Y%m%d-%H%M%S', MyTime.gmtime())
|
||||
shutil.copyfile(self.filename, self._dbBackupFilename)
|
||||
logSys.info("Database backup created: %s", self._dbBackupFilename)
|
||||
|
||||
if version < 2:
|
||||
cur.executescript("BEGIN TRANSACTION;"
|
||||
"CREATE TEMPORARY TABLE logs_temp AS SELECT * FROM logs;"
|
||||
|
@ -455,7 +474,7 @@ class Fail2BanDb(object):
|
|||
queryArgs.append(MyTime.time() - bantime)
|
||||
if ip is not None:
|
||||
query += " AND ip=?"
|
||||
queryArgs.append(ip)
|
||||
queryArgs.append(str(ip))
|
||||
query += " ORDER BY ip, timeofban desc"
|
||||
|
||||
return cur.execute(query, queryArgs)
|
||||
|
|
|
@ -78,9 +78,9 @@ class FailManager:
|
|||
def addFailure(self, ticket, count=1):
|
||||
attempts = 1
|
||||
with self.__lock:
|
||||
ip = ticket.getIP()
|
||||
fid = ticket.getID()
|
||||
try:
|
||||
fData = self.__failList[ip]
|
||||
fData = self.__failList[fid]
|
||||
# if the same object - the same matches but +1 attempt:
|
||||
if fData is ticket:
|
||||
matches = None
|
||||
|
@ -109,7 +109,7 @@ class FailManager:
|
|||
fData = FailTicket(ticket=ticket)
|
||||
if count > ticket.getAttempt():
|
||||
fData.setRetry(count)
|
||||
self.__failList[ip] = fData
|
||||
self.__failList[fid] = fData
|
||||
|
||||
attempts = fData.getRetry()
|
||||
self.__failTotal += 1
|
||||
|
@ -132,7 +132,7 @@ class FailManager:
|
|||
|
||||
def cleanup(self, time):
|
||||
with self.__lock:
|
||||
todelete = [ip for ip,item in self.__failList.iteritems() \
|
||||
todelete = [fid for fid,item in self.__failList.iteritems() \
|
||||
if item.getLastTime() + self.__maxTime <= time]
|
||||
if len(todelete) == len(self.__failList):
|
||||
# remove all:
|
||||
|
@ -142,27 +142,27 @@ class FailManager:
|
|||
return
|
||||
if len(todelete) / 2.0 <= len(self.__failList) / 3.0:
|
||||
# few as 2/3 should be removed - remove particular items:
|
||||
for ip in todelete:
|
||||
del self.__failList[ip]
|
||||
for fid in todelete:
|
||||
del self.__failList[fid]
|
||||
else:
|
||||
# create new dictionary without items to be deleted:
|
||||
self.__failList = dict((ip,item) for ip,item in self.__failList.iteritems() \
|
||||
self.__failList = dict((fid,item) for fid,item in self.__failList.iteritems() \
|
||||
if item.getLastTime() + self.__maxTime > time)
|
||||
self.__bgSvc.service()
|
||||
|
||||
def delFailure(self, ip):
|
||||
def delFailure(self, fid):
|
||||
with self.__lock:
|
||||
try:
|
||||
del self.__failList[ip]
|
||||
del self.__failList[fid]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def toBan(self, ip=None):
|
||||
def toBan(self, fid=None):
|
||||
with self.__lock:
|
||||
for ip in ([ip] if ip != None and ip in self.__failList else self.__failList):
|
||||
data = self.__failList[ip]
|
||||
for fid in ([fid] if fid != None and fid in self.__failList else self.__failList):
|
||||
data = self.__failList[fid]
|
||||
if data.getRetry() >= self.__maxRetry:
|
||||
del self.__failList[ip]
|
||||
del self.__failList[fid]
|
||||
return data
|
||||
self.__bgSvc.service()
|
||||
raise FailManagerEmpty
|
||||
|
|
|
@ -62,18 +62,39 @@ class Regex:
|
|||
def __str__(self):
|
||||
return "%s(%r)" % (self.__class__.__name__, self._regex)
|
||||
|
||||
##
|
||||
# Replaces "<HOST>", "<IP4>", "<IP6>", "<FID>" with default regular expression for host
|
||||
#
|
||||
# (see gh-1374 for the discussion about other candidates)
|
||||
# @return the replaced regular expression as string
|
||||
|
||||
@staticmethod
|
||||
def _resolveHostTag(regex):
|
||||
# Replace "<HOST>" with default regular expression for host:
|
||||
# Other candidates (see gh-1374 for the discussion about):
|
||||
# differentiate: r"""(?:(?:::f{4,6}:)?(?P<IPv4>(?:\d{1,3}\.){3}\d{1,3})|\[?(?P<IPv6>(?:[0-9a-fA-F]{1,4}::?|::){1,7}(?:[0-9a-fA-F]{1,4}|(?<=:):))\]?|(?P<HOST>[\w\-.^_]*\w))"""
|
||||
# expected many changes in filter, failregex, etc...
|
||||
# simple: r"""(?:::f{4,6}:)?(?P<host>[\w\-.^_:]*\w)"""
|
||||
# not good enough, if not precise expressions around <HOST>, because for example will match '1.2.3.4:23930' as ip-address;
|
||||
# Todo: move this functionality to filter reader, as default <HOST> replacement,
|
||||
# make it configurable (via jail/filter configs)
|
||||
return regex.replace("<HOST>",
|
||||
r"""(?:::f{4,6}:)?(?P<host>(?:\d{1,3}\.){3}\d{1,3}|\[?(?:[0-9a-fA-F]{1,4}::?|::){1,7}(?:[0-9a-fA-F]{1,4}\]?|(?<=:):)|[\w\-.^_]*\w)""")
|
||||
# 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:
|
||||
r = r"""(?:::f{4,6}:)?(?P<ip4>(?:\d{1,3}\.){3}\d{1,3})"""
|
||||
regex = regex.replace("<IP4>", r); # self closed
|
||||
regex = regex.replace("<F-IP4/>", r); # closed
|
||||
# separated ipv6:
|
||||
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("<F-IP6/>", r); # closed
|
||||
# separated dns:
|
||||
r = r"""(?P<dns>[\w\-.^_]*\w)"""
|
||||
regex = regex.replace("<DNS>", r); # self closed
|
||||
regex = regex.replace("<F-DNS/>", r); # closed
|
||||
# default failure-id as no space tag:
|
||||
regex = regex.replace("<F-ID/>", r"""(?P<fid>\S+)"""); # closed
|
||||
# default failure port, like 80 or http :
|
||||
regex = regex.replace("<F-PORT/>", r"""(?P<port>\w+)"""); # closed
|
||||
# default failure groups (begin / end tag) for customizable expressions:
|
||||
for o,r in (('IP4', 'ip4'), ('IP6', 'ip6'), ('DNS', 'dns'), ('ID', 'fid'), ('PORT', 'fport')):
|
||||
regex = regex.replace("<F-%s>" % o, "(?P<%s>" % r); # open tag
|
||||
regex = regex.replace("</F-%s>" % o, ")"); # close tag
|
||||
|
||||
return regex
|
||||
|
||||
##
|
||||
# Gets the regular expression.
|
||||
|
@ -207,6 +228,13 @@ class RegexException(Exception):
|
|||
pass
|
||||
|
||||
|
||||
##
|
||||
# Groups used as failure identifier.
|
||||
#
|
||||
# The order of this tuple is important while searching for failure-id
|
||||
#
|
||||
FAILURE_ID_GROPS = ("fid", "ip4", "ip6", "dns")
|
||||
|
||||
##
|
||||
# Regular expression class.
|
||||
#
|
||||
|
@ -220,25 +248,48 @@ class FailRegex(Regex):
|
|||
# Creates a new object. This method can throw RegexException in order to
|
||||
# avoid construction of invalid object.
|
||||
# @param value the regular expression
|
||||
|
||||
|
||||
def __init__(self, regex):
|
||||
# Initializes the parent.
|
||||
Regex.__init__(self, regex)
|
||||
# Check for group "host"
|
||||
if "host" not in self._regexObj.groupindex:
|
||||
raise RegexException("No 'host' group in '%s'" % self._regex)
|
||||
# Check for group "dns", "ip4", "ip6", "fid"
|
||||
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)
|
||||
|
||||
##
|
||||
# Returns the matched host.
|
||||
# Returns all matched groups.
|
||||
#
|
||||
# This corresponds to the pattern matched by the named group "host".
|
||||
# @return the matched host
|
||||
|
||||
def getGroups(self):
|
||||
return self._matchCache.groupdict()
|
||||
|
||||
##
|
||||
# Returns the matched failure id.
|
||||
#
|
||||
# This corresponds to the pattern matched by the named group from given groups.
|
||||
# @return the matched failure-id
|
||||
|
||||
def getHost(self):
|
||||
host = self._matchCache.group("host")
|
||||
if host is None:
|
||||
def getFailID(self, groups=FAILURE_ID_GROPS):
|
||||
fid = None
|
||||
for grp in groups:
|
||||
try:
|
||||
fid = self._matchCache.group(grp)
|
||||
except (IndexError, KeyError):
|
||||
continue
|
||||
if fid is not None:
|
||||
break
|
||||
if fid is None:
|
||||
# Gets a few information.
|
||||
s = self._matchCache.string
|
||||
r = self._matchCache.re
|
||||
raise RegexException("No 'host' found in '%s' using '%s'" % (s, r))
|
||||
return str(host)
|
||||
raise RegexException("No group found in '%s' using '%s'" % (s, r))
|
||||
return str(fid)
|
||||
|
||||
##
|
||||
# Returns the matched host.
|
||||
#
|
||||
# This corresponds to the pattern matched by the named group "ip4", "ip6" or "dns".
|
||||
# @return the matched host
|
||||
|
||||
def getHost(self):
|
||||
return self.getFailID(("ip4", "ip6", "dns"))
|
||||
|
|
|
@ -171,7 +171,7 @@ class Filter(JailThread):
|
|||
if isinstance(value, bool):
|
||||
value = {True: 'yes', False: 'no'}[value]
|
||||
value = value.lower() # must be a string by now
|
||||
if not (value in ('yes', 'no', 'warn')):
|
||||
if not (value in ('yes', 'warn', 'no', 'raw')):
|
||||
logSys.error("Incorrect value %r specified for usedns. "
|
||||
"Using safe 'no'" % (value,))
|
||||
value = 'no'
|
||||
|
@ -418,6 +418,9 @@ class Filter(JailThread):
|
|||
ip = element[1]
|
||||
unixTime = element[2]
|
||||
lines = element[3]
|
||||
fail = {}
|
||||
if len(element) > 4:
|
||||
fail = element[4]
|
||||
logSys.debug("Processing line with time:%s and ip:%s",
|
||||
unixTime, ip)
|
||||
if unixTime < MyTime.time() - self.getFindTime():
|
||||
|
@ -429,7 +432,7 @@ class Filter(JailThread):
|
|||
logSys.info(
|
||||
"[%s] Found %s - %s", self.jail.name, ip, datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S")
|
||||
)
|
||||
tick = FailTicket(ip, unixTime, lines)
|
||||
tick = FailTicket(ip, unixTime, lines, data=fail)
|
||||
self.failManager.addFailure(tick)
|
||||
|
||||
##
|
||||
|
@ -457,7 +460,12 @@ class Filter(JailThread):
|
|||
checkAllRegex=False):
|
||||
failList = list()
|
||||
|
||||
# Checks if we must ignore this line.
|
||||
cidr = IPAddr.CIDR_UNSPEC
|
||||
if self.__useDns == "raw":
|
||||
returnRawHost = True
|
||||
cidr = IPAddr.CIDR_RAW
|
||||
|
||||
# Checks if we mut ignore this line.
|
||||
if self.ignoreLine([tupleLine[::2]]) is not None:
|
||||
# The ignoreregex matched. Return.
|
||||
logSys.log(7, "Matched ignoreregex and was \"%s\" ignored",
|
||||
|
@ -518,19 +526,41 @@ class Filter(JailThread):
|
|||
% ("\n".join(failRegex.getMatchedLines()), timeText))
|
||||
else:
|
||||
self.__lineBuffer = failRegex.getUnmatchedTupleLines()
|
||||
# retrieve failure-id, host, etc from failure match:
|
||||
raw = returnRawHost
|
||||
try:
|
||||
host = failRegex.getHost()
|
||||
if returnRawHost:
|
||||
failList.append([failRegexIndex, IPAddr(host), date,
|
||||
failRegex.getMatchedLines()])
|
||||
fail = failRegex.getGroups()
|
||||
# failure-id:
|
||||
fid = fail.get('fid')
|
||||
# ip-address or host:
|
||||
host = fail.get('ip4') or fail.get('ip6')
|
||||
if host is not None:
|
||||
raw = True
|
||||
else:
|
||||
host = fail.get('dns')
|
||||
if host is None:
|
||||
# if no failure-id also (obscure case, wrong regex), throw error inside getFailID:
|
||||
if fid is None:
|
||||
fid = failRegex.getFailID()
|
||||
host = fid
|
||||
cidr = IPAddr.CIDR_RAW
|
||||
# if raw - add single ip or failure-id,
|
||||
# otherwise expand host to multiple ips using dns (or ignore it if not valid):
|
||||
if raw:
|
||||
ip = IPAddr(host, cidr)
|
||||
# check host equal failure-id, if not - failure with complex id:
|
||||
if fid is not None and fid != host:
|
||||
ip = IPAddr(fid, IPAddr.CIDR_RAW)
|
||||
failList.append([failRegexIndex, ip, date,
|
||||
failRegex.getMatchedLines(), fail])
|
||||
if not checkAllRegex:
|
||||
break
|
||||
else:
|
||||
ips = DNSUtils.textToIp(host, self.__useDns)
|
||||
if ips:
|
||||
for ip in ips:
|
||||
failList.append([failRegexIndex, ip,
|
||||
date, failRegex.getMatchedLines()])
|
||||
failList.append([failRegexIndex, ip, date,
|
||||
failRegex.getMatchedLines(), fail])
|
||||
if not checkAllRegex:
|
||||
break
|
||||
except RegexException, e: # pragma: no cover - unsure if reachable
|
||||
|
|
|
@ -85,10 +85,7 @@ class DNSUtils:
|
|||
return v
|
||||
# retrieve name
|
||||
try:
|
||||
if not isinstance(ip, IPAddr):
|
||||
v = socket.gethostbyaddr(ip)[0]
|
||||
else:
|
||||
v = socket.gethostbyaddr(ip.ntoa)[0]
|
||||
v = socket.gethostbyaddr(ip)[0]
|
||||
except socket.error, e:
|
||||
logSys.debug("Unable to find a name for the IP %s: %s", ip, e)
|
||||
v = None
|
||||
|
@ -138,18 +135,21 @@ class IPAddr(object):
|
|||
# todo: make configurable the expired time and max count of cache entries:
|
||||
CACHE_OBJ = Utils.Cache(maxCount=1000, maxTime=5*60)
|
||||
|
||||
def __new__(cls, ipstr, cidr=-1):
|
||||
CIDR_RAW = -2
|
||||
CIDR_UNSPEC = -1
|
||||
|
||||
def __new__(cls, ipstr, cidr=CIDR_UNSPEC):
|
||||
# check already cached as IPAddr
|
||||
args = (ipstr, cidr)
|
||||
ip = IPAddr.CACHE_OBJ.get(args)
|
||||
if ip is not None:
|
||||
return ip
|
||||
# wrap mask to cidr (correct plen):
|
||||
if cidr == -1:
|
||||
if cidr == IPAddr.CIDR_UNSPEC:
|
||||
ipstr, cidr = IPAddr.__wrap_ipstr(ipstr)
|
||||
args = (ipstr, cidr)
|
||||
# check cache again:
|
||||
if cidr != -1:
|
||||
if cidr != IPAddr.CIDR_UNSPEC:
|
||||
ip = IPAddr.CACHE_OBJ.get(args)
|
||||
if ip is not None:
|
||||
return ip
|
||||
|
@ -166,17 +166,17 @@ class IPAddr(object):
|
|||
ipstr = ipstr[1:-1]
|
||||
# test mask:
|
||||
if "/" not in ipstr:
|
||||
return ipstr, -1
|
||||
return ipstr, IPAddr.CIDR_UNSPEC
|
||||
s = ipstr.split('/', 1)
|
||||
# IP address without CIDR mask
|
||||
if len(s) > 2:
|
||||
raise ValueError("invalid ipstr %r, too many plen representation" % (ipstr,))
|
||||
if "." in s[1]: # 255.255.255.0 style mask
|
||||
if "." in s[1] or ":" in s[1]: # 255.255.255.0 resp. ffff:: style mask
|
||||
s[1] = IPAddr.masktoplen(s[1])
|
||||
s[1] = long(s[1])
|
||||
return s
|
||||
|
||||
def __init(self, ipstr, cidr=-1):
|
||||
def __init(self, ipstr, cidr=CIDR_UNSPEC):
|
||||
""" initialize IP object by converting IP address string
|
||||
to binary to integer
|
||||
"""
|
||||
|
@ -184,55 +184,62 @@ class IPAddr(object):
|
|||
self._addr = 0
|
||||
self._plen = 0
|
||||
self._maskplen = None
|
||||
self._raw = ""
|
||||
# always save raw value (normally used if really raw or not valid only):
|
||||
self._raw = ipstr
|
||||
# if not raw - recognize family, set addr, etc.:
|
||||
if cidr != IPAddr.CIDR_RAW:
|
||||
for family in [socket.AF_INET, socket.AF_INET6]:
|
||||
try:
|
||||
binary = socket.inet_pton(family, ipstr)
|
||||
self._family = family
|
||||
break
|
||||
except socket.error:
|
||||
continue
|
||||
|
||||
for family in [socket.AF_INET, socket.AF_INET6]:
|
||||
try:
|
||||
binary = socket.inet_pton(family, ipstr)
|
||||
self._family = family
|
||||
break
|
||||
except socket.error:
|
||||
continue
|
||||
|
||||
if self._family == socket.AF_INET:
|
||||
# convert host to network byte order
|
||||
self._addr, = struct.unpack("!L", binary)
|
||||
self._plen = 32
|
||||
|
||||
# mask out host portion if prefix length is supplied
|
||||
if cidr is not None and cidr >= 0:
|
||||
mask = ~(0xFFFFFFFFL >> cidr)
|
||||
self._addr &= mask
|
||||
self._plen = cidr
|
||||
|
||||
elif self._family == socket.AF_INET6:
|
||||
# convert host to network byte order
|
||||
hi, lo = struct.unpack("!QQ", binary)
|
||||
self._addr = (hi << 64) | lo
|
||||
self._plen = 128
|
||||
|
||||
# mask out host portion if prefix length is supplied
|
||||
if cidr is not None and cidr >= 0:
|
||||
mask = ~(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL >> cidr)
|
||||
self._addr &= mask
|
||||
self._plen = cidr
|
||||
|
||||
# if IPv6 address is a IPv4-compatible, make instance a IPv4
|
||||
elif self.isInNet(IPAddr.IP6_4COMPAT):
|
||||
self._addr = lo & 0xFFFFFFFFL
|
||||
self._family = socket.AF_INET
|
||||
if self._family == socket.AF_INET:
|
||||
# convert host to network byte order
|
||||
self._addr, = struct.unpack("!L", binary)
|
||||
self._plen = 32
|
||||
|
||||
# mask out host portion if prefix length is supplied
|
||||
if cidr is not None and cidr >= 0:
|
||||
mask = ~(0xFFFFFFFFL >> cidr)
|
||||
self._addr &= mask
|
||||
self._plen = cidr
|
||||
|
||||
elif self._family == socket.AF_INET6:
|
||||
# convert host to network byte order
|
||||
hi, lo = struct.unpack("!QQ", binary)
|
||||
self._addr = (hi << 64) | lo
|
||||
self._plen = 128
|
||||
|
||||
# mask out host portion if prefix length is supplied
|
||||
if cidr is not None and cidr >= 0:
|
||||
mask = ~(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL >> cidr)
|
||||
self._addr &= mask
|
||||
self._plen = cidr
|
||||
|
||||
# if IPv6 address is a IPv4-compatible, make instance a IPv4
|
||||
elif self.isInNet(IPAddr.IP6_4COMPAT):
|
||||
self._addr = lo & 0xFFFFFFFFL
|
||||
self._family = socket.AF_INET
|
||||
self._plen = 32
|
||||
else:
|
||||
# string couldn't be converted neither to a IPv4 nor
|
||||
# to a IPv6 address - retain raw input for later use
|
||||
# (e.g. DNS resolution)
|
||||
self._raw = ipstr
|
||||
self._family = IPAddr.CIDR_RAW
|
||||
|
||||
def __repr__(self):
|
||||
return self.ntoa
|
||||
|
||||
def __str__(self):
|
||||
return self.ntoa
|
||||
|
||||
def __reduce__(self):
|
||||
"""IPAddr pickle-handler, that simply wraps IPAddr to the str
|
||||
|
||||
Returns a string as instance to be pickled, because fail2ban-client can't
|
||||
unserialize IPAddr objects
|
||||
"""
|
||||
return (str, (self.ntoa,))
|
||||
|
||||
@property
|
||||
def addr(self):
|
||||
|
@ -262,6 +269,8 @@ class IPAddr(object):
|
|||
return self._family != socket.AF_UNSPEC
|
||||
|
||||
def __eq__(self, other):
|
||||
if self._family == IPAddr.CIDR_RAW and not isinstance(other, IPAddr):
|
||||
return self._raw == other
|
||||
if not isinstance(other, IPAddr):
|
||||
if other is None: return False
|
||||
other = IPAddr(other)
|
||||
|
@ -277,6 +286,8 @@ class IPAddr(object):
|
|||
return not (self == other)
|
||||
|
||||
def __lt__(self, other):
|
||||
if self._family == IPAddr.CIDR_RAW and not isinstance(other, IPAddr):
|
||||
return self._raw < other
|
||||
if not isinstance(other, IPAddr):
|
||||
if other is None: return False
|
||||
other = IPAddr(other)
|
||||
|
@ -345,7 +356,7 @@ class IPAddr(object):
|
|||
if not suffix:
|
||||
suffix = "in-addr.arpa."
|
||||
elif self.isIPv6:
|
||||
exploded_ip = self.hexdump()
|
||||
exploded_ip = self.hexdump
|
||||
if not suffix:
|
||||
suffix = "ip6.arpa."
|
||||
else:
|
||||
|
@ -384,17 +395,29 @@ class IPAddr(object):
|
|||
|
||||
return (self.addr & mask) == net.addr
|
||||
|
||||
# Pre-calculated map: addr to maskplen
|
||||
def __getMaskMap():
|
||||
m6 = (1 << 128)-1
|
||||
m4 = (1 << 32)-1
|
||||
mmap = {m6: 128, m4: 32, 0: 0}
|
||||
m = 0
|
||||
for i in xrange(0, 128):
|
||||
m |= 1 << i
|
||||
if i < 32:
|
||||
mmap[m ^ m4] = 32-1-i
|
||||
mmap[m ^ m6] = 128-1-i
|
||||
return mmap
|
||||
|
||||
MAP_ADDR2MASKPLEN = __getMaskMap()
|
||||
|
||||
@property
|
||||
def maskplen(self):
|
||||
mplen = 0
|
||||
if self._maskplen is not None:
|
||||
return self._maskplen
|
||||
maddr = self._addr
|
||||
while maddr:
|
||||
if not (maddr & 0x80000000):
|
||||
raise ValueError("invalid mask %r, no plen representation" % (str(self),))
|
||||
maddr = (maddr << 1) & 0xFFFFFFFFL
|
||||
mplen += 1
|
||||
mplen = IPAddr.MAP_ADDR2MASKPLEN.get(self._addr)
|
||||
if mplen is None:
|
||||
raise ValueError("invalid mask %r, no plen representation" % (str(self),))
|
||||
self._maskplen = mplen
|
||||
return mplen
|
||||
|
||||
|
|
|
@ -299,8 +299,10 @@ class Server:
|
|||
flt = self.__jails[name].filter
|
||||
if multiple:
|
||||
for value in value:
|
||||
logSys.debug(" failregex: %r", value)
|
||||
flt.addFailRegex(value)
|
||||
else:
|
||||
logSys.debug(" failregex: %r", value)
|
||||
flt.addFailRegex(value)
|
||||
|
||||
def delFailRegex(self, name, index):
|
||||
|
@ -313,8 +315,10 @@ class Server:
|
|||
flt = self.__jails[name].filter
|
||||
if multiple:
|
||||
for value in value:
|
||||
logSys.debug(" ignoreregex: %r", value)
|
||||
flt.addIgnoreRegex(value)
|
||||
else:
|
||||
logSys.debug(" ignoreregex: %r", value)
|
||||
flt.addIgnoreRegex(value)
|
||||
|
||||
def delIgnoreRegex(self, name, index):
|
||||
|
|
|
@ -36,7 +36,7 @@ logSys = getLogger(__name__)
|
|||
|
||||
class Ticket:
|
||||
|
||||
def __init__(self, ip=None, time=None, matches=None, ticket=None):
|
||||
def __init__(self, ip=None, time=None, matches=None, data={}, ticket=None):
|
||||
"""Ticket constructor
|
||||
|
||||
@param ip the IP address
|
||||
|
@ -50,6 +50,7 @@ class Ticket:
|
|||
self._banTime = None;
|
||||
self._time = time if time is not None else MyTime.time()
|
||||
self._data = {'matches': [], 'failures': 0}
|
||||
self._data.update(data)
|
||||
if ticket:
|
||||
# ticket available - copy whole information from ticket:
|
||||
self.__dict__.update(i for i in ticket.__dict__.iteritems() if i[0] in self.__dict__)
|
||||
|
@ -78,6 +79,9 @@ class Ticket:
|
|||
value = IPAddr(value)
|
||||
self.__ip = value
|
||||
|
||||
def getID(self):
|
||||
return self._data.get('fid', self.__ip)
|
||||
|
||||
def getIP(self):
|
||||
return self.__ip
|
||||
|
||||
|
@ -164,12 +168,12 @@ class Ticket:
|
|||
|
||||
class FailTicket(Ticket):
|
||||
|
||||
def __init__(self, ip=None, time=None, matches=None, ticket=None):
|
||||
def __init__(self, ip=None, time=None, matches=None, data={}, ticket=None):
|
||||
# this class variables:
|
||||
self.__retry = 0
|
||||
self.__lastReset = None
|
||||
# create/copy using default ticket constructor:
|
||||
Ticket.__init__(self, ip, time, matches, ticket)
|
||||
Ticket.__init__(self, ip, time, matches, data, ticket)
|
||||
# init:
|
||||
if ticket is None:
|
||||
self.__lastReset = time if time is not None else self.getTime()
|
||||
|
|
|
@ -52,7 +52,7 @@ class Transmitter:
|
|||
|
||||
def proceed(self, command):
|
||||
# Deserialize object
|
||||
logSys.debug("Command: " + repr(command))
|
||||
logSys.debug("Command: %r", command)
|
||||
try:
|
||||
ret = self.__commandHandler(command)
|
||||
ack = 0, ret
|
||||
|
@ -265,6 +265,7 @@ class Transmitter:
|
|||
action = self.__server.getAction(name, actionname)
|
||||
if multiple:
|
||||
for cmd in command[3]:
|
||||
logSys.debug(" %r", cmd)
|
||||
actionkey = cmd[0]
|
||||
if callable(getattr(action, actionkey, None)):
|
||||
actionvalue = json.loads(cmd[1]) if len(cmd)>1 else {}
|
||||
|
|
|
@ -39,6 +39,7 @@ if sys.version_info >= (2,7):
|
|||
self.jail.actions.add("badips", pythonModule, initOpts={
|
||||
'category': "ssh",
|
||||
'banaction': "test",
|
||||
'timeout': (3 if unittest.F2B.fast else 30),
|
||||
})
|
||||
self.action = self.jail.actions["badips"]
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import time
|
|||
import unittest
|
||||
|
||||
from ..server.action import CommandAction, CallingMap
|
||||
from ..server.actions import OrderedDict
|
||||
from ..server.utils import Utils
|
||||
|
||||
from .utils import LogCaptureTestCase
|
||||
|
@ -65,6 +66,62 @@ class CommandActionTest(LogCaptureTestCase):
|
|||
lambda: CommandAction.substituteRecursiveTags({'A': 'to=<B> fromip=<IP>', 'C': '<B>', 'B': '<C>', 'D': ''}))
|
||||
self.assertRaises(ValueError,
|
||||
lambda: CommandAction.substituteRecursiveTags({'failregex': 'to=<honeypot> fromip=<IP>', 'sweet': '<honeypot>', 'honeypot': '<sweet>', 'ignoreregex': ''}))
|
||||
# We need here an ordered, because the sequence of iteration is very important for this test
|
||||
if OrderedDict:
|
||||
# No cyclic recursion, just multiple replacement of tag <T>, should be successful:
|
||||
self.assertEqual(CommandAction.substituteRecursiveTags( OrderedDict(
|
||||
(('X', 'x=x<T>'), ('T', '1'), ('Z', '<X> <T> <Y>'), ('Y', 'y=y<T>')))
|
||||
), {'X': 'x=x1', 'T': '1', 'Y': 'y=y1', 'Z': 'x=x1 1 y=y1'}
|
||||
)
|
||||
# No cyclic recursion, just multiple replacement of tag <T> in composite tags, should be successful:
|
||||
self.assertEqual(CommandAction.substituteRecursiveTags( OrderedDict(
|
||||
(('X', 'x=x<T> <Z> <<R1>> <<R2>>'), ('R1', 'Z'), ('R2', 'Y'), ('T', '1'), ('Z', '<T> <Y>'), ('Y', 'y=y<T>')))
|
||||
), {'X': 'x=x1 1 y=y1 1 y=y1 y=y1', 'R1': 'Z', 'R2': 'Y', 'T': '1', 'Z': '1 y=y1', 'Y': 'y=y1'}
|
||||
)
|
||||
# No cyclic recursion, just multiple replacement of same tags, should be successful:
|
||||
self.assertEqual(CommandAction.substituteRecursiveTags( OrderedDict((
|
||||
('actionstart', 'ipset create <ipmset> hash:ip timeout <bantime> family <ipsetfamily>\n<iptables> -I <chain> <actiontype>'),
|
||||
('ipmset', 'f2b-<name>'),
|
||||
('name', 'any'),
|
||||
('bantime', '600'),
|
||||
('ipsetfamily', 'inet'),
|
||||
('iptables', 'iptables <lockingopt>'),
|
||||
('lockingopt', '-w'),
|
||||
('chain', 'INPUT'),
|
||||
('actiontype', '<multiport>'),
|
||||
('multiport', '-p <protocol> -m multiport --dports <port> -m set --match-set <ipmset> src -j <blocktype>'),
|
||||
('protocol', 'tcp'),
|
||||
('port', 'ssh'),
|
||||
('blocktype', 'REJECT',),
|
||||
))
|
||||
), OrderedDict((
|
||||
('actionstart', 'ipset create f2b-any hash:ip timeout 600 family inet\niptables -w -I INPUT -p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
|
||||
('ipmset', 'f2b-any'),
|
||||
('name', 'any'),
|
||||
('bantime', '600'),
|
||||
('ipsetfamily', 'inet'),
|
||||
('iptables', 'iptables -w'),
|
||||
('lockingopt', '-w'),
|
||||
('chain', 'INPUT'),
|
||||
('actiontype', '-p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
|
||||
('multiport', '-p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
|
||||
('protocol', 'tcp'),
|
||||
('port', 'ssh'),
|
||||
('blocktype', 'REJECT')
|
||||
))
|
||||
)
|
||||
# Cyclic recursion by composite tag creation, tags "create" another tag, that closes cycle:
|
||||
self.assertRaises(ValueError, lambda: CommandAction.substituteRecursiveTags( OrderedDict((
|
||||
('A', '<<B><C>>'),
|
||||
('B', 'D'), ('C', 'E'),
|
||||
('DE', 'cycle <A>'),
|
||||
)) ))
|
||||
self.assertRaises(ValueError, lambda: CommandAction.substituteRecursiveTags( OrderedDict((
|
||||
('DE', 'cycle <A>'),
|
||||
('A', '<<B><C>>'),
|
||||
('B', 'D'), ('C', 'E'),
|
||||
)) ))
|
||||
|
||||
# missing tags are ok
|
||||
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<C>'}), {'A': '<C>'})
|
||||
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<C> <D> <X>','X':'fun'}), {'A': '<C> <D> fun', 'X':'fun'})
|
||||
|
|
|
@ -45,7 +45,7 @@ TEST_FILES_DIR_SHARE_CFG = {}
|
|||
from .utils import CONFIG_DIR
|
||||
CONFIG_DIR_SHARE_CFG = unittest.F2B.share_config
|
||||
|
||||
STOCK = os.path.exists(os.path.join('config','fail2ban.conf'))
|
||||
STOCK = os.path.exists(os.path.join('config', 'fail2ban.conf'))
|
||||
|
||||
IMPERFECT_CONFIG = os.path.join(os.path.dirname(__file__), 'config')
|
||||
IMPERFECT_CONFIG_SHARE_CFG = {}
|
||||
|
@ -255,6 +255,13 @@ class JailReaderTest(LogCaptureTestCase):
|
|||
result = JailReader.extractOptions(option)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
# And multiple groups (`][` instead of `,`)
|
||||
result = JailReader.extractOptions(option.replace(',', ']['))
|
||||
expected2 = (expected[0],
|
||||
dict((k, v.replace(',', '][')) for k, v in expected[1].iteritems())
|
||||
)
|
||||
self.assertEqual(expected2, result)
|
||||
|
||||
def testVersionAgent(self):
|
||||
jail = JailReader('blocklisttest', force_enable=True, basedir=CONFIG_DIR)
|
||||
# emulate jail.read(), because such jail not exists:
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# Fail2Ban generic example resp. test filter
|
||||
#
|
||||
# Author: Serg G. Brester (sebres)
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
# Read common prefixes. If any customizations available -- read them from
|
||||
# common.local
|
||||
before = ../../../../config/filter.d/common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
_daemon = test-demo
|
||||
|
||||
failregex = ^%(__prefix_line)sF2B: failure from <HOST>$
|
||||
ignoreregex =
|
|
@ -120,6 +120,15 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
|||
self.assertLogged('Dez 31 11:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128')
|
||||
self.assertLogged('Dec 31 11:59:59 [sshd] error: PAM: Authentication failure for kevin from 87.142.124.10')
|
||||
|
||||
def testDirectRE_1raw(self):
|
||||
(opts, args, fail2banRegex) = _Fail2banRegex(
|
||||
"--print-all-matched", "--raw",
|
||||
Fail2banRegexTest.FILENAME_01,
|
||||
Fail2banRegexTest.RE_00
|
||||
)
|
||||
self.assertTrue(fail2banRegex.start(opts, args))
|
||||
self.assertLogged('Lines: 19 lines, 0 ignored, 16 matched, 3 missed')
|
||||
|
||||
def testDirectRE_2(self):
|
||||
(opts, args, fail2banRegex) = _Fail2banRegex(
|
||||
"--print-all-matched",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
import requests
|
||||
|
||||
try:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
if sys.argv[1] == "10.0.0.1":
|
||||
exit(0)
|
||||
|
|
|
@ -67,3 +67,7 @@ Nov 4 18:30:40 localhost asterisk[32229]: NOTICE[32257]: chan_sip.c:23417 in han
|
|||
[2016-01-28 10:34:31] NOTICE[3477][C-000003c3] chan_sip.c: Call from '' (1.2.3.4:10836) to extension '0+441772285407' rejected because extension not found in context 'default'.
|
||||
# failJSON: { "time": "2016-01-28T10:34:33", "match": true , "host": "1.2.3.4" }
|
||||
[2016-01-28 10:34:33] NOTICE[3477][C-000003c3] chan_sip.c: Call from '' (1.2.3.4:10836) to extension '' rejected because extension not found in context 'my-context'.
|
||||
|
||||
# Failed authentication with pjsip on Asterisk 13+
|
||||
# failJSON: { "time": "2016-05-23T10:18:16", "match": true , "host": "1.2.3.4" }
|
||||
[2016-05-23 10:18:16] NOTICE[19388] res_pjsip/pjsip_distributor.c: Request from '"1000" <sip:1000@10.0.0.1>' failed for '1.2.3.4:48336' (callid: 276666022) - No matching endpoint found
|
|
@ -10,3 +10,5 @@ Jul 6 03:42:28 whistler courieresmtpd: error,relay=::ffff:1.2.3.4,from=<>,to=<a
|
|||
Nov 21 23:16:17 server courieresmtpd: error,relay=::ffff:1.2.3.4,from=<>,to=<>: 550 User unknown.
|
||||
# failJSON: { "time": "2004-08-14T12:51:04", "match": true , "host": "1.2.3.4" }
|
||||
Aug 14 12:51:04 HOSTNAME courieresmtpd: error,relay=::ffff:1.2.3.4,from=<firozquarl@aclunc.org>,to=<BOGUSUSER@HOSTEDDOMAIN.org>: 550 User unknown.
|
||||
# failJSON: { "time": "2004-08-14T12:51:04", "match": true , "host": "1.2.3.4" }
|
||||
Aug 14 12:51:04 mail.server courieresmtpd[26762]: error,relay=::ffff:1.2.3.4,msg="535 Authentication failed.",cmd: AUTH PLAIN AAAAABBBBCCCCWxlZA== admin
|
||||
|
|
|
@ -48,10 +48,14 @@
|
|||
2016-03-18 00:34:06 [7513] SMTP protocol error in "AUTH LOGIN" H=(ylmf-pc) [45.32.34.167]:60723 I=[172.89.0.6]:587 AUTH command used when not advertised
|
||||
# failJSON: { "time": "2016-03-19T18:40:44", "match": true , "host": "92.45.204.170" }
|
||||
2016-03-19 18:40:44 [26221] SMTP protocol error in "AUTH LOGIN aW5mb0BtYW5iYXQub3Jn" H=([127.0.0.1]) [92.45.204.170]:14243 I=[172.89.0.6]:587 AUTH command used when not advertised
|
||||
# failJSON: { "time": "2016-05-17T06:25:27", "match": true , "host": "69.10.61.61", "desc": "from gh-1430" }
|
||||
2016-05-17 06:25:27 SMTP protocol error in "AUTH LOGIN" H=(ylmf-pc) [69.10.61.61] AUTH command used when not advertised
|
||||
# failJSON: { "time": "2016-03-21T06:38:05", "match": true , "host": "49.212.207.15" }
|
||||
2016-03-21 06:38:05 [5718] no MAIL in SMTP connection from www3005.sakura.ne.jp [49.212.207.15]:28890 I=[172.89.0.6]:25 D=21s C=EHLO,STARTTLS
|
||||
# failJSON: { "time": "2016-03-21T06:57:36", "match": true , "host": "122.165.71.116" }
|
||||
2016-03-21 06:57:36 [5908] no MAIL in SMTP connection from [122.165.71.116]:2056 I=[172.89.0.6]:25 D=10s
|
||||
# failJSON: { "time": "2016-03-21T06:57:36", "match": true , "host": "122.165.71.116" }
|
||||
2016-03-21 06:57:36 [5908] no MAIL in SMTP connection from [122.165.71.116] I=[172.89.0.6]:25 D=10s
|
||||
# failJSON: { "time": "2016-03-21T04:07:49", "match": true , "host": "174.137.147.204" }
|
||||
2016-03-21 04:07:49 [25874] 1ahr79-0006jK-G9 SMTP connection from (voyeur.webair.com) [174.137.147.204]:44884 I=[172.89.0.6]:25 closed by DROP in ACL
|
||||
# failJSON: { "time": "2016-03-21T04:33:13", "match": true , "host": "206.214.71.53" }
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# -- _daemon with __pid_re, without __hostname --
|
||||
# failJSON: { "time": "2005-06-21T16:47:46", "match": true , "host": "192.0.2.1" }
|
||||
Jun 21 16:47:46 machine test-demo[13709]: F2B: failure from 192.0.2.1
|
||||
# -- _daemon with __pid_re --
|
||||
# failJSON: { "time": "2005-06-21T16:47:48", "match": true , "host": "192.0.2.1" }
|
||||
Jun 21 16:47:48 test-demo[13709]: F2B: failure from 192.0.2.1
|
||||
|
||||
# -- __kernel_prefix --
|
||||
# failJSON: { "time": "2005-06-21T16:47:50", "match": true , "host": "192.0.2.2" }
|
||||
Jun 21 16:47:50 machine kernel: [ 970.699396] F2B: failure from 192.0.2.2
|
||||
|
||||
# -- _daemon_re with and without __pid_re --
|
||||
# failJSON: { "time": "2005-06-21T16:47:52", "match": true , "host": "192.0.2.3" }
|
||||
Jun 21 16:47:52 machine [test-demo] F2B: failure from 192.0.2.3
|
||||
# failJSON: { "time": "2005-06-21T16:47:53", "match": true , "host": "192.0.2.3" }
|
||||
Jun 21 16:47:53 machine [test-demo][13709] F2B: failure from 192.0.2.3
|
||||
# failJSON: { "time": "2005-06-21T16:50:00", "match": true , "host": "192.0.2.3" }
|
||||
Jun 21 16:50:00 machine test-demo(pam_unix) F2B: failure from 192.0.2.3
|
||||
# failJSON: { "time": "2005-06-21T16:50:02", "match": true , "host": "192.0.2.3" }
|
||||
Jun 21 16:50:02 machine test-demo(pam_unix)[13709] F2B: failure from 192.0.2.3
|
||||
|
||||
|
||||
# -- all common definitions together (bsdverbose hostname kernel_prefix vserver tag daemon_id space) --
|
||||
# failJSON: { "time": "2005-06-21T16:55:01", "match": true , "host": "192.0.2.3" }
|
||||
Jun 21 16:55:01 <auth.info> machine kernel: [ 970.699396] @vserver_demo test-demo(pam_unix)[13709] [ID 255 test] F2B: failure from 192.0.2.3
|
||||
# -- the same as above with additional spaces around --
|
||||
# failJSON: { "time": "2005-06-21T16:55:02", "match": true , "host": "192.0.2.3" }
|
||||
Jun 21 16:55:02 <auth.info> machine kernel: [ 970.699396] @vserver_demo test-demo(pam_unix)[13709] [ID 255 test] F2B: failure from 192.0.2.3
|
||||
# -- the same as above with brackets as date ambit --
|
||||
# failJSON: { "time": "2005-06-21T16:55:03", "match": true , "host": "192.0.2.3" }
|
||||
[Jun 21 16:55:03] <auth.info> machine kernel: [ 970.699396] @vserver_demo test-demo(pam_unix)[13709] [ID 255 test] F2B: failure from 192.0.2.3
|
|
@ -1353,13 +1353,51 @@ class DNSUtilsNetworkTests(unittest.TestCase):
|
|||
"""Call before every test case."""
|
||||
unittest.F2B.SkipIfNoNetwork()
|
||||
|
||||
def test_IPAddr(self):
|
||||
self.assertTrue(IPAddr('192.0.2.1').isIPv4)
|
||||
self.assertTrue(IPAddr('2001:DB8::').isIPv6)
|
||||
|
||||
def test_IPAddr_Raw(self):
|
||||
# raw string:
|
||||
r = IPAddr('xxx', IPAddr.CIDR_RAW)
|
||||
self.assertFalse(r.isIPv4)
|
||||
self.assertFalse(r.isIPv6)
|
||||
self.assertTrue(r.isValid)
|
||||
self.assertEqual(r, 'xxx')
|
||||
self.assertEqual('xxx', str(r))
|
||||
self.assertNotEqual(r, IPAddr('xxx'))
|
||||
# raw (not IP, for example host:port as string):
|
||||
r = IPAddr('1:2', IPAddr.CIDR_RAW)
|
||||
self.assertFalse(r.isIPv4)
|
||||
self.assertFalse(r.isIPv6)
|
||||
self.assertTrue(r.isValid)
|
||||
self.assertEqual(r, '1:2')
|
||||
self.assertEqual('1:2', str(r))
|
||||
self.assertNotEqual(r, IPAddr('1:2'))
|
||||
# raw vs ip4 (raw is not an ip):
|
||||
r = IPAddr('93.184.0.1', IPAddr.CIDR_RAW)
|
||||
ip4 = IPAddr('93.184.0.1')
|
||||
self.assertNotEqual(ip4, r)
|
||||
self.assertNotEqual(r, ip4)
|
||||
self.assertTrue(r < ip4)
|
||||
self.assertTrue(r < ip4)
|
||||
# raw vs ip6 (raw is not an ip):
|
||||
r = IPAddr('1::2', IPAddr.CIDR_RAW)
|
||||
ip6 = IPAddr('1::2')
|
||||
self.assertNotEqual(ip6, r)
|
||||
self.assertNotEqual(r, ip6)
|
||||
self.assertTrue(r < ip6)
|
||||
self.assertTrue(r < ip6)
|
||||
|
||||
def testUseDns(self):
|
||||
res = DNSUtils.textToIp('www.example.com', 'no')
|
||||
self.assertEqual(res, [])
|
||||
res = DNSUtils.textToIp('www.example.com', 'warn')
|
||||
self.assertEqual(res, ['93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'])
|
||||
# sort ipaddr, IPv4 is always smaller as IPv6
|
||||
self.assertEqual(sorted(res), ['93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'])
|
||||
res = DNSUtils.textToIp('www.example.com', 'yes')
|
||||
self.assertEqual(res, ['93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'])
|
||||
# sort ipaddr, IPv4 is always smaller as IPv6
|
||||
self.assertEqual(sorted(res), ['93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'])
|
||||
|
||||
def testTextToIp(self):
|
||||
# Test hostnames
|
||||
|
@ -1371,17 +1409,29 @@ class DNSUtilsNetworkTests(unittest.TestCase):
|
|||
for s in hostnames:
|
||||
res = DNSUtils.textToIp(s, 'yes')
|
||||
if s == 'www.example.com':
|
||||
self.assertEqual(res, ['93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'])
|
||||
# sort ipaddr, IPv4 is always smaller as IPv6
|
||||
self.assertEqual(sorted(res), ['93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'])
|
||||
else:
|
||||
self.assertEqual(res, [])
|
||||
# pure ips:
|
||||
for s in ('93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'):
|
||||
ips = DNSUtils.textToIp(s, 'yes')
|
||||
self.assertEqual(ips, [s])
|
||||
self.assertTrue(isinstance(ips[0], IPAddr))
|
||||
|
||||
def testIpToName(self):
|
||||
unittest.F2B.SkipIfNoNetwork()
|
||||
res = DNSUtils.ipToName('8.8.4.4')
|
||||
self.assertEqual(res, 'google-public-dns-b.google.com')
|
||||
# same as above, but with IPAddr:
|
||||
res = DNSUtils.ipToName(IPAddr('8.8.4.4'))
|
||||
self.assertEqual(res, 'google-public-dns-b.google.com')
|
||||
# invalid ip (TEST-NET-1 according to RFC 5737)
|
||||
res = DNSUtils.ipToName('192.0.2.0')
|
||||
self.assertEqual(res, None)
|
||||
# invalid ip:
|
||||
res = DNSUtils.ipToName('192.0.2.888')
|
||||
self.assertEqual(res, None)
|
||||
|
||||
def testAddr2bin(self):
|
||||
res = IPAddr('10.0.0.0')
|
||||
|
@ -1395,11 +1445,44 @@ class DNSUtilsNetworkTests(unittest.TestCase):
|
|||
res = IPAddr('10.0.0.1', cidr=31L)
|
||||
self.assertEqual(res.addr, 167772160L)
|
||||
|
||||
self.assertEqual(IPAddr('10.0.0.0').hexdump, '0a000000')
|
||||
self.assertEqual(IPAddr('1::2').hexdump, '00010000000000000000000000000002')
|
||||
self.assertEqual(IPAddr('xxx').hexdump, '')
|
||||
|
||||
self.assertEqual(IPAddr('192.0.2.0').getPTR(), '0.2.0.192.in-addr.arpa.')
|
||||
self.assertEqual(IPAddr('192.0.2.1').getPTR(), '1.2.0.192.in-addr.arpa.')
|
||||
self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8:1946').getPTR(),
|
||||
'6.4.9.1.8.c.5.2.3.9.8.1.8.4.2.0.1.0.0.0.0.2.2.0.0.0.8.2.6.0.6.2.ip6.arpa.')
|
||||
|
||||
def testIPAddr_Equal6(self):
|
||||
self.assertEqual(
|
||||
IPAddr('2606:2800:220:1:248:1893::'),
|
||||
IPAddr('2606:2800:220:1:248:1893:0:0')
|
||||
)
|
||||
# special case IPv6 in brackets:
|
||||
self.assertEqual(
|
||||
IPAddr('[2606:2800:220:1:248:1893::]'),
|
||||
IPAddr('2606:2800:220:1:248:1893:0:0')
|
||||
)
|
||||
|
||||
def testIPAddr_InInet(self):
|
||||
ip4net = IPAddr('93.184.0.1/24')
|
||||
ip6net = IPAddr('2606:2800:220:1:248:1893:25c8:0/120')
|
||||
# ip4:
|
||||
self.assertTrue(IPAddr('93.184.0.1').isInNet(ip4net))
|
||||
self.assertTrue(IPAddr('93.184.0.255').isInNet(ip4net))
|
||||
self.assertFalse(IPAddr('93.184.1.0').isInNet(ip4net))
|
||||
self.assertFalse(IPAddr('93.184.0.1').isInNet(ip6net))
|
||||
# ip6:
|
||||
self.assertTrue(IPAddr('2606:2800:220:1:248:1893:25c8:1').isInNet(ip6net))
|
||||
self.assertTrue(IPAddr('2606:2800:220:1:248:1893:25c8:ff').isInNet(ip6net))
|
||||
self.assertFalse(IPAddr('2606:2800:220:1:248:1893:25c8:100').isInNet(ip6net))
|
||||
self.assertFalse(IPAddr('2606:2800:220:1:248:1893:25c8:100').isInNet(ip4net))
|
||||
# raw not in net:
|
||||
self.assertFalse(IPAddr('93.184.0.1', IPAddr.CIDR_RAW).isInNet(ip4net))
|
||||
self.assertFalse(IPAddr('2606:2800:220:1:248:1893:25c8:1', IPAddr.CIDR_RAW).isInNet(ip6net))
|
||||
# invalid not in net:
|
||||
self.assertFalse(IPAddr('xxx').isInNet(ip4net))
|
||||
|
||||
def testIPAddr_Compare(self):
|
||||
ip4 = [
|
||||
|
@ -1452,11 +1535,28 @@ class DNSUtilsNetworkTests(unittest.TestCase):
|
|||
self.assertEqual(IPAddr('93.184.0.1', 24).ntoa, '93.184.0.0/24')
|
||||
self.assertEqual(IPAddr('192.168.1.0/255.255.255.128').ntoa, '192.168.1.0/25')
|
||||
|
||||
self.assertEqual(IPAddr('93.184.0.1/32').ntoa, '93.184.0.1')
|
||||
self.assertEqual(IPAddr('93.184.0.1/255.255.255.255').ntoa, '93.184.0.1')
|
||||
|
||||
self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8::', 120)), '2606:2800:220:1:248:1893:25c8:0/120')
|
||||
self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8::', 120).ntoa, '2606:2800:220:1:248:1893:25c8:0/120')
|
||||
self.assertEqual(str(IPAddr('2606:2800:220:1:248:1893:25c8:0/120')), '2606:2800:220:1:248:1893:25c8:0/120')
|
||||
self.assertEqual(IPAddr('2606:2800:220:1:248:1893:25c8:0/120').ntoa, '2606:2800:220:1:248:1893:25c8:0/120')
|
||||
|
||||
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::', 25)), '2606:2880::/25')
|
||||
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/ffff:ff80::')), '2606:2880::/25')
|
||||
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/ffff:ffff:ffff:ffff:ffff:ffff:ffff::')),
|
||||
'2606:28ff:220:1:248:1893:25c8:0/112')
|
||||
|
||||
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/128')),
|
||||
'2606:28ff:220:1:248:1893:25c8:0')
|
||||
self.assertEqual(str(IPAddr('2606:28ff:220:1:248:1893:25c8::/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')),
|
||||
'2606:28ff:220:1:248:1893:25c8:0')
|
||||
|
||||
def testIPAddr_CIDR_Wrong(self):
|
||||
# too many plen representations:
|
||||
self.assertRaises(ValueError, IPAddr, '2606:28ff:220:1:248:1893:25c8::/ffff::/::1')
|
||||
|
||||
def testIPAddr_CIDR_Repr(self):
|
||||
self.assertEqual(["127.0.0.0/8", "::/32", "2001:db8::/32"],
|
||||
[IPAddr("127.0.0.0", 8), IPAddr("::1", 32), IPAddr("2001:db8::", 32)]
|
||||
|
|
|
@ -33,7 +33,7 @@ from glob import glob
|
|||
from StringIO import StringIO
|
||||
|
||||
from ..helpers import formatExceptionInfo, mbasename, TraceBack, FormatterWithTraceBack, getLogger
|
||||
from ..helpers import splitcommaspace
|
||||
from ..helpers import splitwords
|
||||
from ..server.datetemplate import DatePatternRegex
|
||||
from ..server.mytime import MyTime
|
||||
|
||||
|
@ -57,13 +57,15 @@ class HelpersTest(unittest.TestCase):
|
|||
# might be fragile due to ' vs "
|
||||
self.assertEqual(args, "('Very bad', None)")
|
||||
|
||||
def testsplitcommaspace(self):
|
||||
self.assertEqual(splitcommaspace(None), [])
|
||||
self.assertEqual(splitcommaspace(''), [])
|
||||
self.assertEqual(splitcommaspace(' '), [])
|
||||
self.assertEqual(splitcommaspace('1'), ['1'])
|
||||
self.assertEqual(splitcommaspace(' 1 2 '), ['1', '2'])
|
||||
self.assertEqual(splitcommaspace(' 1, 2 , '), ['1', '2'])
|
||||
def testsplitwords(self):
|
||||
self.assertEqual(splitwords(None), [])
|
||||
self.assertEqual(splitwords(''), [])
|
||||
self.assertEqual(splitwords(' '), [])
|
||||
self.assertEqual(splitwords('1'), ['1'])
|
||||
self.assertEqual(splitwords(' 1 2 '), ['1', '2'])
|
||||
self.assertEqual(splitwords(' 1, 2 , '), ['1', '2'])
|
||||
self.assertEqual(splitwords(' 1\n 2'), ['1', '2'])
|
||||
self.assertEqual(splitwords(' 1\n 2, 3'), ['1', '2', '3'])
|
||||
|
||||
|
||||
def _getSysPythonVersion():
|
||||
|
|
|
@ -35,6 +35,7 @@ from ..server.filter import Filter
|
|||
from ..client.filterreader import FilterReader
|
||||
from .utils import setUpMyTime, tearDownMyTime, CONFIG_DIR
|
||||
|
||||
TEST_CONFIG_DIR = os.path.join(os.path.dirname(__file__), "config")
|
||||
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||
|
||||
|
||||
|
@ -60,12 +61,12 @@ class FilterSamplesRegex(unittest.TestCase):
|
|||
"Expected more FilterSampleRegexs tests")
|
||||
|
||||
|
||||
def testSampleRegexsFactory(name):
|
||||
def testSampleRegexsFactory(name, basedir):
|
||||
def testFilter(self):
|
||||
|
||||
# Check filter exists
|
||||
filterConf = FilterReader(name, "jail", {},
|
||||
basedir=CONFIG_DIR, share_config=unittest.F2B.share_config)
|
||||
basedir=basedir, share_config=unittest.F2B.share_config)
|
||||
self.assertEqual(filterConf.getFile(), name)
|
||||
self.assertEqual(filterConf.getJailName(), "jail")
|
||||
filterConf.read()
|
||||
|
@ -126,7 +127,7 @@ def testSampleRegexsFactory(name):
|
|||
(map(lambda x: x[0], ret),logFile.filename(), logFile.filelineno()))
|
||||
|
||||
# Verify timestamp and host as expected
|
||||
failregex, host, fail2banTime, lines = ret[0]
|
||||
failregex, host, fail2banTime, lines, fail = ret[0]
|
||||
self.assertEqual(host, faildata.get("host", None))
|
||||
|
||||
t = faildata.get("time", None)
|
||||
|
@ -155,11 +156,15 @@ def testSampleRegexsFactory(name):
|
|||
|
||||
return testFilter
|
||||
|
||||
for filter_ in filter(lambda x: not x.endswith('common.conf') and x.endswith('.conf'),
|
||||
os.listdir(os.path.join(CONFIG_DIR, "filter.d"))):
|
||||
filterName = filter_.rpartition(".")[0]
|
||||
if not filterName.startswith('.'):
|
||||
setattr(
|
||||
FilterSamplesRegex,
|
||||
"testSampleRegexs%s" % filterName.upper(),
|
||||
testSampleRegexsFactory(filterName))
|
||||
for basedir_, filter_ in (
|
||||
(CONFIG_DIR, lambda x: not x.endswith('common.conf') and x.endswith('.conf')),
|
||||
(TEST_CONFIG_DIR, lambda x: x.startswith('zzz-') and x.endswith('.conf')),
|
||||
):
|
||||
for filter_ in filter(filter_,
|
||||
os.listdir(os.path.join(basedir_, "filter.d"))):
|
||||
filterName = filter_.rpartition(".")[0]
|
||||
if not filterName.startswith('.'):
|
||||
setattr(
|
||||
FilterSamplesRegex,
|
||||
"testSampleRegexs%s" % filterName.upper(),
|
||||
testSampleRegexsFactory(filterName, basedir_))
|
||||
|
|
|
@ -631,11 +631,11 @@ class Transmitter(TransmitterBase):
|
|||
self.assertEqual(
|
||||
self.transm.proceed(
|
||||
["set", self.jailName, "action", action, "timeout", "10"]),
|
||||
(0, 10))
|
||||
(0, "10"))
|
||||
self.assertEqual(
|
||||
self.transm.proceed(
|
||||
["get", self.jailName, "action", action, "timeout"]),
|
||||
(0, 10))
|
||||
(0, "10"))
|
||||
self.assertEqual(
|
||||
self.transm.proceed(["set", self.jailName, "delaction", action]),
|
||||
(0, None))
|
||||
|
@ -837,7 +837,7 @@ class TransmitterLogging(TransmitterBase):
|
|||
outCode=1,
|
||||
outValue=Exception('Failed to change log target'),
|
||||
repr_=True # Exceptions are not comparable apparently
|
||||
)
|
||||
)
|
||||
}[platform.system() in ('Linux',) and os.path.exists('/dev/log')]
|
||||
)
|
||||
|
||||
|
@ -926,6 +926,14 @@ class RegexTests(unittest.TestCase):
|
|||
|
||||
def testHost(self):
|
||||
self.assertRaises(RegexException, FailRegex, '')
|
||||
self.assertRaises(RegexException, FailRegex, '^test no group$')
|
||||
self.assertTrue(FailRegex('^test <HOST> group$'))
|
||||
self.assertTrue(FailRegex('^test <IP4> group$'))
|
||||
self.assertTrue(FailRegex('^test <IP6> group$'))
|
||||
self.assertTrue(FailRegex('^test <DNS> group$'))
|
||||
self.assertTrue(FailRegex('^test id group: ip:port = <F-ID><IP4>(?::<F-PORT/>)?</F-ID>$'))
|
||||
self.assertTrue(FailRegex('^test id group: user:\(<F-ID>[^\)]+</F-ID>\)$'))
|
||||
self.assertTrue(FailRegex('^test id group: anything = <F-ID/>$'))
|
||||
# Testing obscure case when host group might be missing in the matched pattern,
|
||||
# e.g. if we made it optional.
|
||||
fr = FailRegex('%%<HOST>?')
|
||||
|
@ -933,6 +941,30 @@ class RegexTests(unittest.TestCase):
|
|||
fr.search([('%%',"","")])
|
||||
self.assertTrue(fr.hasMatched())
|
||||
self.assertRaises(RegexException, fr.getHost)
|
||||
# The same as above but using separated IPv4/IPv6 expressions
|
||||
fr = FailRegex('%%inet(?:=<F-IP4/>|inet6=<F-IP6/>)?')
|
||||
self.assertFalse(fr.hasMatched())
|
||||
fr.search([('%%inet=test',"","")])
|
||||
self.assertTrue(fr.hasMatched())
|
||||
self.assertRaises(RegexException, fr.getHost)
|
||||
# Success case: using separated IPv4/IPv6 expressions (no HOST)
|
||||
fr = FailRegex('%%(?:inet(?:=<IP4>|6=<IP6>)?|dns=<DNS>?)')
|
||||
self.assertFalse(fr.hasMatched())
|
||||
fr.search([('%%inet=192.0.2.1',"","")])
|
||||
self.assertTrue(fr.hasMatched())
|
||||
self.assertEqual(fr.getHost(), '192.0.2.1')
|
||||
fr.search([('%%inet6=2001:DB8::',"","")])
|
||||
self.assertTrue(fr.hasMatched())
|
||||
self.assertEqual(fr.getHost(), '2001:DB8::')
|
||||
fr.search([('%%dns=example.com',"","")])
|
||||
self.assertTrue(fr.hasMatched())
|
||||
self.assertEqual(fr.getHost(), 'example.com')
|
||||
# Success case: using user as failure-id
|
||||
fr = FailRegex('^test id group: user:\(<F-ID>[^\)]+</F-ID>\)$')
|
||||
self.assertFalse(fr.hasMatched())
|
||||
fr.search([('test id group: user:(test login name)',"","")])
|
||||
self.assertTrue(fr.hasMatched())
|
||||
self.assertEqual(fr.getFailID(), 'test login name')
|
||||
|
||||
|
||||
class _BadThread(JailThread):
|
||||
|
@ -1005,14 +1037,43 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
logSys.debug(l)
|
||||
return True
|
||||
|
||||
def test_IPAddr(self):
|
||||
self.assertTrue(IPAddr('192.0.2.1').isIPv4)
|
||||
self.assertTrue(IPAddr('2001:DB8::').isIPv6)
|
||||
def _testExecActions(self, server):
|
||||
jails = server._Server__jails
|
||||
for jail in jails:
|
||||
# print(jail, jails[jail])
|
||||
for a in jails[jail].actions:
|
||||
action = jails[jail].actions[a]
|
||||
logSys.debug('# ' + ('=' * 50))
|
||||
logSys.debug('# == %-44s ==', jail + ' - ' + action._name)
|
||||
logSys.debug('# ' + ('=' * 50))
|
||||
# we can currently test only command actions:
|
||||
if not isinstance(action, _actions.CommandAction): continue
|
||||
# wrap default command processor, just log if (heavy)debug:
|
||||
action.executeCmd = self._executeCmd
|
||||
# test start :
|
||||
logSys.debug('# === start ==='); self.pruneLog()
|
||||
action.start()
|
||||
# test ban ip4 :
|
||||
logSys.debug('# === ban-ipv4 ==='); self.pruneLog()
|
||||
action.ban({'ip': IPAddr('192.0.2.1')})
|
||||
# test unban ip4 :
|
||||
logSys.debug('# === unban ipv4 ==='); self.pruneLog()
|
||||
action.unban({'ip': IPAddr('192.0.2.1')})
|
||||
# test ban ip6 :
|
||||
logSys.debug('# === ban ipv6 ==='); self.pruneLog()
|
||||
action.ban({'ip': IPAddr('2001:DB8::')})
|
||||
# test unban ip6 :
|
||||
logSys.debug('# === unban ipv6 ==='); self.pruneLog()
|
||||
action.unban({'ip': IPAddr('2001:DB8::')})
|
||||
# test stop :
|
||||
logSys.debug('# === stop ==='); self.pruneLog()
|
||||
action.stop()
|
||||
|
||||
if STOCK:
|
||||
|
||||
def testCheckStockJailActions(self):
|
||||
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=self.__share_cfg) # we are running tests from root project dir atm
|
||||
# we are running tests from root project dir atm
|
||||
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=self.__share_cfg)
|
||||
self.assertTrue(jails.read()) # opens fine
|
||||
self.assertTrue(jails.getOptions()) # reads fine
|
||||
stream = jails.convert(allow_no_files=True)
|
||||
|
@ -1030,10 +1091,17 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
# change to the fast init backend:
|
||||
if cmd[0] == 'add':
|
||||
cmd[2] = 'polling'
|
||||
# change log path to test log of jail (to prevent "Permission denied" on /var/logs/ for test-user):
|
||||
# change log path to test log of the jail
|
||||
# (to prevent "Permission denied" on /var/logs/ for test-user):
|
||||
elif len(cmd) > 3 and cmd[0] == 'set' and cmd[2] == 'addlogpath':
|
||||
cmd[3] = os.path.join(TEST_FILES_DIR, 'logs', cmd[1])
|
||||
# if fast add dummy regex to prevent too long compile of all regexp (we don't use it in this test at all):
|
||||
fn = os.path.join(TEST_FILES_DIR, 'logs', cmd[1])
|
||||
# fallback to testcase01 if jail has no its own test log-file
|
||||
# (should not matter really):
|
||||
if not os.path.exists(fn): # pragma: no cover
|
||||
fn = os.path.join(TEST_FILES_DIR, 'testcase01.log')
|
||||
cmd[3] = fn
|
||||
# if fast add dummy regex to prevent too long compile of all regexp
|
||||
# (we don't use it in this test at all):
|
||||
elif unittest.F2B.fast and (
|
||||
len(cmd) > 3 and cmd[0] in ('set', 'multi-set') and cmd[2] == 'addfailregex'
|
||||
):
|
||||
|
@ -1042,13 +1110,17 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
# command to server, use cmdHandler direct instead of `transm.proceed(cmd)`:
|
||||
try:
|
||||
cmdHandler(cmd)
|
||||
except Exception, e: # pragma: no cover
|
||||
except Exception, e: # pragma: no cover
|
||||
self.fail("Command %r has failed. Received %r" % (cmd, e))
|
||||
|
||||
# jails = server._Server__jails
|
||||
# for j in jails:
|
||||
# print(j, jails[j])
|
||||
|
||||
# test default stock actions sepecified in all stock jails:
|
||||
if not unittest.F2B.fast:
|
||||
self._testExecActions(server)
|
||||
|
||||
def getDefaultJailStream(self, jail, act):
|
||||
act = act.replace('%(__name__)s', jail)
|
||||
actName, actOpt = JailReader.extractOptions(act)
|
||||
|
@ -1064,6 +1136,25 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
stream.extend(action.convert())
|
||||
return stream
|
||||
|
||||
def testCheckStockAllActions(self):
|
||||
unittest.F2B.SkipIfFast()
|
||||
import glob
|
||||
|
||||
server = TestServer()
|
||||
transm = server._Server__transm
|
||||
|
||||
for actCfg in glob.glob(os.path.join(CONFIG_DIR, 'action.d', '*.conf')):
|
||||
act = os.path.basename(actCfg).replace('.conf', '')
|
||||
# transmit artifical jail with each action to the server:
|
||||
stream = self.getDefaultJailStream('j-'+act, act)
|
||||
for cmd in stream:
|
||||
# command to server:
|
||||
ret, res = transm.proceed(cmd)
|
||||
self.assertEqual(ret, 0)
|
||||
# test executing action commands:
|
||||
self._testExecActions(server)
|
||||
|
||||
|
||||
def testCheckStockCommandActions(self):
|
||||
# test cases to check valid ipv4/ipv6 action definition, tuple with (('jail', 'action[params]', 'tests', ...)
|
||||
# where tests is a dictionary contains:
|
||||
|
@ -1073,7 +1164,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
# etc.
|
||||
testJailsActions = (
|
||||
# iptables-multiport --
|
||||
('j-w-iptables-mp', 'iptables-multiport[name=%(__name__)s, bantime="600", port="http,https", protocol="tcp", chain="INPUT"]', {
|
||||
('j-w-iptables-mp', 'iptables-multiport[name=%(__name__)s, bantime="10m", port="http,https", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'),
|
||||
'start': (
|
||||
"`iptables -w -N f2b-j-w-iptables-mp`",
|
||||
|
@ -1111,7 +1202,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
),
|
||||
}),
|
||||
# iptables-allports --
|
||||
('j-w-iptables-ap', 'iptables-allports[name=%(__name__)s, bantime="600", protocol="tcp", chain="INPUT"]', {
|
||||
('j-w-iptables-ap', 'iptables-allports[name=%(__name__)s, bantime="10m", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'),
|
||||
'start': (
|
||||
"`iptables -w -N f2b-j-w-iptables-ap`",
|
||||
|
@ -1149,7 +1240,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
),
|
||||
}),
|
||||
# iptables-ipset-proto6 --
|
||||
('j-w-iptables-ipset', 'iptables-ipset-proto6[name=%(__name__)s, bantime="600", port="http", protocol="tcp", chain="INPUT"]', {
|
||||
('j-w-iptables-ipset', 'iptables-ipset-proto6[name=%(__name__)s, bantime="10m", port="http", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': (' f2b-j-w-iptables-ipset ',), 'ip6': (' f2b-j-w-iptables-ipset6 ',),
|
||||
'start': (
|
||||
"`ipset create f2b-j-w-iptables-ipset hash:ip timeout 600`",
|
||||
|
@ -1181,7 +1272,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
),
|
||||
}),
|
||||
# iptables-ipset-proto6-allports --
|
||||
('j-w-iptables-ipset-ap', 'iptables-ipset-proto6-allports[name=%(__name__)s, bantime="600", chain="INPUT"]', {
|
||||
('j-w-iptables-ipset-ap', 'iptables-ipset-proto6-allports[name=%(__name__)s, bantime="10m", chain="INPUT"]', {
|
||||
'ip4': (' f2b-j-w-iptables-ipset-ap ',), 'ip6': (' f2b-j-w-iptables-ipset-ap6 ',),
|
||||
'start': (
|
||||
"`ipset create f2b-j-w-iptables-ipset-ap hash:ip timeout 600`",
|
||||
|
@ -1213,7 +1304,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
),
|
||||
}),
|
||||
# iptables --
|
||||
('j-w-iptables', 'iptables[name=%(__name__)s, bantime="600", port="http", protocol="tcp", chain="INPUT"]', {
|
||||
('j-w-iptables', 'iptables[name=%(__name__)s, bantime="10m", port="http", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'),
|
||||
'start': (
|
||||
"`iptables -w -N f2b-j-w-iptables`",
|
||||
|
@ -1251,7 +1342,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
),
|
||||
}),
|
||||
# iptables-new --
|
||||
('j-w-iptables-new', 'iptables-new[name=%(__name__)s, bantime="600", port="http", protocol="tcp", chain="INPUT"]', {
|
||||
('j-w-iptables-new', 'iptables-new[name=%(__name__)s, bantime="10m", port="http", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'),
|
||||
'start': (
|
||||
"`iptables -w -N f2b-j-w-iptables-new`",
|
||||
|
@ -1289,7 +1380,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
),
|
||||
}),
|
||||
# iptables-xt_recent-echo --
|
||||
('j-w-iptables-xtre', 'iptables-xt_recent-echo[name=%(__name__)s, bantime="600", chain="INPUT"]', {
|
||||
('j-w-iptables-xtre', 'iptables-xt_recent-echo[name=%(__name__)s, bantime="10m", chain="INPUT"]', {
|
||||
'ip4': ('`iptables ', '/f2b-j-w-iptables-xtre`'), 'ip6': ('`ip6tables ', '/f2b-j-w-iptables-xtre6`'),
|
||||
'start': (
|
||||
"`if [ `id -u` -eq 0 ];then iptables -w -I INPUT -m recent --update --seconds 3600 --name f2b-j-w-iptables-xtre -j REJECT --reject-with icmp-port-unreachable;fi`",
|
||||
|
@ -1318,14 +1409,14 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
),
|
||||
'ip6-unban': (
|
||||
r"`echo -2001:db8:: > /proc/net/xt_recent/f2b-j-w-iptables-xtre6`",
|
||||
),
|
||||
),
|
||||
}),
|
||||
# pf --
|
||||
# pf default -- multiport on default port (tag <port> set in jail.conf, but not in this test case)
|
||||
('j-w-pf', 'pf[name=%(__name__)s]', {
|
||||
'ip4': (), 'ip6': (),
|
||||
'start': (
|
||||
'`echo "table <f2b-j-w-pf> persist counters" | pfctl -f-`',
|
||||
'`echo "block proto tcp from <f2b-j-w-pf> to any port any" | pfctl -f-`',
|
||||
'`echo "block proto tcp from <f2b-j-w-pf> to any port <port>" | pfctl -f-`',
|
||||
),
|
||||
'stop': (
|
||||
'`pfctl -sr 2>/dev/null | grep -v f2b-j-w-pf | pfctl -f-`',
|
||||
|
@ -1339,6 +1430,152 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
'ip6-ban': ("`pfctl -t f2b-j-w-pf -T add 2001:db8::`",),
|
||||
'ip6-unban': ("`pfctl -t f2b-j-w-pf -T delete 2001:db8::`",),
|
||||
}),
|
||||
# pf multiport with custom port --
|
||||
('j-w-pf-mp', 'pf[actiontype=<multiport>][name=%(__name__)s, port=http]', {
|
||||
'ip4': (), 'ip6': (),
|
||||
'start': (
|
||||
'`echo "table <f2b-j-w-pf-mp> persist counters" | pfctl -f-`',
|
||||
'`echo "block proto tcp from <f2b-j-w-pf-mp> to any port http" | pfctl -f-`',
|
||||
),
|
||||
'stop': (
|
||||
'`pfctl -sr 2>/dev/null | grep -v f2b-j-w-pf-mp | pfctl -f-`',
|
||||
'`pfctl -t f2b-j-w-pf-mp -T flush`',
|
||||
'`pfctl -t f2b-j-w-pf-mp -T kill`',
|
||||
),
|
||||
'ip4-check': ("`pfctl -sr | grep -q f2b-j-w-pf-mp`",),
|
||||
'ip6-check': ("`pfctl -sr | grep -q f2b-j-w-pf-mp`",),
|
||||
'ip4-ban': ("`pfctl -t f2b-j-w-pf-mp -T add 192.0.2.1`",),
|
||||
'ip4-unban': ("`pfctl -t f2b-j-w-pf-mp -T delete 192.0.2.1`",),
|
||||
'ip6-ban': ("`pfctl -t f2b-j-w-pf-mp -T add 2001:db8::`",),
|
||||
'ip6-unban': ("`pfctl -t f2b-j-w-pf-mp -T delete 2001:db8::`",),
|
||||
}),
|
||||
# pf allports --
|
||||
('j-w-pf-ap', 'pf[actiontype=<allports>][name=%(__name__)s]', {
|
||||
'ip4': (), 'ip6': (),
|
||||
'start': (
|
||||
'`echo "table <f2b-j-w-pf-ap> persist counters" | pfctl -f-`',
|
||||
'`echo "block proto tcp from <f2b-j-w-pf-ap> to any" | pfctl -f-`',
|
||||
),
|
||||
'stop': (
|
||||
'`pfctl -sr 2>/dev/null | grep -v f2b-j-w-pf-ap | pfctl -f-`',
|
||||
'`pfctl -t f2b-j-w-pf-ap -T flush`',
|
||||
'`pfctl -t f2b-j-w-pf-ap -T kill`',
|
||||
),
|
||||
'ip4-check': ("`pfctl -sr | grep -q f2b-j-w-pf-ap`",),
|
||||
'ip6-check': ("`pfctl -sr | grep -q f2b-j-w-pf-ap`",),
|
||||
'ip4-ban': ("`pfctl -t f2b-j-w-pf-ap -T add 192.0.2.1`",),
|
||||
'ip4-unban': ("`pfctl -t f2b-j-w-pf-ap -T delete 192.0.2.1`",),
|
||||
'ip6-ban': ("`pfctl -t f2b-j-w-pf-ap -T add 2001:db8::`",),
|
||||
'ip6-unban': ("`pfctl -t f2b-j-w-pf-ap -T delete 2001:db8::`",),
|
||||
}),
|
||||
# firewallcmd-multiport --
|
||||
('j-w-fwcmd-mp', 'firewallcmd-multiport[name=%(__name__)s, bantime="10m", port="http,https", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': (' ipv4 ', 'icmp-port-unreachable'), 'ip6': (' ipv6 ', 'icmp6-port-unreachable'),
|
||||
'start': (
|
||||
"`firewall-cmd --direct --add-chain ipv4 filter f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --add-rule ipv4 filter f2b-j-w-fwcmd-mp 1000 -j RETURN`",
|
||||
"`firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -m conntrack --ctstate NEW -p tcp -m multiport --dports http,https -j f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --add-chain ipv6 filter f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --add-rule ipv6 filter f2b-j-w-fwcmd-mp 1000 -j RETURN`",
|
||||
"`firewall-cmd --direct --add-rule ipv6 filter INPUT 0 -m conntrack --ctstate NEW -p tcp -m multiport --dports http,https -j f2b-j-w-fwcmd-mp`",
|
||||
),
|
||||
'stop': (
|
||||
"`firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -m conntrack --ctstate NEW -p tcp -m multiport --dports http,https -j f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --remove-rules ipv4 filter f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --remove-chain ipv4 filter f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --remove-rule ipv6 filter INPUT 0 -m conntrack --ctstate NEW -p tcp -m multiport --dports http,https -j f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --remove-rules ipv6 filter f2b-j-w-fwcmd-mp`",
|
||||
"`firewall-cmd --direct --remove-chain ipv6 filter f2b-j-w-fwcmd-mp`",
|
||||
),
|
||||
'ip4-check': (
|
||||
r"`firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-j-w-fwcmd-mp$'`",
|
||||
),
|
||||
'ip6-check': (
|
||||
r"`firewall-cmd --direct --get-chains ipv6 filter | sed -e 's, ,\n,g' | grep -q '^f2b-j-w-fwcmd-mp$'`",
|
||||
),
|
||||
'ip4-ban': (
|
||||
r"`firewall-cmd --direct --add-rule ipv4 filter f2b-j-w-fwcmd-mp 0 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`",
|
||||
),
|
||||
'ip4-unban': (
|
||||
r"`firewall-cmd --direct --remove-rule ipv4 filter f2b-j-w-fwcmd-mp 0 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`",
|
||||
),
|
||||
'ip6-ban': (
|
||||
r"`firewall-cmd --direct --add-rule ipv6 filter f2b-j-w-fwcmd-mp 0 -s 2001:db8:: -j REJECT --reject-with icmp6-port-unreachable`",
|
||||
),
|
||||
'ip6-unban': (
|
||||
r"`firewall-cmd --direct --remove-rule ipv6 filter f2b-j-w-fwcmd-mp 0 -s 2001:db8:: -j REJECT --reject-with icmp6-port-unreachable`",
|
||||
),
|
||||
}),
|
||||
# firewallcmd-allports --
|
||||
('j-w-fwcmd-ap', 'firewallcmd-allports[name=%(__name__)s, bantime="10m", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': (' ipv4 ', 'icmp-port-unreachable'), 'ip6': (' ipv6 ', 'icmp6-port-unreachable'),
|
||||
'start': (
|
||||
"`firewall-cmd --direct --add-chain ipv4 filter f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --add-rule ipv4 filter f2b-j-w-fwcmd-ap 1000 -j RETURN`",
|
||||
"`firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -j f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --add-chain ipv6 filter f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --add-rule ipv6 filter f2b-j-w-fwcmd-ap 1000 -j RETURN`",
|
||||
"`firewall-cmd --direct --add-rule ipv6 filter INPUT 0 -j f2b-j-w-fwcmd-ap`",
|
||||
),
|
||||
'stop': (
|
||||
"`firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -j f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --remove-rules ipv4 filter f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --remove-chain ipv4 filter f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --remove-rule ipv6 filter INPUT 0 -j f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --remove-rules ipv6 filter f2b-j-w-fwcmd-ap`",
|
||||
"`firewall-cmd --direct --remove-chain ipv6 filter f2b-j-w-fwcmd-ap`",
|
||||
),
|
||||
'ip4-check': (
|
||||
r"`firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-j-w-fwcmd-ap$'`",
|
||||
),
|
||||
'ip6-check': (
|
||||
r"`firewall-cmd --direct --get-chains ipv6 filter | sed -e 's, ,\n,g' | grep -q '^f2b-j-w-fwcmd-ap$'`",
|
||||
),
|
||||
'ip4-ban': (
|
||||
r"`firewall-cmd --direct --add-rule ipv4 filter f2b-j-w-fwcmd-ap 0 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`",
|
||||
),
|
||||
'ip4-unban': (
|
||||
r"`firewall-cmd --direct --remove-rule ipv4 filter f2b-j-w-fwcmd-ap 0 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`",
|
||||
),
|
||||
'ip6-ban': (
|
||||
r"`firewall-cmd --direct --add-rule ipv6 filter f2b-j-w-fwcmd-ap 0 -s 2001:db8:: -j REJECT --reject-with icmp6-port-unreachable`",
|
||||
),
|
||||
'ip6-unban': (
|
||||
r"`firewall-cmd --direct --remove-rule ipv6 filter f2b-j-w-fwcmd-ap 0 -s 2001:db8:: -j REJECT --reject-with icmp6-port-unreachable`",
|
||||
),
|
||||
}),
|
||||
# firewallcmd-ipset --
|
||||
('j-w-fwcmd-ipset', 'firewallcmd-ipset[name=%(__name__)s, bantime="10m", port="http", protocol="tcp", chain="INPUT"]', {
|
||||
'ip4': (' f2b-j-w-fwcmd-ipset ',), 'ip6': (' f2b-j-w-fwcmd-ipset6 ',),
|
||||
'start': (
|
||||
"`ipset create f2b-j-w-fwcmd-ipset hash:ip timeout 600`",
|
||||
"`firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp -m multiport --dports http -m set --match-set f2b-j-w-fwcmd-ipset src -j REJECT --reject-with icmp-port-unreachable`",
|
||||
"`ipset create f2b-j-w-fwcmd-ipset6 hash:ip timeout 600`",
|
||||
"`firewall-cmd --direct --add-rule ipv6 filter INPUT 0 -p tcp -m multiport --dports http -m set --match-set f2b-j-w-fwcmd-ipset6 src -j REJECT --reject-with icmp6-port-unreachable`",
|
||||
),
|
||||
'stop': (
|
||||
"`firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -p tcp -m multiport --dports http -m set --match-set f2b-j-w-fwcmd-ipset src -j REJECT --reject-with icmp-port-unreachable`",
|
||||
"`ipset flush f2b-j-w-fwcmd-ipset`",
|
||||
"`ipset destroy f2b-j-w-fwcmd-ipset`",
|
||||
"`firewall-cmd --direct --remove-rule ipv6 filter INPUT 0 -p tcp -m multiport --dports http -m set --match-set f2b-j-w-fwcmd-ipset6 src -j REJECT --reject-with icmp6-port-unreachable`",
|
||||
"`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`",
|
||||
),
|
||||
'ip4-unban': (
|
||||
r"`ipset del f2b-j-w-fwcmd-ipset 192.0.2.1 -exist`",
|
||||
),
|
||||
'ip6-ban': (
|
||||
r"`ipset add f2b-j-w-fwcmd-ipset6 2001:db8:: timeout 600 -exist`",
|
||||
),
|
||||
'ip6-unban': (
|
||||
r"`ipset del f2b-j-w-fwcmd-ipset6 2001:db8:: -exist`",
|
||||
),
|
||||
}),
|
||||
)
|
||||
server = TestServer()
|
||||
transm = server._Server__transm
|
||||
|
@ -1350,7 +1587,7 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
|||
# for cmd in stream:
|
||||
# print(cmd)
|
||||
|
||||
# filter all start commands (we want not start all jails):
|
||||
# transmit jail to the server:
|
||||
for cmd in stream:
|
||||
# command to server:
|
||||
ret, res = transm.proceed(cmd)
|
||||
|
|
|
@ -24,4 +24,4 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko, Steven Hiscocks, Daniel Black"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2005-2016 Yaroslav Halchenko, 2013-2014 Steven Hiscocks, Daniel Black"
|
||||
__license__ = "GPL-v2+"
|
||||
|
||||
version = "0.9.4.dev0"
|
||||
version = "0.10.0a1"
|
||||
|
|
|
@ -34,15 +34,15 @@ start() {
|
|||
# remove stalled sock file after system crash
|
||||
# bug 347477
|
||||
rm -f /var/run/fail2ban/fail2ban.sock || return 1
|
||||
start-stop-daemon --start --exec ${FAIL2BAN} start \
|
||||
--pidfile /var/run/fail2ban/fail2ban.pid
|
||||
start-stop-daemon --start --pidfile /var/run/fail2ban/fail2ban.pid \
|
||||
-- ${FAIL2BAN} start
|
||||
eend $? "Failed to start fail2ban"
|
||||
}
|
||||
|
||||
stop() {
|
||||
ebegin "Stopping fail2ban"
|
||||
start-stop-daemon --stop --exec ${FAIL2BAN} stop \
|
||||
--pidfile /var/run/fail2ban/fail2ban.pid
|
||||
start-stop-daemon --stop --pidfile /var/run/fail2ban/fail2ban.pid \
|
||||
-- ${FAIL2BAN} stop
|
||||
eend $? "Failed to stop fail2ban"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue