[svn-inject] Installing original source of fail2ban

debian-releases/etch
Yaroslav Halchenko 2005-07-06 23:10:19 +00:00
commit 28cca31e3f
22 changed files with 1785 additions and 0 deletions

66
CHANGELOG Normal file
View File

@ -0,0 +1,66 @@
__ _ _ ___ _
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
Fail2Ban (version 0.4.1) 06/30/2005
=============================================================
ver. 0.4.1 (06/30/2005) - stable
----------
- Fixed textToDNS method which generated wrong matches for
"rhost=12-xyz...". Thanks to Tom Pike
- fail2ban.conf modified for readability. Thanks to Iain Lea
- Added an initd script for Gentoo
- Changed default PID lock file location from /tmp to
/var/run
ver. 0.4.0 (04/24/2005) - stable
----------
- Fixed textToDNS which did not recognize strings like
"12-345-67-890.abcd.mnopqr.xyz"
ver. 0.3.1 (03/31/2005) - beta
----------
- Corrected level of messages
- Added DNS lookup support
- Improved parsing speed. Only parse the new log messages
- Added a second verbose level (-vv)
ver. 0.3.0 (02/24/2005) - beta
----------
- 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
- Fixed a bug when exiting with IP in the ban list
- Added PID lock file
- Improved some parts of the code
- Added ipfw-start-rule option (thanks to Robert Edeker)
- Added -k option which kills a currently running Fail2Ban
ver. 0.1.2 (11/21/2004) - beta
----------
- Add ipfw and ipfwadm support. The rules are taken from
BlockIt. Thanks to Robert Edeker
- Add -e option which allows to set the interface. Thanks to
Robert Edeker who reminded me this
- Small code cleaning
ver. 0.1.1 (10/23/2004) - beta
----------
- Add SIGTERM handler in order to exit nicely when in daemon
mode
- Add -r option which allows to set the maximum number of
login failures
- Remove the Metalog class as the log file are not so syslog
daemon specific
- Rewrite log reader to be service centered. Sshd support
added. Match "Failed password" and "Illegal user"
- Add /etc/fail2ban.conf configuration support
- Code documentation
ver. 0.1.0 (10/12/2004) - alpha
----------
- Initial release

10
PKG-INFO Normal file
View File

@ -0,0 +1,10 @@
Metadata-Version: 1.0
Name: fail2ban
Version: 0.4.1
Summary: Ban IPs that make too many password failure
Home-page: http://www.sourceforge.net/projects/fail2ban
Author: Cyril Jaquier
Author-email: lostcontrol@users.sourceforge.net
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN

145
README Normal file
View File

@ -0,0 +1,145 @@
__ _ _ ___ _
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
Fail2Ban (version 0.4.1) 06/30/2005
=============================================================
Fail2Ban scans log files like /var/log/pwdfail and bans IP
that makes too many password failures. It updates firewall
rules to reject the IP address. Currently iptables, ipfw and
ipfwadm are supported. Fail2Ban can read multiple log files
such as sshd or Apache web server ones. It needs log4py.
This is my first Python program. Moreover, English is not my
mother tongue...
More details:
-------------
Fail2Ban is rather simple. I have a home server connected to
the Internet which runs apache, samba, sshd, ... I see in my
logs that people are trying to log into my box using "manual"
brute force or scripts. They try 10, 20 and sometimes more
user/password (without success anyway). In order to
discourage these script kiddies, I wanted that sshd refuse
login from a specific ip after 3 password failures. After
some Google searches, I found that sshd was not able of that.
So I search for a script or program that do it. I found
nothing :-( So I decide to write mine and to learn Python :-)
For each sections defined in the configuration file, Fail2Ban
tries to find lines which match the failregex. Then it
retrieves the message time using timeregex and timepattern.
It finally gets the ip and if it has already done 3 or more
password failures in the last banTime, the ip is banned for
banTime using a firewall rule. After banTime, the rule is
deleted. Notice that if no "plain" ip is available, Fail2Ban
try to do DNS lookup in order to found one or several ip's to
ban.
Sections can be freely added so it is possible to monitor
several daemons at the same time.
Runs on my server and does its job rather well :-) The idea
is to make fail2ban usable with daemons and services that
require a login (sshd, telnetd, ...). It should also support
others firewalls than iptables.
Installation:
-------------
Require: python-2.3 (http://www.python.org)
log4py-1.1 (http://sourceforge.net/projects/log4py)
To install, just do:
> tar xvfj fail2ban-0.4.1.tar.bz2
> cd fail2ban-0.4.1
> python setup.py install
This will install Fail2Ban into /usr/lib/fail2ban. The
fail2ban.py executable is placed into /usr/bin.
For Gentoo users, an ebuild is available on the website.
Fail2Ban should now be correctly installed. Just type:
> fail2ban.py -h
to see if everything is alright. You can configure fail2ban
with a config file. Copy config/fail2ban.conf.default to
/etc/fail2ban.conf.
Gentoo users can use the initd script available in config/.
Copy gentoo-initd to /etc/init.d/fail2ban and gentoo-confd
to /etc/conf.d/fail2ban. You can start fail2ban and add it
to your default runlevel:
> /etc/init.d/fail2ban start
> rc-update add fail2ban default
Configuration:
--------------
You can configure fail2ban using the file /etc/fail2ban.conf
or using command line options. Command line options override
the value stored in fail2ban.conf. Here are the command line
options:
-b start fail2ban in background
-d start fail2ban in debug mode
-e <INTF> ban IP on the INTF interface
-c <FILE> read configuration file FILE
-p <FILE> create PID lock in FILE
-h display this help message
-i <IP(s)> IP(s) to ignore
-k kill a currently running Fail2Ban instance
-l <FILE> log message in FILE
-r <VALUE> allow a max of VALUE password failure
-t <TIME> ban IP for TIME seconds
-v verbose. Use twice for greater effect
-w <FIWA> select the firewall to use. Can be iptables,
ipfwadm or ipfw
Contact:
--------
You need some new features, you found bugs or you just
appreciate this program, you can contact me at :
Website: http://www.sourceforge.net/projects/fail2ban
Cyril Jaquier: <lostcontrol@users.sourceforge.net>
Thanks:
-------
Kévin Drapel, Marvin Rouge, Sireyessire, Robert Edeker,
Tom Pike, Iain Lea
License:
--------
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

15
TODO Normal file
View File

@ -0,0 +1,15 @@
__ _ _ ___ _
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
ToDo
=============================================================
- cleanup fail2ban.py
- improve configuration file and command line options
handling
- improve installation process
- add init script
- use FAM (inotify, gamin, ...)

View File

@ -0,0 +1,143 @@
# Fail2Ban configuration file
#
# $Revision: 1.8 $
#
# 2005.06.21 modified for readability Iain Lea iain@bricbrac.de
[DEFAULT]
# Option: firewall
# Notes.: select the firewall system to use.
# Values: [iptables | ipfwadm | ipfw] Default: iptables
#
firewall = iptables
# Option: ipfw-start-rule
# Notes.: set first firewall rule number used (only used if firewall = ipfw).
# Values: NUM Default: 100
#
ipfw-start-rule = 100
# Option: background
# Notes.: start fail2ban as a daemon. Output is redirect to logfile.
# Values: [true | false] Default: false
#
background = false
# Option: debug
# Notes.: enable debug mode. More verbose output and bypass root user test.
# Values: [true | false] Default: false
#
debug = false
# Option: pidlock
# Notes.: path of the PID lock file (must be able to write to file).
# Values: FILE Default: /var/run/fail2ban.pid
#
pidlock = /var/run/fail2ban.pid
# Option: logfile
# Notes.: logfile for logging fail2ban messages.
# Values: FILE Default: /var/log/fail2ban.log
#
logfile = /var/log/fail2ban.log
# Option: maxretry
# Notes.: number of retrys before IP gets banned.
# Values: NUM Default: 3
#
maxretry = 3
# Option: bantime
# Notes.: number of seconds an IP will be banned.
# Values: NUM Default: 600
#
bantime = 600
# Option: ignoreip
# Notes.: space separated list of IP's to be ignored by fail2ban
# Example: ignoreip = 192.168.0.1 123.45.235.65
# Values: IP Default:
#
ignoreip =
# Option: interface
# Notes.: interface name on which the IP will be banned.
# Values: INT Default: eth0
#
interface = eth0
# Option: polltime
# Notes.: number of seconds fail2ban sleeps between iterations.
# Values: NUM Default: 1
#
polltime = 1
# You can define a new section for each log file to check for
# password failure. Each section has to define the following
# options: logfile, timeregex, timepattern, failregex.
[Apache]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: false
#
enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/httpd/access_log
#
logfile = /var/log/httpd/access_log
# Option: timeregex
# Notes.: regex to match timestamp in Apache logfile.
# Values: [Wed Jan 05 15:08:01 2005]
# Default \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
#
timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule)
# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y
#
timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
# Option: failregex
# Notes.: regex to match the password failure messages in the logfile.
# Values: TEXT Default: authentication failure|user .* not found
#
failregex = authentication failure|user .* not found
[SSH]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: true
#
enabled = true
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
#
logfile = /var/log/secure
# Option: timeregex
# Notes.: regex to match timestamp in SSH logfile.
# Values: [Mar 7 17:53:28]
# Default \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
#
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule)
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
#
timepattern = %%b %%d %%H:%%M:%%S
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = Authentication failure|Failed password|Invalid user

23
config/gentoo-confd Normal file
View File

@ -0,0 +1,23 @@
# 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: 1.1 $
# Command line options for Fail2Ban. Refer to "fail2ban.py -h" for
# valid options.
FAIL2BAN_OPTS="-v"

50
config/gentoo-initd Executable file
View File

@ -0,0 +1,50 @@
#!/sbin/runscript
# 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: Sireyessire, Cyril Jaquier
#
# $Revision: 1.1 $
opts="start stop restart showlog"
FAIL2BAN="/usr/bin/fail2ban.py"
depend() {
need net
need logger
after iptables
}
start() {
ebegin "Starting fail2ban"
${FAIL2BAN} -b ${FAIL2BAN_OPTS}
eend $? "Failed to start fail2ban"
}
stop() {
ebegin "Stopping fail2ban"
${FAIL2BAN} -k
eend $? "Failed to stop fail2ban"
}
zap() {
rm /var/run/fail2ban.pid
}
showlog(){
less /var/log/fail2ban.log
}

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: 1.1 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.1 $"
__date__ = "$Date: 2005/02/18 13:26:41 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"

View File

@ -0,0 +1,80 @@
# 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: 1.5 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.5 $"
__date__ = "$Date: 2005/03/06 17:45:55 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from ConfigParser import *
class ConfigReader:
""" This class allow the handling of the configuration options.
The DEFAULT section contains the global information about
Fail2Ban. Each other section is for a different log file.
"""
# Each optionValues entry is composed of an array with:
# 0 -> the type of the option
# 1 -> the name of the option
# 2 -> the default value for the option
optionValues = (["bool", "enabled", True],
["str", "logfile", "/dev/null"],
["str", "timeregex", ""],
["str", "timepattern", ""],
["str", "failregex", ""])
def __init__(self, logSys, confPath):
self.confPath = confPath
self.configParser = SafeConfigParser()
self.logSys = logSys
def openConf(self):
""" Opens the configuration file.
"""
self.configParser.read(self.confPath)
def getSections(self):
""" Returns all the sections present in the configuration
file except the DEFAULT section.
"""
return self.configParser.sections()
def getLogOptions(self, sec):
""" Gets all the options of a given section. The options
are defined in the optionValues list.
"""
values = dict()
for option in self.optionValues:
try:
if option[0] == "bool":
v = self.configParser.getboolean(sec, option[1])
elif option[0] == "int":
v = self.configParser.getint(sec, option[1])
else:
v = self.configParser.get(sec, option[1])
values[option[1]] = v
except NoOptionError:
self.logSys.warn("No '"+option[1]+"' defined in '"+sec+"'")
values[option[1]] = option[2]
return values

551
fail2ban.py Executable file
View File

@ -0,0 +1,551 @@
#!/usr/bin/env python
# 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: 1.20 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.20 $"
__date__ = "$Date: 2005/06/30 09:26:38 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import time, sys, getopt, os, signal, string
from ConfigParser import *
# Checks if log4py is present.
try:
import log4py
except:
print "log4py is needed (see README)"
sys.exit(-1)
# Appends our own modules path
sys.path.append('/usr/lib/fail2ban')
from firewall.iptables import Iptables
from firewall.ipfw import Ipfw
from firewall.ipfwadm import Ipfwadm
from logreader.logreader import LogReader
from confreader.configreader import ConfigReader
from version import version
def usage():
print "Usage: fail2ban.py [OPTIONS]"
print
print "Fail2Ban v"+version+" reads log file that contains password failure report"
print "and bans the corresponding IP address using iptables."
print
print " -b start fail2ban in background"
print " -d start fail2ban in debug mode"
print " -e <INTF> ban IP on the INTF interface"
print " -c <FILE> read configuration file FILE"
print " -p <FILE> create PID lock in FILE"
print " -h display this help message"
print " -i <IP(s)> IP(s) to ignore"
print " -k kill a currently running Fail2Ban instance"
print " -l <FILE> log message in FILE"
print " -r <VALUE> allow a max of VALUE password failure"
print " -t <TIME> ban IP for TIME seconds"
print " -v verbose. Use twice for greater effect"
print " -w <FIWA> select the firewall to use. Can be iptables,"
print " ipfwadm or ipfw"
print
print "Report bugs to <lostcontrol@users.sourceforge.net>"
sys.exit(0)
def checkForRoot():
""" Check for root user.
"""
uid = `os.getuid()`
if uid == '0':
return True
else:
return False
def createDaemon():
"""Detach a process from the controlling terminal and run it in the
background as a daemon.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
"""
try:
# Fork a child process so the parent can exit. This will return control
# to the command line or shell. This is required so that the new process
# is guaranteed not to be a process group leader. We have this guarantee
# because the process GID of the parent is inherited by the child, but
# the child gets a new PID, making it impossible for its PID to equal its
# PGID.
pid = os.fork()
except OSError, e:
return((e.errno, e.strerror)) # ERROR (return a tuple)
if (pid == 0): # The first child.
# Next we call os.setsid() to become the session leader of this new
# session. The process also becomes the process group leader of the
# new process group. Since a controlling terminal is associated with a
# session, and this new session has not yet acquired a controlling
# terminal our process now has no controlling terminal. This shouldn't
# fail, since we're guaranteed that the child is not a process group
# leader.
os.setsid()
# When the first child terminates, all processes in the second child
# are sent a SIGHUP, so it's ignored.
signal.signal(signal.SIGHUP, signal.SIG_IGN)
try:
# Fork a second child to prevent zombies. Since the first child is
# a session leader without a controlling terminal, it's possible for
# it to acquire one by opening a terminal in the future. This second
# fork guarantees that the child is no longer a session leader, thus
# preventing the daemon from ever acquiring a controlling terminal.
pid = os.fork() # Fork a second child.
except OSError, e:
return((e.errno, e.strerror)) # ERROR (return a tuple)
if (pid == 0): # The second child.
# Ensure that the daemon doesn't keep any directory in use. Failure
# to do this could make a filesystem unmountable.
os.chdir("/")
# Give the child complete control over permissions.
os.umask(0)
else:
os._exit(0) # Exit parent (the first child) of the second child.
else:
os._exit(0) # Exit parent of the first child.
# Close all open files. Try the system configuration variable, SC_OPEN_MAX,
# for the maximum number of open files to close. If it doesn't exist, use
# the default value (configurable).
try:
maxfd = os.sysconf("SC_OPEN_MAX")
except (AttributeError, ValueError):
maxfd = 256 # default maximum
for fd in range(0, maxfd):
try:
os.close(fd)
except OSError: # ERROR (ignore)
pass
# Redirect the standard file descriptors to /dev/null.
os.open("/dev/null", os.O_RDONLY) # standard input (0)
os.open("/dev/null", os.O_RDWR) # standard output (1)
os.open("/dev/null", os.O_RDWR) # standard error (2)
return True
def sigTERMhandler(signum, frame):
""" Handles the TERM signal when in daemon mode in order to
exit properly.
"""
logSys.debug("Signal handler called with sig "+`signum`)
killApp()
def killApp():
""" Flush the ban list, remove the PID lock file and exit
nicely.
"""
logSys.warn("Restoring firewall rules...")
fireWall.flushBanList(conf["debug"])
removePID(conf["pidlock"])
logSys.info("Exiting...")
sys.exit(0)
def checkForPID(lockfile):
""" Checks for running Fail2Ban.
Returns the current PID if Fail2Ban is running or False
if no instance found.
"""
try:
fileHandler = open(lockfile)
pid = fileHandler.readline()
return pid
except IOError:
return False
def createPID(lockfile):
""" Creates a PID lock file with the current PID.
"""
fileHandler = open(lockfile, mode='w')
pid = os.getpid()
fileHandler.write(`pid`+'\n')
fileHandler.close()
logSys.debug("Created PID lock ("+`pid`+") in "+lockfile)
def removePID(lockfile):
""" Remove PID lock.
"""
os.remove(lockfile)
logSys.debug("Removed PID lock "+lockfile)
def killPID(pid):
""" Kills the process with the given PID using the
INT signal (same effect as <ctrl>+<c>).
"""
try:
return os.kill(pid, 2)
except OSError:
logSys.error("Can not kill process " + `pid` + ". Please check that " +
"Fail2Ban is not running and remove the file " +
"'/tmp/fail2ban.pid'")
if __name__ == "__main__":
# Gets an instance of log4py.
logSys = log4py.Logger().get_instance()
logSys.set_formatstring("%T %L %M")
conf = dict()
conf["verbose"] = 0
conf["background"] = False
conf["debug"] = False
conf["conffile"] = "/etc/fail2ban.conf"
conf["pidlock"] = "/var/run/fail2ban.pid"
conf["logging"] = False
conf["logfile"] = "/var/log/fail2ban.log"
conf["maxretry"] = 3
conf["bantime"] = 600
conf["ignoreip"] = ''
conf["interface"] = "eth0"
conf["firewall"] = "iptables"
conf["ipfw-start-rule"] = 0
conf["polltime"] = 1
# Reads the command line options.
try:
optList, args = getopt.getopt(sys.argv[1:], 'hvbdkc:l:t:i:r:e:w:p:')
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
try:
conf["background"] = configParser.getboolean("DEFAULT", "background")
except ValueError:
logSys.warn("background option should be a boolean")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("background option not in config file")
logSys.warn("Using default value")
# debug
try:
conf["debug"] = configParser.getboolean("DEFAULT", "debug")
except ValueError:
logSys.warn("debug option should be a boolean")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("debug option not in config file")
logSys.warn("Using default value")
# logfile
try:
conf["logfile"] = configParser.get("DEFAULT", "logfile")
except ValueError:
logSys.warn("logfile option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("logfile option not in config file")
logSys.warn("Using default value")
# pidlock
try:
conf["pidlock"] = configParser.get("DEFAULT", "pidlock")
except ValueError:
logSys.warn("pidlock option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("pidlock option not in config file")
logSys.warn("Using default value")
# maxretry
try:
conf["maxretry"] = configParser.getint("DEFAULT", "maxretry")
except ValueError:
logSys.warn("maxretry option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("maxretry option not in config file")
logSys.warn("Using default value")
# bantime
try:
conf["bantime"] = configParser.getint("DEFAULT", "bantime")
except ValueError:
logSys.warn("bantime option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("bantime option not in config file")
logSys.warn("Using default value")
# ignoreip
try:
conf["ignoreip"] = configParser.get("DEFAULT", "ignoreip")
except ValueError:
logSys.warn("ignoreip option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("ignoreip option not in config file")
logSys.warn("Using default value")
# interface
try:
conf["interface"] = configParser.get("DEFAULT", "interface")
except ValueError:
logSys.warn("interface option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("interface option not in config file")
logSys.warn("Using default value")
# firewall
try:
conf["firewall"] = configParser.get("DEFAULT", "firewall")
except ValueError:
logSys.warn("firewall option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("firewall option not in config file")
logSys.warn("Using default value")
# ipfw-start-rule
try:
conf["ipfw-start-rule"] = configParser.getint("DEFAULT",
"ipfw-start-rule")
except ValueError:
logSys.warn("ipfw-start-rule option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("ipfw-start-rule option not in config file")
logSys.warn("Using default value")
# polltime
try:
conf["polltime"] = configParser.getint("DEFAULT", "polltime")
except ValueError:
logSys.warn("polltime option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("polltime option not in config file")
logSys.warn("Using default value")
for opt in optList:
if opt[0] == "-h":
usage()
if opt[0] == "-v":
conf["verbose"] = conf["verbose"] + 1
if opt[0] == "-b":
conf["background"] = True
if opt[0] == "-d":
conf["debug"] = True
if opt[0] == "-e":
conf["interface"] = opt[1]
if opt[0] == "-l":
conf["logging"] = True
conf["logfile"] = opt[1]
if opt[0] == "-t":
try:
conf["bantime"] = int(opt[1])
except ValueError:
logSys.warn("banTime must be an integer")
logSys.warn("Using default value")
if opt[0] == "-i":
conf["ignoreip"] = opt[1]
if opt[0] == "-r":
conf["retrymax"] = int(opt[1])
if opt[0] == "-w":
conf["firewall"] = opt[1]
if opt[0] == "-p":
conf["pidlock"] = opt[1]
if opt[0] == "-k":
pid = checkForPID(conf["pidlock"])
if pid:
killPID(int(pid))
logSys.warn("Killed Fail2Ban with PID "+pid)
sys.exit(0)
else:
logSys.error("No running Fail2Ban found")
sys.exit(-1)
# Process some options
for c in conf:
if c == "verbose":
logSys.warn("Verbose level is "+`conf[c]`)
if conf[c] == 1:
logSys.set_loglevel(log4py.LOGLEVEL_VERBOSE)
elif conf[c] > 1:
logSys.set_loglevel(log4py.LOGLEVEL_DEBUG)
elif c == "debug" and conf[c]:
logSys.set_loglevel(log4py.LOGLEVEL_DEBUG)
logSys.set_formatstring(log4py.FMT_DEBUG)
elif c == "background" and conf[c]:
retCode = createDaemon()
signal.signal(signal.SIGTERM, sigTERMhandler)
logSys.set_target(conf["logfile"])
if not retCode:
logSys.error("Unable to start daemon")
sys.exit(-1)
elif c == "logging" and conf[c]:
try:
open(conf["logfile"], "a")
logSys.set_target(conf["logfile"])
except IOError:
logSys.warn("Unable to log to "+conf["logfile"])
logSys.warn("Using default output for logging")
elif c == "ignoreip":
ignoreIPList = conf[c].split(' ')
elif c == "firewall":
conf[c] = string.lower(conf[c])
if conf[c] == "ipfw":
fireWallName = "Ipfw"
elif conf[c] == "ipfwadm":
fireWallName = "Ipfwadm"
else:
fireWallName = "Iptables"
# Checks for root user. This is necessary because log files
# are owned by root and firewall needs root access.
if not checkForRoot():
logSys.error("You must be root")
if not conf["debug"]:
sys.exit(-1)
# Checks that no instance of Fail2Ban is currently running.
pid = checkForPID(conf["pidlock"])
if pid:
logSys.error("Fail2Ban already running with PID "+pid)
sys.exit(-1)
else:
createPID(conf["pidlock"])
logSys.debug("ConfFile is "+conf["conffile"])
logSys.debug("BanTime is "+`conf["bantime"]`)
logSys.debug("retryAllowed is "+`conf["maxretry"]`)
# Reads the config file and create a LogReader instance for
# each log file to check.
confReader = ConfigReader(logSys, conf["conffile"]);
confReader.openConf()
logList = list()
for t in confReader.getSections():
l = confReader.getLogOptions(t)
if l["enabled"]:
lObj = LogReader(logSys, l["logfile"], l["timeregex"],
l["timepattern"], l["failregex"], conf["bantime"])
lObj.setName(t)
logList.append(lObj)
# Creates one instance of Iptables (thanks to Pyhton dynamic
# features).
fireWallObj = eval(fireWallName)
fireWall = fireWallObj(conf["bantime"], logSys, conf["interface"])
# IPFW needs rules number. The configuration option "ipfw-start-rule"
# defines the first rule number used by Fail2Ban.
if fireWallName == "Ipfw":
fireWall.setCrtRuleNbr(conf["ipfw-start-rule"])
# We add 127.0.0.1 to the ignore list has we do not want
# to be ban ourself.
for element in logList:
element.addIgnoreIP("127.0.0.1")
while len(ignoreIPList) > 0:
ip = ignoreIPList.pop()
for element in logList:
element.addIgnoreIP(ip)
logSys.info("Fail2Ban v"+version+" is running")
failListFull = dict()
# Main loop
while True:
try:
sys.stdout.flush()
sys.stderr.flush()
# Checks if some IP have to be remove from ban
# list.
fireWall.checkForUnBan(conf["debug"])
# If the log file has not been modified since the
# last time, we sleep for 1 second. This is active
# polling so not very effective.
modList = list()
for element in logList:
if element.isModified():
modList.append(element)
if len(modList) == 0:
time.sleep(conf["polltime"])
continue
# Gets the failure list from the log file. For a given IP,
# takes only the service which has the most password failures.
failList = dict()
for element in modList:
e = element.getFailures()
for key in e.iterkeys():
if failList.has_key(key):
if failList[key][0] < e[key][0]:
failList[key] = (e[key][0], e[key][1], element)
else:
failList[key] = (e[key][0], e[key][1], element)
# Add the last log failures to the global failure list.
for key in failList.iterkeys():
if failListFull.has_key(key):
failListFull[key] = (failListFull[key][0] + 1,
failList[key][1], failList[key][2])
else:
failListFull[key] = failList[key]
# Remove the oldest failure attempts from the global list.
unixTime = time.time()
failListFullTemp = failListFull.copy()
for key in failListFullTemp.iterkeys():
failTime = failListFullTemp[key][2].getFindTime()
if failListFullTemp[key][1] < unixTime - failTime:
del failListFull[key]
# We iterate the failure list and ban IP that make
# *retryAllowed* login failures.
failListFullTemp = failListFull.copy()
for key in failListFullTemp.iterkeys():
element = failListFullTemp[key]
if element[0] >= conf["maxretry"]:
logSys.info(element[2].getName()+": "+key+" has "+
`element[0]`+" login failure(s). Banned.")
fireWall.addBanIP(key, conf["debug"])
del failListFull[key]
except KeyboardInterrupt:
# When the user press <ctrl>+<c> we exit nicely.
killApp()

25
firewall/__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: 1.1 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.1 $"
__date__ = "$Date: 2004/10/09 15:33:33 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"

98
firewall/firewall.py Normal file
View File

@ -0,0 +1,98 @@
# 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: 1.8 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.8 $"
__date__ = "$Date: 2005/03/06 17:46:56 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import time, os
class Firewall:
""" Manages the ban list and executes the command that ban
the IP.
"""
banList = dict()
def __init__(self, banTime, logSys, interface):
self.banTime = banTime
self.logSys = logSys
self.interface = interface
def addBanIP(self, ip, debug):
""" Bans an IP.
"""
if not self.inBanList(ip):
self.logSys.warn("Ban "+ip)
self.banList[ip] = time.time()
self.__executeCmd(self.banIP(ip), debug)
else:
self.logSys.error(ip+" already in ban list")
def delBanIP(self, ip, debug):
""" Unban an IP.
"""
if self.inBanList(ip):
self.logSys.warn("Unban "+ip)
del self.banList[ip]
self.__executeCmd(self.unBanIP(ip), debug)
else:
self.logSys.error(ip+" not in ban list")
def inBanList(self, ip):
""" Checks if IP is in ban list.
"""
return self.banList.has_key(ip)
def checkForUnBan(self, debug):
""" Check for IP to remove from ban list.
"""
banListTemp = self.banList.copy()
for element in banListTemp.iteritems():
ip = element[0]
btime = element[1]
if btime < time.time()-self.banTime:
self.delBanIP(ip, debug)
def flushBanList(self, debug):
""" Flushes the ban list and of course the firewall rules.
Called when fail2ban exits.
"""
banListTemp = self.banList.copy()
for element in banListTemp.iteritems():
ip = element[0]
self.delBanIP(ip, debug)
def __executeCmd(self, cmd, debug):
""" Executes an OS command.
"""
self.logSys.debug(cmd)
if not debug:
return os.system(cmd)
else:
return None
def viewBanList(self):
""" Prints the ban list on screen. Usefull for debugging.
"""
for element in self.banList.iteritems():
print element

72
firewall/ipfw.py Normal file
View File

@ -0,0 +1,72 @@
# 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: 1.4 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.4 $"
__date__ = "$Date: 2005/03/06 17:47:51 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os
from firewall import Firewall
class Ipfw(Firewall):
""" This class contains specific methods and variables for the
iptables firewall. Must implements the 'abstracts' methods
banIP(ip) and unBanIP(ip).
Must adds abstract methods definition:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266468
"""
crtRuleNbr = 0
def getCrtRuleNbr(self):
""" Gets the current rule number.
"""
return self.crtRuleNbr
def setCrtRuleNbr(self, value):
""" Sets the current rule number.
"""
self.crtRuleNbr = value
def banIP(self, ip):
""" Returns query to ban IP.
"""
query = "ipfw -q add "+`self.crtRuleNbr`+" deny ip from "+ip+" to any"
self.crtRuleNbr = self.crtRuleNbr + 1
return query
def unBanIP(self, ip):
""" Returns query to unban IP.
"""
ruleNbr = str(self.__findRuleNumber(ip))
query = "ipfw -q delete "+ruleNbr
return query
def __findRuleNumber(self, ip):
""" Uses shell commands in order to find the rule
number we want to delete.
"""
output = os.popen("ipfw list|grep \"from "+ip+" to\"|awk '{print $1}'",
"r");
return output.read()

48
firewall/ipfwadm.py Normal file
View File

@ -0,0 +1,48 @@
# 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: 1.1 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.1 $"
__date__ = "$Date: 2004/11/06 14:02:27 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from firewall import Firewall
class Ipfwadm(Firewall):
""" This class contains specific methods and variables for the
iptables firewall. Must implements the 'abstracts' methods
banIP(ip) and unBanIP(ip).
Must adds abstract methods definition:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266468
"""
def banIP(self, ip):
""" Returns query to ban IP.
"""
query = "ipfwadm -I -a deny -W "+self.interface+" -S "+ip
return query
def unBanIP(self, ip):
""" Returns query to unban IP.
"""
query = "ipfwadm -I -d deny -W "+self.interface+" -S "+ip
return query

48
firewall/iptables.py Normal file
View File

@ -0,0 +1,48 @@
# 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: 1.5 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.5 $"
__date__ = "$Date: 2004/11/06 14:02:07 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from firewall import Firewall
class Iptables(Firewall):
""" This class contains specific methods and variables for the
iptables firewall. Must implements the 'abstracts' methods
banIP(ip) and unBanIP(ip).
Must adds abstract methods definition:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266468
"""
def banIP(self, ip):
""" Returns query to ban IP.
"""
query = "iptables -I INPUT 1 -i "+self.interface+" -s "+ip+" -j DROP"
return query
def unBanIP(self, ip):
""" Returns query to unban IP.
"""
query = "iptables -D INPUT -i "+self.interface+" -s "+ip+" -j DROP"
return query

25
logreader/__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: 1.1 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.1 $"
__date__ = "$Date: 2004/10/10 13:33:40 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"

189
logreader/logreader.py Normal file
View File

@ -0,0 +1,189 @@
# 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: 1.13 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.13 $"
__date__ = "$Date: 2005/03/31 15:45:24 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os, sys, time, re
from utils.dns import *
class LogReader:
""" 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.
"""
def __init__(self, logSys, logPath, timeregex, timepattern, failregex,
findTime = 3600):
self.logPath = logPath
self.timeregex = timeregex
self.timepattern = timepattern
self.failregex = failregex
self.findTime = findTime
self.ignoreIpList = []
self.lastModTime = 0
self.logSys = logSys
self.lastPos = 0
self.lastDate = 0
self.logStats = None
def setName(self, name):
""" Sets the name of the log reader.
"""
self.name = name
def getName(self):
""" Gets the name of the log reader.
"""
return self.name
def getFindTime(self):
""" Gets the find time.
"""
return self.findTime
def addIgnoreIP(self, ip):
""" Adds an IP to the ignore list.
"""
self.logSys.debug("Add "+ip+" to ignore list")
self.ignoreIpList.append(ip)
def inIgnoreIPList(self, ip):
""" Checks if IP is in the ignore list.
"""
return ip in self.ignoreIpList
def openLogFile(self):
""" Opens the log file specified on init.
"""
try:
fileHandler = open(self.logPath)
except OSError:
self.logSys.error("Unable to open "+self.logPath)
sys.exit(-1)
return fileHandler
def isModified(self):
""" Checks if the log file has been modified using os.stat().
"""
try:
self.logStats = os.stat(self.logPath)
except OSError:
self.logSys.error("Unable to get stat on "+self.logPath)
sys.exit(-1)
if self.lastModTime == self.logStats.st_mtime:
return False
else:
self.logSys.debug(self.logPath+" has been modified")
self.lastModTime = self.logStats.st_mtime
return True
def setFilePos(self, file):
""" Sets the file position. We must take care of log file rotation
and reset the position to 0 in that case. Use the log message
timestamp in order to detect this.
"""
line = file.readline()
if self.lastDate < self.getTime(line):
self.logSys.debug("Date " + `self.lastDate` + " is " +
"smaller than " + `self.getTime(line)`)
self.logSys.debug("Log rotation detected for " + self.logPath)
self.lastPos = 0
self.logSys.debug("Setting file position to " + `self.lastPos` + " for "
+ self.logPath)
file.seek(self.lastPos)
def getFailures(self):
""" Gets all the failure in the log file which are
newer than time.time()-self.findTime.
Returns a dict with the IP, the number of failure
and the latest failure time.
"""
ipList = dict()
self.logSys.debug(self.logPath)
logFile = self.openLogFile()
self.setFilePos(logFile)
lastLine = ''
for line in logFile.readlines():
lastLine = line
failList = self.findFailure(line)
for element in failList:
ip = element[0]
unixTime = element[1]
if unixTime < time.time()-self.findTime:
break
if self.inIgnoreIPList(ip):
self.logSys.debug("Ignore "+ip)
continue
self.logSys.debug("Found "+ip)
if ipList.has_key(ip):
ipList[ip] = (ipList[ip][0]+1, unixTime)
else:
ipList[ip] = (1, unixTime)
self.lastPos = logFile.tell()
self.lastDate = self.getTime(lastLine)
logFile.close()
return ipList
def findFailure(self, line):
""" Finds the failure in line. Uses the failregex pattern
to find it and timeregex in order to find the logging
time.
Returns a dict with IP and timestamp.
"""
failList = list()
match = re.search(self.failregex, line)
if match:
timeMatch = re.search(self.timeregex, match.string)
if timeMatch:
date = self.getUnixTime(timeMatch.group())
ipMatch = textToIp(match.string)
if ipMatch:
for ip in ipMatch:
failList.append([ip, date])
return failList
def getTime(self, line):
""" Gets the time of a log message.
"""
date = 0
timeMatch = re.search(self.timeregex, line)
if timeMatch:
date = self.getUnixTime(timeMatch.group())
return date
def getUnixTime(self, value):
""" Returns the Unix timestamp of the given value.
Pattern should describe the date construction of
value.
"""
date = list(time.strptime(value, self.timepattern))
if date[0] < 2000:
date[0] = time.gmtime()[0]
unixTime = time.mktime(date)
return unixTime

5
setup.cfg Normal file
View File

@ -0,0 +1,5 @@
[install]
install-purelib=/usr/lib/fail2ban
[sdist]
formats=bztar

42
setup.py Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python
# 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: 1.4 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.4 $"
__date__ = "$Date: 2005/03/31 15:52:02 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from distutils.core import setup
from version import version
setup(
name = "fail2ban",
version = version,
description = "Ban IPs that make too many password failure",
author = "Cyril Jaquier",
author_email = "lostcontrol@users.sourceforge.net",
url = "http://www.sourceforge.net/projects/fail2ban",
scripts = ['fail2ban.py'],
py_modules = ['version'],
packages = ['firewall', 'logreader', 'confreader', 'utils']
)

25
utils/__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: 1.1 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.1 $"
__date__ = "$Date: 2005/03/06 17:51:24 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"

73
utils/dns.py Normal file
View File

@ -0,0 +1,73 @@
# 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: 1.7 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.7 $"
__date__ = "$Date: 2005/05/28 19:46:18 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os, re, socket
def dnsToIp(dns):
""" Convert a DNS into an IP address using the Python socket module.
Thanks to Kevin Drapel.
"""
try:
return socket.gethostbyname_ex(dns)[2]
except socket.gaierror:
return list()
def textToDns(text):
""" Search for possible DNS in an arbitrary text.
Thanks to Tom Pike.
"""
match = re.findall("(?:(?:\w|-)+\.){2,}\w+", text)
if match:
return match
else:
return []
def searchIP(text):
""" Search if an IP address if directly available and return
it.
"""
match = re.findall("(?:\d{1,3}\.){3}\d{1,3}", text)
if match:
return match
else:
return []
def textToIp(text):
""" Return the IP of DNS found in a given text.
"""
ipList = list()
# Search for plain IP
plainIP = searchIP(text)
for element in plainIP:
ipList.append(element)
if not ipList:
# Try to get IP from possible DNS
dnsList = textToDns(text)
for element in dnsList:
dns = dnsToIp(element)
for e in dns:
ipList.append(e)
return ipList

27
version.py Normal file
View File

@ -0,0 +1,27 @@
# 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: 1.12 $
__author__ = "Cyril Jaquier"
__version__ = "$Revision: 1.12 $"
__date__ = "$Date: 2005/06/30 09:30:59 $"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
version = "0.4.1"