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 问题排查方法。