
Ich versuche, den Client-Verkehr auf den NodePort eines Kubernetes-Clusters umzuleiten, der auf lauscht 192.168.1.100.30000
.
Der Client muss eine Anfrage stellen, 192.168.1.100.8000
daher habe ich die folgende REDIRECT-Regel in iptables hinzugefügt:
iptables -t nat -I PREROUTING -p tcp --dst 192.168.1.100 --dport 8000 -j REDIRECT --to-port 30000
Ich führe dann einen Curl aus 192.168.1.100:8000
, sehe jedoch im TCPdump einen anderen Port:
# tcpdump -i lo -nnvvv host 192.168.1.100 and port 8000
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
[Interface: lo] 20:39:22.685968 IP (tos 0x0, ttl 64, id 20590, offset 0, flags [DF], proto TCP (6), length 40)
[Interface: lo] 192.168.1.100.8000 > 192.168.1.100.49816: Flags [R.], cksum 0xacda (correct), seq 0, ack 3840205844, win 0, length 0
[Interface: lo] 20:39:37.519256 IP (tos 0x0, ttl 64, id 34221, offset 0, flags [DF], proto TCP (6), length 40)
Ich würde erwarten, dass der TCPdump etwas wie
192.168.1.100.8000 > 192.168.1.100.30000
Es wird jedoch ein Fehler „Verbindung abgelehnt“ angezeigt und verursacht diesen, da kein Prozess aufgeführt ist 192.168.1.100.49816
.
192.168.1.100.8000 > 192.168.1.100.49816
Ich verwende eine Testumgebung und habe daher keinen Zugriff auf Remote-Geräte. Deshalb verwende ich curl
zum Testen den REDIRECT-Pfad von iptables.
Gibt es einen Grund, warum das Hinzufügen einer REDIRECT-Regel dazu führt, dass tcpdump den Datenverkehr an einen anderen Port als den angegebenen umleitet?
Bearbeiten:
Nach dem @AB-Vorschlag wurde die folgende OUTPUT-Regel hinzugefügt:
iptables -t nat -I OUTPUT -d 192.168.1.100 -p tcp --dport 8000 -j REDIRECT --to-port 30000
und curl fährt fort, die Paketanzahl für die OUTPUT-Kette steigt an (das Paket der PREROUTING REDIRECT-Kette stieg jedoch nicht an):
2 10 600 REDIRECT tcp -- * * 0.0.0.0/0 192.168.1.100 tcp dpt:8000 redir ports 30000
Es wird jedoch die folgende Fehlermeldung angezeigt:
# curl -vk https://192.168.1.100:8000/v1/api
* About to connect() to 192.168.1.100 port 8000 (#0)
* Trying 192.168.1.100...
* Connected to 192.168.1.100 (192.168.1.100) port 8000 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* NSS error -12263 (SSL_ERROR_RX_RECORD_TOO_LONG)
* SSL received a record that exceeded the maximum permissible length.
* Closing connection 0
curl: (35) SSL received a record that exceeded the maximum permissible length.
Habe außerdem versucht, ein Remotesystem-Netz hinzuzufügen. Dieses Mal erhöht sich die Paketanzahl der PREROUTING REDIRECT CHAIN nach der Ausführung remotesystem curl ...
(die OUTPUT CHAIN erhöht sich jedoch nicht):
2 34 2040 REDIRECT tcp -- * * 0.0.0.0/0 172.16.128.1 tcp dpt:8000 redir ports 30000
Fehler:
# ip netns exec remotesystem curl -vk https://192.168.1.100:8000/v1/api
* About to connect() to 192.168.1.100 port 8000 (#0)
* Trying 192.168.1.100...
* Connection timed out
* Failed connect to 192.168.1.100:8000; Connection timed out
* Closing connection 0
curl: (7) Failed connect to 192.168.1.100:8000; Connection timed out
Antwort1
Um es klarzustellen: Der Test des OP wird vom System 192.168.1.100 zu sich selbst durchgeführt, nicht von einem Remote-System, und das ist die Ursache des Problems. Der Port wurde in diesem Fall nicht geändert, da keine NAT-Regel übereinstimmte, während er gepasst hätte, wenn er von einem Remote-System ausgeführt worden wäre.
Das folgende Schema zeigt, in welcher Reihenfolge die Operationen an einem Paket ausgeführt werden:
Der Grund liegt in der Funktionsweise von NAT unter Linux:iptablessieht ein Paket in der nat
Tabelle nur für das erste Paket eines neuen Conntrack-Flows (das sich somit im Status NEU befindet).
Diese Regel funktioniert einwandfrei, wenn sie von einem Remote-System aus erfolgt. In diesem Fall ist das erste angezeigte Paket ein eingehendes Paket:
to port 8000 --> AF_PACKET (tcpdump) --> conntrack --> nat/PREROUTING (iptables REDIRECT): to port 30000
--> routing decision --> ... --> local process receiving on port 30000
Bei allen folgenden Paketen im gleichen Fluss wird conntrack die Portänderung (oder Portumkehr für Antworten) direkt handhaben und alle iptables-Regeln in der nat
Tabelle überspringen (wie im Schema geschrieben: nat
Tabelle wird nur für NEW
Verbindungen konsultiert). Daher (unter Überspringen des Antwortpaketteils) wird das nächste eingehende Paket stattdessen folgendes durchlaufen:
to port 8000 --> AF_PACKET (tcpdump) --> conntrack: to port 30000
--> routing decision --> ... --> local process receiving on port 30000
Bei einem Test des Systems selbst ist das erste Paket kein eingehendes Paket, sondern ein ausgehendes Paket. Dies geschieht stattdessen über die ausgehende lo
Schnittstelle:
local process client curl --> routing decision --> conntrack --> nat/OUTPUT (
no rule here
)
--> reroute check --> AF_PACKET (tcpdump) --> to port 8000
Und jetzt wird dieses Paket auf der Schnittstelle zurückgeschleift lo
, es erscheint erneut als Paket, das nicht mehr das erste Paket in einer Verbindung ist, also folgt der zweite Fall wie oben: conntrack allein kümmert sich um das NAT und ruft nicht auf nat/PREROUTING
. Außer dass es im Schritt davor nicht angewiesen wurde, NAT durchzuführen:
to port 8000 --> AF_PACKET (tcpdump) --> conntrack
--> routing decision --> ... -->
no
local process receiving on port
8000
Da auf Port 8000 nichts lauscht, sendet das Betriebssystem ein TCP RST zurück.
Damit dies auf dem lokalen System funktioniert, REDIRECT
muss zusätzlich eine Regel in die Kette eingefügt werden nat/OUTPUT
:
iptables -t nat -I OUTPUT -d 192.168.1.100 -p tcp --dport 8000 -j REDIRECT --to-port 30000
Zusätzliche Bemerkungen
Wenn der Fall für die Fernverwendung vorgesehen ist, testen Sie nicht vom lokalen System aus: Die vom Test durchlaufenen Regeln sind nicht dieselben. Dadurch spiegelt der Test nicht die Realität wider.
Verwenden Sie einfach einen Netzwerk-Namespace, um ein Pocket-Remote-System zu erstellen, falls kein anderes System verfügbar ist. Beispiel, das mit einem System funktionieren sollte, das nur die
nat/PREROUTING
Regel des OP hat und Folgendes tutcurl http://192.168.1.100/
(wofür kein DNS erforderlich ist):ip netns add remotesystem ip link add name vethremote up type veth peer netns remotesystem name eth0 ip address add 192.0.2.1/24 dev vethremote ip -n remotesystem address add 192.0.2.2/24 dev eth0 ip -n remotesystem link set eth0 up ip -n remotesystem route add 192.168.1.100 via 192.0.2.1 ip netns exec remotesystem curl http://192.168.1.100:8000/
tcpdump
und NATtcpdump
geschieht in denAF_PACKET
Schritten im obigen Schema: sehr früh für den Eingang und sehr spät für den Ausgang. Das bedeutet, dass im Fall eines Remote-Systems Port 30000 niemals erfasst wird, selbst wenn es funktioniert. Im Fall eines lokalen Systemsnat/OUTPUT
wird Port 30000 erfasst, sobald die Regel hinzugefügt wurde.Vertrauen Sie einfach nicht blind der beim
tcpdump
NAT angezeigten Adresse/dem angezeigten Port: Es hängt vom Einzelfall ab und davon, wo die Erfassung stattfindet.