nftables使用教程

原文参考:CentOS 8 都发布了,你还不会用 nftables?

一、引言:为什么是 nftables?

随着 CentOS 8 和 RHEL 8 的发布,一个重要的变化是:**nftables 框架已取代 iptables 成为默认的网络包过滤工具**。如果你还在使用 iptables,现在是时候了解它的继任者了。

nftables 是什么?
它是 netfilter 项目推出的新框架,旨在全面替代现有的 {ip,ip6,arp,eb}tables。它提供了一个全新的包过滤框架、用户空间工具 nft 以及向后兼容层。

核心优势对比 iptables:

  • 数据结构:iptables 使用数组式布局,nftables 使用链式布局(链表),更灵活。
  • 可扩展性:iptables 功能扩展需修改内核;nftables 大部分工作在用户态完成,添加功能更容易。
  • 性能:iptables 存在内置链和计数器,有空链开销;nftables 无内置链,按需创建。
  • 易用性:原生支持集合、字典和映射,简化了 IPv4/IPv6 双栈管理。

本文主要介绍用户空间命令行工具 nft 的使用方法。

二、基础概念与快速开始

2.1 核心组件

nftables 由三个核心层级构成:

  1. 内核:提供 netlink 配置接口和规则集评估。
  2. libnl:提供与内核通信的基础库。
  3. **nft (用户空间)**:供用户交互的命令行工具。

2.2 规则结构

与 iptables 类似,nftables 也由 表(Table) -> 链(Chain) -> 规则(Rule) 层级构成。规则是真正的执行动作。

检查当前规则集:

1
nft list ruleset

初始状态下,如果没有启用 firewalld 等服务,输出为空,这印证了 nftables 没有内置链的特性。

三、实战操作:从创建到管理

3.1 创建表(Table)

表是规则的顶级容器,每个表只属于一个特定的“地址簇”。

nftables 地址簇 对应的传统工具 说明
ip iptables 仅处理 IPv4 数据包
ip6 ip6tables 仅处理 IPv6 数据包
inet iptables & ip6tables 处理 IPv4 和 IPv6(推荐)
arp arptables 处理 ARP 层数据包
bridge ebtables 处理桥接数据包

创建表示例(使用 inet 簇):

1
nft add table inet my_table

列出所有规则以验证:

1
2
3
4
nft list ruleset
# 输出:
# table inet my_table {
# }

3.2 创建链(Chain)

链是规则的载体,必须显式创建。链有两种类型:

  • 常规链:用于规则分类和跳转,无需指定钩子。
  • 基本链:数据包的入口点,必须指定钩子类型和优先级。

创建常规链:

1
nft add chain inet my_table my_utility_chain

创建基本链(作为数据包入口):

1
nft add chain inet my_table my_filter_chain '{ type filter hook input priority 0; }'
  • type filter:链类型为过滤。
  • hook input:钩子点为输入。
  • priority 0:优先级(数值越小,优先级越高)。
  • 注意:分号 ; 需要用反斜杠 \ 转义,或直接用引号包裹整个参数。

3.3 创建规则(Rule)

规则由语句构成,放置在链中。

在链末尾添加规则(允许 SSH):

1
nft add rule inet my_table my_filter_chain tcp dport ssh accept

在链开头插入规则(允许 HTTP):

1
nft insert rule inet my_table my_filter_chain tcp dport http accept

在指定位置插入规则:
有两种方式,推荐使用稳定的 handle 而非易变的 index

  1. 使用 index(从0开始):
    1
    2
    # 在索引1的规则前插入(即第二条规则前)
    nft insert rule inet my_table my_filter_chain index 1 tcp dport nfs accept
  2. 使用 handle(句柄值唯一且不变):
    1
    2
    3
    4
    5
    # 首先查看规则的句柄
    nft --handle list ruleset
    # 假设 `tcp dport http accept` 的句柄是 4
    # 在该句柄的规则后添加新规则
    nft add rule inet my_table my_filter_chain handle 4 tcp dport 2345 accept
    创建规则时获取句柄:
    1
    2
    nft --echo --handle add rule inet my_table my_filter_chain udp dport 3333 accept
    # 输出会包含新规则的句柄,例如 `# handle 10`

3.4 删除规则

规则只能通过其唯一的 handle 删除。

1
2
3
4
# 1. 查找要删除规则的句柄
nft --handle list ruleset
# 2. 使用句柄删除
nft delete rule inet my_table my_filter_chain handle 8

3.5 查看规则

支持不同粒度的查看。

1
2
3
4
5
6
# 查看所有规则
nft list ruleset
# 查看特定表
nft list table inet my_table
# 查看特定链
nft list chain inet my_table my_filter_chain

四、高级特性:集合与字典

4.1 集合(Sets)

集合用于匹配多个条件(如多个IP、端口),分为匿名集合和命名集合。

匿名集合(适用于固定条件):

1
2
3
4
# 允许来自两个特定IP的流量
nft add rule inet my_table my_filter_chain ip saddr { 10.10.10.123, 10.10.10.231 } accept
# 简化多个端口的规则
nft add rule inet my_table my_filter_chain tcp dport { http, nfs, ssh } accept

命名集合(可动态修改):

  1. 创建集合(指定元素类型):
    1
    nft add set inet my_table my_set '{ type ipv4_addr; }'
  2. 在规则中引用集合(使用 @ 符号):
    1
    nft add rule inet my_table my_filter_chain ip saddr @my_set drop
  3. 向集合添加/删除元素
    1
    2
    nft add element inet my_table my_set { 10.10.10.22, 10.10.10.33 }
    nft delete element inet my_table my_set { 10.10.10.33 }

支持区间的集合(需添加 interval 标志):

1
2
3
4
nft add set inet my_table my_range_set '{ type ipv4_addr; flags interval; }'
nft add element inet my_table my_range_set { 10.20.20.0/24 }
# 或直接使用区间
# nft add element inet my_table my_range_set { 10.20.20.0-10.20.20.255 }

级联类型集合(组合匹配):

1
2
3
4
5
6
# 创建可同时匹配IP、协议、端口的集合
nft add set inet my_table my_concat_set '{ type ipv4_addr . inet_proto . inet_service; }'
# 添加元素
nft add element inet my_table my_concat_set { 10.30.30.30 . tcp . telnet }
# 在规则中引用,需指明对应关系
nft add rule inet my_table my_filter_chain ip saddr . meta l4proto . tcp dport @my_concat_set accept

4.2 字典(Maps)

字典提供高效的键值映射,用于根据条件跳转到不同链或执行不同动作,避免链式跳转的性能开销。

创建字典并用于规则跳转:

1
2
3
4
5
# 1. 创建目标链
nft add chain inet my_table my_tcp_chain
nft add chain inet my_table my_udp_chain
# 2. 使用匿名字典根据协议跳转
nft add rule inet my_table my_filter_chain meta l4proto vmap { tcp : jump my_tcp_chain, udp : jump my_udp_chain }

命名字典:

1
2
3
4
5
6
# 1. 创建字典(键类型: 值类型)
nft add map inet my_table my_vmap '{ type ipv4_addr : verdict; }'
# 2. 添加映射关系
nft add element inet my_table my_vmap { 192.168.0.10 : drop, 192.168.0.11 : accept }
# 3. 在规则中引用字典
nft add rule inet my_table my_filter_chain ip saddr vmap @my_vmap

五、架构设计与命名空间

nftables 中,每个表都是一个独立的命名空间。这意味着不同表中的链、集合可以同名,互不干扰。

1
2
3
4
nft add table inet table_one
nft add chain inet table_one my_chain
nft add table inet table_two
nft add chain inet table_two my_chain # 同名,但允许

重要提示:数据包必须通过所有表中相关链的允许,才能被放行。链的执行顺序由 priority 决定,值越小优先级越高。

六、持久化配置

命令行配置是临时的。要使规则永久生效,需进行备份和恢复。

备份当前规则集:

1
nft list ruleset > /root/nftables.conf

从文件恢复规则集:

1
nft -f /root/nftables.conf

在 CentOS 8/RHEL 8 中:

  • 系统服务 nftables.service 默认从 /etc/nftables.conf 加载规则。
  • 该文件通常会 include 其他配置文件,如 /etc/sysconfig/nftables.conf(默认被注释)。

七、总结

nftables 作为 iptables 的现代替代品,通过更清晰的数据结构、原生集合/字典支持、独立的命名空间等特性,提供了更强大、灵活且高效的防火墙配置体验。

学习路径建议:

  1. 理解 表 -> 链 -> 规则 的核心层级。
  2. 掌握基础的 增(add/insert)、删(delete)、查(list) 操作。
  3. 熟练使用 集合 来简化多条件规则。
  4. 在复杂策略中应用 字典 进行高效跳转。
  5. 最后通过 备份/恢复 实现配置持久化。