菜单

Administrator
发布于 2026-10-16 / 1 阅读
0
0

Linux 进阶 L25:nftables——防火墙界的新掌门

Linux 进阶 L25:nftables——防火墙界的新掌门

上一课我们啃了 iptables,亲手给服务器写规则。学完可能会想:这表、链、规则的三层结构,背得头都大了吧?好消息是:Debian 10、Ubuntu 22.04 这些新系统里,防火墙的"引擎"早就换人了——它叫 nftables。

今天就来认识这位新掌门:它能干的活和 iptables 一样多,写法却简单一半。学会它,以后给服务器写防火墙规则,省下的脑细胞能拿去多喝两杯。

为什么要有 nftables

iptables 不是不能用,而是有几个历史包袱:

  1. 工具分裂:IPv4 用 iptables,IPv6 用 ip6tables,ARP 用 arptables,ebtables 管网桥……四套工具,规则写两遍,脑子也要两份。

  2. 内核包袱重:iptables 基于一套老旧的扩展机制,加新功能难。

  3. 语法啰嗦:一条链套一条链,匹配条件多了就变成裹脚布。

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 端口的写法:

工具

写法

iptables

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

nftables

nft add rule inet filter input tcp dport 22 accept

读起来是不是像英语句子?"在 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:到底换不换

给个实在的建议:

情况

建议

新服务器、Debian 11+/Ubuntu 22.04+

直接用 nftables,官方默认

旧规则在 iptables 上跑得好好的

别折腾,iptables 照样能用

教程/脚本里全是 iptables 命令

知道它是"翻译层"就行,nft list ruleset 能看到真实规则

需要同时管 v4 和 v6

nftables 的 inet 表是真香

不用焦虑"必须迁移"。nftables 是趋势,但 iptables 不会明天就消失。先在测试机上练熟这套写法,等哪天要重装服务器了,直接用 nftables 起新规则。

小结

要点

一句话

nftables 是什么

新一代防火墙引擎,一个工具同时管 IPv4 和 IPv6

核心结构

table → chain → rule,链可自定义、挂钩子点更自由

语法风格

像英语句子:nft add rule inet filter input tcp dport 22 accept

双栈推荐

用 inet 族的表,写一套规则 v4/v6 全生效

规则管理

每条规则有 handle,增删改查比 iptables 顺手

生产姿势

规则写进 /etc/nftables.conf,nft -f 加载,systemctl 开机自启

防 ping 洪水

icmp type echo-request limit rate 5/second accept

看谁在扫你

日志规则 + `journalctl -k

grep "nft-drop"`

下一课预告:日志是服务器的黑匣子,journalctl 能把 systemd 时代的所有日志翻个底朝天——L26 我们专门讲它。


评论