mirror of https://github.com/fail2ban/fail2ban
- Lot of changes. Most of them are cleanup
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@122 a942ae1a-1317-0410-a47c-b1dcaea8d6050.5
parent
e98f8c8182
commit
5595ffcac7
266
fail2ban.py
266
fail2ban.py
|
@ -1,5 +1,3 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# This file is part of Fail2Ban.
|
# This file is part of Fail2Ban.
|
||||||
#
|
#
|
||||||
# Fail2Ban is free software; you can redistribute it and/or modify
|
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||||
|
@ -26,19 +24,9 @@ __date__ = "$Date$"
|
||||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
import time, sys, getopt, os, string, signal
|
import time, sys, getopt, os, string, signal, log4py
|
||||||
from ConfigParser import *
|
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.firewall import Firewall
|
from firewall.firewall import Firewall
|
||||||
from logreader.logreader import LogReader
|
from logreader.logreader import LogReader
|
||||||
from confreader.configreader import ConfigReader
|
from confreader.configreader import ConfigReader
|
||||||
|
@ -48,15 +36,18 @@ from version import version
|
||||||
# Gets the instance of log4py.
|
# Gets the instance of log4py.
|
||||||
logSys = log4py.Logger().get_instance()
|
logSys = log4py.Logger().get_instance()
|
||||||
|
|
||||||
|
# Global variables
|
||||||
|
logFwList = list()
|
||||||
|
conf = dict()
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
print "Usage: fail2ban.py [OPTIONS]"
|
print "Usage: fail2ban [OPTIONS]"
|
||||||
print
|
print
|
||||||
print "Fail2Ban v"+version+" 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 address using iptables."
|
print "and bans the corresponding IP address using iptables."
|
||||||
print
|
print
|
||||||
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 " -c <FILE> read configuration file FILE"
|
print " -c <FILE> read configuration file FILE"
|
||||||
print " -p <FILE> create PID lock in FILE"
|
print " -p <FILE> create PID lock in FILE"
|
||||||
print " -h display this help message"
|
print " -h display this help message"
|
||||||
|
@ -66,8 +57,6 @@ def usage():
|
||||||
print " -r <VALUE> allow a max of VALUE password failure"
|
print " -r <VALUE> allow a max of VALUE password failure"
|
||||||
print " -t <TIME> ban IP for TIME seconds"
|
print " -t <TIME> ban IP for TIME seconds"
|
||||||
print " -v verbose. Use twice for greater effect"
|
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
|
||||||
print "Report bugs to <lostcontrol@users.sourceforge.net>"
|
print "Report bugs to <lostcontrol@users.sourceforge.net>"
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
@ -95,156 +84,20 @@ def killApp():
|
||||||
logSys.warn("Restoring firewall rules...")
|
logSys.warn("Restoring firewall rules...")
|
||||||
for element in logFwList:
|
for element in logFwList:
|
||||||
element[2].flushBanList(conf["debug"])
|
element[2].flushBanList(conf["debug"])
|
||||||
|
# Execute end command of each section
|
||||||
|
for element in logFwList:
|
||||||
|
l = element[4]
|
||||||
|
executeCmd(l["fwend"], conf["debug"])
|
||||||
|
# Execute global start command
|
||||||
|
executeCmd(conf["cmdend"], conf["debug"])
|
||||||
|
# Remove the PID lock
|
||||||
removePID(conf["pidlock"])
|
removePID(conf["pidlock"])
|
||||||
logSys.info("Exiting...")
|
logSys.info("Exiting...")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def getCmdLineOptions(optList):
|
||||||
|
""" Gets the command line options
|
||||||
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:
|
for opt in optList:
|
||||||
if opt[0] == "-h":
|
if opt[0] == "-h":
|
||||||
usage()
|
usage()
|
||||||
|
@ -254,8 +107,6 @@ if __name__ == "__main__":
|
||||||
conf["background"] = True
|
conf["background"] = True
|
||||||
if opt[0] == "-d":
|
if opt[0] == "-d":
|
||||||
conf["debug"] = True
|
conf["debug"] = True
|
||||||
if opt[0] == "-e":
|
|
||||||
conf["interface"] = opt[1]
|
|
||||||
if opt[0] == "-l":
|
if opt[0] == "-l":
|
||||||
conf["logging"] = True
|
conf["logging"] = True
|
||||||
conf["logfile"] = opt[1]
|
conf["logfile"] = opt[1]
|
||||||
|
@ -269,8 +120,6 @@ if __name__ == "__main__":
|
||||||
conf["ignoreip"] = opt[1]
|
conf["ignoreip"] = opt[1]
|
||||||
if opt[0] == "-r":
|
if opt[0] == "-r":
|
||||||
conf["retrymax"] = int(opt[1])
|
conf["retrymax"] = int(opt[1])
|
||||||
if opt[0] == "-w":
|
|
||||||
conf["firewall"] = opt[1]
|
|
||||||
if opt[0] == "-p":
|
if opt[0] == "-p":
|
||||||
conf["pidlock"] = opt[1]
|
conf["pidlock"] = opt[1]
|
||||||
if opt[0] == "-k":
|
if opt[0] == "-k":
|
||||||
|
@ -283,6 +132,49 @@ if __name__ == "__main__":
|
||||||
logSys.error("No running Fail2Ban found")
|
logSys.error("No running Fail2Ban found")
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Fail2Ban main function
|
||||||
|
"""
|
||||||
|
logSys.set_formatstring("%T %L %M")
|
||||||
|
|
||||||
|
conf["verbose"] = 0
|
||||||
|
conf["conffile"] = "/etc/fail2ban.conf"
|
||||||
|
conf["logging"] = False
|
||||||
|
|
||||||
|
# Reads the command line options.
|
||||||
|
try:
|
||||||
|
optList, args = getopt.getopt(sys.argv[1:], 'hvbdkc:l:t:i:r: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]
|
||||||
|
|
||||||
|
# Reads the config file and create a LogReader instance for
|
||||||
|
# each log file to check.
|
||||||
|
confReader = ConfigReader(conf["conffile"]);
|
||||||
|
confReader.openConf()
|
||||||
|
|
||||||
|
# Options
|
||||||
|
optionValues = (["bool", "background", False],
|
||||||
|
["bool", "debug", False],
|
||||||
|
["str", "logfile", "/var/log/fail2ban.log"],
|
||||||
|
["str", "pidlock", "/var/run/fail2ban.pid"],
|
||||||
|
["int", "maxretry", 3],
|
||||||
|
["int", "bantime", 600],
|
||||||
|
["str", "ignoreip", ""],
|
||||||
|
["int", "polltime", 1],
|
||||||
|
["str", "cmdstart", ""],
|
||||||
|
["str", "cmdend", ""])
|
||||||
|
|
||||||
|
# Gets global configuration options
|
||||||
|
conf.update(confReader.getLogOptions("DEFAULT", optionValues))
|
||||||
|
|
||||||
|
# Gets command line options
|
||||||
|
getCmdLineOptions(optList)
|
||||||
|
|
||||||
# Process some options
|
# Process some options
|
||||||
for c in conf:
|
for c in conf:
|
||||||
if c == "verbose":
|
if c == "verbose":
|
||||||
|
@ -310,14 +202,6 @@ if __name__ == "__main__":
|
||||||
logSys.warn("Using default output for logging")
|
logSys.warn("Using default output for logging")
|
||||||
elif c == "ignoreip":
|
elif c == "ignoreip":
|
||||||
ignoreIPList = conf[c].split(' ')
|
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
|
# Checks for root user. This is necessary because log files
|
||||||
# are owned by root and firewall needs root access.
|
# are owned by root and firewall needs root access.
|
||||||
|
@ -338,23 +222,29 @@ if __name__ == "__main__":
|
||||||
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
|
# Options
|
||||||
# each log file to check.
|
optionValues = (["bool", "enabled", True],
|
||||||
confReader = ConfigReader(conf["conffile"]);
|
["str", "logfile", "/dev/null"],
|
||||||
confReader.openConf()
|
["str", "timeregex", ""],
|
||||||
logFwList = list()
|
["str", "timepattern", ""],
|
||||||
|
["str", "failregex", ""],
|
||||||
|
["str", "fwstart", ""],
|
||||||
|
["str", "fwend", ""],
|
||||||
|
["str", "fwban", ""],
|
||||||
|
["str", "fwunban", ""])
|
||||||
|
|
||||||
|
# Gets the options of each sections
|
||||||
for t in confReader.getSections():
|
for t in confReader.getSections():
|
||||||
l = confReader.getLogOptions(t)
|
l = confReader.getLogOptions(t, optionValues)
|
||||||
if l["enabled"]:
|
if l["enabled"]:
|
||||||
# Creates a logreader object
|
# Creates a logreader object
|
||||||
lObj = LogReader(l["logfile"], l["timeregex"], l["timepattern"],
|
lObj = LogReader(l["logfile"], l["timeregex"], l["timepattern"],
|
||||||
l["failregex"], conf["bantime"])
|
l["failregex"], conf["bantime"])
|
||||||
# Creates a firewall object
|
# Creates a firewall object
|
||||||
fObj = Firewall(l["fwbanrule"], l["fwunbanrule"], conf["bantime"],
|
fObj = Firewall(l["fwban"], l["fwunban"], conf["bantime"])
|
||||||
conf["interface"])
|
|
||||||
# Links them into a list. I'm not really happy
|
# Links them into a list. I'm not really happy
|
||||||
# with this :/
|
# with this :/
|
||||||
logFwList.append([t, lObj, fObj, dict()])
|
logFwList.append([t, lObj, fObj, dict(), l])
|
||||||
|
|
||||||
# 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.
|
||||||
|
@ -366,6 +256,12 @@ if __name__ == "__main__":
|
||||||
element[1].addIgnoreIP(ip)
|
element[1].addIgnoreIP(ip)
|
||||||
|
|
||||||
logSys.info("Fail2Ban v"+version+" is running")
|
logSys.info("Fail2Ban v"+version+" is running")
|
||||||
|
# Execute global start command
|
||||||
|
executeCmd(conf["cmdstart"], conf["debug"])
|
||||||
|
# Execute start command of each section
|
||||||
|
for element in logFwList:
|
||||||
|
l = element[4]
|
||||||
|
executeCmd(l["fwstart"], conf["debug"])
|
||||||
# Main loop
|
# Main loop
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
@ -409,7 +305,7 @@ if __name__ == "__main__":
|
||||||
findTime = element[1].getFindTime()
|
findTime = element[1].getFindTime()
|
||||||
for attempt in fails:
|
for attempt in fails:
|
||||||
failTime = fails[attempt][1]
|
failTime = fails[attempt][1]
|
||||||
if failTime < unixTime - failTime:
|
if failTime < unixTime - findTime:
|
||||||
del element[3][attempt]
|
del element[3][attempt]
|
||||||
elif fails[attempt][0] >= conf["maxretry"]:
|
elif fails[attempt][0] >= conf["maxretry"]:
|
||||||
logSys.info(element[0] + ": " + attempt + " has " +
|
logSys.info(element[0] + ": " + attempt + " has " +
|
||||||
|
|
Loading…
Reference in New Issue