我在我的一个 VPS 上使用了 Hurricane Electric 隧道,但它没有完全工作。我使用与此脚本基本相同的脚本设置隧道:http ://www.cybermilitia.net/2013/07/22/ipv6-tunnel-on-openvz/ ,仅对我的特定设置进行了修改。我可以 ping 服务器并从中获取网页,但我从 ping6 得到以下输出:
root@unixshell:~# ping6 -c4 2001:470:1f0e:12a7::2
PING 2001:470:1f0e:12a7::2(2001:470:1f0e:12a7::2) 56 data bytes
From 2002:d8da:e02a::1 icmp_seq=1 Destination unreachable: Address unreachable
64 bytes from 2001:470:1f0e:12a7::2: icmp_seq=1 ttl=63 time=96.4 ms
64 bytes from 2001:470:1f0e:12a7::2: icmp_seq=2 ttl=63 time=73.2 ms
From 2002:d8da:e02a::1 icmp_seq=2 Destination unreachable: Address unreachable
--- 2001:470:1f0e:12a7::2 ping statistics ---
2 packets transmitted, 2 received, +2 errors, 0% packet loss, time 1005ms
rtt min/avg/max/mdev = 73.256/84.838/96.420/11.582 ms
在问题服务器上,运行 tcpdump,我同时看到了上述内容:
root@tektonic:~# tcpdump -n not port 22
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on venet0, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
21:25:44.000024 IP 216.218.224.42 > 207.210.83.205: IP6 2002:cfd2:4a7c::1 > 2001:470:1f0e:12a7::2: ICMP6, echo request, seq 1, length 64
21:25:44.000094 IP 207.210.83.205 > 216.218.224.42: ICMP 207.210.83.205 protocol 41 port 0 unreachable, length 132
21:25:44.000629 IP 207.210.83.205 > 216.218.224.42: IP6 2001:470:1f0e:12a7::2 > 2002:cfd2:4a7c::1: ICMP6, echo reply, seq 1, length 64
21:25:45.020972 IP 216.218.224.42 > 207.210.83.205: IP6 2002:cfd2:4a7c::1 > 2001:470:1f0e:12a7::2: ICMP6, echo request, seq 2, length 64
21:25:45.021059 IP 207.210.83.205 > 216.218.224.42: ICMP 207.210.83.205 protocol 41 port 0 unreachable, length 132
21:25:45.021260 IP 207.210.83.205 > 216.218.224.42: IP6 2001:470:1f0e:12a7::2 > 2002:cfd2:4a7c::1: ICMP6, echo reply, seq 2, length 64
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel
这是我的 iptables 配置的相关部分:
root@tektonic:~# iptables --list | egrep '41|ipv6'
ACCEPT ipv6 -- anywhere anywhere
ACCEPT ipv6 -- anywhere anywhere
我意识到我可以停止使用 iptables 发送 ICMP 不可达消息,如此处所述:禁用 ICMP 不可达回复,但这是一个次优的解决方案。关于如何在无需挖掘内核源代码的情况下解决实际问题的任何想法?
错误消息的“端口 0”部分是一条红鲱鱼。6in4 数据包只是一个带有 ipv4 标头的 ipv6 数据包,因此在 ipv4 级别没有端口号。但是,正在发送的 ICMP 数据包的类型号为 3,代码号为 3,意思是“端口不可达”,而不是代码 2,“协议不可达”。这是一个:
12:15:51.011697 IP 207.210.83.205 > 216.218.224.42: ICMP 207.210.83.205 protocol 41 port 0 unreachable, length 132
0x0000: 45c0 0098 8d6c 0000 4001 0f94 cfd2 53cd [email protected].
0x0010: d8da e02a 0303 62fb 0000 0000 4500 007c ...*..b.....E..|
0x0020: 9157 4000 f829 145c d8da e02a cfd2 53cd .W@..).\...*..S.
0x0030: 6000 0000 0040 3a3b 2002 cfd2 4a7c 0000 `....@:;....J|..
0x0040: 0000 0000 0000 0001 2001 0470 1f0e 12a7 ...........p....
0x0050: 0000 0000 0000 0002 8000 aa6e 1022 0002 ...........n."..
0x0060: ad8a c355 ce94 0a00 0809 0a0b 0c0d 0e0f ...U............
0x0070: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f ................
0x0080: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f .!"#$%&'()*+,-./
0x0090: 3031 3233 3435 3637 01234567
[2015-08-06 更新] 将 tb_userspace 升级到修订版 18,没有变化。
[更新 2015-08-09] tb_userspace.c第 163 行:sockv6 = socket(AF_INET, SOCK_RAW, IPPROTO_IPV6);
,并lsof -c tb_userspace
显示确实创建了套接字:tb_usersp 6614 root 4u raw 0t0 1559059549 CD53D2CF:0029->00000000:0000 st=07
[更新 2015-08-09 17:18 PDT] 确认在没有 openvz 的普通内核上存在同样的问题:
jcomeau@unixshell:~$ ping6 2001:470:66:79d::2
PING 2001:470:66:79d::2(2001:470:66:79d::2) 56 data bytes
64 bytes from 2001:470:66:79d::2: icmp_seq=1 ttl=60 time=86.5 ms
From 2001:470:0:206::2 icmp_seq=1 Destination unreachable: Address unreachable
64 bytes from 2001:470:66:79d::2: icmp_seq=2 ttl=60 time=83.4 ms
From 2001:470:0:206::2 icmp_seq=2 Destination unreachable: Address unreachable
64 bytes from 2001:470:66:79d::2: icmp_seq=3 ttl=60 time=86.1 ms
From 2001:470:0:206::2 icmp_seq=3 Destination unreachable: Address unreachable
^C
--- 2001:470:66:79d::2 ping statistics ---
3 packets transmitted, 3 received, +3 errors, 0% packet loss, time 2012ms
rtt min/avg/max/mdev = 83.429/85.376/86.556/1.427 ms
jcomeau@unixshell:~$ logout
Connection to www closed.
jcomeau@aspire:~$ uname -a
Linux aspire 3.2.0-4-amd64 #1 SMP Debian 3.2.54-2 x86_64 GNU/Linux
还刷新了 iptables 和 ip6tables 并删除了所有 netfilter 模块。相同的症状。
[更新 2015-08-11 01:04] 来自http://linux.die.net/man/7/raw发现在将原始数据包发送到任何原始套接字后,内核仍会将其传递给任何为该协议注册的模块。我自己的上网本上的模块是我正在测试的“没有openvz的原始内核”,它是tunnel4。一旦我删除它,目标无法到达的消息就会停止。我假设我的 VPS 上的单片内核中内置了相同的模块。/proc/kallsyms 上不存在,所以我必须联系客户支持。
[2015-08-11 01:50 更新] http://www.haifux.org/lectures/217/netLec5.pdf也是一个有帮助的资源。
正如问题更新中所指出的,问题在于内核将数据包传递到正在侦听该协议的任何原始套接字之后,它会将其交给为同一协议注册的任何内核模块。因为我一直在上网本上使用坐隧道,所以即使我临时设置了 tb_userspace 隧道进行测试,隧道 4 模块仍然加载;因此,由于它已注册,但未配置任何处理程序,因此它拒绝了带有 ICMP 3:3 消息的数据包。
rmmod sit
随后rmmod tunnel4
解决了这个问题。在最初的问题服务器上,这并不容易,因为它是一个带有单片内核的 openvz VPS,正如客户端“盒子”所见。但有了来自http://linux.die.net/man/7/raw和http://www.haifux.org/lectures/217/netLec5.pdf的信息,我能够与提供商合作解决问题。在这种情况下,他们重新安装了 sat 模块,所以我根本不需要使用 tb_userspace 隧道软件。但我怀疑问题是隧道4也安装在那里。
tektonic 似乎没有将地址 2001:470:1f0e:12a7::2 分配给其 venet0 接口。它正在接收数据包并拒绝它们,即使它们格式正确。
您的下一步应该是验证 tektonic 是否可以与仅 IPv6 的主机(例如 ipv6.google.com)建立 TCP 连接,并且数据包确实通过 IPv4 封装传输到配置的 Hurricane Electric 中继主机。如果 TCP 能通过而 ICMP 不能,那么肯定是端点过滤问题(即防火墙规则)。
ICMP 错误由内核发送,因为不存在用于接收具有特定源和目标 IP 地址组合的协议 41 数据包的套接字。
如果一个进程使用协议 41 创建一个原始套接字,那么内核将停止产生 ICMP 错误。默认情况下,这样的套接字将接收从所有源 IP 发送到分配给本地计算机的任何目标 IP 的数据包。使用 bind 和/或 connect 系统调用,应用程序可以限制它将接收的源 IP 地址和目标 IP 地址的组合。与任何此类套接字不匹配的数据包仍会产生 ICMP 错误。
很明显,在您的情况下,隧道同时接收数据包并产生 ICMP 错误。但是根据我上面的描述,套接字接收到的数据包不可能同时产生 ICMP 错误消息。但是还有其他方法可以接收数据包,这不会阻止内核产生 ICMP 错误。
套接字可以在较低的协议层接收数据包,无论 IP 协议编号如何,所有数据包都是可见的。如果您使用的隧道软件使用如此低级的套接字来接收协议 41 数据包,则会产生 ICMP 错误,如您的问题中所述。
如果这是隧道软件所做的,那么我会认为这是隧道软件的设计缺陷。在这种情况下,您有三个选择: