Linux 防火墙配置与管理完全教程
一、教程简介
本教程系统地讲解 Linux 防火墙的核心原理与四种主流配置工具:iptables、nftables、firewalld 和 UFW。涵盖从 netfilter 内核框架的五个 Hook 点到数据包在内核中的完整流转路径,从有状态/无状态防火墙的本质差异到每种工具的命令详解与实战 Demo。
无论你是在个人 VPS 上用 UFW 快速加固系统,还是在生产环境中用 nftables 追求极致性能,抑或是用 firewalld 的 Zone 模型管理多网络环境,本教程都能提供清晰、可操作的指导。
二、适用人群
| 角色 | 典型需求 |
|---|---|
| Linux 运维工程师 | 生产环境防火墙策略制定、NAT 端口转发、DDoS 防护规则 |
| 安全工程师 | 纵深防御体系中的主机防火墙层、入侵检测规则联动 |
| 个人开发者 / VPS 用户 | 快速加固云服务器、开放常用服务端口、防 SSH 暴力破解 |
| 架构师 / 技术选型 | 在 iptables / nftables / firewalld / UFW 之间做出技术决策 |
| 嵌入式开发者 | 路由器/网关上的 netfilter 规则定制 |
三、完整文档目录
| 编号 | 文件名 | 核心内容 |
|---|---|---|
| 01 | 01-原理概述.md | netfilter 内核框架、五个 Hook 点、有状态 vs 无状态防火墙、四表五链模型 |
| 02 | 02-iptables详解.md | 四表五链全景图、数据包流转路径、规则匹配性能分析、常用匹配模块与目标动作 |
| 03 | 03-nftables详解.md | nftables 与 iptables 架构差异、集合/映射 O(1) 高效查找、原子规则更新、迁移指南 |
| 04 | 04-firewalld详解.md | Zone 信任级别模型、运行时 vs 永久配置分离、富规则语法、D-Bus API |
| 05 | 05-UFW详解.md | UFW 极简设计哲学、命令→iptables 映射原理、应用配置文件机制 |
| 06 | 06-方案选择决策指南.md | 决策流程图、4 方案 x 12 维度对比矩阵、场景速查表、常见误区与 CheatSheet |
四、快速场景速查表
| 场景 | 推荐方案 | 备选方案 | 对应文档 |
|---|---|---|---|
| 个人桌面 / 开发机 (Ubuntu/Debian) | UFW | iptables(直接规则) | 05, 02 |
| 个人桌面 / 开发机 (Fedora/RHEL) | firewalld | iptables | 04, 02 |
| 小型 VPS / Web 服务器(单一管理员) | UFW 或 firewalld | iptables | 05, 04 |
| 中型生产环境(需要精细控制) | firewalld + 富规则 | nftables | 04, 03 |
| 大型 / 高流量环境(性能敏感) | nftables | iptables(遗留) | 03, 02 |
| 容器环境(Docker/K8s 宿主机) | iptables | nftables(需谨慎) | 02, 03 |
| 路由器 / NAT 网关 | iptables 或 nftables | firewalld | 02, 03 |
| 嵌入式 / Linux From Scratch | iptables | nftables(较新内核) | 02, 03 |
| 安全合规要求高 | nftables(原子更新) | firewalld | 03, 04 |
| 学习目的 | 先 iptables 再 nftables | — | 02, 03 |
五、四种方案一句话简介
| 序号 | 方案 | 一句话简介 |
|---|---|---|
| 1 | iptables | Linux 防火墙的事实标准(2001-),通过四表五链模型直接操作 netfilter 内核框架 |
| 2 | nftables | 下一代内核包过滤子系统,统一替代 {ip,ip6,arp,eb}tables,支持集合/映射 O(1) 查找 |
| 3 | firewalld | RHEL 系列的 Zone 模型防火墙,运行时/永久配置分离,D-Bus 动态管理 |
| 4 | UFW | Ubuntu/Debian 的极简防火墙前端,"一条命令搞定"的设计哲学 |
六、Demo 目录使用说明
教程配套的 demo 目录位于 demos/,包含四种方案的配置示例与可执行脚本:
demos/
├── README.md # 本使用说明
├── iptables/ # iptables 规则脚本
│ ├── basic-rules.sh # 基础防护规则(INPUT DROP + 白名单)
│ └── port-forwarding.sh # NAT 端口转发(DNAT/SNAT/MASQUERADE)
├── nftables/ # nftables 规则文件
│ ├── basic-rules.nft # 完整 inet filter 表(集合/映射/计数器)
│ └── compare-iptables.nft # 10+ 组 iptables vs nftables 并排对比
├── firewalld/ # firewalld 脚本
│ └── zone-demo.sh # Zone 切换、富规则、直接规则演示
└── ufw/ # UFW 脚本
└── quick-setup.sh # 默认策略、应用名开放、限速、IP 白名单
每个脚本均可通过 sudo bash <脚本名>.sh 执行(测试环境,生产环境请先阅读脚本内容并按需修改)。
七、使用建议(阅读顺序)
新手路径
01-原理概述 → 02-iptables详解 → 根据你的场景选择 03/04/05
→ 06-方案选择决策指南
运维工程师路径
01-原理概述 → 02-iptables详解 → 04-firewalld详解 → 03-nftables详解
→ 06-方案选择决策指南
架构师/选型路径
01-原理概述 → 02-iptables详解 → 03-nftables详解 → 04-firewalld详解
→ 05-UFW详解 → 06-方案选择决策指南
速查路径
直接查阅本文"快速场景速查表"和"四种方案一句话简介表",定位需要的文档编号后跳转阅读。
八、关于本文档
- 作者: Linux 防火墙技术研究小组
- 版本: v2.0
- 许可: CC BY-SA 4.0
- 反馈: 欢迎提交 Issue / PR 改进本教程
提示:所有文档中的 IP 示例均使用
192.168.1.0/24网段和203.0.113.0/24公网示例网段(RFC 5737)。请根据你的实际网络环境进行替换。
01 — Linux 防火墙原理概述
在深入学习各种防火墙配置工具之前,必须理解 Linux 防火墙的底层架构:netfilter 内核框架如何工作、有状态和无状态防火墙的本质区别、数据包如何在内核协议栈中流转以及四表五链模型的完整设计。
一、整体架构分层
Linux 防火墙系统可以划分为清晰的三层架构,每层承担不同的职责:
┌─────────────────────────────────────────────────────────────────┐
│ 用户态管理工具层 (User Space) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ iptables │ │ nft │ │ firewall-cmd │ │ ufw │ │
│ │ (传统) │ │(下一代) │ │ (firewalld) │ │ (极简前端) │ │
│ └────┬─────┘ └────┬─────┘ └──────┬───────┘ └──────┬────────┘ │
│ │ │ │ │ │
│ ┌────┴────────────┴──────────────┴─────────────────┴───────┐ │
│ │ 内核接口层 │ │
│ │ Netlink (xtables API) │ Netlink (nf_tables API) │ │
│ │ setsockopt/getsockopt │ (NFNL_SUBSYS_NFTABLES) │ │
│ └──────────────────────┬───────────────────────────────────┘ │
│ │ │
├─────────────────────────┼─────────────────────────────────────────┤
│ 内核层 (Kernel Space) │
│ │ │
│ ┌──────────────────────┴──────────────────────────────────┐ │
│ │ netfilter 核心框架 │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 五个 Hook │ │ 连接跟踪 │ │ NAT 子系统 │ │ │
│ │ │ 注册点 │ │ (conntrack) │ │ (DNAT/SNAT) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ xtables 模块 │ │ nf_tables │ │ 数据包匹配 │ │ │
│ │ │ (iptables后端)│ │ (nftables后端)│ │ 引擎 │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ↓ │
│ Linux 内核网络协议栈 (TCP/IP Stack) │
└─────────────────────────────────────────────────────────────────┘
三层通信路径总结:
用户态工具 ──(Netlink/setsockopt)──▶ netfilter 内核框架 ──▶ 协议栈 Hook 点
│ │
└──(procfs /sys 只读)──▶ 查看内核状态 ◀──┘
关键原则:用户态工具通过 Netlink 将规则写入内核,内核在协议栈的 Hook 点执行匹配和动作;/proc/net/ 等 procfs 接口仅用于查看连接跟踪等信息,不能用于配置防火墙规则。
二、netfilter 内核框架详解
2.1 什么是 netfilter
netfilter 是 Linux 内核 2.4 版本(2001 年)引入的包过滤子系统,提供了数据包过滤、网络地址转换(NAT)和端口转换的完整框架。它通过在协议栈的关键位置嵌入钩子函数(Hook Functions),使开发者能够在数据包经过的不同阶段注册回调函数,从而实现对网络流量的精细控制。
netfilter 的核心设计哲学是:不对协议栈本身做侵入式修改,而是通过注册回调的方式,让内核模块在数据包流转的关键节点上"观察"并"决策"每个数据包的命运。
2.2 五个 Hook 点详解
netfilter 在内核协议栈中定义了五个标准 Hook 点,每个 Hook 点位于数据包处理流水线中的不同阶段:
网络
│
┌────────▼────────┐
│ 网卡驱动接收 │
└────────┬────────┘
│
┌─────────────────────▼─────────────────────┐
│ [1] NF_IP_PRE_ROUTING │
│ │
│ - 所有入站数据包必经之路 │
│ - DNAT(目标地址转换)在此进行 │
│ - 原始目标地址在此处被修改 │
│ - 对应链:PREROUTING │
└─────────────────────┬─────────────────────┘
│
┌────────▼────────┐
│ 路由决策 │
│ 目标IP == 本机? │
└───┬──────────┬───┘
│ 是 │ 否(需转发)
┌────────────────▼──┐ ┌───▼────────────────┐
│ [2] NF_IP_LOCAL_IN│ │ [3] NF_IP_FORWARD │
│ │ │ │
│ - 发往本机的包 │ │ - 经本机转发的包 │
│ - INPUT 链在此 │ │ - FORWARD 链在此 │
│ - 过滤进入服务的 │ │ - 过滤转发的流量 │
│ 流量 │ │ │
└────────┬─────────┘ └─────────┬──────────┘
│ │
┌────────▼─────────┐ │
│ 本地进程 │ │
│ (应用程序接收) │ │
└────────┬─────────┘ │
│ │
┌────────▼──────────────────────▼──────────┐
│ [4] NF_IP_LOCAL_OUT │
│ │
│ - 本机发出的数据包 │
│ - OUTPUT 链在此 │
│ - SNAT 可选在此(早于路由决策的场景) │
└─────────────────────┬──────────────────────┘
│
┌────────▼────────┐
│ 路由决策 │
│ (确定出接口/下一跳)│
└────────┬────────┘
│
┌─────────────────────▼──────────────────────┐
│ [5] NF_IP_POST_ROUTING │
│ │
│ - 所有出站数据包必经之路 │
│ - SNAT/MASQUERADE 在此进行 │
│ - 源地址在此被最终修改 │
│ - 对应链:POSTROUTING │
└─────────────────────┬──────────────────────┘
│
┌────────▼────────┐
│ 网卡驱动发送 │
└────────┬────────┘
│
网络
五个 Hook 点速查表:
| Hook | 常量名 | 触发时机 | 主要用途 | 对应链 |
|---|---|---|---|---|
| Hook 1 | NF_IP_PRE_ROUTING | 数据包进入协议栈后,路由决策前 | DNAT、早期过滤、连接跟踪入口 | PREROUTING |
| Hook 2 | NF_IP_LOCAL_IN | 路由决策判定为本地后,进入本地进程前 | 入站流量过滤(防火墙核心) | INPUT |
| Hook 3 | NF_IP_FORWARD | 路由决策判定为转发后 | 转发流量过滤(网关核心) | FORWARD |
| Hook 4 | NF_IP_LOCAL_OUT | 本地进程生成数据包后,路由决策前 | 出站流量过滤、本机 DNAT(透明代理) | OUTPUT |
| Hook 5 | NF_IP_POST_ROUTING | 路由决策完成后,离开协议栈之前 | SNAT、MASQUERADE | POSTROUTING |
2.3 连接跟踪子系统(conntrack)
netfilter 的连接跟踪子系统是有状态防火墙的基础。它为每个通过的数据包创建连接跟踪条目,记录连接的协议、状态、方向和超时信息。
连接跟踪状态转换图(TCP 三次握手为例):
Client Server
│ │
│ ──── SYN ────────────────► │
│ │
┌────▼──────┐ │
│ NEW │ conntrack 创建条目 │
└────┬──────┘ │
│ │
│ ◄──── SYN-ACK ──────────── │
│ │
┌────▼──────────┐ │
│ ESTABLISHED │ 双向通信确认 │
└────┬──────────┘ │
│ │
│ ──── ACK ────────────────► │
│ │
┌────▼──────────┐ │
│ ESTABLISHED │ 连接已建立 │
└────┬──────────┘ │
│ │
│ ──── 数据交换 ────────────► │
│ ◄──── 数据交换 ──────────── │
│ │
│ ──── FIN ────────────────► │
│ ◄──── FIN/ACK ──────────── │
│ │
┌────▼──────┐ │
│ CLOSE/FIN │ 进入关闭流程 │
└────┬──────┘ │
│ │
│ (超时后 conntrack 条目删除) │
conntrack 维护的五种连接状态:
| 状态 | 含义 | 典型场景 |
|---|---|---|
| NEW | 连接的第一个数据包,conntrack 表中无对应条目 | TCP SYN 包、UDP 新流 |
| ESTABLISHED | 连接已建立,双向通信已确认 | TCP 三次握手完成后的数据包 |
| RELATED | 与已建立连接相关的新连接(辅助连接) | FTP 数据通道、SIP RTP 流、ICMP 差错报文 |
| INVALID | 无法识别或状态异常的数据包 | TCP RST 重放、状态错乱、过期残留 |
| UNTRACKED | 被显式标记为不跟踪的数据包 | 使用 NOTRACK 目标的高性能场景 |
# 查看 conntrack 表内容
conntrack -L # 列出所有连接跟踪条目
conntrack -S # 统计信息(新建/删除/查找次数)
conntrack -E # 实时事件流(NEW/UPDATE/DESTROY)
# 查看 conntrack 表容量
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
三、有状态防火墙 vs 无状态防火墙
3.1 核心原理对比
无状态防火墙(Stateless Firewall)
无状态防火墙对每个数据包进行独立判断,不记录任何历史连接信息。每个数据包到达时,防火墙仅根据该包的头部信息(源IP、目标IP、源端口、目标端口、协议类型)与规则集进行逐条匹配。
工作流程:
Packet_1 (SYN, src:1.2.3.4:54321 → dst:5.6.7.8:80)
→ 检查规则:允许 TCP/80入站?→ 匹配 → 通过
Packet_2 (SYN-ACK, src:5.6.7.8:80 → dst:1.2.3.4:54321)
→ 检查规则:允许 TCP/80入站?→ 不匹配(方向相反)→ 需要额外规则!
→ 必须专门添加"允许源端口80的出站SYN-ACK"规则 → 否则被拒绝!
Packet_3 (ACK, src:1.2.3.4:54321 → dst:5.6.7.8:80)
→ 同样需要逐条匹配...
缺点总结:
- 必须为双向流量分别创建规则(规则数量翻倍)
- 无法区分"合法的响应数据包"和"伪造的攻击数据包"
- 对 FTP、SIP 等动态端口协议支持困难
- 规则数量随服务增多呈线性增长
有状态防火墙(Stateful Firewall)
有状态防火墙维护一个连接跟踪表(conntrack table),记录所有通过防火墙的活动连接。当新数据包到达时,防火墙首先检查它是否属于某个已知连接,如果是,则无需逐条匹配规则,直接放行。
工作流程:
Packet_1 (SYN, src:1.2.3.4:54321 → dst:5.6.7.8:80)
→ 查 conntrack 表:未找到(新连接)
→ 逐条匹配规则:匹配到"允许 TCP/80"
→ 在 conntrack 表中创建条目:[NEW] → [ESTABLISHED]
→ 放行
Packet_2 (SYN-ACK, src:5.6.7.8:80 → dst:1.2.3.4:54321)
→ 查 conntrack 表:找到关联条目(状态:ESTABLISHED)
→ **跳过所有规则匹配,直接放行!**
Packet_3 (ACK, src:1.2.3.4:54321 → dst:5.6.7.8:80)
→ 查 conntrack 表:找到关联条目
→ 直接放行(无需再遍历规则链)
3.2 有状态防火墙的优势
| 优势 | 说明 |
|---|---|
| 配置简洁 | 只需定义"发起方向"的规则,响应流量自动放行(单条规则 vs 双向两条规则) |
| 安全性强 | 自动拒绝不属于任何合法连接的伪造数据包,大幅减少攻击面 |
| 协议支持好 | 通过 RELATED 状态自动追踪 FTP 数据通道、SIP RTP 流等辅助连接 |
| 性能优化 | ESTABLISHED 流量走快速路径,无需遍历全规则链 |
3.3 典型的"最小化"有状态防火墙规则
# iptables 版本 —— 三行搞定基础防护
iptables -P INPUT DROP
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# nftables 版本 —— 同样简洁
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0; policy drop; }
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport 22 ct state new accept
规则解读:
- 默认丢弃所有入站流量
- 已建立和相关的连接直接放行(不检查后续规则)
- 仅允许 SSH 新连接的建立
- 其他所有入站请求全部被丢弃
四、数据包在内核中的完整流转路径
4.1 场景 A:入站数据包(外部 → 本机进程)
网卡驱动接收
↓
[1] PREROUTING Hook
├── raw 表(跳过 conntrack?)
├── conntrack 处理(NEW/ESTABLISHED 判定)
├── mangle 表(修改 TOS/TTL?)
└── nat 表(DNAT?)
↓
路由决策:目标 IP == 本机 IP?
↓ 是
[2] INPUT Hook
├── mangle 表
└── filter 表(核心过滤)
↓ 通过(ACCEPT)
本地进程接收
4.2 场景 B:转发数据包(外部 → 本机 → 另一网络)
网卡驱动接收
↓
[1] PREROUTING Hook(同场景 A)
├── conntrack → mangle → nat (DNAT)
↓
路由决策:目标 IP != 本机 IP?(需要转发)
↓ 是
[3] FORWARD Hook
├── mangle 表
└── filter 表(网关过滤核心)
↓ 通过
[5] POSTROUTING Hook
├── mangle 表
└── nat 表(SNAT/MASQUERADE)
↓
网卡驱动发送
4.3 场景 C:出站数据包(本机进程 → 外部)
本地进程生成数据包
↓
[4] OUTPUT Hook
├── raw 表
├── conntrack 处理
├── mangle 表
├── nat 表(本机 DNAT → 透明代理)
└── filter 表(限制本机出站)
↓
路由决策(确定出接口和下一跳)
↓
[5] POSTROUTING Hook
├── mangle 表
└── nat 表(SNAT/MASQUERADE)
↓
网卡驱动发送
4.4 关键路径速查
| 路径 | 经过的 Hook 点(按顺序) | 典型场景 |
|---|---|---|
| 外部 → 本机 | PREROUTING → INPUT | 外部用户访问本机 Web 服务 |
| 本机 → 外部 | OUTPUT → POSTROUTING | 本机 curl 访问外部 API |
| 外部 → 本机 → 外部(转发) | PREROUTING → FORWARD → POSTROUTING | 作为网关/路由器转发流量 |
| 外部 → 本机 → 外部(DNAT+转发) | PREROUTING(DNAT) → FORWARD → POSTROUTING(SNAT) | 端口映射到内网服务器 |
五、四表五链模型详解
iptables 的核心架构可以概括为"四表五链",理解这个模型是掌握 iptables 及所有基于 netfilter 的工具的基础。
5.1 四个表(Tables)
表是按功能分类的规则集合,每个表负责特定类型的处理:
优先级(处理顺序)
│
┌───────────────────────────────────┼───────────────────────────────┐
│ ▼ │
│ 表 功能 包含的链 使用场景 │
│ │
│ raw 跳过连接跟踪 PREROUTING, OUTPUT 高性能场景 │
│ ───────────── │ │
│ mangle 修改包头标记 PREROUTING, INPUT, QoS/TOS │
│ (MARK/TOS/TTL) FORWARD, OUTPUT, │ │
│ POSTROUTING │ │
│ nat 网络地址转换 PREROUTING(DNAT), 端口映射 │
│ INPUT, OUTPUT, │ │
│ POSTROUTING(SNAT) │ │
│ filter 数据包过滤 INPUT, FORWARD, 防火墙核心 │
│ (默认表) OUTPUT │
└───────────────────────────────────────────────────────────────────┘
各表详细说明:
raw 表 —— 最高优先级。包含特殊目标 NOTRACK,用于标记某些数据包不需要被连接跟踪处理。适用场景:高并发 DNS 服务器(大量短时 UDP 查询会使 conntrack 表成为瓶颈)、已知安全的内部流量。
mangle 表 —— 第二优先级。用于对数据包进行"修饰"——修改 IP 头部中的特定字段:
- 修改 TTL(Time To Live)值
- 设置/修改 DSCP 字段实现 QoS
- 给数据包打上内核标记(MARK),供后续路由策略(
ip rule)使用 - 给连接打上标记(CONNMARK),用于复杂策略路由
nat 表 —— 第三优先级。实现网络地址转换:
- DNAT(目标地址转换):发生在 PREROUTING 链,修改目标地址和端口
- SNAT(源地址转换):发生在 POSTROUTING 链,修改源地址实现内网上网
filter 表 —— 最低优先级(但最常用),默认表。负责最基础的数据包过滤:INPUT/OUTPUT/FORWARD 三个链的防火墙规则。
5.2 五个链(Chains)
链是按数据包流转位置分类的规则序列,每个链对应 netfilter 的一个 Hook 点:
| 链名 | 对应 Hook 点 | 数据包来源 | 数据包去向 | 典型规则示例 |
|---|---|---|---|---|
| PREROUTING | NF_IP_PRE_ROUTING | 网卡收到 | 路由决策 | DNAT、早期过滤 |
| INPUT | NF_IP_LOCAL_IN | 路由决策(本地) | 本地进程 | 过滤入站流量 |
| FORWARD | NF_IP_FORWARD | 路由决策(转发) | 另一网卡 | 网关过滤 |
| OUTPUT | NF_IP_LOCAL_OUT | 本地进程 | 路由决策 | 限制本机出站 |
| POSTROUTING | NF_IP_POST_ROUTING | 路由决策后 | 网卡发送 | SNAT、MASQUERADE |
5.3 表与链的交叉矩阵
每个数据包经过链时,该链上不同表的规则按优先级顺序执行:
PREROUTING INPUT FORWARD OUTPUT POSTROUTING
raw ✓ - - ✓ -
mangle ✓ ✓ ✓ ✓ ✓
nat ✓ ✓(极少) - ✓ ✓
filter - ✓ ✓ ✓ -
以 PREROUTING 链为例的处理顺序:
数据包到达 PREROUTING 链
↓
[1] raw 表 PREROUTING 规则 → NOTRACK?(跳过 conntrack)
↓
[2] conntrack 处理 → 判定 NEW/ESTABLISHED/RELATED/INVALID
↓
[3] mangle 表 PREROUTING 规则 → 修改 TOS/TTL/MARK?
↓
[4] nat 表 PREROUTING 规则 → DNAT?
↓
路由决策 ...
5.4 四表五链全景图
数据包到达
│
┌─────────────▼─────────────┐
│ [PREROUTING 链] │
│ raw → conntrack → mangle │
│ → nat (DNAT) │
└─────────────┬─────────────┘
│
┌────────▼────────┐
│ 路由决策 │
│ 目标IP == 本机? │
└───┬──────────┬───┘
│ 是 │ 否(需转发)
┌──────────────▼──┐ ┌───▼──────────────┐
│ [INPUT 链] │ │ [FORWARD 链] │
│ mangle → filter│ │ mangle → filter │
└───────┬─────────┘ └───┬───────────────┘
│ │
┌───────▼─────────┐ │
│ 本地进程 │ │
└───────┬─────────┘ │
│ │
┌───────▼─────────────────▼───────┐
│ [OUTPUT 链] │
│ raw → conntrack → mangle │
│ → nat (DNAT) → filter │
└───────────────┬─────────────────┘
│
┌────────▼────────┐
│ 路由决策 │
│ (确定出接口/下一跳)│
└────────┬────────┘
│
┌───────────────▼───────────────┐
│ [POSTROUTING 链] │
│ mangle → nat (SNAT/MASQ) │
└───────────────┬───────────────┘
│
数据包发出
六、规则匹配引擎的三种实现
从 netfilter 的视角,共有三种规则匹配引擎共存于 Linux 内核中:
用户空间工具
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────────┐
│ iptables │ │ nft │ │ bpfilter │
│ 命令行 │ │ 命令行 │ │ (实验性) │
└────┬─────┘ └────┬─────┘ └──────┬───────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────────┐
│ xtables │ │nf_tables │ │ BPF │
│ (遗留) │ │ (新一代) │ │ (eBPF) │
└────┬─────┘ └────┬─────┘ └──────┬───────┘
│ │ │
└──────────────┼────────────────┘
▼
┌─────────────────┐
│ netfilter 核心 │
│ 五个 Hook 点 │
└─────────────────┘
| 引擎 | 引入时间 | 用户工具 | 状态 |
|---|---|---|---|
| xtables | 2001 (Linux 2.4) | iptables/ip6tables/arptables/ebtables | 遗留但广泛部署,逐步淘汰 |
| nf_tables | 2014 (Linux 3.13) | nft(单一命令) | Linux 防火墙的未来标准 |
| bpfilter | 2018 (Linux 4.18) | iptables(透明兼容) | 实验性,目标是用 eBPF 替代 netfilter |
七、总结
理解 Linux 防火墙原理,核心在于掌握以下几点:
-
三层架构:用户态工具 → Netlink 内核接口 → netfilter 框架 + 协议栈 Hook 点,这是所有防火墙方案共通的底层路径。
-
五个 Hook 点:PREROUTING → INPUT/FORWARD → OUTPUT → POSTROUTING,数据包在每个 Hook 点都可能被拦截、修改或丢弃。
-
有状态防火墙是现代标准:通过 conntrack 连接跟踪,只需定义"发起方向"的规则,响应流量自动放行。这是安全性和配置简洁性的双重飞跃。
-
四表五链模型:raw → mangle → nat → filter 的处理顺序决定了规则的执行优先级;表与链的交叉矩阵是理解 iptables 的关键。
-
三种匹配引擎共存:xtables(iptables 后端)、nf_tables(nftables 后端)、bpfilter(实验性),nftables 是未来的方向。
-
方案选择取决于场景:从极简的 UFW 到高性能的 nftables,没有银弹,只有最适合当前场景的方案。
掌握了这些原理之后,再阅读后续的各方案详解文档,你就能理解每个工具的"为什么"而不只是"怎么做"。
下一步:02 — iptables 详解
02 — iptables 详解
iptables 是 Linux 内核 netfilter 框架的传统用户空间管理工具,自 2001 年伴随 Linux 2.4 内核发布以来,一直是 Linux 防火墙的事实标准。本文深入讲解 iptables 的核心概念、工作原理和进阶用法。
一、四表五链全景图
iptables 的核心架构可以概括为"四表五链"——四张功能表(raw/mangle/nat/filter)和五条数据包流经的链(PREROUTING/INPUT/FORWARD/OUTPUT/POSTROUTING)。
数据包到达
│
┌─────────────▼─────────────┐
│ [PREROUTING 链] │
│ │
│ 1. raw (NOTRACK) │
│ 2. conntrack (状态判定) │
│ 3. mangle (TOS/MARK) │
│ 4. nat (DNAT) │
└─────────────┬─────────────┘
│
┌────────▼────────┐
│ 路由决策 │
│ 目标IP == 本机? │
└───┬──────────┬───┘
│ 是 │ 否(需转发)
┌──────────────▼──┐ ┌───▼──────────────┐
│ [INPUT 链] │ │ [FORWARD 链] │
│ │ │ │
│ 1. mangle │ │ 1. mangle │
│ 2. filter │ │ 2. filter │
└───────┬─────────┘ └───┬───────────────┘
│ │
┌───────▼─────────┐ │
│ 本地进程 │ │
└───────┬─────────┘ │
│ │
┌───────▼─────────────────▼───────┐
│ [OUTPUT 链] │
│ │
│ 1. raw (NOTRACK) │
│ 2. conntrack (状态判定) │
│ 3. mangle (TOS/MARK) │
│ 4. nat (本机 DNAT) │
│ 5. filter (出站过滤) │
└───────────────┬─────────────────┘
│
┌────────▼────────┐
│ 路由决策 │
│ (确定出接口/下一跳)│
└────────┬────────┘
│
┌───────────────▼───────────────┐
│ [POSTROUTING 链] │
│ │
│ 1. mangle (TOS/MARK) │
│ 2. nat (SNAT/MASQ) │
└───────────────┬───────────────┘
│
数据包发出
1.1 四个表详解
| 表名 | 功能 | 包含的链 | 典型使用场景 | 优先级 |
|---|---|---|---|---|
| raw | 跳过连接跟踪 | PREROUTING, OUTPUT | 高并发 DNS 服务器、内部信任流量、conntrack 表已满时的逃生通道 | 最高 |
| mangle | 修改数据包头部标记 | PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING | TOS/DSCP 修改、TTL 调整、连接标记(CONNMARK)、策略路由标记(MARK) | 第二 |
| nat | 网络地址转换 | PREROUTING, INPUT, OUTPUT, POSTROUTING | 端口转发(DNAT)、源地址转换(SNAT)、本机透明代理(REDIRECT) | 第三 |
| filter | 数据包过滤(默认表) | INPUT, FORWARD, OUTPUT | 防火墙核心:放行/拒绝/丢弃规则 | 最低 |
当不指定
-t参数时,iptables 默认操作 filter 表。
1.2 五个链详解
| 链名 | 对应 Hook 点 | 数据包来源 | 数据包去向 | 典型规则示例 |
|---|---|---|---|---|
| PREROUTING | NF_IP_PRE_ROUTING | 网卡收到 | 路由决策 | DNAT、连接跟踪 |
| INPUT | NF_IP_LOCAL_IN | 路由决策(本地) | 本地进程 | -p tcp --dport 22 -j ACCEPT |
| FORWARD | NF_IP_FORWARD | 路由决策(转发) | 另一网卡 | 网关过滤、Docker 容器间通信 |
| OUTPUT | NF_IP_LOCAL_OUT | 本地进程 | 路由决策 | 限制本机出站 DNS 查询 |
| POSTROUTING | NF_IP_POST_ROUTING | 路由决策后 | 网卡发送 | SNAT、MASQUERADE |
1.3 表与链的交叉矩阵
PREROUTING INPUT FORWARD OUTPUT POSTROUTING
raw ✓ - - ✓ -
mangle ✓ ✓ ✓ ✓ ✓
nat ✓ ✓ - ✓ ✓
filter - ✓ ✓ ✓ -
✓ = 该表在此链上有挂钩
- = 无挂钩
二、数据包流转路径图
2.1 三条关键路径
路径 A: 外部 → 本机(访问本机服务)
┌─────────┐ ┌─────────────┐ ┌──────────┐ ┌──────────┐
│ 网卡接收 │ → │ PREROUTING │ → │ INPUT │ → │ 本地进程 │
│ │ │ raw→ct→mangle│ │ mangle │ │ │
│ │ │ → nat(DNAT) │ │ → filter │ │ │
└─────────┘ └─────────────┘ └──────────┘ └──────────┘
路径 B: 外部 → 本机 → 转发(网关模式)
┌─────────┐ ┌─────────────┐ ┌───────────┐ ┌──────────────┐ ┌─────────┐
│ 网卡接收 │ → │ PREROUTING │ → │ FORWARD │ → │ POSTROUTING │ → │ 网卡发送 │
│ │ │ raw→ct→mangle│ │ mangle │ │ mangle │ │ │
│ │ │ → nat(DNAT) │ │ → filter │ │ → nat(SNAT) │ │ │
└─────────┘ └─────────────┘ └───────────┘ └──────────────┘ └─────────┘
路径 C: 本机 → 外部(本机主动出站)
┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌─────────┐
│ 本地进程 │ → │ OUTPUT │ → │ POSTROUTING │ → │ 网卡发送 │
│ │ │ raw→ct→ │ │ mangle │ │ │
│ │ │ mangle→nat│ │ → nat(SNAT) │ │ │
│ │ │ → filter │ │ │ │ │
└──────────┘ └──────────┘ └──────────────┘ └─────────┘
2.2 关键路径速查
| 路径 | 经过的链(按顺序) | 典型场景 |
|---|---|---|
| 外部 → 本机 | PREROUTING → INPUT | 外部用户访问本机 Web 服务 |
| 本机 → 外部 | OUTPUT → POSTROUTING | 本机 curl 访问外部 API |
| 外部 → 本机 → 外部(转发) | PREROUTING → FORWARD → POSTROUTING | 作为网关/路由器转发流量 |
| 外部 → 本机 → 外部(DNAT+转发) | PREROUTING(DNAT) → FORWARD → POSTROUTING(SNAT) | 端口映射到内网服务器 |
| 本机透明代理 | OUTPUT(DNAT/REDIRECT) → POSTROUTING | 将本机出站流量重定向到本地代理 |
2.3 特殊说明:nat 表的 OUTPUT 链
nat 表的 OUTPUT 链是一个容易被忽视但非常实用的特性。它允许对本机发出的数据包进行 DNAT,典型场景:
- 透明代理:将本机发向 80 端口的流量重定向到本地代理端口(如 3128)
- 本机服务访问优化:将本机发出的数据库请求重定向到本地缓存
# 将本机发出的所有 80 端口流量重定向到本地 3128 代理
iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-ports 3128
三、规则匹配顺序与性能分析
3.1 核心原则:第一匹配即停止
iptables 的规则匹配采用**"第一匹配即停止"(First Match Wins)**策略:
数据包进入链
│
▼
规则 1: 匹配? ─── 是 ── ▶ 执行目标动作
│ 否 │
▼ 终结性目标? │
规则 2: 匹配? ─── 是 ── ▶ 是 → 停止处理
│ 否 │
▼ │
... 非终结性目标? │
│ │
▼ 是 → 继续匹配
规则 N: 匹配? ─── 是 ── ▶
│ 否
▼
链默认策略(policy)
终结性目标:ACCEPT、DROP、REJECT、SNAT、DNAT、MASQUERADE、REDIRECT 非终结性目标:LOG、MARK、RETURN(自定义链中)、NOTRACK
3.2 规则遍历过程示例
假设 INPUT 链有以下规则:
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
2 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
3 ACCEPT tcp -- 192.168.1.0/24 0.0.0.0/0 tcp dpt:80
4 LOG tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
5 DROP all -- 0.0.0.0/0 0.0.0.0/0
数据包处理过程:
| 场景 | 匹配路径 | 结果 | 原因 |
|---|---|---|---|
| 已建立连接的 SSH 响应包 | 规则 1 | ACCEPT(1 次匹配) | ctstate ESTABLISHED 命中 |
| 来自 192.168.1.100 的新 HTTP 请求 | 规则 1→2→3 | ACCEPT(3 次匹配) | 规则 3 命中 |
| 来自 10.0.0.1 的新 HTTP 请求 | 规则 1→2→3→4→5 | 先 LOG 后 DROP(5 次匹配) | 规则 4 非终结 + 规则 5 命中 |
| 来自外网的 UDP 53 端口扫描 | 规则 1→2→3→4 | DROP(策略) | 无规则匹配,执行 policy DROP |
3.3 规则顺序对性能的影响
iptables 的规则匹配是 O(n) 线性查找。规则顺序直接影响性能:
最佳实践排序(从快到慢):
1. ESTABLISHED,RELATED 规则 ← 绝大多数合法流量在此命中,立即跳过后面的所有规则
2. 高频匹配的具体规则(如 SSH) ← 将常用服务放在前面
3. 低频匹配的具体规则(如 MySQL)← 偶尔使用的服务放在后面
4. LOG 规则(非终结性) ← 日志记录
5. 默认拒绝(或链的默认策略) ← 兜底规则
性能基准参考(规则数量对吞吐量的影响):
| 规则数量 | 最坏匹配次数 | 预估吞吐量影响(64 字节包) |
|---|---|---|
| 10 条 | 10 次 | ~950K pps(基准的 95%) |
| 50 条 | 50 次 | ~850K pps(基准的 85%) |
| 100 条 | 100 次 | ~800K pps(基准的 80%) |
| 500 条 | 500 次 | ~500K pps(基准的 50%) |
| 1000 条 | 1000 次 | ~300K pps(基准的 30%) |
注:以上为相对参考值。将 ESTABLISHED 规则放在第一位可使绝大多数流量仅需 1 次匹配。
3.4 错误顺序示例与修复
# 错误示例:DROP 在最前面,后面的 ACCEPT 永远不会被执行
iptables -A INPUT -j DROP # ← 所有包都被丢弃
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # ← 这条规则永远到不了
# 正确示例:具体规则在前,默认拒绝在后
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # 最快路径
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT # HTTP
iptables -A INPUT -j DROP # 最后拒绝所有
3.5 链的默认策略(Policy)
每个内置链都有一个默认策略,当数据包走到链末尾仍未匹配任何规则时执行:
# 设置默认策略
iptables -P INPUT DROP # INPUT 链默认丢弃
iptables -P FORWARD DROP # FORWARD 链默认丢弃
iptables -P OUTPUT ACCEPT # OUTPUT 链默认放行
注意事项:
- 默认策略只能是
ACCEPT或DROP,不能是REJECT(REJECT 需要生成 ICMP 响应,这必须通过匹配规则来实现) - 如果远程通过 SSH 管理服务器,在设置
iptables -P INPUT DROP之前,务必先添加允许 SSH 的规则,否则会将自己锁在外面
四、常用匹配模块
iptables 通过**模块化匹配扩展(match extensions)**提供丰富的匹配能力。使用 -m 参数加载匹配模块。
4.1 conntrack(连接跟踪匹配)
conntrack 是 state 模块的现代替代品,提供更精确的连接状态匹配:
# 基本状态匹配
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# 按方向匹配
iptables -A INPUT -m conntrack --ctdir ORIGINAL -j ACCEPT # 原始方向
iptables -A INPUT -m conntrack --ctdir REPLY -j ACCEPT # 回复方向
| 特性 | state 模块(遗留) | conntrack 模块(推荐) |
|---|---|---|
| INVALID 原因 | 不区分 | 可匹配具体原因(--ctstatus) |
| 方向感知 | 无 | 支持 ORIGINAL/REPLY |
| 状态数 | 4 种 | 5 种(多了 UNTRACKED) |
4.2 tcp(TCP 协议匹配)
# 基本端口匹配
iptables -A INPUT -p tcp --dport 80 -j ACCEPT # 目标端口 80
iptables -A INPUT -p tcp --sport 1024:65535 -j ACCEPT # 源端口范围
iptables -A INPUT -p tcp --dport 80:90 -j ACCEPT # 目标端口范围 80-90
# TCP 标志位匹配(高级过滤)
iptables -A INPUT -p tcp --tcp-flags SYN,RST,ACK SYN -j ACCEPT # 仅 SYN 标志(新连接请求)
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP # 空标志包(扫描探测)
iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP # SYN+FIN 组合(可疑扫描)
iptables -A INPUT -p tcp --tcp-flags ALL SYN,ACK -j ACCEPT # SYN+ACK(服务器响应)
iptables -A INPUT -p tcp --tcp-flags ALL RST -j ACCEPT # RST(连接重置)
4.3 udp(UDP 协议匹配)
iptables -A INPUT -p udp --dport 53 -j ACCEPT # DNS 端口
iptables -A INPUT -p udp --sport 123 -j ACCEPT # NTP 端口
iptables -A INPUT -p udp --dport 67:68 -j ACCEPT # DHCP 端口范围
4.4 multiport(多端口匹配)
当需要匹配多个不连续端口时,multiport 比写多条规则更高效:
# 匹配多个目标端口(一条规则替代多条)
iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT
# 端口范围组合
iptables -A INPUT -p tcp -m multiport --dports 20:22,80,443,8080:8090 -j ACCEPT
# 最多可指定 15 个端口(可通过 net.netfilter.nf_conntrack_max 调整)
4.5 limit(速率限制匹配)
limit 模块使用令牌桶算法限制数据包匹配速率,是防御 DoS 攻击的重要工具:
# 令牌桶参数:--limit 速率 --limit-burst 桶容量
iptables -A INPUT -p tcp --dport 22 \
-m limit --limit 3/minute --limit-burst 5 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
输出解读:
--limit 3/minute:每分钟允许 3 个新连接(每 20 秒生成 1 个令牌)--limit-burst 5:初始桶中有 5 个令牌(允许初始突发 5 个连接)- 第 6 个连接起被 DROP(桶已空,令牌补充速度只有 3/min)
速率单位: /second、/minute、/hour、/day
# 防 ping 洪水
iptables -A INPUT -p icmp --icmp-type echo-request \
-m limit --limit 1/second --limit-burst 5 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
4.6 recent(最近访问记录)
recent 模块基于源 IP 维护动态访问记录,实现智能限速(防暴力破解专用):
# SSH 暴力破解防护 —— 60 秒内尝试超过 3 次的新连接一律拒绝
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --set --name SSH # 记录每一次新连接
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP # 第 4 次起拒绝
输出解读:
--set:将当前源 IP 记录到名为 SSH 的列表中--update:更新该 IP 的最后出现时间,同时检查命中次数--seconds 60:仅查看过去 60 秒内的记录--hitcount 4:60 秒内第 4 次命中时执行 DROP
4.7 其他常用匹配模块速查
| 模块 | 用途 | 示例 |
|---|---|---|
iprange | 匹配 IP 范围(比 CIDR 更灵活) | -m iprange --src-range 192.168.1.100-192.168.1.200 |
mac | 匹配源 MAC 地址 | -m mac --mac-source 00:11:22:33:44:55 |
owner | 匹配进程 UID/GID | -m owner --uid-owner 1000 |
time | 按时间范围匹配 | -m time --timestart 09:00 --timestop 18:00 |
string | 匹配数据包载荷内容 | -m string --string "cmd.exe" --algo bm |
comment | 为规则添加注释 | -m comment --comment "允许 SSH" |
connlimit | 限制每 IP 并发连接数 | -m connlimit --connlimit-above 10 -j REJECT |
hashlimit | 基于哈希的精确限速 | -m hashlimit --hashlimit-name mylimit --hashlimit-above 10/sec |
tos | 匹配 TOS/DSCP 字段 | -m tos --tos 0x10 |
ttl | 匹配 TTL 值 | -m ttl --ttl-lt 64 |
五、常用目标(Target)
目标(Target)是匹配成功后执行的动作,分为终结性和非终结性两种。
5.1 终结性目标(执行后停止当前链处理)
ACCEPT —— 放行
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 允许数据包通过当前链,继续协议栈的下一个处理阶段
DROP —— 静默丢弃
iptables -A INPUT -s 203.0.113.50 -j DROP
# 丢弃数据包,不给发送方任何回应
# 优点:攻击者无法判断目标是否存在(不暴露端口)
# 缺点:合法访问超时较长(等待 TCP 重传超时,通常 30-120 秒)
REJECT —— 拒绝并回应
iptables -A INPUT -j REJECT # 默认 ICMP port unreachable
iptables -A INPUT -j REJECT --reject-with icmp-host-unreachable
iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset # TCP RST(推荐)
# 优点:合法客户端快速收到拒绝通知(TCP RST 立即返回)
# 缺点:暴露主机存在的事实
DROP vs REJECT 选择建议:
| 场景 | 推荐 | 理由 |
|---|---|---|
| WAN/公网接口 | DROP | 隐藏服务存在,降低被扫描识别的风险 |
| LAN/内网接口 | REJECT | 快速告知客户端连接被拒绝,改善用户体验 |
| 针对已知攻击 IP | DROP | 不给攻击者任何反馈 |
SNAT —— 静态源地址转换
# 固定单个公网 IP
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.10
# IP 范围(轮询分配)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 \
-j SNAT --to-source 203.0.113.10-203.0.113.20
# 适用场景:有固定公网 IP 的企业网络
MASQUERADE —— 动态源地址转换
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
# 自动使用出口网卡的当前 IP 地址
# 适用场景:PPPoE 拨号、DHCP 动态 IP 的家用路由器
# 网卡 IP 变化时自动适应,无需手动更新规则
DNAT —— 目标地址转换
# 单端口映射
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80
# IP 范围(轮询,实现简单负载均衡)
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-j DNAT --to-destination 192.168.1.100-192.168.1.110
REDIRECT —— 端口重定向
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 3128
# 是 DNAT 的特化版本,只能重定向到本机
# 适用场景:透明代理(如 Squid)
5.2 非终结性目标(执行后继续匹配后续规则)
LOG —— 日志记录
iptables -A INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4
# 日志写入 /var/log/kern.log(或通过 rsyslog/journald 配置)
# 注意:LOG 后会继续匹配后续规则,需要配合终结性目标
常用 LOG 选项:
--log-prefix "前缀":日志前缀,最长 29 字符--log-level 0-7:日志级别(默认 4=warning)--log-tcp-sequence:记录 TCP 序列号--log-tcp-options:记录 TCP 选项--log-ip-options:记录 IP 选项
MARK —— 数据包标记
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
# 标记存储在 sk_buff 结构中,仅内核可见
# 配合 ip rule 和路由表实现策略路由
RETURN —— 返回调用链
# 在自定义链中:返回调用链继续执行下一条规则
# 在内置链中:执行该链的默认策略
iptables -A MY_CHAIN -s 192.168.1.0/24 -j RETURN
5.3 用户自定义链
# 创建自定义链
iptables -N MY_RULES
# 向自定义链添加规则
iptables -A MY_RULES -s 192.168.1.0/24 -j ACCEPT
iptables -A MY_RULES -j DROP
# 从内置链跳转到自定义链(类似函数调用)
iptables -A INPUT -j MY_RULES
# 删除自定义链(需先清空和移除所有引用)
iptables -F MY_RULES # 清空链
iptables -X MY_RULES # 删除链
六、iptables-save/restore 持久化
6.1 为什么需要持久化
iptables 规则存储在内核内存中,系统重启后所有规则丢失。必须通过持久化机制将规则保存到磁盘,系统启动时自动加载。
6.2 iptables-save —— 导出规则
# 导出所有表的规则
iptables-save
# 导出指定表
iptables-save -t filter
iptables-save -t nat
# 导出到文件
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
输出格式:
# Generated by iptables-save v1.8.7
*filter # 表名
:INPUT DROP [23:2156] # 链名 默认策略 [包计数:字节计数]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [156:18234]
-A INPUT -i lo -j ACCEPT # 规则(-A 追加)
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
COMMIT # 提交
*nat
:PREROUTING ACCEPT [0:0]
...
COMMIT
# Completed
6.3 iptables-restore —— 恢复规则
# 从文件恢复规则(默认刷新现有规则)
iptables-restore < /etc/iptables/rules.v4
# 不刷新现有规则(追加模式)
iptables-restore --noflush < /etc/iptables/rules.v4
# 测试语法(不实际加载)
iptables-restore --test < /etc/iptables/rules.v4
6.4 持久化方案对比
| 方案 | 适用发行版 | 配置文件位置 |
|---|---|---|
iptables-persistent 包 | Debian/Ubuntu | /etc/iptables/rules.v4 + rules.v6 |
iptables-services 包 | RHEL/CentOS 7 | /etc/sysconfig/iptables |
| systemd 自定义服务 | 通用 | 自行创建 service 文件 |
netfilter-persistent | 较新 Debian/Ubuntu | iptables-persistent 的现代替代 |
6.5 systemd 持久化示例
# /etc/systemd/system/iptables-restore.service
[Unit]
Description=Restore iptables firewall rules
Before=network-pre.target
Wants=network-pre.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables/rules.v4
ExecStart=/sbin/ip6tables-restore /etc/iptables/rules.v6
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
# 启用
systemctl enable iptables-restore.service
systemctl start iptables-restore.service
6.6 保存前检查规则的最佳实践
# 1. 查看当前规则(带行号)
iptables -L -n -v --line-numbers
# 2. 导出备份(带时间戳)
iptables-save > /etc/iptables/rules.v4.$(date +%Y%m%d_%H%M%S).bak
# 3. 原子加载新规则
iptables-restore < /etc/iptables/rules.v4
# 4. 验证新规则生效
iptables -L -n
# 5. 回滚(如果出错)
iptables-restore < /etc/iptables/rules.v4.YYYYMMDD_HHMMSS.bak
七、适用场景与注意事项
适用场景
| 场景 | 说明 |
|---|---|
| 传统服务器(通用 Linux) | iptables 适用所有 Linux 发行版,兼容性最好 |
| Docker/K8s 宿主机 | Docker 直接操作 iptables,天然兼容 |
| NAT 网关/路由器 | iptables DNAT/SNAT/MASQUERADE 功能成熟稳定 |
| 嵌入式低版本内核 | 内核 >= 2.4 即可,依赖最少 |
| Fail2ban 联动 | Fail2ban 默认使用 iptables 封禁 IP |
| 学习目的 | 理解 iptables 是理解所有 Linux 防火墙的基础 |
注意事项
- 规则顺序至关重要:ESTABLISHED 规则必须放在最前面,DROP 必须放在最后
- 远程操作风险:
iptables -P INPUT DROP之前务必添加允许 SSH 的规则 - 重启丢失规则:iptables 规则存储在内存中,必须通过 iptables-persistent 等工具持久化
- 逐步淘汰趋势:RHEL 8+ / Debian 10+ 已默认推荐 nftables,iptables 进入维护模式
- 与 nftables 混用的冲突:iptables 和 nftables 同时操作 netfilter Hook 点时可能产生意料之外的交互
常用速查命令
# 查看规则
iptables -L -n -v # 查看 filter 表(默认)
iptables -t nat -L -n -v # 查看 nat 表
iptables -L -n -v --line-numbers # 带行号
iptables -S # 查看可执行的规则列表
# 管理规则
iptables -A INPUT ... -j ACCEPT # 追加到链末尾
iptables -I INPUT 1 ... -j ACCEPT # 插入到链开头(位置 1)
iptables -D INPUT 3 # 按行号删除
iptables -D INPUT ... -j ACCEPT # 按规则内容删除
iptables -F INPUT # 清空链
iptables -Z # 清零计数器
# 默认策略
iptables -P INPUT DROP # 设置默认策略
iptables -P INPUT ACCEPT # 恢复默认放行
下一步:03 — nftables 详解
03 — nftables 详解
nftables 是 Linux 内核 netfilter 框架的下一代包过滤子系统,旨在彻底替代 {ip,ip6,arp,eb}tables。它提供了统一的配置语法、更高的性能和更灵活的规则管理能力。
一、nftables vs iptables 架构差异
1.1 iptables 的架构缺陷
iptables 从 2001 年伴随 Linux 2.4 发布后,逐渐暴露出以下架构性问题:
| 问题 | 详细说明 |
|---|---|
| 代码重复 | IPv4 (iptables)、IPv6 (ip6tables)、ARP (arptables)、以太网桥 (ebtables) 各有独立的内核模块和用户空间工具,大量代码重复 |
| 规则膨胀 | 表面一条规则(如 "允许 80 端口"),内核中实际复制为多条内部规则,检查每个可能的协议族和扩展组合 |
| 性能退化 | 每条规则都需要遍历内核模块链表,规则越多性能越差(O(n) 线性查找) |
| 缺乏原子性 | 规则是逐条添加/删除的,中间状态可能产生安全空窗期 |
| 难以调试 | 用户空间的 iptables 命令和内核中的实际规则表示差异巨大,难以追踪 |
1.2 nftables 的架构革新
nftables 在 2014 年随 Linux 3.13 内核引入,从零开始重新设计:
┌──────────────────────────────────────────────────────────────────┐
│ 用户空间 (nft CLI) │
│ │
│ nft list ruleset nft -f ruleset.nft nft add rule │
│ (查看规则) (加载规则文件) (添加单条规则) │
└──────────────────────────────────┬───────────────────────────────┘
│ netlink (NFNL_SUBSYS_NFTABLES)
┌──────────────────────────────────▼───────────────────────────────┐
│ 内核空间 (nf_tables) │
│ │
│ ┌────────────────┐ ┌─────────────────┐ ┌───────────────────┐ │
│ │ 表达式解析器 │ │ 规则编译器 │ │ JIT 字节码引擎 │ │
│ │ (parser) │ │ (compiler) │ │ (jit engine) │ │
│ └───────┬────────┘ └────────┬────────┘ └─────────┬─────────┘ │
│ │ │ │ │
│ └─────────────────────┼────────────────────────┘ │
│ ▼ │
│ ┌────────────────────┐ │
│ │ 统一数据包匹配引擎 │ │
│ │ (generic packet │ │
│ │ matching engine) │ │
│ └────────────────────┘ │
│ │ │
│ ┌─────────────────────┼───────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ IPv4 匹配 │ │ IPv6 匹配 │ │ ARP/网桥匹配 │ │
│ │ (单一模块) │ │ (单一模块) │ │ (单一模块) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 集合查找 O(1) │ │ 映射查找 O(1) │ │ 连接跟踪 │ │
│ │ (hash/rbtree)│ │ (hash/rbtree)│ │ (conntrack) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────────────────────────────────────────────────────┘
1.3 核心差异对比表
| 维度 | iptables (xtables) | nftables |
|---|---|---|
| 协议族处理 | 4 个独立工具(iptables/ip6tables/arptables/ebtables) | 单一 nft 命令,通过 family 区分 |
| 表/链结构 | 固定四表五链,不可自定义 | 完全可自定义的表和链 |
| 规则存储 | 二进制 blob,每个匹配扩展独立 | 高级抽象语法树(AST),编译为统一字节码 |
| 匹配执行 | 遍历内核模块链表(逐模块调用) | 内联 JIT 编译后的字节码(接近原生代码速度) |
| 规则查找 | O(n) 线性遍历 | 支持 O(1) 集合/映射查找 |
| 规则更新 | 逐条操作,非原子 | 事务性原子更新 |
| 规则膨胀 | 1 条用户规则 → 内核中多条规则 | 1 条用户规则 → 1 条编译规则 |
| 动态规则 | 不支持 | 支持(运行时添加/删除,无需刷新) |
| IPv4/IPv6 | 分开管理 | inet family 统一处理双栈 |
| 代码量 | ~30000 行(内核)+ 4 个独立工具 | ~10000 行(内核)+ 1 个统一工具 |
1.4 性能优势来源
- JIT 编译:将规则编译为 BPF(Berkeley Packet Filter)字节码,内核直接执行
- 集合查找:使用哈希表或红黑树,将 O(n) 规则遍历优化为 O(1) 集合查找
- 内联执行:匹配指令被编译为内联代码,减少函数调用开销
- 规则压缩:一条 nftables 规则可以等效替代多条 iptables 规则
性能基准参考(100 条规则,简单匹配场景):
| 指标 | iptables | nftables |
|---|---|---|
| 规则加载时间 | ~50ms | ~5ms |
| 吞吐量(64 字节包) | ~800K pps | ~1.2M pps |
| 规则集内存占用 | ~120KB | ~30KB |
| 原子更新耗时 | 逐条操作,不可原子化 | ~1ms(单次事务提交) |
二、核心概念:Table / Family / Chain / Rule / Set / Map
2.1 Family(协议族)
nftables 中 family 决定了规则作用于哪个协议栈:
| Family | 说明 | 对应 iptables 工具 |
|---|---|---|
ip | IPv4 协议栈 | iptables |
ip6 | IPv6 协议栈 | ip6tables |
inet | 统一的 IPv4+IPv6 协议栈(推荐) | iptables + ip6tables 两套规则 |
arp | ARP 协议栈 | arptables |
bridge | 以太网桥接 | ebtables |
netdev | 设备级(Ingress 钩子,早于协议栈) | 无(nftables 独有) |
inet family 的优势: 一条规则同时处理 IPv4 和 IPv6 流量,无需维护两套相同策略的规则集,减少 50% 的维护工作。
2.2 Table(表)
Table 是规则的容器,在 nftables 中可以任意命名(不像 iptables 固定的四表):
# 创建自定义名称的表
nft add table inet my_firewall
nft add table ip my_nat_rules
# 删除表(级联删除表中所有链和规则)
nft delete table inet my_firewall
# 列出所有表
nft list tables
社区惯例: 虽然表名可任意命名,但通常遵循 iptables 的习惯使用 filter、nat、mangle 等名称。
2.3 Chain(链)
Chain 定义了数据包的处理路径,绑定到特定的 Hook 点:
# 语法
nft add chain [family] [table] [chain] \
{ type [type] hook [hook] priority [priority] ; policy [policy] ; }
# 参数说明:
# type: filter(过滤), nat(地址转换), route(路由)
# hook: prerouting, input, forward, output, postrouting, ingress
# priority: 数值,越小越优先(可为负值)
# policy: accept(默认放行), drop(默认丢弃)
# 示例
nft add chain inet my_filter input_chain \
{ type filter hook input priority 0; policy drop; }
优先级参考表:
| 优先级值 | 用途 | 对应 iptables 表 |
|---|---|---|
| -300 | 原始包过滤(conntrack 之前) | raw |
| -150 | 连接跟踪修改 | conntrack |
| 0 | 标准过滤 | filter |
| 100 | DNAT | nat(PREROUTING) |
| 100 | SNAT/MASQUERADE | nat(POSTROUTING) |
| 300 | 路由后处理 | 无直接对应 |
2.4 Rule(规则)
Rule 是链中的最小执行单元,由匹配条件和动作组成:
规则结构:
[匹配条件1] [匹配条件2] ... [动作]
匹配条件可以自然串联(逻辑与):
ip saddr 192.168.1.0/24 tcp dport 22 ct state new accept
= 匹配来自 192.168.1.0/24 网段、目标端口 22、状态为 NEW 的 TCP 包 → 放行
2.5 Set(集合)—— O(1) 高效查找原理
集合是 nftables 最强大的特性之一。它将多个离散值分组在一起,内部使用哈希表或红黑树存储,支持 O(1) 高效查找:
iptables 的线性匹配(O(n)):
数据包到达 → 检查规则1(不匹配)→ 规则2(不匹配)→ ... → 规则100(匹配!)
最坏情况:100 次检查
nftables 的集合查找(O(1)):
数据包到达 → 提取目标端口 → 哈希查找 → 一次命中/未命中
无论集合中有多少个端口,查找时间恒定
集合使用示例:
# 匿名集合(临时,无法在其他规则中引用)
nft add rule inet filter input ip saddr { 10.0.0.1, 10.0.0.2, 10.0.0.3 } accept
# 命名集合(可复用)
nft add set inet filter allowed_ports { type inet_service; }
nft add element inet filter allowed_ports { 22, 80, 443, 8080 }
# 在规则中使用命名集合
nft add rule inet filter input tcp dport @allowed_ports accept
集合内部存储方式:
| 存储方式 | 适用场景 | 查找复杂度 | 示例 |
|---|---|---|---|
| 哈希表(默认) | 离散值,无固定顺序 | O(1) | { 22, 80, 443 } |
| 红黑树 | 需要范围查找或前缀匹配 | O(log n) | { 10.0.0.0/8, 172.16.0.0/12 } |
| 间隔树 | IP 地址段重叠匹配 | O(log n) | { 192.168.1.100-192.168.1.200 } |
# 指定存储方式
nft add set inet filter ssh_blocklist \
{ type ipv4_addr; flags interval; }
nft add element inet filter ssh_blocklist \
{ 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
性能对比 —— 假设匹配 100 个源 IP:
| 方案 | 规则数 | 最坏匹配次数 | 内存占用 |
|---|---|---|---|
| iptables(逐条) | 100 条 | 100 次 | ~12KB |
| nftables(集合) | 1 条 + 1 个集合 | 1 次(哈希) | ~3KB |
2.6 Map(映射)
Map 是键值对形式的字典结构,将输入值映射到输出动作或目标值:
# 定义映射:端口 → 动作
nft add map inet filter port_to_action \
{ type inet_service: verdict; }
nft add element inet filter port_to_action \
{ 22: accept, 80: accept, 443: accept }
# 在规则中使用映射
nft add rule inet filter input tcp dport vmap @port_to_action
DNAT 映射示例(一条规则替代多条 iptables DNAT 规则):
nft add map inet nat dnat_map \
{ type inet_service: ipv4_addr . inet_service; }
nft add element inet nat dnat_map {
8080: 192.168.1.100 . 80,
2222: 192.168.1.50 . 22,
8443: 192.168.1.200 . 443
}
nft add rule inet nat prerouting dnat to tcp dport map @dnat_map
输出解读: 一条规则完成了三个端口的 DNAT 映射(8080→192.168.1.100:80、2222→192.168.1.50:22、8443→192.168.1.200:443),如果用 iptables 需要 3 条 -j DNAT 规则。
三、nft 语法规则
3.1 语法对照表(iptables → nftables)
| 场景 | iptables 命令 | nftables 命令 |
|---|---|---|
| 列出规则 | iptables -L -n -v | nft list ruleset |
| 列出特定表 | iptables -t filter -L | nft list table inet filter |
| 设置默认策略 | iptables -P INPUT DROP | 在 chain 定义中 policy drop |
| 允许 loopback | iptables -A INPUT -i lo -j ACCEPT | nft add rule inet filter input iif lo accept |
| 允许已建立连接 | iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT | nft add rule inet filter input ct state established,related accept |
| 允许端口 | iptables -A INPUT -p tcp --dport 22 -j ACCEPT | nft add rule inet filter input tcp dport 22 accept |
| 允许多端口 | iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT | nft add rule inet filter input tcp dport {22,80,443} accept |
| 拒绝并重置 | iptables -A INPUT -j REJECT --reject-with tcp-reset | nft add rule inet filter input reject with tcp reset |
| DNAT | iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 | nft add rule inet nat prerouting tcp dport 8080 dnat to 192.168.1.100:80 |
| SNAT | iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.10 | nft add rule inet nat postrouting ip saddr 192.168.1.0/24 oif eth0 snat to 203.0.113.10 |
| MASQUERADE | iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE | nft add rule inet nat postrouting ip saddr 192.168.1.0/24 oif eth0 masquerade |
| 限速 | iptables -A INPUT -p tcp --dport 22 -m limit --limit 3/minute -j ACCEPT | nft add rule inet filter input tcp dport 22 limit rate 3/minute accept |
| 日志 | iptables -A INPUT -j LOG --log-prefix "DROP: " | nft add rule inet filter input log prefix "DROP: " |
| IP 范围 | iptables -A INPUT -m iprange --src-range 10.0.0.1-10.0.0.100 -j ACCEPT | nft add rule inet filter input ip saddr 10.0.0.1-10.0.0.100 accept |
| 保存规则 | iptables-save > rules.v4 | nft list ruleset > rules.nft |
| 恢复规则 | iptables-restore < rules.v4 | nft -f rules.nft |
| 刷新规则 | iptables -F | nft flush ruleset |
| 删除单条 | iptables -D INPUT 3 | nft delete rule inet filter input handle 5 |
3.2 表达式链式组合
nftables 语法允许条件自然地串联,无需像 iptables 那样使用多个 -m 参数:
# iptables: 需要多个 -m 参数
iptables -A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
# nftables: 自然顺序书写
nft add rule inet filter input tcp dport 22 ct state new ...
3.3 声明式配置文件格式
nftables 支持声明式配置文件,与 nft list ruleset 输出一致,便于版本管理:
#!/usr/sbin/nft -f
# 清空现有规则
flush ruleset
# 定义表
table inet filter {
# 定义集合(端口白名单)
set allowed_ports {
type inet_service
elements = { 22, 80, 443, 8080 }
}
# 定义 IP 黑名单(使用间隔树存储)
set banned_ips {
type ipv4_addr
flags interval
elements = { 10.0.0.0/8, 172.16.0.0/12 }
}
# 定义链
chain input {
type filter hook input priority 0; policy drop;
# loopback 无条件放行
iif lo accept
# 已建立连接快速放行
ct state established,related accept
# 黑名单直接丢弃
ip saddr @banned_ips drop
# 使用集合开放端口
tcp dport @allowed_ports ct state new accept
# 日志记录(记录丢弃的包)
log prefix "nft-input-drop: " counter drop
}
}
四、原子规则更新机制
4.1 原子更新的意义
在 iptables 中,添加或删除规则是逐条操作的,中间状态可能产生安全空窗期:
# 危险操作序列!
iptables -D INPUT 3 # 删除了一条负载均衡规则
iptables -I INPUT 3 ... # 在新规则插入之前,存在短暂的安全空窗期
# ↑—— 在这两个命令之间,合法流量可能被误拦,攻击流量可能被放行
nftables 通过 nft -f 将整个规则集作为一个原子事务提交:
# 所有变更在单个事务中原子提交
nft -f new_ruleset.nft
# 新规则集要么完全生效,要么完全不生效,不存在中间状态
4.2 原子更新的实现方式
用户空间: 编写完整规则文件
│
▼
nft -f rules.nft
│
▼ (netlink 通信)
内核空间: 接收完整规则集
│
▼
解析、验证所有规则
│
▼
┌─ 全部有效?──┐
│ │
▼ 是 ▼ 否
生成新规则集 回滚(原规则集不变)
│
▼
原子替换指针
(RCU 机制:读取者不受影响)
│
▼
新规则立即生效
旧规则延迟回收(RCU grace period)
4.3 原子更新的安全优势
| 优势 | 说明 |
|---|---|
| 零空窗期 | 新旧规则切换是瞬时指针替换 |
| 全有或全无 | 规则文件中有任何语法错误,整个事务回滚 |
| RCU 保护 | Read-Copy-Update 机制保护正在处理的数据包不受影响 |
| 可回滚 | 保存旧规则集,随时可以恢复 |
五、从 iptables 迁移指南
5.1 官方翻译工具
nftables 提供了 iptables-translate 工具,将 iptables 命令翻译为等价的 nftables 命令:
# 翻译单条规则
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# 输出: nft add rule ip filter INPUT tcp dport 22 counter accept
# 翻译 NAT 规则
iptables-translate -t nat -A PREROUTING -p tcp --dport 8080 \
-j DNAT --to-destination 192.168.1.100:80
# 输出: nft add rule ip nat PREROUTING tcp dport 8080 dnat to 192.168.1.100:80
# 批量翻译规则集
iptables-save | sed 's/^\[.*\]//' | iptables-restore-translate -f -
5.2 迁移步骤
步骤 1: 审计现有 iptables 规则
├── iptables-save > current_rules.v4
├── ip6tables-save > current_rules.v6
└── 记录所有自定义脚本
步骤 2: 翻译规则
├── iptables-restore-translate -f current_rules.v4 > translated.nft
├── ip6tables-restore-translate -f current_rules.v6 >> translated.nft
└── 检查翻译结果,手动优化
步骤 3: 优化规则结构
├── 将离散规则合并为集合/映射
├── 使用 inet family 统一 IPv4/IPv6
└── 添加注释和文档
步骤 4: 测试环境验证
├── 在测试机器加载: nft -f translated.nft
├── 验证服务可达性
└── 对比 iptables 和 nftables 规则效果
步骤 5: 生产环境切换
├── 备份当前 iptables 规则
├── 计划维护窗口
├── 停止 iptables 服务
├── 加载 nftables 规则: nft -f rules.nft
└── 启用 nftables 服务: systemctl enable nftables
步骤 6: 持久化配置
├── 规则文件: /etc/nftables.conf (Debian/Ubuntu)
├── 或 /etc/sysconfig/nftables.conf (RHEL/Fedora)
└── systemctl enable nftables
5.3 兼容性注意事项
| 注意事项 | 说明 |
|---|---|
| Docker 冲突 | Docker 仍使用 iptables,与 nftables 混用可能导致规则混乱 |
| Fail2ban | 旧版 Fail2ban 使用 iptables,需升级或配置 nftables 后端 |
| Kubernetes | kube-proxy 默认使用 iptables,切换到 nftables 模式需验证 |
| Libvirt | 虚拟机网络默认使用 iptables,需确认兼容性 |
| 内核版本 | 推荐 >= 4.9(部分高级特性需要 >= 5.x) |
5.4 共存策略
如果暂时无法完全切换到 nftables:
# 策略 1: iptables 为主,nftables 处理特殊需求
# 注意:iptables 先于 nftables 执行(默认 priority 均为 0)
# 策略 2: nftables 为主,iptables 仅用于兼容 Docker
# 使用 nftables 的 iptables 兼容层(内核选项 NF_TABLES_IPV4/IPV6)
# 策略 3: 分阶段替换
# ① 先替换 INPUT/OUTPUT 链 → nftables
# ② 再替换 NAT 规则 → nftables
# ③ 最后替换 FORWARD 链 → nftables
六、适用场景与注意事项
适用场景
| 场景 | 说明 |
|---|---|
| 高性能环境 | nftables 是性能最优的 Linux 防火墙方案 |
| 大型规则集 | 集合/映射将 O(n) 查找降为 O(1),大规模规则场景优势显著 |
| 双栈网络 | inet family 一条规则搞定 IPv4+IPv6 |
| 安全合规 | 原子更新消除规则变更期间的安全空窗期 |
| RHEL 8+ / Debian 10+ | 新一代发行版的默认推荐方案 |
| 从 iptables 迁移 | 官方提供 iptables-translate 翻译工具 |
注意事项
- Docker 兼容性:Docker 仍使用 iptables 管理容器网络,与 nftables 混用时需配置正确的后端和优先级
- 旧版工具兼容:Fail2ban、kube-proxy、Libvirt 等工具默认依赖 iptables
- 内核版本要求:推荐 >= 4.9(3.13 基本可用,但部分高级特性缺失)
- 学习成本:从 iptables 迁移需要学习新的语法体系(但更直观)
- 文件持久化路径因发行版而异:Debian/Ubuntu 用
/etc/nftables.conf,RHEL 用/etc/sysconfig/nftables.conf
04 — firewalld 详解
firewalld 是 RHEL/CentOS/Fedora 系列发行版默认的防火墙管理工具,提供基于 Zone(区域)和 Service(服务)的动态防火墙管理框架。与 iptables 直接操作底层规则不同,firewalld 通过抽象层为管理员提供更直观、更安全的配置方式。
一、Zone 信任级别模型
1.1 设计理念
firewalld 的核心设计理念是:网络信任级别决定防火墙策略。基于这一理念,firewalld 引入了 Zone 概念:
- 每个 Zone 代表一个网络信任级别
- 网络接口绑定到某个 Zone 后,自动继承该 Zone 的所有规则
- 切换网络环境时,只需更改接口的 Zone 绑定,无需逐条修改规则
┌───────────────────────────────────────────────────────────────┐
│ firewalld │
│ │
│ Zone: public (默认) Zone: internal │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Interface: eth0 │ │ Interface: eth1 │ │
│ │ ────────────────── │ │ ────────────────── │ │
│ │ Service: ssh │ │ Service: samba │ │
│ │ Service: dhcpv6 │ │ Service: mdns │ │
│ │ Port: 80/tcp │ │ Service: ssh │ │
│ │ Port: 443/tcp │ │ Port: 8080/tcp │ │
│ │ Masquerade: no │ │ Masquerade: no │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ Zone: dmz Zone: drop │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Interface: eth2 │ │ (无接口绑定) │ │
│ │ ────────────────── │ │ │ │
│ │ Service: http │ │ 所有入站流量丢弃 │ │
│ │ Service: https │ │ 无任何回应 │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 后端引擎 │ │
│ │ iptables (RHEL 7) / nftables (RHEL 8+) │ │
│ └───────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
1.2 Zone 工作原理
数据包到达
│
▼
┌─────────────────────────────────────┐
│ 1. 检查源地址绑定 │ ← 最高优先级
│ (Source-based zone binding) │
│ 例: 来源 192.168.1.0/24 → internal│
├─────────────────────────────────────┤
│ 2. 检查接口绑定 │ ← 次优先级
│ (Interface-based zone binding) │
│ 例: eth0 → public │
├─────────────────────────────────────┤
│ 3. 使用默认 Zone │ ← 最低优先级
│ (Default zone) │
│ 例: 默认 = public │
└─────────────────────────────────────┘
│
▼
应用该 Zone 的全部规则
1.3 Zone 信任等级总览
| Zone | 信任级别 | 默认行为 | 适用场景 | 默认允许的服务 |
|---|---|---|---|---|
| trusted | 最高 | 接受所有入站连接 | 完全信任的网络(家庭内网) | 所有 |
| home | 高 | 拒绝入站,仅允许特定服务 | 家庭网络 | ssh, mdns, ipp-client, samba-client, dhcpv6-client |
| internal | 中高 | 拒绝入站,仅允许特定服务 | 内部网络(办公室 LAN) | ssh, mdns, ipp-client, samba-client, dhcpv6-client |
| work | 中等 | 拒绝入站,仅允许特定服务 | 工作网络 | ssh, dhcpv6-client, ipp-client |
| public | 中低(默认) | 拒绝所有入站 | 公共网络(咖啡厅 WiFi、数据中心) | ssh, dhcpv6-client |
| dmz | 低 | 拒绝入站,仅允许特定服务 | DMZ 隔离区(对外服务) | ssh |
| external | 低 | 拒绝入站,开启伪装 | 作为 NAT 网关的外网接口 | ssh(masquerade 开启) |
| block | 极低 | 拒绝所有入站(ICMP 拒绝) | 极度不信任的网络 | 无 |
| drop | 最低 | 丢弃所有入站(无回应) | 攻击场景/最高安全要求 | 无 |
1.4 Zone 用途选择指南
你的网络环境是什么?
┌─ 家庭网络 ─────────────→ 使用 home
├─ 办公室/公司内网 ──────→ 使用 internal
├─ 咖啡厅/机场 ──────────→ 使用 public (默认)
├─ 对外提供服务的服务器 ──→ 使用 dmz
├─ 作为 NAT 网关的外网口 ─→ 使用 external
├─ 遭到攻击时的应急防护 ─→ 切换到 drop
└─ 完全控制的隔离环境 ────→ 使用 trusted
1.5 查看和切换 Zone
# 查看当前默认 Zone
firewall-cmd --get-default-zone
# 查看所有 Zone
firewall-cmd --get-zones
# 查看 Zone 详细信息
firewall-cmd --zone=public --list-all
# 查看所有活跃 Zone
firewall-cmd --get-active-zones
# 查看接口所属 Zone
firewall-cmd --get-zone-of-interface=eth0
# 切换默认 Zone
firewall-cmd --set-default-zone=dmz
# 将接口绑定到指定 Zone
firewall-cmd --zone=internal --add-interface=eth1 # 运行时
firewall-cmd --zone=internal --add-interface=eth1 --permanent # 永久
二、运行时配置 vs 永久配置
2.1 双重配置模式
firewalld 最显著的特性之一是运行时配置和永久配置的完全分离:
┌─────────────────┐ --permanent ┌─────────────────┐
│ 运行时配置 │ ◄────────────────── │ 永久配置 │
│ (内存存储) │ ──────────────────► │ (磁盘存储) │
│ │ --runtime-to- │ │
│ 立即生效 │ permanent │ 需 reload │
│ │ │ 才能生效 │
│ 测试新规则 │ │ 持久化保存 │
│ │ │ │
│ ┌──────────┐ │ │ │
│ │ 规则 A │ │ │ │
│ │ 规则 B │ │ │ │
│ └──────────┘ │ │ │
│ │ │ │ │
│ │ 重启 │ │ │
│ ▼ │ │ │
│ 规则全部丢失! │ │ │
└─────────────────┘ └─────────────────┘
| 特性 | 运行时配置 | 永久配置 |
|---|---|---|
| 存储位置 | 内存 | 磁盘(/etc/firewalld/) |
| 生效时机 | 立即生效 | reload 后生效 |
| 生命周期 | 重启后丢失 | 永久保留 |
| 修改命令 | firewall-cmd [操作] | firewall-cmd [操作] --permanent |
| 安全测试 | 可以大胆试验 | 需要 reload 才能生效 |
2.2 安全工作流最佳实践
# 场景:需要开放一个新的 Web 服务端口 8080
# 步骤 1: 仅修改运行时,立即测试
firewall-cmd --zone=public --add-port=8080/tcp
# 步骤 2: 从外部测试端口可达性
curl -I http://server-ip:8080
# 步骤 3a: 测试成功 —— 持久化变更
firewall-cmd --runtime-to-permanent
# 步骤 3b: 测试失败 —— 直接重载恢复
firewall-cmd --reload
# 运行时变更全部丢弃,系统恢复到原来的永久配置状态
# 步骤 3c: 如果只是个别规则有问题,单独回滚
firewall-cmd --remove-port=8080/tcp
2.3 关键操作命令
# 【只影响运行时】添加服务
firewall-cmd --add-service=http
# 【只影响永久配置】添加服务(不立即生效)
firewall-cmd --add-service=http --permanent
# 【推荐工作流】先测试,后持久化
firewall-cmd --add-service=http # 1. 运行时添加,立即测试
firewall-cmd --add-service=http --permanent # 2. 测试通过,永久配置
# 重载永久配置(丢弃所有未保存的运行时变更)
firewall-cmd --reload
# 完全重载(重建整个规则集)
firewall-cmd --complete-reload
# 查看运行时和永久的差异
firewall-cmd --zone=public --list-all # 运行时
firewall-cmd --zone=public --list-all --permanent # 永久
三、服务(Service)定义和自定义
3.1 服务配置文件
Service 将网络服务的端口、协议、内核模块等打包为单个配置,是 firewalld 管理便利性的核心:
<!-- /etc/firewalld/services/myapp.xml -->
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>MyApp</short>
<description>My Application - Web UI + API</description>
<port protocol="tcp" port="8080"/>
<port protocol="tcp" port="8443"/>
<port protocol="udp" port="9090"/>
<helper name="tftp"/>
<destination ipv4="192.168.1.0/24"/>
</service>
配置文件位置:
- 系统预定义:
/usr/lib/firewalld/services/ - 用户自定义:
/etc/firewalld/services/(优先级更高)
3.2 操作服务
# 列出所有可用服务
firewall-cmd --get-services
# 查看服务定义详情
firewall-cmd --info-service=ssh
firewall-cmd --info-service=http
# 添加服务到 Zone
firewall-cmd --zone=public --add-service=http # 运行时
firewall-cmd --zone=public --add-service=http --permanent # 永久
# 移除服务
firewall-cmd --zone=public --remove-service=http
# 查询服务是否已添加(返回 yes/no)
firewall-cmd --zone=public --query-service=http
3.3 创建自定义服务
# 方法 1: 从模板复制并修改
cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/mycustom.xml
vim /etc/firewalld/services/mycustom.xml
# 方法 2: 直接创建
cat > /etc/firewalld/services/myapp.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>MyApp</short>
<description>My Application - Web + API</description>
<port protocol="tcp" port="8080"/>
<port protocol="tcp" port="8443"/>
</service>
EOF
# 重新加载使新服务可用
firewall-cmd --reload
# 验证新服务
firewall-cmd --info-service=myapp
# 使用新服务
firewall-cmd --zone=public --add-service=myapp --permanent
3.4 直接操作端口
# 不通过服务定义,直接操作端口
firewall-cmd --zone=public --add-port=8080/tcp
firewall-cmd --zone=public --add-port=8000-9000/tcp # 端口范围
firewall-cmd --zone=public --remove-port=8080/tcp
# 添加源地址到 Zone(该源的流量使用此 Zone 的规则)
firewall-cmd --zone=internal --add-source=192.168.1.0/24
四、富规则(Rich Rules)语法详解
4.1 什么是富规则
富规则用于表达超出简单"端口/服务放行"的复杂防火墙需求,被 firewalld 翻译为底层的 iptables/nftables 规则。
4.2 富规则结构
rule
[family="ipv4|ipv6"]
[source address="CIDR" [invert="true"]]
[destination address="CIDR" [invert="true"]]
[service name="service"]
[port port="port" protocol="tcp|udp"]
[protocol value="tcp|udp|icmp"]
[icmp-block name="name"]
[masquerade]
[forward-port port="port" protocol="tcp|udp" to-port="port" to-addr="address"]
[log [prefix="text"] [level="level"] [limit value="rate/duration"]]
[audit]
[accept|reject|drop|mark set="mark"]
4.3 富规则实战示例
# 【示例 1】仅允许特定 IP 访问 SSH(白名单)
firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.100"
service name="ssh"
accept
'
# 【示例 2】按 IP 限速 SSH(防暴力破解,每分钟最多 3 次)
firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
service name="ssh"
limit value="3/m"
accept
'
# 【示例 3】白名单模式:仅允许特定 IP 段访问数据库
firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.0.0/8"
port port="3306" protocol="tcp"
accept
'
# 【示例 4】端口转发(外网 8080 → 内网 80)
firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
forward-port port="8080" protocol="tcp" to-port="80" to-addr="192.168.1.100"
'
# 【示例 5】拒绝并记录日志
firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="203.0.113.50"
log prefix="BLOCKED-IP: " level="warning" limit value="5/m"
reject
'
# 【示例 6】限制 ICMP 速率(防 ping 洪水)
firewall-cmd --zone=public --add-rich-rule='
rule protocol value="icmp"
limit value="1/s"
accept
'
# 查看和删除富规则
firewall-cmd --zone=public --list-rich-rules
firewall-cmd --zone=public --remove-rich-rule='rule family="ipv4" service name="ssh" accept'
输出解读(示例 2): 规则限定同一源 IP 每分钟最多发起 3 个新的 SSH 连接。第 4 个连接到达时将被拒绝。这比 iptables -m recent 语法更直观。
4.4 直接规则(Direct Rules)
当富规则无法满足需求时,可使用直接规则直接操作 iptables:
# 在 filter 表 INPUT 链最前面插入自定义规则
firewall-cmd --direct --add-rule ipv4 filter INPUT 1 \
-p tcp --dport 2222 -s 192.168.1.0/24 -j ACCEPT
# NAT 规则
firewall-cmd --direct --add-rule ipv4 nat PREROUTING 0 \
-p tcp --dport 8443 -j DNAT --to-destination 192.168.1.100:443
# 查看
firewall-cmd --direct --get-all-rules
# 持久化
firewall-cmd --direct --add-rule ... --permanent
注意事项: 不推荐在 firewalld 运行时直接使用 iptables 命令修改规则,因为 firewalld 重载时会覆盖手动规则。如需自定义 iptables 规则,应使用富规则或直接规则。
五、D-Bus API 集成
5.1 接口信息
firewalld 通过 D-Bus 接口暴露全部功能,使外部应用程序可以动态管理防火墙:
| 属性 | 值 |
|---|---|
| 服务名 | org.fedoraproject.FirewallD1 |
| 对象路径 | /org/fedoraproject/FirewallD1 |
| 接口 | org.fedoraproject.FirewallD1 |
| 配置接口 | org.fedoraproject.FirewallD1.config |
5.2 应用场景
| 应用 | 说明 |
|---|---|
| Cockpit Web 管理 | Red Hat 的 Web 管理界面通过 D-Bus 与 firewalld 交互 |
| NetworkManager 集成 | 连接新 Wi-Fi 时自动切换 Zone |
| 自动化脚本 | Python/Ansible 等工具直接通过 D-Bus API 操作 |
| 容器编排 | Docker/Podman 插件动态管理规则 |
# 通过 dbus-send 查询状态
dbus-send --system --print-reply \
--dest=org.fedoraproject.FirewallD1 \
/org/fedoraproject/FirewallD1 \
org.freedesktop.DBus.Properties.Get \
string:"org.fedoraproject.FirewallD1" string:"state"
# 获取默认 Zone
dbus-send --system --print-reply \
--dest=org.fedoraproject.FirewallD1 \
/org/fedoraproject/FirewallD1 \
org.fedoraproject.FirewallD1.getDefaultZone
六、后端架构:iptables vs nftables
┌─────────────────────────────────┐
│ firewalld │
│ (D-Bus 服务, 配置管理) │
│ │
│ Zone 管理 → Service 管理 → 富规则 │
└──────────────┬──────────────────┘
│
┌──────────┴──────────┐
▼ ▼
┌───────────┐ ┌───────────┐
│ iptables │ │ nftables │
│ 后端 │ │ 后端 │
│ (RHEL 7) │ │ (RHEL 8+) │
└─────┬─────┘ └─────┬─────┘
│ │
▼ ▼
┌─────────────────────────────────┐
│ Linux 内核 (netfilter) │
└─────────────────────────────────┘
# 查看当前后端
cat /etc/firewalld/firewalld.conf | grep -i backend
# 切换后端(编辑 /etc/firewalld/firewalld.conf)
# FirewallBackend=nftables
# systemctl restart firewalld
| 特性 | iptables 后端 | nftables 后端 |
|---|---|---|
| RHEL/CentOS 7 | 默认 | 可用(需 backport) |
| RHEL/CentOS 8+ | 已移除 | 默认 |
| 性能 | 标准 | 更高 |
| 原子更新 | 不支持 | 支持 |
| Docker 兼容 | 良好 | 需配置 |
七、适用场景与注意事项
适用场景
| 场景 | 说明 |
|---|---|
| RHEL/CentOS/Fedora 服务器 | 系统默认集成,开箱即用 |
| 多网络环境切换 | Zone 模型天然适合笔记本在不同网络间切换 |
| 中等规模生产环境 | Zone + 富规则提供足够灵活性 |
| 需要 GUI 管理 | 提供 firewall-config 图形界面 |
| 自动化运维(Ansible/Puppet) | D-Bus API 和命令行均支持脚本化 |
| NetworkManager 联动 | Wi-Fi 切换时自动切换 Zone |
注意事项
- 切勿绕过 firewalld 直接操作 iptables:firewalld 重载时会覆盖手动规则
- 运行时 vs 永久分离:务必理解
--permanent的含义,测试时只用运行时 - Docker 兼容性:Docker 直接操作 iptables,可能绕过 firewalld 的规则,需安装
docker-firewalld或配置 nftables 后端 - 富规则 vs 直接规则:优先使用富规则,直接规则是最后手段
- 发行版限定:firewalld 主要面向 RHEL 系列,Ubuntu/Debian 默认使用 UFW
常用速查命令
# 状态与信息
firewall-cmd --state # 运行状态
firewall-cmd --get-default-zone # 默认 Zone
firewall-cmd --get-active-zones # 活跃 Zone
firewall-cmd --zone=public --list-all # Zone 详情
# 服务管理
firewall-cmd --get-services # 所有服务
firewall-cmd --add-service=http # 添加服务(运行时)
firewall-cmd --add-service=http --permanent # 添加服务(永久)
# 端口管理
firewall-cmd --add-port=8080/tcp
firewall-cmd --remove-port=8080/tcp
# 富规则
firewall-cmd --list-rich-rules
firewall-cmd --add-rich-rule='...'
# 持久化
firewall-cmd --runtime-to-permanent # 运行时同步到永久
firewall-cmd --reload # 重载永久配置
下一步:05 — UFW 详解
05 — UFW 详解
UFW(Uncomplicated Firewall)是 Ubuntu/Debian 系列发行版默认推荐的防火墙前端工具。它的设计哲学是"极致简单"——用最少的命令完成最常见的防火墙配置,同时保持底层 iptables 的全部威力。
一、设计哲学与定位
1.1 核心原则
UFW 的设计遵循三个核心原则:
- 极简语法:命令语义化,一看就懂 ——
ufw allow 80vsiptables -A INPUT -p tcp --dport 80 -j ACCEPT - 安全默认值:默认拒绝所有入站、允许所有出站,用户只需声明要开放什么
- 零学习曲线:一条命令即可完成常见防火墙配置,适合个人用户和小型服务器
1.2 架构总览
┌─────────────────────────────────────────────────┐
│ 用户 │
│ ufw allow 80/tcp │
└─────────────────────┬───────────────────────────┘
│
┌─────────────────────▼───────────────────────────┐
│ ufw 前端 (Python 程序) │
│ - 解析用户命令 │
│ - 管理规则文件 │
│ - 生成 iptables 规则 │
└─────────────────────┬───────────────────────────┘
│
┌─────────────────────▼───────────────────────────┐
│ 规则存储层 │
│ /etc/ufw/user.rules (用户规则) │
│ /etc/ufw/before.rules (系统规则-在前面) │
│ /etc/ufw/after.rules (系统规则-在后面) │
│ /lib/ufw/user.rules (初始模板) │
└─────────────────────┬───────────────────────────┘
│
┌─────────────────────▼───────────────────────────┐
│ iptables (内核 netfilter) │
│ - UFW 使用自定义链结构 │
│ - ufw-before-input → ufw-user-input → │
│ ufw-after-input → ufw-track-input │
└─────────────────────────────────────────────────┘
1.3 适用与不适用场景
UFW 适合的场景:
✓ 个人桌面用户
✓ 小型 VPS 管理员
✓ 开发者(快速保护开发环境)
✓ 不想深入理解 iptables 的运维人员
UFW 不太适合的场景:
✗ 需要复杂的 NAT 规则
✗ 需要按数据包内容过滤(应用层防火墙)
✗ 大规模规则集管理(建议 firewalld 或 nftables)
✗ 需要 Zone 或动态策略切换
二、命令 → iptables 规则映射原理
2.1 UFW 自定义 iptables 链结构
UFW 在 iptables 中创建了一套复杂的链结构来实现其功能:
INPUT
↓
ufw-before-logging-input
↓
ufw-before-input ← 系统规则(loopback、已建立连接等)
↓
ufw-reject-input ← 处理 REJECT 动作
↓
ufw-track-input ← 连接跟踪
↓
ufw-user-input ← ★ 用户通过 ufw 命令添加的规则
↓
ufw-after-input ← 系统规则(最后执行的规则)
↓
ufw-after-logging-input
↓
ufw-skip-to-policy-input
↓
DROP / ACCEPT(默认策略)
各链的职责:
| 链名 | 用途 | 用户是否应修改 |
|---|---|---|
ufw-before-input | 最前面的规则(如 loopback、已建立连接) | 高级用户可修改 /etc/ufw/before.rules |
ufw-user-input | 用户通过 ufw 命令添加的规则 | 间接修改(通过 ufw 命令) |
ufw-after-input | 用户规则之后执行的规则 | 高级用户可修改 /etc/ufw/after.rules |
ufw-reject-input | 处理 REJECT 动作 | 不建议手动修改 |
2.2 命令映射对照表
UFW 命令执行后,在 /etc/ufw/user.rules 中生成规则条目,最终由 iptables 执行:
| UFW 命令 | 等效 iptables 规则 | 说明 |
|---|---|---|
ufw allow 22/tcp | iptables -A ufw-user-input -p tcp --dport 22 -j ACCEPT | 开放端口 |
ufw deny 80/tcp | iptables -A ufw-user-input -p tcp --dport 80 -j DROP | 拒绝端口(静默) |
ufw reject 8080/tcp | iptables -A ufw-user-input -p tcp --dport 8080 -j REJECT | 拒绝并回应 |
ufw limit 22/tcp | iptables -A ufw-user-input -p tcp --dport 22 -m limit --limit 3/min -j ACCEPT | 限速规则 |
ufw allow from 192.168.1.100 | iptables -A ufw-user-input -s 192.168.1.100 -j ACCEPT | 允许特定 IP |
ufw allow from 192.168.1.0/24 to any port 3306 | iptables -A ufw-user-input -s 192.168.1.0/24 -p tcp --dport 3306 -j ACCEPT | IP + 端口限制 |
ufw default deny incoming | iptables -P ufw-user-input DROP | 默认拒绝入站 |
ufw default allow outgoing | iptables -P ufw-user-output ACCEPT | 默认允许出站 |
ufw allow proto tcp from any to any port 22 | iptables -A ufw-user-input -p tcp --dport 22 -j ACCEPT | 明确指定协议 |
2.3 查看 UFW 生成的 iptables 规则
# 查看 UFW 创建的 iptables 链
sudo iptables -L -n -v | grep ufw
# 查看用户规则链(你在 ufw 中添加的规则都在这里)
sudo iptables -L ufw-user-input -n -v
# 查看 before 链(系统规则)
sudo iptables -L ufw-before-input -n -v
# 查看 after 链
sudo iptables -L ufw-after-input -n -v
# 查看完整规则集
sudo ufw show raw
# 或直接读取规则文件
sudo cat /etc/ufw/user.rules
2.4 规则文件内部格式
*filter
:ufw-user-input - [0:0]
:ufw-user-output - [0:0]
:ufw-user-forward - [0:0]
...
### tuple ### allow tcp 22 0.0.0.0/0 any 0.0.0.0/0 in
-A ufw-user-input -p tcp --dport 22 -j ACCEPT
### tuple ### allow tcp 80,443 0.0.0.0/0 any 0.0.0.0/0 in
-A ufw-user-input -p tcp -m multiport --dports 80,443 -j ACCEPT
...
COMMIT
关键注意: ### tuple ### 注释行是 UFW 用来追踪规则的元数据,不要手动删除这些注释,否则 UFW 无法正确管理规则。
三、应用配置文件机制
3.1 配置文件位置与格式
UFW 的应用配置文件使你可以用应用名称代替端口号来管理防火墙:
| 路径 | 用途 | 优先级 |
|---|---|---|
/etc/ufw/applications.d/ | 用户自定义应用配置 | 高(覆盖系统配置) |
/usr/share/ufw/applications.d/ | 系统预定义应用配置 | 低 |
# /etc/ufw/applications.d/myapp
[MyApp]
title=My Custom Web Application
description=A custom web app with web UI and API
ports=8080/tcp|8443/tcp
[MyApp-Full]
title=My Custom Web Application (Full)
description=Web UI, API, and Database
ports=8080/tcp|8443/tcp|3306/tcp
[MyApp-Secure]
title=My Custom Web Application (HTTPS Only)
description=Secure web access only
ports=8443/tcp
关键语法:
[ProfileName]—— 配置文件名(用于ufw allow命令)title=—— 简短标题description=—— 详细说明ports=—— 端口/协议定义,多个用|分隔
3.2 查看和使用应用
# 列出所有可用应用配置
ufw app list
# 查看应用配置详情
ufw app info 'Nginx Full'
ufw app info OpenSSH
# 按应用名开放端口
ufw allow 'Nginx Full' # 同时开放 80 和 443
ufw allow OpenSSH # 开放 22
3.3 常见预定义应用
| 应用名 | 包含端口 | 说明 |
|---|---|---|
OpenSSH | 22/tcp | SSH 服务 |
Nginx HTTP | 80/tcp | Nginx HTTP |
Nginx HTTPS | 443/tcp | Nginx HTTPS |
Nginx Full | 80,443/tcp | Nginx HTTP + HTTPS |
Apache Full | 80,443/tcp | Apache HTTP + HTTPS |
Samba | 137,138/udp, 139,445/tcp | 文件共享 |
CUPS | 631/tcp, 631/udp | 打印服务 |
Postfix | 25,465,587/tcp | 邮件服务器 |
3.4 创建自定义应用
# 创建自定义应用配置
sudo tee /etc/ufw/applications.d/myapp << 'EOF'
[MyApp]
title=My Custom Application
description=Web UI on 8080, API on 9090
ports=8080/tcp|9090/tcp
EOF
# 更新应用列表
sudo ufw app update MyApp
# 查看新应用
sudo ufw app info MyApp
# 使用新应用
sudo ufw allow MyApp
四、日志和报告
4.1 日志配置
# 开启日志
sudo ufw logging on
# 日志级别
sudo ufw logging low # 仅记录被阻止的包(默认)
sudo ufw logging medium # 记录阻止+允许的包(含速率限制)
sudo ufw logging high # 记录所有包(含速率限制)
sudo ufw logging full # 记录所有包(无速率限制,可能产生大量日志)
# 关闭日志
sudo ufw logging off
# 查看日志状态
sudo ufw status verbose
4.2 日志位置
# 查看 UFW 日志(rsyslog 系统)
sudo tail -f /var/log/ufw.log
# 或通过 journalctl
sudo journalctl -u ufw -f
# 或查看 kern.log
sudo grep UFW /var/log/kern.log | tail -20
4.3 日志条目解读
[UFW BLOCK] IN=eth0 OUT= MAC=00:11:22:33:44:55:66:77:88:99:aa:bb:08:00
SRC=203.0.113.50 DST=192.168.1.10 LEN=60 TOS=0x00 PREC=0x00 TTL=47
PROTO=TCP SPT=45678 DPT=22 WINDOW=29200 RES=0x00 SYN URGP=0
日志字段解读表:
| 字段 | 含义 | 示例值含义 |
|---|---|---|
[UFW BLOCK] | 动作类型 | 此包被阻止 |
SRC= | 源 IP | 203.0.113.50(攻击来源) |
DST= | 目标 IP | 192.168.1.10(你的服务器) |
DPT= | 目标端口 | 22(攻击者试图连接 SSH) |
SPT= | 源端口 | 45678(攻击者发起连接时使用的随机端口) |
PROTO= | 协议 | TCP |
4.4 状态查看命令
sudo ufw status # 基本状态
sudo ufw status verbose # 详细状态(含日志设置和默认策略)
sudo ufw status numbered # 编号状态(每条规则带编号,便于删除)
sudo ufw show raw # 查看底层 iptables 规则
sudo ufw show added # 查看添加的规则报告
sudo ufw show listening # 查看监听端口报告
ufw status numbered 输出示例与解读:
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp LIMIT IN Anywhere ← SSH 限速
[ 2] 80/tcp ALLOW IN Anywhere ← HTTP 开放
[ 3] 443/tcp ALLOW IN Anywhere ← HTTPS 开放
[ 4] 3306/tcp ALLOW IN 192.168.1.0/24 ← MySQL 仅内网访问
删除规则:sudo ufw delete 3(删除编号 3 的规则)
五、与 Docker 共存时的注意事项
5.1 核心问题
Docker 直接操作 iptables,绕过 UFW。这是 UFW 用户最容易踩的坑:
正常期望:
客户端 → UFW 拒绝 → 无法访问
实际情况(Docker 运行时):
客户端 → Docker iptables 规则(在 UFW 之前执行)→ 直接放行!
原因: Docker 在 DOCKER-USER 链中以优先级更高的方式插入规则,这些规则在 UFW 的 ufw-user-input 链之前执行。如果你用 -p 8080:8080 暴露端口,即使 UFW 拒绝了 8080,外部仍可直接访问。
5.2 解决方案
方案 1:绑定到 localhost(推荐,最安全)
# 启动容器时只绑定到本地回环接口
docker run -p 127.0.0.1:8080:8080 myapp
# 效果:端口仅能从本机访问,完全不经过 iptables 的外部放行
# 如果外部需要访问,通过 Nginx 反向代理 + UFW 允许 80/443
方案 2:使用 DOCKER-USER 链
# Docker 提供的 DOCKER-USER 链供用户添加规则
# 这个链在 Docker 自动规则之后执行,可以覆盖 Docker 的行为
sudo iptables -I DOCKER-USER 1 -p tcp --dport 8080 -j DROP
# 更精确:只允许特定 IP 访问
sudo iptables -I DOCKER-USER 1 -p tcp --dport 8080 \
! -s 192.168.1.0/24 -j DROP
# 持久化此规则:编辑 /etc/ufw/after.rules,在 COMMIT 之前添加
# -A DOCKER-USER -p tcp --dport 8080 ! -s 192.168.1.0/24 -j DROP
方案 3:禁用 Docker 的 iptables 操作
// /etc/docker/daemon.json
{
"iptables": false
}
警告: 禁用后需手动管理所有 Docker 网络规则(容器间通信、端口映射等),维护成本高。
5.3 方案对比
| 方案 | 难度 | 安全级别 | 维护成本 | 推荐场景 |
|---|---|---|---|---|
| 绑定 localhost | 极低 | 最高 | 极低 | 所有场景(首选) |
| DOCKER-USER 链 | 中 | 高 | 中 | 必须暴露端口到外网时 |
| 禁用 Docker iptables | 高 | 中等 | 很高 | 仅限高级用户 |
5.4 Docker Compose 安全配置
version: '3.8'
services:
web:
image: nginx:latest
ports:
# 安全:仅绑定到 localhost,通过反向代理访问
- "127.0.0.1:8080:80"
# 危险(会绕过 UFW):
# - "8080:80"
db:
image: mysql:8
# 不暴露端口到宿主机(仅容器间通信)
expose:
- "3306"
networks:
- internal
networks:
internal:
driver: bridge
六、适用场景与注意事项
适用场景
| 场景 | 说明 |
|---|---|
| Ubuntu/Debian 桌面和服务器 | 系统默认推荐,开箱即用 |
| 小型 VPS(单一管理员) | 极简操作,一条命令搞定 |
| 开发环境快速加固 | 无需深入理解 iptables 即可保护开发机 |
| 学习防火墙的入门工具 | 通过 UFW 理解防火墙概念后再深入 iptables |
| SSH + Web 服务的基本防护 | 防 SSH 暴力破解、开放 HTTP/HTTPS 端口 |
注意事项
- 默认策略是 DENY INCOMING:启用 UFW 后,所有入站连接被阻止,务必先
ufw allow ssh - Docker 绕过 UFW:使用
-p 8080:8080暴露端口的容器可能直接暴露到公网 - ufw enable 后立即生效:如果 SSH 规则未先配置,远程连接会断开
- 规则顺序很重要:
ufw status numbered查看规则编号,编号越小优先级越高 - limited 规则的局限性:无法实现更复杂的速率限制(如 recent 模块的
--hitcount),如需高级限速请直接使用 iptables - 不适用于大规模规则集:超过 20-30 条规则后管理开始不便,建议切换 firewalld 或 nftables
常用速查命令
# 基础操作
sudo ufw enable # 启用(同时设置开机自启)
sudo ufw disable # 禁用
sudo ufw reset # 重置所有规则
sudo ufw reload # 重载配置
# 规则管理
sudo ufw allow 22/tcp # 开放端口
sudo ufw allow 80,443/tcp # 开放多个端口
sudo ufw deny 8080/tcp # 拒绝端口(静默丢弃)
sudo ufw reject 8080/tcp # 拒绝端口(回应 ICMP/TCP RST)
sudo ufw limit 22/tcp # 限速(3/min,防暴力破解)
sudo ufw delete allow 80/tcp # 删除规则
sudo ufw delete 3 # 按编号删除
# IP 级规则
sudo ufw allow from 192.168.1.100 # 允许特定 IP 访问所有端口
sudo ufw allow from 192.168.1.0/24 to any port 3306 # 允许 IP 段访问特定端口
sudo ufw deny from 203.0.113.50 # 拒绝特定 IP
# 默认策略
sudo ufw default deny incoming # 默认拒绝入站(推荐)
sudo ufw default allow outgoing # 默认允许出站(推荐)
# 应用配置
sudo ufw app list # 查看可用应用
sudo ufw app info 'Nginx Full' # 查看应用详情
sudo ufw allow 'Nginx Full' # 按应用名开放
下一步:06 — 方案选择决策指南
06 — 方案选择决策指南
本文是防火墙配置与管理教程的终点站:帮助你根据实际场景,在 iptables、nftables、firewalld、UFW 四种方案中做出最优选择。
一、核心决策流程图
需要 Linux 防火墙方案
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
你是个人用户? 你是运维工程师? 你是架构师?
│ │ │
▼ ▼ ▼
使用什么发行版? 管理什么规模? 性能要求多高?
│ │ │
┌────┐ │ ┌────┐ │ ┌────┐ │
│Ubuntu│ │ │RHEL│ │ │通用│ │
│Debian│ │ │系列│ │ │ │ │
└──┬──┘ │ └──┬┘ │ └──┬┘ │
│ │ │ │ │ │
▼ │ ▼ │ ▼ │
┌──────┐ │ ┌────────┐ │ ┌────────┐ │
│ UFW │◄─┘ │firewalld│ │ │nftables │ │
│(→05) │ │(→04) │ │ │(→03) │ │
└──────┘ └────────┘ │ └────────┘ │
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
需要更灵活? 需要更灵活? 中小规模? 高流量? 容器环境?
│ │ │ │ │
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐┌──────┐
│iptab │ │nftab │ │firewa│ │nftab ││iptab │
│les │ │les │ │lld │ │les ││les │
│(→02) │ │(→03) │ │(→04) │ │(→03) ││(→02) │
└──────┘ └──────┘ └──────┘ └──────┘└──────┘
注:箭头后的数字(如
→ 02)对应本教程的文档编号。
二、全方案对比矩阵(4 方案 x 15 维度)
2.1 综合评分表
| 维度 | iptables | nftables | firewalld | UFW |
|---|---|---|---|---|
| 首次发布 | 2001 (Linux 2.4) | 2014 (Linux 3.13) | 2011 (RHEL 7) | 2008 (Ubuntu 8.04) |
| 内核后端 | xtables(遗留框架) | nf_tables(新一代) | iptables 或 nftables | iptables |
| 用户空间工具 | iptables/ip6tables/arptables/ebtables(4 个) | 单一 nft 命令 | firewall-cmd | ufw |
| 配置模型 | 过程式(命令序列) | 声明式 + 过程式 | 声明式(Zone 模型) | 声明式(极简语法) |
| 细粒度控制 | 强(四表五链直接操作) | 强(自定义表/链/集合) | 中(需富规则) | 弱(有限) |
| 规则更新方式 | 逐条操作,非原子 | 事务性原子更新 | 部分支持 | 间接支持 |
| 规则查找速度 | O(n) 线性 | O(1) 集合/映射 | 等于后端(iptables/nftables) | 等于 iptables |
| IPv4/IPv6 管理 | 分开管理 | 统一管理(inet family) | 统一管理 | 统一管理 |
| 学习曲线 | 高(陡峭) | 中(较直观) | 低(Zone 直观) | 极低(一条命令) |
| 配置复杂度 | 高(手动编写长命令) | 中(结构化语法) | 低(命令抽象) | 极低(最简命令) |
| 动态规则 | 不支持 | 支持 | 支持(运行时/永久分离) | 间接支持 |
| 性能(高流量) | 中 | 高(JIT 编译 + 集合) | 中(等于后端) | 中(等于 iptables) |
| 内核版本要求 | >= 2.4 | >= 3.13(推荐 >= 4.9) | >= 3.x | >= 2.6 |
| 主流发行版 | 通用(逐渐被替代) | RHEL 8+, Debian 10+, openSUSE 15+ | RHEL/CentOS/Fedora | Ubuntu/Debian |
| Docker 兼容性 | 良好(Docker 原生) | 需谨慎配置 | 需配置 | 需配置(Docker 绕过 UFW) |
2.2 维度详解
细粒度控制能力
| 级别 | 工具 | 能力说明 |
|---|---|---|
| 强 | iptables | 四表五链直接操作,支持大量匹配扩展模块(conntrack/tcp/recent/limit 等) |
| 强 | nftables | 自定义表/链/集合/映射,语法更灵活,一套规则处理 IPv4+IPv6 |
| 中 | firewalld | 富规则可覆盖大多数场景,极端需求需直接规则(操作底层 iptables) |
| 弱 | UFW | 仅覆盖常见端口/IP 放行/拒绝/限速场景,不支持高级 NAT/标记等 |
性能等级(大规模规则集场景)
| 级别 | 工具 | 100 条规则下的吞吐量(64 字节包) | 说明 |
|---|---|---|---|
| 高 | nftables | ~1.2M pps | JIT 编译 + 集合 O(1) 查找 |
| 中 | iptables | ~800K pps | O(n) 线性查找,ESTABLISHED 规则可减少实际匹配 |
| 中 | firewalld | 取决于后端(iptables 或 nftables) | 富规则有一定翻译开销 |
| 中 | UFW | ~800K pps(等于 iptables) | 自定义链结构增加少量开销 |
学习曲线
| 级别 | 工具 | 预估上手时间 | 说明 |
|---|---|---|---|
| 极低 | UFW | 5 分钟 | ufw allow 80 即可 |
| 低 | firewalld | 30 分钟 | Zone 概念直观,firewall-cmd 命令简单 |
| 中 | nftables | 2 小时 | 语法比 iptables 直观,但需要理解新概念(set/map/family) |
| 高 | iptables | 1 天 | 需要理解四表五链、匹配模块、目标动作、规则顺序等 |
三、场景 → 推荐方案速查表(决策矩阵)
| 场景关键词 | 第一推荐 | 第二推荐 | 备注 |
|---|---|---|---|
| Ubuntu/Debian 桌面 | UFW | iptables | UFW 开箱即用,一条命令保护系统 |
| Ubuntu/Debian 小型 VPS | UFW | iptables | 个人 VPS 通常只需开放 SSH + Web 端口 |
| Fedora/RHEL 桌面 | firewalld | nftables | firewalld 系统默认集成 |
| RHEL/CentOS 7 服务器 | firewalld | iptables | firewalld 是 RHEL 7 默认,iptables 后端 |
| RHEL/CentOS 8/9 服务器 | firewalld + nftables 后端 | nftables(直接) | RHEL 8+ 默认 nftables 后端 |
| 中型生产环境(需精细控制) | firewalld(富规则) | nftables | Zone 模型 + 富规则满足大部分需求 |
| 大型/高流量环境(性能敏感) | nftables | iptables | 集合 O(1) 查找 + JIT 编译,性能最优 |
| Docker/K8s 宿主机 | iptables | nftables(谨慎) | Docker 原生操作 iptables,兼容性最好 |
| NAT 网关/路由器 | iptables 或 nftables | firewalld | 需要细致的 DNAT/SNAT/MASQUERADE 控制 |
| 安全合规要求高 | nftables | firewalld | nftables 原子更新消除规则变更空窗期 |
| 嵌入式/Linux From Scratch | iptables | nftables | iptables 依赖最少,内核版本要求最低 |
| Fail2ban/第三方工具联动 | iptables | nftables(新版支持) | fail2ban 默认使用 iptables 封禁 |
| 学习 Linux 防火墙 | 先 iptables 再 nftables | — | 理解底层原理后,上层工具才用得明白 |
| 多网络环境切换(笔记本) | firewalld | UFW | Zone 切换 + NetworkManager 联动 |
四、技术演进路线
iptables (2001) ─────────────────────────────────────────► 遗留但广泛部署
│
├──► UFW (2008) ──────────────► 将 iptables 封装为极简接口
│
├──► firewalld (2011) ────────► 将 iptables 封装为 Zone 模型
│ │
│ └──► RHEL 8+ 切换到 nftables 后端
│
└──► nftables (2014) ────────► 内核层面的彻底重构,替代 iptables
│
└──► 未来趋势 ──────► 逐步成为所有发行版的默认方案
五、常见误区与反模式
误区 1:同时运行多个防火墙工具
错误表现:
# 同时启用 firewalld 和手动 iptables 规则
systemctl start firewalld
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT # 手动规则
后果:
- firewalld 重载时会覆盖手动添加的 iptables 规则
- 两个工具各自管理同一组 netfilter Hook 点,规则互相覆盖
- 安全状态不可预测
正确做法:
# 只使用一个防火墙管理工具
# 如果使用 firewalld,所有规则通过 firewall-cmd 添加
# 如果直接使用 iptables/nftables,先停掉 firewalld
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
误区 2:Docker 端口映射绕过 UFW
错误表现:
sudo ufw enable
sudo ufw deny 8080
docker run -p 8080:80 nginx # 8080 端口仍可从外部访问!
原因: Docker 的 iptables 规则在 UFW 规则之前执行,端口映射直接暴露到公网。
正确做法:
# 绑定到 localhost
docker run -p 127.0.0.1:8080:80 nginx
# 或通过 DOCKER-USER 链添加过滤规则
误区 3:iptables -P INPUT DROP 在远程 SSH 会话中执行
错误表现:
# SSH 连接到服务器后执行
iptables -P INPUT DROP
# 连接立即断开!所有 SSH 流量被丢弃
后果: 被锁在服务器外面,需要物理访问或控制台恢复。
正确做法:
# 先添加允许 SSH 的规则
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 再设置默认策略
iptables -P INPUT DROP
误区 4:firewalld 的 --permanent 以为会立即生效
错误表现:
firewall-cmd --add-service=http --permanent
# 以为 HTTP 服务已经在防火墙上开放了
# 实际上还没有!需要 reload
正确做法:
# 方案 A:先运行时添加(立即生效),再永久保存
firewall-cmd --add-service=http # 立即生效
firewall-cmd --add-service=http --permanent # 永久保存
# 或
firewall-cmd --runtime-to-permanent # 同步所有运行时到永久
# 方案 B:修改永久配置后 reload
firewall-cmd --add-service=http --permanent
firewall-cmd --reload # 使永久配置生效
误区 5:nftables 和 iptables 的规则可以简单混用
错误认知: 以为可以在 nftables 规则的基础上再添加几条 iptables 规则,两者"各管各的"。
实际情况: nftables 和 iptables 都向 netfilter 的同一个 Hook 点注册回调。默认 priority 相同的情况下,执行顺序由内核模块加载顺序决定,结果不可预测。
正确做法:
- 使用一种工具作为主防火墙
- 如果必须混用(如 Docker 依赖 iptables),通过 priority 值明确控制执行顺序
- 使用 nftables 的 iptables 兼容层(内核选项
NF_TABLES_IPV4/NF_TABLES_IPV6)
误区 6:UFW 的 limit 规则可以替代专业限速
错误表现:
sudo ufw limit 22/tcp
# 以为这提供了完整的 SSH 防护
现实: UFW 的 limit 规则使用 iptables 的 -m limit 模块,是一个基于全局速率的限制(每分钟 3 次,面向所有 IP 汇总),而不是每 IP 限制。一个攻击者可以耗尽全局限额,导致合法用户无法连接。
需要每 IP 限制时: 直接使用 iptables 的 -m recent 模块,或切换到更专业的限速方案。
六、终极速查卡 Cheat Sheet
| 操作 | iptables | nftables | firewalld | UFW |
|---|---|---|---|---|
| 安装 | 系统自带 | apt install nftables | yum/dnf install firewalld | apt install ufw |
| 查看规则 | iptables -L -n -v | nft list ruleset | firewall-cmd --list-all | ufw status verbose |
| 允许端口 | iptables -A INPUT -p tcp --dport 80 -j ACCEPT | nft add rule inet filter input tcp dport 80 accept | firewall-cmd --add-port=80/tcp | ufw allow 80/tcp |
| 拒绝端口 | iptables -A INPUT -p tcp --dport 80 -j DROP | nft add rule inet filter input tcp dport 80 drop | firewall-cmd --remove-port=80/tcp | ufw deny 80/tcp |
| 允许已建立连接 | iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT | nft add rule inet filter input ct state established,related accept | 自动处理 | 自动处理 |
| 默认拒绝入站 | iptables -P INPUT DROP | nft add chain ... { policy drop; } | firewall-cmd --set-default-zone=drop | ufw default deny incoming |
| 保存规则 | iptables-save > rules.v4 | nft list ruleset > rules.nft | firewall-cmd --runtime-to-permanent | 自动保存 |
| 恢复规则 | iptables-restore < rules.v4 | nft -f rules.nft | firewall-cmd --reload | ufw reload |
| 重置/清空 | iptables -F; iptables -X | nft flush ruleset | firewall-cmd --complete-reload | ufw reset |
| 持久化 | iptables-persistent 或 systemd 服务 | /etc/nftables.conf + systemctl enable nftables | --permanent 标志 | 自动持久化 |
| 允许特定 IP | iptables -A INPUT -s 192.168.1.100 -j ACCEPT | nft add rule inet filter input ip saddr 192.168.1.100 accept | firewall-cmd --add-rich-rule='rule source address="192.168.1.100" accept' | ufw allow from 192.168.1.100 |
| 端口转发 | iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 | nft add rule inet nat prerouting tcp dport 8080 dnat to 192.168.1.100:80 | 富规则 forward-port | 不支持(需直接 iptables) |
| 限速 | iptables -A INPUT -m limit --limit 3/min -j ACCEPT | nft add rule inet filter input limit rate 3/minute accept | 富规则 limit value="3/m" | ufw limit 22/tcp |
| 日志记录 | iptables -A INPUT -j LOG --log-prefix "DROP: " | nft add rule inet filter input log prefix "DROP: " | 富规则 log prefix="..." | ufw logging on |
| 查看状态 | iptables -L -n -v | nft list ruleset | firewall-cmd --state | ufw status |
七、总结:选型核心原则
记住这五条金科玉律:
-
桌面/个人 VPS → UFW 或 firewalld。Ubuntu/Debian 用 UFW,Fedora/RHEL 用 firewalld,开箱即用,学习成本最低。
-
生产服务器(RHEL 系列)→ firewalld。Zone 模型适合多网络环境,运行时/永久配置分离提供安全的变更工作流,D-Bus API 支持自动化运维。
-
高流量/高性能 → nftables。集合 O(1) 查找 + JIT 编译 + 原子更新,是 Linux 防火墙的未来标准。如果你的发行版支持(>= RHEL 8 / Debian 10),应优先考虑。
-
Docker/K8s 宿主机 → iptables。Docker 和 Kubernetes 的 CNI 插件深度依赖 iptables。虽然 nftables 提供了兼容层,但 iptables 仍是容器生态最稳定的选择。
-
学习目的 → 先 iptables 再 nftables。iptables 是理解 Linux 防火墙机制的基石(四表五链、匹配模块、conntrack),掌握了它再去学 nftables 会事半功倍。
最后忠告:
一个系统只需要一套防火墙管理方案。 不要让 iptables 和 firewalld 并存,不要让 UFW 和 nftables 竞争同一个 Hook 点。选好一个,关掉其他的,确保防火墙规则可预测、可审计。
教程系列完结。本教程共 6 篇文档,从 netfilter 内核原理到四种防火墙方案的深入讲解,再到方案选择决策指南,覆盖了 Linux 下所有主流防火墙配置方案。建议按需查阅,结合实际场景选择最合适的方案。
返回:README 教程首页