lge*_*man 5 iptables tc linux-kernel
我想处理用户空间中的 ip 片段,并且我使用 iptables NF_QUEUE 将数据包定向到用户空间。
问题是 IPv4 数据包总是被重新组装并作为一个数据包而不是单个片段进行传递。对于 IPv6,片段按其应有的方式传递。
我认为 conntracker 可能会导致它并在raw
iptables 表中禁用它,但事实证明数据包在到达原始表时已经重新组装:
# 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
Run Code Online (Sandbox Code Playgroud)
这是通过 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
Run Code Online (Sandbox Code Playgroud)
这是在带有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
每当使用conntrack时,主要用于:
-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)使用conntrack ,
或创建一个新的网络命名空间
直接处理流量(很可能使用被盗的物理接口或macvlan接口,或者桥接但不由主机路由)并确保此命名空间中没有发生有状态规则。只要没有什么强制它这样做,碎片整理工具就不会挂接到网络名称空间中(并且可能还具有足够新的内核)
或者有一条链在优先级 -400 之前挂钩。这在最近的内核中实际上是可能的:
对于iptables-legacy,因为内核(可能)>= 4.16
# modinfo -p iptable_raw
raw_before_defrag:Enable raw table before defrag (bool)
Run Code Online (Sandbox Code Playgroud)
刷新原始表,卸载模块并重新加载(并调整/etc/modprobe.d/
):
modprobe iptable_raw raw_before_defrag=1
Run Code Online (Sandbox Code Playgroud)
对于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
Run Code Online (Sandbox Code Playgroud)
(仅处理以下片段,而不是第一个片段,替换0x3fff
为0x1fff
)
对于 IPv6,方法有所不同,因为片段标头可能不是下一个标头。但nft在其 man 中提供了一个简单的表达方式:exthdr frag exists
检测属于碎片的数据包。
iptables-nft API不存在(在许多发行版(如 Debian)上是默认的):它不使用模块iptable_raw,并且没有选项以优先级 -450创建实际的nftables链。
因此,如果您的命令的输出如下所示:
# iptables -V
iptables v1.8.7 (nf_tables)
Run Code Online (Sandbox Code Playgroud)
您不能在conntrack中单独使用它。您必须恢复到iptables-legacy或切换到nft,或者...
仍然可以做的是,在对数据包进行碎片整理之前,混合使用nftables(上述规则)将数据包标记为notrack,并继续使用iptables来处理剩余部分。同时使用nftables和iptables没有问题,只要理解 OP 链接的 Netfilter 示意图中的操作顺序即可。
归档时间: |
|
查看次数: |
1925 次 |
最近记录: |