12 月 20 日 LUG VPN 服务迁移到 202.141.{160,176}.95 以来,IPv6 就一直不能正常访问。今天终于解决了这个问题。一周来给诸位带来诸多不便,望包涵。

原因主要是 ip6tables 配置错误,导致 ICMPv6 消息接收不正常,IPv6 因此中断。由于 ICMPv6 不仅承担了主机发现的功能,还承担着 ping 包,我在测试的时候一直以为是网络中心的配置问题,多次与 jameszhang 测试后才确认是我这边的问题。

问题的详细原因是两个(这里是不指望读者能看懂的,牵扯太多细节了)。

  1. ICMPv6 neighbor advertisement 包经过 ip6tables OUTPUT 链的 CONNMARK 时,被打上了标记,而不知道由于什么原因,有标记的包在路由阶段被丢弃了(ip -6 rule 中没有针对这个默认标记进行设置,所以很奇怪),导致服务器无法响应路由器的 ICMPv6 请求。
  2. 10000 号路由表里有如下这样的路由规则,本来是不应该有 tun0 的。但脚本里写的是 ip -6 route add $prefix via 2001:da8:d800:f001::1 table 10000,而由于 OpenVPN server 插入了路由 ip route 2001:da8:d800:f001::/64 dev tun0(它只支持 /64 的网段,不支持更小的),实际生成的路由就是 dev eth0 和 dev tun0 两条。10000 号路由表的意思是让 chnroutes 里面的 IP 走本地网关。 ```

    240b:8000::/21 via 2001:da8:d800:f001::1 dev eth0 metric 1024 240b:8000::/21 via 2001:da8:d800:f001::1 dev tun0 metric 1024 ```

问题的解决:

  1. ICMPv6 问题:commit 只有一行,就是让 ICMPv6 的包不要经过 CONNMARK 规则。
  2. 路由问题:commit 也只有一行,就是强制选取 eth0 网卡作为路由。

问题的启示:

  1. 之前我们遇到过 ICMPv6 包的问题,那次是防火墙,这次的问题更微妙一些而且没有查清。由于 ICMPv6 属于 IPv6 的上层协议,地址发现这个本来在 IPv4 中属于 ARP 协议(ARP 与 IPv4 平行)的事情被上移了一层,ip6tables 能够管到它了,就容易在设置规则时不小心碰到它。
  2. 在使用 ip -6 route 命令设置路由时,为严谨起见,应当指定 dev 参数。