分类: 嵌入式
2016-06-01 13:45:29
版权声明:本文为博主原创文章,转载请注明出处。
基于linux2.6.21
上一节分析了ip层hook回调函数的注册以及调用流程,本节我们就开始分析每一个模块的具体实现。 工欲善其事必先利其器,一个功能模块的代码实现与其数据结构的设计有很大的关系,所以我们本节主要是分析table、rule、match、target相关的数据结构,争取本节能把数据结构的定义以及数据结构之间的关系分析明了。
在分析table、rule、match、target之前,先把它们之间的联系图贴出来,看了这个图以后,我们基本上就知道xt_table里rule、match、target之间的关联了。
总体框架图
对于一个xt_table表,通过其private指针,指向了xt_table_info结构,而xt_table_info中的entries指针数组的每一个指针成员指向xt_table表在相应cpu中的rule的首地址。
一个表中的所有rule在一个连续的内存块中,让所有rule在一个连续的内存块中,使对rule规则的遍历寻址成为了可能,因为一个规则相对于下一个规则并没有使用链表的形式连接在一起。
而一个完整的rule规则,包括了ipt_entry、ipt_entry_match、ipt_standard_target组成(其实ipt_entry就代表了一个规则,通过ipt_entry->elems即可找到该规则对应的match)。
下面我们一一分析上图提到的数据结构。
该结构体对应于iptables中的表,目前内核注册的table有filter、mangle、nat、raw表,而这些table根据pf值添加到xt_af[pf].tables链表中。而一个xt_table中包含了该表所支持的hook点与该表里已添加的所有rule规则。
上面分析xt_table时,我们只xt_table通过private指针指向了xt_table_info,xt_table_info里面包括了表中含有的规则,是表比较重要的结构体。
关于ipt_tale_info与ipt_table、ipt_entry的关系见上面的总体架构图。
下面我们分析下ipt_entry
对应的ipt_ip定义如下,其主要用于标准匹配
/*
标准匹配时的匹配条件
*/
一个ipt_entry的整体结构如上图。
我们使用到ipt_entry_match时,就说明这是一个扩展match,对于一个标准match是通过调用函数ip_packet_match,对ipt_entry->ip进行判断来实现的,只有扩展match才会使用该结构体在ipt_entry中添加一个ipt_entry_match变量。
match结构体,包括用户态与内核态联合体,通过这个联合体我们发现
只有match_size是共用的。当用户态需要添加新的规则时,对于新规则的
match,用户态只在ipt_entry_match.u.user.name中设置match的名称,而内核在添加规则时
就会根据ipt_entry_match.u.user.name在链表xt[af].match中查找符合要求的ipt_entry_match,当查找
到时就会对ipt_entry_match.u.kernel.match 进行赋值
ipt_entry_match相关的结构体图如下:
上图是一个ipt_entry_match与ipt_match以及一个ipt_match与xt_af[2].match之间的关联,当我们定义了一个xt_match(xt_match与ipt_match是同一个结构)时,需要将其插入到相应的xt_af[pf].match链表中。而当我们为一个rule规则添加一个扩展match时,根据ipt_entry_match.u.user.name查找xt_af[pf].match链表,当查找到相应的xt_match时,就将其地址赋值给ipt_entry_match.u.kernel.match(将该图与总体框架图搭配使用,就基本明了ipt_table、ipt_table_info、ipt_entry、ipt_entry_match、xt_match、xt_af[pf].match这几个数据结构之间的关系)。
而xt_match的定义如下:
如果我们想要添加一个扩展match,就要初始化一个xt_match结构,并且将插入到xt_af[pf].match链表
该结构体主要是对ipt_entry_target的封装,且增加了变量verdict。
这个verdict起到了很大的作用。
对于target,我们需要知道target有两大类,标准target与扩展target
a)对于标准target,其ipt_entry_target.u.kernel.target为NULL,其只需返回NF_ACCEPT/NF_DROP等操作。
b)对于扩展target,需要调用ipt_entry_target.u.kernel.target,执行扩展target操作,并根据返回值决定是否允许数据通行。
即扩展匹配是根据ipt_entry_target.u.kernel.target决定数据包下一步的执行操作,那标准匹配是根据什么决定数据包下一步的操作的呢?
答案就是verdict,当verdict为小于0时,则-verdict则为数据包下一步的执行操作;当verdict大于0时,则说明该target需要跳转到一个用户自定义链的链首地址,其值为用户自定义链相对于表的第一条链规则的偏移量。
基于以上,我们知道verdict的存在即指明了标准target的动作,又为用户链的存在并生效提供了可能。
虽然与ipt_entry_match定义相同,但是ipt_entry_target既可以表示一个标准target,也可以表示一个扩展target。当是一个标准的target时,其ipt_entry_target.u.kernel.target为NULL。
下面我们分析一下这个结构体:
/*
target结构体,包括用户态与内核态联合体,通过这个联合体我们发现
只有target_size是共用的。当用户态需要添加新的规则时,对于新规则的
target,用户态只在ipt_entry_target.u.user.name中设置target的名称,而内核在添加规则时
就会根据ipt_entry_target.u.user.name在链表xt[af].target中查找符合要求的ipt_standard_target,当查找
到时就会对ipt_entry_target.u.kernel.target 进行赋值
*/
ipt_entry_target相关的结构体图如下:
上图是一个ipt_entry_target与ipt_target以及一个ipt_target与xt_af[2].target之间的关联,当我们定义了一个xt_target(xt_target与ipt_target是同一个结构)时,需要将其插入到相应的xt_af[pf].target链表中。而当我们为一个rule规则添加一个扩展target时,根据ipt_entry_target.u.user.name查找xt_af[pf].target链表,当查找到相应的xt_target时,就将其地址赋值给ipt_entry_target.u.kernel.tagret(将该图与总体框架图搭配使用,就基本明了ipt_table、ipt_table_info、ipt_entry、ipt_entry_target、xt_target、xt_af[pf].target这几个数据结构之间的关系)。
xt_target的定义如下:
当我们想要添加一个扩展target,就要初始化一个xt_target结构,并且将插入到xt_af[pf].target链表
至此,基本上就把三层netfilter相关的数据结构一一介绍完了,综合以上分析,结合上面的结构关联图,就把结构体ipt_table、ipt_table_info、ipt_entry、ipt_entry_target、xt_target、xt_af[pf].target、xt_af[pf].match、xt_af[pf].tables、xt_match、ipt_ip之间的关联也介绍清楚了。至此,万事俱备,就差分析表的创建、初始化、添加规则、删除规则、遍历表规则、添加match、添加target等具体实现了。只要对数据结构之间的关系清楚了,分析这些功能的实现就顺理成章了。