强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

iptables 完全指南 / 第 16 章:nftables 迁移指南

第 16 章:nftables 迁移指南

本章目标:理解 nftables 的语法和架构,掌握 iptables 到 nftables 的迁移策略,能够在实际环境中实施渐进式迁移。


16.1 nftables 简介

16.1.1 nftables 的设计目标

nftables 是 Netfilter 项目开发的 iptables 替代品,自 Linux 3.13(2014 年)进入内核主线。它的设计目标是解决 iptables 的架构缺陷:

iptables 缺陷 nftables 改进
多个内核模块 统一的 nf_tables 内核模块
IPv4/IPv6 分离 统一的 inet 表(同时处理 IPv4 和 IPv6)
线性规则匹配 支持集合(set)和字典,O(1) 查找
不支持原子操作 整表替换,避免规则闪烁
固定的表/链结构 完全自定义的表/链/规则层次
有限的编程能力 支持映射(map)、变量、嵌套表达式

16.1.2 nftables 的架构

iptables 架构:
┌─────────┐ ┌──────────┐ ┌───────────┐ ┌───────────┐
│iptables │ │ip6tables │ │arptables  │ │ ebtables  │
└────┬────┘ └────┬─────┘ └─────┬─────┘ └─────┬─────┘
     │           │              │              │
     ▼           ▼              ▼              ▼
┌─────────┐ ┌──────────┐ ┌───────────┐ ┌───────────┐
│ip_tables│ │ip6_tables│ │arp_tables │ │bridge     │
└────┬────┘ └────┬─────┘ └─────┬─────┘ └─────┬─────┘
     │           │              │              │
     └───────────┴──────────────┴──────────────┘
                      │
                      ▼
                  Netfilter

nftables 架构:
┌─────────────────────┐
│     nft CLI 工具     │  ← 统一用户态工具
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│   nf_tables 模块     │  ← 统一内核模块
└──────────┬──────────┘
           │
           ▼
       Netfilter

16.2 基本语法对比

16.2.1 表(Table)操作

iptables

# iptables 中的表是预定义的,不需要手动创建
iptables -t filter -L
iptables -t nat -L

nftables

# nftables 中的表需要显式创建
nft add table inet filter
nft add table ip nat
nft add table ip6 filter

# 查看所有表
nft list tables

# 删除表
nft delete table inet filter

16.2.2 链(Chain)操作

iptables

# iptables 中的链是预定义的
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

nftables

# nftables 中的链需要显式创建,指定类型和钩子
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }

# 添加规则
nft add rule inet filter input tcp dport 22 accept

16.2.3 链的类型和钩子

链类型 说明 适用钩子
filter 过滤 所有钩子
nat 网络地址转换 prerouting, input, output, postrouting
route 路由(等价于 mangle output) output
钩子 说明 优先级
ingress 网卡入口(二层) -200
prerouting 路由前 -100
input 本机入站 0
forward 转发 0
output 本机出站 0
postrouting 路由后 100

16.2.4 规则操作对比

操作 iptables nftables
追加规则 iptables -A INPUT ... nft add rule inet filter input ...
插入规则 iptables -I INPUT 1 ... nft insert rule inet filter input ...
删除规则 iptables -D INPUT 1 nft delete rule inet filter input handle N
列出规则 iptables -L INPUT nft list chain inet filter input
清空规则 iptables -F INPUT nft flush chain inet filter input
默认策略 iptables -P INPUT DROP 链定义时指定 policy drop

16.3 语法详细对比

16.3.1 匹配条件对比

iptables nftables 说明
-p tcp ip protocol tcp 匹配 TCP 协议
-p udp ip protocol udp 匹配 UDP 协议
-s 192.168.1.0/24 ip saddr 192.168.1.0/24 匹配源地址
-d 10.0.0.1 ip daddr 10.0.0.1 匹配目的地址
--dport 80 tcp dport 80 匹配目的端口
--sport 22 tcp sport 22 匹配源端口
-i eth0 iifname "eth0" 匹配入接口
-o eth0 oifname "eth0" 匹配出接口
-m conntrack --ctstate ESTABLISHED ct state established 连接状态匹配
-m limit --limit 10/s limit rate 10/second 速率限制
-m connlimit --connlimit-above 10 ct count over 10 并发连接限制

16.3.2 完整规则对比

SSH 限速规则

# iptables
iptables -A INPUT -p tcp --dport 22 \
  -m hashlimit --hashlimit-above 4/minute \
  --hashlimit-mode srcip --hashlimit-name ssh \
  -j DROP
iptables -A INPUT -p tcp --dport 22 \
  -m connlimit --connlimit-above 3 -j DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# nftables
nft add rule inet filter input tcp dport 22 \
  meter ssh-rate { ip saddr limit rate 4/minute burst 4 packets } \
  counter drop
nft add rule inet filter input tcp dport 22 \
  ct count over 3 counter drop
nft add rule inet filter input tcp dport 22 accept

HTTP/HTTPS 允许规则

# iptables
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
# nftables
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport { 80, 443 } accept

16.3.3 NAT 规则对比

SNAT

# iptables
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.1

# nftables
nft add table ip nat
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip nat postrouting ip saddr 10.0.0.0/24 oifname "eth0" \
  snat to 203.0.113.1

DNAT

# iptables
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -j DNAT --to-destination 10.0.0.10:80

# nftables
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add rule ip nat prerouting iifname "eth0" tcp dport 80 \
  dnat to 10.0.0.10:80

MASQUERADE

# iptables
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE

# nftables
nft add rule ip nat postrouting ip saddr 10.0.0.0/24 oifname "eth0" masquerade

16.4 nftables 独有功能

16.4.1 集合(Set)

# 创建命名集合
nft add set inet filter blacklist { type ipv4_addr \; }

# 向集合中添加元素
nft add element inet filter blacklist { 192.168.1.100, 10.0.0.50 }

# 使用集合匹配
nft add rule inet filter input ip saddr @blacklist drop

# 匿名集合(内联)
nft add rule inet filter input ip saddr { 192.168.1.100, 10.0.0.50 } drop

# 区间集合
nft add set inet filter badnets { type ipv4_addr \; flags interval \; }
nft add element inet filter badnets { 192.168.1.0/24, 10.0.0.0/8 }
nft add rule inet filter input ip saddr @badnets drop

16.4.2 映射(Map)

# 创建映射:端口 → 允许的源地址
nft add map inet filter port-access { type inet_service : ipv4_addr \; }
nft add element inet filter port-access { 22 : 192.168.1.0/24, 3306 : 10.0.1.0/24 }

# 使用映射
nft add rule inet filter input tcp dport vmap @port-access

16.4.3 原子规则替换

# 导出当前规则集到文件
nft list ruleset > /tmp/ruleset.nft

# 编辑规则文件
vim /tmp/ruleset.nft

# 原子性替换所有规则(无闪烁!)
nft -f /tmp/ruleset.nft

16.4.4 统一的 IPv4/IPv6 处理

# 使用 inet 表同时处理 IPv4 和 IPv6
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }

# 一条规则同时匹配 IPv4 和 IPv6
nft add rule inet filter input tcp dport { 22, 80, 443 } accept

# 只匹配 IPv4
nft add rule inet filter input ip saddr 192.168.1.0/24 accept

# 只匹配 IPv6
nft add rule inet filter input ip6 saddr 2001:db8::/32 accept

# 通用匹配(不区分 IPv4/IPv6)
nft add rule inet filter input ct state established,related accept

16.5 迁移策略

16.5.1 渐进迁移路径

阶段 1:兼容层模式
┌──────────────────────────────────────┐
│ 继续使用 iptables 命令              │
│ 底层使用 nftables 内核 API          │
│ (iptables-nft / iptables-translate) │
└──────────────────────────────────────┘
         │
         ▼
阶段 2:混合模式
┌──────────────────────────────────────┐
│ 新规则用 nftables 写                 │
│ 旧规则暂时保留 iptables              │
│ 逐步替换                            │
└──────────────────────────────────────┘
         │
         ▼
阶段 3:完全 nftables
┌──────────────────────────────────────┐
│ 所有规则使用 nftables               │
│ 卸载 iptables 兼容层                │
└──────────────────────────────────────┘

16.5.2 阶段一:使用兼容层

# 检查当前使用的是 iptables-legacy 还是 iptables-nft
iptables --version
# iptables v1.8.9 (nf_tables)   ← nftables 后端
# iptables v1.8.9 (legacy)      ← 传统后端

# Debian/Ubuntu:切换到 nftables 后端
sudo update-alternatives --set iptables /usr/sbin/iptables-nft
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-nft

# 此时继续使用 iptables 命令,但底层是 nftables
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 实际上是在 nftables 中创建了规则

16.5.3 阶段二:规则翻译

# 将现有 iptables 规则翻译为 nftables 语法
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# 输出:nft add rule ip filter INPUT tcp dport 22 accept

# 翻译整个规则集
iptables-translate-save > /tmp/ruleset.nft

# ip6tables 也支持翻译
ip6tables-translate -A INPUT -p tcp --dport 22 -j ACCEPT

16.5.4 阶段三:完全迁移

#!/bin/bash
# ═══════════════════════════════════════════════════
# 完全迁移到 nftables 的脚本
# ═══════════════════════════════════════════════════

# ─── 1. 备份当前 iptables 规则 ───
echo "Backing up current iptables rules..."
iptables-save > /etc/iptables/backup.rules.v4
ip6tables-save > /etc/iptables/backup.rules.v6

# ─── 2. 清空 iptables 规则 ───
echo "Flushing iptables rules..."
iptables -F && iptables -t nat -F && iptables -t mangle -F
ip6tables -F

# ─── 3. 创建 nftables 规则 ───
echo "Creating nftables ruleset..."

cat > /etc/nftables.conf << 'EOF'
#!/usr/sbin/nft -f

flush ruleset

# ─── IPv4/IPv6 过滤表 ───
table inet filter {
    # 黑名单集合
    set blacklist {
        type ipv4_addr
        flags interval, timeout
        elements = { }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        # 已建立的连接
        ct state established,related accept
        ct state invalid drop

        # 回环接口
        iifname "lo" accept

        # 黑名单
        ip saddr @blacklist drop

        # ICMPv6(必须允许关键类型)
        ip6 nexthdr icmpv6 icmpv6 type {
            echo-request,
            echo-reply,
            destination-unreachable,
            packet-too-big,
            time-exceeded,
            parameter-problem,
            neighbor-solicitation,
            neighbor-advertisement,
            router-solicitation,
            router-advertisement,
        } accept

        # IPv4 ICMP
        ip protocol icmp icmp type echo-request limit rate 5/second accept

        # SSH(限速)
        tcp dport 22 meter ssh-rate { ip saddr limit rate 4/minute burst 4 packets } counter drop
        tcp dport 22 ct count over 3 counter drop
        tcp dport 22 accept

        # HTTP/HTTPS
        tcp dport { 80, 443 } meter web-rate { ip saddr limit rate 50/second burst 100 packets } counter drop
        tcp dport { 80, 443 } ct count over 200 counter drop
        tcp dport { 80, 443 } accept

        # 防端口扫描
        tcp flags & fin,psh,urg == fin,psh,urg drop
        tcp flags & syn,fin == syn,fin drop
        tcp flags & syn,rst == syn,rst drop
        tcp flags & all == 0 drop

        # 日志
        limit rate 10/minute burst 30 packets log prefix "NFT-DROP: " level warn
    }

    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;
    }
}

# ─── IPv4 NAT 表 ───
table ip nat {
    chain prerouting {
        type nat hook prerouting priority -100;
        # 在此添加 DNAT 规则
    }

    chain postrouting {
        type nat hook postrouting priority 100;
        # 在此添加 SNAT/MASQUERADE 规则
    }
}
EOF

# ─── 4. 加载 nftables 规则 ───
echo "Loading nftables ruleset..."
nft -f /etc/nftables.conf

# ─── 5. 验证 ───
echo "Verifying..."
nft list ruleset
echo ""
echo "Rule count by chain:"
nft list chain inet filter input | wc -l

# ─── 6. 启用 nftables 服务 ───
systemctl enable nftables
systemctl start nftables

# ─── 7. 禁用 iptables 服务(如果存在)───
systemctl disable netfilter-persistent 2>/dev/null || true

echo ""
echo "✅ Migration to nftables complete!"
echo "   Backup rules: /etc/iptables/backup.rules.v4"
echo "   New ruleset: /etc/nftables.conf"

16.6 nftables 实用工具

16.6.1 规则文件

# nftables 推荐使用配置文件管理规则
# 默认配置文件:/etc/nftables.conf

# 加载配置文件
nft -f /etc/nftables.conf

# 验证配置文件(不加载)
nft -c -f /etc/nftables.conf

# 导出当前规则集(可直接作为配置文件)
nft list ruleset > /etc/nftables.conf

16.6.2 监控和调试

# 监控规则变化
nft monitor

# 查看规则计数
nft list chain inet filter input -a
# -a 显示 handle 编号

# 重置计数器
nft reset counters

# 查看特定规则
nft list chain inet filter input -a | grep "tcp dport 22"

16.6.3 动态元素管理

# 向黑名单集合中动态添加 IP
nft add element inet filter blacklist { 192.168.1.100 }

# 设置超时元素(300 秒后自动删除)
nft add element inet filter blacklist { 192.168.1.100 timeout 5m }

# 删除元素
nft delete element inet filter blacklist { 192.168.1.100 }

# 查看集合内容
nft list set inet filter blacklist

16.7 常见问题

16.7.1 iptables 和 nftables 共存

# 检查当前系统是否同时使用两者
lsmod | grep -E "^(nf_tables|ip_tables)"

# 如果同时加载,可能存在冲突
# 建议:只使用一种

# 检查 iptables 使用的是哪个后端
iptables --version
# 带 (nf_tables) 后缀的表示使用 nftables 后端

16.7.2 Docker 兼容性

# Docker 目前主要使用 iptables
# 如果切换到纯 nftables,Docker 可能无法正常工作

# 解决方案 1:保持 iptables-nft 兼容层
update-alternatives --set iptables /usr/sbin/iptables-nft

# 解决方案 2:Docker 20.10+ 支持 nftables(实验性)
# 在 /etc/docker/daemon.json 中配置
# { "experimental": true }

16.7.3 调试规则不匹配

# nftables 内置追踪功能
nft add rule inet filter input tcp dport 22 meta nftrace set 1

# 监控追踪信息
nft monitor trace

# 输出示例:
# trace id 8f88e410 inet filter input packet: ... tcp dport 22
# trace id 8f88e410 inet filter input rule tcp dport 22 accept (verdict accept)

16.8 迁移检查清单

□ 备份当前 iptables 规则
□ 测试 iptables-translate 翻译结果
□ 编写 nftables.conf 配置文件
□ 在测试环境验证 nftables 规则
□ 确认 Docker/容器兼容性
□ 确认 IPv6 规则已迁移
□ 确认 NAT 规则已迁移
□ 配置 nftables 服务开机自启
□ 配置规则持久化
□ 在生产环境部署(确保有带外访问)
□ 验证所有服务正常
□ 移除 iptables 兼容层(可选)
□ 更新运维文档

16.9 注意事项

⚠️ 迁移前务必备份:iptables-save 导出的规则文件是迁移失败时的回滚方案。

⚠️ 保留带外访问:迁移时确保有 IPMI/KVM/串口等带外访问方式,避免规则错误导致远程连接中断。

⚠️ Docker 兼容性:Docker 目前仍主要依赖 iptables API,使用 iptables-nft 兼容层是最安全的方案。

⚠️ 不要同时运行两套规则:iptables 和 nftables 的规则同时生效时,处理顺序取决于钩子优先级,可能导致不可预期的行为。


16.10 扩展阅读

资源 说明
nftables Wiki https://wiki.nftables.org/
man nft nft 命令手册
man nftables.conf 配置文件格式
man nftables nftables 内核接口文档
Red Hat - Migrating to nftables 企业级迁移指南

本章小结

概念 要点
nftables iptables 的替代品,统一内核模块
inet 表 同时处理 IPv4 和 IPv6
集合(Set) O(1) 查找,支持超时
映射(Map) 键值对查找
原子替换 整表替换,避免规则闪烁
迁移策略 兼容层 → 混合模式 → 完全迁移
iptables-translate 自动翻译工具

下一章第 17 章:故障排查与调试,将学习常见的 iptables 问题排查方法。