了解 Linux 防火墙
1️⃣ Netfilter
提到 Linux 防火墙,很多人会先想到 iptables、nftables、firewalld、ufw,它们本质上都只是 用户态 的 配置工具。
真正负责 “拦包、改包、放行 /丢弃” 的核心,是 Linux 内核里的 Netfilter。

从上图可以看出:流量流动 是先从网卡,再到 linux 内核,最后抵达到网络应用。
流量过滤 指的是先让流量从网卡进来,然后在 linux 内核里进行过滤处理,最后进入网络应用。这样网络应用前面就有一道防火墙,防火墙就位于 linux 内核的实现中。
挂载点
Netfilter 向 内核协议栈 中 不同的位置 注册 钩子函数 HOOK 来对数据包进行过滤或者修改操作,这些位置称为 挂载点。
Netlfilter 通常有 5 个 HOOK 点:
PREROUTING:数据包进入路由表之前INPUT:通过路由表后目的地为本机FORWARD:通过路由表后,目的地不为本机OUTPUT:由本机产生,向外发送POSTROUTIONG:发送到网卡接口之前。

2️⃣ iptables
iptables 是建立在 Netfilter 之上的 ip 数据包过滤器,通过向 Netfilter 的 挂载点 上注册 钩子函数HOOK 来实现对数据包过滤。
iptables 通过把这些规则 rule 挂载在 Netfilter 不同挂载点 的不同链 chain上,对进出内核协议栈的数据包进行 过滤 或者 修改 操作。
1️⃣ 表 Tables、链 Chains 、规则 Rules 三者联系

表 Tables
表 Tables 是 “按处理目的分类” 的规则集合。
filter:做放行/拦截(ACCEPT/DROP/REJECT)nat:做地址转换(DNAT/SNAT/MASQUERADE)mangle:做改包/打标(TTL/TOS/MARK等)raw:更早阶段的处理,常用于影响连接跟踪(conntrack)
链 Chains
链 Chains 是 “表 Tables 在某个挂载点 HOOK” 的入口规则列表。
PREROUTING:由PREROUTINGHOOK触发;INPUT:由INPUTHOOK触发;FORWARD:由FORWARDHOOK触发;OUTPUT:由OUTPUTHOOK触发;POSTROUTIONG:由POSTROUTIONGHOOK触发;
规则 Rules
规则 rule 是一条 “匹配条件 + 动作” 的行为。
- 规则
rule存在于链Chain中;当某条链Chain被执行时,数据包会按顺序逐条匹配规则,命中后执行动作。 - 优先级:
Table有优先级,由高到低排列为:raw->mangle->nat->filter。当有多个Table包含同一类型的Chain时,所有的Table都会按照上面Table优先级被遍历,执行Table中实际的Chain下的规则。
2️⃣ 整体框架

3️⃣ 数据包处理流程图

- 数据包流入: 数据包通过 网卡 进入
Netfliter时- 首先对数据包进行
DNAT,将公网地址ip转换成局域网地址; - 进行路由判断:
- 如果 目的地址 为本机地址
local_address,则进行包过滤; - 如果 目的地址
dst不为本机地址local_address,则准备进行 数据包转发,经过filter表中Forward链的规则匹配后,如果允许对 目的地址dst进行转发,则进行包转发; - 通过
Nat表中PostRouting链的规则查看当前数据包的转发是否要做SNAT,处理完成后发出数据包。 - 值得注意的是,当数据包流入后,经过路由选择发现不是发给
Local的包,则会通过FORWARD链直接到达POSTROUTING链,而不会再走OUTPUT链。
- 如果 目的地址 为本机地址
- 首先对数据包进行
- 数据包流出:
- 当数据包从本机准备发出时,会先经过
Nat表的Output链进行规则检查; - 随后,会经过
Filter表的Output链进行规则检查; - 最后根据
Nat表中PostRouting链的规则查看当前数据包的发出是否要做SNAT,处理完成后发出数据包。
- 当数据包从本机准备发出时,会先经过
3️⃣ iptables 语法
iptables 命令的大致语法如下:
1 | iptables [-t TABLE] [COMMAND] [OPTIONS] |
3️⃣ nftables
nftables 是 Linux 新一代防火墙/包处理框架,底层仍然依托内核的 Netfilter hooks。可以把 nftables 理解为:同一套 Netfilter 的入口机制,但规则语言、组织方式、可维护性和性能更现代。
1️⃣ 为什么要有 nftables ?
iptables的历史包袱: 多工具割裂iptables体系里,IPv4、IPv6、ARP等由 不同工具 分别管理,维护成本高、规则分散。nftables用nft统一表达与管理,通过用不同 “地址族family” 区分协议栈。
- 入口链更灵活: 不再被固定链名限制
iptables的入口链基本是内置的,只能建 “自定义链” 并从内置链jump过去。nftables允许自定义基础链base chain,并显式绑定hook + priority + policy
- 大规则集更好维护: 用
set/map/vmap/concat把 “海量规则” 变成 “数据结构”。- 在
iptables里,一旦需要维护大量 “白名单IP、端口、网段、组合条件”,就需要不断追加规则:- 100 个
IP白名单 → 100 条规则 - 50 个
Port放行 → 50 条规则 - “不同来源网段 + 不同端口” 组合 → 规则爆炸
- 100 个
nftables的强项是把这些 “很多条 if-then” 收敛成 集合set/映射map来管理。
- 在
2️⃣ 表 Tables、链 Chains 、规则 Rules 三者联系
表 Tables
nftables 的 Table 不是 iptables 的 “固定四张表”,而是自己创建的命名空间,并且先通过 family 来表示处理的是什么类型的数据包,以下是 family 的类型:
ip:仅 IPv4ip6:仅 IPv6inet:IPv4 + IPv6 通用arp: ARPbridge:二层桥接帧netdev:更靠近网卡入口
链 Chains
基础链 base chain
自动绑定 Netfilter hook,会自动接住流量。
创建 自定义基础链 时,必须给出
type:filter/nat/route等;hook:input/forward/output/prerouting/postrouting;priority:同hook多链的执行顺序policy: 默认策略,可选但常用
1 | sudo nft add table inet firewall |
常规链 regular chain
不绑定 hook,不会自动触发,只能被 jump / goto 调用,用于拆分、复用规则。
规则 Rules
规则 rule 是一条 “匹配条件 + 动作” 的行为。
accept/drop/rejectdnat/snat/masqueradelog/counterjump/goto/return
3️⃣ nftable 的 set 、 map 以及 vmap
nftables 的 set 与 map 非常方便,这使得 “查找规则” 变成 “查表”。
set:只有 “元素集合”,用来做 成员测试(in/not in)map:是 “键 → 值” 的映射,用来做 查值vmap:特殊map,value不是普通数据而是verdict,用来做按条件分发执行路径。
1️⃣ set
set 适合于 成员测试,即判断某值是否属于集合。常发生以下场景:
IP白名单/黑名单(很多地址/网段)- 端口白名单(很多端口)
- 任何 “同一字段要匹配多个候选值” 的场景
命名 set
命名 set 是一个可复用、可更新的 “元素集合”。
最大价值在于:可以在 不替换规则 的情况下 更新集合内容,适合动态名单。
案例代码
1
nft add set inet firewall office_ips { type ipv4_addr; elements = { 10.0.0.0/8, 203.0.113.10 }; }
set office_ips:创建一个名为office_ips的集合对象type ipv4_addr:声明集合元素类型- 常见类型包括
ipv4_addr/ipv6_addr/inet_service/inet_proto/ether_addr等
- 常见类型包括
elements:集合的初始元素(可以是单IP,也可以是网段/CIDR)
如何在规则中使用
set1
ip saddr @office_ips tcp dport 22 acceptcounter drop
ip saddr @office_ips:源IPv4地址是否属于集合 office_ipstcp dport 22:端口条件counter drop:丢弃并计数,便于排障
匿名 set
直接写在规则里 { 22,80,443 }
缺点:想改集合就必须 “替换整条规则”。
set 存放区间 interval
如果希望集合能存 “范围/区间”(比如 192.0.2.0-192.0.2.255),创建时要加:
1 | nft add set inet firewall office_ips { type ipv4_addr\; flags interval\; } |
2️⃣ map/vmap
map / vmap 适合于 键值映射(查表):
map:key → value(查到的是普通值,用于后续继续判断/赋值等)vmap:key → verdict(查到的是动作:accept/drop/reject/jump…)
常见场景:
- 端口
port→ 策略/动作(22 放行、23 丢弃、80 放行…) - 协议
protocol→ 分发到不同链(TCP/UDP分别跳转到不同“子程序链”) - 把大量
if-else规则分支收敛成一条查表规则
命名 vmap
命名 vmap 是一个可复用、可更新的 “映射表(字典)”。
最大价值在于:把 “条件 → 动作” 的分支写成一张表,后续变更只需要改表的
elements,不用改规则结构。
- 案例代码:
1
nft add map inet firewall svc_map { type inet_service : verdict; elements = { 22 : accept, 23 : drop, 80 : accept }; }
svc_map:创建一个名为svc_map的映射表对象type inet_service : verdict:声明key/value类型inet_service:key是端口(22/80/443)verdict:value是动作(accept``/drop/reject/jump…)
elements:映射表内容(端口到动作的映射)
- 如何在规则中使用
vmap:1
tcp dport vmap @svc_map counter drop
tcp dport:取包的 目的端口 作为keyvmap @svc_map:查表,查到什么verdict就执行什么(accept或drop)counter drop:兜底策略(不在表里的端口会继续往下走,最终被丢弃并计数)重要行为: 如果
dport不在svc_map里,这条vmap规则不会产生verdict,会继续执行后续规则,因此通常需要一个兜底drop``/reject。
- 维护命名
vmap1
2
3nft add element inet firewall svc_map { 443 : accept }
nft delete element inet firewall svc_map { 23 : drop }
vmap 的“最强形态”:分发到不同链
1 | ip protocol vmap { tcp : jump tcp_packets, udp : jump udp_packets } |
- 入口规则只负责“分类”
tcp_packets/udp_packets子链里写各自细节(端口白名单、日志、限速、统计…)
4️⃣ iptables 与 nftables 的区别
| 特性 | iptables | nftables | 优势解读 |
|---|---|---|---|
| 统一管理 | iptables、ip6tables、arptables 等多个独立命令 | 统一使用 nft 一个命令 | 极大地简化了管理,一个规则集可同时处理 IPv4/v6。 |
| 语法 | 冗长,基于命令行参数 | 简洁、直观,类似编程语言 | 更易读、易写、易于脚本化。 |
| 性能 | 规则越多,遍历匹配越慢 | 利用 集合(sets)和映射(maps) 等高效数据结构,实现快速查找 | 在处理大量 IP 地址黑白名单时,性能优势极其明显。 |
| 规则更新 | 非原子性,修改时存在短暂的无防火墙状态 | 原子性(Atomic),所有规则作为一个整体进行更新,要么全部成功,要么全部失败 | 更安全、更可靠,杜绝了更新过程中的安全空窗期。 |
| 内核实现 | 在内核中有大量协议相关的代码 | 内核只提供一个通用的虚拟机,大部分逻辑在用户空间规则中实现 | 更简洁的内核代码,更少的内核 bug 可能性。 |
