Netfilter 钩子,就是嵌入 Linux 内核网络协议栈路径上的"钩子点"。当数据包经过时,内核会触发这些钩子点,允许你注册的自定义函数介入,对数据包进行检查、修改或丢弃等处理。
下面这张图可以帮助你更直观地理解这些钩子在网络协议栈中的位置:
网络协议栈
目的为本机
目的为转发
网络接口 (接收)
NF_INET_PRE_ROUTING
路由判断
NF_INET_LOCAL_IN
上层协议 (TCP/UDP)
NF_INET_FORWARD
NF_INET_POST_ROUTING
网络接口 (发送)
本地进程发出
NF_INET_LOCAL_OUT
📍 五大"关口":核心钩子详解
IPv4 协议族定义了 5 个标准的钩子点,贯穿了数据包收发的完整生命周期:
-
NF_INET_PRE_ROUTING(路由前)- 时机:数据包刚进入网络栈,在路由判决之前。
- 典型应用 :适合做目标地址转换(DNAT),比如根据目的IP/端口修改数据包。
-
NF_INET_LOCAL_IN(本地入站)- 时机:路由判决后,目标为本机,数据包将发往上层协议。
- 典型应用 :本机防火墙规则,如限制对SSH端口的访问。
-
NF_INET_FORWARD(转发)- 时机:路由判决后,目标为其他主机,数据包将被转发。
- 典型应用 :作为网关或路由器时,对经过流量进行过滤和管理。
-
NF_INET_LOCAL_OUT(本地出站)- 时机:本机进程发出的数据包,在第一次路由判决之后。
- 典型应用 :限制本机进程的对外访问,或做源地址转换(SNAT)。
-
NF_INET_POST_ROUTING(路由后)- 时机 :数据包即将离开网络接口,是离开主机前的最后一站,也是SNAT的最佳位置。
⚙️ 机制与交互:钩子如何工作
每个钩子点上可以注册多个处理函数。为保证调用顺序,引入了优先级的概念:
- 优先级 :Netfilter 执行钩子函数时,会 按
priority字段的数值从小到大依次调用 (priority越小,优先级越高)。例如,-200 的优先级就高于 0。 - 注册数据结构 (
nf_hook_ops) :内核模块使用此结构来注册钩子函数,其中就包含协议族(pf)、钩子点(hooknum)和优先级(priority)等关键信息。 - 常用优先级值 (Linux内核预定义)
-400:NF_IP_PRI_RAW(raw 表)-300:NF_IP_PRI_MANGLE(mangle 表)-200:NF_IP_PRI_CONNTRACK(conntrack)-100:NF_IP_PRI_NAT_DST(DNAT)-50:NF_IP_PRI_FILTER(filter 表)100:NF_IP_PRI_NAT_SRC(SNAT)
➕ 更多钩子:扩展与前沿
除了上述五大钩子,Netfilter 框架还包含几个重要的扩展钩子:
- Ingress Hook :位于
NF_INET_PRE_ROUTING之前,是数据包进入协议栈的第一道关卡 ,可以对流量进行早期过滤 。它按网络设备配置 ,而非全局,内核版本要求4.2+,且仅适用于 nftables。 - Egress Hook :位于
NF_INET_POST_ROUTING之后,是数据包离开内核前的最后一站 。它同样按网络设备配置 ,内核版本要求5.10+,也仅适用于 nftables。 - Bridge Hooks (br_netfilter) :当 Linux 被用作网桥时,
br_netfilter模块允许网桥流量"绕道"进入 IPv4/IPv6 的 Netfilter 钩子,从而实现所有流量的统一策略。 - 其他钩子 :例如
NF_INET_LOCAL_IN和NF_INET_LOCAL_OUT钩子可以根据地址族配置网络地址转换(NAT),而route类型的钩子则可以在 IP 头更改后触发新的路由查找。
🛠️ iptables 与 nftables:权限外的说明
这部分的细节属于工具如何使用的问题,我们快速过一下要点:
iptables中的表 :它是 Netfilter 钩子的用户态使用者。在 5 大钩子上注册了不同优先级、不同用途(filter,nat,mangle,raw)的规则。nftables的改进 :相比iptables,取消了预定义链 ,让用户显式创建链;并可以使用关键字 (如raw,filter)来设置优先级。- 创建
filter表基本链示例:nft add chain inet my_table my_input_chain { type filter hook input priority 0; policy drop; }
- 创建
🚀 eBPF 的介入
eBPF 可以在数据包处理路径的多个阶段 与 Netfilter 交互:在网卡驱动层 使用 XDP (eXpress Data Path) 进行最早期的处理 ,或使用 BPF_PROG_TYPE_NETFILTER 直接 替换传统的 Netfilter 钩子 进行快速决策,也可以从 conntrack 子系统中读取状态信息。
🔧 高级调试技巧
当规则不生效时,nft monitor trace 是一种 实时观察数据包匹配过程 的方法。例如,你可以这样追踪从特定 IP 发出的 ICMP 包:
bash
nft add rule ip filter INPUT ip saddr 192.168.1.100 icmp type echo-request meta nftrace set 1
sudo nft monitor trace
若想清除所有跟踪规则,可以使用:
bash
nft --check delete rule ip filter INPUT handle <X>
⚠️ 重要:br_netfilter 模块对数据包路径的影响
当 br_netfilter 内核模块被加载时,桥接的数据包处理路径会发生关键变化:
- 路径改变 :数据包会从
br_netfilter的钩子重新回到标准的 IPv4/IPv6 Netfilter 钩子进行处理。 - 后果 :这意味着,原本期望在桥接层(如
bridge族的PREROUTING)处理的规则,可能会因为路径改变而不再生效。
🔬 实战:iptables 与 nftables 链的优先级对照
下面的对照表可以帮助你更清晰地理解,当 iptables 和 nftables 规则共存时,它们在同一个 Netfilter 钩子点上的执行顺序:
| Netfilter 钩子点 | iptables 链 / 表顺序 (优先级由高到低依次执行) |
nftables 链名示例 (以 priority 数字标识, 数字越小优先级越高) |
|---|---|---|
NF_INET_PRE_ROUTING |
1. raw (PREROUTING) 2. mangle (PREROUTING) 3. nat (PREROUTING, DNAT) | my_prerouting_raw (prio -300) my_prerouting_mangle (prio -150) my_prerouting_nat (prio -100) |
NF_INET_LOCAL_IN |
1. mangle (INPUT) 2. filter (INPUT) | my_input_mangle (prio -150) my_input_filter (prio 0) |
NF_INET_FORWARD |
1. mangle (FORWARD) 2. filter (FORWARD) | my_forward_mangle (prio -150) my_forward_filter (prio 0) |
NF_INET_LOCAL_OUT |
1. raw (OUTPUT) 2. mangle (OUTPUT) 3. nat (OUTPUT) 4. filter (OUTPUT) | my_output_raw (prio -300) my_output_mangle (prio -150) my_output_nat (prio -100) my_output_filter (prio 0) |
NF_INET_POST_ROUTING |
1. mangle (POSTROUTING) 2. nat (POSTROUTING, SNAT) | my_postrouting_mangle (prio -150) my_postrouting_nat (prio 100) |
无论你使用的是 iptables 还是 nftables,它们最终都依赖底层的 Netfilter 钩子。