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

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 规则操作对比

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

16.3 语法详细对比

16.3.1 匹配条件对比

iptablesnftables说明
-p tcpip protocol tcp匹配 TCP 协议
-p udpip protocol udp匹配 UDP 协议
-s 192.168.1.0/24ip saddr 192.168.1.0/24匹配源地址
-d 10.0.0.1ip daddr 10.0.0.1匹配目的地址
--dport 80tcp dport 80匹配目的端口
--sport 22tcp sport 22匹配源端口
-i eth0iifname "eth0"匹配入接口
-o eth0oifname "eth0"匹配出接口
-m conntrack --ctstate ESTABLISHEDct state established连接状态匹配
-m limit --limit 10/slimit rate 10/second速率限制
-m connlimit --connlimit-above 10ct 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 Wikihttps://wiki.nftables.org/
man nftnft 命令手册
man nftables.conf配置文件格式
man nftablesnftables 内核接口文档
Red Hat - Migrating to nftables企业级迁移指南

本章小结

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

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