Iptables

路由策略數據庫未檢測到標記的數據包

  • December 6, 2020

我在實驗室伺服器中有一個下表規則,如果目標地址是,則mangle標記 UDP 流量:1``6.6.6.6

$ sudo iptables -t mangle -L PREROUTING 2 -v -n --line-numbers
2       17   884 MARK       udp  --  ge-0.0.0-Iosv6 *       0.0.0.0/0            6.6.6.6              MARK set 0x1
$

6.6.6.6/32``lo在該伺服器上配置。每次我執行traceroute指向6.6.6.6時,上面的規則計數器都會增加,這是預期的。換句話說,數據包似乎被標記了。我的路由策略數據庫如下所示:

$ ip rule show
0:      from all lookup local
32764:  from all fwmark 0x2 lookup twohundred
32765:  from all fwmark 0x1 lookup threehundred
32766:  from all lookup main
32767:  from all lookup default
$

..表格threehundred如下所示:

$ ip r sh table threehundred
default via 192.168.100.2 dev ge-0.0.0-Iosv6
$

但是,標記的數據包不是基於 table 中的條目路由threehundred,而是基於 table 中的條目main。我可以通過 確認tcpdumpUDP 數據包通過 進入伺服器ge-0.0.0-Iosv6,但 ICMP回復是通過與表中的預設路由相關聯的port unreachable方式發送出去的。正如我之前提到的,表規則#2 在此期間遞增。eth0``main``mangle``PREROUTING

什麼可能導致這種行為?我正在執行 Ubuntu 16.04.6 LTS。

這是Netfilter 和通用網路示意圖中的數據包流:

Netfilter 和通用網路中的數據包流

雖然入口數據包被標記在 PREROUTING 中,但本地生成的回複數據包確實通過 OUTPUT 出口:那裡沒有標記它的規則,因此沒有標記並且路由不同。

更改 mangle/OUTPUT 中的數據包,包括更改標記等元資訊,會觸發重新路由檢查。此重新路由應將路由從eth0切換到ge-0.0.0-Iosv6(注意:使用nftables而不是iptables,需要專用的路由鏈類型才能產生此效果)。這條規則將做到這一點:

iptables -t mangle -A OUTPUT -s 6.6.6.6 -j MARK --set-mark 1

無需以兩種方式使用特定規則標記獨立數據包,而是可以自動標記整個流(由conntrack 跟踪)。可以使用connmark匹配及其*CONNMARK*目標對應項。該部落格給出了使用範例:Netfilter Connmark

對於這種情況,而不是上面的iptables規則:

  • 應該是 mangle/PREROUTING 中的最後一條規則:
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j CONNMARK --save-mark
  • 應該是 mangle/OUTPUT 中的第一條規則,因此如果需要它仍然可以更改。這將觸發重新路由檢查:
iptables -t mangle -I OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark

還有一些事情需要知道和警告,如果沒有測試,很難可靠地預測:

  • 切換fwmark_reflect(例如:)sysctl -w net.ipv4.fwmark_reflect=1對於這種特定情況可能已經足夠,並且可以代替上述規則使用,但對於更一般的情況無濟於事。同樣,也tcp_fwmark_accept可以簡化 TCP 案例。UDP 等其他協議沒有等價物。
  • 有時,由於嚴格的反向路徑轉發,路由在重新路由檢查之前失敗,並且數據包在有機會被標記和重新路由之前被提前丟棄。顯然這裡不是這種情況(甚至可能沒有啟用 SRPF),但如果發生這種情況,應該通過更改設置(例如:)。rp_filtersysctl -w net.ipv4.conf.eth0.rp_filter=2
  • 有時,主表中的一些附加路由必須在附加表中複製,因為它是在回退到表之前首先讀取的,並且可能不匹配。很難確定何時需要,尤其是涉及*標記時。*例如:
ip route add table threehundred 192.168.100.2/32 dev ge-0.0.0-Iosv6
  • ip route get ...即使提供了足夠的命令,該命令mark似乎也不能總是準確地預測涉及標記iptables時目前發生的情況。
  • 與標記、路線和預測之間的互動相關的行為可以通過未記錄的切換(也可以通過)ip route get來更改。僅當它似乎可以解決問題時才使用它。src_valid_marksysctl
  • 可以發現策略路由情況下的 UDP 伺服器行為與 TCP 伺服器行為不同,原因很複雜。使用標記只會增加複雜性。

引用自:https://unix.stackexchange.com/questions/622946