I'm using ip6tables
to nat packages to an IP on a different interface (localhost), but all packets sent there are lost.
I have the same iptables
rules for IPv4 where everything is working fine.
Setup
The host is a debian 11 VM, the client is a docker container running debian:stable-slim
.
/etc/docker/daemon.json
:
{
"ipv6": true,
"fixed-cidr-v6": "2d00::/8",
"ip6tables": true,
"experimental": true
}
The host has the docker0
interface IPs 2d00::1
and 172.17.0.2
for IPv6 and IPv4 respectively.
I'm setting up the following ip(6)tables rules to NAT for IPv4 and IPv6 respectively:
ip6tables -t nat -A PREROUTING -d 2d00::1 -p tcp -m tcp --dport 8081 -j DNAT --to-destination [::1]:9999
iptables -t nat -A PREROUTING -d 172.17.0.2 -p tcp -m tcp --dport 8081 -j DNAT --to-destination 127.0.0.1:9999
I have also appended the following rules to my /etc/sysctl.conf
:
net.ipv4.ip_forward = 1
net.ipv4.conf.all.route_localnet = 1
net.ipv6.conf.all.use_tempaddr = 0
net.ipv6.conf.all.forwarding = 1
Minimal non-working example
Set up an HTTP server on the host, listening on [::1]:9999
:
python3 -m http.server --bind ::1 9999
And try to connect to it from a client container:
docker run --rm -it --name client debian:stable-slim /bin/bash
apt update
apt install -y curl
curl http://[2d00::1]:8081
The result is that curl hangs for a while and continuously tries to establish a connection, but i never get a response.
Things i have tried and observed
I have done the same test as in the non-working example above for
- IPv4 with nat
- IPv6 without nat
- IPv6 with nat to an IP on the same interface as the original destination IP (i.e. just change the port, or NAT to the interface's link-local address)
and they all succeeded.
So the only non-working case is IPv6 with NAT where the NAT wants to route to a different interface.
I have also added log outputs to various ip(6)tables chains and i could see that in the successful cases, i can observe packets arriving at the filter
table's INPUT
chain, as well as the nat
table's PREROUTING
chain.
As soon as i try to NAT IPv6 traffic to a different interface, i no longer get any packets arriving at any chain in the filter
table.
I have also used tcpdump
to track packets on the host, and observed that in the successful cases i see the packets at the veth*
virtual interfaces created by docker, as well as on the docker0
interface.
When doing the NAT to a different interface on IPv6, the packets no longer appear at the docker0
interface, but i still see them at the veth*
interface.