# 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](https://db-ip.com/db/download/ip-to-country-lite) MMDB-Datenbank (gelesen via [`geoip2`](https://pypi.org/project/geoip2/)). Typischer Einsatzzweck: Webserver-Access-Logs nach Herkunftsland filtern und daraus z. B. [CrowdSec](https://www.crowdsec.net/)-Blockentscheidungen ableiten. --- ## Funktionsweise Für jede Eingabezeile: 1. Zeile an Leerzeichen zerlegen, `parts[0]` ist die IP. 2. IP gegen die MMDB auflösen → `continent.code` (z. B. `EU`) und `country.name` (z. B. `Germany`). 3. Nicht auflösbare IPs (`AddressNotFoundError`) werden als Land `Unknown` markiert. 4. Ausgabe: alle Felder **pipe-separiert** (`|`), mit Kontinent und Land vorangestellt: ``` ||||... ``` 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 in `pyproject.toml` deklariert) - Eine **MMDB-Datei** namens `dbip-country-lite-2025-02.mmdb` im Arbeitsverzeichnis (Pfad ist in `resolver.py` fest verdrahtet). MMDB-Dateien sind per `.gitignore` vom Repository ausgeschlossen und müssen separat bezogen werden. --- ## Installation Mit [uv](https://docs.astral.sh/uv/) — installiert die in `pyproject.toml` deklarierten Abhängigkeiten: ```bash uv sync ``` Oder klassisch mit pip: ```bash 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: ```bash # 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 ```bash 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](#packaging)). Alternativ direkt über Python: ```bash 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: ```bash 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: ```bash 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 -o0` erzwingt ungepuffertes Streaming, damit die Pipeline zeilenweise (nahezu > in Echtzeit) durchläuft. --- ## Packaging Ein eigenständiges Binary (ohne Python-Runtime auf dem Zielsystem) mit [PyInstaller](https://pyinstaller.org/) erzeugen: ```bash 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.py` entsprechend 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`) |