mirror of https://github.com/fail2ban/fail2ban
- Added PID lock file support
- Added log reader name support - Improve some algorithms - Changed some info messages to warn git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@60 a942ae1a-1317-0410-a47c-b1dcaea8d6050.6
parent
deffa8f5aa
commit
1711a87dff
75
fail2ban.py
75
fail2ban.py
|
@ -56,6 +56,7 @@ def usage():
|
||||||
print " -d start fail2ban in debug mode"
|
print " -d start fail2ban in debug mode"
|
||||||
print " -e <INTF> ban IP on the INTF interface"
|
print " -e <INTF> ban IP on the INTF interface"
|
||||||
print " -c <FILE> read configuration file FILE"
|
print " -c <FILE> read configuration file FILE"
|
||||||
|
print " -p <FILE> create PID lock in FILE"
|
||||||
print " -h display this help message"
|
print " -h display this help message"
|
||||||
print " -i <IP(s)> IP(s) to ignore"
|
print " -i <IP(s)> IP(s) to ignore"
|
||||||
print " -l <FILE> log message in FILE"
|
print " -l <FILE> log message in FILE"
|
||||||
|
@ -161,6 +162,30 @@ def sigTERMhandler(signum, frame):
|
||||||
fireWall.flushBanList(conf["debug"])
|
fireWall.flushBanList(conf["debug"])
|
||||||
logSys.info("Exiting...")
|
logSys.info("Exiting...")
|
||||||
sys.exit(0)
|
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:
|
||||||
|
fileHandler = open(lockfile, mode='w')
|
||||||
|
pid = os.getpid()
|
||||||
|
fileHandler.write(`pid`+'\n')
|
||||||
|
fileHandler.close()
|
||||||
|
logSys.debug("Created PID lock ("+`pid`+") in "+lockfile)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def removePID(lockfile):
|
||||||
|
""" Remove PID lock.
|
||||||
|
"""
|
||||||
|
os.remove(lockfile)
|
||||||
|
logSys.debug("Removed PID lock "+lockfile)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
@ -173,6 +198,7 @@ if __name__ == "__main__":
|
||||||
conf["background"] = False
|
conf["background"] = False
|
||||||
conf["debug"] = False
|
conf["debug"] = False
|
||||||
conf["conffile"] = "/etc/fail2ban.conf"
|
conf["conffile"] = "/etc/fail2ban.conf"
|
||||||
|
conf["pidlock"] = "/tmp/fail2ban.pid"
|
||||||
conf["logging"] = False
|
conf["logging"] = False
|
||||||
conf["logfile"] = "/var/log/fail2ban.log"
|
conf["logfile"] = "/var/log/fail2ban.log"
|
||||||
conf["maxretry"] = 3
|
conf["maxretry"] = 3
|
||||||
|
@ -184,7 +210,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Reads the command line options.
|
# Reads the command line options.
|
||||||
try:
|
try:
|
||||||
optList, args = getopt.getopt(sys.argv[1:], 'hvbdc:l:t:i:r:e:w:')
|
optList, args = getopt.getopt(sys.argv[1:], 'hvbdc:l:t:i:r:e:w:p:')
|
||||||
except getopt.GetoptError:
|
except getopt.GetoptError:
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
|
@ -227,6 +253,16 @@ if __name__ == "__main__":
|
||||||
logSys.warn("logfile option not in config file")
|
logSys.warn("logfile option not in config file")
|
||||||
logSys.warn("Using default value")
|
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
|
# maxretry
|
||||||
try:
|
try:
|
||||||
conf["maxretry"] = configParser.getint("DEFAULT", "maxretry")
|
conf["maxretry"] = configParser.getint("DEFAULT", "maxretry")
|
||||||
|
@ -313,6 +349,8 @@ if __name__ == "__main__":
|
||||||
conf["retrymax"] = int(opt[1])
|
conf["retrymax"] = int(opt[1])
|
||||||
if opt[0] == "-w":
|
if opt[0] == "-w":
|
||||||
conf["firewall"] = opt[1]
|
conf["firewall"] = opt[1]
|
||||||
|
if opt[0] == "-p":
|
||||||
|
conf["pidlock"] = opt[1]
|
||||||
|
|
||||||
# Process some options
|
# Process some options
|
||||||
for c in conf:
|
for c in conf:
|
||||||
|
@ -352,6 +390,12 @@ if __name__ == "__main__":
|
||||||
logSys.error("You must be root")
|
logSys.error("You must be root")
|
||||||
if not conf["debug"]:
|
if not conf["debug"]:
|
||||||
sys.exit(-1)
|
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)
|
||||||
|
|
||||||
logSys.debug("ConfFile is "+conf["conffile"])
|
logSys.debug("ConfFile is "+conf["conffile"])
|
||||||
logSys.debug("BanTime is "+`conf["bantime"]`)
|
logSys.debug("BanTime is "+`conf["bantime"]`)
|
||||||
|
@ -366,7 +410,7 @@ if __name__ == "__main__":
|
||||||
l = confReader.getLogOptions(t)
|
l = confReader.getLogOptions(t)
|
||||||
lObj = LogReader(logSys, l["logfile"], l["timeregex"],
|
lObj = LogReader(logSys, l["logfile"], l["timeregex"],
|
||||||
l["timepattern"], l["failregex"], conf["bantime"])
|
l["timepattern"], l["failregex"], conf["bantime"])
|
||||||
lObj.openLogFile()
|
lObj.setName(t)
|
||||||
logList.append(lObj)
|
logList.append(lObj)
|
||||||
|
|
||||||
# Creates one instance of Iptables (thanks to Pyhton dynamic
|
# Creates one instance of Iptables (thanks to Pyhton dynamic
|
||||||
|
@ -383,7 +427,7 @@ if __name__ == "__main__":
|
||||||
for element in logList:
|
for element in logList:
|
||||||
element.addIgnoreIP(ip)
|
element.addIgnoreIP(ip)
|
||||||
|
|
||||||
logSys.info("Fail2Ban v"+version+" is running")
|
logSys.warn("Fail2Ban v"+version+" is running")
|
||||||
# Main loop
|
# Main loop
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
@ -397,21 +441,31 @@ if __name__ == "__main__":
|
||||||
# If the log file has not been modified since the
|
# If the log file has not been modified since the
|
||||||
# last time, we sleep for 1 second. This is active
|
# last time, we sleep for 1 second. This is active
|
||||||
# polling so not very effective.
|
# polling so not very effective.
|
||||||
isModified = False
|
|
||||||
modList = list()
|
modList = list()
|
||||||
for element in logList:
|
for element in logList:
|
||||||
if element.isModified():
|
if element.isModified():
|
||||||
isModified = True
|
|
||||||
modList.append(element)
|
modList.append(element)
|
||||||
|
|
||||||
if not isModified:
|
if len(modList) == 0:
|
||||||
time.sleep(conf["polltime"])
|
time.sleep(conf["polltime"])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Gets the failure list from the log file.
|
# Gets the failure list from the log file. For a given IP,
|
||||||
|
# takes only the service which has the most password failures.
|
||||||
failList = dict()
|
failList = dict()
|
||||||
for element in modList:
|
for element in modList:
|
||||||
failList.update(element.getFailures())
|
e = element.getFailures()
|
||||||
|
iter = e.iterkeys()
|
||||||
|
for i in range(len(e)):
|
||||||
|
key = iter.next()
|
||||||
|
if failList.has_key(key):
|
||||||
|
if failList[key][0] < e[key][0]:
|
||||||
|
failList[key] = (e[key][0], e[key][1],
|
||||||
|
element.getName())
|
||||||
|
else:
|
||||||
|
failList[key] = (e[key][0], e[key][1],
|
||||||
|
element.getName())
|
||||||
|
|
||||||
|
|
||||||
# We iterate the failure list and ban IP that make
|
# We iterate the failure list and ban IP that make
|
||||||
# *retryAllowed* login failures.
|
# *retryAllowed* login failures.
|
||||||
|
@ -419,6 +473,8 @@ if __name__ == "__main__":
|
||||||
for i in range(len(failList)):
|
for i in range(len(failList)):
|
||||||
element = iterFailList.next()
|
element = iterFailList.next()
|
||||||
if element[1][0] >= conf["maxretry"]:
|
if element[1][0] >= conf["maxretry"]:
|
||||||
|
logSys.warn(`element[1][2]`+": "+element[0]+" has "+
|
||||||
|
`element[1][0]`+" login failure(s). Banned.")
|
||||||
fireWall.addBanIP(element[0], conf["debug"])
|
fireWall.addBanIP(element[0], conf["debug"])
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
@ -426,5 +482,6 @@ if __name__ == "__main__":
|
||||||
# and exit nicely.
|
# and exit nicely.
|
||||||
logSys.info("Restoring iptables...")
|
logSys.info("Restoring iptables...")
|
||||||
fireWall.flushBanList(conf["debug"])
|
fireWall.flushBanList(conf["debug"])
|
||||||
logSys.info("Exiting...")
|
removePID(conf["pidlock"])
|
||||||
|
logSys.warn("Exiting...")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
Loading…
Reference in New Issue