Skip to content

Commit

Permalink
Merge branch 'geolocation_ignore' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinbreiz committed Jan 3, 2024
2 parents e69ca01 + 821b754 commit 5b59777
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Optional:
* [python-systemd package](https://www.freedesktop.org/software/systemd/python-systemd/index.html)
- [dnspython](http://www.dnspython.org/)
- [pyasyncore](https://pypi.org/project/pyasyncore/) and [pyasynchat](https://pypi.org/project/pyasynchat/) (normally bundled-in within fail2ban, for python 3.12+ only)
- [geoiplookup](https://linux.die.net/man/1/geoiplookup)
- [mmdblookup](https://maxmind.github.io/libmaxminddb/mmdblookup.html)


To install:
Expand Down
8 changes: 8 additions & 0 deletions fail2ban/client/beautifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ def beautify(self, response):
for ip in response[:-1]:
msg += "|- " + ip + "\n"
msg += "`- " + response[-1]
elif inC[2] in ("ignoregeo", "addignoregeo", "delignoregeo"):
if len(response) == 0:
msg = "No GEO location is ignored"
else:
msg = "These GEO locations are ignored:\n"
for geo in response[:-1]:
msg += "|- " + geo + "\n"
msg += "`- " + response[-1]
elif inC[2] in ("failregex", "addfailregex", "delfailregex",
"ignoreregex", "addignoreregex", "delignoreregex"):
if len(response) == 0:
Expand Down
3 changes: 3 additions & 0 deletions fail2ban/client/jailreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def _glob(path):
"ignorecommand": ["string", None],
"ignoreself": ["bool", None],
"ignoreip": ["string", None],
"ignoregeo": ["string", None],
"ignorecache": ["string", None],
"filter": ["string", ""],
"logtimezone": ["string", None],
Expand Down Expand Up @@ -279,6 +280,8 @@ def convert(self, allow_no_files=False):
logSys.warning(msg)
elif opt == "ignoreip":
stream.append(["set", self.__name, "addignoreip"] + splitwords(value))
elif opt == "ignoregeo":
stream.append(["set", self.__name, "addignoregeo"] + splitwords(value))
elif opt not in JailReader._ignoreOpts:
stream.append(["set", self.__name, opt, value])
# consider options order (after other options):
Expand Down
3 changes: 3 additions & 0 deletions fail2ban/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def __getattr__(self, name):
["set <JAIL> ignoreself true|false", "allows the ignoring of own IP addresses"],
["set <JAIL> addignoreip <IP>", "adds <IP> to the ignore list of <JAIL>"],
["set <JAIL> delignoreip <IP>", "removes <IP> from the ignore list of <JAIL>"],
["set <JAIL> addignoregeo <GEO>", "adds <GEO> to the ignore list of <JAIL>"],
["set <JAIL> delignoregeo <GEO>", "removes <GEO> from the ignore list of <JAIL>"],
["set <JAIL> ignorecommand <VALUE>", "sets ignorecommand of <JAIL>"],
["set <JAIL> ignorecache <VALUE>", "sets ignorecache of <JAIL>"],
["set <JAIL> addlogpath <FILE> ['tail']", "adds <FILE> to the monitoring list of <JAIL>, optionally starting at the 'tail' of the file (default 'head')."],
Expand Down Expand Up @@ -129,6 +131,7 @@ def __getattr__(self, name):
["get <JAIL> journalmatch", "gets the journal filter match for <JAIL>"],
["get <JAIL> ignoreself", "gets the current value of the ignoring the own IP addresses"],
["get <JAIL> ignoreip", "gets the list of ignored IP addresses for <JAIL>"],
["get <JAIL> ignoregeo", "gets the list of ignored GEO locations for <JAIL>"],
["get <JAIL> ignorecommand", "gets ignorecommand of <JAIL>"],
["get <JAIL> failregex", "gets the list of regular expressions which matches the failures for <JAIL>"],
["get <JAIL> ignoreregex", "gets the list of regular expressions which matches patterns to ignore for <JAIL>"],
Expand Down
51 changes: 51 additions & 0 deletions fail2ban/server/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
import re
import sys
import time
import subprocess
import shutil


from .actions import Actions
from .failmanager import FailManagerEmpty, FailManager
Expand Down Expand Up @@ -83,6 +86,8 @@ def __init__(self, jail, useDns='warn'):
## The ignore IP list.
self.__ignoreIpSet = set()
self.__ignoreIpList = []
## The ignore GEO ip list.
self.__ignoreGeoSet = set()
## External command
self.__ignoreCommand = False
## Cache for ignoreip:
Expand Down Expand Up @@ -541,6 +546,33 @@ def logIgnoreIp(self, ip, log_ignore, ignore_source="unknown source"):
def getIgnoreIP(self):
return self.__ignoreIpList + list(self.__ignoreIpSet)

def addIgnoreGEO(self, geo):
# An empty string is always false
if geo == "":
return

# Avoid exact duplicates
if geo in self.__ignoreGeoSet:
logSys.log(logging.MSG, " Ignore duplicate %r, already in geo ignore list", geo)
return

# log and append to ignore list
logSys.debug(" Add %r to geo ignore list", geo)
self.__ignoreGeoSet.add(geo)

def delIgnoreGEO(self, geo=None):
# clear all:
if geo is None:
self.__ignoreGeoSet.clear()
return
# delete by ip:
logSys.debug(" Remove %r from geo ignore list", geo)
if geo in self.__ignoreGeoSet:
self.__ignoreGeoSet.remove(geo)

def getIgnoreGEO(self):
return list(self.__ignoreGeoSet)

##
# Check if IP address/DNS is in the ignore list.
#
Expand Down Expand Up @@ -579,6 +611,25 @@ def _inIgnoreIPList(self, ip, ticket, log_ignore=True):
if self.__ignoreCache: c.set(key, True)
return True

# check if the IP's geolocation is not on geo ignore list

if self.__ignoreGeoSet:
geoipcc = None
geoip2cf = "/usr/share/GeoIP/GeoIP2-Country.mmdb"

if shutil.which("mmdblookup") and os.path.isfile(geoip2cf):
geoipcc = str(subprocess.check_output(["mmdblookup","--file","/usr/share/GeoIP/GeoIP2-Country.mmdb","--ip",str(ip),"country","iso_code"])).split(" ")[2].replace("\"", "")
elif shutil.which("geoiplookup"):
if shutil.which("mmdblookup") and not os.path.isfile(geoip2cf):
logSys.warning("Found mmdblookup but cannot find mmdb country file at /usr/share/GeoIP/GeoIP2-Country.mmdb, using geoiplookup instead.")
geoipcc = str(subprocess.check_output(["geoiplookup",str(ip)])).split(" ")[3].replace(",","")
else:
logSys.warning("Cannot find geoiplookup or correctly set mmdblookup. Geolocation is unavailable. If you have mmdblookup installed, please check if /usr/share/GeoIP/GeoIP2-Country.mmdb file is available.")

if geoipcc in self.__ignoreGeoSet:
self.logIgnoreIp(ip, log_ignore, ignore_source="geo-" + geoipcc)
return True

# check if the IP is covered by ignore IP (in set or in subnet/dns):
if ip in self.__ignoreIpSet:
self.logIgnoreIp(ip, log_ignore, ignore_source="ip")
Expand Down
9 changes: 9 additions & 0 deletions fail2ban/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,15 @@ def delIgnoreIP(self, name, ip):

def getIgnoreIP(self, name):
return self.__jails[name].filter.getIgnoreIP()

def addIgnoreGEO(self, name, geo):
self.__jails[name].filter.addIgnoreGEO(geo)

def delIgnoreGEO(self, name, geo):
self.__jails[name].filter.delIgnoreGEO(geo)

def getIgnoreGEO(self, name):
return self.__jails[name].filter.getIgnoreGEO()

def addLogPath(self, name, fileName, tail=False):
filter_ = self.__jails[name].filter
Expand Down
12 changes: 12 additions & 0 deletions fail2ban/server/transmitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,16 @@ def __commandSet(self, command, multiple=False):
self.__server.delIgnoreIP(name, value)
if self.__quiet: return
return self.__server.getIgnoreIP(name)
elif command[1] == "addignoregeo":
for value in command[2:]:
self.__server.addIgnoreGEO(name, value)
if self.__quiet: return
return self.__server.getIgnoreGEO(name)
elif command[1] == "delignoregeo":
value = command[2]
self.__server.delIgnoreGEO(name, value)
if self.__quiet: return
return self.__server.getIgnoreGEO(name)
elif command[1] == "ignorecommand":
value = command[2]
self.__server.setIgnoreCommand(name, value)
Expand Down Expand Up @@ -453,6 +463,8 @@ def __commandGet(self, command):
return self.__server.getIgnoreSelf(name)
elif command[1] == "ignoreip":
return self.__server.getIgnoreIP(name)
elif command[1] == "ignoregeo":
return self.__server.getIgnoreGEO(name)
elif command[1] == "ignorecommand":
return self.__server.getIgnoreCommand(name)
elif command[1] == "ignorecache":
Expand Down
12 changes: 12 additions & 0 deletions man/fail2ban-client.1
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,14 @@ adds <IP> to the ignore list of
removes <IP> from the ignore list
of <JAIL>
.TP
\fBset <JAIL> addignoregeo <GEO>\fR
adds <GEO> to the ignore list of
<JAIL>
.TP
\fBset <JAIL> delignoreigeo <GEO>\fR
removes <GEO> from the ignore list
of <JAIL>
.TP
\fBset <JAIL> ignorecommand <VALUE>\fR
sets ignorecommand of <JAIL>
.TP
Expand Down Expand Up @@ -392,6 +400,10 @@ ignoring the own IP addresses
gets the list of ignored IP
addresses for <JAIL>
.TP
\fBget <JAIL> ignoregeo\fR
gets the list of ignored GEO
addresses for <JAIL>
.TP
\fBget <JAIL> ignorecommand\fR
gets ignorecommand of <JAIL>
.TP
Expand Down
3 changes: 3 additions & 0 deletions man/jail.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ boolean value (default true) indicates the banning of own IP addresses should be
.B ignoreip
list of IPs not to ban. They can include a DNS resp. CIDR mask too. The option affects additionally to \fBignoreself\fR (if true) and don't need to contain own DNS resp. IPs of the running host.
.TP
.B ignoregeo
list of GEO location codes of IPs not to ban. For this to work, you should have a `geoiplookup` or `mmdblookup` or other program with the same name installed. This feature was only tested with Maxmind's `geoiplookup` or `mmdblookup`.
.TP
.B ignorecommand
command that is executed to determine if the current candidate IP for banning (or failure-ID for raw IDs) should not be banned. This option operates alongside the \fBignoreself\fR and \fBignoreip\fR options. It is executed first, only if neither \fBignoreself\fR nor \fBignoreip\fR match the criteria.
.br
Expand Down

0 comments on commit 5b59777

Please sign in to comment.