关于Netfilter的五个钩子的思考
前言
我是卖钩子起家的。 —朱八八
近期项目有个需求,要修改之前的NAT
规则,实现新的NPTv6
转换协议(有空再写篇NPTv6转换器的博文吧),于是就是看之前的实现原理,过了一遍整个框架的大致处理逻辑,发现之前的实现上和Linux
内核那套实际也差不多,也是在项目自己实现的netfilter
上处理的,而自己实现的这个netfilter
感觉和内核的实现也是大差不差,实际一些细节上可能有所出入,但是基本的几个钩子过程上的处理好像都差不多了。
Netfilter
之前就知道netfilter
,也知道有钩子(hooks)这个东西,但是它具体是干什么的却不是很清楚。
定义:netfilter
是 Linux 内核中一套用于处理网络数据包的“框架”。
Netfilter 框架体现
组成部分 | 说明 |
---|---|
钩子点定义 | 内核中明确了协议栈的关键位置插入处理逻辑的位置(5 个) |
nf_hook_ops |
提供注册钩子函数的标准接口 |
链式处理机制 | 所有注册函数被串联执行,每个函数可决定包的命运 |
内核模块(如 ip_tables) | 实现具体的逻辑、策略规则(如 NAT、防火墙) |
Netfilter
是内核网络协议栈中的钩子机制框架,它在数据包流经的关键路径埋设了钩子点(锚点),开发者或用户通过内核模块(如 iptables
、nftables
)在这些点上注册处理逻辑,用户空间工具通过规则配置间接控制这些逻辑,实现包过滤、NAT、流控等功能。
可以把协议栈想象成一条流水线,而 Netfilter 就是在流水线上开了几个窗口(锚点),你可以通过这几个窗口:
- 观察包(LOG)
- 拦截包(DROP)
- 放行包(ACCEPT)
- 修改包(SNAT/DNAT)
- 标记包(MARK)
用户态可以告诉这些窗口要干啥(规则),而真正干活的是挂在窗口上的内核模块(处理逻辑)
钩子点
1 | 用户态应用 |
内核里的钩子定义include/linux/netfilter_ipv4.h
1 | enum nf_inet_hooks { |
① NF_INET_PRE_ROUTING
(0)
时机:数据包刚到达网络接口,在进入本地协议栈、做路由判断之前。
用途:
- 修改目标地址(DNAT)
- 早期丢包
- 检查来源合法性(如源地址过滤)
常用表/链:
raw
表nat
表中的PREROUTING
链mangle
表的PREROUTING
② NF_INET_LOCAL_IN
(1)
时机:数据包已经确认是要发往本机的,准备进入用户空间处理前。
用途:
- 本地防火墙过滤(例如允许某些端口)
- 最后机会拦截入站包
常用表/链:
filter
表的INPUT
链mangle
表的INPUT
③ NF_INET_FORWARD
(2)
时机:包不是发往本地,而是要转发出去,比如路由器场景。
用途:
- 转发规则控制(启用路由功能时)
- 防火墙控制通过主机的转发流量
常用表/链:
filter
表的FORWARD
mangle
表的FORWARD
④ NF_INET_LOCAL_OUT
(3)
时机:包是本机用户进程生成的,还没经过路由判定。
用途:
- 修改或拦截本机发出的数据包
- 阻止某些进程发送数据
常用表/链:
raw
表的OUTPUT
filter
表的OUTPUT
nat
表的OUTPUT
⑤ NF_INET_POST_ROUTING
(4)
时机:包已经确定路由(无论来自本地还是转发),马上要发出去了。
用途:
- 修改源地址(SNAT)
- 最后阶段处理出站包
常用表/链:
nat
表的POSTROUTING
mangle
表的POSTROUTING
总结表格
钩子点名 | 时机 | 典型用途 | 涉及表/链 |
---|---|---|---|
PRE_ROUTING (0) | 包一到就触发 | DNAT、防火墙、QoS | raw , mangle , nat |
LOCAL_IN (1) | 确定是发往本机 | 防火墙过滤入站流量 | filter , mangle |
FORWARD (2) | 包需要转发 | 控制路由流量 | filter , mangle |
LOCAL_OUT (3) | 本机发出的包 | 本地防火墙、拦截 | raw , filter , nat |
POST_ROUTING (4) | 发出去前最后一步 | SNAT、标记出站包 | mangle , nat |
钩子与协议栈
有个问题,钩子和协议栈有啥关系呢?是属于协议栈里面的东西?还是剥离出协议栈的?
实现角度
Netfilter 是嵌入在协议栈中的“钩子机制”
✅ 钩子点确实是协议栈中的一部分,嵌在协议栈各个关键函数中。
举个真实例子(来自内核源码,以 IPv4 为例):
1 | c复制编辑// linux/net/ipv4/ip_input.c |
这说明:
- 数据包刚到内核,就先走了
NF_INET_PRE_ROUTING
钩子(这一步属于 Netfilter)。 - 如果没有被丢弃/处理掉,再继续走
ip_rcv_finish()
进入协议栈真正的 IP 层处理。
类似的钩子在 ip_forward()
、ip_output()
、ip_local_deliver()
等函数中也有嵌入。
👉 所以这些钩子是 直接嵌入在协议栈处理流程里的函数调用点。
架构设计
Netfilter 是“协议栈的扩展机制”
虽然代码嵌在协议栈中,但从架构上,Linux 把 Netfilter 视作一个插件式的包处理框架 —— 类似于协议栈的“扩展点”。
这有几个关键特性:
特性 | 说明 |
---|---|
协议无关设计 | Netfilter 支持 IPv4、IPv6、桥接、甚至子系统如 Bluetooth |
插件式钩子注册机制 | 外部模块(如 iptables)通过 nf_register_net_hook() 动态插入逻辑 |
可以不使用 | 若未加载 ip_tables 或未配置规则,这些钩子点不会做任何事,性能无损 |
与协议实现解耦 | 钩子点与核心协议处理逻辑(如 TCP/IP stack)互不干扰,遵循 SRP(单一职责) |
总结
类比 | 协议栈 | Netfilter |
---|---|---|
高速公路 | 网络协议栈 | 是道路上的“收费站/监控卡口” |
主干函数 | ip_rcv() 、ip_forward() 等 |
在中间插入了 nf_hook() 调用 |
是否属于协议栈 | ✅ 是 | ✅ 属于,是内核网络协议处理逻辑的一部分 |
Netfilter 的钩子点本质上属于协议栈的组成部分,嵌在网络协议栈的数据路径中,但它通过模块化的机制把协议栈处理“开放出来”,让其他模块可以动态插入处理逻辑。
内核态
从之前与协议栈的关系其实也能看出netfilter
其实是属于内核态的东西了。
模块 | 所属空间 | 说明 |
---|---|---|
Netfilter 本身 | ✅ 内核态 | 在协议栈中嵌入,C 语言实现,运行在 Ring 0 |
iptables/nftables 工具 | ❎ 用户态 | 控制命令/规则编辑器,用于设置规则 |
netlink/socket 接口 | 通信桥梁 | 用户态和内核态之间的数据通道 |
iptables
定义
iptables
是一个用户态命令行工具,用来配置 Linux 内核中的 Netfilter 子系统。
你可以用它来定义防火墙规则,例如:
- 放行/拦截某个端口的包
- 做 NAT 转换
- 标记流量
- 日志记录等
⚠️ 注意:iptables 自身不处理包,它只是告诉内核该怎么处理包。
四表五链
🔷 表(tables):定义你要做什么类型的操作
表名 | 用途 | 常见链 |
---|---|---|
filter |
默认表,做包过滤 | INPUT , OUTPUT , FORWARD |
nat |
做 NAT(SNAT, DNAT) | PREROUTING , POSTROUTING , OUTPUT |
mangle |
修改包(TTL, TOS, MARK) | 所有 5 条链都支持 |
raw |
跳过连接跟踪(conntrack)等 | PREROUTING , OUTPUT |
🔗 链(chains):对应 Netfilter 的钩子点
链名 | 时机 | 对应钩子 |
---|---|---|
PREROUTING |
包刚到达接口 | NF_INET_PRE_ROUTING |
INPUT |
发往本机 | NF_INET_LOCAL_IN |
FORWARD |
要转发的包 | NF_INET_FORWARD |
OUTPUT |
本机发出的包 | NF_INET_LOCAL_OUT |
POSTROUTING |
包要发出去了 | NF_INET_POST_ROUTING |
nftables
定义
nftables
(简称 nft
)——这是 iptables
的“继任者”,也是 Linux 网络包过滤的现代工具。
nft
是 Linux 防火墙的新一代用户态工具,配置内核中的 Netfilter 子系统,替代iptables
、ip6tables
、arptables
和ebtables
。
对比
特性 | iptables |
nftables |
---|---|---|
配置工具 | iptables 、ip6tables |
一个统一的:nft |
表和链结构 | 每种功能一套表 | 所有功能合一,结构更统一 |
表达式语法 | 基于命令行参数拼接 | 类似脚本语言,结构清晰 |
性能 | 较低,线性匹配规则 | 内核中是状态机匹配,效率高 |
可扩展性 | 差,新功能要补模块 | 高,很多特性通过扩展字段即可支持 |
状态和计数支持 | 有限 | 强大,可组合条件、使用映射等 |
支持 IPv4+IPv6 合并规则 | ❌ | ✅ 一条规则支持两者 |
状态机与性能优化
nft 在内核中用的是 BPF-style 的规则状态机(不像 iptables 的链式匹配),这意味着:
- 规则可跳转、组合、复用,性能更高
- 支持高级数据结构:集合、映射、计数器
- 动态添加规则不会阻塞主规则集,适合高并发环境
使用
1 | sudo nft list ruleset |
示例:
1 | table inet my_table { |
从现实来看它的表规则也更加清楚了
1 | 一个命名空间: |
UFW与firewalld
往事重提
其实认识iptable
最初是通过firewalld
认识的,相信每个人用红帽系的云服务都会遇到服务不通然后研究如何用firewalld
开放端口的经历吧。换到ubuntu
上面,想用命令firewalld
的命令开放端口,结果又发现没这个东西了,研究一下才知道ubuntu
是用ufw
,当时好像是搜索的时候才知道原来ufw
也就是iptables
的一个前端,按照这个思路再一搜,果然firwalld
也是基于iptables
实现的啊。
ufw
✅ ufw
的核心功能
ufw
是一个简化的命令行防火墙工具,旨在使防火墙配置更加简单,尤其适合不熟悉 iptables
或 nftables
的用户。它默认使用 iptables
(或在支持的系统中,nft
)来管理网络规则。
- 简化规则管理:
ufw
提供了非常简单的命令来添加、删除、列出和管理规则。 - 适用于桌面和服务器:尤其适合桌面环境,但也可以用于服务器。
✅ ufw
与 iptables
的关系
ufw
实际上是iptables
的一个前端工具,通过简单的命令来配置复杂的防火墙规则。ufw
会生成相应的iptables
规则并将它们添加到iptables
中,因此所有的规则最终都是由iptables
(或nft
)来执行。
例如,当你运行 ufw allow 22
时,ufw
会在后台生成类似于以下的 iptables
规则:
1 | iptables -A INPUT -p tcp --dport 22 -j ACCEPT |
✅ ufw
与 nft
的关系
- 在支持
nftables
的系统上,ufw
会自动切换到nft
,并使用nft
来配置防火墙规则。 - 在现代的 Linux 发行版上,
ufw
会检测系统是否支持nftables
,如果支持,它将自动使用nft
进行管理。
firewalld
✅ firewalld
的核心功能
firewalld
是一个动态管理防火墙规则的工具,广泛用于 CentOS、RHEL、Fedora 等发行版中。它提供了一种区域化(zone-based)防火墙策略,并且能通过命令行或图形界面进行动态配置。
- 区域管理:
firewalld
将网络接口和服务划分为不同的区域,每个区域有不同的防火墙规则。 - 动态调整:不同于
iptables
,firewalld
支持实时更改防火墙规则而不需要重启防火墙服务。
✅ firewalld
与 iptables
的关系
firewalld
是iptables
的封装器,提供了一个更友好的界面来操作iptables
规则。firewalld
内部使用nftables
(如果系统支持) 或iptables
来实际执行规则配置,依赖于系统的内核模块。- 在
firewalld
配置的背后,实际上运行的是iptables
或nft
,因此最终的规则是通过这些工具来应用的。
✅ firewalld
与 nft
的关系
firewalld
在支持nft
的系统中,默认会使用nft
来配置和管理规则。firewalld
通过对nftables
(或iptables
)的封装来动态管理防火墙规则。
对比
特性 | ufw |
firewalld |
---|---|---|
目标用户 | 简单易用,面向桌面和服务器 | 更适合服务器,支持动态管理 |
配置方式 | 简单命令行,适合快速设置 | 动态管理,支持区域化配置 |
底层实现 | 依赖 iptables 或 nft |
依赖 iptables 或 nft |
动态规则支持 | 不支持动态修改 | 支持动态修改规则 |
配置语言 | 无(只需简单命令) | 基于区域/服务的配置系统 |
典型命令 | ufw allow , ufw deny |
firewall-cmd --zone=public --add-port=22/tcp |
conntrack
连接追踪(conntrack
) 是在 Netfilter 框架内实现的,并且它的创建和销毁并不是单纯地发生在某个特定的钩子过程中。它的工作是依赖于 Netfilter
的各个钩子点,但连接的状态管理和生命周期是与协议栈的处理过程紧密相连的。
连接追踪的基本工作流程
- 连接追踪的创建:当一个新的网络连接(例如,TCP 建立三次握手的初始 SYN 包)进入
Netfilter
时,连接追踪会在NF_INET_PRE_ROUTING
钩子点的早期阶段创建一个新的连接跟踪条目。它会基于包的元数据(源IP、目标IP、端口号、协议类型等)来判断是否需要建立新的连接条目。如果没有找到现有的条目,就会创建一个新的连接条目。 - 连接状态管理:
- 每当一个数据包通过
Netfilter
时,conntrack
会检查该数据包是否属于已知连接,或者是否需要为其创建一个新的连接追踪条目。 - 每个数据包在经过
Netfilter
处理时,都会被分配一个连接的“状态”,这些状态包括:NEW
:新的连接。ESTABLISHED
:已经建立的连接。RELATED
:与某个已存在连接相关联的流量。INVALID
:无效连接(如反向的 SYN 包)。
- 每当一个数据包通过
- 连接追踪的销毁:当连接的生命周期结束(如 TCP 会话的四次挥手结束或连接超时),连接追踪条目会被删除或标记为超时。在
NF_INET_POST_ROUTING
钩子阶段,某些数据包离开时,连接追踪可能会被更新或销毁。
具体的钩子点与连接追踪的关系
NF_INET_PRE_ROUTING
(数据包刚进入协议栈前)- 在这个阶段,连接追踪模块会检查数据包是否属于已有的连接,如果没有,且数据包是发起连接的第一个包(例如 TCP SYN),则会创建新的连接追踪条目。
NF_INET_LOCAL_IN
(本机接收的数据包)- 如果数据包是发往本机的,连接追踪会更新该数据包的连接状态。若是响应包(如 TCP ACK 包),连接追踪将确认该包属于已建立的连接。
NF_INET_FORWARD
(转发的数据包)- 如果数据包是转发的,连接追踪会根据原始源和目标地址判断该包是否属于已有连接,更新连接状态。
NF_INET_LOCAL_OUT
(本机发送的包)- 在这里,连接追踪会检查本机发出的包是否已经有对应的连接条目,若是响应包,则状态会更新。
NF_INET_POST_ROUTING
(包即将离开协议栈)- 当包离开系统时,连接追踪会完成最终的状态更新,若连接终止(如 TCP 四次挥手),对应的连接追踪条目会被销毁。
连接追踪与协议栈的关系
- 协议栈和连接追踪协作:虽然连接追踪是在
Netfilter
中实现的,它和协议栈是密切协作的。在协议栈处理过程中,连接的状态变化(如从SYN
到ESTABLISHED
)是由协议栈本身决定的,而连接追踪通过监控数据包流动来实时更新其连接条目。 - 协议栈层面上的连接:协议栈层面上的连接(如 TCP 连接)与连接追踪是紧密关联的。当协议栈处理连接(例如,TCP 握手时),它会向
Netfilter
注册状态,Netfilter
使用这些信息来维护连接追踪条目。因此,连接追踪是对协议栈连接状态的一种外部管理。
总结
- 连接追踪(
conntrack
)是在Netfilter
的钩子过程中创建和管理的,但它的生命周期和状态变化与协议栈的连接状态密切相关。 - 在每个钩子点,
Netfilter
都会查询或更新conntrack
条目,但连接的具体生命周期管理是与协议栈的状态机协作的。 - 连接追踪条目在包到达协议栈时创建,并在协议栈连接结束(例如 TCP 连接关闭)或超时后销毁。
conntrack工具
conntrack
工具是用于查看和管理 Linux 系统中 连接追踪表(Connection Tracking Table,简称 conntrack table)的工具。它是一个非常有用的工具,可以帮助我们诊断和调试网络连接,并且在 Netfilter
框架下提供连接追踪的管理和查询功能。
conntrack
工具 是 Netfilter 的一部分,用来查看和管理 连接追踪表(conntrack table
),这些表是由 Netfilter 在内核中维护的。conntrack
工具与iptables
和nftables
配合,提供连接状态跟踪和管理功能。iptables
和nftables
使用连接追踪表来决定是否允许数据包进入、离开或被拒绝。
总结
做点实际项目还是有提升自己对内核上的一些机制的了解,起码有个了解的契机和窗口了。但是感觉还是停在表面上,比如钩子具体在哪里起作用的,钩子是如何工作的,在协议栈上又是什么的行为,这些自己也就只有个大概印象,感觉还是要深入看一下内核源码,才能有些具体的了解。也要看工作上有没有这方面的安排了,有空闲时间更想看看Service Mesh
的东西,这个感觉还是感兴趣点,但是有点协议栈的知识的话对分布式网络也会有更好的认识吧/。