diff --git a/debian/changelog b/debian/changelog index d95b9ab1..b1915834 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -fail2ban (0.5.4-5.9) unstable; urgency=low +fail2ban (0.5.4-5.10) unstable; urgency=low * Added a notification regarding the importance of 0.5.4-5 change of failregex in the config file. @@ -14,6 +14,7 @@ fail2ban (0.5.4-5.9) unstable; urgency=low * Introduced fwcheck option to verify consistency of the chains. Implemented automatic restart of fail2ban main function in case if check of fwban or fwban command failed (closes: #329163, #331695). + (Introduced patch was further adjusted by upstream author) -- Yaroslav Halchenko Mon, 3 Oct 2005 22:26:28 -1000 diff --git a/fail2ban.py b/fail2ban.py index 63c60095..2d65070e 100755 --- a/fail2ban.py +++ b/fail2ban.py @@ -100,9 +100,7 @@ def initializeFwRules(): executeCmd(conf["cmdstart"], conf["debug"]) # Execute start command of each section for element in logFwList: - l = element[4] - executeCmd(l["fwstart"], conf["debug"]) - + element[2].initialize(conf["debug"]) def reBan(): """ For each section asks the Firewall to reban known IPs @@ -117,13 +115,12 @@ def restoreFwRules(): for element in logFwList: try: element[2].flushBanList(conf["debug"]) - except ExternalError, e: + except ExternalError: # nothing bad really - we can survive :-) pass # Execute end command of each section for element in logFwList: - l = element[4] - executeCmd(l["fwend"], conf["debug"]) + element[2].restore(conf["debug"]) # Execute global end command executeCmd(conf["cmdend"], conf["debug"]) @@ -220,6 +217,7 @@ def main(): ["int", "reinittime", 100], ["int", "maxreinits", 100]) + # Gets global configuration options conf.update(confReader.getLogOptions("DEFAULT", optionValues)) @@ -398,7 +396,7 @@ def main(): fObj = Firewall(l["fwban"], l["fwunban"], l["fwcheck"], l["bantime"]) # Links them into a list. I'm not really happy # with this :/ - logFwList.append([t, lObj, fObj, dict(), l]) + logFwList.append([t, lObj, fObj, dict()]) logSys.info("Enabled sections: %s"%enabledSections) @@ -416,8 +414,8 @@ def main(): logSys.warn(ip + " is not a valid IP address") initializeFwRules() - - lastReinitTime = time.time()-conf["reinittime"]-1 # try to reinit once if it fails immediately + # try to reinit once if it fails immediately + lastReinitTime = time.time() - conf["reinittime"] - 1 reinits = 0 # Main loop while True: @@ -484,23 +482,28 @@ def main(): reinits += 1 logSys.error(e) if ((unixTime - lastReinitTime > conf["reinittime"]) and - ((conf["maxreinits"]<0) or (reinits < conf["maxreinits"]))): + ((conf["maxreinits"] < 0) or (reinits < conf["maxreinits"]))): logSys.warn("#%d reinitialization of firewalls"%reinits) lastReinitTime = unixTime else: - logSys.error("Exiting: reinits follow too often, or too many reinit attempts") + logSys.error("Exiting: reinits follow too often, or too many " + + "reinit attempts") killApp() - # save firewalls to keep a list of IPs for rebanning logFwListCopy = copy.deepcopy(logFwList) - # restore as much as possible - restoreFwRules() - # reinitialize all the chains - initializeFwRules() - # restore the lists of baned IPs - logFwList.__init__(logFwListCopy) - # reBan known IPs - reBan() + try: + # restore as much as possible + restoreFwRules() + # reinitialize all the chains + initializeFwRules() + # restore the lists of baned IPs + logFwList.__init__(logFwListCopy) + # reBan known IPs + reBan() + except ExternalError: + raise ExternalError("Big Oops happened: situation is out of " + + "control. Something is wrong with your " + + "setup. Please check your settings") except KeyboardInterrupt: # When the user press + we exit nicely. killApp() diff --git a/firewall/firewall.py b/firewall/firewall.py index c552bf3a..04aac6e1 100644 --- a/firewall/firewall.py +++ b/firewall/firewall.py @@ -28,7 +28,6 @@ import time, os, logging, re from utils.process import executeCmd from utils.strings import replaceTag -from utils.process import ExternalError # Gets the instance of the logger. logSys = logging.getLogger("fail2ban") @@ -42,23 +41,44 @@ class Firewall: self.banRule = banRule self.unBanRule = unBanRule self.checkRule = checkRule + self.startRule = "" + self.endRule = "" self.banTime = banTime self.banList = dict() + def setStartRule(self, cmd): + self.startRule = cmd + + def getStartRule(self): + return self.startRule + + def setEndRule(self, cmd): + self.endRule = cmd + + def getEndRule(self): + return self.endRule + + def initialize(self, debug): + logSys.debug("Initialize firewall rules") + executeCmd(self.startRule, debug) + + def restore(self, debug): + logSys.debug("Restore firewall rules") + executeCmd(self.endRule, debug) + def addBanIP(self, aInfo, debug): """ Bans an IP. """ ip = aInfo["ip"] - self.runCheck("pre-fwban", debug) if not self.inBanList(ip): crtTime = time.time() logSys.warn("Ban " + ip) self.banList[ip] = crtTime aInfo["bantime"] = crtTime - cmd = self.banIP(aInfo) - if executeCmd(cmd, debug): - raise ExternalError("Firewall: execution of fwban command '%s' failed"%cmd) + self.runCheck(debug) + executeCmd(self.banIP(aInfo), debug) else: + self.runCheck(debug) logSys.error(ip+" already in ban list") def delBanIP(self, aInfo, debug): @@ -66,37 +86,36 @@ class Firewall: """ ip = aInfo["ip"] if self.inBanList(ip): - logSys.warn("Unban "+ip) + logSys.warn("Unban " + ip) del self.banList[ip] - self.runCheck("pre-fwunban", debug) + self.runCheck(debug) executeCmd(self.unBanIP(aInfo), debug) else: logSys.error(ip+" not in ban list") def reBan(self, debug): """ Re-Bans known IPs. + TODO: implement "failures" and "failtime" """ for ip in self.banList: aInfo = {"ip": ip, - "bantime":self.banList[ip]} - logSys.warn("ReBan "+ip) + "bantime": self.banList[ip]} + logSys.warn("ReBan " + ip) # next piece is similar to the on in addBanIp # so might be one more function will not hurt - self.runCheck("pre-fw-reban", debug) - cmd = self.banIP(aInfo) - if executeCmd(cmd, debug): - raise ExternalError("Firewall: execution of fwban command '%s' failed"%cmd) + self.runCheck(debug) + executeCmd(self.banIP(aInfo), debug) def inBanList(self, ip): """ Checks if IP is in ban list. """ return self.banList.has_key(ip) - def runCheck(self, location, debug): - """ Runs fwcheck command and throws an exception if it returns non-0 result """ - if executeCmd(self.checkRule, debug): - raise ExternalError("Firewall: %s fwcheck command '%s' failed" - %(location,self.checkRule)) + def runCheck(self, debug): + """ Runs fwcheck command and throws an exception if it returns non-0 + result + """ + executeCmd(self.checkRule, debug) def checkForUnBan(self, debug): """ Check for IP to remove from ban list. diff --git a/utils/process.py b/utils/process.py index b36f5098..f8be076d 100644 --- a/utils/process.py +++ b/utils/process.py @@ -30,7 +30,8 @@ import os, logging, signal logSys = logging.getLogger("fail2ban") class ExternalError(UserWarning): - """ Exception to warn about failed fwcheck or fwban command """ + """ Exception to warn about failed command + """ pass def createDaemon(): @@ -130,6 +131,7 @@ def executeCmd(cmd, debug): retval = os.system(cmd) if not retval == 0: logSys.error("'" + cmd + "' returned " + `retval`) + raise ExternalError("Execution of command '%s' failed" % cmd) return retval else: return None