我的防火墙配置有问题。我想阻止特定接口中的所有 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
表格中,可能只有在才有意义PREROUTING
,ip6tables将能够看到碎片。它可以在那里过滤它们,或者选择跳过 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
这只是一个例子,没有什么意义。