Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
country-resolve — Logfile Country Resolver
Ein kleiner Stream-Filter, der Logzeilen von stdin liest, die erste Spalte als IP-Adresse interpretiert und die Zeile um Kontinent und Land anreichert wieder auf stdout ausgibt.
Die Auflösung erfolgt offline über eine lokale
DB-IP Country Lite MMDB-Datenbank
(gelesen via geoip2).
Typischer Einsatzzweck: Webserver-Access-Logs nach Herkunftsland filtern und daraus z. B. CrowdSec-Blockentscheidungen ableiten.
Funktionsweise
Für jede Eingabezeile:
- Zeile an Leerzeichen zerlegen,
parts[0]ist die IP. - IP gegen die MMDB auflösen →
continent.code(z. B.EU) undcountry.name(z. B.Germany). - Nicht auflösbare IPs (
AddressNotFoundError) werden als LandUnknownmarkiert. - Ausgabe: alle Felder pipe-separiert (
|), mit Kontinent und Land vorangestellt:
<Kontinent>|<Land>|<originalfeld1>|<originalfeld2>|...
Fehlerhafte Einzelzeilen werden übersprungen (kein Abbruch des Streams).
Ausgabeformat
EU|Germany|93.229.122.46|-|-|[27/Feb/2025:00:00:02|+0100]|"GET|/pages/...|HTTP/1.1"|200|...
| Feld 1 | Feld 2 | ab Feld 3 |
|---|---|---|
Kontinent-Code (EU, AS, NA, …) |
Ländername (Germany, Unknown, …) |
die ursprünglichen, an Leerzeichen getrennten Felder |
Voraussetzungen
- Python ≥ 3.13 (siehe
.python-version) - Python-Paket
geoip2(als Abhängigkeit inpyproject.tomldeklariert) - Eine MMDB-Datei namens
dbip-country-lite-2025-02.mmdbim Arbeitsverzeichnis (Pfad ist inresolver.pyfest verdrahtet). MMDB-Dateien sind per.gitignorevom Repository ausgeschlossen und müssen separat bezogen werden.
Installation
Mit uv — installiert die in pyproject.toml deklarierten Abhängigkeiten:
uv sync
Oder klassisch mit pip:
python3 -m venv .venv
source .venv/bin/activate
pip install geoip2
MMDB-Datenbank besorgen
Die Lite-Datenbank kostenlos bei DB-IP herunterladen und passend benennen:
# Beispiel (Dateiname muss zur Konstante in resolver.py passen)
mv dbip-country-lite-2025-02.mmdb ./dbip-country-lite-2025-02.mmdb
Für eine andere/aktuellere DB den Pfad in resolver.py (Zeile mit geoip2.database.Reader(...))
anpassen.
Benutzung
Einzelne Zeile auflösen
head -1 access_crowdsec.log
# 93.229.122.46 - - [27/Feb/2025:00:00:02 +0100] "GET /pages/images/website/home/2502-01.jpg HTTP/1.1" 200 60233 "https://www.plainpicture.com/de" "Mozilla/5.0 ..."
head -1 access_crowdsec.log | ./resolver
# EU|Germany|93.229.122.46|-|-|[27/Feb/2025:00:00:02|+0100]|"GET|/pages/images/website/home/2502-01.jpg|HTTP/1.1"|200|...
./resolver ist das gepackte Binary (siehe Packaging). Alternativ direkt über Python:
head -1 access_crowdsec.log | python3 resolver.py
Anwendungsbeispiel: Länder-basiertes Blocking mit CrowdSec
Access-Log streamen, auf interessante Requests filtern, Herkunft auflösen und nach bestimmten Ländern/Kontinenten filtern:
cat access_crowdsec.log \
| stdbuf -o0 grep "/search" \
| grep -v "Safari/" \
| stdbuf -o0 /tmp/resolver \
| stdbuf -o0 egrep "Russia|Belarus|^SA|^AS|^AF" \
> block_20250227.txt
Aus den Treffern /16-Netze ableiten und als CrowdSec-Decisions importieren:
cscli decisions delete --all
cat block_20250227.txt \
| cut -d"|" -f3 \
| perl -ne 's/(\d+)\.(\d+)\..*/$1.$2/; print ' \
| uniq \
| perl -ne 'chomp; print $_,".0.0/16\n"' \
| cscli decisions import -i - --format values -d48h -R toomuch_AS_SA_AF
stdbuf -o0erzwingt ungepuffertes Streaming, damit die Pipeline zeilenweise (nahezu in Echtzeit) durchläuft.
Packaging
Ein eigenständiges Binary (ohne Python-Runtime auf dem Zielsystem) mit PyInstaller erzeugen:
pyinstaller --onefile resolver.py
# oder mit der mitgelieferten Spec-Datei:
pyinstaller resolver.spec
Das Ergebnis liegt anschließend unter dist/resolver und kann z. B. nach /tmp/resolver
kopiert und in Pipelines eingesetzt werden.
Die MMDB-Datei wird nicht ins Binary eingebettet — sie muss zur Laufzeit im Arbeitsverzeichnis liegen (bzw. der Pfad in
resolver.pyentsprechend gesetzt sein).
Projektdateien
| Datei | Zweck |
|---|---|
resolver.py |
Der eigentliche Stream-Filter |
resolver.spec |
PyInstaller-Spezifikation für das --onefile-Binary |
pyproject.toml |
Projekt-Metadaten (Python ≥ 3.13) |
.python-version |
Fixierte Python-Version (3.13) |
*.mmdb |
GeoIP-Datenbank (nicht im Repo, per .gitignore) |