为什么我们需要不断演进防火墙技术?
很多运维工程师对 iptables 又爱又恨。爱的是它足够强大,几乎能解决所有网络层面的访问控制问题;恨的是它的规则集一旦庞大起来,管理和维护就成了噩梦。更关键的是,当你的服务器需要处理每秒数十万甚至上百万个数据包时,iptables 线性匹配规则的性能开销开始变得无法忽视。
这种困境并非偶然。iptables 诞生于网络服务规模远小于今天的时代,其设计初衷是灵活和功能完备,而非极致性能。随着云计算、微服务和 5G 边缘计算的发展,网络流量模型发生了根本变化:短连接、高并发、细粒度的策略需求成为常态。内核网络栈的瓶颈,尤其是防火墙处理部分,开始直接制约整个系统的吞吐量和延迟。
于是,演进发生了。这不是简单的工具替换,而是内核网络子系统为适应新时代而进行的一场深度重构。
第一代支柱:iptables 与它的“表链”王国
iptables 的成功,很大程度上归功于它清晰的概念模型:表(Tables)、链(Chains)和规则(Rules)。filter 表负责过滤,nat 表处理地址转换,mangle 表修改数据包,raw 表用于连接跟踪豁免。数据包按照预定义的路径(如 INPUT、FORWARD、OUTPUT 链)流动,依次匹配链中的规则。
这种设计的优势在于直观。管理员可以很清晰地构建出“先做 NAT,再过滤”这样的逻辑。然而,其缺点在复杂场景下暴露无遗:
- 性能随规则数量线性下降:每个数据包需要依次遍历链中的规则,直到命中一个最终动作(ACCEPT/DROP)。对于拥有数千条规则的网关设备,这带来了巨大的 CPU 开销。
- 规则集膨胀与碎片化:为了实现复杂的策略,往往需要添加大量规则,这些规则之间可能存在重叠或依赖,导致管理混乱,且难以实现规则的原子性更新。
- 多协议工具分裂:IPv4、IPv6、ARP 等分别由 iptables、ip6tables、arptables 等不同工具管理,配置和维护缺乏一致性。
一个典型的场景是,为了防御一种新的攻击模式,运维团队紧急添加了十条规则。几个月后攻击不再流行,但这些规则却因为担心影响未知业务而不敢删除,最终沉淀为“僵尸规则”,持续消耗着系统性能。
第二代革新:nftables 的统一与表达力
nftables 的出现,目标直指 iptables 的痛点。它并非在原有框架上修修补补,而是基于全新的内核子系统 nf_tables 进行了重写。
其核心改进在于:
- 统一的配置语法:一套工具和语法管理所有协议(IPv4, IPv6, ARP, Bridge等),脚本和工具的复用性大大增强。
- 声明式规则集:nftables 的配置更像一个完整的配置文件,支持包含、继承等特性,易于版本化管理。
- 更高效的匹配机制:引入了命名集(named sets)和映射(maps)。你可以将需要频繁匹配的 IP 地址、端口号放入一个集合中,一条规则即可完成对数以千计元素的匹配,避免了线性遍历。
来看一个对比示例。假设我们需要允许来自一个IP列表(10.0.0.0/24, 192.168.1.100)的 SSH 访问,并记录日志。
iptables 方式(需要多条规则):
iptables -A INPUT -s 10.0.0.0/24 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -s 192.168.1.100 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "SSH Reject: "
iptables -A INPUT -p tcp --dport 22 -j DROP
nftables 方式(使用集合,更简洁):
nft add set inet filter ssh_allow { type ipv4_addr; flags interval; elements = { 10.0.0.0/24, 192.168.1.100 } }
nft add chain inet filter input { type filter hook input priority 0; }
nft add rule inet filter input tcp dport 22 ip saddr @ssh_allow counter accept
nft add rule inet filter input tcp dport 22 log prefix "SSH Reject: " counter drop
更重要的是,nftables 的规则在内部被表达为一棵表达式树,这为编译时和运行时的优化提供了可能,例如合并相似的检查条件。
然而,nftables 依然运行在内核的协议栈路径上。对于追求微秒级延迟的超高性能网络(如金融交易、电信核心网),或者希望将网络功能卸载到智能网卡的需求,它仍有其局限性。
第三代前瞻:bpfilter 与内核旁路愿景
这正是 bpfilter 登场的背景。bpfilter 不是一个直接面向用户的管理工具,而是一个内核框架。它的核心思想是:将防火墙的过滤规则编译成 eBPF 字节码,然后在内核中,甚至是在硬件(如支持 eBPF 卸载的网卡)中执行。
eBPF 本身是一个沙盒化的虚拟机,允许将用户定义的程序安全地注入内核执行。bpfilter 利用这一点,带来了范式性的改变:
| 特性 | iptables/nftables (传统路径) | bpfilter (eBPF路径) |
|---|---|---|
| 执行位置 | 内核网络协议栈内(软件处理) | 可位于协议栈早期、XDP层,或卸载至智能网卡 |
| 性能特征 | 受制于协议栈处理开销,上下文切换多 | 极低延迟,可线速处理,避免不必要的内核开销 |
| 更新机制 | 需要遍历和替换规则链,可能引起短暂中断 | eBPF程序可原子性热替换,实现零中断策略更新 |
| 可编程性 | 限于预定义的匹配模块和动作 | 可通过C语言子集编写自定义过滤逻辑,功能无限 |
| 当前状态 | 生产就绪,生态成熟 | 仍在积极开发,部分功能作为内核模块存在,是未来方向 |
想象一个场景:一个云服务商需要为每个租户的每个容器实例实施不同的网络策略。使用传统方式,海量的规则会导致内核路由和防火墙表爆炸。而 bpfilter 结合 eBPF,可以为每个网络命名空间动态加载一个微型的、定制化的过滤程序,实现极致的灵活性和性能隔离。
不过,bpfilter 的“激进”也带来了挑战。它的复杂性更高,调试更困难,且严重依赖较新的内核版本(5.10+ 版本支持更完善)。对于大多数常规企业服务器和网络设备,nftables 在可预见的未来仍是更稳妥、更易管理的选择。
演进背后的逻辑与选型建议
回顾这三代技术,其演进逻辑清晰可见:从功能完备(iptables),到统一与优化(nftables),再到追求极致性能与灵活性(bpfilter/eBPF)。每一次演进都不是对前一代的简单否定,而是为了解决在新的规模和技术条件下暴露出的核心矛盾。
对于当下的技术选型,我的建议是:
- 新项目与通用服务器:优先采用 nftables。它正在成为主流发行版的默认防火墙工具(如 RHEL 8+/CentOS Stream,最新版 Ubuntu),拥有更好的长期支持前景、更优的性能和更现代化的管理体验。
- 现有 iptables 环境:如果稳定运行且规则集不复杂,不必急于迁移。iptables 仍有庞大的生态和知识库。迁移的动力应来自于管理复杂性或性能瓶颈的实际需求。可以利用
iptables-translate等工具辅助迁移。 - 高性能/云原生/定制化场景:密切关注并评估 bpfilter 和 eBPF 技术栈。特别是对于需要实现自定义网络协议解析、毫秒级策略生效或与 Kubernetes Cilium 等云原生网络方案深度集成的场景,eBPF 是必经之路。可以从网络监控、可观测性等非关键路径开始尝试。
防火墙的演进,本质上是 Linux 内核应对“数据包洪流”的持续努力。理解从 iptables 到 nftables 再到 bpfilter 的路径,不仅能帮助我们做出更明智的技术选择,更能让我们洞察到系统软件为适应硬件发展与业务需求而进行自我革新的内在节奏。未来,防火墙的形态可能会进一步模糊,融入更广泛的“可编程数据面”,但确保流量安全、可控的核心使命将始终如一。
原创文章,作者:,如若转载,请注明出处:https://fudengji.cn/article/126/