geoblock: purge scannt zusaetzlich INPUT/FORWARD/OUTPUT (Chain-Wechsel raeumt Reste auf)

purge_geoblock_rules() scannt jetzt die konfigurierten Chains PLUS die Standard-
Filter-Chains INPUT/FORWARD/OUTPUT. Damit werden verwaiste geoblock-Regeln auch
dann entfernt, wenn 'chain' zwischen zwei Laeufen geaendert wurde (z.B. INPUT ->
FORWARD) -- vorher blieben die alten Regeln der nicht mehr konfigurierten Chain
stehen. Es werden nur Regeln geloescht, die auf das eigene ipset verweisen.

README: Abschnitt "Manuelle Nutzung" um die Aufraeum-Semantik ergaenzt (jeder
--apply/Service-Restart entfernt alle geoblock-Regeln und setzt sie frisch,
inkl. Reste aus geaenderter ports/protocol/chain-Config).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-07-23 12:05:15 +02:00
co-authored by Claude Opus 4.8
parent da83f351d7
commit af2a75c443
2 changed files with 35 additions and 9 deletions
+12
View File
@@ -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
+23 -9
View File
@@ -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 <name> 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 <name> 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