![Verwenden der iptables-Weiterleitung unter Beibehaltung der Quell-IP](https://rvso.com/image/776289/Verwenden%20der%20iptables-Weiterleitung%20unter%20Beibehaltung%20der%20Quell-IP.png)
Ich habe einen Server, auf dem Wireguard läuft (und benötige daher masquerade
), und einen Container, der auf Port 2525 läuft.
Ich habe folgende iptables
Regeln:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 172.18.0.1:2525
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Bei einer server:2525
direkten Verbindung zu kann der Docker-Container meine echte IP-Adresse sehen ( 1.2.3.4
). Bei einer Verbindung zu Port server:25
sieht der Docker-Container die lokale IP, die bereitgestellt wird von docker network
:
Apr 07 12:45:46 mx postfix/smtpd[87]: lost connection after CONNECT from unknown[172.18.0.1]
Apr 07 12:45:46 mx postfix/smtpd[87]: disconnect from unknown[172.18.0.1] commands=0/0
Wie stelle ich sicher, dass der Docker-Container die öffentliche IP-Adresse beim Verbinden mit Port 25 richtig sieht (und nicht nur beim Verbinden mit Port 2525)?
Danke
# iptables -L -n -v -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
52300 3131K DNAT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:25 to:172.18.0.1:2525
150K 8524K DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
2 120 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3385 256K MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
1733K 104M MASQUERADE all -- * !br-b147ffdbc9f3 172.18.0.0/16 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:53
0 0 MASQUERADE udp -- * * 172.17.0.2 172.17.0.2 udp dpt:53
0 0 MASQUERADE tcp -- * * 172.18.0.2 172.18.0.2 tcp dpt:25
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
12 1419 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- br-b147ffdbc9f3 * 0.0.0.0/0 0.0.0.0/0
56 3192 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:5354 to:172.17.0.2:53
0 0 DNAT udp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 udp dpt:5354 to:172.17.0.2:53
107 6020 DNAT tcp -- !br-b147ffdbc9f3 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:2525 to:172.18.0.2:25
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 32:d0:56:15:0a:64 brd ff:ff:ff:ff:ff:ff
altname enp0s3
altname ens3
inet 159.223.80.86/20 brd 159.223.95.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.15.0.19/16 brd 10.15.255.255 scope global eth0:1
valid_lft forever preferred_lft forever
inet6 2400:6180:0:d0::f57:6001/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::30d0:56ff:fe15:a64/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 32:dc:4a:e4:27:be brd ff:ff:ff:ff:ff:ff
altname enp0s4
altname ens4
inet 10.130.244.15/16 brd 10.130.255.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::30dc:4aff:fee4:27be/64 scope link
valid_lft forever preferred_lft forever
4: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.200.200.52/24 scope global wg0
valid_lft forever preferred_lft forever
5: wg1: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.222.111.1/24 scope global wg1
valid_lft forever preferred_lft forever
6: br-b147ffdbc9f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:46:21:70:c0 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-b147ffdbc9f3
valid_lft forever preferred_lft forever
inet6 fe80::42:46ff:fe21:70c0/64 scope link
valid_lft forever preferred_lft forever
7: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:66:22:41:91 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:66ff:fe22:4191/64 scope link
valid_lft forever preferred_lft forever
9: veth31eff9d@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether e6:fb:80:5d:c7:a3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::e4fb:80ff:fe5d:c7a3/64 scope link
valid_lft forever preferred_lft forever
19: veth01269f5@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-b147ffdbc9f3 state UP group default
link/ether 36:f4:e7:43:5f:da brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet6 fe80::34f4:e7ff:fe43:5fda/64 scope link
valid_lft forever preferred_lft forever
Antwort1
Überlassen Sie die Umleitung einfach Docker. Sie ist dynamisch und kann sich ändern, wenn Container hinzugefügt, entfernt oder neu gestartet werden. Aber sieheAKTUALISIERENunten.
Diese Umleitung sollte nicht auf 172.18.0.1 erfolgen, da es sich hier um den Host und nicht um den Container handelt. Wenn der Host eine solche Verbindung empfängt, wird sie vondocker-proxy
welches es an den Container weiterleitet, wobei die Quell-IP-Adresse dabei verloren geht.
Docker leitet diesen Port bereits in der allerletzten Regel des Regelsatzes korrekt per DNAT + weiter (außer vom Host selbst, der docker-proxy
diese Rolle spielt), zum laufenden Container mit der Adresse 172.18.0.2. Außer dass er so konfiguriert ist, dass Port 2525 statt Port 25 verwendet wird.
107 6020 DNAT tcp -- !br-b147ffdbc9f3 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:2525 to:172.18.0.2:25
Dies sollte mit den Docker-Einstellungen behoben werden, nicht manuelliptablesRegeln, die sich nicht ändern können, wenn sich das Containerlayout ändert. Da Port 25 privilegiert ist, sind zusätzliche Einstellungen erforderlich, wenn Docker rootless ausgeführt wird. Überprüfen Sie dieDokumentation zum Freigeben privilegierter Ports.
AKTUALISIEREN(unter Berücksichtigung der Kommentare des OP): Der OP kann derzeit nicht verwendet werden, -p 25:25
da docker-proxy
er mit dem SMTP-Server des lokalen Hosts kollidiert und um das Abhören auf Port 25 auf dem Host konkurriert. Das ist der Grund für die anfängliche (falsche)iptablesDie Umleitung wurde von OP vorgenommen.
Man kann entweder:
Deaktivieren Sie es global,
docker-proxy
indem Sie esdockerd
mit der Eigenschaftuserland-proxy
„false“ ausführen.entweder alsParameter
--userland-proxy=false
oder als Eigenschaft"userland-proxy": false
hinzugefügt zu/etc/docker/daemon.json
.Dies ermöglicht dann die Verwendung
docker run ... -p 25:25 ...
(alsdokumentiert) ohne Konflikte: Der Host erreicht sich selbst, wenn er localhost oder $HOSTNAME erreicht, Remote-Systeme erreichen den Container und keine „Adresse wird bereits verwendet“ führt dazu, dass der SMTP-Daemon des Hosts oder der Container von Docker beim Start fehlschlägt.oder fügen Sie eine manuelle Umleitung hinzu (mit der langwierigen Einrichtung weiter unten, um dies fast automatisch durchzuführen)
Bei jedem Neustart des Containers besteht das Risiko, dass sich seine (interne) IP-Adresse ändert. Diese muss also berechnet werden. Bei einem Container, der
mx
über ein Netzwerk benannt istmx
und nur eine IP-Adresse verwendet, kann dies wie unten erläutert erfolgen.Erstellen Sie eine separate Prerouting-Kette (damit sie geleert werden kann, ohne dass etwas anderes geleert werden muss) und rufen Sie sie zuerst auf:
iptables -t nat -N mynat iptables -t nat -I PREROUTING -j mynat
Die IP-Adresse des Containers kann programmgesteuert abgerufen werden (für den einfachen Fall eines Containers, der
mx
mit einer einzelnen Adresse benannt ist):containerip=$(docker container inspect --format '{{.NetworkSettings.IPAddress}}' mx)
(oder man könnte
jq
:containerip=$(docker container inspect mx | jq '.[].NetworkSettings.IPAddress'
)Den Namen der Bridge-Schnittstelle zu finden ist komplizierter, oder zumindest konnte ich keine Möglichkeit finden, dies nur mit zu tun
docker ... inspect
. Suchen Sie also die IP-Adresse auf dem Host und fragen Sie den Host mit ab,ip address
um nur die Bridge-Schnittstelle zu finden, auf der diese spezielle IP-Adresse festgelegt ist (erfordert denjq
Befehl).bridgeip=$(docker network inspect --format '{{(index .IPAM.Config 0).Gateway}}' mx) bridgeinterface=$(ip -json address show to "$bridgeip"/32 | jq -r '.[].ifname')
mynat
Bei jedem (Neu-)Start des Containers leeren und neu auffüllen :iptables -t nat -F mynat iptables -t nat -A mynat ! -i "$bridgeinterface" -p tcp --dport 25 -j DNAT --to-destination "$containerip":25
was im vorliegenden Fall lauten würde:
iptables -t nat -I mynat ! -i br-b147ffdbc9f3 -p tcp --dport 25 -j DNAT --to-destination 172.18.0.2:25
Und um sicherzugehen, dass Dockers eigene Firewall-Regeln diesen Datenverkehr nicht blockieren, führen Sie etwas Ähnliches aus, beginnend in filter/
FORWARD
imDOCKER-USER
Kette.Zunächst (wenn vom Boot aus, müssen Sie möglicherweise auch zuerst
DOCKER-USER
):iptables -N myforward iptables -I DOCKER-USER 1 -j myforward
Dann später bei jedem (Neu-)Start des Containers:
iptables -F myforward iptables -A myforward -p tcp ! -i "$bridgeinterface" -d "$containerip" -p tcp --dport 25 -j ACCEPT
was im vorliegenden Fall lauten würde:
iptables -A myforward -p tcp ! -i br-b147ffdbc9f3 -d 172.18.0.2 -p tcp --dport 25 -j ACCEPT
Anmerkungen:
Um die oben genannten Regeln zu vereinfachen und einige der Berechnungen zu vermeiden, können der Container und sein Bridge-Netzwerk mit festen IP-Adressen gestartet werden. Siehe beispielsweise diese SO Q/A:Weisen Sie dem Docker-Container eine statische IP zu.
Hier ist auch ein UL SE Q/A mit einer Antwort von mir über Probleme bei der Interaktion mit Docker (es richtet sich anNftablesaber einige Teile über die
DOCKER-USER
Ketten- oderbr_netfilter
Brückeninteraktionen sind immer noch von Interesse):Nftables-Whitelist-Docker