Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Für Modifikationen in und um KeyHelp.
R@iner
Posts: 2
Joined: Thu 24. Apr 2025, 13:17

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by R@iner »

Hallo Gemeinde,

zunächst vielen Dank für das Importskript. Ich hatte eine kleine Idee, wie man dessen Ausführungszeit signifikant reduzieren kann.
Man kann viel Zeit sparen, indem man vor dem Import der einzelnen IPs nachschaut, welche Adressen bereits in der f2b-Datenbank stehen, um so die heruntergeladene Datei auf die bisher noch unbekannten IPs zu beschränken. Das Ergebnis des folgenden Progrämmchens ist eine stark reduzierte Blocklisten-Datei, die, wie oben vorgeschlagen, Zeile für Zeile eingelesen werden kann.
Sicher geht das mit php auch, ich hatte es aber schneller mit Python zusammengekloppt, was die Erstellung einer virtuellen Umgebung erfordert, damit man nicht Python Packages in die Systemumgebung installiert.
Alles weitere steht im Skript.

shrink_blocklist.py:

Code: Select all

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
/root/banip/py/shrink_blocklist.py
----------------------------------
Kürzere Sperrliste für f2b erstellen.
Ref: https://community.keyhelp.de/viewtopic.php?p=54945

Holt die Datei aus der url und vergleicht die ip-Adressen mit denen, die in der f2b-Datenbank gespeichert sind.
Erstellt aus dem Vergleich der Adressen eine Datei, die nur die neu hinzugekommenen IPs beinhaltet.

Bitte vor der Installation der requirements ein virtuelles environment erstellen.
(Pandas gehört normalerweise nicht zur Systemumgebung.)

Getestet mit Keyhelp 15.1 (Python 3.11.*) / Debian 12.11

Vorbereitung:
-------------
Einloggen als root
$ apt install sqlite3 pip python3.11-venv

$ mkdir /root/banip/py
$ cd /root/banip/py

In das Verzeichnis muss diese Datei kopiert werden.

Wichtig: Virtual environment 'mypy' (oder anderer Name) im Verzeichnis erstellen:
------------------------------------------------------
$ python -m venv /root/banip/py/mypy

Wichtig: Virtual environment aktivieren:
----------------------------------------
§ source mypy/bin/activate

Jetzt sollte die Kommandozeile ein dem Prompt vorangestelltes (mypy) aufweisen.

(mypy)$ ls -al

drwxr-xr-x 3 root root 4096  3. Jul 00:01 .
drwxr-xr-x 3 root root 4096  3. Jul 00:01 ..
drwxr-xr-x 5 root root 4096  3. Jul 00:01 mypy
-rw-r--r-- 1 root root 7787  3. Jul 00:01 shrink_blocklist.py

Python Packages installieren:
------------------------------
(mypy)$ pip install pandas
(mypy)$ pip install requests
(mypy)$ pip install sqlite3

Kontrolle:
----------
Z.B.:
(mypy)$ pip list
Package            Version
------------------ -----------
certifi            2025.6.15
charset-normalizer 3.4.2
idna               3.10
numpy              2.3.1
pandas             2.3.0
pip                23.0.1
python-dateutil    2.9.0.post0
pytz               2025.2
requests           2.32.4
setuptools         66.1.1
six                1.17.0
tzdata             2025.2
urllib3            2.5.0

as Environment wird mit
$ deactivate
wieder auf die Basis des Systems zurückgesetzt.

Programm starten:
-----------------
$ python3 shrink_blocklist.py

Wenn alles installiert ist, dann sollte die Ausgabe etwa so aussehen:

Datei holen von https://raw.githubusercontent.com/borestad/blocklist-abuseipdb/refs/heads/main/abuseipdb-s100-3d.ipv4
Download beendet.
Die Dateigröße von blocklist.txt beträgt 7508167 Bytes.
Die Datei beinhaltet 129695 Zeilen.
Suche die erste Zeile in 'blocklist.txt', die mit einer gültigen ip-Adresse beginnt.
Beginn der ip-Adressen in Zeile: 14
Datenbank /var/lib/fail2ban/fail2ban.sqlite3 öffnen.
Die Tabelle 'bips' enthält 236318 Zeilen für den jail 'iplistblock'.
IP-Adressen der Datei laden.
Anzahl: 129681
IP-Adressen der f2b-Datenbank einlesen.
Anzahl: 236318
Neue IP-Adressen ermitteln
Anzahl: 11483
Datei mit neuen IP-Adressen erstellen
Alles OK. Die Dateigröße von shrinked_blocklist.txt beträgt 166190 Bytes.

Nun sollte das aktuelle Verzeichnis zusätzlich die Dateien 'blocklist.txt' und 'shrinked_blocklist.txt' aufweisen.

Das Environment wird mit
$ deactivate
wieder auf die Basis des Systems zurückgesetzt, falls noch andere Arbeiten anstehen, die Python-Skripte verwenden.
"""

__author__ = 'whocares'
__created__ = '03.07.2025'

import os
import shutil
import requests as req
import re
import sqlite3
import pandas as pd

url = 'https://raw.githubusercontent.com/borestad/blocklist-abuseipdb/refs/heads/main/abuseipdb-s100-3d.ipv4'
# größere 30-Tage-Liste alternativ, wie beschrieben unter https://github.com/borestad/blocklist-abuseipdb
# url = 'https://raw.githubusercontent.com/borestad/blocklist-abuseipdb/refs/heads/main/abuseipdb-s100-30d.ipv4
blfname = 'blocklist.txt'             # Heruntergeladene Blocklist
newblfname = 'shrinked_blocklist.txt' # Blocklist mit ausschließlich neuen Adressen, die f2b noch nicht kennt
jail = 'iplistblock'
minlines   = 100                      # Willkürlicher Wert für die Mindestanzahl an Zeilen in der Input-Datei
maxipstart =  25                      # Willkürlicher Wert für die erste Zeile mit einer ip-Adresse in der Input-Blocklist
                                      # Idee: Ist der Header zu lang, wird abgebrochen. Vlt. stehen in der Datei ganz andere Dinge?

db_filename = "/var/lib/fail2ban/fail2ban.sqlite3"

def getnumoflines(fname):
    with open(fname) as f:
        return len(f.readlines())


def errorexit(msg):
    if len(msg) > 0:
        for elem in msg:
            print(elem)

    print('Das Programm wird nach Fehler beendet.')
    exit(1)


def successexit(fname):
    fstat = os.stat(fname)
    print('Alles OK. Die Dateigröße von ' + fname + ' beträgt ' + str(fstat.st_size) + ' Bytes.')
    exit(0)


def main():
    """
    main()
    """
    print('Datei holen von ' + url)
    r = req.get(url, timeout=10)

    if r.ok:
        with open(blfname, mode="wb") as f:
            f.write(r.content)  # überschreibt die Datei, falls vorhanden
    else:
        errorexit(['Fehler beim Download', 'Fehlercode: ' + str(r.status_code), 'Stimmt die url?'])

    print('Download beendet.')

    fstat = os.stat(blfname)
    if fstat.st_size == 0:
        errorexit(['Die Dateigröße ist 0 Bytes', 'Stimmt die url?'])
    else:
        print('Die Dateigröße von ' + blfname + ' beträgt ' + str(fstat.st_size) + ' Bytes.')

    numoflines = getnumoflines(blfname)

    if numoflines < minlines:
        errorexit(['Die heruntegeladene Datei hat ' + str(numoflines) + ' Zeilen.', 'Sie sollte jedoch mehr als ' + str(minlines) + ' beinhalten.'])
    else:
        print('Die Datei beinhaltet ' + str(numoflines) + ' Zeilen.')

    print("Suche die erste Zeile in '" + blfname + "', die mit einer gültigen ip-Adresse beginnt.")

    # Regex: Nur ip-Adresse holen, die zu Beginn einer Zeile steht
    pat = re.compile(r"(?:\b|^)((?:(?:(?:\d)|(?:\d{2})|(?:1\d{2})|(?:2[0-4]\d)|(?:25[0-5]))\.){3}(?:(?:(?:\d)|(?:\d{2})|(?:1\d{2})|(?:2[0-4]\d)|(?:25[0-5]))))(?:\b|$)")

    with open(blfname) as f:
        i = 1
        for x in f:
            checkip4 = pat.findall(x)
            # print(checkip4)
            if len(checkip4) == 0:
                i += 1
                if i > maxipstart:
                    errorexit(['In den ersten ' + str(maxipstart) + ' Zeilen der Datei wurde keine IP-Adresse identifiziert.', \
                               'Header länger als erwartet? Enthält die Datei gültige ip-Adressen, die am Zeilenanfang stehen?'])
            else:
                break

    print('Beginn der ip-Adressen in Zeile: ' + str(i))
    print('Datenbank ' + db_filename + ' öffnen.')

    # ToDo: Fehlerbehandlung
    with sqlite3.connect(db_filename) as conn:
        cur = conn.cursor()

        sql = "SELECT COUNT(*) FROM bips WHERE jail='" + jail + "' or jail IS NULL;"
        cur.execute(sql)
        numofrows = cur.fetchone()[0]

        print("Die Tabelle 'bips' enthält " + str(numofrows) + " Zeilen für den jail '" + jail + "'." )

    if (numofrows == 0):
        print("In der Datenbak sind bisher keine Einträge für den jail '" + jail + "' vorhanden.")
        print('Die heruntergeladene Datei muss komplett eingelesen werden.')
        print('Kopiere ' + blfname + ' nach ' + newblfname)
        shutil.copy2(blfname, newblfname)
    else:
        print('IP-Adressen der Datei laden.')
        df_file = pd.read_csv(blfname, sep='#', skiprows=i, names=['ip', 'comment'])
        df_file['ip'] = df_file['ip'].str.strip() # Whitespace am Anfang und Ende der ip-Adressen für späteren Vergleich entfernen
        # print(df_file)
        print('Anzahl: ' + str(len(df_file.index)))

        print('IP-Adressen der f2b-Datenbank einlesen.')
        with sqlite3.connect(db_filename) as conn:
            df_db = pd.read_sql("SELECT ip FROM bips WHERE jail='" + jail + "'", conn)
        # print(df_db)
        print('Anzahl: ' + str(len(df_db.index)))

        print('Neue IP-Adressen ermitteln')
        df_new = df_file[~df_file['ip'].isin(df_db['ip'])]
        # print(df_new)
        print('Anzahl: ' + str(len(df_new.index)))
        print('Datei mit neuen IP-Adressen erstellen')
        df_new.to_csv(newblfname, columns=['ip'], header=False, index=False)
    
    successexit(newblfname)

if __name__ == "__main__":
    main() 
Das bash-Skript für cron muss entsprechend angepasst werden und sieht bei mir so aus:

cron.sh:

Code: Select all

#! /usr/bin/bash
echo `date "+%Y-%m-%d %H:%M:%S"`
cd /root/banip/py
source mypy/bin/activate
python3 shrink_blocklist.py
exit_status=$?
if [ "${exit_status}" -ne 0 ];
then
    echo "Python-Skript mit Fehler beendet. Shellskript wird abgebrochen(1)"
    echo `date "+%Y-%m-%d %H:%M:%S"`
    exit 1
fi
echo `date "+%Y-%m-%d %H:%M:%S"`
INFILE=/root/banip/py/shrinked_blocklist.txt
IFS=$'\n'
for IP in $(cat "$INFILE")
do
    fail2ban-client set iplistblock banip $IP >/dev/null 2>&1
done
echo `date "+%Y-%m-%d %H:%M:%S"`
echo "IP Blocklist verarbeitet"
rm /root/banip/py/blocklist.txt
rm /root/banip/py/shrinked_blocklist.txt
echo `date "+%Y-%m-%d %H:%M:%S"`
echo "fertig"
Lustig ist, dass man bei über 200000 Einträgen in der f2b-Verwaltung im Keyhelp-Dashboard einfach nur noch einen Timeout erhält.
Vielleicht wäre das eine Anregung, ein funktionierendes Paging zu programmieren?
Eine Alternative an dieser Stelle könnte dort eine nach Jails gruppierte Darstellung sein, sodass man auf den ersten Blick nur die Gesamtanzahl der Einträge per Gruppe erhielte. Denn wer will sich schon durch hundertausende Einträge blättern? Eine Suchfunktion für einzelne IPs wäre dann ausreichend.

Have phun!
User avatar
Fezzi
Posts: 316
Joined: Wed 12. Dec 2018, 04:04

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Fezzi »

Echt? :o Du betreibst noch so eine alte Version?
Getestet mit Keyhelp 15.1
TImeouts kann ich bisher nicht erkennen, aber ja, es dauert ein wenig (bis zu einer Minute) dass sich die Fail2Ban Seite zeigt... Die Anregung...
Eine Alternative an dieser Stelle könnte dort eine nach Jails gruppierte Darstellung sein, sodass man auf den ersten Blick nur die Gesamtanzahl der Einträge per Gruppe erhielte. Denn wer will sich schon durch hundertausende Einträge blättern? Eine Suchfunktion für einzelne IPs wäre dann ausreichend.
...finde ich gut... und die Suchfunktion fuer einzelne IPs gibt es ja schon...

Noch zu der anderen IP Set Loesung... die ist ja gut und schoen.. aber in meinem Fall (viele Kunden in TH) ist die F2B Loesung besser, da ich dann schnell mal die ein oder andere TH IP entsperren kann die sich in der Ban Liste befindet... TOT, TTT etc. das sind hier die gaengigen ISPs... aber ja, die CPU Last ist auf jeden Fall hoeher mit F2B
Gruss

Fezzi

Everyone can do something, no one can do everything.
R@iner
Posts: 2
Joined: Thu 24. Apr 2025, 13:17

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by R@iner »

p.s.: Noch ein bisschen Eigenwerbung. Ich habe die Skripte jetzt seit zwei Tagen laufen. Resümee:

Code: Select all

$ sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "select count(*) from bips where jail = 'iplistblock';"
liefert 293208 Datensätze als Ergebnis.
Seitdem die große Masse an Adressen von abuseipdb-s100-30d.ipv4 erst einmal eingelesen war, lasse ich den Cronjob stündlich ausführen. Da höchstens 500 neue Adressen hinzukommen, dauert das Einlesen nur ein paar Minuten.
Der Prozessor dümpelt ansonsten vor sich hin und es herrscht weitgehend Ruhe im Karton.

Danke nochmals für den Tip mit den AbuseIPDB blocklists!

Grüsse
R@iner
User avatar
@ITS
Posts: 249
Joined: Tue 17. May 2022, 14:33

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by @ITS »

Danke Tobi
Habe mir dein Script auch mal auf 2 Server eingebunden und Teste es.
Für mein Zweck derweil jedoch die 1d Liste herangezogen statt 3 Tage
Michael_M
Posts: 3
Joined: Sat 20. Dec 2025, 13:30

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Michael_M »

Hi,
ich lese hier schon ein paar Jahre mit und fand die Idee mit den Blocklisten sehr cool.
fail2ban ist mir bei der Menge zu langsam - Deshalb ist meine Lösung mit ipset

Wenn noch nicht vorhanden: apt install ipset

mkdir -p /etc/ipset-blocklist

ipset-blocklist.sh(.txt) + ipset-blocklist.conf(.txt)
in das Verzeichnis kopieren

chmod +x /etc/ipset-blocklist/ipset-blocklist.sh

# Installieren (erstellt systemd Service + Timer)
/etc/ipset-blocklist/ipset-blocklist.sh --install

# Erstes Update manuell starten
/etc/ipset-blocklist/ipset-blocklist.sh --update

....fertig


Befehle:

--update - Listen laden, ipset aktualisieren
--stats - Statistik anzeigen
--save / --restore - manuell speichern/laden

Features:

Mehrere Listen in Config (eine URL pro Zeile)
24h Cache pro Liste
Automatisches Update täglich 04:00
iptables-Regel an Position 1 (vor KeyHelp)
Persistenz über Reboot

Schnelle Anzeige ob alle IPs drin sind:

# Anzahl IPs im Set
ipset list blocklist | head -10

# Nur Anzahl
ipset list blocklist | grep -c "^[0-9]"

# Pruefen ob bestimmte IP drin ist
ipset test blocklist 1.2.3.4

Ablauf täglich 04:00 (Timer):

Listen neu downloaden
Neues Set mit aktuellen IPs befüllen
Swap → alte IPs weg, neue IPs aktiv
Keine manuelle Pflege nötig


Grüße
Michael
Attachments
ipset-blocklist.sh.txt
(11.18 KiB) Downloaded 4 times
ipset-blocklist.conf.txt
(724 Bytes) Downloaded 5 times
Michael_M
Posts: 3
Joined: Sat 20. Dec 2025, 13:30

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Michael_M »

Kleine Erweiterung: ipset-whitelist.conf

Ich wollte eigentlich nur Bogons rausfiltern, hab aber sicherheitshalber auch die wichtigsten Bot-Adressen mit reingepackt

Subnetze sind jetzt auch möglich
--uninstall hinzugefügt

Der Rest ist so geblieben - Siehe oben

68000 Einträge dauern mit dem Skript ca. 3 Minuten

Grüße
Michael
Attachments
ipset-blocklist.sh.txt
(15.79 KiB) Downloaded 4 times
ipset-whitelist.conf.txt
(4.67 KiB) Downloaded 4 times
ipset-blocklist.conf.txt
(1015 Bytes) Downloaded 4 times
User avatar
Fezzi
Posts: 316
Joined: Wed 12. Dec 2018, 04:04

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Fezzi »

Hier nochmals die zusaetzliche Info, die evtl. fuer den Ein oder Anderen interessant/wichtig ist.

Mit der oben genannten IP Block Liste sperrt Ihr auch automatisch alle potenziellen Kunden aus vielen Asiatischen Laendern!

In der List sind z.B. alle IP Adressen der zwei groessten ISPS Thailands mit dabei... das bedeutet, dass Ihr damit auch alle aussperrt die von Thailand aus auf Eure (Kunden)Webseiten zugreifen wollen.

Solche Listen sind zwar praktisch, aber dennoch mit Vorsicht zu geniessen, denn da hat man schnell mal IP Ranges mit dabei die man eigentlich nicht sperren moechte.
Gruss

Fezzi

Everyone can do something, no one can do everything.
User avatar
NicoMSH
Posts: 102
Joined: Sun 1. Jun 2025, 16:54
Location: nähe Halle

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by NicoMSH »

Fezzi wrote: Sun 21. Dec 2025, 04:41 Hier nochmals die zusaetzliche Info, die evtl. fuer den Ein oder Anderen interessant/wichtig ist.

Mit der oben genannten IP Block Liste sperrt Ihr auch automatisch alle potenziellen Kunden aus vielen Asiatischen Laendern!

In der List sind z.B. alle IP Adressen der zwei groessten ISPS Thailands mit dabei... das bedeutet, dass Ihr damit auch alle aussperrt die von Thailand aus auf Eure (Kunden)Webseiten zugreifen wollen.

Solche Listen sind zwar praktisch, aber dennoch mit Vorsicht zu geniessen, denn da hat man schnell mal IP Ranges mit dabei die man eigentlich nicht sperren moechte.
Danke für den erneuten Hinweis. Wir sind zB eine internationale K-Pop Community, da wäre es suboptimal IP Ranges aus Asien zu sperren^^
Deshalb halte ich mich im Allgemeinen mit solchen vorgefertigten Blocklisten zurück.

Wünsche Euch Frohe Weihnachten und wenn man sich nicht mehr schreibt auch ein gesundes neues Jahr :)
Michael_M
Posts: 3
Joined: Sat 20. Dec 2025, 13:30

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Michael_M »

>Mit der oben genannten IP Block Liste sperrt Ihr auch automatisch alle potenziellen Kunden aus vielen Asiatischen Laendern!
>In der List sind z.B. alle IP Adressen der zwei groessten ISPS Thailands mit dabei... das bedeutet, dass Ihr damit auch alle aussperrt die von Thailand aus auf Eure (Kunden)Webseiten zugreifen wollen.

na ja

https://raw.githubusercontent.com/bores ... 00-3d.ipv4

s100 bedeutet Listen mit 100% Spam

Ich sag mal so - Bei dieser Liste ist es fast nicht möglich potenziellen Kunden zu sperren :)
Außerdem sind in der Liste nur einzel-IPs

Aber grundsätzlich sollte klar sein, dass man solche harten Eingriffe nur machen sollte, wenn man weiß, was man macht.

Und wenn ich das bei uns so sehe: Die Bots sind (leider) extrem clever geworden.
IPs wechseln ohne Ende / es werden VPNs genutzt und tausend andere Sachen....


Grüße
Michael
User avatar
Fezzi
Posts: 316
Joined: Wed 12. Dec 2018, 04:04

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Fezzi »

Du weist schon dass das keine Fixen Ips sind?

Anyway, ich wollte nur darauf hinweisen... viel Spass beim blocken.
Gruss

Fezzi

Everyone can do something, no one can do everything.
User avatar
Ralph
Posts: 1421
Joined: Mon 30. Mar 2020, 16:14

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Ralph »

Code: Select all

# AbuseIPDB - 3 Tage Liste (~60k IPs, empfohlen)
https://raw.githubusercontent.com/borestad/blocklist-abuseipdb/refs/heads/main/abuseipdb-s100-3d.ipv4

# Spamhaus DROP (Don't Route Or Peer) - sehr konservativ, kaum false positives
https://www.spamhaus.org/drop/drop.txt

# Firehol Level 1 - jetzt sicher nutzbar (Bogons werden per Whitelist gefiltert)
https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset
AbuseIPDB und Spamhaus haben nichts mit Geoblocking zu tun, das sind alles als attackierend gemeldete IP Adressen mit einem Score von 100% z.b.
https://www.abuseipdb.com/check/1.36.201.177
Details:
https://github.com/borestad/blocklist-abuseipdb
Ist im Grunde auch nur ein Tropfen auf dem heißen Stein ...etwas weniger "Grundrauschen" würde Joli sagen :D
Diese 100% ler können gnadenlos geblockt werden ... zusätzlich auch mal selbst die Logs nach Attacken durchforsten, diese Listen reichen nicht aus.

Firehol Level 1 beinhaltet einiges an subnets ... und "611656000 unique IPs" ist einfach zu viel für ein Non-Cluster-System.
https://github.com/firehol/blocklist-ip ... el1.netset
Blubby
Posts: 90
Joined: Tue 5. Mar 2024, 13:10

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by Blubby »

Ralph wrote: Tue 23. Dec 2025, 10:27 ....
Ist im Grunde auch nur ein Tropfen auf dem heißen Stein ...etwas weniger "Grundrauschen" würde Joli sagen :D
Also die Abuseipdb Listen haben bei mir krass was ausgemacht, 90% weniger extrem Ereignisse sind das schon gewesen.
User avatar
technotravel
KeyHelp Translator
Posts: 475
Joined: Mon 19. Oct 2020, 11:11

Re: Länder IP Ban mit Fail2Ban, KeyHelp und Static Files

Post by technotravel »

Blubby wrote: Tue 23. Dec 2025, 12:49 Also die Abuseipdb Listen haben bei mir krass was ausgemacht, 90% weniger extrem Ereignisse sind das schon gewesen.
Was muss man denn für die eintragen im KH Interface?
Chers francophones, je traduis KeyHelp en français. S'il y a des erreurs ou des propositions d'amélioration, n'hésitez pas à me contacter !
(Ich übersetze KeyHelp ins Französische)
Post Reply