我使用ip6tables
nat 将包发送到不同接口 (localhost) 上的 IP,但发送到那里的所有数据包都丢失了。我iptables
对 IPv4 有相同的规则,一切正常。
设置
主机是 debian 11 VM,客户端是运行的 docker 容器debian:stable-slim
。
/etc/docker/daemon.json
:
{
"ipv6": true,
"fixed-cidr-v6": "2d00::/8",
"ip6tables": true,
"experimental": true
}
主机具有分别用于 IPv6 和 IPv4 的docker0
接口 IP2d00::1
和172.17.0.2
。我分别设置了以下 ip(6)tables 规则以针对 IPv4 和 IPv6 进行 NAT:
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
我还将以下规则附加到我的/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
最小的非工作示例
在主机上设置一个 HTTP 服务器,监听[::1]:9999
:
python3 -m http.server --bind ::1 9999
并尝试从客户端容器连接它:
docker run --rm -it --name client debian:stable-slim /bin/bash
apt update
apt install -y curl
curl http://[2d00::1]:8081
结果是 curl 挂了一段时间并不断尝试建立连接,但我从未得到响应。
我尝试过和观察到的事情
我已经对上述不起作用的示例进行了相同的测试
- 带 nat 的 IPv4
- 无需NAT的IPv6
- IPv6 带有 nat 到与原始目标 IP 位于同一接口上的 IP(即,仅更改端口,或 NAT 到接口的链路本地地址)
和他们全部成功。因此,唯一不起作用的情况是带有 NAT 的 IPv6,其中 NAT 想要路由到不同的接口。
我还向各种 ip(6)tables 链添加了日志输出,我可以看到在成功的情况下,我可以观察到到达表链filter
的数据包INPUT
以及nat
表的PREROUTING
链。一旦我尝试将 IPv6 流量 NAT 到不同的接口,我就再也收不到到达表中任何链的数据包了filter
。
我也曾经tcpdump
在主机上跟踪数据包,并观察到在成功的情况下,我在veth*
docker 创建的虚拟接口以及docker0
接口上都可以看到数据包。当对 IPv6 上的其他接口进行 NAT 时,数据包不再出现在接口上docker0
,但我仍然可以在veth*
接口上看到它们。
答案1
经过进一步挖掘,我发现问题不是跨接口路由,而是路由到::1
,这这是另一个主题的答案根据 RFC 4291 第 2.5.3 节的规定,IPv6 中不允许这样做。