Proxy-Option fuer Zonefile-Abruf (Host ohne direkte Internetverbindung)

This commit is contained in:
ARIA
2026-07-21 12:08:30 +00:00
parent 8d5908ac78
commit cd9addbec1
2 changed files with 64 additions and 5 deletions
+37
View File
@@ -245,6 +245,11 @@ Siehe Kommentare in der Datei selbst — kurz:
einzelner Ports" unten. einzelner Ports" unten.
- `protocol`: nur relevant wenn `ports` gesetzt ist — `tcp` (Default), `udp` - `protocol`: nur relevant wenn `ports` gesetzt ist — `tcp` (Default), `udp`
oder `tcp,udp` oder `tcp,udp`
- `proxy`: optional, HTTP(S)-Proxy fuer den Abruf der Zonefiles von ipdeny.com
(z.B. `http://10.0.0.5:3128`, mit Auth `http://user:pass@host:port`). Nur
noetig, wenn der Host selbst keine direkte Internetverbindung hat, aber
ueber einen Proxy raus kann. Leer lassen = direkte Verbindung (Standard).
Siehe Abschnitt "Proxy fuer den Zonefile-Abruf" unten.
Abschnitt `[testserver]` (fuer `geoblock_testserver.py`): Abschnitt `[testserver]` (fuer `geoblock_testserver.py`):
@@ -295,3 +300,35 @@ Fuer einen sauberen End-to-End-Test der iptables-Regeln selbst (ohne Fragen
zu Proxy-Ketten/CDN reinzumischen) ist Variante 1 — Testmaschine direkt mit zu Proxy-Ketten/CDN reinzumischen) ist Variante 1 — Testmaschine direkt mit
eigener oeffentlicher IP, Geoblocking direkt auf dieser Maschine — der eigener oeffentlicher IP, Geoblocking direkt auf dieser Maschine — der
einfachste und eindeutigste Weg. einfachste und eindeutigste Weg.
## Proxy fuer den Zonefile-Abruf (`proxy` in `geoblock.ini`)
**Wichtig — das ist ein ANDERES Thema als der Reverse-Proxy-Abschnitt oben.**
Dort ging es darum, wo die *eingehende* Client-Verbindung ankommt. Hier geht
es darum, wie `geoblock.py` selbst *ausgehend* die Zonefiles von ipdeny.com
laedt.
**Wann noetig:** Manche Hosts sind zwar aus dem Internet erreichbar (z.B.
ueber einen vorgelagerten Reverse-Proxy oder eine Firewall mit Portweiterleitung),
haben aber selbst **keine direkte ausgehende Internetverbindung** — nur einen
Weg ueber einen internen HTTP(S)-Proxy nach draussen. Ohne diesen Proxy kann
`geoblock.py` `https://www.ipdeny.com/...` nicht erreichen und bricht mit
einem URL-Fehler ab.
**Konfiguration** in `geoblock.ini`, Abschnitt `[geoblock]`:
```ini
[geoblock]
countries = de
proxy = http://10.0.0.5:3128
; mit Basic-Auth am Proxy:
; proxy = http://user:pass@10.0.0.5:3128
```
Der Proxy wird sowohl fuer HTTP- als auch HTTPS-Abrufe genutzt (ipdeny liefert
per HTTPS aus). Leer lassen (Standard) = das Script verbindet sich direkt,
ohne Proxy — das ist der Normalfall auf den meisten Servern.
Betroffen ist **nur** der Abruf der Zonefiles beim Ausfuehren von
`--apply`/`--update`. iptables/ipset selbst und der Testserver brauchen dafuer
keinen Proxy — die filtern nur lokal am Kernel-Paketfilter.
+27 -5
View File
@@ -20,6 +20,8 @@ VORAUSSETZUNGEN (auf dem Ziel-Host, NICHT im Container):
- Pakete installiert: iptables, ipset - Pakete installiert: iptables, ipset
Debian/Ubuntu: apt install iptables ipset Debian/Ubuntu: apt install iptables ipset
- Internetzugang zum Laden der Zonefiles von ipdeny.com - Internetzugang zum Laden der Zonefiles von ipdeny.com
(falls der Host selbst keine direkte Verbindung hat: 'proxy' in der
.ini setzen -- siehe README)
BENUTZUNG: BENUTZUNG:
sudo python3 geoblock.py --config geoblock.ini --apply sudo python3 geoblock.py --config geoblock.ini --apply
@@ -167,6 +169,7 @@ def load_config(path):
"log_file": sec.get("log_file", "").strip(), "log_file": sec.get("log_file", "").strip(),
"ports": ports, "ports": ports,
"protocols": protocols, "protocols": protocols,
"proxy": sec.get("proxy", "").strip(),
} }
@@ -213,12 +216,31 @@ def _variant_label(variant):
return f"{variant['proto']}/{variant['dports']}" return f"{variant['proto']}/{variant['dports']}"
def fetch_country_cidrs(country_code): def _build_url_opener(proxy):
"""Laedt die CIDR-Liste eines Landes von ipdeny.com. Gibt Liste von Strings zurueck.""" """Baut einen urllib-Opener. Mit 'proxy' gesetzt (z.B. 'http://host:3128' oder
'http://user:pass@host:3128') wird dieser fuer http UND https genutzt -- fuer
Server, die selbst keine direkte Internetverbindung haben und nur ueber
einen Vorgelagerten Proxy raus koennen."""
if not proxy:
return urllib.request.build_opener()
handler = urllib.request.ProxyHandler({"http": proxy, "https": proxy})
return urllib.request.build_opener(handler)
def fetch_country_cidrs(country_code, proxy=""):
"""Laedt die CIDR-Liste eines Landes von ipdeny.com. Gibt Liste von Strings zurueck.
'proxy' (optional): HTTP(S)-Proxy-URL, falls der Server selbst keine direkte
Internetverbindung hat und ipdeny.com nur ueber einen Proxy erreichen kann.
"""
url = ZONE_URL_TMPL.format(cc=country_code) url = ZONE_URL_TMPL.format(cc=country_code)
log(f"Lade IP-Ranges fuer '{country_code}' von {url}") if proxy:
log(f"Lade IP-Ranges fuer '{country_code}' von {url} (ueber Proxy {proxy})")
else:
log(f"Lade IP-Ranges fuer '{country_code}' von {url}")
opener = _build_url_opener(proxy)
try: try:
with urllib.request.urlopen(url, timeout=20) as resp: with opener.open(url, timeout=20) as resp:
text = resp.read().decode("utf-8", errors="ignore") text = resp.read().decode("utf-8", errors="ignore")
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
raise RuntimeError( raise RuntimeError(
@@ -276,7 +298,7 @@ def apply_geoblock(cfg, dry_run=False):
# 2) alle CIDRs aller konfigurierten Laender sammeln # 2) alle CIDRs aller konfigurierten Laender sammeln
all_cidrs = [] all_cidrs = []
for cc in cfg["countries"]: for cc in cfg["countries"]:
all_cidrs.extend(fetch_country_cidrs(cc)) all_cidrs.extend(fetch_country_cidrs(cc, proxy=cfg.get("proxy", "")))
if not all_cidrs and not dry_run: if not all_cidrs and not dry_run:
raise RuntimeError("Keine IP-Bereiche geladen — Abbruch, um kein leeres Set zu aktivieren") raise RuntimeError("Keine IP-Bereiche geladen — Abbruch, um kein leeres Set zu aktivieren")