diff --git a/config/jail.conf b/config/jail.conf index edf3e676..ffdce2b5 100644 --- a/config/jail.conf +++ b/config/jail.conf @@ -166,6 +166,11 @@ mode = normal # filter = %(__name__)s[mode=%(mode)s] +# "ignoregeo" specifies the countries to ignore based on geolocation. +#ignoregeo = + +# "geoipdb" specifies the path to the GeoIP database. +#geoipdb = # # ACTIONS diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index 26e80107..1bbf9b63 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -743,3 +743,56 @@ class Actions(JailThread, Mapping): ("Banned Country list", self.banManager.geBanListExtendedCountry(cymru_info)), ("Banned RIR list", self.banManager.geBanListExtendedRIR(cymru_info))] return ret + + def perform_geolocation_lookup(self, ip): + """Perform geolocation lookup for the given IP address. + + Parameters + ---------- + ip : str + The IP address to perform geolocation lookup for. + + Returns + ------- + str + The country code of the IP address. + """ + # Implement the geolocation lookup logic here + # For example, you can use an external service like ip-api.com + import requests + response = requests.get(f"http://ip-api.com/json/{ip}") + data = response.json() + return data.get("countryCode") + + def ban(self, aInfo): + """Executes the given command ("actionban" or "actionreban"). + + Replaces the tags in the action command with actions properties + and ban information, and executes the resulting command. + + Parameters + ---------- + aInfo : dict + Dictionary which includes information in relation to + the ban. + """ + # Perform geolocation lookup + ip = aInfo["ip"] + country_code = self.perform_geolocation_lookup(ip) + aInfo["country_code"] = country_code + + # Check if the IP should be ignored based on geolocation + ignoregeo = self._jail.filter.getOptions().get("ignoregeo", "").split() + if country_code in ignoregeo: + logSys.info("Ignoring IP %s from country %s based on geolocation", ip, country_code) + return + + # if we should start the action on demand (conditional by family): + family = aInfo.get('family', '') + if self._startOnDemand: + if not self.__started.get(family): + self._start(family, forceStart=True) + # ban: + if not self._processCmd('', aInfo): + raise RuntimeError("Error banning %(ip)s" % aInfo) + self.__started[family] = self.__started.get(family, 0) | 3; # started and contains items diff --git a/fail2ban/server/banmanager.py b/fail2ban/server/banmanager.py index d3e89820..906b4a4a 100644 --- a/fail2ban/server/banmanager.py +++ b/fail2ban/server/banmanager.py @@ -384,3 +384,23 @@ class BanManager: except KeyError: pass return None # if none found + + ## + # Handle geolocation data for banned IPs. + # + # @param ticket the ticket + # @return True if the IP address is not in the ban list + + def handleGeolocationData(self, ticket): + # Perform geolocation lookup + ip = ticket.getID() + country_code = self.perform_geolocation_lookup(ip) + ticket.setData("country_code", country_code) + + # Check if the IP should be ignored based on geolocation + ignoregeo = self._jail.filter.getOptions().get("ignoregeo", "").split() + if country_code in ignoregeo: + logSys.info("Ignoring IP %s from country %s based on geolocation", ip, country_code) + return False + + return True diff --git a/fail2ban/server/jail.py b/fail2ban/server/jail.py index 0f8e3566..c0226528 100644 --- a/fail2ban/server/jail.py +++ b/fail2ban/server/jail.py @@ -85,6 +85,8 @@ class Jail(object): if backend is not None: self._realBackend = self._setBackend(backend) self.backend = backend + self.__ignoregeo = set() + self.__geoipdb = None def __repr__(self): return "%s(%r)" % (self.__class__.__name__, self.name) @@ -207,6 +209,16 @@ class Jail(object): Used by filter to add a failure for banning. """ + # Perform geolocation lookup + ip = ticket.getID() + country_code = self.actions.perform_geolocation_lookup(ip) + ticket.setData("country_code", country_code) + + # Check if the IP should be ignored based on geolocation + if country_code in self.__ignoregeo: + logSys.info("Ignoring IP %s from country %s based on geolocation", ip, country_code) + return + self.__queue.put(ticket) # add ban to database moved to observer (should previously check not already banned # and increase ticket time if "bantime.increment" set) @@ -324,6 +336,8 @@ class Jail(object): self.filter.start() self.actions.start() self.restoreCurrentBans() + self.__ignoregeo = set(self.filter.getOptions().get("ignoregeo", "").split()) + self.__geoipdb = self.filter.getOptions().get("geoipdb", None) logSys.info("Jail %r started", self.name) def stop(self, stop=True, join=True):