我如何阻止发送协议 41 不可达数据包?

我如何阻止发送协议 41 不可达数据包?

我在我的一台 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_用户空间.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也是一种有帮助的资源。

答案1

正如问题更新中所述,问题在于,在内核将数据包传递给正在侦听该协议的任何原始套接字后,它然后将其交给任何内核模块注册了相同的协议。由于我一直在上网本上使用 sit 隧道,因此即使我临时设置了 tb_userspace 隧道进行测试,tunnel4 模块仍然会加载;因此,由于它已注册,但没有配置处理程序,因此它拒绝了带有 ICMP 3:3 消息的数据包。rmmod sit随后rmmod tunnel4解决了问题。

在原始问题服务器上,这并不那么容易,因为它是一个 openvz VPS,具有单片内核,如客户端“盒子”所见。但有了来自http://linux.die.net/man/7/rawhttp://www.haifux.org/lectures/217/netLec5.pdf我能够与提供商合作解决问题。在这种情况下,他们重新安装了 sit 模块,所以我根本不需要使用 tb_userspace 隧道软件。但我怀疑问题在于 tunnel4 也安装在那里。

答案2

看起来 tektonic 没有为其 venet0 接口分配地址 2001:470:1f0e:12a7::2。它正在接收数据包并拒绝它们,即使这些数据包格式正确。

下一步应该是验证 tektonic 是否可以与仅支持 IPv6 的主机(例如 ipv6.google.com)建立 TCP 连接,以及数据包是否确实通过 IPv4 封装传输到配置的 Hurricane Electric 中继主机。如果 TCP 通过但 ICMP 未通过,那么这肯定是端点过滤问题(即防火墙规则)。

答案3

ICMP 错误由内核发送,因为不存在套接字来接收具有特定源和目标 IP 地址组合的协议 41 数据包。

如果进程创建了协议为 41 的原始套接字,则内核将停止生成 ICMP 错误。默认情况下,此类套接字将接收从所有源 IP 发送到本地计算机的任何目标 IP 的数据包。使用 bind 和/或 connect 系统调用,应用程序可以限制它将接收的源 IP 地址和目标 IP 地址的组合。与任何此类套接字不匹配的数据包仍将生成 ICMP 错误。

很明显,在您的例子中,隧道同时接收数据包并产生 ICMP 错误。但根据我上面的描述,套接字接收的数据包不可能也产生 ICMP 错误消息。但还有其他方法可以接收数据包,这不会阻止内核产生 ICMP 错误。

套接字可以在较低的协议层接收数据包,在该层中,无论 IP 协议号如何,所有数据包都是可见的。如果您使用的隧道软件使用这种低级套接字接收协议 41 数据包,那么将产生 ICMP 错误,如您的问题中所述。

如果隧道软件确实存在这种问题,那么我认为这是隧道软件的设计缺陷。在这种情况下,您有三个选择:

  • 通过过滤数据包(例如使用 iptables)来解决该缺陷。
  • 获取软件源代码并修复设计缺陷。
  • 切换到不同的软件时不存在这个设计缺陷。

相关内容