nftables 教程:从入门到精通
nftables 是 Linux 内核中新一代的网络包过滤框架。它旨在取代旧的 iptables、ip6tables、arptables 和 ebtables,提供一个更简单、更高效、更统一的管理界面。
本教程将带您了解 nftables 的核心逻辑,并指导您构建一个安全、高效的防火墙。
nftables 的一切都由三个基本组件构成:表 (Table)、链 (Chain) 和 规则 (Rule)。
功能: 表 是最顶层的“容器”,用于存放特定目的的 链。
关键属性 (Family - 地址族): 创建表时,您必须指定它处理哪种流量:
ip:仅限 IPv4。ip6:仅限 IPv6。inet:(强烈推荐) 同时适用于 IPv4 和 IPv6。这是 nftables 相比 iptables 的最大优势,让您可以用一套规则管理所有流量。arp, bridge:用于更高级的网络功能。命名 (filter 是什么?):
table inet my_vps_security。filter(例如 table inet filter)只是一个约定俗成的习惯,继承自 iptables,表明这个表用于“包过滤”(接受/丢弃)。table ip filter 和 table inet filter 是两个完全不同的表。ip 族只管 IPv4,inet 族管 IPv4 和 IPv6。请不要同时使用它们,这会导致规则冲突。
功能: 链 是一个规则的有序列表。数据包会进入一个链,并从上到下逐一被规则检查。
链 有两种类型:
A) 基本链 (Base Chain):
这是“挂钩”到 Linux 内核网络堆栈的“入口”。
所有流量都必须经过这些“钩子 (Hook)”。
最关键的钩子:
input:处理目的地是您服务器本身的包(例如:SSH, Web 访问)。output:处理从您服务器本身发出的包(例如:ping google.com)。forward:处理需要穿过您服务器的包(即服务器作为路由器)。B) 常规链 (Regular Chain):
fail2ban 会创建一个 f2b-sshd 链,然后在 input 链中添加一条规则:tcp dport 22 jump f2b-sshd。
功能: 规则 是防火墙的最小执行单元。
它由两部分组成:
A) 匹配 (Match): 即“如果...”(条件)。
ip saddr 1.2.3.4 (如果源 IP 是 1.2.3.4)tcp dport 22 (如果目标是 TCP 22 端口)iif "eth0" (如果从 eth0 网卡进入)ct state established,related (如果是一个已建立的连接)B) 动作 (Action): 即“那么...”(执行)。
accept:接受。数据包通过。drop:丢弃。默默地丢弃,不给任何回应(推荐)。reject:拒绝。丢弃包,但发回一个错误(如 port unreachable)。jump <链名>:跳转到另一个常规链。counter:计数。记录匹配的包数量和字节数。
这是 nftables 的核心裁决机制,解决了“多个表/链同时存在时听谁的”问题。
当一个数据包到达一个钩子(例如 input)时:
nftables 会查看所有“挂”在这个 input 钩子上的所有链(无论它们在哪个表中)。priority(优先级)对这些链进行排序。priority 数字越小,优先级越高,越先执行。示例场景(您的问题):
table_A 的 chain_A 挂在 hook input priority 0,规则是 accept 10000。table_B 的 chain_B 挂在 hook input priority -10,规则是 drop 10000。裁决:
因为 -10 小于 0,chain_B 胜出并先执行。数据包在 chain_B 中被 drop。处理立即终止。chain_A 的 accept 规则永远不会被执行。
priority filter 是什么?
为了让规则更易读,nftables 提供了一些标准名称作为 priority 数字的别名:
priority raw = priority -300priority filter = priority 0priority nat = priority 100所以,priority filter 和 priority 0 是完全一样的。
我们的目标:默认拒绝一切(policy drop),只放行我们明确允许的服务。
永远只使用 inet 族! 这样您就不必担心 ip 和 inet 冲突。
x1# 1. 清空所有旧规则(小心!会断开现有连接)2sudo nft flush ruleset34# 2. 创建一个名为 'filter' 的 'inet' 族表5sudo nft add table inet filter
这是最关键的一步。我们将定义 input, forward, output 链,并将 input 和 forward 的默认策略设为 drop。
xxxxxxxxxx141# 1. 创建 input 链:2# type filter: 它的类型是过滤3# hook input: 它挂在 'input' 钩子上4# priority filter: 它的优先级是 0 (标准过滤级别)5# policy drop: 它的默认策略是 "丢弃"6sudo nft add chain inet filter input { type filter hook input priority filter \; policy drop \; }78# 2. 创建 forward 链:9# (我们不是路由器,所以默认丢弃所有转发包)10sudo nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }1112# 3. 创建 output 链:13# (我们通常信任自己服务器发出的流量,设为 accept)14sudo nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }现在,您的服务器是 100% 安全的,但也 100% 没用了,因为它会 drop 掉 包括您 SSH 在内 的所有新连接。
规则在链中是有顺序的。我们必须立即添加允许我们自己访问的规则。
x
1# 规则 1:允许 'lo' (localhost) 接口的所有流量(极其重要!)2sudo nft add rule inet filter input iif lo accept34# 规则 2:允许已建立的连接(这是防火墙的“记忆”)5# 允许所有 "已建立" 和 "相关" 的包。6# 这能让您访问外部网站的 "返回" 流量进入。7sudo nft add rule inet filter input ct state established,related accept89# 规则 3:允许 SSH (TCP 22)10sudo nft add rule inet filter input tcp dport 22 accept1112# 规则 4:允许 Web (HTTP/HTTPS)13sudo nft add rule inet filter input tcp dport { 80, 443 } accept1415# 规则 5:安全地允许 ICMP (Ping)16# ICMP 没有端口!它使用 'type'。17# 我们只允许必要的类型,并对 'ping' (echo-request) 进行限速。18sudo nft add rule inet filter input icmp type { echo-request, destination-unreachable, time-exceeded } limit rate 5/second accept19# (IPv6 需要更多 ICMPv6 类型,但 'inet' 表会自动处理)
您在命令行中的所有操作都会在重启后丢失。
xxxxxxxxxx81# 1. 将您当前的规则 "快照" 保存到配置文件2sudo nft list ruleset > /etc/nftables.conf34# 2. 启用 nftables 服务,使其开机自启5sudo systemctl enable nftables67# 3. 立即启动服务(或重启以应用配置)8sudo systemctl start nftables今后,请直接编辑 /etc/nftables.conf 文件,然后运行 sudo systemctl reload nftables 来应用更改。
xxxxxxxxxx121# 查看所有表、链和规则2sudo nft list ruleset34# 查看 'input' 链,并显示 'handle' (句柄号)5sudo nft -a list chain inet filter input6# 输出:7# ...8# tcp dport 22 accept # handle 49# ...1011# 按句柄号删除 SSH 规则12sudo nft delete rule inet filter input handle 4
fail2ban 是如何工作的?
fail2ban 与 nftables 配合得天衣无缝。当 fail2ban 启动时,它会:
创建自己的链: 例如 chain f2b-sshd。
添加跳转规则: 在您的 input 链中(通常在 ct state 规则之后)添加一条 jump 规则,例如:tcp dport 22 jump f2b-sshd。
动态管理: 当它检测到攻击时,它不会修改您的 input 链,而是向 f2b-sshd 链中添加一条规则:
ip saddr 203.116.129.142 counter packets 28 bytes 1456 reject
当封禁时间到期,它会从 f2b-sshd 链中删除这条规则。
fail2ban 的封禁在重启后会“幸存”吗?
是的。 防火墙规则本身是临时的,但 fail2ban 将其所有封禁记录保存在一个持久化数据库中(例如 /var/lib/fail2ban/fail2ban.sqlite3)。当 fail2ban 服务重启时,它会读取这个数据库,并自动将所有尚未过期的 IP 重新添加到 nftables 中。
table inet filter 来管理您的防火墙。policy drop 作为 input 链的默认策略。ct state established,related accept 作为您的第一条 accept 规则。priority 数字最小的链会最先执行并胜出。ping 使用 icmp type echo-request,不要完全禁用 ICMP。/etc/nftables.conf 中,并由 systemctl enable nftables 服务加载。