对转发的 ipv4 数据包进行不需要的碎片整理

对转发的 ipv4 数据包进行不需要的碎片整理

我想处理用户空间中的 ip 片段,并且我使用 iptables NF_QUEUE 将数据包定向到用户空间。

问题是 IPv4 数据包总是被重新组装并作为一个数据包而不是单个片段进行传递。对于 IPv6,片段按其应有的方式传送。

我认为 conntracker 可能会导致它并在rawiptables 表中禁用它,但事实证明数据包在到达原始表时已经重新组装:

# iptables -t raw -nvL
Chain PREROUTING (policy ACCEPT 58 packets, 62981 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    1 30028 CT         all  --  *      *       0.0.0.0/0            10.0.0.0/24          NOTRACK

这是通过 IPv4 发送 30000 字节 UDP 数据包时的情况。 IPv6对应的:

# ip6tables -t raw -nvL
Chain PREROUTING (policy ACCEPT 46 packets, 62304 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   21 31016 CT         all      *      *       ::/0                 1000::               NOTRACK

这是在带有virtio网络设备的虚拟环境kvm/qemu中,mtu=1500。某些硬件卸载似乎不会导致此问题,因为我可以看到所有带有tcpdump -ni eth2 host 10.0.0.0.

所以我的问题是 Linux 内核中的什么可以强制 IPv4 数据包在 netfilter 链之前重新组装raw/PREROUTING

我怀疑“ingress/qdisc”,因为它位于 AF_PACKET (tcpdump) 和 raw/PREROUTING 链之间,但我找不到问题。

数据包流向:https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg

答案1

每当连线正在使用中,主要用于:

  • 状态防火墙 ( -m conntrack ...)
  • 网络地址转换 ( -t nat ...)

nf_defrag_ipv4 加载由内核模块提供的附加隐藏设施nf_defrag_ipv6提供的附加隐藏设施。该设施以优先级 -400 连接到网络预路由:即之前iptables'原始表以优先级 -300 挂钩。在数据包遍历之后,nf_defrag_ipv[46]不存在任何片段:数据包被提前重新组装。目标是 Netfilter 和 iptables 中的各种协议检查器可以获得所有数据包内容,包括 UDP 目标端口:此信息仅出现在第一个片段中。

因此,为了避免这种情况,原始表中的-j NOTRACK(obsoleted by ) 是不够的。-j CT --notrack

一罐:

  • 从不使用连线直接(状态规则)或间接(NAT),

  • 或创建一个新的网络命名空间

    直接处理流量(很可能使用被盗的物理接口,或者麦克夫兰接口,或被桥接但未路由由主机)并确保此名称空间中没有发生有状态规则。只要没有什么强制它这样做,碎片整理工具就不会挂接到网络命名空间中(并且可能还具有足够新的内核)

  • 或者有一条链在优先级 -400 之前挂钩。这在最近的内核中实际上是可能的:

    • 为了iptables-旧版自从内核(可能)>= 4.16

      # modinfo -p iptable_raw
      raw_before_defrag:Enable raw table before defrag (bool)
      

      刷新原始表,卸载模块并重新加载(并调整/etc/modprobe.d/):

      modprobe iptable_raw raw_before_defrag=1
      
    • 为了nftables

      只需创建优先级低于-400的链,例如:

      nft add table ip handlefrag
      nft add chain ip handlefrag predefrag '{ type filter hook prerouting priority -450; policy accept; }'
      nft add rule ip handlefrag predefrag ip 'frag-off & 0x3fff != 0' notrack 
      

      (仅处理以下片段,而不是第一个片段,替换0x3fff0x1fff

      对于 IPv6,方法有所不同,因为片段头可能不是下一个标题。但NFFT在其 man 中提供了一个简单的表达:exthdr frag exists检测属于片段的数据包。

    • 不存在任何东西iptables-nftAPI(在许多发行版(如 Debian)上是默认的):它不使用该模块iptable_raw并且没有创建实际的选项nftables优先级为 -450 的链。

      因此,如果您的命令的输出如下所示:

      # iptables -V
      iptables v1.8.7 (nf_tables)
      

      你不能单独使用这个连线。您必须恢复到iptables-旧版或切换到NFFT, 或者...

    • 仍然可以做的就是混合nftables(上述规则)将数据包标记为不追踪在对它们进行碎片整理之前,然后继续iptables来处理剩下的部分。使用上没有任何问题nftablesiptables同时,只要理解OP链接的Netfilter示意图中的操作顺序即可。

答案2

iptables有(对于 IPv4)该-f标志。添加它应该可以工作。还要检查链条INPUT

[!] -f, --fragment

这意味着该规则仅涉及分段数据包的第二个及更多 IPv4 分段。由于无法知道此类数据包(或 ICMP 类型)的源端口或目标端口,因此此类数据包将不匹配指定它们的任何规则。当。。。的时候 ”!”参数位于“-f”标志之前,规则将仅匹配头片段或未分段的数据包。此选项是 IPv4 特定的,在 ip6tables 中不可用。

相关内容