diff --git a/README.md b/README.md index d9b874a..08a2ebc 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,18 @@ unten. das ipset atomar per `swap`, damit waehrend der Aktualisierung kein Loch im Blocking entsteht. +**Aufraeumen bei jedem Lauf:** `--apply` (und damit auch jeder Neustart von +`geoblock.service`) entfernt zuerst **alle** bestehenden geoblock-Regeln und +setzt sie danach frisch. Gescannt werden dabei die konfigurierten Chains **plus** +die Standard-Filter-Chains INPUT/FORWARD/OUTPUT — es werden ausschliesslich +Regeln geloescht, die auf das eigene `ipset` verweisen (fremde Regeln bleiben +unberuehrt). Dadurch verschwinden automatisch auch Reste aus frueheren Laeufen +mit **anderer Config**: geaenderte `ports`/`protocol` ebenso wie eine geaenderte +`chain`. Konkret heisst das: Stellst du z.B. von `chain = INPUT` auf +`chain = FORWARD` um und startest den Dienst neu, werden die alten INPUT-Regeln +automatisch entfernt — du musst nicht von Hand aufraeumen. (Gleiches gilt fuer +`--remove`, das ebenfalls diesen Purge nutzt.) + **Achtung:** iptables-Regeln sind nicht reboot-persistent. Wer das zusaetzlich braucht: `iptables-persistent` / `netfilter-persistent save` nutzen — der systemd-Timer sorgt aber ohnehin bei jedem Boot fuer einen diff --git a/geoblock.py b/geoblock.py index ae98e4c..0fef7d7 100755 --- a/geoblock.py +++ b/geoblock.py @@ -78,6 +78,13 @@ import urllib.error ZONE_URL_TMPL = "https://www.ipdeny.com/ipblocks/data/countries/{cc}.zone" +# Standard-Filter-Chains, die beim Aufraeumen IMMER mitgescannt werden -- auch +# wenn sie gerade nicht in 'chain' konfiguriert sind. So werden verwaiste +# geoblock-Regeln entfernt, wenn 'chain' zwischen zwei Laeufen geaendert wurde +# (z.B. von INPUT auf FORWARD umgestellt). Rein additiv zum Scan: es werden nur +# Regeln geloescht, die auf UNSER ipset verweisen -- fremde Regeln bleiben unberuehrt. +STANDARD_FILTER_CHAINS = ("INPUT", "FORWARD", "OUTPUT") + # Wird in main() aus der .ini gesetzt (log_file). None = keine Datei-Logs. LOG_FILE = None @@ -308,20 +315,27 @@ def _list_chain_rules(chain): def purge_geoblock_rules(cfg, dry_run=False): - """Loescht in ALLEN konfigurierten Chains alle Regeln, die auf das geoblock-ipset - verweisen (--match-set src) -- unabhaengig von Proto/Port/Variante. + """Loescht in allen konfigurierten Chains PLUS den Standard-Filter-Chains + (INPUT/FORWARD/OUTPUT) alle Regeln, die auf das geoblock-ipset verweisen + (--match-set src) -- unabhaengig von Proto/Port/Variante. Dadurch werden auch alte Regeln aus frueheren --apply-Laeufen mit anderer - ini (z.B. andere Ports/Protokolle) sauber entfernt, die build_rule_variants(cfg) - fuer die AKTUELLE Config gar nicht mehr kennt. Wir rekonstruieren das Loesch- - Kommando direkt aus 'iptables -S' (per shlex, damit z.B. das --log-prefix mit - Leerzeichen erhalten bleibt), statt die Args selbst nachzubauen -- so passt das - -D immer exakt zur real existierenden Regel. + ini sauber entfernt: andere Ports/Protokolle (kennt build_rule_variants(cfg) + nicht mehr) UND andere Chains (z.B. nach Umstellung von INPUT auf FORWARD -- + die verwaisten INPUT-Regeln werden dank Standard-Chain-Scan trotzdem gefunden). + Wir rekonstruieren das Loesch-Kommando direkt aus 'iptables -S' (per shlex, + damit z.B. das --log-prefix mit Leerzeichen erhalten bleibt), statt die Args + selbst nachzubauen -- so passt das -D immer exakt zur real existierenden Regel. """ name = cfg["ipset_name"] needle = f"--match-set {name} src" + # Konfigurierte Chains PLUS die Standard-Filter-Chains scannen (dedupliziert, + # Reihenfolge erhalten). Faengt auch verwaiste Regeln ab, wenn 'chain' seit dem + # letzten Lauf geaendert wurde (z.B. INPUT -> FORWARD): die alten INPUT-Regeln + # werden trotzdem gefunden und entfernt. + scan_chains = list(dict.fromkeys(list(cfg["chains"]) + list(STANDARD_FILTER_CHAINS))) removed = 0 - for chain in cfg["chains"]: + for chain in scan_chains: n = 0 for line in _list_chain_rules(chain): if needle not in line: @@ -334,7 +348,7 @@ def purge_geoblock_rules(cfg, dry_run=False): log(f"{n} bestehende geoblock-Regel(n) aus Chain '{chain}' entfernt (Set '{name}')") removed += n if not removed: - log(f"Keine bestehenden geoblock-Regeln in Chains {cfg['chains']} gefunden") + log(f"Keine bestehenden geoblock-Regeln gefunden (gescannt: {', '.join(scan_chains)})") return removed