geoblock: match_original_dport (conntrack --ctorigdstport) fuer Dienste hinter DNAT
Bei Portweiterleitung/DNAT schreibt der Kernel den Zielport in PREROUTING um, BEVOR der Filter laeuft -- eine Regel auf den oeffentlichen Port (z.B. 1194) matcht dann nie, weil im Filter der interne Port (z.B. 6666/6667) ankommt. Genau der Fall auf Endian-Appliances (public 1194 -> intern 6666-6667, 443 -> 30443). Neue Option 'match_original_dport = true': matcht per 'conntrack --ctorigdstport' den urspruenglichen Zielport (vor DNAT). Dann in 'ports' die OEFFENTLICHEN Ports eintragen -- immun gegen den internen Remap. - build_rule_variants: bei orig-dport eine Regel pro (proto, port), da conntrack --ctorigdstport einwertig ist (kein multiport). _variant_port_args nutzt dann conntrack statt multiport. - load_config: match_original_dport (bool, default false). - show_status zeigt den Match-Modus an. - Doku: geoblock.ini.example + README-Abschnitt "Dienst hinter Portweiterleitung/DNAT". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
af2a75c443
commit
161d90de45
@@ -352,6 +352,60 @@ genauso wie in INPUT, weil DNAT nur das Ziel umschreibt, nicht die Quelle.
|
||||
> Ort. Kombiniere das am besten mit dem Reassert-Watchdog (Abschnitt oben), da
|
||||
> die Appliance auch die FORWARD-Chain bei jedem Reload neu baut.
|
||||
|
||||
## Dienst hinter Portweiterleitung/DNAT (`match_original_dport`)
|
||||
|
||||
Noch eine Stolperfalle bei Firewalls/Routern mit Portweiterleitung — und zwar
|
||||
eine gemeine, weil Chain und Regel-Position stimmen koennen und es **trotzdem**
|
||||
nicht blockt: **der Zielport wird durch DNAT umgeschrieben, bevor der Filter
|
||||
laeuft.**
|
||||
|
||||
Reihenfolge im Kernel:
|
||||
|
||||
```
|
||||
PREROUTING (nat/DNAT: schreibt Ziel-IP/Port um) -> Routing -> INPUT/FORWARD (filter: unsere DROP-Regel)
|
||||
```
|
||||
|
||||
Beispiel Endian-OpenVPN: aussen kommt `udp/1194` an, die Appliance macht per DNAT
|
||||
`1194 -> 6666-6667` (interner OpenVPN-Daemon). Wenn das Paket die FORWARD-/INPUT-
|
||||
Chain erreicht, hat es als Zielport laengst **6666/6667**, nicht mehr 1194. Eine
|
||||
Regel mit `ports = 1194` matcht dann **nie** — obwohl Set, Chain und Position
|
||||
stimmen. (Gleiches Muster fuer Web: `443 -> 30443` o.ae.)
|
||||
|
||||
Wie man das erkennt — auf dem Firewall-Host die DNAT-Regeln ansehen:
|
||||
|
||||
```bash
|
||||
sudo iptables -t nat -L PREROUTING -n -v # zeigt meist nur Spruenge in Sub-Chains
|
||||
sudo iptables -t nat -L PORTFW -n -v # (Endian) Portweiterleitungen
|
||||
sudo iptables -t nat -L PROXIES -n -v # (Endian) weitere DNAT/Proxy-Regeln
|
||||
# gesucht: eine DNAT-Zeile mit 'dpt:<oeffentlicher-port>' und 'to:<intern>:<anderer-port>'
|
||||
```
|
||||
|
||||
**Zwei Loesungen:**
|
||||
|
||||
1. **Den umgeschriebenen Port matchen** — `ports` auf den *internen* Port setzen
|
||||
(im Beispiel `6666:6667`). Funktioniert, ist aber fragil: aendert die Appliance
|
||||
den internen Port (Update/Umbau), musst du es nachziehen.
|
||||
2. **Empfohlen: `match_original_dport = true`** — matcht per `conntrack
|
||||
--ctorigdstport` den Port, den der **Client** gewaehlt hat (vor DNAT). Dann
|
||||
traegst du in `ports` die **oeffentlichen** Ports ein und bist immun gegen den
|
||||
internen Remap:
|
||||
|
||||
```ini
|
||||
[geoblock]
|
||||
chain = INPUT, FORWARD
|
||||
ports = 1194, 443
|
||||
protocol = tcp, udp
|
||||
match_original_dport = true
|
||||
```
|
||||
|
||||
Der `src`-Match (echte Client-IP) funktioniert in beiden Faellen, weil DNAT nur
|
||||
das Ziel umschreibt, nicht die Quelle — vorausgesetzt es ist echtes DNAT und kein
|
||||
terminierender L7-Proxy (der wuerde die Verbindung neu aufbauen, dann sieht der
|
||||
Filter die Proxy-IP statt der des Clients; siehe Reverse-Proxy-Abschnitt).
|
||||
|
||||
`--status` zeigt den aktiven Match-Modus an (`Zielport (dports)` vs.
|
||||
`Original-Zielport vor DNAT (conntrack)`).
|
||||
|
||||
## Verbindungstest (Test-Webserver)
|
||||
|
||||
`geoblock_testserver.py` ist ein winziger HTTP-Server ohne
|
||||
@@ -482,6 +536,11 @@ Siehe Kommentare in der Datei selbst — kurz:
|
||||
einzelner Ports" unten.
|
||||
- `protocol`: nur relevant wenn `ports` gesetzt ist — `tcp` (Default), `udp`
|
||||
oder `tcp,udp`
|
||||
- `match_original_dport`: `true`/`false` (Default `false`), nur relevant wenn
|
||||
`ports` gesetzt ist. Fuer Dienste hinter einer Portweiterleitung/DNAT: matcht
|
||||
den **urspruenglichen** Zielport (vor DNAT) statt des umgeschriebenen. Dann in
|
||||
`ports` die oeffentlichen Ports eintragen. Siehe Abschnitt "INPUT vs FORWARD"
|
||||
bzw. "Dienst hinter Portweiterleitung/DNAT" unten.
|
||||
- `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
|
||||
|
||||
Reference in New Issue
Block a user