mirror of https://github.com/fail2ban/fail2ban
Merge branch 'master' into kwirk-merge
Conflicts: ChangeLog testcases/files/logs/dropbearpull/336/head
commit
b589533d69
|
@ -31,7 +31,7 @@ ver. 0.8.11 (2013/XX/XXX) - loves-unittests
|
||||||
Daniel Black
|
Daniel Black
|
||||||
* action.d/hostsdeny -- NOTE: new dependancy 'ed'. Switched to use 'ed' across
|
* action.d/hostsdeny -- NOTE: new dependancy 'ed'. Switched to use 'ed' across
|
||||||
all platforms to ensure permissions are the same before and after a ban -
|
all platforms to ensure permissions are the same before and after a ban -
|
||||||
closes gh-266
|
closes gh-266. hostsdeny supports daemon_list now too.
|
||||||
- New Features:
|
- New Features:
|
||||||
Daniel Black & ykimon
|
Daniel Black & ykimon
|
||||||
* filter.d/3proxy.conf -- filter added
|
* filter.d/3proxy.conf -- filter added
|
||||||
|
@ -39,6 +39,8 @@ ver. 0.8.11 (2013/XX/XXX) - loves-unittests
|
||||||
* filter.d/exim-spam.conf -- a splitout of exim's spam regexes
|
* filter.d/exim-spam.conf -- a splitout of exim's spam regexes
|
||||||
with additions for greater control over filtering spam.
|
with additions for greater control over filtering spam.
|
||||||
* add date expression for apache-2.4 - milliseconds
|
* add date expression for apache-2.4 - milliseconds
|
||||||
|
Christophe Carles & Daniel Black
|
||||||
|
* filter.d/perdition.conf -- filter added
|
||||||
- Enhancements:
|
- Enhancements:
|
||||||
Daniel Black
|
Daniel Black
|
||||||
* filter.d/{asterisk,assp,dovecot,proftpd}.conf -- regex hardening
|
* filter.d/{asterisk,assp,dovecot,proftpd}.conf -- regex hardening
|
||||||
|
|
|
@ -82,7 +82,7 @@ REQ: Create /etc/fail2ban/jail.local containing:
|
||||||
|
|
||||||
enabled = true
|
enabled = true
|
||||||
filter = sshd
|
filter = sshd
|
||||||
action = hostsdeny
|
action = hostsdeny[daemon_list=sshd]
|
||||||
sendmail-whois[name=SSH, dest=you@example.com]
|
sendmail-whois[name=SSH, dest=you@example.com]
|
||||||
ignoreregex = for myuser from
|
ignoreregex = for myuser from
|
||||||
logpath = /var/adm/auth.log
|
logpath = /var/adm/auth.log
|
||||||
|
@ -119,6 +119,4 @@ GOTCHAS AND FIXMES
|
||||||
|
|
||||||
* Fail2ban adds lines like these to /etc/hosts.deny:
|
* Fail2ban adds lines like these to /etc/hosts.deny:
|
||||||
|
|
||||||
ALL: 1.2.3.4
|
sshd: 1.2.3.4
|
||||||
|
|
||||||
wouldn't it be better to just block sshd?
|
|
||||||
|
|
1
THANKS
1
THANKS
|
@ -11,6 +11,7 @@ Axel Thimm
|
||||||
Bill Heaton
|
Bill Heaton
|
||||||
Carlos Alberto Lopez Perez
|
Carlos Alberto Lopez Perez
|
||||||
Christian Rauch
|
Christian Rauch
|
||||||
|
Christophe Carles
|
||||||
Christoph Haas
|
Christoph Haas
|
||||||
Christos Psonis
|
Christos Psonis
|
||||||
Daniel B. Cid
|
Daniel B. Cid
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Fail2banReader(ConfigReader):
|
||||||
ConfigReader.read(self, "fail2ban")
|
ConfigReader.read(self, "fail2ban")
|
||||||
|
|
||||||
def getEarlyOptions(self):
|
def getEarlyOptions(self):
|
||||||
opts = [["string", "socket", "/tmp/fail2ban.sock"],
|
opts = [["string", "socket", "/var/run/fail2ban/fail2ban.sock"],
|
||||||
["string", "pidfile", "/var/run/fail2ban/fail2ban.pid"]]
|
["string", "pidfile", "/var/run/fail2ban/fail2ban.pid"]]
|
||||||
return ConfigReader.getOptions(self, "Definition", opts)
|
return ConfigReader.getOptions(self, "Definition", opts)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
#
|
#
|
||||||
|
|
||||||
__author__ = "Cyril Jaquier"
|
__author__ = "Cyril Jaquier"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
|
@ -32,7 +32,7 @@ from jailreader import JailReader
|
||||||
logSys = logging.getLogger("fail2ban.client.config")
|
logSys = logging.getLogger("fail2ban.client.config")
|
||||||
|
|
||||||
class JailsReader(ConfigReader):
|
class JailsReader(ConfigReader):
|
||||||
|
|
||||||
def __init__(self, force_enable=False, **kwargs):
|
def __init__(self, force_enable=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -44,17 +44,25 @@ class JailsReader(ConfigReader):
|
||||||
ConfigReader.__init__(self, **kwargs)
|
ConfigReader.__init__(self, **kwargs)
|
||||||
self.__jails = list()
|
self.__jails = list()
|
||||||
self.__force_enable = force_enable
|
self.__force_enable = force_enable
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
return ConfigReader.read(self, "jail")
|
return ConfigReader.read(self, "jail")
|
||||||
|
|
||||||
def getOptions(self, section = None):
|
def getOptions(self, section=None):
|
||||||
|
"""Reads configuration for jail(s) and adds enabled jails to __jails
|
||||||
|
"""
|
||||||
opts = []
|
opts = []
|
||||||
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
|
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
|
||||||
|
|
||||||
if section:
|
if section is None:
|
||||||
# Get the options of a specific jail.
|
sections = self.sections()
|
||||||
jail = JailReader(section, basedir=self.getBaseDir(), force_enable=self.__force_enable)
|
else:
|
||||||
|
sections = [ section ]
|
||||||
|
|
||||||
|
# Get the options of all jails.
|
||||||
|
for sec in sections:
|
||||||
|
jail = JailReader(sec, basedir=self.getBaseDir(),
|
||||||
|
force_enable=self.__force_enable)
|
||||||
jail.read()
|
jail.read()
|
||||||
ret = jail.getOptions()
|
ret = jail.getOptions()
|
||||||
if ret:
|
if ret:
|
||||||
|
@ -62,23 +70,10 @@ class JailsReader(ConfigReader):
|
||||||
# We only add enabled jails
|
# We only add enabled jails
|
||||||
self.__jails.append(jail)
|
self.__jails.append(jail)
|
||||||
else:
|
else:
|
||||||
logSys.error("Errors in jail '%s'. Skipping..." % section)
|
logSys.error("Errors in jail %r. Skipping..." % sec)
|
||||||
return False
|
return False
|
||||||
else:
|
|
||||||
# Get the options of all jails.
|
|
||||||
for sec in self.sections():
|
|
||||||
jail = JailReader(sec, basedir=self.getBaseDir(), force_enable=self.__force_enable)
|
|
||||||
jail.read()
|
|
||||||
ret = jail.getOptions()
|
|
||||||
if ret:
|
|
||||||
if jail.isEnabled():
|
|
||||||
# We only add enabled jails
|
|
||||||
self.__jails.append(jail)
|
|
||||||
else:
|
|
||||||
logSys.error("Errors in jail '" + sec + "'. Skipping...")
|
|
||||||
return False
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def convert(self, allow_no_files=False):
|
def convert(self, allow_no_files=False):
|
||||||
"""Convert read before __opts and jails to the commands stream
|
"""Convert read before __opts and jails to the commands stream
|
||||||
|
|
||||||
|
@ -99,6 +94,6 @@ class JailsReader(ConfigReader):
|
||||||
# Start jails
|
# Start jails
|
||||||
for jail in self.__jails:
|
for jail in self.__jails:
|
||||||
stream.append(["start", jail.getName()])
|
stream.append(["start", jail.getName()])
|
||||||
|
|
||||||
return stream
|
return stream
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
# Notes.: command executed once at the start of Fail2Ban.
|
# Notes.: command executed once at the start of Fail2Ban.
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstart = touch /tmp/fail2ban.dummy
|
actionstart = touch /var/run/fail2ban/fail2ban.dummy
|
||||||
printf %%b "<init>\n" >> /tmp/fail2ban.dummy
|
printf %%b "<init>\n" >> /var/run/fail2ban/fail2ban.dummy
|
||||||
|
|
||||||
# Option: actionstop
|
# Option: actionstop
|
||||||
# Notes.: command executed once at the end of Fail2Ban
|
# Notes.: command executed once at the end of Fail2Ban
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstop = rm -f /tmp/fail2ban.dummy
|
actionstop = rm -f /var/run/fail2ban/fail2ban.dummy
|
||||||
|
|
||||||
# Option: actioncheck
|
# Option: actioncheck
|
||||||
# Notes.: command executed once before each actionban command
|
# Notes.: command executed once before each actionban command
|
||||||
|
@ -31,7 +31,7 @@ actioncheck =
|
||||||
# Tags: See jail.conf(5) man page
|
# Tags: See jail.conf(5) man page
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "+<ip>\n" >> /tmp/fail2ban.dummy
|
actionban = printf %%b "+<ip>\n" >> /var/run/fail2ban/fail2ban.dummy
|
||||||
|
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
@ -39,7 +39,7 @@ actionban = printf %%b "+<ip>\n" >> /tmp/fail2ban.dummy
|
||||||
# Tags: See jail.conf(5) man page
|
# Tags: See jail.conf(5) man page
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = printf %%b "-<ip>\n" >> /tmp/fail2ban.dummy
|
actionunban = printf %%b "-<ip>\n" >> /var/run/fail2ban/fail2ban.dummy
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Fail2Ban configuration file
|
# Fail2Ban configuration file
|
||||||
#
|
#
|
||||||
# Author: Cyril Jaquier
|
# Author: Cyril Jaquier
|
||||||
|
# Edited for cross platform by: James Stout, Yaroslav Halchenko and Daniel Black
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ actioncheck =
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = IP=<ip> &&
|
actionban = IP=<ip> &&
|
||||||
printf %%b "ALL: $IP\n" >> <file>
|
printf %%b "<daemon_list>: $IP\n" >> <file>
|
||||||
|
|
||||||
# Option: actionunban
|
# Option: actionunban
|
||||||
# Notes.: command executed when unbanning an IP. Take care that the
|
# Notes.: command executed when unbanning an IP. Take care that the
|
||||||
|
@ -39,7 +40,7 @@ actionban = IP=<ip> &&
|
||||||
# Tags: See jail.conf(5) man page
|
# Tags: See jail.conf(5) man page
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionunban = echo "/ALL: <ip>$/<br>d<br>w<br>q" | ed <file>
|
actionunban = echo "/^<daemon_list>: <ip>$/<br>d<br>w<br>q" | ed <file>
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
|
@ -48,3 +49,9 @@ actionunban = echo "/ALL: <ip>$/<br>d<br>w<br>q" | ed <file>
|
||||||
# Values: STR Default: /etc/hosts.deny
|
# Values: STR Default: /etc/hosts.deny
|
||||||
#
|
#
|
||||||
file = /etc/hosts.deny
|
file = /etc/hosts.deny
|
||||||
|
|
||||||
|
# Option: daemon_list
|
||||||
|
# Notes: The list of services that this action will deny. See the man page
|
||||||
|
# for hosts.deny/hosts_access. Default is all services.
|
||||||
|
# Values: STR Default: ALL
|
||||||
|
daemon_list = ALL
|
||||||
|
|
|
@ -30,7 +30,7 @@ failregex = ^%(log_prefix)s Registration from '[^']*' failed for '<HOST>(:\d+)?'
|
||||||
^%(log_prefix)s Host <HOST> failed to authenticate as '[^']*'$
|
^%(log_prefix)s Host <HOST> failed to authenticate as '[^']*'$
|
||||||
^%(log_prefix)s No registration for peer '[^']*' \(from <HOST>\)$
|
^%(log_prefix)s No registration for peer '[^']*' \(from <HOST>\)$
|
||||||
^%(log_prefix)s Host <HOST> failed MD5 authentication for '[^']*' \([^)]+\)$
|
^%(log_prefix)s Host <HOST> failed MD5 authentication for '[^']*' \([^)]+\)$
|
||||||
^%(log_prefix)s Failed to authenticate user [^@]+@<HOST>\S*$
|
^%(log_prefix)s Failed to authenticate (user|device) [^@]+@<HOST>\S*$
|
||||||
^%(log_prefix)s (?:handle_request_subscribe: )?Sending fake auth rejection for (device|user) \d*<sip:[^@]+@<HOST>>;tag=\w+\S*$
|
^%(log_prefix)s (?:handle_request_subscribe: )?Sending fake auth rejection for (device|user) \d*<sip:[^@]+@<HOST>>;tag=\w+\S*$
|
||||||
^%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="[\d-]+",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="\d+",SessionID="0x[\da-f]+",LocalAddress="IPV[46]/(UD|TC)P/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UD|TC)P/<HOST>/\d+"(,Challenge="\w+",ReceivedChallenge="\w+")?(,ReceivedHash="[\da-f]+")?$
|
^%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="[\d-]+",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="\d+",SessionID="0x[\da-f]+",LocalAddress="IPV[46]/(UD|TC)P/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UD|TC)P/<HOST>/\d+"(,Challenge="\w+",ReceivedChallenge="\w+")?(,ReceivedHash="[\da-f]+")?$
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,9 @@ _daemon = dropbear
|
||||||
# These match the unmodified dropbear messages. It isn't possible to
|
# These match the unmodified dropbear messages. It isn't possible to
|
||||||
# match the source of the 'exit before auth' messages from dropbear.
|
# match the source of the 'exit before auth' messages from dropbear.
|
||||||
#
|
#
|
||||||
failregex = ^%(__prefix_line)slogin attempt for nonexistent user ('.*' )?from <HOST>:.*\s*$
|
failregex = ^%(__prefix_line)s(L|l)ogin attempt for nonexistent user ('.*' )?from <HOST>:.*\s*$
|
||||||
^%(__prefix_line)sbad password attempt for .+ from <HOST>:.*\s*$
|
^%(__prefix_line)s(B|b)ad password attempt for .+ from <HOST>:.*\s*$
|
||||||
|
^%(__prefix_line)sExit before auth \(user '.+', \d+ fails\): Max auth tries reached - user '.+' from <HOST>:\d+\s*$
|
||||||
|
|
||||||
# The only line we need to match with the modified dropbear.
|
# The only line we need to match with the modified dropbear.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Fail2Ban configuration file
|
||||||
|
#
|
||||||
|
# Author: Christophe Carles and Daniel Black
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
_daemon=perdition.\S+
|
||||||
|
|
||||||
|
failregex = ^%(__prefix_line)sAuth: <HOST>:\d+->(\d{1,3}\.){3}\d{1,3}:\d+ client-secure=\S+ authorisation_id=NONE authentication_id=".+" server="\S+" protocol=\S+ server-secure=\S+ status="failed: (local authentication failure|Re-Authentication Failure)"$
|
||||||
|
^%(__prefix_line)sFatal Error reading authentication information from client <HOST>:\d+->(\d{1,3}\.){3}\d{1,3}:\d+: Exiting child$
|
|
@ -103,7 +103,7 @@ logpath = /root/path/to/assp/logs/maillog.txt
|
||||||
|
|
||||||
enabled = false
|
enabled = false
|
||||||
filter = sshd
|
filter = sshd
|
||||||
action = hostsdeny
|
action = hostsdeny[daemon_list=sshd]
|
||||||
sendmail-whois[name=SSH, dest=you@example.com]
|
sendmail-whois[name=SSH, dest=you@example.com]
|
||||||
ignoreregex = for myuser from
|
ignoreregex = for myuser from
|
||||||
logpath = /var/log/sshd.log
|
logpath = /var/log/sshd.log
|
||||||
|
@ -409,3 +409,10 @@ enabled = false
|
||||||
filter = exim-spam
|
filter = exim-spam
|
||||||
action = iptables-multiport[name=exim-spam,port="25,465,587"]
|
action = iptables-multiport[name=exim-spam,port="25,465,587"]
|
||||||
logpath = /var/log/exim/mainlog
|
logpath = /var/log/exim/mainlog
|
||||||
|
|
||||||
|
[perdition]
|
||||||
|
enabled = false
|
||||||
|
filter = perdition
|
||||||
|
action = iptables-multiport[name=perdition,port="110,143,993,995"]
|
||||||
|
logpath = /var/log/maillog
|
||||||
|
|
||||||
|
|
|
@ -240,7 +240,7 @@ class Fail2banRegex(object):
|
||||||
|
|
||||||
def process(self, test_lines):
|
def process(self, test_lines):
|
||||||
|
|
||||||
for line in test_lines:
|
for line_no, line in enumerate(test_lines):
|
||||||
if line.startswith('#') or not line.strip():
|
if line.startswith('#') or not line.strip():
|
||||||
# skip comment and empty lines
|
# skip comment and empty lines
|
||||||
continue
|
continue
|
||||||
|
@ -256,6 +256,9 @@ class Fail2banRegex(object):
|
||||||
self._line_stats.missed_lines.append(line)
|
self._line_stats.missed_lines.append(line)
|
||||||
self._line_stats.tested += 1
|
self._line_stats.tested += 1
|
||||||
|
|
||||||
|
if line_no % 10 == 0:
|
||||||
|
self._filter.dateDetector.sortTemplate()
|
||||||
|
|
||||||
def printLines(self, ltype):
|
def printLines(self, ltype):
|
||||||
lstats = self._line_stats
|
lstats = self._line_stats
|
||||||
assert(len(lstats.missed_lines) == lstats.tested - (lstats.matched + lstats.ignored))
|
assert(len(lstats.missed_lines) == lstats.tested - (lstats.matched + lstats.ignored))
|
||||||
|
@ -374,7 +377,7 @@ if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
hdlr = open(cmd_log)
|
hdlr = open(cmd_log)
|
||||||
print "Use log file : %s" % cmd_log
|
print "Use log file : %s" % cmd_log
|
||||||
test_lines = hdlr.readlines()
|
test_lines = hdlr # Iterable
|
||||||
except IOError, e:
|
except IOError, e:
|
||||||
print e
|
print e
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
|
@ -35,7 +35,7 @@ HELP:
|
||||||
/etc/init.d/fail2ban stop
|
/etc/init.d/fail2ban stop
|
||||||
|
|
||||||
2.) delete the socket if available
|
2.) delete the socket if available
|
||||||
rm /tmp/fail2ban.sock
|
rm /var/run/fail2ban/fail2ban.sock
|
||||||
|
|
||||||
3.) start the Service
|
3.) start the Service
|
||||||
/etc/init.d/fail2ban start
|
/etc/init.d/fail2ban start
|
||||||
|
|
|
@ -157,7 +157,7 @@ class DateDetector:
|
||||||
self._appendTemplate(template)
|
self._appendTemplate(template)
|
||||||
# MySQL: 130322 11:46:11
|
# MySQL: 130322 11:46:11
|
||||||
template = DateStrptime()
|
template = DateStrptime()
|
||||||
template.setName("MonthDayYear Hour:Minute:Second")
|
template.setName("YearMonthDay Hour:Minute:Second")
|
||||||
template.setRegex("^\d{2}\d{2}\d{2} +\d{1,2}:\d{2}:\d{2}")
|
template.setRegex("^\d{2}\d{2}\d{2} +\d{1,2}:\d{2}:\d{2}")
|
||||||
template.setPattern("%y%m%d %H:%M:%S")
|
template.setPattern("%y%m%d %H:%M:%S")
|
||||||
self._appendTemplate(template)
|
self._appendTemplate(template)
|
||||||
|
|
|
@ -62,6 +62,9 @@ class DateTemplate:
|
||||||
|
|
||||||
def incHits(self):
|
def incHits(self):
|
||||||
self.__hits += 1
|
self.__hits += 1
|
||||||
|
|
||||||
|
def resetHits(self):
|
||||||
|
self.__hits = 0
|
||||||
|
|
||||||
def matchDate(self, line):
|
def matchDate(self, line):
|
||||||
dateMatch = self.__cRegex.search(line)
|
dateMatch = self.__cRegex.search(line)
|
||||||
|
|
|
@ -47,7 +47,7 @@ class Ticket:
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s: ip=%s time=%s #attempts=%d" % \
|
return "%s: ip=%s time=%s #attempts=%d" % \
|
||||||
(self.__class__, self.__ip, self.__time, self.__attempt)
|
(self.__class__.__name__.split('.')[-1], self.__ip, self.__time, self.__attempt)
|
||||||
|
|
||||||
|
|
||||||
def setIP(self, value):
|
def setIP(self, value):
|
||||||
|
@ -59,12 +59,6 @@ class Ticket:
|
||||||
def getIP(self):
|
def getIP(self):
|
||||||
return self.__ip
|
return self.__ip
|
||||||
|
|
||||||
def setFile(self, value):
|
|
||||||
self.__file = value
|
|
||||||
|
|
||||||
def getFile(self):
|
|
||||||
return self.__file
|
|
||||||
|
|
||||||
def setTime(self, value):
|
def setTime(self, value):
|
||||||
self.__time = value
|
self.__time = value
|
||||||
|
|
||||||
|
|
3
setup.py
3
setup.py
|
@ -53,7 +53,8 @@ setup(
|
||||||
packages = [
|
packages = [
|
||||||
'common',
|
'common',
|
||||||
'client',
|
'client',
|
||||||
'server'
|
'server',
|
||||||
|
'testcases'
|
||||||
],
|
],
|
||||||
data_files = [
|
data_files = [
|
||||||
('/etc/fail2ban',
|
('/etc/fail2ban',
|
||||||
|
|
|
@ -21,7 +21,7 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import os, shutil, tempfile, unittest
|
import os, tempfile, shutil, unittest
|
||||||
from client.configreader import ConfigReader
|
from client.configreader import ConfigReader
|
||||||
from client.jailreader import JailReader
|
from client.jailreader import JailReader
|
||||||
from client.jailsreader import JailsReader
|
from client.jailsreader import JailsReader
|
||||||
|
@ -65,7 +65,14 @@ option = %s
|
||||||
self._write('d.conf', 0)
|
self._write('d.conf', 0)
|
||||||
self.assertEqual(self._getoption('d'), 0)
|
self.assertEqual(self._getoption('d'), 0)
|
||||||
os.chmod(f, 0)
|
os.chmod(f, 0)
|
||||||
self.assertFalse(self.c.read('d')) # should not be readable BUT present
|
# fragile test and known to fail e.g. under Cygwin where permissions
|
||||||
|
# seems to be not enforced, thus condition
|
||||||
|
if not os.access(f, os.R_OK):
|
||||||
|
self.assertFalse(self.c.read('d')) # should not be readable BUT present
|
||||||
|
else:
|
||||||
|
# SkipTest introduced only in 2.7 thus can't yet use generally
|
||||||
|
# raise unittest.SkipTest("Skipping on %s -- access rights are not enforced" % platform)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def testOptionalDotDDir(self):
|
def testOptionalDotDDir(self):
|
||||||
|
@ -126,6 +133,13 @@ class JailsReaderTest(unittest.TestCase):
|
||||||
# commands to communicate to the server
|
# commands to communicate to the server
|
||||||
self.assertEqual(comm_commands, [])
|
self.assertEqual(comm_commands, [])
|
||||||
|
|
||||||
|
# We should not "read" some bogus jail
|
||||||
|
old_comm_commands = comm_commands[:] # make a copy
|
||||||
|
self.assertFalse(jails.getOptions("BOGUS"))
|
||||||
|
# and there should be no side-effects
|
||||||
|
self.assertEqual(jails.convert(), old_comm_commands)
|
||||||
|
|
||||||
|
|
||||||
def testReadStockJailConfForceEnabled(self):
|
def testReadStockJailConfForceEnabled(self):
|
||||||
# more of a smoke test to make sure that no obvious surprises
|
# more of a smoke test to make sure that no obvious surprises
|
||||||
# on users' systems when enabling shipped jails
|
# on users' systems when enabling shipped jails
|
||||||
|
|
|
@ -24,7 +24,7 @@ __author__ = "Cyril Jaquier"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest
|
import unittest, calendar, datetime, re, pprint
|
||||||
from server.datedetector import DateDetector
|
from server.datedetector import DateDetector
|
||||||
from server.datetemplate import DateTemplate
|
from server.datetemplate import DateTemplate
|
||||||
|
|
||||||
|
@ -122,6 +122,45 @@ class DateDetectorTest(unittest.TestCase):
|
||||||
self.__datedetector.getTime('2012/10/11 02:37:17 [error] 18434#0')[:6],
|
self.__datedetector.getTime('2012/10/11 02:37:17 [error] 18434#0')[:6],
|
||||||
m1)
|
m1)
|
||||||
|
|
||||||
|
def testDateDetectorTemplateOverlap(self):
|
||||||
|
patterns = [template.getPattern()
|
||||||
|
for template in self.__datedetector.getTemplates()
|
||||||
|
if hasattr(template, "getPattern")]
|
||||||
|
|
||||||
|
year = 2008 # Leap year, 08 for %y can be confused with both %d and %m
|
||||||
|
def iterDates(year):
|
||||||
|
for month in xrange(1, 13):
|
||||||
|
for day in xrange(2, calendar.monthrange(year, month)[1]+1, 9):
|
||||||
|
for hour in xrange(0, 24, 6):
|
||||||
|
for minute in xrange(0, 60, 15):
|
||||||
|
for second in xrange(0, 60, 15): # Far enough?
|
||||||
|
yield datetime.datetime(
|
||||||
|
year, month, day, hour, minute, second)
|
||||||
|
|
||||||
|
overlapedTemplates = set()
|
||||||
|
for date in iterDates(year):
|
||||||
|
for pattern in patterns:
|
||||||
|
datestr = date.strftime(pattern)
|
||||||
|
datestrs = set([
|
||||||
|
datestr,
|
||||||
|
re.sub(r"(\s)0", r"\1 ", datestr),
|
||||||
|
re.sub(r"(\s)0", r"\1", datestr)])
|
||||||
|
for template in self.__datedetector.getTemplates():
|
||||||
|
template.resetHits()
|
||||||
|
for datestr in datestrs:
|
||||||
|
if template.matchDate(datestr): # or getDate?
|
||||||
|
template.incHits()
|
||||||
|
|
||||||
|
matchedTemplates = [template
|
||||||
|
for template in self.__datedetector.getTemplates()
|
||||||
|
if template.getHits() > 0]
|
||||||
|
assert matchedTemplates != [] # Should match at least one
|
||||||
|
if len(matchedTemplates) > 1:
|
||||||
|
overlapedTemplates.add((pattern, tuple(sorted(template.getName()
|
||||||
|
for template in matchedTemplates))))
|
||||||
|
if overlapedTemplates:
|
||||||
|
print "WARNING: The following date templates overlap:"
|
||||||
|
pprint.pprint(overlapedTemplates)
|
||||||
|
|
||||||
# def testDefaultTempate(self):
|
# def testDefaultTempate(self):
|
||||||
# self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
# self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
||||||
|
|
|
@ -78,6 +78,20 @@ class AddFailure(unittest.TestCase):
|
||||||
ticket = self.__failManager.toBan()
|
ticket = self.__failManager.toBan()
|
||||||
self.assertEqual(ticket.getIP(), "193.168.0.128")
|
self.assertEqual(ticket.getIP(), "193.168.0.128")
|
||||||
self.assertTrue(isinstance(ticket.getIP(), str))
|
self.assertTrue(isinstance(ticket.getIP(), str))
|
||||||
|
|
||||||
|
# finish with rudimentary tests of the ticket
|
||||||
|
# verify consistent str
|
||||||
|
ticket_str = str(ticket)
|
||||||
|
self.assertEqual(
|
||||||
|
ticket_str,
|
||||||
|
'FailTicket: ip=193.168.0.128 time=1167605999.0 #attempts=5')
|
||||||
|
# and some get/set-ers otherwise not tested
|
||||||
|
ticket.setTime(1000002000.0)
|
||||||
|
self.assertEqual(ticket.getTime(), 1000002000.0)
|
||||||
|
# and str() adjusted correspondingly
|
||||||
|
self.assertEqual(
|
||||||
|
str(ticket),
|
||||||
|
'FailTicket: ip=193.168.0.128 time=1000002000.0 #attempts=5')
|
||||||
|
|
||||||
def testbanNOK(self):
|
def testbanNOK(self):
|
||||||
self.__failManager.setMaxRetry(10)
|
self.__failManager.setMaxRetry(10)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
# Sample log files for asterisk
|
# Sample log files for asterisk
|
||||||
|
# failJSON: { "time": "2013-07-25T07:26:43", "match": true , "host": "1.2.3.4" }
|
||||||
|
[2013-07-25 07:26:43] NOTICE[26015][C-000006b2] chan_sip.c: Failed to authenticate device 101<sip:101@1.2.3.4>;tag=deadbeef
|
||||||
# failJSON: { "time": "2012-02-13T17:21:54", "match": true , "host": "1.2.3.4" }
|
# failJSON: { "time": "2012-02-13T17:21:54", "match": true , "host": "1.2.3.4" }
|
||||||
[2012-02-13 17:21:54] NOTICE[1638] chan_sip.c: Registration from '<sip:301@example.com>' failed for '1.2.3.4' - Wrong password
|
[2012-02-13 17:21:54] NOTICE[1638] chan_sip.c: Registration from '<sip:301@example.com>' failed for '1.2.3.4' - Wrong password
|
||||||
# failJSON: { "time": "2012-02-13T17:18:22", "match": true , "host": "1.2.3.4" }
|
# failJSON: { "time": "2012-02-13T17:18:22", "match": true , "host": "1.2.3.4" }
|
||||||
|
|
|
@ -7,3 +7,9 @@ Mar 24 15:25:51 buffalo1 dropbear[4092]: bad password attempt for 'root' from 19
|
||||||
# failJSON: { "time": "2005-02-11T15:23:17", "match": true , "host": "198.51.100.215" }
|
# failJSON: { "time": "2005-02-11T15:23:17", "match": true , "host": "198.51.100.215" }
|
||||||
Feb 11 15:23:17 dropbear[1252]: login attempt for nonexistent user from ::ffff:198.51.100.215:60495
|
Feb 11 15:23:17 dropbear[1252]: login attempt for nonexistent user from ::ffff:198.51.100.215:60495
|
||||||
|
|
||||||
|
# failJSON: { "time": "2005-07-27T01:04:12", "match": true , "host": "1.2.3.4" }
|
||||||
|
Jul 27 01:04:12 fail2ban-test dropbear[1335]: Bad password attempt for 'root' from 1.2.3.4:60588
|
||||||
|
# failJSON: { "time": "2005-07-27T01:04:22", "match": true , "host": "1.2.3.4" }
|
||||||
|
Jul 27 01:04:22 fail2ban-test dropbear[1335]: Exit before auth (user 'root', 10 fails): Max auth tries reached - user 'root' from 1.2.3.4:60588
|
||||||
|
# failJSON: { "time": "2005-07-27T01:18:59", "match": true , "host": "1.2.3.4" }
|
||||||
|
Jul 27 01:18:59 fail2ban-test dropbear[1477]: Login attempt for nonexistent user from 1.2.3.4:60794
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# failJSON: { "time": "2005-07-18T16:07:18", "match": true , "host": "192.168.8.100" }
|
||||||
|
Jul 18 16:07:18 ares perdition.imaps[3194]: Auth: 192.168.8.100:2274->193.48.191.9:993 client-secure=ssl authorisation_id=NONE authentication_id="carles" server="imap.biotoul.fr:993" protocol=IMAP4S server-secure=ssl status="failed: Re-Authentication Failure"
|
||||||
|
# failJSON: { "time": "2005-07-18T16:08:58", "match": true , "host": "192.168.8.100" }
|
||||||
|
Jul 18 16:08:58 ares perdition.imaps[3194]: Fatal Error reading authentication information from client 192.168.8.100:2274->193.48.191.9:993: Exiting child
|
|
@ -83,7 +83,12 @@ def _assert_equal_entries(utest, found, output, count=None):
|
||||||
utest.assertEqual(found_time, output_time)
|
utest.assertEqual(found_time, output_time)
|
||||||
if len(output) > 3 and count is None: # match matches
|
if len(output) > 3 and count is None: # match matches
|
||||||
# do not check if custom count (e.g. going through them twice)
|
# do not check if custom count (e.g. going through them twice)
|
||||||
utest.assertEqual(repr(found[3]), repr(output[3]))
|
if os.linesep != '\n' or sys.platform.startswith('cygwin'):
|
||||||
|
# on those where text file lines end with '\r\n', remove '\r'
|
||||||
|
srepr = lambda x: repr(x).replace(r'\r', '')
|
||||||
|
else:
|
||||||
|
srepr = repr
|
||||||
|
utest.assertEqual(srepr(found[3]), srepr(output[3]))
|
||||||
|
|
||||||
def _assert_correct_last_attempt(utest, filter_, output, count=None):
|
def _assert_correct_last_attempt(utest, filter_, output, count=None):
|
||||||
"""Additional helper to wrap most common test case
|
"""Additional helper to wrap most common test case
|
||||||
|
|
|
@ -24,7 +24,7 @@ __author__ = "Cyril Jaquier"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import unittest, socket, time, tempfile, os
|
import unittest, socket, time, tempfile, os, sys
|
||||||
from server.server import Server
|
from server.server import Server
|
||||||
from server.jail import Jail
|
from server.jail import Jail
|
||||||
from common.exceptions import UnknownJailException
|
from common.exceptions import UnknownJailException
|
||||||
|
@ -498,7 +498,8 @@ class TransmitterLogging(TransmitterBase):
|
||||||
|
|
||||||
self.setGetTest("logtarget", "STDOUT")
|
self.setGetTest("logtarget", "STDOUT")
|
||||||
self.setGetTest("logtarget", "STDERR")
|
self.setGetTest("logtarget", "STDERR")
|
||||||
self.setGetTest("logtarget", "SYSLOG")
|
if sys.platform.lower().startswith('linux'):
|
||||||
|
self.setGetTest("logtarget", "SYSLOG")
|
||||||
|
|
||||||
def testLogLevel(self):
|
def testLogLevel(self):
|
||||||
self.setGetTest("loglevel", "4", 4)
|
self.setGetTest("loglevel", "4", 4)
|
||||||
|
|
Loading…
Reference in New Issue