目录
- 初步准备:基础概念与常见命令
- 场景一:基础服务器防火墙(过滤规则)
- 场景二:NAT 网关(SNAT / MASQUERADE / DNAT / 端口转发)
- 场景三:黑名单 / 白名单 / 大量 IP 的批量管理
- 场景四:记录日志与限速(log / limit / meter)
- 场景五:仅允许特定网卡或特定连接状态(iif/oif/ct state)
- 场景六:桥接防火墙、VLAN 与 ingress 过滤(bridge / vlan / ingress)
- 场景七:IPv6 网络配置要点
- 其它必备命令:查看 / 修改 / 删除 / 清空规则
- 附:从 iptables 迁移到 nftables 的注意事项
- 参考资料与建议
初步准备:基础概念与常见命令
-
Netfilter & nftables
- Netfilter 是 Linux 内核中的网络数据包处理子系统,nftables 则是其新一代的用户态工具,用来管理防火墙和 NAT 规则。
- 它替代了传统的 iptables、ip6tables、arptables、ebtables,提供统一的配置方式和更灵活的语法。
-
基本结构
- 表(table):用于容纳“链”
- 链(chain):一组规则的集合,同时指定在哪个处理阶段(hook)应用,如
prerouting
、input
、forward
、output
、postrouting
。 - 规则(rule):具体的匹配条件 + 动作(如
drop
、accept
、dnat
、snat
、log
、reject
、masquerade
等)。
-
常见命令行
sudo nft add table <family> <tablename>
:创建表sudo nft add chain <family> <tablename> <chainname> { ... }
:创建链,指定类型、hook、priority、policy 等sudo nft add rule <family> <tablename> <chainname> <match> <action>
:添加规则sudo nft list ruleset
:查看当前完整配置sudo nft delete rule/chain/table ...
:删除对应对象sudo nft flush ruleset
:清空所有规则(谨慎操作)
-
协议族 (family)
ip
(仅 IPv4),ip6
(仅 IPv6),inet
(同时管理 IPv4/IPv6),arp
,bridge
等。- 一般推荐使用
inet
统一管理 IPv4/IPv6 防火墙规则(但NAT 通常只能使用ip
或ip6
)。
-
常见 hook
prerouting
:数据包刚进来,还没决定路由input
:发往本机的数据包forward
:要转发给其他目的地的数据包output
:本机发出的数据包postrouting
:数据包即将离开本机,常用于 SNATingress
:更早阶段的过滤,在协议栈处理之前(见场景六)
-
默认策略 (policy)
accept
:默认放行drop
:默认丢弃- 常用做法:在关键链(如
input
、forward
等)上设置policy drop
,然后再加特定的放行规则(白名单式)。
-
优先级 (priority)
- 每个 hook 可以设置
priority
,以决定规则生效的先后顺序。 - 常见做法:
prerouting
(DNAT)常用priority -100
filter
(如input
、forward
)常用priority 0
postrouting
(SNAT)常用priority 100
- 每个 hook 可以设置
场景一:基础服务器防火墙(过滤规则)
在一台常见的服务器上,你可能只想开放 SSH、HTTP、HTTPS,其他都拒绝,并且对本地回环 (lo
) 和已建立连接 (established
) 要放行。这是典型的应用场景。
1. 创建一个表和链
# 创建一个名为 "firewall" 的表,协议族 "inet"(同时管IPv4+IPv6)
sudo nft add table inet firewall
# 在该表下创建一个链,类型 filter,挂到 input 阶段,优先级 0,默认策略为 drop
sudo nft add chain inet firewall input {
type filter hook input priority 0;
policy drop;
}
2. 添加基础规则
# 允许本地回环接口 (主要是127.0.0.1)
sudo nft add rule inet firewall input iifname "lo" accept
# 允许已建立(ESTABLISHED)或相关(RELATED)状态的连接继续
sudo nft add rule inet firewall input ct state established,related accept
# 允许 SSH (tcp/22)、HTTP (tcp/80)、HTTPS (tcp/443)
sudo nft add rule inet firewall input tcp dport {22,80,443} accept
# IPv4情况下:允许ICMP ping
sudo nft add rule inet firewall input ip protocol icmp icmp type echo-request accept
# IPv6情况下:允许ICMPv6 ping
sudo nft add rule inet firewall input ip6 nexthdr icmpv6 icmpv6 type echo-request accept
# 对于其他想要“显式拒绝”的端口或协议,
# 可以考虑用 reject 动作:
# sudo nft add rule inet firewall input tcp dport 23 reject with tcp reset
# (比 drop 动作更“可见”,会返回 RST 给对端)
# 以上未匹配到的流量(因为policy=drop)均丢弃
这样就完成了一个最常见的服务器防火墙规则:只允许某些常用端口和已建立的连接,其他丢弃。
场景二:NAT 网关(SNAT / MASQUERADE / DNAT / 端口转发)
如果你的机器同时扮演网关角色,需要做源地址转换 (SNAT/MASQUERADE) 和目的地址转换 (DNAT),则可以在 prerouting
/ postrouting
阶段进行 NAT 配置。
注意:NAT 功能通常仅在
ip
或ip6
family 下使用。常见的是ip nat
(IPv4)。
1. SNAT:出站地址转换
如果网关对外网的 IP 是 203.0.113.5
,内网网卡为 eth1
,外网网卡为 eth0
,要让内网 192.168.1.x
的流量通过网关统一 NAT 成 203.0.113.5
:
sudo nft add table ip nat
# 创建 chain: postrouting,用于 SNAT
sudo nft add chain ip nat postrouting {
type nat hook postrouting priority 100;
policy accept;
}
# SNAT 规则
sudo nft add rule ip nat postrouting \
oifname "eth0" \
snat to 203.0.113.5
使用 MASQUERADE(适合动态外网 IP)
如果外网 IP 不是固定的,比如 PPPoE 拨号或 DHCP,会用 masquerade
动作,而不是手动指定 IP:
sudo nft add rule ip nat postrouting oifname "eth0" masquerade
这样系统会自动使用 eth0
当前的 IP 做 NAT,无需频繁修改。
2. DNAT:入站地址转换 / 端口转发
如果外网访问 203.0.113.5:80
,想转发到内网 192.168.1.10:8080
:
sudo nft add chain ip nat prerouting {
type nat hook prerouting priority -100;
policy accept;
}
sudo nft add rule ip nat prerouting \
tcp dport 80 \
dnat to 192.168.1.10:8080
这样,访问网关 203.0.113.5
的 80 端口时,会重定向到内网服务器 192.168.1.10:8080
。
提示:在做 DNAT 后,别忘了在防火墙
forward
链里适当放行该流量,或使用policy accept
(视安全策略而定)。
场景三:黑名单 / 白名单 / 大量 IP 的批量管理
当你需要屏蔽大量可疑 IP,或者放行某些特定网段时,一条条写规则会非常繁琐。nftables 提供了 set
/ map
等数据结构,可一次性管理多值。
1. 黑名单示例
# 在 table inet firewall 下创建一个黑名单 set
sudo nft add set inet firewall blacklist {
type ipv4_addr;
flags interval; # 可以使用网段
}
# 往黑名单里添加元素
sudo nft add element inet firewall blacklist { 1.2.3.0/24, 5.6.7.8 }
# 在 input 链的规则中引用这个 set
sudo nft add rule inet firewall input ip saddr @blacklist drop
这样就不用写多条 ip saddr X drop
,以后只要
sudo nft add element inet firewall blacklist { <IP 或网段> }
即可。
动态封禁 / 过期
nftables 允许给 set 中的元素添加 “timeout” 参数,实现自动过期。适合类似“fail2ban”的场景:
sudo nft add set inet firewall blacklist {
type ipv4_addr;
timeout 1h; # 每个元素默认过期时间
}
# 往里面加元素时,也可以自定义过期时长
sudo nft add element inet firewall blacklist { 1.2.3.4 timeout 10m }
到期后 1.2.3.4
会自动从黑名单中移除。
2. 白名单示例
如果只想允许一批 IP,其余全部丢弃,可以把默认策略设为 drop
,然后在规则里写:
# 创建一个名为 whitelist 的 set
sudo nft add set inet firewall whitelist {
type ipv4_addr;
flags interval;
}
# 为了演示,先加几个IP
sudo nft add element inet firewall whitelist { 192.168.1.0/24, 10.10.10.10 }
# 在 input 链中
sudo nft add rule inet firewall input ip saddr @whitelist accept
因为链的 policy=drop
,不在白名单的全部拒绝。
3. 使用 map 简化多动作映射(verdict map)
除了 set,还可以用 map
来进行“值 → 动作”的映射(或“值 → 值”的映射),进一步简化配置。例如,根据 IP 地址直接映射到不同动作:
sudo nft add map inet firewall action_map {
type ipv4_addr : verdict;
}
sudo nft add element inet firewall action_map {
1.2.3.4 : drop,
10.0.0.0/8 : accept
}
# 一条规则即可处理多种动作
sudo nft add rule inet firewall input ip saddr vmap @action_map
这样比多条 if (saddr=...) drop; if (saddr=...) accept;
要简洁得多。
场景四:记录日志与限速(log / limit / meter)
1. 记录日志(log)
有时你想记录所有被丢弃的数据包或特定攻击流量,用 log
动作即可。示例:
sudo nft add rule inet firewall input ip saddr 1.2.3.4 log prefix "BLOCKED_IP " drop
prefix "BLOCKED_IP "
:出现在日志的前缀- 系统日志可在
journalctl -k
、dmesg
或/var/log/syslog
中查看(具体路径与发行版相关)。
2. 限速(limit)
如果不想每个数据包都写日志,比如要限制日志过于频繁,可以:
sudo nft add rule inet firewall input ip saddr 1.2.3.4 \
limit rate 3/second \
log prefix "BLOCKED_IP " \
drop
limit rate 3/second
:表示只有在这个速率以内的包才会触发日志动作,超出速率时跳过日志动作(但drop
依然执行)。
3. 更高级的 meter / quota 等
nftables 支持更丰富的“状态计数”功能,如 meter、quota 等,用来做连接数限制或带宽配额等更复杂的场景。例如:
sudo nft add rule inet firewall input meter ddos_meter {
ip saddr limit rate 10/second
} log prefix "DOS_ATTEMPT " drop
meter
可以对特定字段(如 IP)进行自定义统计,超过阈值时执行特定动作等,适合抵御 DDOS 或限流。
场景五:仅允许特定网卡或特定连接状态(iif/oif/ct state)
1. 按网络接口名过滤
常见于服务器多网卡环境,如内网网卡 eth1
、外网网卡 eth0
,只允许某些流量从内网进来:
sudo nft add rule inet firewall input iifname "eth1" accept
sudo nft add rule inet firewall input iifname "eth0" drop
或者要反过来,拦截除了 eth0
外所有接口,就用:
sudo nft add rule inet firewall input iifname != "eth0" drop
2. 按连接状态 (ct state)
nftables 同样使用连接跟踪机制,可以区分数据包是 new
、established
、related
、invalid
等。
# 只允许已建立或相关连接
sudo nft add rule inet firewall input ct state established,related accept
# 拒绝无效连接
sudo nft add rule inet firewall input ct state invalid drop
# 允许新建连接访问 80 端口
sudo nft add rule inet firewall input ct state new tcp dport 80 accept
场景六:桥接防火墙、VLAN 与 ingress 过滤(bridge / vlan / ingress)
1. 桥接 (bridge) family
如果你的 Linux 服务器做“二层交换/桥接”或者管理 VLAN,需要用到 bridge
family 或 VLAN 相关匹配:
sudo nft add table bridge brtable
sudo nft add chain bridge brtable forward {
type filter hook forward priority 0;
policy drop;
}
# 例如 只允许从特定源MAC地址通过
sudo nft add rule bridge brtable forward ether saddr aa:bb:cc:dd:ee:ff accept
需要注意的是,在桥接场景下,你必须在 bridge
family 下创建表/链,否则无法拦截二层包。此外,如果需要在桥上查看/过滤 IP 层的信息,通常还需要内核模块 br_netfilter
并启用 net.bridge.bridge-nf-call-iptables=1
等相关 sysctl。
2. VLAN 匹配
# 过滤 VLAN ID=100 的数据包
sudo nft add rule bridge brtable forward vlan id 100 drop
或者更细的匹配:vlan pcp
等等。
3. ingress hook(更早阶段过滤)
nftables 也支持 ingress hook(基于 TC ingress 机制),可以在数据包进入协议栈之前进行过滤,适合DDoS防护等需要尽早丢包的场景。例如:
sudo nft add chain inet firewall ingress {
type filter hook ingress device eth0 priority -500;
policy drop;
}
sudo nft add rule inet firewall ingress ip saddr 1.2.3.4 drop
ingress 上无法使用部分连接跟踪特性,请根据需求确认可行性。
场景七:IPv6 网络配置要点
若你在 IPv6 环境下部署防火墙,可以:
-
使用
inet
family:同时管理 IPv4/IPv6- 规则里可以写
ip
(仅针对 IPv4)或ip6
(仅针对 IPv6),或者直接用通用条件(如tcp dport 80
)同时生效。
- 规则里可以写
-
ICMPv6 规则非常重要
- IPv6 依赖 ICMPv6 做邻居发现 (NDP) 等功能。若把 ICMPv6 全部阻断,可能导致网络中断。
- 常见做法是明确放行 NDP:
sudo nft add rule inet firewall input \ icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } accept
-
NAT in IPv6?
- 原则上 IPv6 不推荐做 NAT。但技术上也可以配置
snat/dnat
之类,只是场景较少。 - 如果确有需求,使用
ip6 nat
family 并在prerouting/postrouting
钩子上加 NAT 规则即可(写法与 IPv4 类似)。
- 原则上 IPv6 不推荐做 NAT。但技术上也可以配置
其它必备命令:查看 / 修改 / 删除 / 清空规则
-
查看当前所有规则
sudo nft list ruleset
这会打印所有表、链和规则的完整结构。
-
查看指定表 / 链
sudo nft list table inet firewall sudo nft list chain inet firewall input
-
查看规则的 handle ID
sudo nft list chain inet firewall input -a
-a
会显示每条规则的 handle 编号,便于定向删除或修改。 -
删除规则
- 根据规则表达式删除:
sudo nft delete rule inet firewall input ip saddr 1.2.3.4 drop
- 或根据 handle ID 删除:
# 先查看 handle sudo nft list chain inet firewall input -a # 假设要删 handle=10 的那条 sudo nft delete rule inet firewall input handle 10
- 根据规则表达式删除:
-
删除链 / 表
- 必须先删除或清空该链内的规则,然后才能删链,再删除表:
sudo nft delete chain inet firewall input sudo nft delete table inet firewall
- 必须先删除或清空该链内的规则,然后才能删链,再删除表:
-
清空/刷新整个规则集
- 如果想一次性把所有链、表、规则都清除:
sudo nft flush ruleset
- 这是一个非常“暴力”的操作,执行后系统可能暂时没有任何防火墙规则,要谨慎使用。
- 如果想一次性把所有链、表、规则都清除:
-
实时监控 (monitor)
sudo nft monitor
可以动态观察规则的添加、删除、修改操作。
-
脚本批量加载
- 可以把规则写到一个
.nft
文件中,然后通过-f
参数一次性加载:sudo nft -f /path/to/your_rules.nft
- 可以把规则写到一个
附:从 iptables 迁移到 nftables 的注意事项
-
现代发行版默认使用 “nftables 后端”的 iptables
- 执行
iptables -L
时,可能实际上调用的是 iptables-nft,会影响 nftables 规则集。 - 最好尽量只使用 nftables,避免混合写两套规则导致冲突。
- 执行
-
语法思维差异
- iptables 中常用
-A
、-I
、-D
等,nftables 采用nft add rule
/nft insert rule
/nft delete rule
的方式。 - iptables 里 NAT、filter 是不同命令行,这些在 nftables 里都是同一个工具
nft
,只是在创建链时指定type nat
或type filter
。
- iptables 中常用
-
Docker / Container / Kubernetes 环境
- 现代 Docker 默认也基于 nftables,或者使用一套 iptables-nft 规则;它会自动向系统规则集注入 NAT/forward 规则。
- 手动编写 NAT 或 forward 规则时,要注意不要与 Docker 的规则冲突或相互覆盖。
- 在 Kubernetes 环境下(如使用 kube-proxy iptables 模式),也需要留意 iptables-nft 后端的影响。
-
服务自启动 / 持久化
- 如果以前在
/etc/iptables/rules.v4
或rules.v6
中写规则,那么在 nftables 下可以改为/etc/nftables.conf
。 - 大多数发行版可以通过
systemctl enable nftables
+systemctl start nftables
来管理开机启动;或者编辑/etc/default/nftables
、/etc/nftables.conf
等。 - 常用做法:
# 将当前规则输出到配置文件 sudo nft list ruleset > /etc/nftables.conf # 确保开机加载 sudo systemctl enable nftables
- 如果以前在
-
flowtable(可选的高性能转发)
- 如果你做网关且对性能要求很高,可了解 nftables 的 flow offload / flowtable 特性(Linux 4.18+),可将转发加速至内核 fast path 或硬件。
- 典型示例(非常简化):
nft add table inet xflow nft add chain inet xflow forward { type filter hook forward priority 0; policy accept; } nft add rule inet xflow forward ip protocol tcp \ flow offload @DEV { eth0, eth1 } accept
- 具体配置要根据内核版本、硬件环境来调整,非所有场景都适合。
参考资料与建议
- 官方文档与 Wiki
man nft
手册- 终端输入
man nft
或nft --help
- 终端输入
- 调试思路
- 使用
sudo nft list ruleset
确认最终规则 dmesg
或journalctl -k
查看日志- 同时注意网络接口名、IP 地址是否正确;经常出现 NAT 链类型不匹配、priority 值冲突、IPv4/IPv6 混淆等问题
- 使用
- 发行版文档
- 部分发行版可能对 nftables 做了额外封装(如 Debian/Ubuntu 的
nftables
服务、Red Hat 系的nftables.conf
位置等),请查看对应发行版的官方指南。
- 部分发行版可能对 nftables 做了额外封装(如 Debian/Ubuntu 的
总结
- nftables 的基本结构始终是:表(table) → 链(chain) → 规则(rule)。
- 应用场景决定是做 过滤(type filter) 还是 NAT(type nat),以及要挂载到哪个 hook(如
input
、prerouting
、postrouting
、ingress
等)。 - 常见匹配包括源/目的 IP、端口、协议、接口名、连接状态 (ct state)、MAC 地址等;动作可为
accept
,drop
,reject
,snat
,dnat
,masquerade
,log
等。 - 高级用法如
set
(批量黑白名单)、map
(值→动作映射)、log
(记录日志)、limit
/meter
(限速或计数)能够减少重复规则,提高可读性和性能。 - 注意发行版、内核版本、Docker/k8s 等环境差异,以免默认配置或自动生成的规则与手动写的规则冲突。也要关注持久化方式和服务启动脚本的配置。
通过以上 场景化 的例子与高级用法扩展,相信你能更准确地定位自己的需求,然后套用相应的链、规则写法来部署 nftables。祝一切顺利!