ver. 0.9.5 (2016/07/15) - old-not-obsolete

-----------
 
 0.9.x line is no longer heavily developed.  If you are interested in
 new features (e.g. IPv6 support), please consider 0.10 branch and its
 releases.
 
 * `filter.d/monit.conf`
     - Extended failregex with new monit "access denied" version (gh-1355)
     - 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`
     - Fixed security log support for PJSIP and Asterisk 13+ (gh-1456)
     - Improved log support for PJSIP and Asterisk 13+ with different
       callID (gh-1458)
 
 * New Actions:
     - `action.d/firewallcmd-rich-rules` and `action.d/firewallcmd-rich-logging`
 	(gh-1367)
 * New filters:
     - slapd - ban hosts, that were failed to connect with invalid
 	credentials: error code 49 (gh-1478)
 
 * 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)
 * Added additional regex filter for dovecot ldap authentication failures (gh-1370)
 * `filter.d/exim*conf`
     - Added additional regexes (gh-1371)
     - Made port entry optional
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iEYEABECAAYFAleIPhkACgkQjRFFY3XAJMiDBQCeNg/+B5nN1rJaDiqZmMlnIl+4
 CUsAoLhGyYWZ0imRBbkpUTaFZ+NdN5d6
 =H9Zr
 -----END PGP SIGNATURE-----

Merge tag '0.9.5' into debian

ver. 0.9.5 (2016/07/15) - old-not-obsolete
-----------

0.9.x line is no longer heavily developed.  If you are interested in
new features (e.g. IPv6 support), please consider 0.10 branch and its
releases.

* `filter.d/monit.conf`
    - Extended failregex with new monit "access denied" version (gh-1355)
    - 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`
    - Fixed security log support for PJSIP and Asterisk 13+ (gh-1456)
    - Improved log support for PJSIP and Asterisk 13+ with different
      callID (gh-1458)

* New Actions:
    - `action.d/firewallcmd-rich-rules` and `action.d/firewallcmd-rich-logging`
	(gh-1367)
* New filters:
    - slapd - ban hosts, that were failed to connect with invalid
	credentials: error code 49 (gh-1478)

* 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)
* Added additional regex filter for dovecot ldap authentication failures (gh-1370)
* `filter.d/exim*conf`
    - Added additional regexes (gh-1371)
    - Made port entry optional

* tag '0.9.5': (70 commits)
  DOC: preparations for 0.9.5 release
  Added missing files to MANIFEST
  another variant of regex
  add trailing anchor to failregex
  DOC: Reformatted ChangeLog into legit Markdown (Closes #962)
  DOC: tuned up ChangeLog entries for 0.9.5
  add PR id to ChangeLog
  improved failregex according to @sebres recomendations
  Improved changes of gh-1458:   `[^']*` after callid was wrong, changed to `[^\)]*`;   regexp anchored at the end;   almost the same regex grouped to one;
  Improve PJSIP log support for asterisk 13+ with different callID (Squash gh-1458) Change the asterisk pjsip filter to don't take the callId part Add optional part between "Request" and "from" Listed all log message from asterisk
  * add `__prefix_line` to regex * fix time in log file
  add info to log file
  added sample log lines for slapd
  adding openldap slapd filter
  badip timeout option introduced, set to 30 seconds in our test cases (#1463)
  DOC: changelog for recent exim filters tune up
  Asterisk pjsip (#1456)
  BF: finalize that sample log line for exim4
  amend for new option of `usedns=raw` - forgotten validation fix inside setUseDns
  RF: for consistency use (?:XXX)? instead of (?:|XXX)
  ...
pull/1858/head
Yaroslav Halchenko 2016-07-14 21:36:59 -04:00
commit bbbe592788
57 changed files with 1410 additions and 912 deletions

1616
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,8 @@ config/action.d/firewallcmd-allports.conf
config/action.d/firewallcmd-ipset.conf
config/action.d/firewallcmd-multiport.conf
config/action.d/firewallcmd-new.conf
config/action.d/firewallcmd-rich-logging.conf
config/action.d/firewallcmd-rich-rules.conf
config/action.d/hostsdeny.conf
config/action.d/ipfilter.conf
config/action.d/ipfw.conf
@ -124,6 +126,7 @@ config/filter.d/sendmail-auth.conf
config/filter.d/sendmail-reject.conf
config/filter.d/sendmail-spam.conf
config/filter.d/sieve.conf
config/filter.d/slapd.conf
config/filter.d/sogo-auth.conf
config/filter.d/solid-pop3d.conf
config/filter.d/squid.conf
@ -205,6 +208,7 @@ fail2ban/tests/config/fail2ban.conf
fail2ban/tests/config/filter.d/simple.conf
fail2ban/tests/config/filter.d/test.conf
fail2ban/tests/config/filter.d/test.local
fail2ban/tests/config/filter.d/zzz-generic-example.conf
fail2ban/tests/config/jail.conf
fail2ban/tests/config/paths-common.conf
fail2ban/tests/config/paths-debian.conf
@ -306,6 +310,7 @@ fail2ban/tests/files/logs/sendmail-auth
fail2ban/tests/files/logs/sendmail-reject
fail2ban/tests/files/logs/sendmail-spam
fail2ban/tests/files/logs/sieve
fail2ban/tests/files/logs/slapd
fail2ban/tests/files/logs/sogo-auth
fail2ban/tests/files/logs/solid-pop3d
fail2ban/tests/files/logs/squid
@ -320,6 +325,7 @@ fail2ban/tests/files/logs/vsftpd
fail2ban/tests/files/logs/webmin-auth
fail2ban/tests/files/logs/wuftpd
fail2ban/tests/files/logs/xinetd-fail
fail2ban/tests/files/logs/zzz-generic-example
fail2ban/tests/files/testcase01.log
fail2ban/tests/files/testcase02.log
fail2ban/tests/files/testcase03.log

View File

@ -2,7 +2,7 @@
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
v0.9.4 2015/03/08
v0.9.5 2016/07/15
## Fail2Ban: ban hosts that cause multiple authentication errors
@ -39,8 +39,8 @@ Optional:
To install, just do:
tar xvfj fail2ban-0.9.4.tar.bz2
cd fail2ban-0.9.4
tar xvfj fail2ban-0.9.5.tar.bz2
cd fail2ban-0.9.5
python setup.py install
This will install Fail2Ban into the python library directory. The executable

22
RELEASE
View File

@ -53,7 +53,7 @@ Preparation
or an alternative for comparison with previous release
git diff 0.9.4 | grep -B2 'index 0000000..' | grep -B1 'new file mode' | sed -n -e '/^diff /s,.* b/,,gp' >> MANIFEST
git diff 0.9.5 | grep -B2 'index 0000000..' | grep -B1 'new file mode' | sed -n -e '/^diff /s,.* b/,,gp' >> MANIFEST
sort MANIFEST | uniq | sponge MANIFEST
* Run::
@ -66,24 +66,24 @@ Preparation
* Which indicates that testcases/files/logs/mysqld.log has been moved or is a directory::
tar -C /tmp -jxf dist/fail2ban-0.9.4.tar.bz2
tar -C /tmp -jxf dist/fail2ban-0.9.6.tar.bz2
* clean up current direcory::
* clean up current directory::
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.4/
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.5/
* Only differences should be files that you don't want distributed.
* Ensure the tests work from the tarball::
cd /tmp/fail2ban-0.9.4/ && bin/fail2ban-testcases
cd /tmp/fail2ban-0.9.6/ && bin/fail2ban-testcases
* Add/finalize the corresponding entry in the ChangeLog
* To generate a list of committers use e.g.::
git shortlog -sn 0.9.4.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g'
git shortlog -sn 0.9.5.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g'
* Ensure the top of the ChangeLog has the right version and current date.
* Ensure the top entry of the ChangeLog has the right version and current date.
@ -106,7 +106,7 @@ Preparation
* Tag the release by using a signed (and annotated) tag. Cut/paste
release ChangeLog entry as tag annotation::
git tag -s 0.9.4
git tag -s 0.9.5
Pre Release
===========
@ -190,14 +190,14 @@ Post Release
Add the following to the top of the ChangeLog::
ver. 0.9.5 (2015/XX/XXX) - wanna-be-released
ver. 0.9.7 (2016/XX/XXX) - wanna-be-released
-----------
- Fixes:
### Fixes
- New Features:
### New Features
- Enhancements:
### Enhancements
Alter the git shortlog command in the previous section to refer to the just
released version.

2
THANKS
View File

@ -12,6 +12,7 @@ Adrien Clerc
ache
ag4ve (Shawn)
Alasdair D. Campbell
Alexandre Perrin (kAworu)
Amir Caspi
Amy
Andrew St. Jean
@ -34,6 +35,7 @@ Daniel B. Cid
Daniel B.
Daniel Black
David Nutter
David Reagan (jerrac)
Derek Atkins
Donald Yandt
Eric Gerbier

View File

@ -376,8 +376,10 @@ class Fail2banClient:
logSys.setLevel(logging.WARNING)
elif verbose == 2:
logSys.setLevel(logging.INFO)
else:
elif verbose == 3:
logSys.setLevel(logging.DEBUG)
else:
logSys.setLevel(logging.HEAVYDEBUG)
# Add the default logging handler to dump to stderr
logout = logging.StreamHandler(sys.stderr)
# set a format which is simpler for console use

View File

@ -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(

View File

@ -6,7 +6,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]

View File

@ -5,15 +5,15 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-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>
firewall-cmd --direct --add-rule ipv4 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 state --state 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>

View File

@ -0,0 +1,65 @@
# Fail2Ban configuration file
#
# Author: Donald Yandt
#
# Because of the rich rule commands requires firewalld-0.3.1+
# This action uses firewalld rich-rules which gives you a cleaner iptables since it stores rules according to zones and not
# by chain. So for an example all deny rules will be listed under <zone>_deny and all log rules under <zone>_log.
#
# Also this action logs banned access attempts so you can filter that and increase ban time for offenders.
#
# If you use the --permanent rule you get a xml file in /etc/firewalld/zones/<zone>.xml that can be shared and parsed easliy
#
# Example commands to view rules:
# firewall-cmd [--zone=<zone>] --list-rich-rules
# firewall-cmd [--zone=<zone>] --list-all
# firewall-cmd [--zone=zone] --query-rich-rule='rule'
[Definition]
actionstart =
actionstop =
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>"
# 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>"
# 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
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
[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'

View File

@ -0,0 +1,57 @@
# Fail2Ban configuration file
#
# Author: Donald Yandt
#
# Because of the rich rule commands requires firewalld-0.3.1+
# This action uses firewalld rich-rules which gives you a cleaner iptables since it stores rules according to zones and not
# by chain. So for an example all deny rules will be listed under <zone>_deny.
#
# If you use the --permanent rule you get a xml file in /etc/firewalld/zones/<zone>.xml that can be shared and parsed easliy
#
# Example commands to view rules:
# firewall-cmd [--zone=<zone>] --list-rich-rules
# firewall-cmd [--zone=<zone>] --list-all
# firewall-cmd [--zone=zone] --query-rich-rule='rule'
[Definition]
actionstart =
actionstop =
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>"
# service name example:
# firewall-cmd --zone=<zone> --add-rich-rule="rule family='ipv4' source address='<ip>' service name='<service>' <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
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
[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'

View File

@ -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+)?'\s\(callid: [^\)]*\) - (?:No matching endpoint found|Not match Endpoint(?: Contact)? ACL|(?:Failed|Error) to authenticate)\s*$
ignoreregex =

View File

@ -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

View File

@ -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 =

View File

@ -13,6 +13,7 @@ failregex = ^%(__prefix_line)s(%(__pam_auth)s(\(dovecot:auth\))?:)?\s+authentica
^%(__prefix_line)s(pop3|imap)-login: (Info: )?(Aborted login|Disconnected)(: Inactivity)? \(((auth failed, \d+ attempts)( in \d+ secs)?|tried to use (disabled|disallowed) \S+ auth)\):( user=<\S*>,)?( method=\S+,)? rip=<HOST>(, lip=(\d{1,3}\.){3}\d{1,3})?(, TLS( handshaking(: SSL_accept\(\) failed: error:[\dA-F]+:SSL routines:[TLS\d]+_GET_CLIENT_HELLO:unknown protocol)?)?(: Disconnected)?)?(, session=<\S+>)?\s*$
^%(__prefix_line)s(Info|dovecot: auth\(default\)|auth-worker\(\d+\)): pam\(\S+,<HOST>\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$
^%(__prefix_line)s(auth|auth-worker\(\d+\)): (pam|passwd-file)\(\S+,<HOST>\): unknown user\s*$
^%(__prefix_line)s(auth|auth-worker\(\d+\)): Info: ldap\(\S*,<HOST>,\S*\): invalid credentials\s*$
ignoreregex =
@ -22,9 +23,10 @@ journalmatch = _SYSTEMD_UNIT=dovecot.service
# DEV Notes:
# * the first regex is essentially a copy of pam-generic.conf
# * Probably doesn't do dovecot sql/ldap backends properly
# * Probably doesn't do dovecot sql/ldap backends properly (resolved in edit 21/03/2016)
# * Removed the 'no auth attempts' log lines from the matches because produces
# lots of false positives on misconfigured MTAs making regexp unusable
#
# Author: Martin Waschbuesch
# Daniel Black (rewrote with begin and end anchors)
# Martin O'Neal (added LDAP authentication failure regex)

View File

@ -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

View File

@ -14,10 +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 \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 =
@ -30,3 +33,4 @@ ignoreregex =
#
# Author: Cyril Jaquier
# Daniel Black (rewrote with strong regexs)
# Martin O'Neal (added additional regexs to detect authentication failures, protocol errors, and drops)

View File

@ -16,7 +16,7 @@ failregex = ^\.\d+ \[WARNING\] sofia_reg\.c:\d+ SIP auth (failure|challenge) \((
ignoreregex =
# Author: Rupa SChomaker, soapee01, Daniel Black
# http://wiki.freeswitch.org/wiki/Fail2ban
# https://freeswitch.org/confluence/display/FREESWITCH/Fail2Ban
# Thanks to Jim on mailing list of samples and guidance
#
# No need to match the following. Its a duplicate of the SIP auth regex.

View File

@ -2,9 +2,20 @@
#
#
[INCLUDES]
# Read common prefixes. If any customizations available -- read them from
# common.local
before = common.conf
[Definition]
failregex = ^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied unknown user '\w+' accessing monit httpd$
^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied wrong password for user '\w+' accessing monit httpd$
_daemon = monit
# Regexp for previous (accessing monit httpd) and new (access denied) versions
failregex = ^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied (?:unknown user '[^']+'|wrong password for user '[^']*') accessing monit httpd$
^%(__prefix_line)s\w+: access denied -- client <HOST>: (?:unknown user '[^']+'|wrong password for user '[^']*'|empty password)$
# Ignore login with empty user (first connect, no user specified)
# ignoreregex = %(__prefix_line)s\w+: access denied -- client <HOST>: (?:unknown user '')
ignoreregex =

View File

@ -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 =

View File

@ -7,7 +7,7 @@ before = common.conf
[Definition]
_daemon = postfix(-\w+)?/(submission/)?smtp(d|s)
_daemon = postfix(-\w+)?/(?:submission/|smtps/)?smtp[ds]
failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/:]*={0,2})?\s*$

View File

@ -10,7 +10,7 @@ before = common.conf
[Definition]
_daemon = postfix(-\w+)?/(submission/)?smtp(d|s)
_daemon = postfix(-\w+)?/(?:submission/|smtps/)?smtp[ds]
failregex = ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 554 5\.7\.1 .*$
^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 450 4\.7\.1 Client host rejected: cannot find your hostname, (\[\S*\]); from=<\S*> to=<\S+> proto=ESMTP helo=<\S*>$

View File

@ -21,6 +21,10 @@ failregex = ^%(__prefix_line)s\(.+?@<HOST>\) \[WARNING\] %(__errmsg)s\s*$
ignoreregex =
[Init]
journalmatch = _SYSTEMD_UNIT=pure-ftpd.service + _COMM=pure-ftpd
# Author: Cyril Jaquier
# Modified: Yaroslav Halchenko for pure-ftpd
# Documentation thanks to Blake on http://www.fail2ban.org/wiki/index.php?title=Fail2ban:Community_Portal

View File

@ -0,0 +1,25 @@
# slapd (Stand-alone LDAP Daemon) openldap daemon filter
#
# Detecting invalid credentials: error code 49
# http://www.openldap.org/doc/admin24/appendix-ldap-result-codes.html#invalidCredentials (49)
[INCLUDES]
# Read common prefixes. If any customizations available -- read them from
# common.local
before = common.conf
[Definition]
_daemon = slapd
failregex = ^(?P<__prefix>%(__prefix_line)s)conn=(?P<_conn_>\d+) fd=\d+ ACCEPT from IP=<HOST>:\d{1,5} \(IP=\S+\)\s*<SKIPLINES>(?P=__prefix)conn=(?P=_conn_) op=\d+ RESULT(?:\s(?!err)\S+=\S*)* err=49 text=[\w\s]*$
ignoreregex =
[Init]
# "maxlines" is number of log lines to buffer for multi-line regex searches
maxlines = 20
# Author: Andrii Melnyk

View File

@ -18,7 +18,7 @@ before = common.conf
_daemon = sshd
failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from <HOST>( via \S+)?\s*$
failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error|failed) for .* from <HOST>( via \S+)?\s*$
^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$
^%(__prefix_line)sFailed \S+ for .*? from <HOST>(?: port \d*)?(?: ssh\d*)?(: (ruser .*|(\S+ ID \S+ \(serial \d+\) CA )?\S+ %(__md5hex)s(, client user ".*", client host ".*")?))?\s*$
^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$

View File

@ -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
@ -839,3 +840,8 @@ logencoding = utf-8
# See "haproxy-http-auth" filter for a brief cautionary note when setting
# maxretry and findtime.
logpath = /var/log/haproxy.log
[slapd]
port = ldap,ldaps
filter = slapd
logpath = /var/log/slapd.log

View File

@ -40,7 +40,8 @@ lighttpd_error_log = /var/log/lighttpd/error.log
# http://www.hardened-php.net/suhosin/configuration.html#suhosin.log.syslog.facility
# syslog_user is the default. Lighttpd also hooks errors into its log.
suhosin_log = %(syslog_user)s %(lighttpd_error_log)s
suhosin_log = %(syslog_user)s
%(lighttpd_error_log)s
# defaults to ftp or local2 if ftp doesn't exist
proftpd_log = %(syslog_ftp)s

View File

@ -34,7 +34,8 @@ apache_access_log = /var/log/httpd/*access_log
exim_main_log = /var/log/exim/main.log
mysql_log = /var/lib/mysql/mysqld.log
mysql_log = /var/log/mariadb/mariadb.log
/var/log/mysqld.log
roundcube_errors_log = /var/log/roundcubemail/errors
@ -48,4 +49,3 @@ pureftpd_backend = systemd
wuftpd_backend = systemd
postfix_backend = systemd
dovecot_backend = systemd
mysql_backend = systemd

View File

@ -61,7 +61,7 @@ def debuggexURL(sample, regex):
q = urllib.urlencode({ 're': regex.replace('<HOST>', '(?&.ipv4)'),
'str': sample,
'flavor': 'python' })
return 'http://www.debuggex.com/?' + q
return 'https://www.debuggex.com/?' + q
def output(args):
print(args)
@ -126,6 +126,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 +241,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)
@ -335,7 +338,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

View File

@ -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__)
@ -214,7 +214,7 @@ class JailReader(ConfigReader):
elif opt == "maxretry":
stream.append(["set", self.__name, "maxretry", self.__opts[opt]])
elif opt == "ignoreip":
for ip in splitcommaspace(self.__opts[opt]):
for ip in splitwords(self.__opts[opt]):
stream.append(["set", self.__name, "addignoreip", ip])
elif opt == "findtime":
stream.append(["set", self.__name, "findtime", self.__opts[opt]])

View File

@ -128,12 +128,12 @@ 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)))

View File

@ -55,6 +55,9 @@ _RETCODE_HINTS = {
signame = dict((num, name)
for name, num in signal.__dict__.iteritems() if name.startswith("SIG"))
# max tag replacement count:
MAX_TAG_REPLACE_COUNT = 10
class CallingMap(MutableMapping):
"""A Mapping type which returns the result of callable values.
@ -390,22 +393,22 @@ class CommandAction(ActionBase):
"""
t = re.compile(r'<([^ <>]+)>')
# 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) )
return False
@ -417,7 +420,9 @@ class CommandAction(ActionBase):
continue
value = value.replace('<%s>' % found_tag , tags[found_tag])
#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?
@ -426,6 +431,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

View File

@ -181,8 +181,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")
@ -202,6 +217,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
@ -244,13 +262,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;"

View File

@ -168,7 +168,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'
@ -523,7 +523,7 @@ class Filter(JailThread):
self.__lineBuffer = failRegex.getUnmatchedTupleLines()
try:
host = failRegex.getHost()
if returnRawHost:
if returnRawHost or self.__useDns == "raw":
failList.append([failRegexIndex, host, date,
failRegex.getMatchedLines()])
if not checkAllRegex:

View File

@ -37,6 +37,7 @@ if sys.version_info >= (2,7):
self.jail.actions.add("badips", pythonModule, initOpts={
'category': "ssh",
'banaction': "test",
'timeout': 30,
})
self.action = self.jail.actions["badips"]

View File

@ -29,6 +29,7 @@ import time
import tempfile
from ..server.action import CommandAction, CallingMap
from ..server.actions import OrderedDict
from .utils import LogCaptureTestCase
from .utils import pid_exists
@ -58,6 +59,62 @@ class CommandActionTest(LogCaptureTestCase):
# Unresolveable substition
self.assertFalse(CommandAction.substituteRecursiveTags({'A': 'to=<B> fromip=<IP>', 'C': '<B>', 'B': '<C>', 'D': ''}))
self.assertFalse(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.assertFalse(CommandAction.substituteRecursiveTags( OrderedDict((
('A', '<<B><C>>'),
('B', 'D'), ('C', 'E'),
('DE', 'cycle <A>'),
)) ))
self.assertFalse(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'})
@ -125,6 +182,7 @@ class CommandActionTest(LogCaptureTestCase):
CallingMap(matches=lambda: str(10))),
"09 10 11")
def testReplaceNoTag(self):
# As tag not present, therefore callable should not be called
# Will raise ValueError if it is
self.assertEqual(

View File

@ -28,7 +28,7 @@ import unittest
from ..server.banmanager import BanManager
from ..server.ticket import BanTicket
from .utils import assert_dict_equal
class AddFailure(unittest.TestCase):
def setUp(self):
@ -74,15 +74,10 @@ class StatusExtendedCymruInfo(unittest.TestCase):
def testCymruInfo(self):
cymru_info = self.__banManager.getBanListExtendedCymruInfo()
if "assertDictEqual" in dir(self):
self.assertDictEqual(cymru_info, {"asn": [self.__asn],
"country": [self.__country],
"rir": [self.__rir]})
else:
# Python 2.6 does not support assertDictEqual()
self.assertEqual(cymru_info["asn"], [self.__asn])
self.assertEqual(cymru_info["country"], [self.__country])
self.assertEqual(cymru_info["rir"], [self.__rir])
assert_dict_equal(cymru_info,
{"asn": [self.__asn],
"country": [self.__country],
"rir": [self.__rir]})
def testCymruInfoASN(self):
self.assertEqual(
@ -100,16 +95,24 @@ class StatusExtendedCymruInfo(unittest.TestCase):
[self.__rir])
def testCymruInfoNxdomain(self):
ticket = BanTicket("10.0.0.0", 1167605999.0)
self.__banManager = BanManager()
# non-existing IP
ticket = BanTicket("0.0.0.0", 1167605999.0)
self.assertTrue(self.__banManager.addBanTicket(ticket))
cymru_info = self.__banManager.getBanListExtendedCymruInfo()
if "assertDictEqual" in dir(self):
self.assertDictEqual(cymru_info, {"asn": ["nxdomain"],
"country": ["nxdomain"],
"rir": ["nxdomain"]})
else:
# Python 2.6 does not support assertDictEqual()
self.assertEqual(cymru_info["asn"], ["nxdomain"])
self.assertEqual(cymru_info["country"], ["nxdomain"])
self.assertEqual(cymru_info["rir"], ["nxdomain"])
assert_dict_equal(cymru_info,
{"asn": ["nxdomain"],
"country": ["nxdomain"],
"rir": ["nxdomain"]})
# even for private IPs ASNs defined
# Since it outputs for all active tickets we would get previous results
# and new ones
ticket = BanTicket("10.0.0.0", 1167606000.0)
self.assertTrue(self.__banManager.addBanTicket(ticket))
cymru_info = self.__banManager.getBanListExtendedCymruInfo()
assert_dict_equal(cymru_info,
{"asn": ["nxdomain", "4565",],
"country": ["nxdomain", "unknown"],
"rir": ["nxdomain", "other"]})

View File

@ -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 =

View File

@ -40,6 +40,7 @@ except ImportError:
from ..client import fail2banregex
from ..client.fail2banregex import Fail2banRegex, get_opt_parser, output
from .utils import LogCaptureTestCase, logSys
from .utils import CONFIG_DIR
fail2banregex.logSys = logSys
@ -48,8 +49,6 @@ def _test_output(*args):
fail2banregex.output = _test_output
CONF_FILES_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__),"..", "..", "config"))
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
@ -66,7 +65,7 @@ class Fail2banRegexTest(LogCaptureTestCase):
FILENAME_02 = os.path.join(TEST_FILES_DIR, "testcase02.log")
FILENAME_WRONGCHAR = os.path.join(TEST_FILES_DIR, "testcase-wrong-char.log")
FILTER_SSHD = os.path.join(CONF_FILES_DIR, 'filter.d', 'sshd.conf')
FILTER_SSHD = os.path.join(CONFIG_DIR, 'filter.d', 'sshd.conf')
def setUp(self):
"""Call before every test case."""
@ -133,6 +132,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",
@ -176,6 +184,6 @@ class Fail2banRegexTest(LogCaptureTestCase):
self.assertTrue(fail2banRegex.start(opts, args))
self.assertLogged('Lines: 4 lines, 0 ignored, 2 matched, 2 missed')
self.assertLogged('http://')
self.assertLogged('https://')

View File

@ -67,3 +67,18 @@ 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
# 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) - Not match Endpoint ACL
# 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) - Not match Endpoint Contact ACL
# 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) - Failed to authenticate
# 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) - Error to authenticate
# Failed authentication with pjsip on Asterisk 13+
# failJSON: { "time": "2016-06-08T23:40:26", "match": true , "host": "2.3.4.5" }
[2016-06-08 23:40:26] NOTICE[32497] res_pjsip/pjsip_distributor.c: Request from '"317" <sip:317@1.2.3.4>' failed for '2.3.4.5:5089' (callid: 206f178f-896564cb-57573f49@1.2.3.4) - No matching endpoint found

View File

@ -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

View File

@ -70,3 +70,6 @@ Jun 13 21:48:06 platypus dovecot: pop3-login: Disconnected: Inactivity (no auth
Jun 13 20:20:21 platypus dovecot: imap-login: Disconnected (no auth attempts): rip=180.189.168.166, lip=113.212.99.194, TLS handshaking: Disconnected
# failJSON: { "time": "2005-07-02T13:49:32", "match": false , "host": "192.51.100.13" }
Jul 02 13:49:32 hostname dovecot[442]: pop3-login: Disconnected (no auth attempts in 58 secs): user=<>, rip=192.51.100.13, lip=203.0.113.17, session=<LgDINsQCkttVIMPg>
# failJSON: { "time": "2005-03-23T06:10:52", "match": true , "host": "52.37.139.121" }
Mar 23 06:10:52 auth: Info: ldap(dog,52.37.139.121,): invalid credentials

View File

@ -43,3 +43,27 @@
# failJSON: { "time": "2014-12-02T03:00:23", "match": true , "host": "193.254.202.35" }
2014-12-02 03:00:23 auth_plain authenticator failed for (rom182) [193.254.202.35]:41556 I=[10.0.0.1]:25: 535 Incorrect authentication data (set_id=webmaster)
# failJSON: { "time": "2016-03-18T00:34:06", "match": true , "host": "45.32.34.167" }
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" }
2016-03-21 04:33:13 [26074] 1ahrVl-0006mY-79 SMTP connection from riveruse.com [206.214.71.53]:39865 I=[172.89.0.6]:25 closed by DROP in ACL
# failJSON: { "time": "2016-04-01T11:08:39", "match": true , "host": "192.0.2.1" }
2016-04-01 11:08:39 [18643] no MAIL in SMTP connection from host.example.com (SERVER) [192.0.2.1]:1418 I=[172.89.0.6]:25 D=34s C=EHLO,AUTH
# failJSON: { "time": "2016-04-01T11:09:21", "match": true , "host": "192.0.2.1" }
2016-04-01 11:09:21 [18648] SMTP protocol error in "AUTH LOGIN" H=host.example.com (SERVER) [192.0.2.1]:4692 I=[172.89.0.6]:25 AUTH command used when not advertised
# failJSON: { "time": "2016-03-27T16:48:48", "match": true , "host": "192.0.2.1" }
2016-03-27 16:48:48 [21478] 1akDqs-0005aQ-9b SMTP connection from host.example.com (SERVER) [192.0.2.1]:47714 I=[172.89.0.6]:25 closed by DROP in ACL

View File

@ -1,6 +1,21 @@
# Previous version --
# failJSON: { "time": "2005-04-16T21:05:29", "match": true , "host": "69.93.127.111" }
[PDT Apr 16 21:05:29] error : Warning: Client '69.93.127.111' supplied unknown user 'foo' accessing monit httpd
# failJSON: { "time": "2005-04-16T20:59:33", "match": true , "host": "97.113.189.111" }
[PDT Apr 16 20:59:33] error : Warning: Client '97.113.189.111' supplied wrong password for user 'admin' accessing monit httpd
# Current version -- corresponding "https://bitbucket.org/tildeslash/monit/src/6905335aa903d425cae732cab766bd88ea5f2d1d/src/http/processor.c?at=master&fileviewer=file-view-default#processor.c-728"
# failJSON: { "time": "2005-03-09T09:18:28", "match": false, "desc": "should be ignored: no login" }
Mar 9 09:18:28 hostname monit[5731]: HttpRequest: access denied -- client 1.2.3.4: missing or invalid Authorization header
# failJSON: { "time": "2005-03-09T09:18:28", "match": false, "desc": "should be ignored: no login" }
Mar 9 09:18:28 hostname monit[5731]: HttpRequest: access denied -- client 1.2.3.4: invalid Authorization header
# failJSON: { "time": "2005-03-09T09:18:29", "match": false, "desc": "should be ignored: connect, still no user specified" }
Mar 9 09:18:29 hostname monit[5731]: HttpRequest: access denied -- client 1.2.3.4: empty username
# failJSON: { "time": "2005-03-09T09:18:31", "match": false, "desc": "should be ignored: connect, still no user specified" }
Mar 9 09:18:31 hostname monit[5731]: HttpRequest: access denied -- client 1.2.3.4: unknown user ''
# failJSON: { "time": "2005-03-09T09:18:32", "match": true, "host": "1.2.3.4", "desc": "no password try" }
Mar 9 09:18:32 hostname monit[5731]: HttpRequest: access denied -- client 1.2.3.4: empty password
# failJSON: { "time": "2005-03-09T09:18:33", "match": true, "host": "1.2.3.4", "desc": "unknown user try" }
Mar 9 09:18:33 hostname monit[5731]: HttpRequest: access denied -- client 1.2.3.4: unknown user 'test1'
# failJSON: { "time": "2005-03-09T09:18:34", "match": true, "host": "1.2.3.4", "desc": "wrong password try" }
Mar 9 09:18:34 hostname monit[5731]: HttpRequest: access denied -- client 1.2.3.4: wrong password for user 'test2'

View File

@ -32,3 +32,6 @@ Jan 31 13:55:24 xxx postfix/smtpd[3462]: NOQUEUE: reject: EHLO from s271272.stat
# failJSON: { "time": "2005-01-31T13:55:24", "match": true , "host": "78.107.251.238" }
Jan 31 13:55:24 xxx postfix-incoming/smtpd[3462]: NOQUEUE: reject: EHLO from s271272.static.corbina.ru[78.107.251.238]: 504 5.5.2 <User>: Helo command rejected: need fully-qualified hostname; proto=SMTP helo=<User>
# failJSON: { "time": "2005-04-12T02:24:11", "match": true , "host": "62.138.2.143" }
Apr 12 02:24:11 xxx postfix/smtps/smtpd[42]: NOQUEUE: reject: EHLO from astra4139.startdedicated.de[62.138.2.143]: 504 5.5.2 <User>: Helo command rejected: need fully-qualified hostname; proto=SMTP helo=<User>

View File

@ -23,3 +23,6 @@ Feb 3 08:29:28 mail postfix/smtpd[21022]: warning: unknown[1.1.1.1]: SASL LOGIN
# failJSON: { "time": "2005-01-29T08:11:45", "match": true , "host": "1.1.1.1" }
Jan 29 08:11:45 mail postfix-incoming/smtpd[10752]: warning: unknown[1.1.1.1]: SASL LOGIN authentication failed: Password:
# failJSON: { "time": "2005-04-12T02:24:11", "match": true , "host": "62.138.2.143" }
Apr 12 02:24:11 xxx postfix/smtps/smtpd[42]: warning: astra4139.startdedicated.de[62.138.2.143]: SASL LOGIN authentication failed: UGFzc3dvcmQ6

View File

@ -0,0 +1,18 @@
# failJSON: { "match": false }
Jul 8 01:47:19 ldap-server slapd[1183]: conn=1022 fd=21 ACCEPT from IP=8.8.8.8:45011 (IP=0.0.0.0:636)
# failJSON: { "match": false }
Jul 8 01:47:19 ldap-server slapd[1183]: conn=1022 fd=21 TLS established tls_ssf=256 ssf=256
# failJSON: { "match": false }
Jul 8 01:47:19 ldap-server slapd[1183]: conn=1022 op=0 EXT oid=1.3.6.1.4.1.6.1
# failJSON: { "match": false }
Jul 8 01:47:19 ldap-server slapd[1183]: conn=1022 op=0 STARTTLS
# failJSON: { "match": false }
Jul 8 01:47:19 ldap-server slapd[1183]: conn=1022 op=0 RESULT oid= err=1 text=TLS already started
# failJSON: { "match": false }
Jul 8 01:47:20 ldap-server slapd[1183]: conn=1022 op=1 BIND dn="uid=gipson,ou=people,dc=example,dc=com" method=128
# failJSON: { "time": "2005-07-08T01:47:20", "match": true , "host": "8.8.8.8", "desc": "Multiline match for invalid credentials" }
Jul 8 01:47:20 ldap-server slapd[1183]: conn=1022 op=1 RESULT tag=97 err=49 text=
# failJSON: { "match": false }
Jul 8 01:47:20 ldap-server slapd[1183]: conn=1022 op=2 UNBIND
# failJSON: { "match": false }
Jul 8 01:47:20 ldap-server slapd[1183]: conn=1022 fd=21 closed

View File

@ -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

View File

@ -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
@ -56,13 +56,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'])
class SetupTest(unittest.TestCase):

View File

@ -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,11 +61,11 @@ 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)
filterConf = FilterReader(name, "jail", {}, basedir=basedir)
self.assertEqual(filterConf.getFile(), name)
self.assertEqual(filterConf.getJailName(), "jail")
filterConf.read()
@ -147,11 +148,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_))

View File

@ -312,4 +312,10 @@ else:
kernel32.CloseHandle(process)
return True
else:
return False
return False
# Python 2.6 compatibility. in 2.7 assertDictEqual
def assert_dict_equal(a, b):
assert isinstance(a, dict), "Object is not dictionary: %r" % a
assert isinstance(b, dict), "Object is not dictionary: %r" % b
assert a==b, "Dictionaries differ:\n%r !=\n%r" % (a, b)

View File

@ -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"
version = "0.9.5"

View File

@ -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"
}

View File

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
.TH FAIL2BAN-CLIENT "1" "March 2016" "fail2ban-client v0.9.4" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH FAIL2BAN-CLIENT "1" "July 2016" "fail2ban-client v0.9.5" "User Commands"
.SH NAME
fail2ban-client \- configure and control the server
.SH SYNOPSIS
.B fail2ban-client
[\fI\,OPTIONS\/\fR] \fI\,<COMMAND>\/\fR
.SH DESCRIPTION
Fail2Ban v0.9.4 reads log file that contains password failure report
Fail2Ban v0.9.5 reads log file that contains password failure report
and bans the corresponding IP addresses using firewall rules.
.SH OPTIONS
.TP

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
.TH FAIL2BAN-REGEX "1" "March 2016" "fail2ban-regex 0.9.4" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH FAIL2BAN-REGEX "1" "July 2016" "fail2ban-regex 0.9.5" "User Commands"
.SH NAME
fail2ban-regex \- test Fail2ban "failregex" option
.SH SYNOPSIS
@ -48,6 +48,9 @@ set custom pattern used to match date/times
\fB\-e\fR ENCODING, \fB\-\-encoding\fR=\fI\,ENCODING\/\fR
File encoding. Default: system locale
.TP
\fB\-r\fR, \fB\-\-raw\fR
Raw hosts, don't resolve dns
.TP
\fB\-L\fR MAXLINES, \fB\-\-maxlines\fR=\fI\,MAXLINES\/\fR
maxlines for multi\-line regex
.TP

View File

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
.TH FAIL2BAN-SERVER "1" "March 2016" "fail2ban-server v0.9.4" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH FAIL2BAN-SERVER "1" "July 2016" "fail2ban-server v0.9.5" "User Commands"
.SH NAME
fail2ban-server \- start the server
.SH SYNOPSIS
.B fail2ban-server
[\fI\,OPTIONS\/\fR]
.SH DESCRIPTION
Fail2Ban v0.9.4 reads log file that contains password failure report
Fail2Ban v0.9.5 reads log file that contains password failure report
and bans the corresponding IP addresses using firewall rules.
.PP
Only use this command for debugging purpose. Start the server with

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.2.
.TH FAIL2BAN-TESTCASES "1" "March 2016" "fail2ban-testcases 0.9.4" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH FAIL2BAN-TESTCASES "1" "July 2016" "fail2ban-testcases 0.9.5" "User Commands"
.SH NAME
fail2ban-testcases \- run Fail2Ban unit-tests
.SH SYNOPSIS