Ubuntu 22.04
我正在尝试将ICMPv6
数据包路由到另一个目的地,这iptables
似乎非常合适。
所以我尝试了表-j DNAT
的目标-t nat
,发现它基本上没有影响ICMPv6
。相比之下,默认filter
表成功捕获了ICMPv6
数据包。事实上,如果我添加一个LOG
目标,如下所示:
# successfully logs incoming ICMPv6 packets
sudo ip6tables -i eth0 -p icmpv6 -d xxxx::xxxx -A INPUT -j LOG
我可以看到通过 记录的条目dmesg
。但附加到表的INPUT
/链接不会产生任何日志条目:PREROUTING
nat
# No logs produced
sudo ip6tables -i eth0 -p icmpv6 -d xxxx::xxxx -A PREROUTING -j LOG -t nat
sudo ip6tables -i eth0 -p icmpv6 -d xxxx::xxxx -A INPUT -j LOG -t nat
这是合理的,man iptables(8)
因为
nat: This table is consulted when a packet that creates a new connection is encountered.
并且没有任何与 相关的数据包创建新连接ICMPv6
。问题是-j DNAT
只能与 一起使用-t nat
。
有没有办法将ICMPv6
数据包路由到另一个目的地?
就可路由的 ICMPv6 数据包而言:
具体来说,对于 ICMP “Echo”和“Echo Reply”(即
ping
数据包),它与 ICMP 的工作方式与 UDP 相同 - conntrack(iptables 连接跟踪子系统)尚不知道的第一个数据包是创建流状态的原因,并且所有后续数据包都会自动识别为该流的一部分。在闲置
sysctl net.netfilter.nf_conntrack_icmp{,v6}_timeout
数秒后,或者在您使用 手动删除它后,该流将被自动遗忘(即手册页术语中的“连接关闭”)conntrack -D -p icmpv6
。与 UDP 的主要区别在于,conntrack 条目不是以源/目标端口为关键字,而是以 ICMP Echo Request ID 为关键字(或者可能仅以 IP 地址为关键字)。很少使用的 ICMP Timestamp Request 的工作方式相同。
所有其他非请求ICMP 数据包都无法进行 DNAT 处理(或者说单独对它们进行 DNAT 处理毫无意义),因为它们已经属于现有流。例如,响应 TCP 数据包而生成的 ICMP“网络不可达”数据包将被视为 TCP 流的一部分(并且当且仅当原始 TCP 连接经过 DNAT/SNAT 处理时才会进行 DNAT/SNAT 处理)。
最后,ICMPv6 特定的“邻居发现”数据包(NS/NA/RS/RA)无法进行 NAT,因为它们本质上是链路本地的,并且首先不通过路由器转发。