Files
2026-08-05 04:15:47 +02:00

159 lines
5.0 KiB
Markdown

# 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:
```
<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 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`) |