nftables精講與例子(NAT、限速、限流量、禁ping等例子)
前言
- 本文先說明語法規則,再展示命令示例,最后詳細解釋相關知識
- 相信你認真看完本文,并按博文例子實踐之后,你會完全從iptables過渡過來。
- 本博文主要參考
- 本博文是作者“進取有樂”原創,僅發布于博客園,轉載請注明出處。
基本概念
-
層級關系:分表、鏈、規則,表可以裝多條鏈,鏈可以裝多條規則。
-
地址族類型:一共6種,ip、ip6、inet、arp、bridge、netdev。這6種分別表示“ipv4地址族”、“ipv6地址族”、“ipv4和ipv6雙棧地址族”、“arp地址族”、“橋接地址族”(處理經過橋接設備的報文)、“netdev網絡設備地址族”,netdev地址族是處理入站和出站報文專門用于創建綁定到單個網絡接口的基礎鏈,這類基礎鏈能夠監控指定接口上的所有網絡流量(不分2、3層)。創建的每個表、鏈、規則都要指明地址族類型。不指定地址族時,表示使用默認值,即ip(作用于ipv4)
-
鏈類型:鏈分基本鏈和常規鏈,常規鏈就是創建的時候花括號中不帶任何內容,常規鏈常于跳轉的目標鏈。
- 基本鏈有3種filter、nat、route
類型 支持地址族 支持的鉤子 說明 filter 全部 全部 標準鏈類型 nat ip、ip6、inet input、output、forward、prerouting、postrouting snat、dnat、源地址偽裝等 route ip、ip6 output 會影響路由結果 - 上面提到的鉤子之間的關系是
本 地 處 理 ^ | .-----------. .-----------. | | | 路 由 | | |-----> input / \---> | 選 擇 |----> output -\ --> prerouting ---> | 路 由 | .-----------. \ | 選 擇 | --> postrouting | | / | |---------------> forward --------------------------- .-----------. 4.2內核后多了ingress鉤子,ingress鉤子與其他鉤子的關系如下: .-----------. | |-----> input ... ---> ingress ---> prerouting --->| 路 由 | | 選 擇 | | | | |-----> forward ... .-----------.
- 基本鏈有3種filter、nat、route
-
鏈的優先級:優先級(Priority) 是用于確定鏈在處理網絡數據包時的執行順序的關鍵機制。它通過數值大小決定同一鉤子(Hook)上多個鏈的處理先后順序,數值越小優先級越高,越先執行。可以將此參數設為整數值,或使用標準優先級名稱。
- 標準優先級見下表(優先級filter、srcnat、dstnat在使用bridge地址族是,這三個標準優先級所代表的整數值會與下表不同,可以自行參看man nftables):
名稱 所代表的數值 地址族 鉤子 raw -300 ip, ip6, inet 全部 mangle -150 ip, ip6, inet 全部 dstnat -100 ip, ip6, inet prerouting filter 0 ip, ip6, inet, arp, netdev 全部 security 50 ip, ip6, inet 全部 srcnat 100 ip, ip6, inet postrouting
- 標準優先級見下表(優先級filter、srcnat、dstnat在使用bridge地址族是,這三個標準優先級所代表的整數值會與下表不同,可以自行參看man nftables):
-
鏈的預設動作:某鏈下所有規則都不匹配的時候,就使用該鏈的預設動作(accept或drop)。如果匹配了某鏈下的某個規則,則使用該規則的動作(比如accpet、srcnat、dstnat、drop、jump等)。
-
規則的構成: 規則由“匹配表達式(Expressions)”和“動作(Statements)”構成。關于匹配表達式和動作說明見后面章節的匹配表達式和動作。
nft命令的語法
- nft命令的選項
-a 顯示handle(句柄號),我們可以通過規則的handle號來執行刪除、在某handle號代表的規則之前或之后插入規則,替換某handle號代表的規則。 -D 名稱=值,定義變量。僅可與 -f 選項配合使用。 -c 檢查語法,而不是真的執行 -o 優化語句,可以和-c配合使用 -n 數字格式顯示,例如:沒有此選項nft list ruleset顯示某條規則為ct state established,related accept。使用nft -n list ruleset,則該規則顯示為ct state 0x2,0x4 accept。 -s 不顯示動態狀態信息(比如有counter的規則,nft -s list ruleset時,不會顯示數據表個數和流量字節數) -S 顯示服務名,比如22顯示成ssh,80顯示成http -N 反向解析(不顯示ip地址,而是解析成名稱) -j 以json格式輸出 -u 打印用戶/組的guid -y 以數字形式打印鏈的優先級 -p 以數字形式打印第四層協議 -T 以數字形式打印時間 -t 輸出中省略集合內容。 - shell轉義注意事項
在shell中,分號(;)表示語句結束,花括弧({})表示展開(比如rm /tmp/{a,b}.txt等效于rm /tmp/a.txt /tmp/b.txt),<和>表示重定向,&表后臺執行,()表示子shell命令組... 所以nft命令遇到; {} <>等時要轉義或用單引號包含。
比如:nft add chain ip tb0 ch0 '{ type filter hook input priority 0; policy accept; }'
再比如:nft add rule ip tb0 ch0 tcp dport '{22,80,443}' accept
如果你不用shell解釋器,而是直接使用nft解釋器,那么就無需做shell轉義。具體用法如下
root@raspberrypi:~#
root@raspberrypi:~# nft -i # 輸入nft -i就進入nft交互模式,解釋器由/usr/bin/bash變成了/usr/sbin/nft,命令提示由"~#"變成了"nft>",花括號外就不需要單引號包含了,免去了某些符合的shell轉義問題。
nft> add rule inet tb0 ch0 ip saddr 192.168.1.121 tcp dport {80,443} drop
-
規則集(ruleset)操作
nft list ruleset [地址族]# 顯示規則集,也就是顯示所有表、鏈、規則等。如果需要查看特定地址族的規則集,則需要加上地址族。
nft -a list ruleset#顯示規則集及handle號(句柄號,可以通過句柄號插入、刪、改規則,刪表或鏈一般不用handle號,而是直接用名字)
nft flush ruleset#清理所有規則級 -
表操作
nft <add|create> table [地址族] <表名> ['{ comment "備注";}' '{ flags 標記}']#添加表,地址族可選(如果是非ipv4地址族,則必選),備注和標志,create和add類似,但是如果表名存在,則create會返回錯誤。
nft add table [地址族] <表名> '{ flags dormant; }'# 臨時禁用某個表(表的地址族不是ip,則必須指明地址族),使用 nft add table [地址族] <表名> 恢復表。
nft delete table [地址族] <表名>#刪除表,如果待刪表的地址族不是ip,則必須指明地址族
請注意:后面的內容對于[地址族]不再強調“地址族如果不是ip,則必須指明地址族” -
鏈操作
nft <add|create> chain [地址族] <所屬表名> <鏈名> '{ type <基本鏈類型> hook <鉤子名> priority <優先級>; policy <預設動作>; [comment 備注]}'# 添加基本鏈,關于基本鏈類型、鉤子函數名、 優先級見基本概念。鏈的預設動作可選值為accept和drop。如果不寫policy <鏈的預設動作>,則表示該鏈的預設動作是accept。 如果不加'{}' 不分,則表示該鏈是常規鏈,常用于規則跳轉的目標鏈create和add差不多,只是create創建鏈的時候,如果鏈已經在,則返回錯誤。
nft <delete|list|flush> chain [地址族] <所屬表名> <鏈名># 刪除鏈、列出鏈、清除鏈規則
nft list chains [地址族]# 列出所有鏈,或指定地址族的鏈,注意這里是chains,復數。
nft rename chain [地址族] table <所屬表名> <舊鏈名> <新鏈名># 重命名鏈 -
規則操作
nft <add|insert> rule [地址族] <表名> <鏈名> [handle 句柄號 | index 規則序號] 語句... [comment 備注]# 添加或插入一條規則,句柄號、規則序號、備注是可選。規則序號是一條鏈上的排序,從0開始排序。語句由匹配表達式和動作構成。(man 原文是 expressions和statements, man中statements有各種各樣的動作,所以這里我就直接翻譯成動作了)
nft replace rule [地址族] <表名> <鏈名> handle 句柄號 語句... [comment 備注]# 替換規則(使用句柄號來表示舊規則)
delete rule [地址族] <表名> <鏈名> handle 句柄號# 刪除規則(按句柄號來刪除)
nft命令示例(基礎版)
注意:下面所有的示例,建議在測試之前執行一下nft flush ruleset清理規則集,避免舊規則干擾新規則
- 表、鏈、規則基礎操作(匹配表達式、動作的解釋參考后文的 匹配表達式和動作 )
nft add table inet tb0# 添加一個表,表名是tb0, 作用于inet地址族(ipv4和ipv6雙棧)
nft add chain inet tb0 ch0 '{ type filter hook input priority 0; policy accept; }'# 在tb0表下添加一條名為ch0的基本鏈,鏈的類型是filter,鉤子是input,優先級是0,鏈的預設動作是accept(此處可以省略"policy accept;", 因為不指明預設動作,就是使用accept)。
nft add rule inet tb0 ch0 oifname eth0 tcp dport 22 drop# 在tb0表的ch0鏈下添加一條規則,從eth0出去的tcp 22端口的數據包要丟棄(禁止本機通過eth0訪問外部ssh)
nft -a list ruleset# 列出規則集,使用-a選項后,我們看到上一條規則的句柄號是2,下面的命令我們在句柄號2代表的規則前插入一條規則
nft insert rule inet tb0 ch0 handle 2 oifname eth0 tcp dport '{80,443}' counter comment '"統計通過eth0訪問http/https的瀏覽"'# 在句柄號為2的規則前插入一條規則,并給規則增加備注(為了防止shell轉移,備注用單引號和雙引號包裹,這樣才可以讓備注可以使用空格等字符)
nft add table inet tb0 '{flags dormant;}'# 臨時禁用tb0表,測試發現通過eth0可以訪問外部ssh了。
nft add table inet tb0# 重新啟用tb0, 測試發現又不可以通過eth0訪問外部ssh了。
nft replace rule inet tb0 ch0 handle 2 oifname eth0 tcp dport 22222 drop comment '"禁止通過eth0訪問外部22222端口"'# 替換原來句柄號是2的規則,并給規則備注
nft delete rule inet tb0 ch0 handle 2# 通過句柄號刪除限制本機通過eth0訪問外部ssh的規則
nft flush chain inet tb0 ch0# 清空tb0表下的ch0鏈下的所有規則。
nft add table ip tb1 '{ comment '\"測試表1\"'; }'# 添加一個表tb1,并備注。注意因為花括號外已經使用了一對單引號,所以comment部分的雙引號要"轉義
nft add chain inet tb1 ch1 '{ type filter hook output priority filter; comment '\"通過eth0出去的\"'; }'# 添加一條新鏈ch1, 并備注
nft rename chain inet tb1 ch1 ch_test# 修改tb1表下的ch1鏈的名字為ch_test - 集合、映射等基礎操作示例請參考后文,請點擊:其他數據結構:范圍、集合、映射等 )
nft命令示例(進階版)
-
進階示例的知識點不是循序漸進的,相關知識點可能出現在本段落之后。下面所有的示例,建議在測試之前執行一下
nft flush ruleset清理規則集,避免舊規則干擾新規則 -
1.NAT與端口重定向
- NAT語法
snat [[ip | ip6] to] 地址 [:端口號] [標志] dnat [[ip | ip6] to] 地址 [:端口號] [標志] masquerade [to :端口號] [標志] redirect [to :端口號] [標志] 地址 := 地址 | 地址1 - 地址2 # 單個地址或地址范圍 端口號 := 端口號 | 端口號1 - 端口號2 # 單個端口號或端口號范圍 標志 := persistent | fully-random # 固定端口號或隨機端口號 ### 注意,如果表/鏈/規則是inet地址族的,則規則中必須指明snat、dnat的地址族是ip還是ip6,例如:nft add rule inet tb1 ch0 oif wlan0 ip6 saddr fd00:a::/64 snat ip6 to fd00:b::1 ,后面部分不能寫成snat to fd00:b::1 ### - SNAT源地址轉換
應用場景:請求的數據要跨子網流出
為什么要SNAT: 舉例,假設電腦有兩個接口,eth0(10.0.0.10,能連上互聯網)和wlan0(192.168.1.11)。手機通過wifi連接到電腦的wlan0,手機的默認網關指向192.168.1.11(此時wlan0是熱點模式),手機的請求數據包通過電腦的wlan0進入電腦,電腦的啟用ipv4 forward轉發之后,wlan0進來的數據包會被轉發后經eth0出去,經eth0出去的ip數據包的源地址是192.168.1.11,遠端服務器響應后返回的數據包沒法回到電腦。所以就需要在ip數據包從eth0出去前把源地址替換成eth0的ip地址10.0.0.10。所以說SNAT和出去的數據包相關, 也就是路由選擇之后,所以SNAT關聯的鉤子是postrouting鉤子。
nft add table ip tb0# 添加表
nft add chain ip tb0 ch_snat '{type nat hook postrouting priority srcnat; }'# 添加鏈,使用postrouting鉤子(路由選擇之后)
nft add rule ip tb0 ch_snat oifname eth0 ip saddr 192.168.1.11 snat to 10.0.0.10# 對流出接口是eth0,源地址是192.168.1.11做SNAT,把源地址替換成eth0的ip地址10.0.0.10(SNAT用于知道源IP地址的場景)。 - masquerade 源地址偽裝,相當于動態SNAT
nft add table ip tb0# 添加表
nft add chain ip tb0 ch_snat '{type nat hook postrouting priority srcnat; }'# 添加鏈,使用postrouting鉤子(路由選擇之后)
nft add rule ip tb0 ch_snat oifname eth0 ip saddr 192.168.1.0/24 masquerade# 源地址偽裝(masquerade用于不知道源ip地址場景),假設電腦有兩個網口eth0(10.0.0.10)和wlan0(192.168.1.11),eth0連接了互聯網,現在在電腦開啟ipv4 forward(命令sysctl -w net.ipv4.ip_forward=1)。wlan0是開啟了熱點功能,并啟用了DHCP服務(手機連上該熱點后,獲取了一個192.168.1.X的網址,默認網關是192.168.1.11)。然后手機就可以通過電腦的網絡上網了。 - DNAT目標地址轉換
應用場景:請求的數據要跨子網流入
為什么要DNAT:舉例,假設主機A有兩個接口eth0(10.0.0.10)和eth1(192.168.1.11)。 主機B上有web服務,監聽在192.168.1.200,主機B的網線連接了主機A的eth1,,現在想要通過主機A的eth0跨子網請求主機B的web服務,那么當數據包從主機A的eth0進來的時候,目標地址eth0的IP地址,此時數據包還在路由選擇之前,為了訪問主機B的web服務,就需要把數據包的目標地址改成主機B的IP地址192.168.1.200。DNAT和進入的數據相關,還處于路由選擇之前,所以要用prerouting鉤子。
nft add table ip tb0# 添加表
nft add chain ip tb0 ch_dnat '{type nat hook prerouting priority dstnat; }'# 添加鏈,使用postrouting鉤子(路由選擇之后)
nft add rule ip tb0 ch_dnat iifname eth0 tcp dport 80 dnat to 192.168.1.200# 把從eth0進來的,且目標端口是80的數據包做目標地址轉換,進來的數據包目標ip地址從eth0的10.0.0.10轉換另一個主機的ip地址192.168.1.200。如果192.168.1.200的web服務監聽在8000端口,則最后一段應該寫成dstnat 192.168.1.200:8000 - 端口重定向
nft create table ip tb0; nft add chain ip tb0 ch0 '{type filter hook prerouting priority filter; }'# 兩條語句表示:添加表和鏈,鏈的鉤子是prerouting
nft add rule ip tb0 ch0 tcp dport 80 redirect to :8000# 把訪問80的端口重定向到8000, 測試http服務監聽于8000端口,外部瀏覽器仍然可以通過80端口訪問該http服務
- NAT語法
-
2.無狀態NAT
假設一臺裝了Linux的PC有兩個網口,一個是無線網口,無線網口已經設置了熱點,一個是有線網口(ip地址是192.168.1.11),有線網口連接了網關可以上網。現在要實現手機連接到PC的熱點后可以上網,假設手機連接熱點后獲得的IP地址是192.168.2.22。如果要實現無狀態NAT,使手機能通過PC的熱點上互聯網的話,可以這樣實現:
nft add table ip tb-raw# 新建一個ip地址族的表
nft add chain ip tb-raw ch-prerouting '{type filter hook prerouting priority raw;}'# 在表下新建一條鏈,注意這里的優先級是raw(-300)的優先級,很高,說明該鏈優先于后面的ch-snat和ch-dnat鏈處理數據包。
nft add rule ip tb-raw ch-prerouting oif eth0 ip saddr 192.168.2.22 notrack return# 對從有線網口出去的且來自手機的數據包不跟蹤連接狀態
nft add rule ip tb-raw ch-prerouting iif eth0 ip daddr 192.168.1.11 notrack return# 對進入有線網口的目標ip是有線網口ip地址的數據包不跟蹤連接狀態
nft add table ip tb-nat# 新建一個ip地址族的表
nft add chain ip tb-nat ch-snat '{type filter hook postrouting priority srcnat + 1; }'# 新建一條鏈,使用postroting鉤子,注意這里優先級100+1=101,比上面ch-prerouting鏈要低
nft add rule ip tb-nat ch-snat oif eth0 ip saddr 192.168.2.22 ip saddr set 192.168.1.11# 新建規則:對從有線網口出去的且來自手機的數據包修改源ip地址為有線網口的ip地址
nft add chain ip tb-nat ch-dnat '{type filter hook prerouting priority dstnat + 1; }'# 新建一條鏈,使用prerouting鉤子,注意這里優先級-100+1=-99,比上面ch-prerouting鏈要低
nft add rule ip tb-nat ch-dnat iif eth0 ip daddr 192.168.1.11 ip daddr set 192.168.2.22# 新建規則:對從有線網口進入且目標ip地址是有線網口ip地址的數據包修改目標ip地址為手機的ip地址
然后我們就可以用手機通過pc的熱點上網了,但是注意,如果其他主機想要訪問這臺pc的服務是不行的,因為我們上面的語句沒有限制端口號,所以所有訪問pc有線網口的數據,都會被轉到手機上。 -
3.限制網速
nft create table inet tb0; nft add chain inet tb0 ch0 '{ type filter hook input priority filter; }'# 添加表和鏈,地址族是inet(作用于ipv4和ipv6)
nft add rule inet tb0 ch0 iif wlan0 ip saddr != 192.168.1.0/24 limit rate over 50 kbytes/second drop# 對于從wlan0進入的且源ip地址不是192.168.1.0/24的數據包,超過50KB/秒就drop。可以用wget測試速度。
nft add rule inet tb0 ch0 iif eth0 meta l4proto tcp limit rate over 200 kbytes/second burst 100 mbytes drop# 對tcp流量限速,我們觀察到突發流量100MB用完后,速率就下降到200KB/秒
nft add rule inet tb0 ch0 iif eth1 ip saddr != 192.168.3.0/24 limit rate over 100 mbytes/minute counter# 超過100MB/分鐘就DROP,流量可以按字節數算(單位可以是bytes、kbytes、mbytes),也可按包個數算(100/s表示100個包每秒)。周期可以是second、minute、hour、day、week。 -
4.限制流量
nft add table ip tb0; nft add chain ip tb0 ch1 '{ type filter hook output priority 0 ; }'# 添加表和鏈,地址族是ip
nft add set ip tb0 s0 '{type ipv4_addr; timeout 1d; flags dynamic;}'# 添加一個存放ipv4地址的集合,集合元素過期時間是1天,元素是動態加入的
nft add rule ip tb0 ch1 oif wlan0 tcp sport '{80,443}' add @s0 '{ip saddr}'# 把訪問本機的http和https的源ipv4地址動態添加到集合s0。這里add @s0是動作,不用update,因為update會更新過期時間(動作的語法參考后面動作部分)
nft add rule ip tb0 ch1 oif wlan0 ip saddr @s0 tcp sport '{80,443}' quota over 4096 mbytes counter drop# 添加規則,動作是:限制集合s0中的源ipv4地址的訪問本機的下行流量為4GB,統計流量,超過就drop。我的實測是s0使用2分鐘超時,下載流量10MB,使用nft -a list ruleset查看流量后發現超過10MB后,客戶端無法訪問本機web服務,2分鐘超時后,又能恢復訪問。
還有一種簡潔的寫法,上面的第3、4句添加的兩條規則可以用一條規則解決:nft add rule ip tb0 ch1 oif wlan0 tcp sport '{80,443}' add @s0 '{ip saddr quota over 4096 mbytes }' counter drop#執行一下nft list ruleset,注意觀察這兩種寫法集合的元素有何不同。 -
5.連接數限制
nft add table inet tb0; nft add chain inet tb0 ch0 '{ type filter hook input priority 0 ; }'# 添加表和鏈
nft add set inet tb0 set-ssh '{type ipv4_addr;flags dynamic; }'# 添加集合,集合元素是ipv4地址, 標志是動態(動態加入元素)
nft add rule inet tb0 ch0 tcp dport 22 ct state new add @set-ssh '{ ip saddr ct count over 2 }' counter reject with tcp reset# 限制同一ip連進來的ssh連接數是2,超過就拒絕鏈接。測試發現第三次連ssh服務失敗。這條語句有三個動作"add集合元素"、counter、reject -
6.限制玩游戲(按時間段)
假設游戲是和平精英,百度查到和平精英的端口號是TCP 27015-27030。 本例子沒有實測,因為我不玩游戲,但是類似的場景我測試過。
nft create table inet tb0; nft add chain inet tb0 ch0 '{type filter hook output priority filter; }'# 添加表和鏈,地址族是inet
nft add rule inet tb0 ch0 tcp dport 27015-27030 meta hour != '"08:00"'-'"22:00"' limit rate 300/minute drop# 每天的8點到22點玩和平精英網速正常,8點-22點之外的時間,網速會限速300個包/分鐘(我也不知道具體限速多少合適,目的不是斷網,而是讓游戲卡頓,玩得不舒服)。當然也可以按星期幾限制,按年月日時分秒限制,具體知識點參考后面的meta部分。結合運算符能更加靈活,比如meta hour ge '"16:00"'匹配下午4點之后。 -
7.reject返回錯誤
-
tcp
nft create table inet tb0; nft add chain inet tb0 ch0 '{type filter hook input priority filter; }'# 添加表和鏈,地址族是inet
nft add rule inet tb0 ch0 iif wlan0 ip protocol tcp reject with tcp reset# 使用 tcp reset拒絕來從wlan0進來tcp流量 -
icmp禁ping
nft create table inet tb0; nft add chain inet tb0 ch0 '{type filter hook input priority filter; }'# 添加表和鏈,地址族是ip
nft add rule ip tb0 ch0 iif eth0 icmp type echo-request reject with icmp host-unreachable# 對來自eth0的ping請求做"主機不可達"錯誤icmp包返回。icmp或icmpv6的更多信息請參考匹配表達式和動作
-
-
8.防syn flood
nft create table inet tb0; nft add chain inet tb0 ch0 '{type filter hook input priority filter; }'# 添加表和鏈,地址族是inet
nft add rule inet tb0 ch0 tcp flags '& (fin | syn | rst | ack) == syn' ct state new limit rate over 20/second burst 50 packets counter drop#限制新連接的tcp syn包20個每秒,突發流量50個包。還要結合syn cookie、源ip驗證等來防止syn flood -
9.其他例子請參考后面的“其他數據結構:范圍、集合、映射等”
匹配表達式和動作
-
匹配表達式
-
提示:這里給出的是常用的,不常用的匹配條件以及例子可以參考:https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Matches
-
ip:
<saddr|daddr> <ip地址>:源/目標ipv4地址,例如:ip saddr 192.168.1.22或ip saddr 192.168.1.0/24或ip saddr 192.168.1.2-192.168.1.254
protocol <協議>: ip協議,取值為tcp udp icmp等, 如果你是inet地址族的,要使用meta l4proto
length <數值>: 連接所有包的長度 -
ip6:
<saddr|daddr> <ipv6地址>:源/目標ipv6地址,例如ip6 saddr ::/64
length <數值>: ipv6連接的payload長度。例如:ip6 length != 233 -
tcp/udp:
<tcp/udp> <sport|dport> <端口號>:tcp/udp的源/目標端口,例如tcp sport {22,80,443}ucp dport gt 40000。
tcp flags <標志>:tcp標志,有8個標志 fin, syn, rst, psh, ack, urg, ecn, cwr。例如tcp flags '& (fin|syn|ack|rst) == syn' -
icmp/icmpv6:
type <icmp/icmpv6類型>: 類型。例如icmp type echo-request表示ping請求。icmpv6 type echo-reply表示icmpv6 ping回復 -
ether:
saddr <mac地址>: 以太網源mac地址, 例如ether saddr 00:0f:11:0c:31:0d
type <類型>: 以太網幀類型,例如ether type vlan -
vlan:
id <vlan號>: vlan id, 例如:vlan id 134 -
ct: 注意ct是關于連接的,和meta不一樣,meta是關于包的。
state <連接狀態>:連接的狀態,可選值有:new, established, related, untracked 例如:ct state new
direction <original|reply>: 連接的方向, 可選值有:original(初始的或請求的),reply(回復的) 例如:ct direction reply
[original|reply] <bytes|packets> <數值>:連接的流量(可以限制方向),例如ct original bytes gt 1048576表示請求方向大于1MB
<original|reply> ip <saddr|daddr> <ip地址>:某個連接方向的源/目標IP
count [over] <連接數>:連接數, 例如nft add rule ip tb_pi ch_in tcp dport 22 ip saddr 192.168.1.98 ct state new ct count gt 2 counter reject表示從192.168.1.98發起的ssh連接數超過2就拒絕,over表示大于(測試發現不能用gt,估計是ct內部不支持nft常用比較運算符,省略over表示等于某值)
[original | reply] l3proto <協議># netfilter協議(ipv4/ipv6). 例如ct original l3proto ipv4
[original | reply] protocol <協議>:協議(icmp/udp/tcp), 例如ct original protocol 6或ct original protocol tcp,ct original protocol icmp
mark: 連接標記 -
meta:
<iifname|oifname> <網口名>: 數據進來、出去的網絡接口名,例如meta iifname eth0、meta oifname '{eth0,wlan0}'、meta 'eth*'(支持通配符匹配,這里有單引號防止shell展開)
<iif|oif> <網口序號>: 數據進來或出去的網絡接口序號,例如meta oif != eth0。注意和iifname、oifname區分,iif/oif是索引,規則添加完后,如果接口重命名了,規則仍有效,iifname/oifname則不然。
<iiftype|oiftype> <網口類型>: 網口類型,例如meta iiftype ppp、meta oiftype ether
length <數值>:包長度,注意和ct的ip/ip6的length區分,ct的是關于連接的,meta是關于包的。例子:meta length gt 1000
protocol <協議>:協議(ip、ip6、arp、vlan)
nfproto <協議>:協議(ipv4,ipv6)
l4proto <協議>:協議(tcp、udp、icmp等) 。例如meta l4proto '{tcp, udp}'# 同時匹配udp/tcp協議
mark [set]: 數據包標記,注意和ct的mark區分
pkttype <廣播類型>:包的廣播類型,broadcast、 unicast、 multicast
time、day、hour: 匹配時間,time支持unix時間或ISO標準時間(類似"2025-09-01T12:03:15Z+08:00"或"2025-09-01 16:23:00"或"2025-09-01",不指定時分秒表示00:00:00)。 day表示周幾,比如周日是0,周六是6. hour表示小時,比如"16:25"或"16:12:13". 注意這些屬于字符串,在shell中要單雙引號包含,例如nft add rule inet tb0 ch0 tcp dport '{80,443}' meta hour gt '"22:00"' drop -
原始載荷表達式(RAW PAYLOAD)
- 語法:
@基址,偏移量,長度 - 原始載荷表達式用于從指定偏移量加載指定長度的比特數據。位0對應數據包的第一個比特
- 支持的載荷基址如下:
基址 描述 ll 鏈路層(如以太網頭) nh 網絡層(如IPv4/IPv6頭) th 傳輸層(如TCP頭) ih 內部載荷(傳輸層頭之后的載荷) - 示例:
nft add rule inet tb1 ch0 meta l4proto {tcp, udp} @th,16,16 { 53, 80 } counter# 表示匹配tcp、udp協議的數據包,數據包參考th基址偏移16位,讀取16位長度的數據(從tcp/udp數據包結構可知,偏移16位讀取16位長度的數據是指tcp/udp的目標端口號)。 所以示例的含義是,匹配tcp和udp數據包,且目標端口號是53或80的數據包,執行流量統計。
- 語法:
-
其他表達式:比如擴展頭表達式、數值生成器(結合映射做負載均衡)、哈希表達式(結合映射做負載均衡)等表達式這里不詳述。如果需要,自己查看man手冊。
-
比較運算符
eq或== :等于 ne或!= :不等于 lt或< : 小于 gt或> : 大于 le或<= :小于等于 ge或>= : 大于等于例子:
nft add rule inet tb0 ch0 iif wlan0 tcp dport ge 1024 drop# tcp端口大于等于1024的流入數據丟棄。ge 1024也可以寫成'>=' 1024,因為>在shell中是重定向的意思,所以要用單引號包含
-
-
動作
- 動作分終止性動作(立即終止規則處理)和非終止性動作(繼續處理后續規則)。終止性動作有accept、drop、queue、continue、return、jump、goto等, 非終止性動作有log、counter等。
動作名 描述 accept 接受數據包并停止后續規則評估 drop 丟棄數據包并停止后續規則評估 queue 將數據包排隊至用戶空間并停止后續規則評估 continue 繼續使用下一條規則評估規則集 return 從當前鏈返回,并在最后一個鏈的下一條規則繼續執行(在基礎鏈中等同于accept) jump <鏈> 跳轉至<鏈>的第一條規則繼續執行,在收到返回語句后將執行下一條規則 goto <鏈> 與jump類似,但評估完新鏈后會繼續在最后一個鏈執行,而非包含goto語句的鏈 log 寫日志, 比如動作 log prefix ExtSSH, 則可以用journalctl -k -g 'ExtSSH'查看日志reject 類似drop但是返回拒絕數據包,reject后面可以不帶任何類型,如果帶的話,可以是: reject with tcp reset。或reject with <icmp|icmpv6|icmpx> type <icmp類型>注意icmp、
icmpv6、icmpx,其中icmp僅用于inet地址族。icmp的reject動作格式 可選類型主要是主機不可達、網絡不可達,常用的icmp類型如下:icmp協議的host-unreachable、
net-unreachable。icmpv6協議的no-route、addr-unreachable。icmpx(也就是inet)的host-unreachable、no-route。更多的請參考文首的網址counter 統計流量 snat、dnat、redirect、tproxy 源地址轉換、目標地址轉換、端口重定向、透明代理 其他動作 比如數據包頭修改(payload表達式 set value)、包元信息(meta ... set)修改、連接元信息修改(ct {mark | label | zone} set)、數據包復制到其他網口或ip地址(dup to動作
鏡像數據包到遠程主機方便分析)、轉發數據包到其他網口或ip地址(fwd to動作,類似dup,但是數據沒有副本,直接轉發)、負載均衡、add或update集合或映射... - 關于上面表格中的其他動作中的add或update集合或映射
語法:{add | update} @集合名或映射名 { 匹配表達式 [timeout timeout] [comment string] }# 匹配表達是類似于ip saddr(集合)或 ip saddr:tcp dport(映射)
- 動作分終止性動作(立即終止規則處理)和非終止性動作(繼續處理后續規則)。終止性動作有accept、drop、queue、continue、return、jump、goto等, 非終止性動作有log、counter等。
其他數據結構:范圍、集合、映射等
-
范圍
例如
ip daddr 192.168.0.1-192.168.0.250tcp dport 1-1024 -
集合(sets)
- 匿名集合:用逗號分開的值,例如
tcp dport '{ 22、80、443 }'. 匿名集合的缺陷是,如果要更改集合,則需要替換規則。對于動態解決方案,使用命名集合。 - 命名集合是一個列表或一組元素,您可以在表中的多個規則中引用。命名集合的另外一個好處在于,您可以更新命名的集合而不必替換使用集合的規則。
- 命名集合的元素類型可以是:ipv4地址(ipv4_addr)、ipv6地址(ipv6_addr)、mac地址(ether_addr)、傳輸層協議(inet_proto)比如tcp/udp/icmp,互聯網服務(inet_service)比如ssh/http。數據包標記(mark)
- 命名集合的語法規則:
add set [地址族] <所屬表名> set { type 元素類型 | typeof 表達式 ; [flags 標志 ;] [timeout 超時;] [gc-interval gc間隔;] [elements = { 元素[, ...] } ;] [size 大小 ;] [comment 備注 ;] [policy 策略;] [auto-merge ;] }# 添加集合。
· type: 集合元素類型,可選值ipv4_addr/ipv6_addr/ether_addr/inet_proto/inet_service/mark 也可以用typeof 表達式推導得出(不知道是什么類型的時候,用typeof很好用),比如typeof iifname、type of ct direction
· flags: 集合標志,可選值:constant、dynamic、interval、timeout等。constant表示如果該集合被規則引用了,那么就無法增刪集合的元素,dynamic與constant相反,我測試發現,不指定dynamic也能動態的增刪集合元素。
· timeout: 超時,單位是d、h、m、s(天、時、分、秒),timeout是元素在集合中停留的時間,比如timeout=30s,則元素被添加進集合30秒后自動刪除,當元素是通過規則動態添加進集合時,該選項必選。
· gc-interval: gc間隔,垃圾回收間隔,單位是d、h、m、s, 當 timeout或flags timeout指定是,該選項必選。
· elements: 新創建的集合的初始元素
· size:集合的容量,當元素是動態從規則集中添加的時候,該選項必選。
· policy :可選值performance(預設值)、memory。
· counter :針對每個元素做流量統計,比如 nft add set inet tb1 set0 '{type ipv4_addr; counter}' 則nft list ruleset的時候,能看到每個ipv4地址的流量
· auto-merge:自動合并區間,比如192.168.1.1-192.168.1.30與192.168.1.25-192.168.1.50,會自動合并成192.168.1.1-192.168.1.50
{delete | list | flush} set [family] <表名> <集合名># 刪除集合、列出集合元素、清除集合元素
list sets [地址族]# 列出所有集合
delete set [地址族] <所屬表名> handle <句柄號># 通過句柄號刪除集合
{add | delete} element [地址族] <所屬表名> <集合名> { 元素[, ...] }# 給集合添加或刪除元素 - 命名集合示例
nft add table inet tb1# 添加表,地址族是inet
nft add set inet tb1 set-v4-addr '{type ipv4_addr; timeout 12h; }'# 在表下面添加一個元素類型是ipv4地址的命名集合,元素是ipv4地址,元素超時12小時后就會從集合中移除
nft add element inet tb1 set-v4-addr '{ 192.168.1.10 , 192.168.1.17, 192.168.1.26 timeout 48h }'# 向剛創建的命名集合里添加元素, 前兩個元素過期時間是默認的12小時,最后一個元素過期時間是48小時。
nft add chain inet tb1 ch0 '{type filter hook input priority filter; }'# 在表下添加一條鏈,以便此鏈可以引用上面的命名集合
nft add rule inet tb1 ch0 meta l4proto tcp ip saddr @set-v4-addr counter# 在鏈里面引用命名集合,源ip地址是集合中的3個ipv4地址時,做tcp流量統計
nft add rule inet tb1 ch0 ip daddr 192.168.1.240 tcp dport 80 add @set-v4-addr '{ip saddr}'# 凡是訪問了192.168.1.240的http服務的主機,都動態的加入到set-v4-addr命名集合中(語句格式:add @集合名 '{元素}')
nft delete element inet tb1 set-v4-addr '{192.168.1.10, 192.168.1.17}'# 從命名集合中刪除兩個元素,執行nft list sets發現元素少了兩個
nft delete set inet tb1 set-v4-addr# 刪除命名集合,但是提示Error: Could not process rule: Device or resource busy,因為鏈引用了該命名集合
nft delete rule inet tb1 ch0 handle 13# 刪除引用set-v4-addr集合的鏈后,再執行上面的語句就可以成功刪除命名集合了。
nft add set inet tb1 set-addr4-interval '{ type ipv4_addr; flags interval; }'# 添加一個可以裝ipv4地址范圍的集合,注意這里的flags interval;
nft add element inet tb1 set-addr4-interval '{192.168.2.1-192.168.2.254,192.168.1.0/24}'# 向該命名集合添加兩個元素,兩個元素都表示ipv4地址范圍。
- 匿名集合:用逗號分開的值,例如
-
映射(maps)
- 匿名映射
匿名映射的元素是 { 鍵:值 } 語句。這里映射元素"鍵:值",可以有多個,用逗號分開,鍵和值的類型可以是:ipv4_addr/ipv6_addr/ether_addr/inet_proto/inet_service/mark/等(counter、quota不可以做鍵類型,但是可以作為值類型)。匿名映射的缺點是,如果要修改映射,則必須替換該匿名映射所屬的規則(具體例子請參考后面的示例)。 - 命名映射
- 命名映射的語法規則
- 映射操作語法規則
add map [地址族] <所屬表名> <映射名> { type 元素類型 | typeof 表達式 [flags 標記 ;] [elements = { 元素[, ...] } ;] [size 映射容量;] [comment 備注;] [policy 策略;] }# 添加集合。
· type : 映射的元素數據類型(鍵類型),可選值:ipv4_addr/ipv6_addr/ether_addr/inet_proto/inet_service/mark/counter/quota等,也可以用typeof 表達式推導。
· flags : 映射標記, 可選值:constant/interval。
· elements: 映射初始元素(鍵:值對)
· size : 映射最大容量
· policy :映射策略,可選值performance(默認)/memory
{delete | list | flush} map [地址族] <所屬表名> <映射名># 刪除、列出、清除映射
list maps [地址族]# 列出所有映射,可以限定地址族
- 映射操作語法規則
- 命名映射的示例
- 命名映射的語法規則
- 判決映射(vmaps/verdict maps)**
- 概念: 判決映射我個人的理解是一種{ 匹配表達式 : 動作 } 的特殊映射,也就是說這種映射的鍵和常規映射的鍵的類型是一樣的,值的類型是verdict。(verdict表示各種動作,比如accept、drop、queue、continue、return、jump、goto)。判決映射也分匿名判決映射和命名判決映射。
- 映射的示例(判決映射、映射)
nft create table inet tb1; nft create chain inet tb1 ch0 '{type filter hook input priority filter; }'# 添加表和鏈,地址族是inet
nft add chain inet tb1 ch-counter# 添加一條名為ch-counter的常規鏈,作為跳轉目標鏈,注意常規鏈是不帶'{ type xxx hook xxxx priority xxx; policy xxx }'的。
nft add rule inet tb1 ch-counter tcp dport 443 counter# 給ch-counter的常規鏈添加一條規則,用于統計請求443端口的流量
nft add rule inet tb1 ch0 ip saddr vmap '{ 192.168.1.12:drop, 192.168.2.0/24:accept, 192.168.3.0/24: jump ch-counter}'# 添加一條規則,使用匿名判決映射,注意vmap關鍵字,注意ip saddr vmap表示ip saddr對應到匿名映射中的三個成員, 如果ip saddr是192.168.1.12則drop,如果ip saddr是192.168.2.0/24則accept, 如果ip saddr是192.168.3.0/24,則跳轉到ch-counter鏈。
nft add map inet tb1 vmap0 '{type ipv4_addr:verdict;}'# 在tb1表下新增一個命名判決映射vmap0,映射的類型是。ipv4地址映射到verdict。
nft add element inet tb1 vmap0 '{192.168.33.11:accept, 192.168.33.22:drop, 192.168.33.33:jump ch-counter}'# 給命名判決映射添加元素
nft add rule inet tb1 ch0 ip saddr @vmap0# 在規則中引用命名判決映射vmap0
nft add chain inet tb1 ch-snat '{type nat hook postrouting priority srcnat; }'# 添加一條SNAT鏈,用于下面映射舉例
nft add map inet tb1 map-snat '{type ipv4_addr:ipv4_addr; flags interval; }'# 添加一個名為map-snat的映射,映射元素的鍵和值類型都是ipv4地址,flags是范圍,亦即:ipv4地址范圍映射到ipv4地址
nft add element inet tb1 map-snat '{ 192.168.1.0/24:192.168.3.55, 192.168.2.0/24:192.168.3.66 }'# 給映射添加兩個元素
nft add rule inet tb1 ch-snat snat ip to ip saddr map @map-snat# 添加一條snat的規則引用映射, 注意,因為tb1是inet地址族,所以snat to之間要指明是ip還是ip6地址族。這里是數據包的源ip地址映射到地址轉換后的源ip地址。
- 匿名映射
-
集合或映射的元素操作語法規則
{add | create | delete | get } element [地址族] <所屬表名> <集合名> { 元素[,...] } # 元素相關命令允許修改命名集合(sets)和映射(maps)的內容。 元素 := 鍵表達式 選項 [: 值表達式 ] 選項 := [timeout 時間定義 ] [expires 時間定義 ] [comment 字符串] 時間定義 := [Xd][Xh][Xm][X[s]] # X表示數字,d、h、m、s表示天、時、分、秒 鍵表達式(key_expression)通常是與集合類型匹配的值。值表達式(value_expression)在集合中不允許使用,但在向映射添加元素時是必需的(需匹配其類型定 義中的數據部分)。當從映射中刪除元素時,值表達式可以指定但非必需(因為鍵表達式能唯一標識元素)。create命令與add命令類似,區別在于列出的所有元素必須 都不存在(即不能重復添加已存在的元素)。get命令可用于檢查元素是否包含在集合中,對于非常大或區間類型的集合(interval sets),這種檢查可能并不簡單。 對于區間集合,get命令會返回包含該元素的區間,而不僅僅是元素本身。 timeout:帶有超時標志(timeout)的集合/映射的超時值 expires: 給定元素的過期時間,僅用于規則集復制(ruleset replication) comment: 每個元素的注釋字段 -
連接
語法格式:
匹配表達式.匹配表達式, 可以連接多個,連接可以作為集合的元素、映射元素的鍵或值等,直接上例子解釋:
nft create table inet tb1; nft add chain inet tb1 ch0 '{type filter hook input priority filter; }'# 添加表和鏈,地址族是inet
nft add set inet tb1 set-a2p '{ type ipv4_addr . inet_service; }'# 新建一個集合,集合的元素類型是"ipv4地址 . 端口號"的連接,務必注意點號前后都有空格。
nft add element inet tb1 set-a2p '{192.168.22.10 . 80, 192.168.22.11 . 443}'# 給集合添加兩個元素。
nft add rule inet tb1 ch0 ip saddr . tcp dport @set-a2p counter# 新建規則,引用集合。目的是統計源ip是192.168.22.10目標端口號是80端口、源ip是192.168.22.11目標端口號是443端口的網絡流量
nft add map inet tb1 map-a2p '{type ipv4_addr . inet_service : verdict;}'# 增加一個映射,"ipv4地址 . 端口號"作為映射的鍵,動作作為值
nft add element inet tb1 map-a2p '{192.168.22.66 . 80:accept, 192.168.22.77 . 22:drop}'# 添加映射元素
nft add rule inet tb1 ch0 ip saddr . tcp dport @map-a2p#引用上面的映射(源ip地址是192.168.22.66,tcp目標端口是80就執行accept;源ip地址是192.168.22.77,tcp目標端口是22就執行drop) -
狀態對象(stateful object)
- 狀態對象是表下面的,他們能聚合規則的狀態信息,通過
類型 name 名字引用,例如counter name "cnt0"。 狀態對象主要有:counter(流量計數器)、quota(配額)、limit(限速)等 - 語法規則如下:
{add | delete | list | reset} 狀態對象 [地址族] 所屬表名 對象名 [{ 狀態對象的選項; [comment 備注;]}] # 新建/刪除/列出/重置 狀態對象。這里狀態對象的選項隨狀態對象的種類不同而不同,比如counter的選項是 "packets 數值 bytes 數值 ;" quota的選項是“ [over|until] 數值 流量單位 [ used 數值 流量單位 ] ”(流量單位是bytes、kbytes、mbytes) 。 delete 狀態對象 [地址族] 所屬表名 handle handle # 用句柄號刪除狀態對象 list 狀態對象 [地址族] #列出狀態對象 reset 狀態對象s [地址族] # 重置所有狀態對象,注意復數s,比如重置所有inet地址族的counter,則使用nft reset counters inet reset 狀態對象s [地址族] table 所屬表名 #重置某表下的所有狀態對象,注意復數s - 示例
nft create table inet tb1; nft create chain inet tb1 ch0 '{type filter hook input priority filter; }'# 添加表和鏈,地址族是inet
nft add counter inet tb1 cnt-web-down '{comment '\"統計http、https下行流量\"';}'# 新建一個counter,統計流量
nft add rule inet tb1 ch0 iif wlan0 tcp sport '{80,443}' counter name "cnt-web-down"# 統計從wlan0進入且tcp源端口是80或443的流量。
nft add counter inet tb1 cnt-80-down; nft add counter inet tb1 cnt-443-down# 兩條語句表示建立兩個名為“cnt-80-down”和“cnt-443-down”流量計數器
nft add rule inet tb1 ch0 iif wlan0 counter name tcp sport map'{80:"cnt-80-down",443:"cnt-443-down"}'# 創建一條規則,結合匿名映射(端口號映射到命名的計數器),分別統計http和https的流量。如果不使用匿名映射的形式,則應該寫成:nft add map inet tb1 map-port2cnt '{type inet_service:counter;}'; nft add element inet tb1 map-port2cnt '{80:"cnt-80-down", 443:"cnt-443-down"}'; nft add rule inet tb1 ch0 iif wlan0 counter name tcp sport map @map-port2cnt 三條語句分表表示:1創建一個命名映射,映射的元素類型是端口號映射到計數器。2向該命名映射添加元素。3引用映射。
nft add limit inet tb1 lmt-web-down rate over 100 kbytes/second# 添加一個限速100KBytes/秒的limit對象
nft add rule inet tb1 ch0 iif wlan0 tcp sport '{80,443}' limit name "lmt-web-down" drop# 引用該限速器,因為規則所屬的鏈的預設動作是accept,所以這里超過100kB/s的時候,要drop。 wget測試網速生效
nft add quota inet tb1 quo-web-down over 100 mbytes# 添加一個配額100MB
nft add rule inet tb1 ch0 iif wlan0 tcp sport '{80,443}' quota name "quo-web-down" drop# 添加一條規則應用配額,下載超過100MB就drop,wget測試發現,下載到100MB的時候,下載停止了。執行nft reset quotas,剛才的配額又歸零了。
- 狀態對象是表下面的,他們能聚合規則的狀態信息,通過
-
流表(flowtable)
- 流表用于加速數據包轉發,通過元組(輸入接口、源/目的地址、源/目的端口、協議)緩存轉發信息。
- 語法:
{add | create} flowtable [地址族] 所屬表名 流表名 { hook 鉤子 priority 優先級 ; devices = { 設備,... } ; }#添加流表
list flowtables [地址族]# 列出所有流表
{delete | list} flowtable [地址族] 所屬表名 流表名# 刪除或列出某表下的流表
delete flowtable [地址族] 所屬表名 handle 句柄號# 通過句柄號刪除流表- 流表參數:
優先級支持整數或標準名稱(如filter表示0),支持算術運算(如filter+5表示5)
地址族支持ip/ip6/inet(inet為IPv4/IPv6混合表)
- 流表參數:
- 示例:
nft add flowtable inet tb1 ftb0 '{hook ingress priority filter; devices = {wlan0,eth0};}'# 添加一個inet地址族的流表
nftables腳本
有三種形式:
- shell形式
上面是/tmp/nft.sh的內容,準確說這是shell腳本,不是nft腳本,執行方法有兩種:1、直接執行#!/bin/bash nft flush ruleset nft add table ip tb0 '{ comment '\"測試表\"'; }' nft add chain ip tb0 ch0 '{ type filter hook input priority filter; comment '\"測試鏈\"';}' nft add rule ip tb0 ch0 iifname eth0 tcp dport 22 drop comment '"測試規則"'bash /tmp/nft.sh。2、增加可執行權限chmod a+x /tmp/nft.sh再執行:/tmp/nft.sh
- 與nft命令基本相同的形式
上面是/tmp/a.nft的內容,注意和shell版本比較:首行的解釋器、引號和轉義、每行首少了nft命令。執行方式有兩種:1、賦x權限#!/usr/sbin/nft -f flush ruleset add table ip tb0 { comment "測試表"; } add chain ip tb0 ch0 { type filter hook input priority filter; comment "測試鏈";} add rule ip tb0 ch0 iifname eth0 tcp dport 22 drop comment "測試規則"chmod a+x /tmp/a.nft,執行/tmp/a.nft2、直接用解釋器導入nft -f /tmp/a.nft
- 與nft list ruleset顯示結果基本相同的形式
執行方法有兩種:1、賦x權限#!/usr/sbin/nft -f flush ruleset table ip tb0 { comment "測試表" chain ch0 { comment "測試鏈" type filter hook input priority filter; policy accept; iifname "eth0" tcp dport 22 drop comment "測試規則" } }chmod a+x /tmp/a.nft,再執行/tmp/a.nft2、直接用解釋器導入nft -f /tmp/a.nft
- 其他知識點:比如腳本定義變量、腳本中導入外部腳本(include "test.nft")等知識點,這里不詳述,可以參看man nftables
- 開機啟動nftables服務
systemctl enable nftables#這樣每次啟動的時候,nftables服務會載入/etc/nftables.conf配置文件,配置文件的格式建議使用上面第3種形式。
浙公網安備 33010602011771號