轉發的 ipv4 數據包的不需要的碎片整理
我想處理使用者空間中的 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
這是通過 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
.
raw/PREROUTING
所以我的問題是Linux核心中的什麼可以強制IPv4數據包在netfilter鏈之前重新組裝?我懷疑“ingress/qdisc”位於 AF_PACKET (tcpdump) 和 raw/PREROUTING 鏈之間,但我找不到問題所在。
數據包流:https ://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg
每當使用conntrack時,主要用於:
- 狀態防火牆 (
-m conntrack ...
)- NAT (
-t nat ...
)核心模組
nf_defrag_ipv4
和nf_defrag_ipv6
. 該工具以 -400 的優先級連接到網路預路由:在iptables 的原始表之前,它以 -300 的優先級連接。在一個或多個數據包遍歷之後,nf_defrag_ipv[46]
不存在任何片段:數據包被提前重新組裝。目標是 Netfilter 和 iptables 中的各種協議檢查器可以獲取所有數據包內容,包括例如 UDP 目標埠:此資訊將僅存在於第一個片段中。因此,為了避免這種情況,原始表中的
-j NOTRACK
(被 廢棄-j CT --notrack
)是不夠的。一罐:
- 永遠不要直接(有狀態規則)或間接(NAT)使用conntrack ,
- 或創建一個新的網路命名空間
直接處理流量(很可能使用被盜的物理介面或macvlan介面,或者被橋接但不被主機路由)並確保在此命名空間中不發生有狀態規則。碎片整理工具不會掛在網路命名空間中,只要沒有任何東西強制它這樣做(並且可能還有足夠新的核心)
或者有一個在優先級-400之前掛鉤的鏈條。這在最近足夠多的核心中實際上是可能的:
- 對於iptables-legacy,因為核心(可能)> = 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
(只處理後面的片段,而不是第一個,替換
0x3fff
為0x1fff
)對於 IPv6,方法不同,因為片段標頭可能不是下一個標頭。但是nft在其 man 中提供了一個簡單的表達方式:
exthdr frag exists
檢測作為片段的數據包。
- iptables-nft API不存在任何東西(這是許多發行版(如 Debian)的預設設置):它不使用模組iptable_raw並且沒有選項來創建優先級為 -450 的實際nftables鏈。
因此,如果您的命令輸出如下所示:
# iptables -V iptables v1.8.7 (nf_tables)
您不能在conntrack中單獨使用它。您必須恢復到iptables-legacy或切換到nft,或者…
- 仍然可以做的是混合nftables (上面的規則)在數據包進行碎片整理之前將數據包標記為notrack ,然後繼續使用**iptables處理剩餘部分。同時使用nftables和iptables是沒有問題的,只要理解 OP 連結的 Netfilter 示意圖中的操作順序即可。