nftables - Arch Linux 中文维基

跳至內容

# nftables

出自 Arch Linux 中文维基

相關文章

- iptables
- Firewalld

翻譯狀態：

- 本文（或部分內容）譯自 nftables，最近一次同步於 2023-2-24，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

nftables 是一個網絡過濾器項目，旨在替換現有的 {ip,ip6,arp,eb}tables 框架。它提供了一個新的數據包過濾框架、一個新的用戶空間實用程序（nft）和一個針對 {ip,ip6}tables 的兼容層。它使用了現有的鉤子、連接跟蹤系統、用戶空間隊列組件和網絡過濾器的日誌子系統。

它由三個主要組件組成：內核實現、libnl 網絡連結通信和 nftables 用戶空間前端。 內核提供了一個網絡連結配置接口，以及運行時規則集計算，libnl 包含用於與內核通信的底層函數，nftables 前端供用戶通過 nft 進行交互。

你也可以訪問官方 nftables wiki 頁獲取更多信息。

## 安裝

安裝用戶空間實用程序包 nftables包 或 git 版本 nftables-gitAUR。

或者，安裝 iptables-nft包，它將 nftables包 作為一個依賴項，將自動卸載 iptables包（base包元包的間接依賴項），並在一起使用時防止 iptables包 和 nftables包 之間的衝突。

提示：大多數 iptables 前端都不直接或間接支持 nftables，但可能會引入它。[1] 一個同時支持 nftables 和 iptables 的圖形前端是 firewalld。[2]

### 前端

- firewalld (firewall-cmd) — 用於配置網絡和防火牆域以及建立和配置防火牆規則的守護進程和控制台界面。

  https://firewalld.org/ || firewalld包

- nft-blackhole — 腳本/守護進程可以按國家和黑名單阻止 nftables 中的 IP。

  https://github.com/tomasz-c/nft-blackhole || nft-blackholeAUR

- ufw — Ufw（即 Uncomplicated Firewall 的縮寫）是一個管理網絡防火牆的程序。它提供了一個命令行界面，旨在簡單（uncomplicated）易用。

  https://launchpad.net/ufw || ufw包

## 用法

提示：如果你已經擁有 iptables 規則，那麼可以將 iptables 規則轉換為 nftables 規則，參見[3]。

nftables 不區分命令行中製作的臨時規則和從文件加載或保存到文件中的永久規則。

所有規則都必須使用 `nft` 命令行工具創建或加載。

請參考 #配置章節了解如何使用。

可以列印當前規則集：

    # nft list ruleset

刪除所有規則集，使系統沒有防火牆：

    # nft flush ruleset

通過重啟 `nftables.service` 從 `/etc/nftables.conf` 讀取規則集。

### 簡單的防火牆

nftables包 附帶了一個簡單而安全的防火牆配置，存儲在 `/etc/nftables.conf` 文件中。

`nftables.service` 將在啟動或啟用時從該文件加載規則。

## 配置

nftables 的用戶空間實用程序 `nft` 在將規則集傳遞給內核之前執行大多數規則集評估。規則存儲在鏈中，而鏈又存儲在表中。以下部分說明如何創建和修改這些構件。

要從文件讀取輸入，請使用 `-f`/`--file` 選項：

    # nft --file 文件名

請注意，任何已加載的規則都不會自動刷新。

有關所有命令的完整列表，請參見 nft(8)。

### 表

表包含#鏈。與 iptables 中的表不同，nftables 中沒有內置表。表的數量及其名稱由用戶決定。不過，每個表只有一個地址族，並且僅適用於該族的數據包。表可以指定五個族之一：

nftables 族 | iptables 實用程序
--- | ---
ip | iptables
ip6 | ip6tables
inet | iptables 和 ip6tables
arp | arptables
bridge | ebtables

`ip`（即 IPv4）是默認族，如果未指定族，則將使用該族。

要創建同時適用於 IPv4 和 IPv6 的規則，請使用 `inet`。`inet` 允許統一 `ip` 和 `ip6` 族，從而使同時定義兩者的規則更加容易。

參見 nft(8) § ADDRESS FAMILIES 獲得關於地址族的完整描述。

在以下所有示例中，`族類型` 是可選的，如果未指定，則設置為 `ip`。

#### 創建表

以下示例添加一個新表：

    # nft add table 族类型 表名

#### 列出表

要列出所有表：

    # nft list tables

#### 列出表中的鏈和規則

要列出指定表的所有鏈和規則，請執行：

    # nft list table 族类型 表名

例如，要列出 `inet` 族的 `my_table` 表的所有規則：

    # nft list table inet my_table

#### 刪除表

要刪除一個表，請執行：

    # nft delete table 族类型 表名

這會銷毀表中的所有鏈。

#### 刷新表

要刷新來自表的所有規則，請執行：

    # nft flush table 族类型 表名

### 鏈

鏈的用途是包含#規則。與 iptables 中的鏈不同，nftables 中沒有內置鏈。這意味著，如果沒有鏈在網絡過濾器框架中使用任何類型或鉤子，則與 iptables 不同，nftables 將不會觸及流經這些鏈的數據包。

鏈有兩種類型。基本鏈是來自網絡堆棧的數據包的入口點，其中指定了一個鉤子值。為了更好地組織，可以使用常規鏈作為跳轉目標。

在以下所有示例中 `族類型` 都是可選的，如果未指定則設為 `ip`。

#### 創建鏈

##### 基本鏈

要添加基本鏈，請指定鉤子和優先級值：

    # nft add chain 族类型 表名 链名 '{ type 链类型 hook 钩子类型 priority 优先级值 ; }'

`鏈類型` 可以是 `filter`, `route`, 或 `nat`。

對於 IPv4/IPv6/Inet 地址族，`鉤子類型` 可以是 `prerouting`, `input`, `forward`, `output`, 或 `postrouting`。見 nft(8) § ADDRESS FAMILIES 獲取其他族的鉤子列表。

`優先級值` 採用優先級名稱或整數值。見 nft(8) § CHAINS 獲取標準優先級名稱和值的列表。數字較低的鏈首先被處理，並且可以是負數。[4]

例如，要添加過濾輸入數據包的基本鏈：

    # nft add chain inet my_table my_chain '{ type filter hook input priority 0; }'

在上述任意情況中用 `create` 替換 `add` 以添加新鏈，但如果該鏈已經存在，則返回錯誤。

##### 常規鏈

下面將常規鏈 `鏈名` 添加到表 `表名` 中：

    # nft add chain 族类型 表名 链名

例如，要將名為 `my_tcp_chain` 的常規鏈添加到 `inet` 地址族的 `my_table` 表，請執行：

    # nft add chain inet my_table my_tcp_chain

#### 列出規則

下面列出鏈的所有規則：

    # nft list chain 族类型 表名 链名

例如，下面列出名為 `my_table` 的 `inet` 表中名為 `my_output` 的鏈的規則：

    # nft list chain inet my_table my_output

#### 編輯鏈

要編輯鏈，只需按其名稱調用它並定義要更改的規則。

    # nft chain 族类型 表名 链名 '{ [ type 链类型 hook 钩子类型 device 设备名 priority 优先级值 ; policy 策略类型 ; ] }'

例如，要將 `my_table` 表的 `my_input` 鏈策略從 `accept` 更改為 `drop`

    # nft chain inet my_table my_input '{ policy drop ; }'

#### 刪除鏈

要刪除一個鏈，請執行：

    # nft delete chain 族类型 表名 链名

鏈不能包含任何規則或是跳轉目標。

#### 刷新來自鏈的規則

要刷新來自鏈的規則，請執行：

    # nft flush chain 族类型 表名 链名

### 規則

規則由表達式或語句構成，並包含在鏈中。

#### 添加規則

要向鏈添加規則，請執行：

    # nft add rule 族类型 表名 链名 handle 句柄值 语句

規則附加在 `句柄值` 處，這是可選的。如果未指定，規則將附加到鏈的末端。

應當用可以添加到任何有效列表命令的 `--handle` 開關確定規則句柄。此開關告訴 `nft` 在其輸出中列出句柄。 `--numeric` 參數用於查看某些數值輸出，如未解析的 IP 地址。

    # nft --handle --numeric list chain inet my_table my_input

    table inet my_table {
         chain input {
              type filter hook input priority 0;
              ip saddr 127.0.0.1 accept # handle 10
         }
    }

要將規則添加到指定位置，請執行：

    # nft insert rule 族类型 表名 链名 handle 句柄值 语句

如果未指定 `句柄值`，則規則將附加到鏈的開頭。

##### 表達式

通常，一個 `語句` 包括一些要匹配的表達式，然後是一個判斷語句。判斷語句包括 `accept`, `drop`, `queue`, `continue`, `return`, `jump 鏈名`, 和 `goto 鏈名`。存在判斷語句以外的其他語句。有關詳細信息，見 nft(8)。

nftables 中有各種可用的表達式，並且在很大程度上與 iptables 對應的表達式一致。最明顯的區別是沒有通用或隱式匹配。通用匹配總是可用的，例如 `--protocol` 或 `--source`。隱式匹配是特定於協議的，例如，當數據包被確定為 TCP 時，即為 `--sport`。

以下是可用匹配項的不完整列表：

- meta (元屬性，例如 interfaces)
- icmp (ICMP 協議)
- icmpv6 (ICMPv6 協議)
- ip (IP 協議)
- ip6 (IPv6 協議)
- tcp (TCP 協議)
- udp (UDP 協議)
- sctp (SCTP 協議)
- ct (連接跟蹤)

以下是匹配參數的不完整列表（有關更完整的列表，見 nft(8)）：

    meta:
      oif <output interface INDEX>
      iif <input interface INDEX>
      oifname <output interface NAME>
      iifname <input interface NAME>

      （oif 和 iif 接受字符串参数并转换为接口索引）
      （oifname 和 iifname 更动态，但由于字符串匹配，速度较慢）

    icmp:
      type <icmp type>

    icmpv6:
      type <icmpv6 type>

    ip:
      protocol <protocol>
      daddr <destination address>
      saddr <source address>

    ip6:
      daddr <destination address>
      saddr <source address>

    tcp:
      dport <destination port>
      sport <source port>

    udp:
      dport <destination port>
      sport <source port>

    sctp:
      dport <destination port>
      sport <source port>

    ct:
      state <new | established | related | invalid>

#### 刪除

單個規則只能通過其句柄刪除。獲取句柄在#添加規則中展示。假設

    # nft --handle --numeric list chain inet my_table my_input

    table inet my_table {
         chain input {
              type filter hook input priority 0;
              ip saddr 127.0.0.1 accept # handle 10
         }
    }

    # nft delete rule inet my_table my_input handle 10

刪去它。

可以使用 `nft flush table` 命令刷新表中的所有鏈。使用 `nft flush chain` 或 `nft delete rule` 命令可以刷新單個鏈。

    # nft flush table 表名
    # nft flush chain 族类型 表名 链名
    # nft delete rule 族类型 表名 链名

第一個命令刷新 ip `表名` 表中的所有鏈。第二個刷新 `族類型` `表名` 表中的 `鏈名` 鏈。第三個刪除 `族類型` `表名` 表中 `鏈名` 鏈中的所有規則。

### 集

集是命名的或匿名的，由一個或多個元素組成，用逗號分隔，用大括號括起來。匿名集嵌入到規則中，無法更新，必須刪除並重新添加規則。例如，下面您不能從 dports 的匿名集中只刪除 「http」：

    # nft add rule ip6 filter input tcp dport {telnet, http, https} accept

命名集可以被更新，並且可以被類型化和標記。sshguard 為被阻止主機的 IP 地址使用命名集。

    table ip sshguard {
           set attackers {
                   type ipv4_addr
                   flags interval
                   elements = { 1.2.3.4 }
           }

要從該集添加（add）或刪除（delete）元素（element），使用：

    # nft add element ip sshguard attackers { 5.6.7.8/32 }
    # nft delete element ip sshguard attackers { 1.2.3.4/32 }

注意，ipv4_addr 類型可以包含 CIDR 網絡掩碼（此處的 「/32」 不是必需的，但為了完整起見，包含了它）。此外請注意，這裡由 「TABLE ip sshguard { SET attackers }」 定義的集被稱為 `ip sshguard attackers`。

### 原子重載

刷新當前規則集：

    # echo "flush ruleset" > /tmp/nftables

轉儲當前規則集：

    # nft -s list ruleset >> /tmp/nftables

現在，您可以編輯 `/tmp/nftables` 並通過以下方式應用更改：

    # nft -f /tmp/nftables

## 示例

### 工作站

    /etc/nftables.conf

    flush ruleset

    table inet my_table {
    	set LANv4 {
    		type ipv4_addr
    		flags interval

    		elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 }
    	}
    	set LANv6 {
    		type ipv6_addr
    		flags interval

    		elements = { fd00::/8, fe80::/10 }
    	}

    	chain my_input_lan {
    		udp sport 1900 udp dport >= 1024 meta pkttype unicast limit rate 4/second burst 20 packets accept comment "接受 UPnP IGD 端口映射回复"

    		udp sport netbios-ns udp dport >= 1024 meta pkttype unicast accept comment "接受 Samba Workgroup 浏览回复"

    	}

    	chain my_input {
    		type filter hook input priority filter; policy drop;

    		iif lo accept comment "接受所有本机流量"
    		ct state invalid drop comment "丢弃无效连接"
    		ct state established,related accept comment "接受来自我们（us）的流量"

    		meta l4proto ipv6-icmp accept comment "接受 ICMPv6"
    		meta l4proto icmp accept comment "接受 ICMP"
    		ip protocol igmp accept comment "接受 IGMP"

    		udp dport mdns ip6 daddr ff02::fb accept comment "接受 mDNS"
    		udp dport mdns ip daddr 224.0.0.251 accept comment "接受 mDNS"

    		ip6 saddr @LANv6 jump my_input_lan comment "来自专用 IP 地址范围的连接"
    		ip saddr @LANv4 jump my_input_lan comment "来自专用 IP 地址范围的连接"

    		counter comment "统计任何其他流量"
    	}

    	chain my_forward {
    		type filter hook forward priority filter; policy drop;
    		# 丢弃转发给我们的所有内容。我们不转发。这是路由器的工作。
    	}

    	chain my_output {
    		type filter hook output priority filter; policy accept;
    		# 接受每个出站连接
    	}

    }

### 伺服器

    /etc/nftables.conf

    flush ruleset

    table inet my_table {
    	set LANv4 {
    		type ipv4_addr
    		flags interval

    		elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 }
    	}
    	set LANv6 {
    		type ipv6_addr
    		flags interval

    		elements = { fd00::/8, fe80::/10 }
    	}

    	chain my_input_lan {
    		meta l4proto { tcp, udp } th dport 2049 accept comment "接受 NFS"

    		udp dport netbios-ns accept comment "接受 NetBIOS 名称服务 (nmbd)"
    		udp dport netbios-dgm accept comment "接受 NetBIOS 数据报服务 (nmbd)"
    		tcp dport netbios-ssn accept comment "接受 NetBIOS 会话服务 (smbd)"
    		tcp dport microsoft-ds accept comment "接受 Microsoft 目录服务 (smbd)"

    		udp sport { bootpc, 4011 } udp dport { bootps, 4011 } accept comment "接受 PXE"
    		udp dport tftp accept comment "接受 TFTP"
    	}

    	chain my_input {
    		type filter hook input priority filter; policy drop;

    		iif lo accept comment "接受所有本机流量"
    		ct state invalid drop comment "丢弃无效链接"
    		ct state established,related accept comment "接受来自我们（us）的流量"

    		meta l4proto ipv6-icmp accept comment "接受 ICMPv6"
    		meta l4proto icmp accept comment "接受 ICMP"
    		ip protocol igmp accept comment "接受 IGMP"

    		udp dport mdns ip6 daddr ff02::fb accept comment "接受 mDNS"
    		udp dport mdns ip daddr 224.0.0.251 accept comment "接受 mDNS"

    		ip6 saddr @LANv6 jump my_input_lan comment "来自专用 IP 地址范围的连接"
    		ip saddr @LANv4 jump my_input_lan comment "来自专用 IP 地址范围的连接"

    		tcp dport ssh accept comment "在 端口 22 上接受 SSH"

    		tcp dport ipp accept comment "在端口 631 上接受 IPP/IPPS"

    		tcp dport { http, https, 8008, 8080 } accept comment "接受 HTTP (端口 80, 443, 8008, 8080)"

    		udp sport bootpc udp dport bootps ip saddr 0.0.0.0 ip daddr 255.255.255.255 accept comment "接受 DHCPDISCOVER (对于 DHCP-Proxy)"
    	}

    	chain my_forward {
    		type filter hook forward priority filter; policy drop;
    		# 丢弃转发给我们的所有内容。我们不转发。这是路由器的工作。
    	}

    	chain my_output {
    		type filter hook output priority filter; policy accept;
    		# 接受每个出站连接
    	}

    }

### 限速

    table inet my_table {
    	chain my_input {
    		type filter hook input priority filter; policy drop;

    		iif lo accept comment "接受所有本机流量"
    		ct state invalid drop comment "丢弃无效链接"

    		meta l4proto icmp icmp type echo-request limit rate over 10/second burst 4 packets drop comment "无 ping 洪流"
    		meta l4proto ipv6-icmp icmpv6 type echo-request limit rate over 10/second burst 4 packets drop comment "无 ping 洪流"

    		ct state established,related accept comment "接受来自我们（us）的流量"

    		meta l4proto ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, echo-reply, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept comment "接受 ICMPv6"
    		meta l4proto icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept comment "接受 ICMP"
    		ip protocol igmp accept comment "接受 IGMP"

    		tcp dport ssh ct state new limit rate 15/minute accept comment "避免在 SSH 上使用暴力破解"

    	}

    }

### 跳轉（Jump）

在配置文件中使用跳轉時，必須首先定義目標鏈。否則可能會出現 `Error: Could not process rule: No such file or directory`。

    table inet my_table {
        chain web {
            tcp dport http accept
            tcp dport 8080 accept
        }
        chain my_input {
            type filter hook input priority filter;
            ip saddr 10.0.2.0/24 jump web
            drop
        }
    }

### 不同接口的不同規則

如果您的機箱有多個網絡接口，並且您希望對不同的接口使用不同的規則，那麼您可能需要使用 「分派（dispatching）」 過濾器鏈，然後使用特定於接口的過濾器鏈。例如，假設您的機箱充當家庭路由器，您希望運行可通過 LAN 訪問的網絡伺服器（接口 `enp3s0`），但不能從公共網絡訪問（接口 `enp2s0`）。您可能需要考慮這樣的結構：

    table inet my_table {
      chain my_input { # 该链充当分派器
        type filter hook input priority filter;

        iif lo accept comment "始终接受环回"
        iifname enp2s0 jump my_input_public
        iifname enp3s0 jump my_input_private

        reject with icmpx port-unreachable comment "拒绝来自所有其他接口的流量"
      }
      chain my_input_public { # 适用于公共接口界面的规则
        ct state {established,related} accept
        ct state invalid drop
        udp dport bootpc accept
        tcp dport bootpc accept
        reject with icmpx port-unreachable comment "所有其它流量"
      }
      chain my_input_private {
        ct state {established,related} accept
        ct state invalid drop
        udp dport bootpc accept
        tcp dport bootpc accept
        tcp port http accept
        tcp port https accept
        reject with icmpx port-unreachable comment "所有其它流量"
      }
      chain my_output { # 我们把一切都放出来
        type filter hook output priority filter;
        accept
      }
    }

或者，您可以只選擇一個 `iifname` 語句，例如針對單個上游接口，並將所有其他接口的默認規則放在一個位置，而不是為每個接口分派。

### 偽裝（Masquerading）

nftables 有一個特別的關鍵字 `masquerade`「其中源地址被自動設為輸出接口的地址」（來源）。這對於接口的 IP 地址不可預測或不穩定的情況尤其有用，例如連接到許多 ISP 的路由器的上游接口。如果沒有它，每次接口的 IP 地址更改時都必須更新網絡地址轉換規則。

要使用它：

- 確保在內核中啟用偽裝（如果使用默認內核，則已啟用），否則請在內核配置期間，設置 `CONFIG_NFT_MASQ=m`。
- `masquerade` 關鍵字只能在 `nat` 類型的鏈中使用。
- 偽裝是一種源網絡地址轉換（NAT），因此只在輸出路徑中工作。

具有兩個接口的機器示例：LAN 連接到 `enp3s0`，公共網絡連接到 `enp2s0`：

    table inet my_nat {
      chain my_masquerade {
        type nat hook postrouting priority srcnat;
        oifname "enp2s0" masquerade
      }
    }

由於表類型為 `inet`，IPv4 和 IPv6 數據包都將被偽裝。如果您只希望 ipv4 數據包被偽裝（因為 IPv6 的額外地址空間不需要 NAT），可以在 `oifname "enp2s0"` 前面使用 `meta nfproto ipv4` 表達式，或者可以將表類型更改為 `ip`。

### 帶埠轉發的 NAT

本文或本章節的事實準確性存在爭議。

原因： I think `my_postrouting` chain will cause the destination computer see that connections are made by router rather than from some global IP. Also this does not masquerade outbound traffic.（在 Talk:Nftables 中討論）

此示例將埠22和80轉發到 `destination_ip`。您需要通過 sysctl 將 `net.ipv4.ip_forward` 和 `net.ipv4.conf.wan_interface.forwarding` 設置為 `1`。

    table ip my_nat {
      chain my_prerouting {
        type nat hook prerouting priority dstnat;

        tcp dport { ssh, http } dnat to destination_ip
      }

      chain my_postrouting {
        type nat hook postrouting priority srcnat;

        ip daddr destination_ip masquerade
      }
    }

### 計算每個 IP 的新連接數

使用此代碼段計算 HTTPS 連接數：

    /etc/nftables.conf

    table inet filter {
        set https {
            type ipv4_addr;
            flags dynamic;
            size 65536;
            timeout 60m;
        }

        chain input {
            type filter hook input priority filter;
            ct state new tcp dport 443 update @https { ip saddr counter }
        }
    }

要列印計數器，請運行 `nft list set inet filter https`。

### 動態黑洞

使用此代碼段可以在1分鐘內從超過 10/秒 限制的源 IP 斷開所有 HTTPS 連接。

    /etc/nftables.conf

    table inet dev {
        set blackhole {
            type ipv4_addr;
            flags dynamic, timeout;
            size 65536;
        }

        chain input {
            ct state new tcp dport 443 \
                    meter flood size 128000 { ip saddr timeout 10s limit rate over 10/second } \
                    add @blackhole { ip saddr timeout 1m }

            ip saddr @blackhole counter drop
        }
    }

要列印黑洞的 IP，請運行 `nft list set inet dev blackhole`。

## 提示和技巧

### 保存當前規則集

`nft list ruleset` 命令的輸出也是它的有效輸入文件。當前規則集可以保存到文件中，稍後再加載回。

    $ nft -s list ruleset | tee filename

注意：`nft list` 不輸出變量定義，如果原始文件中有任何變量定義，它們將丟失。規則中使用的任何變量都將被其值替換。

### 簡單的狀態防火牆

本文或本章節的事實準確性存在爭議。

原因： 這不是一個非常簡單的防火牆。我認為 Arch Linux 在 /etc/nftables.conf 中提供的內容很簡單。建議用該腳本替換此部分，並給出如何根據特定需要擴展該部分的一些指導。（在 Talk:Nftables 中討論）

見 Simple stateful firewall 獲取更多信息。

#### 單機

刷新當前規則集：

    # nft flush ruleset

添加一個表：

    # nft add table inet my_table

添加輸入（input）、轉發（forward）和輸出（output）基本鏈。輸入和轉發的策略將是丟棄。輸出的策略是接受。

    # nft add chain inet my_table my_input '{ type filter hook input priority 0 ; policy drop ; }'
    # nft add chain inet my_table my_forward '{ type filter hook forward priority 0 ; policy drop ; }'
    # nft add chain inet my_table my_output '{ type filter hook output priority 0 ; policy accept ; }'

添加兩個將與 tcp 和 udp 關聯的常規鏈：

    # nft add chain inet my_table my_tcp_chain
    # nft add chain inet my_table my_udp_chain

將接受相關（related）和已建立（established）的流量：

    # nft add rule inet my_table my_input ct state related,established accept

將接受所有環回接口流量：

    # nft add rule inet my_table my_input iif lo accept

丟棄所有無效流量：

    # nft add rule inet my_table my_input ct state invalid drop

接受 ICMP 和 IGMP：

    # nft add rule inet my_table my_input meta l4proto ipv6-icmp accept
    # nft add rule inet my_table my_input meta l4proto icmp accept
    # nft add rule inet my_table my_input ip protocol igmp accept

新的 udp 流量將跳轉到 UDP 鏈：

    # nft add rule inet my_table my_input meta l4proto udp ct state new jump my_udp_chain

新的 tcp 流量將跳轉到 TCP 鏈：

    # nft add rule inet my_table my_input 'meta l4proto tcp tcp flags & (fin|syn|rst|ack) == syn ct state new jump my_tcp_chain'

拒絕其他規則未處理的所有流量：

    # nft add rule inet my_table my_input meta l4proto udp reject
    # nft add rule inet my_table my_input meta l4proto tcp reject with tcp reset
    # nft add rule inet my_table my_input counter reject with icmpx port-unreachable

此時，您應該決定要向傳入連接打開哪些埠，這些埠由 TCP 和 UDP 鏈處理。例如，要打開網絡伺服器的連接，請添加：

    # nft add rule inet my_table my_tcp_chain tcp dport 80 accept

要接受網絡伺服器的 HTTPS 連接在埠 443：

    # nft add rule inet my_table my_tcp_chain tcp dport 443 accept

要接受 SSH 流量在埠 22：

    # nft add rule inet my_table my_tcp_chain tcp dport 22 accept

要接受傳入的DNS請求：

    # nft add rule inet my_table my_tcp_chain tcp dport 53 accept
    # nft add rule inet my_table my_udp_chain udp dport 53 accept

確保在滿意後使您的更改永久化。

### 防止暴力攻擊

Sshguard 是個程序，它可以檢測暴力攻擊，並根據臨時列入黑名單的 IP 地址修改防火牆。見 Sshguard#nftables 了解如何設置與之一起使用的 nftables。

### 記錄流量

你可以使用 `log` 操作記錄數據包。記錄所有傳入流量的最簡單規則是：

    # nft add rule inet filter input log

見 nftables wiki 獲取詳情。

## 故障排除

### 與 Docker 一起工作

注意：

- 使用以下設置，即使具有 `--net host --privileged`，您也無法在容器內使用 `AF_BLUETOOTH` 等協議。
- 無根 Docker 容器已經在單獨的網絡命名空間中運行。你可能不需要做任何事情。

使用 nftables 可能會干擾 Docker 網絡（以及其他容器運行時）。您可以在網際網路上找到各種解決方案，其中包括修補 iptables 規則並確保定義的服務啟動順序，或者完全禁用 dockers iptables 管理，這使得使用 docker 非常受限（想想埠轉發或 docker-compose）。

一種可靠的方法是讓 docker 在一個單獨的網絡命名空間中運行，在那裡它可以為所欲為。最好不要使用 iptables-nft包 來防止 docker 混合 nftables 和 iptables 規則。

使用以下 docker 服務放置文件[損壞的連結：無效的章節]：

    /etc/systemd/system/docker.service.d/netns.conf

    [Service]
    PrivateNetwork=yes

    # 清理
    ExecStartPre=-nsenter -t 1 -n -- ip link delete docker0

    # 添加虛擬接口
    ExecStartPre=nsenter -t 1 -n -- ip link add docker0 type veth peer name docker0_ns
    ExecStartPre=sh -c 'nsenter -t 1 -n -- ip link set docker0_ns netns "$$BASHPID" && true'
    ExecStartPre=ip link set docker0_ns name eth0

    # 使主機聯機
    ExecStartPre=nsenter -t 1 -n -- ip addr add 10.0.0.1/24 dev docker0
    ExecStartPre=nsenter -t 1 -n -- ip link set docker0 up

    # 使命名伺服器聯機
    ExecStartPre=ip addr add 10.0.0.100/24 dev eth0
    ExecStartPre=ip link set eth0 up
    ExecStartPre=ip route add default via 10.0.0.1 dev eth0

如果 `10.0.0.*` IP 地址不適合您的設置，請調整它們。

使用以下後路由規則為 docker0 啟用 IP 轉發並設置 NAT：

    iifname docker0 oifname eth0 masquerade

然後，確保已啟用內核 IP 轉發。

現在，您可以使用 nftables 為 `docker0` 接口設置防火牆和埠轉發，而不受任何干擾。

## 另見

- 網絡過濾器 nftables wiki
- debian:nftables
- gentoo:nftables
- First release of nftables
- nftables quick howto
- The return of nftables
- What comes after 『iptables』? Its successor, of course: `nftables`

分類：​

- 防火牆

隱藏分類：​

- 使用「模板:準確性」標記的頁面或章節
- 包含損壞章節連結的頁面

nftables
新增話題