diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index b4612f8c..1db07ba1 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -42,6 +42,7 @@ from .banmanager import BanManager from .jailthread import JailThread from .action import ActionBase, CommandAction, CallingMap from .mytime import MyTime +from .filter import IPAddr from ..helpers import getLogger # Gets the instance of the logger. @@ -178,7 +179,7 @@ class Actions(JailThread, Mapping): def getBanTime(self): return self.__banManager.getBanTime() - def removeBannedIP(self, ip): + def removeBannedIP(self, ipstr): """Removes banned IP calling actions' unban method Remove a banned IP now, rather than waiting for it to expire, @@ -186,14 +187,16 @@ class Actions(JailThread, Mapping): Parameters ---------- - ip : str - The IP address to unban + ipstr : str + The IP address string to unban Raises ------ ValueError If `ip` is not banned """ + # Create new IPAddr object from IP string + ip = IPAddr(ipstr) # Always delete ip from database (also if currently not banned) if self._jail.database is not None: self._jail.database.delBan(self._jail, ip) diff --git a/fail2ban/server/banmanager.py b/fail2ban/server/banmanager.py index 662666b0..39d0321b 100644 --- a/fail2ban/server/banmanager.py +++ b/fail2ban/server/banmanager.py @@ -152,9 +152,9 @@ class BanManager: for banData in self.__banList: ip = banData.getIP() # Reference: http://www.team-cymru.org/Services/ip-to-asn.html#dns - # TODO: IPv6 compatibility - reversed_ip = ".".join(reversed(ip.split("."))) - question = "%s.origin.asn.cymru.com" % reversed_ip + question = ip.getPTR("origin.asn.cymru.com" if ip.isIPv4() + else "origin6.asn.cymru.com" + ) try: answers = dns.resolver.query(question, "TXT") for rdata in answers: diff --git a/fail2ban/server/database.py b/fail2ban/server/database.py index 7de87554..eda3ee24 100644 --- a/fail2ban/server/database.py +++ b/fail2ban/server/database.py @@ -32,6 +32,7 @@ from threading import RLock from .mytime import MyTime from .ticket import FailTicket +from .filter import IPAddr from ..helpers import getLogger # Gets the instance of the logger. @@ -413,7 +414,7 @@ class Fail2BanDb(object): #TODO: Implement data parts once arbitrary match keys completed cur.execute( "INSERT INTO bans(jail, ip, timeofban, data) VALUES(?, ?, ?, ?)", - (jail.name, ticket.getIP(), int(round(ticket.getTime())), + (jail.name, ticket.getIP().ntoa(), int(round(ticket.getTime())), {"matches": ticket.getMatches(), "failures": ticket.getAttempt()})) @@ -428,7 +429,7 @@ class Fail2BanDb(object): ip : str IP to be removed. """ - queryArgs = (jail.name, ip); + queryArgs = (jail.name, ip.ntoa()); cur.execute( "DELETE FROM bans WHERE jail = ? AND ip = ?", queryArgs); @@ -446,7 +447,7 @@ class Fail2BanDb(object): queryArgs.append(MyTime.time() - bantime) if ip is not None: query += " AND ip=?" - queryArgs.append(ip) + queryArgs.append(ip.ntoa()) query += " ORDER BY ip, timeofban" return cur.execute(query, queryArgs) @@ -462,7 +463,7 @@ class Fail2BanDb(object): Ban time in seconds, such that bans returned would still be valid now. Negative values are equivalent to `None`. Default `None`; no limit. - ip : str + ip : IPAddr object IP Address to filter bans by. Default `None`; all IPs. Returns @@ -471,7 +472,8 @@ class Fail2BanDb(object): List of `Ticket`s for bans stored in database. """ tickets = [] - for ip, timeofban, data in self._getBans(**kwargs): + for ipstr, timeofban, data in self._getBans(**kwargs): + ip = IPAddr(ipstr) #TODO: Implement data parts once arbitrary match keys completed tickets.append(FailTicket(ip, timeofban, data.get('matches'))) tickets[-1].setAttempt(data.get('failures', 1)) @@ -491,7 +493,7 @@ class Fail2BanDb(object): Ban time in seconds, such that bans returned would still be valid now. Negative values are equivalent to `None`. Default `None`; no limit. - ip : str + ip : IPAddr object IP Address to filter bans by. Default `None`; all IPs. Returns @@ -512,6 +514,8 @@ class Fail2BanDb(object): ticket = None results = list(self._getBans(ip=ip, jail=jail, bantime=bantime)) + # Convert IP strings to IPAddr objects + results = map(lambda i:(IPAddr(i[0]),)+i[1:], results) if results: prev_banip = results[0][0] matches = [] diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index 798dc0c9..1fe70564 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -303,13 +303,19 @@ class Filter(JailThread): def getIgnoreCommand(self): return self.__ignoreCommand + ## + # create new IPAddr object from IP address string + def newIP(self, ipstr): + return IPAddr(ipstr) + ## # Ban an IP - http://blogs.buanzo.com.ar/2009/04/fail2ban-patch-ban-ip-address-manually.html # Arturo 'Buanzo' Busleiman # # to enable banip fail2ban-client BAN command - def addBannedIP(self, ip): + def addBannedIP(self, ipstr): + ip = IPAddr(ipstr) if self.inIgnoreIPList(ip): logSys.warning('Requested to manually ban an ignored IP %s. User knows best. Proceeding to ban it.' % ip) @@ -433,7 +439,7 @@ class Filter(JailThread): logSys.debug("Ignore line since time %s < %s - %s" % (unixTime, MyTime.time(), self.getFindTime())) break - if self.inIgnoreIPList(ip.ntoa(), log_ignore=True): + 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]),) @@ -528,17 +534,16 @@ class Filter(JailThread): try: host = failRegex.getHost() if returnRawHost: - ipaddr = IPAddr(host) - failList.append([failRegexIndex, ipaddr, date, + ip = IPAddr(host) + failList.append([failRegexIndex, ip, date, failRegex.getMatchedLines()]) if not checkAllRegex: break else: - ipMatch = DNSUtils.textToIp(host, self.__useDns) - if ipMatch: - for ip in ipMatch: - ipaddr = IPAddr(ip) - failList.append([failRegexIndex, ipaddr, + ips = DNSUtils.textToIp(host, self.__useDns) + if ips: + for ip in ips: + failList.append([failRegexIndex, ip, date, failRegex.getMatchedLines()]) if not checkAllRegex: break diff --git a/fail2ban/server/ticket.py b/fail2ban/server/ticket.py index 70be06fe..a0eae491 100644 --- a/fail2ban/server/ticket.py +++ b/fail2ban/server/ticket.py @@ -48,7 +48,9 @@ class Ticket: def __str__(self): return "%s: ip=%s time=%s #attempts=%d matches=%r" % \ - (self.__class__.__name__.split('.')[-1], self.__ip, self.__time, self.__attempt, self.__matches) + (self.__class__.__name__.split('.')[-1], + self.__ip.ntoa(), self.__time, self.__attempt, + self.__matches) def __repr__(self): return str(self) @@ -63,9 +65,6 @@ class Ticket: return False def setIP(self, value): - if isinstance(value, basestring): - # guarantee using regular str instead of unicode for the IP - value = str(value) self.__ip = value def getIP(self):