Score:0

Why does ip6tables lose packets after PREROUTING to a different interface?

td flag

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.

us flag
Have you enabled IPv6 forwarding on the host at `/proc/sys/net/ipv6/conf/all/forwarding`?
pohlarized avatar
td flag
Thanks for the suggestion, yes i have! I also listed the (afaik) relevant kernel parameters above as part of my `/etc/sysctl.conf`.
Score:0
td flag

After some more digging i found out that the problem is not cross-interface routing, but routing to ::1, which this answer to a different thread has shown me, is not allowed in IPv6 as per RFC 4291 Section 2.5.3.

I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.