使用 iptables 與 nftables 進行 Linux 封包過濾

最後更新: 2026-08-23 11:46:28 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

Linux 封包過濾由 Netfilter 實作。Netfilter 是一個在網路堆疊中公開掛鉤的核心框架。iptables 與 nftables 並不是彼此獨立的防火牆,而是在這些掛鉤處對封包分類與動作進行程式設計的使用者空間介面。

iptables 是歷史悠久的介面。使用 nft 指令設定的原生 nftables,以一種語言和一個 Netlink API,取代了分開存在的 iptables、ip6tables、arptables 與 ebtables 規則管理模型。相容性工具仍可接受 iptables 語法,同時寫入 nftables 核心後端,因此單憑指令名稱無法判定目前啟用的實作。

Netfilter 封包流程 #

封包在網路堆疊中移動時,Netfilter 會呼叫已註冊的作業:

NetworkIningresspreroutingRoutffeoorrDwweaacrriddsiopNnoe+st-twi-ron-orp-uku-tt-iO>nugtLocalouPtrpouctess

路由決策會決定封包經過哪條路徑:

  • 尋址至本機 socket 的封包會經過 prerouting 與 input。
  • 經由主機轉送的封包會經過 prerouting、forward 與 postrouting。
  • 在本機建立的封包會經過 output 與 postrouting。
  • 可選的裝置專用 ingress 掛鉤會在 prerouting 之前執行。

ingress 掛鉤可以在後續網路處理發生前拒絕流量,但此時 IP 分片尚未重新組裝。因此,在該位置讀取 TCP 或 UDP 標頭的規則無法分類非初始分片。

掛鉤名稱描述封包處理中的位置,而不是內建規則。nftables 預設不會建立鏈;規則集必須明確將基礎鏈附加至每個需要的掛鉤。

三種介面與兩種核心 API #

目前的系統可以提供三種命令介面,它們由兩種不同的核心規則 API 支援:

iixgpp_ettttaaa/bbbsllleeeetssss-olsAceyPkgnIoatpcatyxiippttaabblleess-nsfytntnNafex_ttlaibnlkesAPInnffttablessyntax
  • iptables-legacy 會操作歷史上的 x_tables 核心 API。
  • iptables-nft 接受 iptables 語法,但透過相容層與 nft_compat 操作 nf_tables。
  • nft 使用原生 nftables 語言與 nf_tables Netlink API。

nftables 後端會將規則編譯為核心內、網路專用虛擬機的指令。它會重複使用既有的 Netfilter 掛鉤、連線追蹤、NAT、記錄、佇列及其他支援基礎設施。

請確認選取的 iptables 後端,不要根據二進位檔名稱推斷:

sh
iptables --version
readlink -f "$(command -v iptables)"

包含 (nf_tables) 的版本字串表示使用 nftables 後端。發行版 alternatives 或符號連結可能改變選取結果。

iptables 模型 #

iptables 將規則整理到預先定義的表與內建鏈中。主要的 IPv4 表如下:

TablePrimary Purpose
filter接受或拒絕通過 INPUT、FORWARD 與 OUTPUT 的封包。
nat為新連線建立位址或連接埠轉譯。
mangle修改封包欄位與標記,以進行特殊處理。
raw在連線追蹤前執行,包括 NOTRACK 判斷。
security套用 Linux 安全模組使用的安全標記。

鏈中的規則會依序評估。匹配條件可以根據介面、位址、協定、連接埠、連線狀態、標記或擴充功能專屬屬性選取封包。目標接著可以接受、丟棄、拒絕、記錄、轉譯封包,或將控制權轉移到另一條鏈。

IPv4 與 IPv6 使用分開的命令與規則集:

sh
iptables -A INPUT -p tcp --dport 22 \
  -m conntrack --ctstate NEW -j ACCEPT

ip6tables -A INPUT -p tcp --dport 22 \
  -m conntrack --ctstate NEW -j ACCEPT

iptables-legacy 的增量修改需要讀取、修改並取代一個表。因此,同時寫入的程序會透過 xtables 鎖進行協調。相較於包含許多獨立 iptables -A 命令的 shell 指令稿,iptables-restore 更為適合,因為它會取代完整的表,而不是暴露一連串部分策略。

nftables 模型 #

nftables 使用由家族、表、鏈、規則與具狀態物件組成的階層:

  1. 家族選取封包網域:ip、ip6、inet、arp、bridge 或 netdev。
  2. 表是鏈、集合、對映、計數器與流量表的命名空間。
  3. 基礎鏈附加至 Netfilter 掛鉤,並宣告鏈類型、優先順序與可選的預設策略。
  4. 一般鏈沒有掛鉤,透過 jump 或 goto 到達。
  5. 規則由左至右評估運算式,並在運算式匹配時執行陳述式。

inet 家族允許單一規則集處理 IPv4 與 IPv6 流量。協定專用運算式仍只會選取一個協定家族;例如,ip saddr 匹配 IPv4 位址,而 ip6 saddr 匹配 IPv6 位址。

雙堆疊主機防火牆 #

以下檔案定義具狀態、預設拒絕的輸入策略,同時允許回送流量、回應、診斷用 ICMP,以及來自 IPv4 管理網路的 SSH:

nft
#!/usr/sbin/nft -f

flush ruleset

table inet firewall {
    set admin_ipv4 {
        type ipv4_addr
        flags interval
        elements = { 192.0.2.0/24 }
    }

    chain input {
        type filter hook input priority filter
        policy drop

        ct state invalid drop
        ct state established,related accept

        iifname "lo" accept
        meta l4proto { icmp, ipv6-icmp } accept
        ip saddr @admin_ipv4 tcp dport 22 accept
    }

    chain forward {
        type filter hook forward priority filter
        policy drop
    }

    chain output {
        type filter hook output priority filter
        policy accept
    }
}

將檔案驗證並以單一交易載入:

sh
nft --check --file /etc/nftables.conf
nft --file /etc/nftables.conf
nft list ruleset

nft --file 會解析完整批次,並將其作為單一核心交易提交。如果任何命令失敗,交易就不會部分提交。在同一個檔案中放置 flush ruleset,即可以原子方式取代受管理的規則集。重複載入追加型檔案時省略 flush,可能造成規則重複。

當其他服務擁有無關的 nftables 表時,不要使用 flush ruleset。在此情況下,只取代分配給目前元件的表。

掛鉤、優先順序與判決 #

基礎鏈宣告會控制其執行時機:

nft
type filter hook input priority filter; policy drop;
  • type filter 選取一般封包過濾。
  • hook input 將鏈附加至本機遞送流量。
  • priority filter 將其置於標準過濾優先順序,數值為零。
  • policy drop 會在評估到達結尾且沒有其他判決時套用。

多個基礎鏈可以附加至同一個掛鉤。Netfilter 會按照數值優先順序由低至高評估,其中包括分片重組、連線追蹤、目的地 NAT 與來源 NAT 等內部作業。

accept 判決會結束目前的鏈,但同一掛鉤上較晚執行的基礎鏈仍可丟棄封包。drop 判決會立即丟棄封包。因此,防火牆分析必須包含掛鉤上的每一條基礎鏈,而不只是第一條回傳 accept 的鏈。

一般鏈的控制流程也有所不同:

  • jump service_checks 進入另一條鏈,並在該鏈到達結尾時返回。
  • goto service_checks 轉移控制權,但不返回呼叫鏈。
  • return 恢復呼叫鏈;從基礎鏈返回時,則套用基礎鏈策略。

連線追蹤 #

nf_conntrack 子系統會將封包關聯至流量。iptables 與 nftables 都使用它進行具狀態過濾與 NAT。常見狀態如下:

StateMeaning
new有效封包啟動尚未完成雙向流量交換的流量,或屬於該流量。
establishedConntrack 已觀察到雙向的有效流量。
related新流量與現有的受追蹤連線相關聯。
invalid封包無法關聯至有效的受追蹤流量。
untracked先前的策略明確將封包排除在追蹤之外。

具狀態規則可以在不開放所有暫時性目的地連接埠的情況下允許回應流量:

nft
ct state established,related accept
ct state invalid drop

Conntrack 會消耗有限的核心記憶體。如果其表達到 nf_conntrack_max,核心就無法追蹤更多流量,並可能丟棄新的流量。請同時監控這兩個值:

sh
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max

未計算記憶體使用量就提高上限,只會移動資源限制。高流量系統還需要檢查逾時、驗證流量並監控容量。

網路位址轉譯 #

具狀態 NAT 會根據受追蹤流量的第一個封包建立轉譯繫結。後續封包會使用 conntrack 狀態,而不是重新評估每一條 NAT 規則。因此,過濾應放在 filter 鏈,而不是 NAT 鏈。

路由器可以如下定義目的地 NAT 與來源 NAT:

nft
table inet nat {
    chain prerouting {
        type nat hook prerouting priority dstnat
        tcp dport 443 dnat ip to 192.0.2.20:8443
    }

    chain postrouting {
        type nat hook postrouting priority srcnat
        oifname "wan0" masquerade
    }
}

inet 家族中的 NAT 需要 Linux 5.2 或更新版本。較舊的核心需要分開的 ip 與 ip6 NAT 表。

  • DNAT 通常在 prerouting 執行,此時尚未選取轉送路由。
  • SNAT 與 masquerade 通常在 postrouting 執行,此時已完成路由選取。
  • redirect 會將流量傳送至本機。
  • masquerade 會從輸出介面推導來源位址,適合該位址可能變更的情況。

NAT 不是安全性策略。經過轉譯的封包仍必須通過相關的 input 或 forward 過濾策略。

集合、對映與串接 #

iptables 規則集通常以線性規則表示重複值,或依賴獨立的 ipset 功能。nftables 整合了具型別的資料結構:

nft
set web_ports {
    type inet_service
    elements = { 80, 443 }
}

map service_targets {
    type inet_service : ipv4_addr
    elements = {
        80 : 192.0.2.10,
        443 : 192.0.2.20
    }
}
  • 集合判斷鍵是否存在。
  • 對映回傳鍵所對應的值。
  • 判決對映回傳 accept、drop 或 jump chain 等判決。
  • 串接會將來源位址與目的地連接埠等欄位組合為一個複合鍵。

具名集合可以在不重建所有參照它的規則下更新。區間集合能夠緊湊地表示位址與連接埠範圍。對映與串接可減少幾乎相同規則的長串,因為查找會直接選取資料或控制流程。

計數器、記錄與追蹤 #

規則只有在包含計數器陳述式或參照具名計數器時,才會計算流量:

nft
tcp dport 22 counter accept

記錄是非終止陳述式,因此一條規則可以同時記錄並作出判決:

nft
ct state invalid log prefix "invalid: " limit rate 10/second drop

封包觸發的記錄可能消耗 CPU、儲存空間與記錄服務容量,因此必須進行速率限制。

nftables 追蹤會記錄選定封包的規則遍歷。使用範圍狹窄的規則啟用追蹤:

nft
meta l4proto tcp tcp dport 443 meta nftrace set 1

然後觀察事件:

sh
nft monitor trace

診斷完成後移除追蹤規則,因為廣泛追蹤可能產生大量事件串流。

從 iptables 遷移 #

遷移有兩個不同目標:

  1. 相容性遷移在保留 iptables 語法的同時變更核心後端。iptables-nft-restore 會將 iptables-save 檔案載入 nf_tables。
  2. 原生遷移先進行轉換,再以 nftables 語法重新設計策略。

變更任一後端前,先盤點所有作用中規則的擁有者:

sh
iptables --version
iptables-legacy-save
ip6tables-legacy-save
nft list ruleset

轉換工具不會修改即時規則集:

sh
iptables-legacy-save > iptables-v4.save
ip6tables-legacy-save > iptables-v6.save

iptables-restore-translate -f iptables-v4.save > rules-v4.nft
ip6tables-restore-translate -f iptables-v6.save > rules-v6.nft

轉換只是起點,因為它會保留舊有結構。請檢查輸出中的:

  • 不支援或僅部分支援的 xtables 擴充;
  • 可合併為單一 inet 規則的重複 IPv4 與 IPv6 規則;
  • 應轉換為集合、對映或判決對映的重複規則;
  • 鏈策略、計數器、記錄速率與 NAT 行為;
  • 對標記、路由策略、介面、命名空間或連線追蹤輔助程式的依賴;
  • 由容器引擎、虛擬機器管理器、入侵防禦工具或防火牆前端動態插入的規則。

iptables-nft 適合作為過渡介面,因為其變更是原子的,且可透過 nft list ruleset 查看。它仍然表達 xtables 語意,部分擴充可能繼續透過 nft_compat 包裝,而不會轉為原生 nftables 運算式。

共存與規則擁有權 #

不要將 iptables-legacy 與 nftables 作為相同流量的獨立管理者運作。舊版 x_tables 規則與 nf_tables 規則是分開的核心規則集,任一命令檢視都無法提供完整策略。封包可能通過兩者,造成看似規則遺失或互相矛盾的故障。

iptables-nft 與 nft 共用 nf_tables 後端,但共用儲存空間不代表共用擁有權。使用原生命令編輯由相容工具產生的鏈,可能違反建立該鏈的工具所依賴的假設。

請明確分配擁有權:

  • 使用單一服務載入主機防火牆。
  • 在編排系統支援該模型時,為其提供分開的表。
  • 確認 firewalld、容器引擎、Kubernetes 元件、虛擬機器管理器、VPN 軟體與封鎖工具是否會新增規則。
  • 不要清除其他元件擁有的表。
  • 透過發行版的 nftables 服務或選定的防火牆管理器持久化規則,而不是透過彼此競爭的啟動指令稿。

後端支援取決於軟體版本與發行版封裝方式。請檢查已部署的系統,不要假設工具名稱代表舊版或原生 nftables 行為。

專案狀態 #

nftables 自 Linux 上游核心 3.13 版起即可使用。Netfilter 專案自 2018 年 6 月起將原始 xtables/setsockopt 工具視為舊版工具,但仍持續在 nftables 後端上提供 iptables 相容工具。

因此,目前的 iptables 套件有兩項職責:維護既有的舊版部署,以及提供通往 nf_tables 的相容路徑。核心、nftables 與 iptables 版本仍依發行版而異;請驗證已部署的後端與所需功能版本,不要依賴發行版名稱。

維運檢查清單 #

  1. 變更遠端主機的 input 策略前,確保有可用的頻外主控台。
  2. 套用前使用 nft --check --file 驗證檔案。
  3. 使用 nft --file 載入完整變更,而不是執行依序排列的 shell 指令。
  4. 強制執行預設拒絕策略前,先建立回送與管理存取。
  5. 檢查每個掛鉤上的所有基礎鏈與優先順序。
  6. 監控計數器、記錄、conntrack 容量與規則集變更。
  7. 將 NAT、封包過濾、路由與流量控制視為彼此獨立的策略,因為其中一項不能取代其他項目。
  8. 為每個表保留一個權威擁有者,並記錄動態管理的表。

對於新的 Linux 防火牆設計,原生 nftables 提供清晰的模型、雙堆疊 inet 規則、整合的集合與對映,以及交易式更新。iptables 相容性對現有應用程式仍然有價值,但應將其視為遷移機制,而不是新規則集的架構。

參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)