為什麼 net.bridge.bridge-nf-call-{arp,ip,ip6}tables 預設為 1?
至少在 Arch Linux 中,這是預設設置。我認為這使得網橋行為具有連續性,因為它應該像非託管交換機一樣工作,並且它現在正在丟棄數據包,因為我們大多數轉發鏈的預設策略是丟棄。
這些預設值背後有什麼原因嗎?
此功能允許通過在網橋路徑中使用iptables來增加ebtables的使用,以實現有狀態的防火牆網橋(而不是路由器)。它已經存在了很長時間(2002 年),最初沒有切換並且是橋程式碼的一部分:如果啟用了橋和網路過濾器支持,那麼它也是。
然後在 2003 年添加了切換。當然,出於兼容性原因,預設設置為啟用。
然後在核心 3.18中,該功能被分離到它自己的核心模組
br_netfilter
,因為它可能導致問題。存在對兼容性的擔憂,並且已經針對nftables棄用它的目標:請注意,這會破壞兼容性
$$ … $$但是,通過 modprobing br_netfilter 可以輕鬆消除損壞。
最重要的是,計劃是 nftables 將不依賴此軟體層,而是將連接跟踪集成到橋接層中以啟用狀態過濾和 NAT,這似乎是橋接網路過濾器使用者所需要的。
現在必須載入核心模組才能使該功能正常工作。但是,它的主要已知客戶通常會在任何橋接狀態防火牆設置中找到,它將是出於兼容性原因再次自動載入的iptables目標。
physdev
br_netfilter
所以在一個簡單的系統上,
br_netfilter
不應該載入,也不應該有任何可用的sysctl在net.bridge
:bridge-nf-call-arptables
,bridge-nf-call-ip6tables
,bridge-nf-call-iptables
(以及bridge-nf-filter-pppoe-tagged
,bridge-nf-filter-vlan-tagged
,bridge-nf-pass-vlan-input-dev
)中根本不應該出現。但是現在,這個核心模組有了一個新的主要客戶:Docker。遇到此問題的通常方式是在執行 Docker 時,因為Docker 顯式載入
br_netfilter
以能夠控制容器之間的內部通信,同時預設情況下過濾和丟棄轉發的數據包。因此,人們往往會發現它在使用中,即使在沒有預料到它的情況下,或者認為這種行為是預期的行為,但它不應該再出現了。由於預設設置是系統範圍的,除了 Docker 管理的網橋之外,它還會影響系統上的所有其他網橋:不僅是初始主機名稱空間中的網橋,還包括任何其他網路名稱空間中的網橋。
同樣,iptables的
physdev
自動載入br_netfilter
僅在它自己的模組 ( ) 本身被載入時(在此更新檔xt_physdev
之前它曾經比這更頻繁)。請注意在更新檔描述中是如何寫的:更好的解決方法是將“call-iptables”預設值更改為 0 並將顯式設置強制為 1,但這會破壞向後兼容性。
所有這一切使得這個問題的答案是:
這是出於向後兼容性的原因。
補充說明。
在目前未載入核心模組的系統上
xt_physdev
,僅允許執行使用者命名空間的普通使用者可以執行以下操作:br_netfilter
$ unshare -urnm # iptables -A FORWARD -m physdev --physdev-is-bridged # exit $
並且可能已經破壞了系統上安裝的任何其他技術(虛擬機、容器……)的 LAN 連接,這些技術沒有使用特殊和僅外觀無用的規則來保護自己免受
iptables -P FORWARD DROP
此 Netfilter 文件頁面中描述了這些效果,解釋了橋接路徑、路由路徑、ebtables 和 iptables 之間的互動: 基於 Linux 的橋接上的 ebtables/iptables 互動。第7 部分特別有用,因為它描述了應該添加什麼樣的保護,例如:
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -d 172.16.1.0/24 -j ACCEPT iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE
上面,第一條規則沒有多大意義,因為同一 LAN 中地址之間的數據包不在 IP 層轉發(即路由),而是在乙太網層作為幀轉發(橋接/交換),因此該規則永遠不匹配,因為它們不被視為路由但被橋接,並且iptables預計只能在第 3 層工作:IPv4。但是當
br_netfilter
載入這些類型的“無用規則”時變得需要,否則僅用於路由的操作將在橋接路徑的第 2 層發生(如這裡:NAT 將由同一 LAN 中的兩個節點之間的橋接完成,無需第一條規則)。正在努力(多年來)擺脫
br_netfilter
,但這需要功能奇偶校驗。對於 IP 和 IPv6(我猜是 ARP),核心 5.3、nftables和核心模組或多或少地實現了nf_conntrack_bridge
這一點,這些模組允許系列中的nftablesbridge
(不在ip
,ip6
或inet
類似br_netfilter
觸發器的系列中)使用conntrack:這提供了 `br_netfilter’ 基礎設施的替代品。
狀態過濾
自 Linux 核心 5.3 起,網橋系列就支持連接跟踪。
您只需匹配規則集中的 conntrack 狀態資訊即可啟用它。
對於那些熟悉 iptables 的人:這提供了 br_netfilter 的替代品和 iptables 的 -m physdev 匹配。
但是其他涉及 VLAN 封裝/解封裝或特別是 PPPoE 協議的功能還沒有準備好。
此外,從核心 5.3 開始,可以停用網路名稱空間範圍的功能,並使其僅在每個網路名稱空間甚至每個網橋上都處於活動狀態。但這要求創建的每個新命名空間(包括初始網路命名空間就是這樣的需要)在其內部早期執行,例如:
sysctl -w net.bridge.bridge-nf-call-arptables=0 sysctl -w net.bridge.bridge-nf-call-iptables=0 sysctl -w net.bridge.bridge-nf-call-ip6tables=0
然後對於需要它的手工挑選的橋樑,在橋樑創建(
ip link add ...
)或以後(ip link set ...
):ip link set somebridge type bridge nf_call_iptables 1
具有預設iptables設置的 Docker 無法處理此問題,因此 Docker 無法在具有此類設置的主機上同時執行,但是 Docker-in-Docker(實際上是在其他容器技術中,如 LXC 而不是 Docker原因)可能會很好,因為每個新命名空間中的預設值仍然向後兼容。