主题
nftables
nftables 是 Linux 内核自 3.13 起引入的新一代包过滤框架,旨在替代 iptables/ip6tables/arptables/ebtables。它采用统一的 nft 命令行工具和新的虚拟机(VM)引擎,语法更简洁、性能更优。
与 iptables 的对比
| 特性 | iptables | nftables |
|---|---|---|
| 命令行工具 | iptables/ip6tables/arptables/ebtables | 统一的 nft |
| 规则语法 | 每条规则一个命令,需重复链名/表名 | 支持批量定义,语法更紧凑 |
| 匹配语法 | -m module --param 扩展模块 | 内置集(set)、字典(map)、连接跟踪等 |
| 性能 | 线性遍历规则链 | 支持集合查找 O(1),VM 字节码执行 |
| 配置持久化 | iptables-save/restore | 原生 JSON/YAML,或 nft list ruleset |
| 默认表/链 | 内置 filter/nat/mangle/raw | 无内置,需手动创建(或由系统脚本创建) |
核心概念
家族(Family)
nftables 按协议家族组织规则:
| 家族 | 说明 | 对应 iptables |
|---|---|---|
ip | IPv4 | iptables |
ip6 | IPv6 | ip6tables |
inet | IPv4 + IPv6 统一 | iptables + ip6tables |
arp | ARP 协议 | arptables |
bridge | 桥接 | ebtables |
netdev | 网络设备层(入口过滤) | 无 |
推荐使用
inet家族,一条规则同时匹配 IPv4 和 IPv6。
表(Table)
表是链的容器,按家族划分。nftables 没有预置的表,需要手动创建。
bash
# 创建表
nft add table inet mytable
# 列出所有表
nft list tables
# 列出表的完整规则
nft list table inet mytable
# 删除表(会删除表中所有链和规则)
nft delete table inet mytable链(Chain)
链是规则的容器,分为基础链(挂载到内核钩子)和常规链(用于跳转,不挂载钩子)。
5 个内核钩子(hook):
| 钩子 | 说明 | 对应 iptables 链 |
|---|---|---|
prerouting | 路由前,刚进入网卡 | PREROUTING |
input | 目的地是本机 | INPUT |
forward | 转发数据包 | FORWARD |
output | 本机发出 | OUTPUT |
postrouting | 路由后,即将离开网卡 | POSTROUTING |
bash
# 创建基础链(挂载到内核钩子)
nft add chain inet mytable input '{ type filter hook input priority 0 ; policy accept ; }'
nft add chain inet mytable forward '{ type filter hook forward priority 0 ; policy accept ; }'
nft add chain inet mytable output '{ type filter hook output priority 0 ; policy accept ; }'
# 创建 NAT 基础链
nft add chain inet mytable prerouting '{ type nat hook prerouting priority -100 ; }'
nft add chain inet mytable postrouting '{ type nat hook postrouting priority 100 ; }'
# 创建常规链(不挂载钩子,用于 jump 跳转)
nft add chain inet mytable mychain
# 删除链
nft delete chain inet mytable mychain优先级说明:
| 优先级 | 值 | 说明 |
|---|---|---|
| raw | -300 | 连接跟踪之前 |
| conntrack | -200 | 连接跟踪 |
| mangle | -150 | 包修改 |
| dstnat (DNAT) | -100 | 目的地址转换 |
| filter | 0 | 过滤(默认) |
| security | 50 | SELinux |
| srcnat (SNAT) | 100 | 源地址转换 |
规则(Rule)
规则定义匹配条件和执行动作。
bash
# 基本格式
nft add rule inet mytable input <匹配条件> <动作>
# 在指定位置插入规则
nft insert rule inet mytable input position 2 <匹配条件> <动作>
# 按句柄删除规则
nft delete rule inet mytable input handle 5常用匹配条件
基本匹配
bash
# 协议匹配
nft add rule inet mytable input ip protocol tcp accept
nft add rule inet mytable input ip protocol udp accept
nft add rule inet mytable input ip protocol icmp accept
# 端口匹配
nft add rule inet mytable input tcp dport 22 accept
nft add rule inet mytable input tcp dport { 80, 443 } accept
nft add rule inet mytable input tcp dport 8000-9000 accept
# IP 地址匹配
nft add rule inet mytable input ip saddr 192.168.1.0/24 accept
nft add rule inet mytable input ip6 saddr 2001:db8::/64 accept
nft add rule inet mytable input ip daddr 10.0.0.1 accept
# 网络接口匹配
nft add rule inet mytable input iif eth0 accept
nft add rule inet mytable input oif eth0 accept
nft add rule inet mytable input iifname "eth0" accept
nft add rule inet mytable input oifname "eth0" accept连接跟踪(conntrack)
bash
# 允许已建立和相关连接
nft add rule inet mytable input ct state established,related accept
# 允许新连接
nft add rule inet mytable input ct state new tcp dport 22 accept
# 丢弃无效连接
nft add rule inet mytable input ct state invalid drop
# 丢弃未跟踪的连接
nft add rule inet mytable input ct state untracked dropICMP 匹配
bash
# 允许 ICMP(ping)
nft add rule inet mytable input icmp type echo-request accept
nft add rule inet mytable input ip6 nexthdr icmpv6 icmpv6 type echo-request accept
# 允许 ICMPv6 必要类型(IPv6 需要)
nft add rule inet mytable input ip6 nexthdr icmpv6 icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect } accept集合(Set)
nftables 的集合(set)是最强大的特性之一,支持 O(1) 查找:
bash
# 匿名集合(内联在规则中)
nft add rule inet mytable input tcp dport { 22, 80, 443 } accept
nft add rule inet mytable input ip saddr { 10.0.0.1, 192.168.1.0/24 } accept
# 命名集合(可复用、可动态增删)
nft add set inet mytable allowed_ports '{ type inet_service ; }'
nft add element inet mytable allowed_ports { 22, 80, 443 }
nft add rule inet mytable input tcp dport @allowed_ports accept
# 动态增删集合元素
nft add element inet mytable allowed_ports { 8080 }
nft delete element inet mytable allowed_ports { 8080 }
# 带区间的集合(需要 interval 标志)
nft add set inet mytable allowed_ips '{ type ipv4_addr ; flags interval ; }'
nft add element inet mytable allowed_ips { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
# 带超时的集合元素
nft add set inet mytable blacklist '{ type ipv4_addr ; flags timeout ; timeout 1h ; }'
nft add element inet mytable blacklist { 1.2.3.4 timeout 30m }
nft add element inet mytable blacklist { 5.6.7.8 } # 使用默认超时 1h字典(Map / Verdict Map)
字典(map)可以根据键值映射到不同的动作或值:
bash
# 匿名字典(端口到动作的映射)
nft add rule inet mytable input tcp dport vmap { 22 : accept, 80 : accept, 443 : accept }
# 命名字典
nft add map inet mytable port_map '{ type inet_service : verdict ; }'
nft add element inet mytable port_map { 22 : accept, 80 : accept, 443 : accept }
nft add rule inet mytable input tcp dport vmap @port_map
# 常规字典(端口到 IP 的映射,用于 NAT)
nft add map inet mytable dnat_map '{ type inet_service : ipv4_addr ; }'
nft add element inet mytable dnat_map { 80 : 192.168.1.10, 443 : 192.168.1.11 }
nft add rule inet mytable prerouting tcp dport vmap @dnat_map常用动作(Verdict)
| 动作 | 说明 |
|---|---|
accept | 接受数据包 |
drop | 静默丢弃 |
reject | 拒绝并返回错误(默认 icmp-port-unreachable) |
reject with icmp type host-unreachable | 指定拒绝类型 |
jump <chain> | 跳转到另一条链(可返回) |
goto <chain> | 跳转到另一条链(不返回) |
return | 返回到调用链 |
snat to <addr> | 源地址转换 |
dnat to <addr> | 目的地址转换 |
masquerade | 动态 SNAT(用于动态 IP) |
redirect to <port> | 重定向到本机端口 |
log prefix "..." | 记录日志 |
counter | 计数(常与其他动作组合) |
meta mark set 0x1 | 设置包标记 |
bash
# 记录日志后丢弃
nft add rule inet mytable input ip saddr 10.0.0.0/8 log prefix "SPOOF: " counter drop
# 组合 counter 和 accept
nft add rule inet mytable input tcp dport 22 counter accept
# 拒绝并指定类型
nft add rule inet mytable input tcp dport 139 reject with tcp reset
# 跳转到自定义链
nft add rule inet mytable input jump mychain完整示例
基础防火墙
bash
#!/usr/sbin/nft -f
flush ruleset
table inet firewall {
chain input {
type filter hook input priority 0 ; policy drop ;
# 允许回环接口
iifname "lo" accept
# 允许已建立和相关连接
ct state established,related accept
# 丢弃无效连接
ct state invalid drop
# 允许 ICMP
icmp type echo-request limit rate 5/second accept
ip6 nexthdr icmpv6 icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect } accept
# 允许 SSH
tcp dport 22 accept
# 允许 HTTP/HTTPS
tcp dport { 80, 443 } accept
# 其他全部丢弃并记录
log prefix "nftables-drop: " counter drop
}
chain forward {
type filter hook forward priority 0 ; policy drop ;
ct state established,related accept
}
chain output {
type filter hook output priority 0 ; policy accept ;
}
}网关 NAT(共享上网)
bash
#!/usr/sbin/nft -f
flush ruleset
table inet nat {
chain prerouting {
type nat hook prerouting priority -100 ; policy accept ;
# DNAT 示例:将外部 80 端口转发到内网 192.168.1.10
iifname "eth0" tcp dport 80 dnat to 192.168.1.10
}
chain postrouting {
type nat hook postrouting priority 100 ; policy accept ;
# MASQUERADE:动态源地址转换(适合动态 IP)
oifname "eth0" masquerade
# 或者使用固定 SNAT
# oifname "eth0" snat to 203.0.113.1
}
}
table inet filter {
chain input {
type filter hook input priority 0 ; policy drop ;
iifname "lo" accept
ct state established,related accept
ct state invalid drop
icmp type echo-request accept
tcp dport 22 accept
}
chain forward {
type filter hook forward priority 0 ; policy drop ;
ct state established,related accept
# 允许内网转发
iifname "eth1" oifname "eth0" accept
}
chain output {
type filter hook output priority 0 ; policy accept ;
}
}NAT 需要开启内核转发:
sysctl -w net.ipv4.ip_forward=1
端口转发
bash
# 将本机 8080 端口转发到 192.168.1.10:80
nft add rule inet nat prerouting tcp dport 8080 dnat to 192.168.1.10:80
nft add rule inet filter forward ct state new tcp dport 80 dnat to 192.168.1.10 accept黑名单/白名单
bash
# 黑名单模式
nft add set inet firewall blacklist '{ type ipv4_addr ; flags timeout ; timeout 1d ; }'
nft add element inet firewall blacklist { 1.2.3.4, 5.6.7.8 }
nft add rule inet firewall input ip saddr @blacklist drop
# 白名单模式
nft add set inet firewall whitelist '{ type ipv4_addr ; }'
nft add element inet firewall whitelist { 10.0.0.0/8, 172.16.0.0/12 }
nft add rule inet firewall input ip saddr != @whitelist drop常用管理命令
bash
# 查看所有规则
nft list ruleset
# 查看指定表
nft list table inet firewall
# 查看指定链
nft list chain inet firewall input
# 查看集合元素
nft list set inet firewall blacklist
# 查看规则句柄(用于精确删除)
nft -a list table inet firewall
# 按句柄删除规则
nft delete rule inet firewall input handle 10
# 清空所有规则
nft flush ruleset
# 清空指定链的规则
nft flush chain inet firewall input
# 计数器归零
nft reset counters
# 导出规则(用于备份)
nft list ruleset > /etc/nftables.conf
# 从文件加载规则
nft -f /etc/nftables.conf
# 检查语法(不加载)
nft -c -f /etc/nftables.conf从 iptables 迁移
使用 iptables-nft 兼容层
bash
# Debian/Ubuntu 安装
apt install nftables iptables-nft
# 自动转换现有 iptables 规则
iptables-restore-translate -f /etc/iptables/rules.v4 > ruleset.nft
ip6tables-restore-translate -f /etc/iptables/rules.v6 >> ruleset.nft
# 检查并加载转换后的规则
nft -c -f ruleset.nft
nft -f ruleset.nft常见语法对照
| 功能 | iptables | nftables |
|---|---|---|
| 默认策略 | iptables -P INPUT DROP | nft add chain inet f input '{ type filter hook input priority 0 ; policy drop ; }' |
| 允许已建立连接 | iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT | nft add rule inet f input ct state established,related accept |
| 允许 TCP 端口 | iptables -A INPUT -p tcp --dport 22 -j ACCEPT | nft add rule inet f input tcp dport 22 accept |
| 允许多端口 | iptables -A INPUT -m multiport -p tcp --dports 80,443 -j ACCEPT | nft add rule inet f input tcp dport { 80, 443 } accept |
| 源地址匹配 | iptables -A INPUT -s 10.0.0.0/8 -j DROP | nft add rule inet f input ip saddr 10.0.0.0/8 drop |
| MASQUERADE | iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE | nft add rule inet nat postrouting oifname "eth0" masquerade |
| DNAT | iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.1.10 | nft add rule inet nat prerouting tcp dport 80 dnat to 192.168.1.10 |
| 日志 | iptables -A INPUT -j LOG --prefix "DROP: " | nft add rule inet f input log prefix "DROP: " drop |
| 限制速率 | iptables -A INPUT -p icmp -m limit --limit 5/s -j ACCEPT | nft add rule inet f input icmp type echo-request limit rate 5/second accept |
系统服务
bash
# Debian/Ubuntu
apt install nftables
systemctl enable nftables
systemctl start nftables
# 配置文件路径
/etc/nftables.conf
# 开机自动加载规则
systemctl enable nftables
# CentOS/RHEL 8+
dnf install nftables
systemctl enable --now nftables
# 配置文件路径
/etc/sysconfig/nftables.conf注意事项
- nftables 规则默认不持久化,重启后丢失。需要将规则保存到配置文件(如
/etc/nftables.conf),或通过 systemd 服务自动加载 iif/oif匹配接口索引(整数),iifname/oifname匹配接口名称(字符串)。接口名可能变化时用iifname- 集合中包含区间时必须声明
flags interval inet家族的规则同时适用于 IPv4 和 IPv6,推荐优先使用- 使用
nft -c -f检查语法,避免加载错误规则导致锁死 - 在远程服务器上操作时,建议先确保 SSH 端口放行,或使用
at/cron设置定时恢复任务