- Changed Fail2Ban in order to handle several log files

git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@50 a942ae1a-1317-0410-a47c-b1dcaea8d605
0.6
Cyril Jaquier 2005-02-18 13:30:54 +00:00
parent 2c778a9b76
commit 2e5bfe5bb6
14 changed files with 298 additions and 169 deletions

View File

@ -4,9 +4,15 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_| |_| \__,_|_|_/___|_.__/\__,_|_||_|
============================================================= =============================================================
Fail2Ban (version 0.1.2) 11/21/2004 Fail2Ban (version 0.3.0) 02/??/2005
============================================================= =============================================================
ver. 0.3.0 (02/??/2005) - alpha
----------
- Re-writting of parts of the code in order to handle several
log files with different rules
- Removed sshd.py because it is no more needed
ver. 0.1.2 (11/21/2004) - beta ver. 0.1.2 (11/21/2004) - beta
---------- ----------
- Add ipfw and ipfwadm support. The rules are taken from - Add ipfw and ipfwadm support. The rules are taken from

View File

@ -12,5 +12,6 @@ firewall/ipfwadm.py
logreader/__init__.py logreader/__init__.py
logreader/logreader.py logreader/logreader.py
logreader/parser.py logreader/parser.py
logreader/sshd.py confreader/__init__.py
confreader/configreader.py
config/fail2ban.conf.default config/fail2ban.conf.default

2
README
View File

@ -79,7 +79,7 @@ options:
-b start fail2ban in background -b start fail2ban in background
-d start fail2ban in debug mode -d start fail2ban in debug mode
-e <INTF> ban IP on the INTF interface -e <INTF> ban IP on the INTF interface
-f <FILE> read password failure from FILE -c <FILE> read configuration file FILE
-h display this help message -h display this help message
-i <IP(s)> IP(s) to ignore -i <IP(s)> IP(s) to ignore
-l <FILE> log message in FILE -l <FILE> log message in FILE

View File

@ -16,10 +16,6 @@ background = false
# and bypass root user test. # and bypass root user test.
debug = false debug = false
# pwdfailfile: the path of the file which contains the
# password failure log.
pwdfailfile = /var/log/pwdfail/current
# logfile: the path of the file for logging messages of # logfile: the path of the file for logging messages of
# fail2ban. # fail2ban.
logfile = /var/log/fail2ban.log logfile = /var/log/fail2ban.log
@ -44,3 +40,40 @@ interface = eth0
# log file). 1 is a good value. # log file). 1 is a good value.
polltime = 1 polltime = 1
# You can define a new section for each log file to check for
# password failure.
[Apache]
# logfile: file to monitor.
logfile = log-test/apache
# timeregex: regular expression which have to match the
# timestamp of an Apache log event.
# [Wed Jan 05 15:08:01 2005]
timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
# timepattern: indicates the "timeregex" fields signification.
# See syntax here: http://rgruet.free.fr/PQR2.3.html#timeModule
timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
# failregex: regular expression which have to match the
# message written in the log file in case of password failure.
failregex = authentication failure
[SSH]
# logfile: file to monitor.
logfile = log-test/current
# timeregex: regular expression which have to match the
# timestamp of an Apache log event.
# Mar 7 17:53:28
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# timepattern: indicates the "timeregex" fields signification.
# See syntax here: http://rgruet.free.fr/PQR2.3.html#timeModule
timepattern = %%b %%d %%H:%%M:%%S
# failregex: regular expression which have to match the
# message written in the log file in case of password failure.
failregex = Authentication failure

25
confreader/__init__.py Normal file
View File

@ -0,0 +1,25 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"

View File

@ -24,32 +24,34 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
from parser import Parser import os, sys, time
class Sshd(Parser): from ConfigParser import *
""" OpenSSH daemon log parser. Contains specific code for sshd.
class ConfigReader:
""" Reads a log file and reports information about IP that make password
failure, bad user or anything else that is considered as doubtful login
attempt.
""" """
_instance = None optionValues = ("logfile", "timeregex", "timepattern", "failregex")
# This is the pattern to look for.
pattern = "Failed password|Illegal user" def __init__(self, confPath):
self.confPath = confPath
self.configParser = SafeConfigParser()
def openConf(self):
self.configParser.read(self.confPath)
def getSections(self):
return self.configParser.sections()
def getLogOptions(self, sec):
values = dict()
for option in self.optionValues:
v = self.configParser.get(sec, option)
values[option] = v
return values
def getInstance():
""" We use a singleton.
"""
if not Sshd._instance:
Sshd._instance = Sshd()
return Sshd._instance
getInstance = staticmethod(getInstance)
def parseLogLine(self, line):
""" Matches sshd bad login attempt. Returns the IP and the
log time.
"""
if self.getLogMatch(self.pattern, line):
matchIP = self.getLogIP(line)
if matchIP:
return [matchIP, self.getLogTime(line)]
else:
return False

View File

@ -44,6 +44,7 @@ from firewall.ipfw import Ipfw
from firewall.ipfwadm import Ipfwadm from firewall.ipfwadm import Ipfwadm
from logreader.logreader import LogReader from logreader.logreader import LogReader
from version import version from version import version
from confreader.configreader import ConfigReader
def usage(): def usage():
print "Usage: fail2ban.py [OPTIONS]" print "Usage: fail2ban.py [OPTIONS]"
@ -54,7 +55,7 @@ def usage():
print " -b start fail2ban in background" print " -b start fail2ban in background"
print " -d start fail2ban in debug mode" print " -d start fail2ban in debug mode"
print " -e <INTF> ban IP on the INTF interface" print " -e <INTF> ban IP on the INTF interface"
print " -f <FILE> read password failure from FILE" print " -c <FILE> read configuration file FILE"
print " -h display this help message" print " -h display this help message"
print " -i <IP(s)> IP(s) to ignore" print " -i <IP(s)> IP(s) to ignore"
print " -l <FILE> log message in FILE" print " -l <FILE> log message in FILE"
@ -167,15 +168,12 @@ if __name__ == "__main__":
logSys = log4py.Logger().get_instance() logSys = log4py.Logger().get_instance()
logSys.set_formatstring("%T %L %M") logSys.set_formatstring("%T %L %M")
# Config file
configParser = SafeConfigParser()
configParser.read("/etc/fail2ban.conf")
conf = dict() conf = dict()
conf["verbose"] = False conf["verbose"] = False
conf["background"] = False conf["background"] = False
conf["debug"] = False conf["debug"] = False
conf["pwdfailfile"] = "/var/log/pwdfail/current" conf["conffile"] = "/etc/fail2ban.conf"
conf["apachefile"] = "log-test/current"
conf["logging"] = False conf["logging"] = False
conf["logfile"] = "/var/log/fail2ban.log" conf["logfile"] = "/var/log/fail2ban.log"
conf["maxretry"] = 3 conf["maxretry"] = 3
@ -185,6 +183,21 @@ if __name__ == "__main__":
conf["firewall"] = "iptables" conf["firewall"] = "iptables"
conf["polltime"] = 1 conf["polltime"] = 1
# Reads the command line options.
try:
optList, args = getopt.getopt(sys.argv[1:], 'hvbdc:l:t:i:r:e:w:')
except getopt.GetoptError:
usage()
# Pre-parsing of command line options for the -c option
for opt in optList:
if opt[0] == "-c":
conf["conffile"] = opt[1]
# Config file
configParser = SafeConfigParser()
configParser.read(conf["conffile"])
# background # background
try: try:
conf["background"] = configParser.getboolean("DEFAULT", "background") conf["background"] = configParser.getboolean("DEFAULT", "background")
@ -204,16 +217,6 @@ if __name__ == "__main__":
except NoOptionError: except NoOptionError:
logSys.warn("debug option not in config file") logSys.warn("debug option not in config file")
logSys.warn("Using default value") logSys.warn("Using default value")
# pwdfailfile
try:
conf["pwdfailfile"] = configParser.get("DEFAULT", "pwdfailfile")
except ValueError:
logSys.warn("pwdfailfile option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("pwdfailfile option not in config file")
logSys.warn("Using default value")
# logfile # logfile
try: try:
@ -265,7 +268,7 @@ if __name__ == "__main__":
logSys.warn("interface option not in config file") logSys.warn("interface option not in config file")
logSys.warn("Using default value") logSys.warn("Using default value")
# interface # firewall
try: try:
conf["firewall"] = configParser.get("DEFAULT", "firewall") conf["firewall"] = configParser.get("DEFAULT", "firewall")
except ValueError: except ValueError:
@ -285,12 +288,6 @@ if __name__ == "__main__":
logSys.warn("polltime option not in config file") logSys.warn("polltime option not in config file")
logSys.warn("Using default value") logSys.warn("Using default value")
# Reads the command line options.
try:
optList, args = getopt.getopt(sys.argv[1:], 'hvbdf:l:t:i:r:e:w:')
except getopt.GetoptError:
usage()
for opt in optList: for opt in optList:
if opt[0] == "-h": if opt[0] == "-h":
usage() usage()
@ -302,8 +299,6 @@ if __name__ == "__main__":
conf["debug"] = True conf["debug"] = True
if opt[0] == "-e": if opt[0] == "-e":
conf["interface"] = opt[1] conf["interface"] = opt[1]
if opt[0] == "-f":
conf["pwdfailfile"] = opt[1]
if opt[0] == "-l": if opt[0] == "-l":
conf["logging"] = True conf["logging"] = True
conf["logfile"] = opt[1] conf["logfile"] = opt[1]
@ -359,22 +354,35 @@ if __name__ == "__main__":
if not conf["debug"]: if not conf["debug"]:
sys.exit(-1) sys.exit(-1)
logSys.debug("logFilePath is "+conf["pwdfailfile"]) logSys.debug("ConfFile is "+conf["conffile"])
logSys.debug("BanTime is "+`conf["bantime"]`) logSys.debug("BanTime is "+`conf["bantime"]`)
logSys.debug("retryAllowed is "+`conf["maxretry"]`) logSys.debug("retryAllowed is "+`conf["maxretry"]`)
# Reads the config file and create a LogReader instance for
# each log file to check.
confReader = ConfigReader(conf["conffile"]);
confReader.openConf()
logList = list()
for t in confReader.getSections():
l = confReader.getLogOptions(t)
lObj = LogReader(logSys, l["logfile"], l["timeregex"],
l["timepattern"], l["failregex"])
lObj.openLogFile()
logList.append(lObj)
# Creates one instance of Iptables (thanks to Pyhton dynamic # Creates one instance of Iptables (thanks to Pyhton dynamic
# features) and one of LogReader. # features) and one of LogReader.
fireWallObj = eval(fireWallName) fireWallObj = eval(fireWallName)
fireWall = fireWallObj(conf["bantime"], logSys, conf["interface"]) fireWall = fireWallObj(conf["bantime"], logSys, conf["interface"])
logFile = LogReader(conf["pwdfailfile"], logSys, conf["bantime"])
# We add 127.0.0.1 to the ignore list has we do not want # We add 127.0.0.1 to the ignore list has we do not want
# to be ban ourself. # to be ban ourself.
logFile.addIgnoreIP("127.0.0.1") for element in logList:
element.addIgnoreIP("127.0.0.1")
while len(ignoreIPList) > 0: while len(ignoreIPList) > 0:
ip = ignoreIPList.pop() ip = ignoreIPList.pop()
logFile.addIgnoreIP(ip) for element in logList:
element.addIgnoreIP(ip)
logSys.info("Fail2Ban v"+version+" is running") logSys.info("Fail2Ban v"+version+" is running")
# Main loop # Main loop
@ -390,12 +398,19 @@ if __name__ == "__main__":
# If the log file has not been modified since the # If the log file has not been modified since the
# last time, we sleep for 1 second. This is active # last time, we sleep for 1 second. This is active
# polling so not very effective. # polling so not very effective.
if not logFile.isModified(): isModified = False
for element in logList:
if element.isModified():
isModified = True
if not isModified:
time.sleep(conf["polltime"]) time.sleep(conf["polltime"])
continue continue
# Gets the failure list from the log file. # Gets the failure list from the log file.
failList = logFile.getPwdFailure() failList = dict()
for element in logList:
failList.update(element.getFailures())
# We iterate the failure list and ban IP that make # We iterate the failure list and ban IP that make
# *retryAllowed* login failures. # *retryAllowed* login failures.

102
log-test/apache Normal file
View File

@ -0,0 +1,102 @@
[Mon Jan 03 05:02:15 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:20 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:20 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:21 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/\xe0
[Mon Jan 03 05:02:23 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msdac
[Mon Jan 03 05:02:23 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msdac
[Mon Jan 03 05:02:24 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/PBServer
[Mon Jan 03 05:02:24 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/PBServer
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/Rpc
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/Rpc
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/samples
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/samples
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts..\xc1\x9c..
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:32 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:32 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:34 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:34 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:39 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:39 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 11:08:29 2005] [error] [client 128.178.150.127] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Mon Jan 03 20:08:52 2005] [error] [client 83.76.202.195] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:19:50 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:19:55 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:01 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:05 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:08 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:12 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:16 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:22 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:26 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:28 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:38 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 20:54:59 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 20:55:04 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 20:55:29 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 21:34:29 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 21:34:32 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 00:17:41 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 00:18:03 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 00:18:12 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:38 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:40 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:46 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:48 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:25:58 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:26:34 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:26:37 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:13:02 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:13:07 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:13:10 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:17:07 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:40 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:45 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:47 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:51 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:55:30 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:44 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:48 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:57 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:06:45 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Mar 05 15:07:28 2005] [error] [client 192.168.0.128] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Jan 05 15:08:01 2005] [error] [client 192.168.0.128] user not found: /phpinfo
[Wed Jan 05 15:10:45 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/css/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:10:45 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/images/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:10:45 2005] [error] [client 192.168.0.128] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:11:09 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 05 15:11:10 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 06 15:11:11 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 06 15:11:13 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 06 15:11:14 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 05 15:11:15 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/css/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:11:15 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/images/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:11:15 2005] [error] [client 192.168.0.128] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:12:32 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:48 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:51 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:54 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:56 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:59 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:14:20 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:14:24 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:14:29 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:14:34 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Mar 05 15:08:28 2005] [error] [client 192.168.0.128] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 05 15:09:28 2005] [error] [client 192.168.0.128] user cyril: authentication failure for "/phpinfo": Password Mismatch

View File

@ -1,4 +1,5 @@
- Last output repeated 2 times - Jan 7 17:53:15 [sshd] (pam_unix) 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=62.220.137.36 user=kevin
Oct 7 11:47:08 [sshd] Failed password for illegal user test from 69.182.27.122 port 34015 ssh2 Jan 7 17:53:26 [sshd] (pam_unix) authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=62.220.137.36 user=kevin
Oct 7 11:47:09 [sshd] Failed password for illegal user guest from 69.182.27.122 port 34068 ssh2 Mar 7 17:53:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36
Oct 7 11:47:11 [sshd] Failed password for illegal user admin from 69.182.27.122 port 34127 ssh2 Mar 7 17:55:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36

View File

@ -425,7 +425,8 @@ Oct 7 01:03:12 [sshd] Failed password for illegal user tata from 128.178.164.52
- Last output repeated 2 times - - Last output repeated 2 times -
Oct 7 01:03:20 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37187 ssh2 Oct 7 01:03:20 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37187 ssh2
- Last output repeated 2 times - - Last output repeated 2 times -
Oct 11 11:47:08 [sshd] Failed password for illegal user test from 69.182.27.122 port 34015 ssh2 Nov 14 11:47:08 [sshd] Failed password for illegal user test from 69.182.27.122 port 34015 ssh2
Oct 11 11:47:09 [sshd] Failed password for illegal user guest from 69.182.27.122 port 34068 ssh2 Nov 14 11:47:09 [sshd] Failed password for illegal user guest from 69.182.27.122 port 34068 ssh2
Oct 11 11:47:11 [sshd] Failed password for illegal user admin from 69.182.27.122 port 34127 ssh2 Nov 14 11:47:11 [sshd] Failed password for illegal user admin from 69.182.27.122 port 34127 ssh2
Oct 12 21:54:11 yellow sshd[16069]: Failed password for cyril from 212.41.79.210 port 29404 ssh2 Nov 15 11:12:11 yellow sshd[16069]: Failed password for cyril from 212.41.79.210 port 29404 ssh2
Nov 15 21:54:11 yellow sshd[16069]: Illegal user for cyril from 212.41.79.210 port 29404 ssh2

View File

@ -24,9 +24,7 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
import os, sys, time import os, sys, time, re
from sshd import Sshd
class LogReader: class LogReader:
""" Reads a log file and reports information about IP that make password """ Reads a log file and reports information about IP that make password
@ -34,13 +32,15 @@ class LogReader:
attempt. attempt.
""" """
def __init__(self, logPath, logSys, findTime = 3600): def __init__(self, logSys, logPath, timeregex, timepattern, failregex, findTime = 3600):
self.logPath = logPath self.logPath = logPath
self.timeregex = timeregex
self.timepattern = timepattern
self.failregex = failregex
self.findTime = findTime self.findTime = findTime
self.ignoreIpList = [] self.ignoreIpList = []
self.lastModTime = 0 self.lastModTime = 0
self.logSys = logSys self.logSys = logSys
self.parserList = ["Sshd"]
def addIgnoreIP(self, ip): def addIgnoreIP(self, ip):
""" Adds an IP to the ignore list. """ Adds an IP to the ignore list.
@ -79,30 +79,14 @@ class LogReader:
self.lastModTime = logStats.st_mtime self.lastModTime = logStats.st_mtime
return True return True
def matchLine(self, line): def getFailures(self):
""" Checks if the line contains a pattern. It does this for all
classes specified in *parserList*. We use a singleton to avoid
creating/destroying objects too much.
Return a dict with the IP and number of retries.
"""
for i in self.parserList:
match = eval(i).getInstance().parseLogLine(line)
if match:
return match
return None
def getFailInfo(self, findTime):
""" Gets the failed login attempt. Returns a dict() which contains
IP and the number of retries.
"""
ipList = dict() ipList = dict()
logFile = self.openLogFile() logFile = self.openLogFile()
for line in logFile.readlines(): for line in logFile.readlines():
match = self.matchLine(line) value = self.findFailure(line)
if match: if value:
ip = match[0] ip = value[0]
unixTime = match[1] unixTime = value[1]
if unixTime < time.time()-self.findTime: if unixTime < time.time()-self.findTime:
continue continue
if self.inIgnoreIPList(ip): if self.inIgnoreIPList(ip):
@ -115,9 +99,35 @@ class LogReader:
ipList[ip] = (1, unixTime) ipList[ip] = (1, unixTime)
logFile.close() logFile.close()
return ipList return ipList
def findFailure(self, line):
match = self.matchLine(line, self.failregex)
if match:
timeMatch = self.matchLine(match.string, self.timeregex)
if timeMatch:
date = self.getUnixTime(timeMatch.group(), self.timepattern)
ipMatch = self.matchAddress(match.string)
if ipMatch:
ip = ipMatch.group()
return [ip, date]
return None
def getUnixTime(self, value, pattern):
date = list(time.strptime(value, pattern))
if date[0] < 2000:
date[0] = time.gmtime()[0]
unixTime = time.mktime(date)
return unixTime
def getPwdFailure(self): def matchLine(self, line, pattern):
""" Executes the getFailInfo method. Not very usefull... """ Checks if the line contains a pattern. It does this for all
classes specified in *parserList*. We use a singleton to avoid
creating/destroying objects too much.
Return a dict with the IP and number of retries.
""" """
failList = self.getFailInfo(self.findTime) return re.search(pattern, line)
return failList
def matchAddress(self, line):
return re.search("(?:\d{1,3}\.){3}\d{1,3}", line)

View File

@ -1,67 +0,0 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import time, re
class Parser:
""" This class is the main log parser class. It should be inherited
by all the service specific classes.
"""
def getLogMatch(self, pattern, line):
""" Returns a match if pattern is found in line.
"""
return re.search(pattern, line)
def getLogIPv4(self, line):
""" Returns IP if one is found in line. Match IPv4 string.
"""
matchIP = re.search("(?:\d{1,3}\.){3}\d{1,3}", line)
if matchIP:
return matchIP.group()
else:
return None
def getLogIP(self, line):
""" Returns IP if one is found in line.
"""
return self.getLogIPv4(line)
def getLogTimeStandard(self, line):
""" Returns the log time of line using a standard log format.
Format: Oct 14 11:47:08
"""
date = list(time.strptime(line[0:15], "%b %d %H:%M:%S"))
date[0] = time.gmtime()[0]
unixTime = time.mktime(date)
return unixTime
def getLogTime(self, line):
""" Returns the log time of line.
"""
return self.getLogTimeStandard(line)

View File

@ -38,5 +38,5 @@ setup(
url = "http://www.sourceforge.net/projects/fail2ban", url = "http://www.sourceforge.net/projects/fail2ban",
scripts = ['fail2ban.py'], scripts = ['fail2ban.py'],
py_modules = ['version'], py_modules = ['version'],
packages = ['firewall', 'logreader'] packages = ['firewall', 'logreader', 'confreader']
) )

View File

@ -24,4 +24,4 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
version = "0.1.2" version = "0.3.0-CVS"