MISC: merge from master

pull/348/head
Daniel Black 12 years ago
commit d5291517a7

@ -63,13 +63,15 @@ 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
Daniel Black Daniel Black
* 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.
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

@ -253,6 +253,10 @@ Use the text "closes #333"/"resolves #333 "/"fixes #333" where 333 represents
an issue that is closed. Other text and details in link below. an issue that is closed. Other text and details in link below.
See: https://help.github.com/articles/closing-issues-via-commit-messages See: https://help.github.com/articles/closing-issues-via-commit-messages
If merge resulted in conflicts, clarify what changes were done to
corresponding files in the 'Conflicts:' section of the merge commit
message. See e.g. https://github.com/fail2ban/fail2ban/commit/f5a8a8ac
Adding Actions Adding Actions
-------------- --------------

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

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

@ -341,7 +341,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
@ -357,6 +357,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))

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

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

@ -198,7 +198,7 @@ logpath = /root/path/to/assp/logs/maillog.txt
[sshd-tcpwrapper] [sshd-tcpwrapper]
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
@ -540,3 +540,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

@ -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(__name__) logSys = logging.getLogger(__name__)
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

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

@ -24,8 +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 fail2ban.server.datedetector import DateDetector from fail2ban.server.datedetector import DateDetector
from fail2ban.server.datetemplate import DateTemplate from fail2ban.server.datetemplate import DateTemplate
from fail2ban.tests.utils import setUpMyTime, tearDownMyTime from fail2ban.tests.utils import setUpMyTime, tearDownMyTime
@ -127,6 +126,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}")

@ -79,6 +79,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)

@ -2,3 +2,5 @@
# and https://github.com/fail2ban/fail2ban/issues/126 # and https://github.com/fail2ban/fail2ban/issues/126
# failJSON: { "time": "2005-02-21T09:21:54", "match": true , "host": "192.0.43.10" } # failJSON: { "time": "2005-02-21T09:21:54", "match": true , "host": "192.0.43.10" }
Feb 21 09:21:54 xxx postfix/smtpd[14398]: NOQUEUE: reject: RCPT from example.com[192.0.43.10]: 450 4.7.1 : Helo command rejected: Host not found; from=<> to=<> proto=ESMTP helo= Feb 21 09:21:54 xxx postfix/smtpd[14398]: NOQUEUE: reject: RCPT from example.com[192.0.43.10]: 450 4.7.1 : Helo command rejected: Host not found; from=<> to=<> proto=ESMTP helo=
# failJSON: { "time": "2005-07-12T07:47:48", "match": true , "host": "1.2.3.4" }
Jul 12 07:47:48 saturn postfix/smtpd[8738]: NOQUEUE: reject: RCPT from 1-2-3-4-example.com[1.2.3.4]: 554 5.7.1 <smtp@example.com>: Relay access denied; from=<john@example.com> to=<smtp@example.org> proto=SMTP helo=<198.51.100.17>

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

@ -0,0 +1,2 @@
# failJSON: { "time": "2004-12-01T20:36:56", "match": true , "host": "1.2.3.4" }
Dec 1 20:36:56 mail sieve[23713]: badlogin: example.com[1.2.3.4] PLAIN authentication failure
Loading…
Cancel
Save