Linux 进阶 L25:nftables——防火墙界的新掌门
上一课我们啃了 iptables,亲手给服务器写规则。学完可能会想:这表、链、规则的三层结构,背得头都大了吧?好消息是:Debian 10、Ubuntu 22.04 这些新系统里,防火墙的"引擎"早就换人了——它叫 nftables。
今天就来认识这位新掌门:它能干的活和 iptables 一样多,写法却简单一半。学会它,以后给服务器写防火墙规则,省下的脑细胞能拿去多喝两杯。
为什么要有 nftables
iptables 不是不能用,而是有几个历史包袱:
工具分裂:IPv4 用 iptables,IPv6 用 ip6tables,ARP 用 arptables,ebtables 管网桥……四套工具,规则写两遍,脑子也要两份。
内核包袱重:iptables 基于一套老旧的扩展机制,加新功能难。
语法啰嗦:一条链套一条链,匹配条件多了就变成裹脚布。
nftables 统一了这一切:一个工具、一种语法、同时管 IPv4 和 IPv6。写一套规则,v4/v6 全生效——这就是它最大的爽点。
注意:现在系统里
iptables命令很多时候只是 nftables 的"翻译层"(iptables-nft 后端)。真正的内核规则都跑在 nftables 上。可以用nft list ruleset验证一下。
新世界观:table → chain → rule(但更自由)
nftables 和 iptables 的概念差不多,但少了几层枷锁:
table(表):分
ip(IPv4)、ip6(IPv6)、inet(v4+v6 双栈,推荐)、arp、bridge、netdev六种族。以前写两遍的规则,现在一个inet表搞定。chain(链):不用再背系统预置的 INPUT/OUTPUT。链可以自定义名字、自己决定挂到哪(hook 哪个点、优先级是多少)。预置链长这样:
type filter hook input priority 0。rule(规则):还是"如果…就…",但语法是一句话读完的,不再是命令参数大杂烩。
对比一下,开 22 端口的写法:
读起来是不是像英语句子?"在 filter 表的 input 链上,TCP 目标端口 22,accept"。记住这一个感觉,nftables 就学会了三分之一。
实战一:给 VPS 写一套双栈防火墙
先检查 nftables 装了没(新系统基本自带):
nft --version
nftables v1.0.6 (Happy Birthday)
如果没有:sudo apt install nftables。
现在写一套规则。注意顺序,先写允许,再设默认拒绝,否则把自己锁在门外就只能去服务商后台救火了。
第一步,建表和链:
# 建一个 inet 表,同时管 v4 和 v6
sudo nft add table inet filter
# input 链:进本机的数据包,先经过这里
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
# output 链:本机出去的包
sudo nft add chain inet filter output '{ type filter hook output priority 0; policy accept; }'
# forward 链:路过的包(Docker 会用到)
sudo nft add chain inet filter forward '{ type filter hook forward priority 0; policy drop; }'
解读一下:type filter 说明是过滤链;hook input 说明挂在"数据包进本机"这个钩子点上;priority 0 是处理顺序;policy drop 是默认丢掉,没命中任何规则的包直接没收。
第二步,写规则(先写这些,再回头看第一步的 policy drop 就安全了):
# 1. 本机自己(回环接口)全放行——很多程序内部通信走这里
sudo nft add rule inet filter input iif "lo" accept
# 2. 已建立的连接放行——这条最重要,没有它 SSH 会话立刻断线
sudo nft add rule inet filter input ct state established,related accept
# 3. 允许 SSH(把 22 换成你的实际端口)
sudo nft add rule inet filter input tcp dport 22 accept
# 4. 允许网站的 80 / 443
sudo nft add rule inet filter input tcp dport 80 accept
sudo nft add rule inet filter input tcp dport 443 accept
第三步,检查长啥样:
sudo nft list table inet filter
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state established,related accept
tcp dport 22 accept
tcp dport 80 accept
tcp dport 443 accept
}
chain output {
type filter hook output priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
}
}
看,一套表里 v4 和 v6 的规则全管了。换成 iptables 时代,这里要写两遍:iptables + ip6tables。
实战二:规则的增删改查(比 iptables 顺手多了)
规则建错了很正常,nftables 的修改体验比 iptables 强得多,因为每条规则都有编号(handle),可以直接定位。
先看带 handle 的规则列表:
sudo nft --handle list chain inet filter input
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept # handle 2
ct state established,related accept # handle 3
tcp dport 22 accept # handle 4
tcp dport 80 accept # handle 5
tcp dport 443 accept # handle 6
}
}
删规则:
# 比如不再需要 80 端口了,删掉它(handle 5)
sudo nft delete rule inet filter input handle 5
插规则(插到指定位置,不用像 iptables 那样数 -I 1):
# 在 handle 4 之后插入一条允许 8080 的规则
sudo nft insert rule inet filter input position 4 tcp dport 8080 accept
position 比 iptables 的"行号"直观多了:你看到 handle 是多少,就往哪里插,规则不会因为增删就乱套。
实战三:一个文件管全部规则(生产环境的正确姿势)
前面一条条敲,适合实验。真正跑在服务器上的规则,应该写在一个文件里统一管理:
/etc/nftables.conf:
#!/usr/sbin/nft -f
# 清空旧规则,防止重复
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state established,related accept
# 防护:ICMP 限速放行(ping 别被人打爆)
icmp type echo-request limit rate 5/second accept
icmpv6 type echo-request limit rate 5/second accept
tcp dport 22 accept
tcp dport 80 accept
tcp dport 443 accept
}
chain output {
type filter hook output priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
}
}
里面有两条新东西,值得单独说:
flush ruleset:先清空,避免旧规则残留。icmp type echo-request limit rate 5/second:ping 每秒最多放行 5 个。有人用 ping 洪水打你?直接被限流,服务器安然无恙。icmpv6是 IPv6 版本,inet表下 v4 和 v6 可以写在同一个文件里——双栈的爽点又出现了。
应用它:
sudo nft -f /etc/nftables.conf
让它开机自动生效:
sudo systemctl enable --now nftables
这样 nftables 服务开机就会加载 /etc/nftables.conf。以后改规则:编辑文件 → sudo nft -f /etc/nftables.conf → 完事。不用再一条条敲,不用担心重启丢规则。
实战四:记录可疑流量(日志版规则)
想知道有没有人在扫你的端口?加一条日志规则:
sudo nft add rule inet filter input position 3 log prefix "nft-drop: " drop
position 3是插到 established 规则之后、端口规则之前,这样已放行的流量不会被记一遍日志,日志里只剩"被拦下的"。
被拒绝的包会出现在系统日志里:
sudo journalctl -k | grep "nft-drop" | tail -5
kernel: nft-drop: IN=eth0 OUT= MAC=... SRC=45.148.10.88 DST=你的服务器IP LEN=40 TOS=0x00 PROTO=TCP SPT=51234 DPT=22 WINDOW=1024 SYN
读法:SRC=45.148.10.88 是扫描者的 IP,DPT=22 是它在扫你的 SSH 端口。看到这种日志别慌,正常服务器每天都被扫几百次——规则拦住了,就是胜利。
nftables vs iptables:到底换不换
给个实在的建议:
不用焦虑"必须迁移"。nftables 是趋势,但 iptables 不会明天就消失。先在测试机上练熟这套写法,等哪天要重装服务器了,直接用 nftables 起新规则。
小结
下一课预告:日志是服务器的黑匣子,journalctl 能把 systemd 时代的所有日志翻个底朝天——L26 我们专门讲它。