Repository: fail2ban/fail2ban

Issue:
Log cause of Ignore
INFO logs occur if IP is in ignoreip or ignorecommand returns false (and presumably ignoreregex matches), but the log only says "Ignore <ip>". I think the cause of the IP being ignored is also valuable.



Discussion:

Resolving patch:
diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py
--- a/fail2ban/server/filter.py
+++ b/fail2ban/server/filter.py
@@ -338,6 +338,10 @@ def delIgnoreIP(self, ip):
 		logSys.debug("Remove " + ip + " from ignore list")
 		self.__ignoreIpList.remove(ip)
 
+	def logIgnoreIp(self, ip, log_ignore, ignore_source="unknown source"):
+		if log_ignore:
+			logSys.info("[%s] Ignore %s by %s" % (self.jail.name, ip, ignore_source))
+
 	def getIgnoreIP(self):
 		return self.__ignoreIpList
 
@@ -349,7 +353,7 @@ def getIgnoreIP(self):
 	# @param ip IP address
 	# @return True if IP address is in ignore list
 
-	def inIgnoreIPList(self, ip):
+	def inIgnoreIPList(self, ip, log_ignore=False):
 		for i in self.__ignoreIpList:
 			# An empty string is always false
 			if i == "":
@@ -369,16 +373,20 @@ def inIgnoreIPList(self, ip):
 				# Check if IP in DNS
 				ips = DNSUtils.dnsToIp(i)
 				if ip in ips:
+					self.logIgnoreIp(ip, log_ignore, ignore_source="dns")
 					return True
 				else:
 					continue
 			if a == b:
+				self.logIgnoreIp(ip, log_ignore, ignore_source="ip")
 				return True
 
 		if self.__ignoreCommand:
 			command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip } )
 			logSys.debug('ignore command: ' + command)
-			return CommandAction.executeCmd(command)
+			ret_ignore = CommandAction.executeCmd(command)
+			self.logIgnoreIp(ip, log_ignore and ret_ignore, ignore_source="command")
+			return ret_ignore
 
 		return False
 
@@ -418,8 +426,7 @@ def processLineAndAdd(self, line, date=None):
 				logSys.debug("Ignore line since time %s < %s - %s"
 							 % (unixTime, MyTime.time(), self.getFindTime()))
 				break
-			if self.inIgnoreIPList(ip):
-				logSys.info("[%s] Ignore %s" % (self.jail.name, ip))
+			if self.inIgnoreIPList(ip, log_ignore=True):
 				continue
 			logSys.info("[%s] Found %s" % (self.jail.name, ip))
 			## print "D: Adding a ticket for %s" % ((ip, unixTime, [line]),)
diff --git a/fail2ban/server/jail.py b/fail2ban/server/jail.py
--- a/fail2ban/server/jail.py
+++ b/fail2ban/server/jail.py
@@ -213,7 +213,7 @@ def start(self):
 		if self.database is not None:
 			for ticket in self.database.getBansMerged(
 				jail=self, bantime=self.actions.getBanTime()):
-				if not self.filter.inIgnoreIPList(ticket.getIP()):
+				if not self.filter.inIgnoreIPList(ticket.getIP(), log_ignore=True):
 					self.__queue.put(ticket)
 		logSys.info("Jail '%s' started" % self.name)
 


Test patch:
diff --git a/fail2ban/tests/filtertestcase.py b/fail2ban/tests/filtertestcase.py
--- a/fail2ban/tests/filtertestcase.py
+++ b/fail2ban/tests/filtertestcase.py
@@ -266,6 +266,15 @@ def testIgnoreCommand(self):
 		self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1"))
 		self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0"))
 
+	def testIgnoreCauseOK(self):
+		ip = "93.184.216.34"
+		for ignore_source in ["dns", "ip", "command"]:
+			self.filter.logIgnoreIp(ip, True, ignore_source=ignore_source)
+			self.assertTrue(self._is_logged("[%s] Ignore %s by %s" % (self.jail.name, ip, ignore_source)))
+
+	def testIgnoreCauseNOK(self):
+		self.filter.logIgnoreIp("example.com", False, ignore_source="NOT_LOGGED")
+		self.assertFalse(self._is_logged("[%s] Ignore %s by %s" % (self.jail.name, "example.com", "NOT_LOGGED")))
 
 class IgnoreIPDNS(IgnoreIP):