nftables 是 Linux 内核 Netfilter 项目的下一代包过滤框架。它旨在逐步取代传统的 iptables (以及 ip6tables, arptables, ebtables) 工具集,提供一个统一的、高效的、更易于管理和扩展的防火墙解决方案。nftables 引入了一套全新的语法和设计理念,旨在解决 iptables 长期存在的一些问题,例如命令复杂性、重复代码以及 IPv4 和 IPv6 规则管理的独立性等。

核心思想:基于表达式的统一规则集,支持原子性更新,并针对 IPv4/IPv6/桥接等协议提供统一管理。 它的设计哲学是从指令式规则集转向声明式通用虚拟机指令,使得规则处理更高效、更灵活。


一、为什么需要 nftables?iptables 的局限性

虽然 iptables 强大且稳定,但它在设计和使用上存在一些固有的局限性,促使 Netfilter 社区开发 nftables:

  1. 语法复杂且碎片化

    • iptables (用于 IPv4)、ip6tables (用于 IPv6)、arptables (用于 ARP)、ebtables (用于以太网帧)。每种协议一套独立的工具和规则集,增加了学习和管理的复杂度。
    • 每个表 (filter, nat, mangle, raw) 和链 (INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING) 都有固定的用途和位置,缺乏灵活性。
  2. 性能瓶颈与规则重复

    • 规则是顺序匹配的,当规则集非常庞大时,性能会下降。
    • 在多个表中可能需要重复定义类似的匹配条件,增加了内存占用和管理负担。
  3. 缺乏原子性操作

    • iptables 每次添加/删除一条规则都是一个独立操作,若要一次性应用大批规则,可能导致短时间内的网络中断或不一致状态。
  4. 模块化不足

    • 新的匹配条件和目标需要作为内核模块加载,并且通常在用户空间也需要对应的扩展,增加了开发和维护难度。

nftables 应运而生,致力于解决这些问题,提供一个更现代、更高效的防火墙管理机制。

二、nftables 的核心概念

nftables 采用了一种全新的、基于字节码的过滤引擎,其核心概念包括:

2.1 表 (Tables)

在 nftables 中,表是规则集的最顶层容器,可以根据用户的需求创建任意数量的表。一个表可以包含:

  • 地址族 (Address Family):指定表适用的网络协议类型。

    • 最常见的是 ip (IPv4), ip6 (IPv6), inet (同时适用于 IPv4 和 IPv6), bridge (以太网桥), arp (ARP 协议), netdev (网络设备,用于在数据包进入网络堆栈之前处理,如流量分类)。
    • 通过 inet 地址族,可以为 IPv4 和 IPv6 编写一套统一的规则,极大地简化了双栈网络的管理。
  • 链 (Chains):表内包含用户自定义的链,链中包含具体的规则。

命令示例:

1
2
3
4
# 创建一个名为 'my_table' 的 inet 表
sudo nft add table inet my_table
# 列出所有表
sudo nft list tables

2.2 链 (Chains)

与 iptables 的预定义链不同,nftables 中的链有两种类型:

  1. 基本链 (Base Chains)

    • 直接挂载到 Netfilter 的特定钩子点 (Hook Points) 上。
    • 这些钩子点与 iptables 的链位置类似:prerouting, input, forward, output, postrouting
    • 基本链需要指定其类型 (Type) (filter, nat, route) 和优先级 (Priority)
      • type filter:用于过滤和丢弃数据包。
      • type nat:用于地址转换 (SNAT/DNAT)。
      • type route:用于在路由决策后修改目的地址(不常用)。
    • 优先级决定了在同一个钩子点上,不同链的执行顺序。
    • 命令示例:
      1
      2
      3
      # 在 'my_table' 表中创建一个名为 'input_chain' 的基本链
      # 挂载到 input 钩子点,类型为 filter,优先级为 0 (标准过滤)
      sudo nft add chain inet my_table input_chain { type filter hook input priority 0 \; }
  2. 常规链 (Regular Chains)

    • 不直接挂载到钩子点,只包含规则。
    • 通过其他链的 jumpgoto 动作来调用。
    • 用途:实现规则的模块化和复用,例如将所有关于 SSH 的规则放在一个单独的常规链中。
    • 命令示例:
      1
      2
      # 在 'my_table' 表中创建一个名为 'ssh_rules' 的常规链
      sudo nft add chain inet my_table ssh_rules

2.3 规则 (Rules)

规则是 nftables 的核心,由匹配条件 (Matches)语句 (Statements) 组成。nftables 的规则语法是基于表达式的,更加灵活强大。

  • 匹配条件:可以匹配各种数据包字段。
    • ip saddr <source_ip>:源 IP 地址
    • ip daddr <destination_ip>:目的 IP 地址
    • tcp dport <destination_port>:目的 TCP 端口
    • iif <interface>:入站接口
    • oif <interface>:出站接口
    • meta l4proto <protocol>:四层协议 (tcp, udp, icmp)
    • ct state <state>:连接跟踪状态 (new, established, related, invalid)
    • 集合 (Sets):nftables 引入了强大的集合功能,可以将 IP 地址、端口、MAC 地址等放入集合中,然后在规则中高效地匹配。这比 iptables 中 --source--destination 每次都列举地址列表的效率更高。
      • 命令示例:
        1
        2
        3
        4
        5
        6
        # 定义一个名为 'whitelist_ips' 的 IPv4 地址集合
        sudo nft add set inet my_table whitelist_ips { type ipv4_addr \; flags interval \; }
        # 向集合添加 IP 地址
        sudo nft add element inet my_table whitelist_ips { "192.168.1.10", "192.168.1.20" }
        # 在规则中使用集合
        sudo nft add rule inet my_table input_chain ip saddr @whitelist_ips accept
  • 动作 (Statements):数据包匹配规则后执行的操作。
    • accept:允许数据包通过。
    • drop:默默丢弃数据包。
    • reject:丢弃数据包并返回错误信息。
    • log:记录日志。
    • counter:为规则添加计数器,统计匹配的包和字节。
    • snat, dnat, masquerade:NAT 操作。
    • jump <chain>:跳转到另一个常规链,处理完毕后返回。
    • goto <chain>:跳转到另一个常规链,不返回。
    • return:返回到调用链或上层。

命令示例:

1
2
3
4
5
6
# 允许 loopback 接口的流量
sudo nft add rule inet my_table input_chain iif lo accept
# 允许 SSH 端口
sudo nft add rule inet my_table input_chain tcp dport 22 ct state new,established accept
# 丢弃所有其他流量
sudo nft add rule inet my_table input_chain drop

三、nftables 常用操作命令

nft 是 nftables 的命令行工具。

3.1 查看和列出规则

  • sudo nft list tables:列出所有表。
  • sudo nft list table inet my_table:列出指定表中的所有内容(链和规则)。
  • sudo nft list ruleset:列出整个规则集(所有表、链、规则)。
  • sudo nft -a list ruleset:显示更详细的信息,包括句柄 (handle),方便删除或修改。
  • sudo nft list chain inet my_table input_chain:列出指定链中的规则。

3.2 添加和插入规则

  • 添加表/链
    1
    2
    sudo nft add table inet my_table
    sudo nft add chain inet my_table input_chain { type filter hook input priority 0 \; }
  • 添加规则 (add rule 默认添加到链的末尾):
    1
    2
    3
    4
    # 允许已建立和相关联的连接
    sudo nft add rule inet my_table input_chain ct state established,related accept
    # 允许所有来自 192.168.1.0/24 网段的 TCP 80 端口访问
    sudo nft add rule inet my_table input_chain ip saddr 192.168.1.0/24 tcp dport 80 accept
  • 插入规则 (insert rule 默认插入到链的开头,也可指定位置):
    1
    2
    3
    4
    # 在链的开头插入规则
    sudo nft insert rule inet my_table input_chain ip saddr 127.0.0.1 accept
    # 在指定句柄 (handle) 之前插入规则 (先用 nft -a list ruleset 查 handle)
    # sudo nft insert rule inet my_table input_chain handle 123 ip saddr 10.0.0.1 accept

3.3 删除规则

  • 删除表sudo nft delete table inet my_table
  • 删除链sudo nft delete chain inet my_table input_chain
  • 删除规则 (两种方式):
    • 按句柄 (handle) 删除 (推荐):sudo nft delete rule inet my_table input_chain handle 123
    • 按规则内容删除:sudo nft delete rule inet my_table input_chain tcp dport 22 accept (必须精确匹配规则内容)

3.4 清空规则

  • 清空表中的所有链和规则sudo nft flush table inet my_table
  • 清空链中的所有规则sudo nft delete rule inet my_table input_chain (等同于 flush chain)

3.5 NAT 规则示例 (SNAT/DNAT)

场景描述:

  • 路由器/防火墙:公网 IP 203.0.113.10 (接口 eth0),内网 IP 192.168.1.1 (接口 eth1)
  • 内部 Web 服务器192.168.1.100,提供 HTTP 服务 (端口 80)。
  1. DNAT (端口转发):将外部访问 203.0.113.10:80 的请求转发到 192.168.1.100:80

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 启用 IP 转发
    sudo sysctl -w net.ipv4.ip_forward=1 net.ipv6.conf.all.forwarding=1

    # 创建一个 inet 表用于 NAT 规则
    sudo nft add table inet nat_table

    # 创建 DNAT 基本链
    sudo nft add chain inet nat_table prerouting { type nat hook prerouting priority -100 \; } # priority -100 是标准的 prerouting NAT 优先级

    # 创建 SNAT / Masquerade 基本链
    sudo nft add chain inet nat_table postrouting { type nat hook postrouting priority 100 \; } # priority 100 是标准的 postrouting NAT 优先级

    # 添加 DNAT 规则
    # 当目的地是公网接口的公网 IP,且端口为 80 的 TCP 连接,执行 DNAT
    sudo nft add rule inet nat_table prerouting iifname "eth0" ip daddr 203.0.113.10 tcp dport 80 dnat to 192.168.1.100:80

    # 添加 SNAT 规则 (确保内部服务器的回包能正确返回给外部客户端)
    # 当源 IP 是内部服务器,且出站接口是公网接口时,执行 masquerade (自动获取公网 IP 作为源 IP)
    sudo nft add rule inet nat_table postrouting oifname "eth0" ip saddr 192.168.1.100 masquerade

    注:nftables 通常会默认启用 filter 表,其 forward 链的默认策略可能为 accept,所以无需像 iptables 那样显式添加 FORWARD 规则,但最佳实践仍是配置明确的 filter 规则。

四、持久化 nftables 规则

nftables 规则默认不持久化,系统重启后会丢失。需要将规则保存到文件,并在系统启动时加载。

  1. 保存规则到文件

    1
    sudo nft list ruleset > /etc/nftables.conf
    • /etc/nftables.conf 是常见的规则文件路径。
  2. 自动加载规则

    • Systemd 服务:大多数 Linux 发行版会提供 nftables.service
      1
      2
      sudo systemctl enable nftables.service  # 启用服务,使其在开机时启动
      sudo systemctl start nftables.service # 立即启动服务加载规则
      nftables.service 通常会执行 nft -f /etc/nftables.conf 来加载规则。

五、nftables 的优势

  1. 统一的语法和工具nft 命令统一管理 IPv4、IPv6、桥接等所有协议的规则,消除了 iptables 系列工具的碎片化。
  2. 原子性更新:可以一次性加载整个规则集,保证规则集的原子性更新,避免了瞬时中断或不一致状态。
  3. 高性能:基于内核的字节码解释器,可以更高效地处理数据包和规则匹配。引入了更高效的数据结构(如集合、映射)。
  4. 灵活的规则定义:用户可以任意定义表和链,更灵活地组织规则。inet 地址族允许 IPv4 和 IPv6 规则的合并。
  5. 增强的匹配能力:支持更复杂的匹配表达式,例如基于各种网络协议头部字段匹配,以及强大的集合 (Set) 和映射 (Map) 功能。
  6. 简化 NAT:NAT 配置更加直观,例如 dnat to <ip>:<port>
  7. 连接跟踪改进:结合了 Netfilter 的连接跟踪器,可以更精细地控制连接状态。

六、总结

nftables 是 Linux 防火墙技术的一次重大飞跃,它在设计理念、性能和易用性方面都超越了传统的 iptables。通过统一的管理工具、灵活的规则结构、原子性更新和高效的内部处理机制,nftables 为 Linux 系统网络数据包过滤和管理提供了一个更强大、更现代的解决方案。虽然其语法与 iptables 截然不同,需要一定的学习成本,但随着主流发行版(如 Debian、Ubuntu、Fedora、RHEL)逐渐将其作为默认防火墙后端,掌握 nftables 将成为 Linux 系统管理员和网络工程师必备的技能。