当前位置: 首页 > news >正文

Linux netfilter工作原理详解

1. Netfilter 工作原理深入分析

1.1 核心概念与定位

Linux netfilter 是一个位于 Linux 内核中的框架,它为数据包过滤、网络地址转换(NAT)和数据包修改等功能提供了基础设施。它本质上是在内核网络协议栈的关键路径上预置了一系列钩子点(Hook Points),允许内核模块在这些点上注册回调函数,从而对经过的数据包进行检查、修改或决策。

1.2 数据包流向与钩子点(Hook Points)

这是理解 netfilter 的核心。一个数据包在协议栈中的流动路径决定了它会经过哪些钩子点。下图清晰地展示了这一过程:

Netfilter Hook Points
NF_IP_PRE_ROUTING
路由前
NF_IP_LOCAL_IN
本地输入
NF_IP_FORWARD
转发
NF_IP_LOCAL_OUT
本地输出
NF_IP_POST_ROUTING
路由后
网络数据包抵达
路由决策
目的地址是本机?
上层协议
TCP/UDP/ICMP
用户空间进程
发送至外部网络
本地进程发出数据

5个关键的钩子点及其含义:

钩子点常量含义常见应用
NF_IP_PRE_ROUTING数据包刚进入协议栈,尚未进行路由决策raw 表(连接跟踪)、mangle 表、NAT 表(目标地址转换 DNAT)
NF_IP_LOCAL_IN数据包经过路由决策,目标是本机filter 表(INPUT 链)、mangle 表
NF_IP_FORWARD数据包经过路由决策,目标不是本机,需要转发filter 表(FORWARD 链)、mangle 表
NF_IP_LOCAL_OUT本机进程产生的数据包,刚进入协议栈。raw 表、mangle 表、NAT 表(源地址转换 SNAT on OUTPUT)
NF_IP_POST_ROUTING数据包即将离开协议栈,发送到网络设备之前mangle 表、NAT 表(源地址转换 SNAT)
1.3 表(Tables)与链(Chains)的组织结构

为了管理方便,netfilter 使用“表”和“链”的概念来组织规则。

  • 表(Table): 用于特定目的的规则的集合。不同的表在不同的钩子点上注册处理函数。
  • 链(Chain): 每个表内部又包含若干“链”,链直接对应到钩子点。规则被放置在某个表的特定链中。

表与钩子点的对应关系(核心关系表):

表 (Table)主要功能内置链 (Chains)优先级(生效顺序)
raw连接跟踪的预处理(NOTRACK)PREROUTING, OUTPUT最高 (-300)
mangle修改数据包(TOS、TTL、MARK等)ALL FIVE HOOKS(-150)
nat网络地址转换(SNAT, DNAT, MASQUERADE)PREROUTING, INPUT, OUTPUT, POSTROUTING(-100)
filter过滤数据包(Accept/Drop/Reject)INPUT, FORWARD, OUTPUT最低 (0)
security强制访问控制(SELinux)INPUT, FORWARD, OUTPUT(50)

数据包处理流程(以 PREROUTING 钩子为例):
当一个数据包到达 NF_IP_PRE_ROUTING 钩子点时,它会依次经过注册在该钩子点上的各个表的处理函数:
raw (PREROUTING) -> mangle (PREROUTING) -> nat (PREROUTING)

1.4 规则(Rules)与匹配(Matches)/目标(Targets)
  • 规则(Rule): 一条规则是“如果数据包满足XX条件,就执行YY动作”的语句。
  • 匹配(Match): 规则的条件部分。可以是IP、TCP、UDP等头部信息的匹配,也可以是更复杂的状态(state)、连接跟踪(conntrack)等匹配。
  • 目标(Target): 规则的动作部分。例如:
    • ACCEPT: 接受数据包,继续后续流程。
    • DROP: 丢弃数据包,无响应。
    • RETURN: 跳出当前链,返回上一级调用链。
    • JUMP: 跳转到用户自定义链。
    • SNAT / DNAT: 进行地址转换。
    • REJECT: 丢弃数据包并发送错误消息(如port-unreachable)。

2. 实现机制与代码框架

2.1 核心数据结构

(以下代码基于 Linux 5.x 内核)

  1. struct nf_hook_ops: 代表一个钩子操作。内核模块通过注册此结构来挂载到钩子点。

    struct nf_hook_ops {struct list_head list;       /* 内核使用:链表 *//* 钩子函数:返回 NF_ACCEPT, NF_DROP, NF_STOLEN, NF_QUEUE, NF_REPEAT */nf_hookfn *hook;struct net *net;             /* 所属网络命名空间 */int pf;                      /* 协议族:PF_INET for IPv4 */int hooknum;                 /* 钩子号:NF_INET_PRE_ROUTING 等 */int priority;                /* 优先级:决定在同一钩子点上的执行顺序 */
    };
    
  2. struct nf_hook_state: 包含钩子函数被调用时的状态信息(网络设备、协议族等)。

    struct nf_hook_state {unsigned int hook;u_int8_t pf;struct net_device *in;struct net_device *out;struct sock *sk;struct net *net;int (*okfn)(struct net *, struct sock *, struct sk_buff *);
    };
    
  3. struct sk_buff最重要的数据结构,代表一个内核中的网络数据包。钩子函数主要就是操作这个结构体。它包含了数据包的所有信息和数据。

  4. struct nf_conn: 代表一个连接跟踪条目。连接跟踪是NAT和状态防火墙的基础。

2.2 代码框架与执行流程

1. 钩子注册与调用:
内核在网络协议栈代码(如 ip_rcv, ip_forward_finish, ip_output 等函数中)调用 NF_HOOK 宏,从而进入 netfilter 框架。

// 例如在 ip_rcv 函数中(处理接收到的IP包)
return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,net, NULL, skb, dev, NULL,ip_rcv_finish);

NF_HOOK 宏会遍历所有注册在指定钩子点(NF_INET_PRE_ROUTING)和协议族(NFPROTO_IPV4)上的 nf_hook_ops,并根据其 priority 顺序依次调用它们的 hook 函数。

2. 表与规则的实现:
iptablesnftables 等用户空间工具只是用于配置 netfilter 规则的前端。它们最终通过 setsockopt 系统调用将规则传递给内核。
内核中,每个表(如 filter)实际上是一个包含多个链(如 INPUT)的集合,而每个链又包含一个规则列表。规则的核心是 ipt_entry 结构,它包含了匹配条件和目标动作。

简化的规则检查流程(以 filter 表的 INPUT 链为例):

unsigned int ipt_do_table(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{const struct ipt_entry *e;const struct xt_table *table = priv;// ... 获取 table 和对应的 chain .../* 遍历 chain 中的每一条规则 */for (; offset < size; offset += e->next_offset) {e = (void *)entry_base + offset;/* 对规则中的所有匹配条件进行判断 */if (!ip_packet_match(...)) {// 不匹配,跳到下一条规则continue;}/* 所有匹配都通过,执行目标的 target() 函数 */t = ipt_get_target(e);if (!t->target) { // 是标准目标(ACCEPT/DROP等)int v = ((struct ipt_standard_target *)t)->verdict;if (v < 0) { if (v == IPT_RETURN) { ... }return (unsigned int)(-v); // 返回 NF_ACCEPT/DROP 等}// ... 跳转到其他用户链 ...}// 执行扩展目标ret = t->target->target(skb, state);if (ret != XT_CONTINUE)return ret;}// 链的默认策略(Policy)return (unsigned int)(-jumpstack[stackptr]. verdict);
}

3. 简单应用实例:一个简单的防火墙规则

以下是一个使用 iptables 用户空间工具配置 netfilter 的简单例子。

目标:禁止所有外部主机 ping 本机(丢弃入站的 ICMP Echo Request 包)。

源码(iptables 命令):

# 1. 在 filter 表的 INPUT 链末尾添加一条规则
# -A INPUT: Append to INPUT chain
# -p icmp: Match ICMP protocol
# --icmp-type 8: Match ICMP Echo Request type
# -j DROP: Jump to DROP target
sudo iptables -A INPUT -p icmp --icmp-type 8 -j DROP# 2. 查看当前规则
sudo iptables -L INPUT -v --line-numbers# 预期输出:
# Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
# num   pkts bytes target     prot opt in     out     source               destination
# 1        0     0 DROP       icmp --  any    any     anywhere             anywhere             icmp echo-request# 3. 测试:从另一台机器 ping 本机,应该会超时(Request timeout),而本机 ping 外部仍然正常。

内核中发生了什么:

  1. 用户命令通过 setsockopt 系统调用将规则添加到内核的 filter 表的 INPUT 链中。
  2. 当一个 ICMP Echo Request 包从外部到达,经过协议栈,路由后发现目标是本机,它会进入 NF_IP_LOCAL_IN 钩子点。
  3. 内核依次调用注册在该钩子点上的处理函数(raw->mangle->nat->filter)。
  4. 当执行到 filter 表的 INPUT 链处理函数时,开始遍历其规则。
  5. 该数据包匹配到了我们添加的规则(-p icmp --icmp-type 8),于是执行目标动作 -j DROP
  6. 内核返回 NF_DROP,该数据包被丢弃,不会传递给上层协议(如 ping 进程),也不会产生任何回复。

4. 常用工具命令与 Debug 手段

4.1 工具命令
工具描述常用示例
iptables配置 IPv4 规则的传统工具iptables -L -v -n (查看规则)
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT (添加规则)
ip6tables配置 IPv6 规则iptables
nft新一代的配置工具,取代 iptablesnft list ruleset (查看所有规则)
conntrack查看和管理连接跟踪表conntrack -L (查看连接)
conntrack -D -s 1.2.3.4 (删除连接)
ss / netstat查看本地socket和连接状态ss -tuln (查看监听端口)
4.2 Debug 手段
  1. 日志(Log)

    # 添加一条记录日志的规则,通常放在感兴趣规则的前面
    sudo iptables -A INPUT -p icmp --icmp-type 8 -j LOG --log-prefix "ICMP-BLOCKED: " --log-level 4
    sudo iptables -A INPUT -p icmp --icmp-type 8 -j DROP# 查看内核日志
    tail -f /var/log/kern.log
    # 或
    dmesg -w
    

    你将会看到类似 ICMP-BLOCKED: IN=eth0 OUT= MAC=... SRC=192.168.1.100 DST=192.168.1.1 ... 的日志。

  2. 数据包追踪(Packet Tracing)
    Linux 内核提供了强大的 nftracextables-monitor 工具来跟踪数据包在 netfilter 中的完整路径。

    # 1. 启用跟踪(需要内核支持)
    sudo iptables -A INPUT -p icmp --icmp-type 8 -j TRACE# 2. 使用 xtables-monitor 查看实时跟踪信息
    sudo xtables-monitor --trace
    

    然后在另一台机器 ping 本机,你可以在 xtables-monitor 中看到该数据包经过每个链、每个规则时的详细决策过程。

  3. /procsysfs 文件系统

    # 查看连接跟踪表当前条目数/最大值
    cat /proc/sys/net/netfilter/nf_conntrack_count
    cat /proc/sys/net/netfilter/nf_conntrack_max# 查看各个链的规则计数和字节计数(iptables -L -v 的数据来源)
    cat /proc/net/ip_tables_names # 表名
    cat /proc/net/ip_tables_matches # 匹配模块
    cat /proc/net/ip_tables_targets # 目标模块
    
  4. iptables 详细模式

    sudo iptables -L -v -n --line-numbers
    

    -v 选项显示每个规则匹配的数据包和字节数,这对于判断规则是否生效至关重要。--line-numbers 显示行号,便于后续删除或插入规则。


总结

Linux netfilter 是一个强大而复杂的内核子系统,它通过钩子点、表、链、规则的多层抽象,实现了灵活的包处理功能。理解数据包的流向(五个钩子点)以及各表的优先级顺序是掌握其原理的关键。虽然直接使用内核代码进行开发很复杂,但通过用户空间的 iptables/nft 工具,我们可以轻松地配置出强大的防火墙和NAT网关。高效的 Debug 需要结合日志、计数器和跟踪工具来综合分析数据包的行为。

http://www.dtcms.com/a/346959.html

相关文章:

  • Spring Boot 整合网易163邮箱发送邮件实现找回密码功能
  • 数据库MVCC是什么
  • 每日算法题【链表】:链表的中间节点、返回倒数第k个节点、合并两个有序链表
  • Git checkout 与 Git reset 核心区别解析(分支与版本关联逻辑)
  • C语言初学者笔记【动态内存管理】
  • 在WSL2 Ubuntu中部署FastDFS服务的完整指南
  • Elasticsearch底层存储原理
  • Codeforces Round 1043 (Div. 3)(A-E)
  • 数据库优化提速(三)JSON数据类型在酒店管理系统搜索—仙盟创梦IDE
  • jetson ubuntu 打不开 firefox和chromium浏览器
  • 非线性规划学习笔记
  • SpringBootWeb入门
  • 力扣(全排列)
  • 生成模型 | 扩散模型损失函数公式推导
  • Go语言数据结构与算法-基础数据结构
  • 《WinRAR》 [7.12] [x64] 烈火版 下载
  • 数据结构的线性表:顺序表
  • piecewise jerk算法介绍
  • 2025年音乐创作大模型有哪些?国内国外模型汇总以及优点分析
  • 高阶数据结构---ST表
  • 同类软件对比(一):Visual Studio(IDE) VS Visual Studio Code
  • [CISCN2019 华北赛区 Day1 Web5]CyberPunk
  • MySQL存储过程入门
  • OCR、文档解析工具合集(下)
  • MySQL InnoDB引擎
  • STM32F1 SysTick介绍及应用
  • Nacos-12--扩展:@RefreshScope和@ConfigurationProperties实现热更新的原理
  • PHP - 线程安全 - 疑问与答案
  • springboot 表现层消息一致性处理:前后端数据协议
  • SpringMVC相关自动配置