Netzwerke und Cybersicherheit 17 Min. Lesezeit

Zuverlässige GeoIP-Filterung auf MikroTik RouterOS konfigurieren

Eine CIDR-Liste je geografische Zone generieren, diese vor der Veröffentlichung validieren, sie ohne Löschen der letzten funktionsfähigen Version importieren und sie auf den richtigen Firewall-Ketten anwenden.

RouterOS enthält keine integrierte GeoIP-Datenbank, die es ermöglicht, ein Land in einer Firewall-Regel auszuwählen. Der Mechanismus basiert auf externen CIDR-Präfixlisten : der Router importiert diese in eine Address-List, und dann verwendet eine Regel input oder forward diese Liste als Kriterium.

Der heikle Teil ist nicht die endgültige Regel. Er besteht darin, überprüfbare Daten zu erhalten, eine funktionierende Liste niemals durch eine leere Datei zu ersetzen und den Filter in der Kette zu platzieren, die tatsächlich zum Dienst gehört. Dieser Leitfaden erstellt eine IPv4-Liste für Belgien und ermöglicht gleichzeitig das einfache Hinzufügen von Frankreich, den Niederlanden oder Luxemburg.

Wie das GeoIP-Filtering funktioniert

Eine geografische Datenbank ordnet Adressblöcke einem Gebietscode zu. Für eine Firewall werden diese Blöcke einfach zu Netzwerken wie 203.0.113.0/24. RouterOS führt während der Paketverarbeitung keine geografische Suche durch : Es prüft nur, ob die Quelladresse zu einem der Einträge in der Liste gehört.

KomponenteRolleZu kontrollierendes Risiko
RIR-DatenBereitstellung der nach ISO-Code registrierten PräfixeDas Registrierungsland kann vom tatsächlichen Standort abweichen
GeneratorValidieren und Konvertieren der CIDR in RouterOS-BefehleEin leerer Download darf niemals die aktive Liste überschreiben
Address-listSpeichern der Netzwerke in RouterOSTausende von Einträgen verbrauchen Speicher und Importzeit
FirewallZulassen oder Ablehnen gemäß der ListeEine falsche Kette oder Reihenfolge macht den Filter unwirksam
SchedulerAktualisieren der DatenBerechtigungen und Fehler müssen sichtbar sein

Die unten verwendeten Listen stammen aus den Zuteilungsdaten der regionalen Internet-Register, gruppiert nach ISO-Code und täglich veröffentlicht. Sie sind kleiner als eine sehr detaillierte Geolokalisierungsdatenbank, was für einen Router besser geeignet ist. Sie beschreiben jedoch die Registrierung der Internet-Ressourcen, keine GPS-Position.

Empfohlene Architektur

Der Router sollte nicht direkt von einer im laufenden Betrieb umgewandelten Webseite abhängen. Ein Linux-Server oder ein NAS lädt die Daten herunter, validiert jedes CIDR, erstellt eine Datei .rsc und veröffentlicht diese dann über HTTPS. MikroTik lädt diese Datei herunter, führt einen Probelauf-Import durch und wendet sie nur an, wenn ihre Syntax gültig ist.

Sichere GeoIP-Aktualisierungspipeline mit HTTPS-Download, CIDR-Validierung, temporärer Liste und kontrolliertem Wechsel
Die Ersetzung erfolgt nach dem Download, der Validierung der CIDRs, dem Laden in eine temporäre Liste und einer Volumenprüfung.

Vorbereiten des Listenservers

Das Beispiel geht von einem Server mit bash, curl und Python 3 aus. Python verwendet hier nur das Standardmodul ipaddress : Es ist keine zusätzliche Bibliothek erforderlich.

Erstellen Sie ein Verzeichnis, das von Ihrem Webserver veröffentlicht wird, z. B. /srv/www/geoip, und schützen Sie es dann mit HTTPS. Das folgende Skript lädt die belgische Liste herunter, lehnt eine zu kurze Datei ab, validiert jedes IPv4-Netzwerk, aggregiert die Präfixe, die aggregiert werden können, und generiert atomar eine RouterOS-Datei.

#!/usr/bin/env bash
set -Eeuo pipefail

COUNTRIES=(be)
BASE_URL="https://raw.githubusercontent.com/ipverse/rir-ip/master/country"
PUBLISH_DIR="/srv/www/geoip"
FINAL_FILE="$PUBLISH_DIR/GeoIP-BE.rsc"
WORK_DIR="$(mktemp -d)"
PUBLISH_TMP="$(mktemp "$PUBLISH_DIR/.GeoIP-BE.XXXXXX")"

cleanup() {
    rm -rf "$WORK_DIR"
    if [[ -n "${PUBLISH_TMP:-}" && -f "$PUBLISH_TMP" ]]; then
        rm -f "$PUBLISH_TMP"
    fi
}
trap cleanup EXIT

RAW_FILE="$WORK_DIR/all-prefixes.txt"
VALID_FILE="$WORK_DIR/validated-prefixes.txt"
: > "$RAW_FILE"

for country in "${COUNTRIES[@]}"; do
    curl --fail --location --silent --show-error --retry 3 \
        "$BASE_URL/$country/ipv4-aggregated.txt" \
        --output "$WORK_DIR/$country.txt"
    grep -Ev '^(#|$)' "$WORK_DIR/$country.txt" >> "$RAW_FILE"
done

python3 - "$RAW_FILE" "$VALID_FILE" <<'PY'
import ipaddress
import sys

source, destination = sys.argv[1:3]
networks = []
with open(source, encoding="utf-8") as handle:
    for raw_line in handle:
        line = raw_line.strip()
        if not line:
            continue
        network = ipaddress.ip_network(line, strict=True)
        if network.version != 4:
            raise SystemExit(f"Kein IPv4-Praefix: {line}")
        networks.append(network)

collapsed = list(ipaddress.collapse_addresses(networks))
if len(collapsed) < 100:
    raise SystemExit("Ungewoehnlich kurze Liste: Veroeffentlichung abgebrochen")

with open(destination, "w", encoding="ascii") as handle:
    for network in collapsed:
        handle.write(f"{network}\n")
PY

python3 - "$VALID_FILE" "$PUBLISH_TMP" <<'PY'
import sys

source, destination = sys.argv[1:3]
with open(source, encoding="ascii") as handle:
    prefixes = [line.strip() for line in handle if line.strip()]

with open(destination, "w", encoding="ascii") as output:
    output.write(':do { /ip firewall address-list remove '
                 '[find where list="GeoIP-BE-next"] } on-error={}\n')
    for prefix in prefixes:
        output.write('/ip firewall address-list add '
                     f'list="GeoIP-BE-next" address={prefix} '
                     'comment="GeoIP generated"\n')
    output.write(':local imported [/ip firewall address-list print '
                 'count-only where list="GeoIP-BE-next"]\n')
    output.write(':if ($imported < 100) do={ '
                 ':error "Liste GeoIP trop courte" }\n')
    output.write('/ip firewall address-list remove '
                 '[find where list="GeoIP-BE"]\n')
    output.write(':foreach id in=[/ip firewall address-list find '
                 'where list="GeoIP-BE-next"] do={ '
                 '/ip firewall address-list set numbers=$id '
                 'list="GeoIP-BE" }\n')
    output.write(':log info ("GeoIP: aktive Liste, " . '
                 '$imported . " prefixes")\n')
PY

chmod 0644 "$PUBLISH_TMP"
mv -f "$PUBLISH_TMP" "$FINAL_FILE"
PUBLISH_TMP=""
echo "Veroeffentlicht: $FINAL_FILE"

Um eine größere Zone zu erstellen, ersetzen Sie COUNTRIES=(be) durch COUNTRIES=(be fr nl lu) und passen Sie die Namen GeoIP-BE und GeoIP-BE-next an. Beginnen Sie mit einer einzigen Zone : Eine erweiterte Liste erhöht die Importzeit und den verwendeten Speicher.

Warum dieser Generator sicherer ist

  • curl --fail wandelt einen HTTP-Fehler in einen Fehlschlag um, anstatt eine Fehlerseite als Liste zu speichern ;
  • ipaddress lehnt eine ungültige CIDR-Syntax ab und überprüft, ob es sich tatsächlich um IPv4 handelt ;
  • ein Mindestschwellenwert verhindert die Veröffentlichung einer leeren oder offensichtlich unvollständigen Datei ;
  • die öffentliche Datei wird erst nach vollständiger Generierung ersetzt ;
  • die RouterOS-Datei lädt zuerst GeoIP-BE-next, überprüft ihr Volumen und wechselt dann zu GeoIP-BE.

Führen Sie den Generator manuell aus, überprüfen Sie die veröffentlichte Datei und planen Sie ihn dann täglich auf dem Server. Bewahren Sie die Protokolle auf und löschen Sie nicht sofort die letzte als gültig bekannte Version.

Testen des Imports auf MikroTik

Vor jeder Automatisierung exportieren Sie die Firewall und aktivieren Sie den Safe Mode. Ersetzen Sie die untenstehende Dokumentationsdomäne durch Ihre eigene HTTPS-URL.

/ip firewall export file=avant-geoip
/system backup save name=avant-geoip
/tool fetch \
    url="https://updates.example.net/geoip/GeoIP-BE.rsc" \
    output=file dst-path="GeoIP-BE.rsc"

/import file-name="GeoIP-BE.rsc" verbose=yes dry-run=yes
/import file-name="GeoIP-BE.rsc" verbose=yes

Der Modus dry-run des Imports ist in den aktuellen Versionen von RouterOS 7 verfügbar. Er analysiert die Datei, ohne die Konfiguration zu ändern. Die Umgebung dieses Leitfadens zielt auf RouterOS 7.16 oder eine höhere Version ab.

/ip firewall address-list print count-only where list="GeoIP-BE"
/ip firewall address-list print where list="GeoIP-BE"
/log print where message~"GeoIP"

Ein belgischer Import erzeugt normalerweise weit mehr als hundert Präfixe. Der Schwellenwert dient lediglich als Schutz gegen einen offensichtlichen Ausfall ; er beweist weder die Vollständigkeit noch die geografische Qualität des Datensatzes.

Automatisieren des Downloads in RouterOS

Erstellen Sie ein Skript namens update-geoip mit den Richtlinien ftp, read, write, policy und test. Die Richtlinie ftp ist für Dateioperationen erforderlich, auch wenn der Download selbst HTTPS verwendet.

:local geoUrl "https://updates.example.net/geoip/GeoIP-BE.rsc"
:local geoFile "GeoIP-BE.rsc"

:do { /file remove [find where name=$geoFile] } on-error={}

:do {
    /tool fetch url=$geoUrl output=file dst-path=$geoFile
    /import file-name=$geoFile verbose=yes dry-run=yes
    /import file-name=$geoFile verbose=yes
    :log info "GeoIP: Aktualisierung abgeschlossen"
} on-error={
    :log error "GeoIP: fehlgeschlagen, alte Liste beibehalten"
}

Die importierte Datei arbeitet mit der temporären Liste. Ein Download-Ausfall, ein Syntaxfehler oder ein anormales Volumen unterbricht den Vorgang vor der Löschung von GeoIP-BE.

Planen Sie nach einem erfolgreichen manuellen Test die Ausführung einmal pro Tag zu einer Zeit, in der der Router wenig belastet ist.

/system scheduler add \
    name=update-geoip-daily \
    start-time=05:40:00 interval=1d \
    on-event="/system script run update-geoip" \
    policy=ftp,read,write,policy,test \
    comment="GeoIP-Liste aktualisieren"

Anwenden der Liste an der richtigen Stelle

Die Kette input verarbeitet den Verkehr, der für den Router selbst bestimmt ist. Die Kette forward verarbeitet den Verkehr, der das MikroTik durchquert, um einen internen Server zu erreichen. Eine GeoIP-Regel, die nur in input platziert wird, schränkt also keinen Server ein, der über dst-nat veröffentlicht wird.

Fall 1 : Beschränken des Zugriffs auf ein auf dem Router gehostetes VPN

Das Beispiel erlaubt einen WireGuard-Einstiegspunkt auf UDP 51820 aus der GeoIP-Liste. Es geht davon aus, dass weiter unten eine Regel zum Ablehnen des WAN-Verkehrs zum Router existiert. Veröffentlichen Sie WinBox oder WebFig nicht direkt im Internet.

/ip firewall address-list
add list=GeoIP-TRUSTED address=198.51.100.10 \
    comment="Notfalladresse - Beispiel RFC 5737"

/ip firewall filter
add chain=input action=accept in-interface-list=WAN \
    protocol=udp dst-port=51820 \
    src-address-list=GeoIP-TRUSTED \
    comment="VPN: Notfallzugang"

add chain=input action=accept in-interface-list=WAN \
    protocol=udp dst-port=51820 \
    src-address-list=GeoIP-BE \
    comment="VPN: GeoIP-Zone erlauben"

Ersetzen Sie die Dokumentationsadresse durch eine echte, kontrollierte Fallback-Adresse. Platzieren Sie die Regeln nach der Akzeptanz von established,related und der Ablehnung von invalid-Paketen, aber vor der allgemeinen WAN-Ablehnung.

Fall 2 : Beschränken eines über dst-nat veröffentlichten Servers

Die folgende Regel verwirft neue TCP-Verbindungen zum öffentlichen Port 443, wenn diese nicht zu GeoIP-BE gehören. Eine davor platzierte Fallback-Regel ermöglicht eine explizite Ausnahme.

/ip firewall filter
add chain=forward action=accept in-interface-list=WAN \
    connection-state=new connection-nat-state=dstnat \
    protocol=tcp dst-port=443 \
    src-address-list=GeoIP-TRUSTED \
    comment="Server: Notfallzugang"

add chain=forward action=drop in-interface-list=WAN \
    connection-state=new connection-nat-state=dstnat \
    protocol=tcp dst-port=443 \
    src-address-list=!GeoIP-BE \
    comment="Server: ausserhalb GeoIP-Zone ablehnen"

Fügen Sie diese Regeln vor einer eventuellen allgemeinen Akzeptanz von dstnat-Verbindungen ein. Der Port muss der öffentliche Port sein, der vom Filter gesehen wird. Wenn der externe Port 8443 auf 443 übersetzt wird, verwenden Sie 8443 in diesem Kriterium.

Testen, ohne sich selbst auszusperren

  1. Arbeiten Sie aus dem LAN und aktivieren Sie den Safe Mode.
  2. Fügen Sie zuerst Ihren Fallback-Zugriff in GeoIP-TRUSTED hinzu.
  3. Importieren Sie die Liste und überprüfen Sie ihre Anzahl an Einträgen, bevor Sie eine Ablehnungsregel hinzufügen.
  4. Testen Sie von einer externen Verbindung aus der erlaubten Zone.
  5. Testen Sie dann von einem anderen kontrollierten Ausgang, z. B. einem mobilen Zugang oder einem Labor-VPN.
  6. Überprüfen Sie die Zähler, ohne ein Protokoll pro Paket zu aktivieren.
  7. Verlassen Sie den Safe Mode erst, wenn der Dienst und der Fallback-Pfad funktionieren.
/ip firewall filter print stats where comment~"GeoIP|zone"
/ip firewall address-list print count-only where list="GeoIP-BE"
/system resource print
/log print where message~"GeoIP"

Grenzen und häufige Fehler

  • Zuteilung mit Standort verwechseln : ein in Belgien registriertes Präfix kann woanders angekündigt oder verwendet werden.
  • Eine Zone als Identitätsnachweis zulassen : ein Relay in der Zone passiert denselben Filter wie ein legitimer Benutzer.
  • Die aktive Liste vor dem Download löschen : ein Ausfall verwandelt einen restriktiven Filter in eine vollständige Sperrung.
  • Download über HTTP : eine Sicherheitsliste muss über HTTPS aus einer kontrollierten Quelle transportiert werden.
  • Import ohne dry-run : ein Syntaxfehler kann ein partielles Update hinterlassen.
  • Die Regel in input für einen internen Server platzieren : der veröffentlichte Verkehr durchquert forward.
  • IPv6 vergessen : eine IPv4-Regel schützt keinen Dienst, der auch über IPv6 erreichbar ist.
  • Zu viele Zonen laden : große Listen verlangsamen den Import und verbrauchen die Ressourcen des Routers.
  • Jede Ablehnung protokollieren : verwenden Sie die Regelzähler, um eine Protokollüberlastung zu vermeiden.

Generieren Sie für IPv6 eine separate Liste aus ipv6-aggregated.txt, importieren Sie diese in /ipv6 firewall address-list und erstellen Sie die entsprechenden Regeln in /ipv6 firewall filter. Lassen Sie IPv6 nicht zu einem unbeabsichtigten Umweg werden.

Fazit

Zuverlässiges GeoIP-Filtering auf MikroTik beruht weniger auf der Anzahl der blockierten Länder als auf der Qualität der Update-Kette. Die Daten müssen über HTTPS abgerufen, als CIDR-Netzwerke validiert, atomar veröffentlicht, als Probelauf importiert und vor jedem Wechsel in eine temporäre Liste geladen werden.

Sobald diese Basis solide ist, wird die Address-List zu einem einfachen Kriterium der Firewall : input für einen Dienst des Routers, forward für einen veröffentlichten Server. Die Maßnahme reduziert Rauschen und Exposition, behält aber absichtlich einen sekundären Platz hinter VPN, Authentifizierung, Updates und einer minimalen Firewall-Richtlinie.

Technische Referenzen

Über den Autor

Jeremy Kraft betreut die Infrastruktur und die selbst gehosteten Dienste des IBCSC. Diese Anleitungen beschreiben Konfigurationen, die tatsächlich im Einsatz waren und vor der Veröffentlichung erneut geprüft wurden.

Diskussion

Kommentare

0

Noch kein Kommentar. Eröffnen Sie die Diskussion gern mit einer Frage oder Ihrem eigenen Erfahrungsbericht.

Sie haben ein Konto? Anmelden

Reiner Text, höchstens 2 000 Zeichen. Neue Kommentare werden moderiert. Ihr Name wird mit dem Kommentar angezeigt. Es wird keine E-Mail-Adresse abgefragt; gegen Spam wird nur ein nicht umkehrbarer Fingerabdruck Ihrer IP-Adresse gespeichert.