![Usando o encaminhamento de iptables, mantendo adequadamente o IP de origem](https://rvso.com/image/776289/Usando%20o%20encaminhamento%20de%20iptables%2C%20mantendo%20adequadamente%20o%20IP%20de%20origem.png)
Eu tenho um servidor rodando o Wireguard (precisando assim masquerade
) e um contêiner rodando na porta 2525.
Eu tenho as seguintes iptables
regras:
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
Ao conectar-se server:2525
diretamente, o contêiner Docker é capaz de ver meu endereço IP real ( 1.2.3.4
). Ao se conectar ao port server:25
, o contêiner do Docker vê o IP local fornecido por 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
Como posso ter certeza de que o contêiner do Docker está vendo corretamente o endereço IP público ao conectar-se à porta 25 (e não apenas ao conectar-se à porta 2525).
Obrigado
# 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
Responder1
Deixe o Docker cuidar do redirecionamento, que é dinâmico e pode mudar quando os contêineres são adicionados, removidos ou reiniciados. Mas vejaATUALIZARabaixo.
Esse redirecionamento não deve ser para 172.18.0.1, que é o host e não o contêiner. Quando o host recebe tal conexão, ela é tratada pordocker-proxy
que faz proxy para o contêiner, perdendo o endereço IP de origem no processo.
O Docker já DNAT+ roteia essa porta corretamente (exceto do próprio host, onde docker-proxy
desempenha essa função) na última regra do conjunto de regras, para o contêiner em execução com o endereço 172.18.0.2. Exceto que está configurado para usar a porta 2525 em vez da porta 25.
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
Isso deve ser corrigido com as configurações do Docker, não manualmentetabelas de ipregras que não podem ser alteradas sempre que o layout do contêiner for alterado. Como a porta 25 é privilegiada, se o Docker estiver rodando sem root, serão necessárias configurações adicionais, verifique odocumentação sobre a exposição de portas privilegiadas.
ATUALIZAR(considerando os comentários do OP): O OP não pode ser usado no momento -p 25:25
porque docker-proxy
entra em conflito com o servidor SMTP do host local e compete pela escuta na porta 25 do host. Essa é a razão pela qual a inicial (errada)tabelas de ipo redirecionamento foi feito pelo OP.
Pode-se:
desabilitar globalmente
docker-proxy
executandodockerd
com a propriedadeuserland-proxy
definida como falseseja como umparâmetro
--userland-proxy=false
ou como uma propriedade"userland-proxy": false
adicionada a/etc/docker/daemon.json
.Isso permitirá então usar
docker run ... -p 25:25 ...
(comodocumentado) sem conflito: o host alcançará a si mesmo ao alcançar localhost ou $ HOSTNAME, os sistemas remotos alcançarão o contêiner e nenhum "Endereço já em uso" fará com que o daemon SMTP do host ou o contêiner do Docker falhem na inicialização.ou então adicione um redirecionamento manual (com configuração demorada abaixo para fazer isso quase automaticamente)
Sempre que o contêiner é reiniciado, existe o risco de seu endereço IP (interno) ser alterado. Então isso deve ser computado. Portanto, com um contêiner nomeado
mx
usando uma rede nomeadamx
e um único endereço IP envolvido, isso pode ser feito conforme explicado abaixo.Crie uma cadeia de pré-roteamento separada (para que possa ser liberada sem a necessidade de liberar mais nada) e chame-a primeiro:
iptables -t nat -N mynat iptables -t nat -I PREROUTING -j mynat
O endereço IP do contêiner pode ser recuperado programaticamente (para o caso simples de um contêiner nomeado
mx
com um único endereço):containerip=$(docker container inspect --format '{{.NetworkSettings.IPAddress}}' mx)
(ou alguém poderia usar
jq
:)containerip=$(docker container inspect mx | jq '.[].NetworkSettings.IPAddress'
Encontrar o nome da interface da ponte é mais complicado, ou pelo menos não consegui encontrar uma maneira de fazer isso usando apenas
docker ... inspect
. Portanto, encontre seu endereço IP no host e consulte o host usandoip address
para encontrar apenas a interface da ponte onde esse endereço IP específico está definido (requer ojq
comando).bridgeip=$(docker network inspect --format '{{(index .IPAM.Config 0).Gateway}}' mx) bridgeinterface=$(ip -json address show to "$bridgeip"/32 | jq -r '.[].ifname')
Limpe e preencha novamente
mynat
cada vez que o contêiner for (re)iniciado:iptables -t nat -F mynat iptables -t nat -A mynat ! -i "$bridgeinterface" -p tcp --dport 25 -j DNAT --to-destination "$containerip":25
o que seria para o caso atual:
iptables -t nat -I mynat! -i br-b147ffdbc9f3 -p tcp --dport 25 -j DNAT --to-destination 172.18.0.2:25
E para ter certeza de que as próprias regras de firewall do Docker não bloqueiam esse tráfego, faça algo semelhante começando em filter/
FORWARD
doDOCKER-USER
corrente.Inicialmente (se for da inicialização, talvez você precise criar primeiro
DOCKER-USER
):iptables -N myforward iptables -I DOCKER-USER 1 -j myforward
Mais tarde, cada vez que o contêiner for (re)iniciado:
iptables -F myforward iptables -A myforward -p tcp ! -i "$bridgeinterface" -d "$containerip" -p tcp --dport 25 -j ACCEPT
o que seria para o caso atual:
iptables -A myforward -p tcp ! -i br-b147ffdbc9f3 -d 172.18.0.2 -p tcp --dport 25 -j ACCEPT
Notas:
Para simplificar as regras acima e evitar alguns cálculos, o contêiner e sua rede bridge podem ser iniciados com endereços IP fixos. Veja, por exemplo, este SO Q/A:Atribuir IP estático ao contêiner Docker.
Aqui está também uma pergunta/resposta da UL SE com uma resposta minha sobre problemas ao interagir com o Docker (ele é voltado paranftáveismas algumas partes sobre as interações
DOCKER-USER
em cadeia oubr_netfilter
ponte ainda são de interesse):janela de encaixe da lista de permissões do nftables