本页目录

nftables 操作手册

nftables 是 Linux 下一代防火墙框架,替代 iptables/ip6tables/arptables/ebtables。使用 nft 命令管理,配置可原子性加载。Gentoo 上内核需开启 CONFIG_NF_TABLES 及相关模块。

核心概念: table (namespace, 按 family 分组), chain (规则容器, 分 type/hook/priority), rule (匹配+动作), set (IP/端口集合), verdict (accept/drop/reject/跳转)。

状态查看

# 列出所有规则
nft list ruleset                          # 完整规则集 (人类可读)
nft -a list ruleset                       # 带 handle 编号 (删改规则用)

# 按表/链查看
nft list table inet filter                 # 查看某张表
nft list chain inet filter input           # 查看某条链
nft list table ip nat                      # IPv4 NAT 表

# 查看 sets / counters
nft list sets                              # 所有命名集合
nft list counters                          # 所有计数器

# 规则集统计
nft --stateless list ruleset               # 不含状态对象 (更紧凑)
nft list ruleset | wc -l                   # 粗略估算规模

基础规则管理

# 临时修改 (重启丢失, 用于测试)
nft add rule inet filter input tcp dport 22 accept
nft delete rule inet filter input handle 5  # 按 handle 删
nft flush chain inet filter input           # 清空一条链
nft flush ruleset                           # 清空所有规则 (!危险)

# 查看 handle
nft -a list chain inet filter input
# 输出:  tcp dport 22 accept # handle 5

持久化与原子加载

# 保存当前规则集
nft list ruleset > /etc/nftables.conf

# 原子性替换 (推荐)
nft -f /etc/nftables.conf                  # 全量替换, 失败则回滚

# 检查语法 (不加载)
nft -c -f /etc/nftables.conf

# systemd 自动加载
systemctl enable nftables
systemctl restart nftables                  # 从 /etc/nftables.conf 加载

常用表/链结构模板

table inet filter {                        # inet = IPv4 + IPv6
    chain input {
        type filter hook input priority 0; policy drop;
        # 允许 lo
        iif lo accept
        # 允许已建立/相关连接
        ct state established,related accept
        # 允许 SSH
        tcp dport 22 accept
        # 允许 ICMPv6 (IPv6 必需)
        ip6 nexthdr icmpv6 accept
    }
    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;
    }
}

规则写法

# 匹配
tcp dport {22, 80, 443}                    # 端口集合
ip saddr 192.168.1.0/24                    # 源 IP 网段
ip daddr != 10.0.0.0/8                     # 非目标网段
iif eth0                                   # 入接口
oif wg0                                    # 出接口
ct state new                               # 新连接
ct state established,related               # 已建立/关联
tcp flags syn / syn,ack,rst                # 匹配 SYN (新连接请求)
meta l4proto {tcp, udp}                    # 传输层协议
meta hour "09:00"-"18:00"                  # 时间匹配
limit rate 10/second                       # 速率限制
counter                                    # 计数 (不改变动作)
log prefix "SSH: "                         # 记录日志

# 动作
accept                                     # 放行
drop                                       # 丢弃 (无响应)
reject                                     # 拒绝 (返回 ICMP/RST)
jump another_chain                         # 跳转到自定义链
return                                     # 从自定义链返回
dnat to 192.168.1.100                      # 目标 NAT
snat to 203.0.113.1                        # 源 NAT
masquerade                                 # 动态 SNAT (出口 IP 可变)
redirect to :8080                          # 本地端口重定向

NAT / 端口转发

# 表定义
table ip nat {
    chain prerouting {
        type nat hook prerouting priority dstnat; policy accept;
    }
    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;
    }
}

# DNAT (端口转发, 外→内)
nft add rule ip nat prerouting iif eth0 tcp dport 8443 dnat to 192.168.1.100:443

# SNAT (出口统一 IP)
nft add rule ip nat postrouting oif eth0 snat to 203.0.113.1

# MASQUERADE (动态 IP 出口, 如 DHCP 接口)
nft add rule ip nat postrouting oif eth0 masquerade

# 端口重定向 (本机 80 → 8080)
nft add rule ip nat prerouting tcp dport 80 redirect to :8080

Sets (集合, 高效批量匹配)

# 定义命名集合
nft add set inet filter blackhole { type ipv4_addr\; }   # shell 需要转义分号
# 或在配置文件中:
#   set blackhole { type ipv4_addr; }

# 动态添加/删除元素
nft add element inet filter blackhole { 10.10.10.10, 10.10.10.11 }
nft delete element inet filter blackhole { 10.10.10.10 }

# 在规则中使用
# ip saddr @blackhole drop

# 带超时的集合 (自动过期)
# set ratelimit { type ipv4_addr; timeout 1h; }
# ip saddr @ratelimit counter drop

# 集合类型:
# ipv4_addr / ipv6_addr          IP 地址
# ipv4_addr . inet_service       IP+端口组合
# ifname                         接口名
# mark                           连接标记

运维操作

# 插入规则到指定位置 (默认 append)
nft insert rule inet filter input position 3 tcp dport 8080 accept

# 替换规则
nft replace rule inet filter input handle 7 tcp dport 2222 accept

# 规则注释
# 在文件中:  tcp dport 22 accept comment "SSH access"

# 计数器清零
nft reset counters

# 实时监控
nft monitor                              # 监控规则集变更

# 调试
nft --debug=netlink list ruleset         # 看 netlink 消息
nft --debug=scanner -f rules.conf        # 看词法分析

常见场景

# 防 SSH 爆破 (限制新连接速率)
# tcp dport 22 ct state new limit rate 4/minute accept
# tcp dport 22 ct state new drop

# 只允许特定 IP 访问某端口
# ip saddr {10.0.0.1, 10.0.0.2} tcp dport 5432 accept
# tcp dport 5432 drop

# 透明代理 (TPROXY, 需配合 mihomo/v2ray)
# table ip mangle {
#     chain prerouting { type filter hook prerouting priority mangle; }
# }
# meta l4proto tcp ip daddr != 127.0.0.0/8 tproxy to :12345

# Docker 用户注意
# Docker 会插入自己的 iptables 规则, 与 nftables 混用可能乱序。
# 建议: 要么只用 iptables (Docker 兼容模式), 要么确保 nftables 规则在 Docker 之前加载
# 检查: nft list ruleset | grep -i docker
# Docker 的 nftables 支持: /etc/docker/daemon.json → "iptables": false

迁移备忘 (iptables → nft)

# 查看当前 iptables 规则
iptables-save

# 自动翻译 (不完美, 只能做参考)
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# 输出: nft add rule ip filter INPUT tcp dport 22 counter accept

# 批量翻译 (完整规则集)
iptables-restore-translate < <(iptables-save)