Country‑Block per nftables – einfache Lösung ohne Zusatztools

For topics beyond KeyHelp. / Für Themen jenseits von KeyHelp.
Post Reply
Systemweb
Posts: 18
Joined: Tue 25. Jul 2017, 09:50

Country‑Block per nftables – einfache Lösung ohne Zusatztools

Post by Systemweb »

Ich stelle hier meine Country‑Block‑Lösung für KeyHelp bereit, die vollständig auf nftables basiert und ohne zusätzliche Tools oder Plugins auskommt. Alle benötigten Pakete sind vorhanden. Es muss nichts installiert werden und es resultieren keinerlei Kollisionen mit Keyhelp.

Diese Lösung deckt ausschließlich IPv4‑Adressen ab.
IPv6 wird bewusst nicht berücksichtigt, da die meisten öffentlich dokumentierten Angriffsstatistiken weiterhin klar von IPv4‑Traffic dominiert werden und auch auf meinen eigenen Servern nahezu das gesamte „Grundrauschen“ aus IPv4‑Netzen stammt.

Ob ein zusätzlicher IPv6‑Country‑Block in der Praxis einen spürbaren Mehrwert bringt, hängt stark von der jeweiligen Umgebung ab. Für viele typische Hosting‑Szenarien ist der Nutzen derzeit eher gering, kann aber bei Bedarf jederzeit ergänzt werden.

Die blockierten Länder sind:
China (cn), Hongkong (hk), Macau (mo), Nigeria (ng), Russland (ru), Ukraine (ua), Rumänien (ro), Brasilien (br), Indien (in), Vietnam (vn), Indonesien (id), Türkei (tr), Iran (ir), Pakistan (pk) und Saudi‑Arabien (sa). Das sind laut aktuellem Stand ca. 32.000 IP-Bereiche.

Diese Länder führen in vielen öffentlich einsehbaren Statistiken regelmäßig die Listen automatisierter Angriffe an.
Die getroffene Auswahl ist eine bewusste Abwägung zwischen Schutz und Offenheit und kann von jedem individuell angepasst werden.

1. nftables‑Konfiguration
In der nftables‑Konfiguration werden pro Land Sets angelegt, die später durch das Script befüllt werden.

Lege die Datei an: /etc/nftables/country-block.conf:

Code: Select all

# Country block sets (IPv4)
#Die Regeln werden automatisch in die bestehende chain input eingefügt.
set block_cn { type ipv4_addr; flags interval; }
set block_hk { type ipv4_addr; flags interval; }
set block_mo { type ipv4_addr; flags interval; }
set block_ng { type ipv4_addr; flags interval; }
set block_ru { type ipv4_addr; flags interval; }
set block_ua { type ipv4_addr; flags interval; }
set block_ro { type ipv4_addr; flags interval; }
set block_br { type ipv4_addr; flags interval; }
set block_in { type ipv4_addr; flags interval; }
set block_vn { type ipv4_addr; flags interval; }
set block_id { type ipv4_addr; flags interval; }
set block_tr { type ipv4_addr; flags interval; }
set block_ir { type ipv4_addr; flags interval; }
set block_pk { type ipv4_addr; flags interval; }
set block_sa { type ipv4_addr; flags interval; }

# Country block rules
ip saddr @block_cn counter drop
ip saddr @block_hk counter drop
ip saddr @block_mo counter drop
ip saddr @block_ng counter drop
ip saddr @block_ru counter drop
ip saddr @block_ua counter drop
ip saddr @block_ro counter drop
ip saddr @block_br counter drop
ip saddr @block_in counter drop
ip saddr @block_vn counter drop
ip saddr @block_id counter drop
ip saddr @block_tr counter drop
ip saddr @block_ir counter drop
ip saddr @block_pk counter drop
ip saddr @block_sa counter drop


Bereits vorhandene /etc/nftables.conf anpassen

Du findest in dieser Datei ganz am Ende folgende Zeile:

Code: Select all

include "/etc/nftables/fail2ban.conf"
Füge DAVOR eine neue Zeile ein:

Code: Select all

include "/etc/nftables/country-block.conf"
Wenn die zitierte Zeile für fail2ban ganz fehlt (auf Debian-/Ubuntu-Systemen ohne Keyhelp) dann einfach am Ende der Datei hinzufügen.
Keyhelp rührt meines Wissen nach Erstinstallation diese Datei nicht mehr an. Falls doch (z.B. bei BS-Upgrade) muss nur diese Zeile erneut hinzugefügt werden.

Testen der nftables‑Konfiguration:

Code: Select all

nft -c -f /etc/nftables.conf
Wenn keine Fehlermeldung erscheint, ist die Konfiguration gültig.

Nach erfolgreichem Test kann nftables neu geladen werden:

Code: Select all

nft -f /etc/nftables.conf

2. Country‑Block‑Script
Das Script lädt die IP‑Ranges der gewünschten Länder, leert die Sets und füllt sie neu. Das Ganze läuft über eine Batchdatei, die am Ende verarbeitet wird. Somit erfolgt nur 1 Aufruf pro Land statt ~32.000 mal für alle IP-Bereiche und das Script benötigt nur max. 5 Sekunden. Eine Logdatei wird autom. unter /root/country-block.log angelegt und beinhaltet immer nur den letzten Durchlauf zur Kontrolle.

Neue Datei: /root/country-block.sh

Code: Select all

#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

LOGFILE="/root/country-block.log"
IPV4_URL="https://www.ipdeny.com/ipblocks/data/countries"

COUNTRIES="cn hk mo ng ru ua ro br in vn id tr ir pk sa"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOGFILE"
}

: > "$LOGFILE"
log "Starte Country-Block Update (per-country only)"

declare -A DATA

SECONDS=0

#
# 1) Länderlisten EINMAL herunterladen
#
for c in $COUNTRIES; do
    log "Lade $c..."
    DATA[$c]=$(curl -s "$IPV4_URL/$c.zone")
done

#
# 2) Alle Sets leeren
#
for c in $COUNTRIES; do
    nft flush set inet filter block_$c
done

#
# 3) Batch-Inserts pro Land
#
for c in $COUNTRIES; do
    log "Fülle block_$c..."

    # Batch-Block öffnen
    echo "add element inet filter block_$c {" > /tmp/batch_$c.nft

    # Elemente einfügen
    while read ip; do
        [ -n "$ip" ] || continue
        echo "  $ip," >> /tmp/batch_$c.nft
    done <<< "${DATA[$c]}"

    # Batch-Block schließen
    echo "}" >> /tmp/batch_$c.nft

    # Einmaliger nft-Aufruf
    nft -f /tmp/batch_$c.nft
    
    # Batch-Datei entfernen
    rm /tmp/batch_$c.nft
done

log "Update abgeschlossen in ${SECONDS}s."


3. Cronjob
Der Cronjob aktualisiert die Listen beim Systemstart sowie einmal pro Woche.

Anlegen: /etc/cron.d/country-block

Code: Select all

SHELL=/bin/bash
@reboot root /root/country-block.sh
15 2 * * 1 root /root/country-block.sh


4. Manuelles Update
Jederzeit möglich mittels Aufruf von

Code: Select all

/root/country-block.sh
Dieser Befehl sollte an dieser Stelle 1x ausgeführt werden um zu initialisieren.


5. Anpassung
Die Länderliste kann jederzeit im Script geändert werden:

Code: Select all

COUNTRIES="cn hk mo ng ru ua ro br in vn id tr ir pk sa"
Natürlich muss auch in /etc/nftables/country-block.conf entspr. ergänzt werden nach Hinzufügen bzw. Entfernen von Ländern.
Nach Änderungen an der Datei muss die nftables Konfiguration erneut getestet und geladen werden.

Weitere Country‑Codes und Zonenlisten findest du bei ipdeny.

6. Vollständige Deinstallation / Rückbau
Include‑Eintrag aus /etc/nftables.conf entfernen oder auskommentieren:

Code: Select all

include "/etc/nftables/country-block.conf"
Country‑Block‑Datei löschen:

Code: Select all

rm /etc/nftables/country-block.conf
nftables neu laden:

Code: Select all

systemctl reload nftables
(Reload entfernt die Sets automatisch, weil sie nicht mehr definiert sind.)
Cronjob entfernen:

Code: Select all

rm /etc/cron.d/country-block
Script löschen:

Code: Select all

rm /root/country-block.sh
Anmerkungen:
Ich habe bewusst die Listen nach Ländern gruppiert und in nftables nicht einfach alles unter einem Chain "countryblock" o.ä. definiert. Auf diese Weise ist es z.B. jederzeit möglich, die geblockten Pakete nach Ländern zu ermitteln.
Hierfür existiert ein ebenfalls von mir erstelltes Munin-Plugin. Falls daran Interesse besteht werde ich das hier nachreichen.
Systemweb
Posts: 18
Joined: Tue 25. Jul 2017, 09:50

Re: Country‑Block per nftables – einfache Lösung ohne Zusatztools

Post by Systemweb »

Ich habe mir überlegt, die Munin-Plugins direkt statt später nachzuliefern, damit man beides an gleicher Stelle zusammenhängend finden kann.

So sieht das Ganze nachher aus
Munin-Graph 1: Insgesamt geblockte Pakete und aktuell enthaltene IPs/IP-Ranges in der Blockliste:
Image
Munin-Graph 2: Auflistung blockierter Pakete nach Ländern:
Image

Anlegen der Plugins
Plugin #1 anlegen unter /usr/share/munin/plugins/nft_countryblock

Code: Select all

#!/bin/bash

TABLE="inet"
CHAIN="input"
COUNTRIES="cn hk mo ng ru ua ro br in vn id tr ir pk sa"

###############################################
# CONFIG
###############################################
if [ "$1" = "config" ]; then
    echo "graph_title Countryblock - Total Drops & Set Size (Weekly)"
    echo "graph_category firewall"
    echo "graph_vlabel packets / entries"
    echo "graph_args --lower-limit 0"
    echo "graph_scale no"
    echo "graph_period second"

    echo "total_drops.label Total Drops"
    echo "total_drops.type GAUGE"
    echo "total_drops.min 0"
    echo "total_drops.graph_printf %.0lf"

    echo "setsize.label Set Size (blocked IP ranges)"
    echo "setsize.type GAUGE"
    echo "setsize.min 0"
    echo "setsize.graph_printf %.0lf"

    exit 0
fi

###############################################
# 1) Absolute nftables-Drops summieren
###############################################
total=0
for c in $COUNTRIES; do
    rule=$(nft -a list chain $TABLE filter $CHAIN | grep -A1 "@block_$c")
    drops=$(echo "$rule" | grep -oP 'packets \K[0-9]+' | head -n1)
    drops=${drops:-0}
    total=$((total + drops))
done

###############################################
# 2) Set Size (aktuell gesperrte IP-Ranges)
###############################################
setsize=0
for c in $COUNTRIES; do
    count=$(nft list set $TABLE filter block_$c 2>/dev/null | grep -c '/')
    count=${count:-0}
    setsize=$((setsize + count))
done

###############################################
# 3) Werte ausgeben
###############################################
echo "total_drops.value $total"
echo "setsize.value $setsize"

WICHTIG: Die angegebenen COUNTRIES sollten mit denen im Script /root/country-block.sh übereinstimmen!

Plugin #2 anlegen unter /usr/share/munin/plugins/nft_countryattackers

Code: Select all

#!/bin/bash

TABLE="inet"
CHAIN="input"

declare -A NAMES=(
    [cn]="China"
    [hk]="Hong Kong"
    [mo]="Macau"
    [ng]="Nigeria"
    [ru]="Russia"
    [ua]="Ukraine"
    [ro]="Romania"
    [br]="Brazil"
    [in]="India"
    [vn]="Vietnam"
    [id]="Indonesia"
    [tr]="Turkey"
    [ir]="Iran"
    [pk]="Pakistan"
    [sa]="Saudi Arabia"
)

COUNTRIES="cn hk mo ng ru ua ro br in vn id tr ir pk sa"

###############################################
# CONFIG
###############################################
if [ "$1" = "config" ]; then
    echo "graph_title Countryblock - Drops by Country (Weekly)"
    echo "graph_category firewall"
    echo "graph_vlabel packets"
    echo "graph_args --lower-limit 0"
    echo "graph_scale no"
    echo "graph_period second"

    for c in $COUNTRIES; do
        fullname=${NAMES[$c]}
        upper=$(echo "$c" | tr '[:lower:]' '[:upper:]')
        echo "drops_${c}.label ${upper} - ${fullname}"
        echo "drops_${c}.type GAUGE"
        echo "drops_${c}.min 0"
        echo "drops_${c}.graph_printf %.0lf"
    done

    exit 0
fi

###############################################
# 1) Absolute nftables-Drops pro Land
###############################################
for c in $COUNTRIES; do
    rule=$(nft -a list chain $TABLE filter $CHAIN | grep -A1 "@block_$c")
    drops=$(echo "$rule" | grep -oP 'packets \K[0-9]+' | head -n1)
    drops=${drops:-0}
    echo "drops_${c}.value $drops"
done

WICHTIG: Auch hier muss die Liste der COUNTRIES mit den bereits konfigurierten übereinstimmen!
Außerdem gibt es den zusätzl. Block, der zu den Kürzeln die ausgeschriebenen Länder definiert. Nach Änderungen muss auch das editiert werden.

Beide Plugins ausführbar machen

Code: Select all

chmod +x /usr/share/munin/plugins/nft_countryblock
chmod +x /usr/share/munin/plugins/nft_countryattackers


Symlinks anlegen, um die Plugins zu aktivieren

Code: Select all

ln -s /usr/share/munin/plugins/nft_countryblock /etc/munin/plugins/nft_countryblock
ln -s /usr/share/munin/plugins/nft_countryattackers /etc/munin/plugins/nft_countryattackers


Munin benötigt für den Zugriff auf nftables erweiterte Berechtigung, die wir hier anlegen: /etc/munin/plugin-conf.d/nft_countryblock

Code: Select all

[nft_countryblock]
user root
timeout 10

[nft_countryattackers]
user root
timeout 10

Die zusätzliche Definition für Timeout verhindert, dass das Plugin bei unerwarteten Fehlern ewig lädt.

Überprüfen der Plugin-Syntax
Nun ist es an der Zeit, die beiden neuen Plugins zu testen

Code: Select all

munin-run nft_countryblock config
munin-run nft_countryblock

munin-run nft_countryattackers config
munin-run nft_countryattackers

Falls keine Ausgabe erfolgt bzw. Fehler angezeigt werden
Munin reagiert empfindlich auf ungültige versteckte Zeichen wie Windows-Zeilenenden (BOM, CRLF). Hierfür empfiehlt es sich, das Tool dos2unix zu verwenden um die betreff. Dateien zu konvertieren:

Code: Select all

dos2unix /usr/share/munin/plugins/nft_countryblock
dos2unix /usr/share/munin/plugins/nft_countryattackers
Falls dos2unix noch nicht installiert ist, vorher dies erledigen:

Code: Select all

apt update && apt install dos2unix -y
.
Nach der Konvertierung den Syntax-Test nochmal durchführen.

Wenn die Prüfung der Syntax erfolgreich war (Werte wurden ausgegeben), muss nur noch munin-node neu gestartet werden:

Code: Select all

systemctl restart munin-node
Sobald per Reboot oder wöchentl. Cronjob die Listen aktualisiert wurden (per Ausführen von /root/countryblock.sh) beginnen alle Zähler wieder bei Null.
Post Reply