本文分析ip_queue的内核态源码。文中如有任何疏漏和差错,欢迎各位朋友指正。
本文大纲如下:
一、IP Queue的生效
二、网络层中IP报文进入IP Queue的流程
三、ip_queue代码分析
(一)数据结构的定义
(二)ip_queue模块的加载和卸载
(三)ip_queue报文入队处理函数的注册
(四)入队函数ipq_enqueue_packet —— 发送数据包到用户空间
(五)接收和处理用户空间的配置—— 接收用户空间的数据包
(六)数据包的终处理
一、IP Queue的生效
数据包能够进入ip_queue模块,需要两个动作:
(1)模块的加载:modprobe ip_queue
(2)NF上对数据包执行NF_QUEUE的动作,这个可以通过用户态配置一条iptables规则实现:
iptables -A INPUT -p tcp --dport 21 -j QUEUE
这里假设对发往本机的TCP报文端口为21的进行QUEUE。
有了以上两个步骤, 所有匹配到(2)中的报文将会调用IP Queue模块的相关函数。
二、网络层中IP报文进入IP Queue的流程
本文中分析的代码的内核版本为2.6.18.3.
这里我们以本地接收报文为例,如果是转发的报文,可比照着分析即可。
IP层接收报文的函数为:ip_rcv()(ip_input.c)。该函数对报文进行一些初步的检查后,就将报文交给PREROUTING Hook点注册的钩子函数处理:
由以上代码可见,报文经过钩子函数之后,由ip_rcv_finish()接着处理。该函数主要完成数据报文的路由查找。
如果是发往本地的报文,则会调用ip_local_deliver()函数:
该函数主要功能就是将报文交给NF_IP_LOCAL_IN hook点的钩子函数进行处理。我们在部分中添加的一条iptables规则就是对于经过INPUT链的TCP报文且目的端口21执行动作QUEUE。如果此时用户空间已经开启socket等待接收IP Queue报文的话,那么对应的报文就会进入用户空间,然后就可以参照我们之前提供的用户空间例程进行处理。
这里,我们简单列出在NF_IP_LOCAL_IN中NF_HOOK宏的调用函数过程:
NF_HOOK()->NF_HOOK_THRESH()->nf_hook_thresh()->nf_hook_slow()
当nf_hook_slow函数返回值为NF_QUEUE时,进一步调用nf_queue()。该函数对所有动作为QUEUE的报文进行处理,其中关键的一行代码如下:
这行代码就是将报文按照IP层的协议交给对应的queue handler。IPv4协议中注册的queue handler为ipq_enqueue_packet(),即我们要分写ip_queue模块的代码。
至此,需要QUEUE的报文已经走入了我们要分析ip_queue,我们下面就开始走入正题,分析ip_queue的代码。
--未完待续
文章来源CU社区:Linux内核IP Queue机制的分析(三)——ip_queue内核模块的分析