mirror of https://github.com/fail2ban/fail2ban
- One step forward to 0.7.0
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@250 a942ae1a-1317-0410-a47c-b1dcaea8d6050.x
parent
ea1948eff4
commit
12c222bd1c
13
CHANGELOG
13
CHANGELOG
|
@ -4,9 +4,20 @@
|
|||
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||
|
||||
=============================================================
|
||||
Fail2Ban (version 0.6.1) 2006/03/16
|
||||
Fail2Ban (version 0.7.0) 2006/07/??
|
||||
=============================================================
|
||||
|
||||
ver. 0.7.0 (2006/07/??) - alpha
|
||||
----------
|
||||
- Almost a complete rewrite :) Fail2ban design is really
|
||||
better (IMHO). There is a lot of new features
|
||||
- Client/Server architecture
|
||||
- Multithreading. Each jail has its own threads: one for the
|
||||
log reading and another for the actions
|
||||
- Execute several actions
|
||||
- Split configuration files. They are more readable and easy
|
||||
to use
|
||||
|
||||
ver. 0.6.1 (2006/03/16) - stable
|
||||
----------
|
||||
- Added permanent banning. Set banTime to a negative value to
|
||||
|
|
61
MANIFEST
61
MANIFEST
|
@ -1,29 +1,52 @@
|
|||
README
|
||||
CHANGELOG
|
||||
TODO
|
||||
setup.cfg
|
||||
fail2ban-client
|
||||
fail2ban-server
|
||||
fail2ban-testcases
|
||||
client/__init__.py
|
||||
client/actionreader.py
|
||||
client/configreader.py
|
||||
client/configurator.py
|
||||
client/csocket.py
|
||||
client/fail2banreader.py
|
||||
client/filterreader.py
|
||||
client/jailreader.py
|
||||
client/jailsreader.py
|
||||
server/__init__.py
|
||||
server/action.py
|
||||
server/actions.py
|
||||
server/banmanager.py
|
||||
server/banticket.py
|
||||
server/faildata.py
|
||||
server/failmanager.py
|
||||
server/failticket.py
|
||||
server/filter.py
|
||||
server/jail.py
|
||||
server/jailthread.py
|
||||
server/server.py
|
||||
server/ssocket.py
|
||||
server/ticket.py
|
||||
server/transmitter.py
|
||||
setup.py
|
||||
version.py
|
||||
fail2ban
|
||||
fail2ban.py
|
||||
firewall/__init__.py
|
||||
firewall/firewall.py
|
||||
logreader/__init__.py
|
||||
logreader/logreader.py
|
||||
confreader/__init__.py
|
||||
confreader/configreader.py
|
||||
testcases/__init__.py
|
||||
testcases/banmanagertestcase.py
|
||||
testcases/failmanagertestcase.py
|
||||
testcases/filtertestcase.py
|
||||
testcases/servertestcase.py
|
||||
utils/__init__.py
|
||||
utils/dns.py
|
||||
utils/process.py
|
||||
utils/mail.py
|
||||
utils/strings.py
|
||||
utils/pidlock.py
|
||||
config/fail2ban.conf.iptables
|
||||
config/fail2ban.conf.shorewall
|
||||
config/fail2ban.conf.hostsdeny
|
||||
config/gentoo-initd
|
||||
config/gentoo-confd
|
||||
config/redhat-initd
|
||||
config/debian-initd
|
||||
utils/process.py
|
||||
utils/strings.py
|
||||
version.py
|
||||
config/fail2ban.conf
|
||||
config/fail2ban.local
|
||||
config/jail.conf
|
||||
config/action.d/dummy.conf
|
||||
config/action.d/iptables.conf
|
||||
config/filter.d/apache-auth.conf
|
||||
config/filter.d/sshd.conf
|
||||
man/fail2ban.8
|
||||
man/fail2ban.conf.5
|
||||
|
|
2
TODO
2
TODO
|
@ -1,2 +1,2 @@
|
|||
- Don't close socket after a send
|
||||
- Multiple actions !!!
|
||||
- Refactoring in server.py, actions.py, filter.py
|
|
@ -53,8 +53,7 @@ class ActionReader(ConfigReader):
|
|||
ConfigReader.read(self, "action.d/" + self.file)
|
||||
|
||||
def getOptions(self, pOpts):
|
||||
opts = [["string", "bantime", "600"],
|
||||
["string", "actionstart", ""],
|
||||
opts = [["string", "actionstart", ""],
|
||||
["string", "actionstop", ""],
|
||||
["string", "actioncheck", ""],
|
||||
["string", "actionban", ""],
|
||||
|
@ -62,19 +61,19 @@ class ActionReader(ConfigReader):
|
|||
self.opts = ConfigReader.getOptions(self, "DEFAULT", opts, pOpts)
|
||||
|
||||
def convert(self):
|
||||
head = ["set", self.name]
|
||||
stream = list()
|
||||
stream.append(head + ["addaction", self.file])
|
||||
for opt in self.opts:
|
||||
if opt == "bantime":
|
||||
stream.append(["set", self.name, "bantime", self.opts[opt]])
|
||||
elif opt == "actionstart":
|
||||
stream.append(["set", self.name, "actionstart", self.opts[opt]])
|
||||
if opt == "actionstart":
|
||||
stream.append(head + ["actionstart", self.file, self.opts[opt]])
|
||||
elif opt == "actionstop":
|
||||
stream.append(["set", self.name, "actionstop", self.opts[opt]])
|
||||
stream.append(head + ["actionstop", self.file, self.opts[opt]])
|
||||
elif opt == "actioncheck":
|
||||
stream.append(["set", self.name, "actioncheck", self.opts[opt]])
|
||||
stream.append(head + ["actioncheck", self.file, self.opts[opt]])
|
||||
elif opt == "actionban":
|
||||
stream.append(["set", self.name, "actionban", self.opts[opt]])
|
||||
stream.append(head + ["actionban", self.file, self.opts[opt]])
|
||||
elif opt == "actionunban":
|
||||
stream.append(["set", self.name, "actionunban", self.opts[opt]])
|
||||
stream.append(head + ["actionunban", self.file, self.opts[opt]])
|
||||
return stream
|
||||
|
|
@ -38,7 +38,7 @@ class JailReader(ConfigReader):
|
|||
ConfigReader.__init__(self)
|
||||
self.name = name
|
||||
self.filter = None
|
||||
self.action = None
|
||||
self.actions = list()
|
||||
|
||||
def setName(self, value):
|
||||
self.name = value
|
||||
|
@ -55,7 +55,7 @@ class JailReader(ConfigReader):
|
|||
def getOptions(self):
|
||||
opts = [["bool", "enabled", "false"],
|
||||
["int", "maxretry", None],
|
||||
["int", "bantime", None],
|
||||
["int", "bantime", 600],
|
||||
["string", "filter", ""],
|
||||
["string", "action", ""]]
|
||||
self.opts = ConfigReader.getOptions(self, self.name, opts)
|
||||
|
@ -67,9 +67,11 @@ class JailReader(ConfigReader):
|
|||
self.filter.getOptions(self.opts)
|
||||
|
||||
# Read action
|
||||
self.action = ActionReader(self.opts["action"], self.name)
|
||||
self.action.read()
|
||||
self.action.getOptions(self.opts)
|
||||
for act in self.opts["action"].split():
|
||||
action = ActionReader(act, self.name)
|
||||
action.read()
|
||||
action.getOptions(self.opts)
|
||||
self.actions.append(action)
|
||||
|
||||
def convert(self):
|
||||
stream = [["add", self.name]]
|
||||
|
@ -79,6 +81,7 @@ class JailReader(ConfigReader):
|
|||
elif opt == "bantime":
|
||||
stream.append(["set", self.name, "bantime", self.opts[opt]])
|
||||
stream.extend(self.filter.convert())
|
||||
stream.extend(self.action.convert())
|
||||
for action in self.actions:
|
||||
stream.extend(action.convert())
|
||||
return stream
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
[DEFAULT]
|
||||
|
||||
bantime = 1234
|
||||
|
||||
name = temporary
|
||||
|
||||
# Option: protocol
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
[DEFAULT]
|
||||
|
||||
name = temporary
|
||||
|
||||
# Option: protocol
|
||||
# Notes.: internally used by config reader for interpolations.
|
||||
# Values: [ tcp | udp | icmp | all ] Default: tcp
|
||||
#
|
||||
protocol = tcp
|
||||
|
||||
# Option: fwstart
|
||||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstart = touch /tmp/fail2ban.foo
|
||||
|
||||
# Option: fwend
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstop = rm /tmp/fail2ban.foo
|
||||
|
||||
# Option: fwcheck
|
||||
# Notes.: command executed once before each fwban command
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actioncheck =
|
||||
|
||||
# Option: fwban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: <ip> IP address
|
||||
# <failures> number of failures
|
||||
# <failtime> unix timestamp of the last failure
|
||||
# <bantime> unix timestamp of the ban time
|
||||
# Values: CMD
|
||||
# Default: iptables -I INPUT 1 -s <ip> -j DROP
|
||||
#
|
||||
actionban = echo "+<ip>" >> /tmp/fail2ban.foo
|
||||
|
||||
# Option: fwunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: <ip> IP address
|
||||
# <bantime> unix timestamp of the ban time
|
||||
# <unbantime> unix timestamp of the unban time
|
||||
# Values: CMD
|
||||
# Default: iptables -D INPUT -s <ip> -j DROP
|
||||
#
|
||||
actionunban = echo "-<ip>" >> /tmp/fail2ban.foo
|
|
@ -1,4 +1,4 @@
|
|||
[DEFAULT]
|
||||
|
||||
loglevel = 4
|
||||
loglevel = 3
|
||||
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
[DEFAULT]
|
||||
|
||||
test = 4567
|
||||
prout = fuck you
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
enabled = true
|
||||
filter = sshd
|
||||
action = dummy
|
||||
action = dummy foo
|
||||
maxretry = 2
|
||||
#bantime = 10
|
||||
bantime = 5
|
||||
|
||||
[SSH]
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import sys, string, os, pickle, re, logging, getopt, time
|
|||
sys.path.insert(1, "/usr/lib/fail2ban")
|
||||
|
||||
# Now we can import our modules
|
||||
from version import version
|
||||
from client.csocket import CSocket
|
||||
from client.configurator import Configurator
|
||||
|
||||
|
@ -57,7 +58,7 @@ class Fail2banClient:
|
|||
"""
|
||||
print "Usage: "+self.argv[0]+" [OPTIONS] <COMMAND>"
|
||||
print
|
||||
print "Fail2Ban v0.7 reads log file that contains password failure report"
|
||||
print "Fail2Ban v" + version + " reads log file that contains password failure report"
|
||||
print "and bans the corresponding IP addresses using firewall rules."
|
||||
print
|
||||
print " -b start in background"
|
||||
|
@ -126,6 +127,10 @@ class Fail2banClient:
|
|||
self.startServer(self.conf["background"])
|
||||
# Configure the server
|
||||
self.processCmd(self.stream)
|
||||
elif cmd[0] == "loadconf" and len(cmd) == 1:
|
||||
self.readConfig()
|
||||
# Configure the server
|
||||
self.processCmd(self.stream)
|
||||
else:
|
||||
try:
|
||||
client = CSocket()
|
||||
|
|
|
@ -25,9 +25,15 @@ __date__ = "$Date: 2004/10/10 13:33:40 $"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import locale, getopt, logging, sys
|
||||
|
||||
# Inserts our own modules path first in the list
|
||||
# fix for bug #343821
|
||||
sys.path.insert(1, "/usr/lib/fail2ban")
|
||||
|
||||
from version import version
|
||||
from server.server import Server
|
||||
from utils.process import *
|
||||
import locale, getopt, logging, sys
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger("fail2ban")
|
||||
|
@ -53,7 +59,7 @@ class Fail2banServer:
|
|||
"""
|
||||
print "Usage: "+self.argv[0]+" [OPTIONS]"
|
||||
print
|
||||
print "Fail2Ban v0.7 reads log file that contains password failure report"
|
||||
print "Fail2Ban v" + version + " reads log file that contains password failure report"
|
||||
print "and bans the corresponding IP addresses using firewall rules."
|
||||
print
|
||||
print " -b start in background"
|
||||
|
|
|
@ -28,6 +28,11 @@ __license__ = "GPL"
|
|||
|
||||
import unittest, logging, sys
|
||||
|
||||
# Inserts our own modules path first in the list
|
||||
# fix for bug #343821
|
||||
sys.path.insert(1, "/usr/lib/fail2ban")
|
||||
|
||||
from version import version
|
||||
from testcases import filtertestcase
|
||||
from testcases import servertestcase
|
||||
from testcases import failmanagertestcase
|
||||
|
@ -40,7 +45,7 @@ stdout = logging.StreamHandler(sys.stdout)
|
|||
logSys.addHandler(stdout)
|
||||
logSys.setLevel(logging.FATAL)
|
||||
|
||||
print "Fail2ban test suite. Please wait..."
|
||||
print "Fail2ban " + version + " test suite. Please wait..."
|
||||
|
||||
tests = unittest.TestSuite()
|
||||
|
||||
|
|
158
server/action.py
158
server/action.py
|
@ -24,13 +24,10 @@ __date__ = "$Date: 2004/10/10 13:33:40 $"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
from banmanager import BanManager
|
||||
from failmanager import FailManager, FailManagerEmpty
|
||||
from jailthread import JailThread
|
||||
import time, logging, os
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger("fail2ban.action")
|
||||
logSys = logging.getLogger("fail2ban.actions.action")
|
||||
|
||||
##
|
||||
# Execute commands.
|
||||
|
@ -39,20 +36,10 @@ logSys = logging.getLogger("fail2ban.action")
|
|||
# action has to be taken. A BanManager take care of the banned IP
|
||||
# addresses.
|
||||
|
||||
class Action(JailThread):
|
||||
class Action:
|
||||
|
||||
##
|
||||
# Constructor.
|
||||
#
|
||||
# Initialize the filter object with default values.
|
||||
# @param jail the jail object
|
||||
|
||||
def __init__(self, jail):
|
||||
JailThread.__init__(self, jail)
|
||||
## The jail which contains this action.
|
||||
self.jail = jail
|
||||
## The ban manager.
|
||||
self.banManager = BanManager()
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
## Command executed in order to initialize the system.
|
||||
self.actionStart = ''
|
||||
## Command executed when an IP address gets banned.
|
||||
|
@ -64,7 +51,13 @@ class Action(JailThread):
|
|||
## Command executed in order to stop the system.
|
||||
self.actionStop = ''
|
||||
logSys.debug("Created Action")
|
||||
|
||||
|
||||
def setName(self, name):
|
||||
self.name = name
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
##
|
||||
# Set the "start" command.
|
||||
#
|
||||
|
@ -82,6 +75,9 @@ class Action(JailThread):
|
|||
def getActionStart(self):
|
||||
return self.actionStart
|
||||
|
||||
def execActionStart(self, aInfo):
|
||||
return self.executeCmd(self.actionStart, aInfo);
|
||||
|
||||
##
|
||||
# Set the "ban" command.
|
||||
#
|
||||
|
@ -99,6 +95,9 @@ class Action(JailThread):
|
|||
def getActionBan(self):
|
||||
return self.actionBan
|
||||
|
||||
def execActionBan(self, aInfo):
|
||||
return self.executeCmd(self.actionBan, aInfo);
|
||||
|
||||
##
|
||||
# Set the "unban" command.
|
||||
#
|
||||
|
@ -116,6 +115,9 @@ class Action(JailThread):
|
|||
def getActionUnban(self):
|
||||
return self.actionUnban
|
||||
|
||||
def execActionUnban(self, aInfo):
|
||||
return self.executeCmd(self.actionUnban, aInfo);
|
||||
|
||||
##
|
||||
# Set the "check" command.
|
||||
#
|
||||
|
@ -133,6 +135,9 @@ class Action(JailThread):
|
|||
def getActionCheck(self):
|
||||
return self.actionCheck
|
||||
|
||||
def execActionCheck(self, aInfo):
|
||||
return self.executeCmd(self.actionCheck, aInfo);
|
||||
|
||||
##
|
||||
# Set the "stop" command.
|
||||
#
|
||||
|
@ -150,104 +155,8 @@ class Action(JailThread):
|
|||
def getActionStop(self):
|
||||
return self.actionStop
|
||||
|
||||
##
|
||||
# Set the ban time.
|
||||
#
|
||||
# @param value the time
|
||||
|
||||
def setBanTime(self, value):
|
||||
self.banManager.setBanTime(value)
|
||||
logSys.info("Set banTime = %s" % value)
|
||||
|
||||
##
|
||||
# Get the ban time.
|
||||
#
|
||||
# @return the time
|
||||
|
||||
def getBanTime(self):
|
||||
return self.banManager.getBanTime()
|
||||
|
||||
##
|
||||
# Main loop.
|
||||
#
|
||||
# This function is the main loop of the thread. It checks the Jail
|
||||
# queue and executes commands when an IP address is banned.
|
||||
# @return True when the thread exits nicely
|
||||
|
||||
def run(self):
|
||||
self.executeCmd(self.actionStart)
|
||||
self.setActive(True)
|
||||
while self.isActive():
|
||||
if not self.isIdle:
|
||||
#logSys.debug(self.jail.getName() + ": action")
|
||||
ret = self.checkBan()
|
||||
if not ret:
|
||||
self.checkUnBan()
|
||||
time.sleep(self.sleepTime)
|
||||
else:
|
||||
time.sleep(self.sleepTime)
|
||||
self.flushBan()
|
||||
self.executeCmd(self.actionStop)
|
||||
logSys.debug(self.jail.getName() + ": action terminated")
|
||||
return True
|
||||
|
||||
##
|
||||
# Check for IP address to ban.
|
||||
#
|
||||
# Look in the Jail queue for FailTicket. If a ticket is available,
|
||||
# it executes the "ban" command and add a ticket to the BanManager.
|
||||
# @return True if an IP address get banned
|
||||
|
||||
def checkBan(self):
|
||||
logSys.debug("Check for IP address to ban")
|
||||
ticket = self.jail.getFailTicket()
|
||||
if ticket != False:
|
||||
aInfo = dict()
|
||||
bTicket = BanManager.createBanTicket(ticket)
|
||||
aInfo["ip"] = bTicket.getIP()
|
||||
logSys.info("Ban %s" % aInfo["ip"])
|
||||
self.executeCmd(self.replaceTag(self.actionBan, aInfo))
|
||||
self.banManager.addBanTicket(bTicket)
|
||||
return True
|
||||
return False
|
||||
|
||||
##
|
||||
# Check for IP address to unban.
|
||||
#
|
||||
# Unban IP address which are outdated.
|
||||
|
||||
def checkUnBan(self):
|
||||
logSys.debug("Check for IP address to unban")
|
||||
for ticket in self.banManager.unBanList(time.time()):
|
||||
aInfo = dict()
|
||||
aInfo["ip"] = ticket.getIP()
|
||||
logSys.info("Unban %s" % aInfo["ip"])
|
||||
self.executeCmd(self.replaceTag(self.actionUnban, aInfo))
|
||||
|
||||
##
|
||||
# Flush the ban list.
|
||||
#
|
||||
# Unban all IP address which are still in the banning list.
|
||||
|
||||
def flushBan(self):
|
||||
logSys.debug("Flush ban list")
|
||||
for ticket in self.banManager.flushBanList():
|
||||
aInfo = dict()
|
||||
aInfo["ip"] = ticket.getIP()
|
||||
logSys.info("Unban %s" % aInfo["ip"])
|
||||
self.executeCmd(self.replaceTag(self.actionUnban, aInfo))
|
||||
|
||||
##
|
||||
# Get the status of the filter.
|
||||
#
|
||||
# Get some informations about the filter state such as the total
|
||||
# number of failures.
|
||||
# @return a list with tuple
|
||||
|
||||
def status(self):
|
||||
ret = [("Currently banned", self.banManager.size()),
|
||||
("Total banned", self.banManager.getBanTotal())]
|
||||
return ret
|
||||
def execActionStop(self, aInfo):
|
||||
return self.executeCmd(self.actionStop, aInfo);
|
||||
|
||||
@staticmethod
|
||||
def replaceTag(query, aInfo):
|
||||
|
@ -261,21 +170,26 @@ class Action(JailThread):
|
|||
return string
|
||||
|
||||
@staticmethod
|
||||
def executeCmd(cmd):
|
||||
def executeCmd(cmd, aInfo = None):
|
||||
""" Executes an OS command.
|
||||
"""
|
||||
if cmd == "":
|
||||
logSys.debug("Nothing to do")
|
||||
return True
|
||||
|
||||
logSys.debug(cmd)
|
||||
retval = os.system(cmd)
|
||||
# Replace tags
|
||||
if not aInfo == None:
|
||||
realCmd = Action.replaceTag(cmd, aInfo)
|
||||
else:
|
||||
realCmd = cmd
|
||||
|
||||
logSys.debug(realCmd)
|
||||
retval = os.system(realCmd)
|
||||
#if not retval == 0:
|
||||
# logSys.error("'" + cmd + "' returned " + `retval`)
|
||||
# raise Exception("Execution of command '%s' failed" % cmd)
|
||||
if retval == 0:
|
||||
return True
|
||||
else:
|
||||
logSys.error("%s returned %x" % (cmd, retval))
|
||||
return False
|
||||
|
||||
logSys.error("%s returned %x" % (realCmd, retval))
|
||||
return False
|
|
@ -0,0 +1,183 @@
|
|||
# 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"
|
||||
|
||||
from banmanager import BanManager
|
||||
from failmanager import FailManager, FailManagerEmpty
|
||||
from jailthread import JailThread
|
||||
from action import Action
|
||||
import time, logging, os
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger("fail2ban.actions")
|
||||
|
||||
##
|
||||
# Execute commands.
|
||||
#
|
||||
# This class reads the failures from the Jail queue and decide if an
|
||||
# action has to be taken. A BanManager take care of the banned IP
|
||||
# addresses.
|
||||
|
||||
class Actions(JailThread):
|
||||
|
||||
##
|
||||
# Constructor.
|
||||
#
|
||||
# Initialize the filter object with default values.
|
||||
# @param jail the jail object
|
||||
|
||||
def __init__(self, jail):
|
||||
JailThread.__init__(self, jail)
|
||||
## The jail which contains this action.
|
||||
self.jail = jail
|
||||
self.actions = list()
|
||||
## The ban manager.
|
||||
self.banManager = BanManager()
|
||||
|
||||
def addAction(self, name):
|
||||
action = Action(name)
|
||||
self.actions.append(action)
|
||||
|
||||
def delAction(self, name):
|
||||
for action in self.actions:
|
||||
if action.getName() == name:
|
||||
self.actions.remove(action)
|
||||
break
|
||||
|
||||
def getAction(self, name):
|
||||
for action in self.actions:
|
||||
if action.getName() == name:
|
||||
return action
|
||||
raise KeyError
|
||||
|
||||
def getLastAction(self):
|
||||
action = self.actions.pop()
|
||||
self.actions.append(action)
|
||||
return action
|
||||
|
||||
##
|
||||
# Set the ban time.
|
||||
#
|
||||
# @param value the time
|
||||
|
||||
def setBanTime(self, value):
|
||||
self.banManager.setBanTime(value)
|
||||
logSys.info("Set banTime = %s" % value)
|
||||
|
||||
##
|
||||
# Get the ban time.
|
||||
#
|
||||
# @return the time
|
||||
|
||||
def getBanTime(self):
|
||||
return self.banManager.getBanTime()
|
||||
|
||||
##
|
||||
# Main loop.
|
||||
#
|
||||
# This function is the main loop of the thread. It checks the Jail
|
||||
# queue and executes commands when an IP address is banned.
|
||||
# @return True when the thread exits nicely
|
||||
|
||||
def run(self):
|
||||
for action in self.actions:
|
||||
action.execActionStart(None)
|
||||
self.setActive(True)
|
||||
while self.isActive():
|
||||
if not self.isIdle:
|
||||
#logSys.debug(self.jail.getName() + ": action")
|
||||
ret = self.checkBan()
|
||||
if not ret:
|
||||
self.checkUnBan()
|
||||
time.sleep(self.sleepTime)
|
||||
else:
|
||||
time.sleep(self.sleepTime)
|
||||
self.flushBan()
|
||||
for action in self.actions:
|
||||
action.execActionStop(None)
|
||||
logSys.debug(self.jail.getName() + ": action terminated")
|
||||
return True
|
||||
|
||||
##
|
||||
# Check for IP address to ban.
|
||||
#
|
||||
# Look in the Jail queue for FailTicket. If a ticket is available,
|
||||
# it executes the "ban" command and add a ticket to the BanManager.
|
||||
# @return True if an IP address get banned
|
||||
|
||||
def checkBan(self):
|
||||
logSys.debug("Check for IP address to ban")
|
||||
ticket = self.jail.getFailTicket()
|
||||
if ticket != False:
|
||||
aInfo = dict()
|
||||
bTicket = BanManager.createBanTicket(ticket)
|
||||
aInfo["ip"] = bTicket.getIP()
|
||||
logSys.info("Ban %s" % aInfo["ip"])
|
||||
for action in self.actions:
|
||||
action.execActionBan(aInfo)
|
||||
self.banManager.addBanTicket(bTicket)
|
||||
return True
|
||||
return False
|
||||
|
||||
##
|
||||
# Check for IP address to unban.
|
||||
#
|
||||
# Unban IP address which are outdated.
|
||||
|
||||
def checkUnBan(self):
|
||||
logSys.debug("Check for IP address to unban")
|
||||
for ticket in self.banManager.unBanList(time.time()):
|
||||
aInfo = dict()
|
||||
aInfo["ip"] = ticket.getIP()
|
||||
logSys.info("Unban %s" % aInfo["ip"])
|
||||
for action in self.actions:
|
||||
action.execActionUnban(aInfo)
|
||||
|
||||
##
|
||||
# Flush the ban list.
|
||||
#
|
||||
# Unban all IP address which are still in the banning list.
|
||||
|
||||
def flushBan(self):
|
||||
logSys.debug("Flush ban list")
|
||||
for ticket in self.banManager.flushBanList():
|
||||
aInfo = dict()
|
||||
aInfo["ip"] = ticket.getIP()
|
||||
logSys.info("Unban %s" % aInfo["ip"])
|
||||
for action in self.actions:
|
||||
action.execActionUnban(aInfo)
|
||||
|
||||
##
|
||||
# Get the status of the filter.
|
||||
#
|
||||
# Get some informations about the filter state such as the total
|
||||
# number of failures.
|
||||
# @return a list with tuple
|
||||
|
||||
def status(self):
|
||||
ret = [("Currently banned", self.banManager.size()),
|
||||
("Total banned", self.banManager.getBanTotal())]
|
||||
return ret
|
||||
|
|
@ -24,7 +24,7 @@ __date__ = "$Date: 2004/10/10 13:33:40 $"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
from action import Action
|
||||
from actions import Actions
|
||||
from filter import Filter
|
||||
import Queue
|
||||
|
||||
|
@ -35,7 +35,7 @@ class Jail:
|
|||
self.name = name
|
||||
self.queue = Queue.Queue()
|
||||
self.filter = Filter(self)
|
||||
self.action = Action(self)
|
||||
self.action = Actions(self)
|
||||
|
||||
def setName(self, name):
|
||||
self.name = name
|
||||
|
|
|
@ -162,7 +162,25 @@ class Server:
|
|||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
# Action
|
||||
# Action
|
||||
def addAction(self, name, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().addAction(value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def getLastAction(self, name):
|
||||
if self.jails.has_key(name):
|
||||
return self.jails[name].getAction().getLastAction()
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def delAction(self, name, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().delAction(value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setBanTime(self, name, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().setBanTime(value)
|
||||
|
@ -175,63 +193,63 @@ class Server:
|
|||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setActionStart(self, name, value):
|
||||
def setActionStart(self, name, action, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().setActionStart(value)
|
||||
self.jails[name].getAction().getAction(action).setActionStart(value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def getActionStart(self, name):
|
||||
def getActionStart(self, name, action):
|
||||
if self.jails.has_key(name):
|
||||
return self.jails[name].getAction().getActionStart()
|
||||
return self.jails[name].getAction().getAction(action).getActionStart()
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setActionStop(self, name, value):
|
||||
def setActionStop(self, name, action, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().setActionStop(value)
|
||||
self.jails[name].getAction().getAction(action).setActionStop(value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def getActionStop(self, name):
|
||||
def getActionStop(self, name, action):
|
||||
if self.jails.has_key(name):
|
||||
return self.jails[name].getAction().getActionStop()
|
||||
return self.jails[name].getAction().getAction(action).getActionStop()
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setActionCheck(self, name, value):
|
||||
def setActionCheck(self, name, action, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().setActionCheck(value)
|
||||
self.jails[name].getAction().getAction(action).setActionCheck(value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def getActionCheck(self, name):
|
||||
def getActionCheck(self, name, action):
|
||||
if self.jails.has_key(name):
|
||||
return self.jails[name].getAction().getActionCheck()
|
||||
return self.jails[name].getAction().getAction(action).getActionCheck()
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setActionBan(self, name, value):
|
||||
def setActionBan(self, name, action, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().setActionBan(value)
|
||||
self.jails[name].getAction().getAction(action).setActionBan(value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def getActionBan(self, name):
|
||||
def getActionBan(self, name, action):
|
||||
if self.jails.has_key(name):
|
||||
return self.jails[name].getAction().getActionBan()
|
||||
return self.jails[name].getAction().getAction(action).getActionBan()
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setActionUnban(self, name, value):
|
||||
def setActionUnban(self, name, action, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().setActionUnban(value)
|
||||
self.jails[name].getAction().getAction(action).setActionUnban(value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def getActionUnban(self, name):
|
||||
def getActionUnban(self, name, action):
|
||||
if self.jails.has_key(name):
|
||||
return self.jails[name].getAction().getActionUnban()
|
||||
return self.jails[name].getAction().getAction(action).getActionUnban()
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ class Transmitter:
|
|||
self.server.setLogLevel(value)
|
||||
return self.server.getLogLevel()
|
||||
# Jail
|
||||
if action[1] == "idle":
|
||||
elif action[1] == "idle":
|
||||
if action[2] == "on":
|
||||
self.server.setIdleJail(name, True)
|
||||
elif action[2] == "off":
|
||||
|
@ -140,26 +140,38 @@ class Transmitter:
|
|||
value = action[2]
|
||||
self.server.setBanTime(name, int(value))
|
||||
return self.server.getBanTime(name)
|
||||
elif action[1] == "addaction":
|
||||
value = action[2]
|
||||
self.server.addAction(name, value)
|
||||
return self.server.getLastAction(name).getName()
|
||||
elif action[1] == "delaction":
|
||||
self.server.delAction(name, value)
|
||||
return None
|
||||
elif action[1] == "actionstart":
|
||||
value = action[2]
|
||||
self.server.setActionStart(name, value)
|
||||
return self.server.getActionStart(name)
|
||||
act = action[2]
|
||||
value = action[3]
|
||||
self.server.setActionStart(name, act, value)
|
||||
return self.server.getActionStart(name, act)
|
||||
elif action[1] == "actionstop":
|
||||
value = action[2]
|
||||
self.server.setActionStop(name, value)
|
||||
return self.server.getActionStop(name)
|
||||
act = action[2]
|
||||
value = action[3]
|
||||
self.server.setActionStop(name, act, value)
|
||||
return self.server.getActionStop(name, act)
|
||||
elif action[1] == "actioncheck":
|
||||
value = action[2]
|
||||
self.server.setActionCheck(name, value)
|
||||
return self.server.getActionCheck(name)
|
||||
act = action[2]
|
||||
value = action[3]
|
||||
self.server.setActionCheck(name, act, value)
|
||||
return self.server.getActionCheck(name, act)
|
||||
elif action[1] == "actionban":
|
||||
value = action[2]
|
||||
self.server.setActionBan(name, value)
|
||||
return self.server.getActionBan(name)
|
||||
act = action[2]
|
||||
value = action[3]
|
||||
self.server.setActionBan(name, act, value)
|
||||
return self.server.getActionBan(name, act)
|
||||
elif action[1] == "actionunban":
|
||||
value = action[2]
|
||||
self.server.setActionUnban(name, value)
|
||||
return self.server.getActionUnban(name)
|
||||
act = action[2]
|
||||
value = action[3]
|
||||
self.server.setActionUnban(name, act, value)
|
||||
return self.server.getActionUnban(name, act)
|
||||
raise Exception("Invalid command (no set action)")
|
||||
|
||||
def actionGet(self, action):
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[install]
|
||||
install-purelib=/usr/lib/fail2ban
|
||||
|
||||
[sdist]
|
||||
formats=bztar
|
|
@ -0,0 +1,84 @@
|
|||
#!/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.6 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 1.6 $"
|
||||
__date__ = "$Date: 2006/01/22 11:08:42 $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
from distutils.core import setup
|
||||
from version import version
|
||||
from os.path import isfile, join
|
||||
from sys import exit, argv
|
||||
|
||||
longdesc = '''
|
||||
Fail2Ban scans log files like /var/log/pwdfail or
|
||||
/var/log/apache/error_log and bans IP that makes
|
||||
too many password failures. It updates firewall rules
|
||||
to reject the IP address or executes user defined
|
||||
commands.'''
|
||||
|
||||
setup(
|
||||
name = "fail2ban",
|
||||
version = version,
|
||||
description = "Ban IPs that make too many password failure",
|
||||
long_description = longdesc,
|
||||
author = "Cyril Jaquier",
|
||||
author_email = "lostcontrol@users.sourceforge.net",
|
||||
url = "http://fail2ban.sourceforge.net",
|
||||
license = "GPL",
|
||||
platforms = "Posix",
|
||||
scripts = ['fail2ban-client', 'fail2ban-server',
|
||||
'fail2ban-testcases'],
|
||||
py_modules = ['version'],
|
||||
packages = ['client', 'server', 'testcases', 'utils']
|
||||
)
|
||||
|
||||
# Do some checks after installation
|
||||
# Search for obsolete files.
|
||||
obsoleteFiles = []
|
||||
elements = {"/etc/": ["fail2ban.conf"],
|
||||
"/usr/bin/": ["fail2ban.py"],
|
||||
"/usr/lib/fail2ban/firewall/": ["iptables.py", "ipfwadm.py",
|
||||
"ipfw.py"]}
|
||||
for dir in elements:
|
||||
for f in elements[dir]:
|
||||
path = join(dir, f)
|
||||
if isfile(path):
|
||||
obsoleteFiles.append(path)
|
||||
if obsoleteFiles:
|
||||
print
|
||||
print "Obsolete files from previous Fail2Ban versions were found on " \
|
||||
"your system."
|
||||
print "Please delete them:"
|
||||
print
|
||||
for f in obsoleteFiles:
|
||||
print "\t" + f
|
||||
print
|
||||
|
||||
# Update config file
|
||||
if argv[1] == "install":
|
||||
print
|
||||
print "Please do not forget to update your configuration files."
|
||||
print "Use config/ as an example."
|
||||
print
|
|
@ -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.15.2.1 $
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision: 1.15.2.1 $"
|
||||
__date__ = "$Date: 2006/03/19 18:35:21 $"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
version = "0.7.0-SVN"
|
Loading…
Reference in New Issue