如何阻止传入的 IPv6 碎片?

如何阻止传入的 IPv6 碎片?

我的防火墙配置有问题。我想阻止特定接口中的所有 IPv6 碎片数据包。因此,我尝试了:

# ip6tables -A INPUT -d <ipv6_address> -i eth0 -m ipv6header --header ipv6-frag --soft -j DROP

但是 IPv6 碎片流量仍在不断流入。

我还发现了这个链接:https://www.secfu.net/2015/03/25/how-to-block-incoming-ipv6-fragments-in-latest-red-hat-releases/ 这解释了为什么 ipv6-frag 或 frag 不会阻止最新的 CentOS 中的 ipv6 碎片流量,因为在 bug id 1011214(kernel-2.6.32-437.el6)之后,netfilter 开始处理重组的数据包,而不是像 IPv4 那样处理碎片。同一篇文章建议使用 nftables,如下所示:

table ip6 filter {
   chain preroute500 {
      type filter hook prerouting priority -500; policy accept;
      ip6 nexthdr ipv6-frag counter packets 2 bytes 2104
   }
 } 

我如何使用 ip6tables 做这样的事情?

# cat /etc/system-release
CentOS Linux release 7.5.1804 (Core)

# uname -r
5.0.8-1.el7.elrepo.x86_64

答案1

正如前面所说,你应该确保阻止碎片确实是你的目标,而不是你认为最适合你的目标的方法,尽管可能存在更好的方法。无论如何,你必须:

  • 使用足够新的内核。特征曾是在内核 4.16 中添加。CentOS 使用 3.10。虽然许多功能都已反向移植(从 nftables 开始,它在原始 3.10 内核上不可用,但在 RHEL/CentOS 的 3.10 上可用),但截至最新的 CentOS 7.6 内核。由于您使用的是“elrepo”5.0.8 内核,因此该功能可用。以下是该功能的描述以及它存在的原因(主要用于路由,或者至少是非状态/非 NAT 防火墙路由情况):

    netfilter: nf_defrag:

    如果设置了 NOTRACK,则跳过 defrag。仅当某些模块(如 CONNTRACK 或 NAT)明确请求时,才需要 conntrack defrag。对于普通转发场景,不需要 defrag,如果在规则中设置了 NOTRACK,则可以跳过 defrag。

    由于 conntrack defrag 的优先级目前高于 raw table,因此设置 NOTRACK 是不够的。我们需要将 raw 移至 iptables 的更高优先级。

    这是通过引入模块参数“raw_before_defrag”实现的,该参数允许更改原始表的优先级以将其置于碎片整理之前。默认情况下,该参数被禁用,原始表的优先级为 NF_IP_PRI_RAW 以支持旧行为。如果启用了模块参数,则原始表的优先级设置为 NF_IP_PRI_RAW_BEFORE_DEFRAG。

  • (如果需要删除现有的原始 ip6tables 规则,卸载并)ip6table_raw使用参数加载模块raw_before_defrag=1,因此原始的钩子(在 PREROUTING 中)在 defrag 的 -400 之前从 prio -300 切换到 -450。

    modprobe ip6table_raw raw_before_defrag=1
    

    它应该得到如下内核消息ip6table_raw: Enabling raw table before defrag

现在在raw表格中,可能只有在才有意义PREROUTINGip6tables将能够看到碎片。它可以在那里过滤它们,或者选择跳过 conntrack ( iptables -t raw -A PREROUTING ... -j CT --notrack),正如功能补丁中所述,这也将跳过碎片整理,允许其他链处理它们(当然不包括nat表的链或任何其他 conntrack 相关功能)。


请注意,为了见证问题描述在测试网络命名空间中,必须先人为地启用连接跟踪操作连接跟踪的依赖碎片整理,直到第一次需要时才会激活。以下是网络命名空间示例:

ip netns add sender
ip netns add receiver
ip -n sender   link add veth0 address 02:00:00:00:00:01 type veth peer netns receiver name veth0 address 02:00:00:00:00:02
ip -n sender   link set veth0 up
ip -n receiver link set veth0 up

这有效:

# ip netns exec sender ping6 -s 4000 fe80::ff:fe00:2%veth0
PING fe80::ff:fe00:2%veth0(fe80::ff:fe00:2%veth0) 4000 data bytes
4008 bytes from fe80::ff:fe00:2%veth0: icmp_seq=1 ttl=64 time=0.069 ms
^C

此后,它将不再起作用:

ip netns exec receiver ip6tables -A INPUT -m ipv6header --header ipv6-frag --soft -j DROP

一次连接跟踪在网络命名空间中使用这些命令显然会导致无操作:

ip netns exec receiver ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED
ip netns exec receiver ip6tables -D INPUT -m conntrack --ctstate ESTABLISHED

ipv6 碎片整理也已激活。现在之前的 ping 将始终有效,因为 INPUT 中的规则仅看到碎片整理的数据包。

使用先前ip6table_raw用参数(重新)加载的模块raw_before_defrag=1,这将恢复碎片 ping 的阻塞:

ip netns exec receiver ip6tables -t raw -A PREROUTING -m ipv6header --header ipv6-frag --soft -j DROP

或者,有趣的数据包可以标记为诺特拉克,从而免除他们连接跟踪,因此没有收到碎片整理处理,允许再次使用链中的规则过滤它们filter/INPUT。因此,与之前的raw规则不同,这也会阻止 ping 数据包(每次 ping 3 个数据包),但这次还是在链中filter/INPUT

ip netns exec receiver ip6tables -t raw -A PREROUTING -m ipv6header --header ipv6-frag --soft -j CT --notrack

这只是一个例子,没有什么意义。

相关内容