[align=center][size=18pt]L[/size][size=16pt]inux-Netfilter&iptables[/size][font=宋体][size=16pt]实现机制的分析及应用[/size][/font][/align]
[align=center][font=宋体][size=16pt]by Minit<[email=tangwen1123@163.com]tangwen1123@163.com[/email]>[/size][/font][/align]
(pdf在7楼提供下载)
[size=16pt]1.
[font=宋体]引言[/font]
[size=3][font=宋体]本文分析了[/font]linux[font=宋体]下[/font]netfilter/iptables[font=宋体]的实现机制,主要集中于分析用户态与内核态之间规则的关系,以及在此基础上对用户规则的解析的生成,然后分析了扩展模块的实现原理,并介绍了如何写一个扩展模块。本文分析的内核源码为[/font]2.6.21.2[font=宋体],相应的[/font]iptables[font=宋体]程序的版本为[/font]1.3.7[font=宋体]。由于自身水平有限,且相关的参考资料较少,不能保证文中的分析结论一定正确,如果读者发现问题,望不吝与作者联系。[/font]
[/size]
[size=3]
[/size]
[size=3]2.
[font=宋体]用户态规则与内核态规则的关系[/font]
[font=宋体]在[/font]Netfilter/iptables[font=宋体]实现机制中,实际对数据包进行过滤的是内核态的规则,但为了用户能够对内核态的规则进行操作,需要将内核态的规则信息读取到用户空间,对用户空间的规则进行修改后,再根据用户态的规则信息设置内核态的规则信息。用户从内核态中获取规则信息的方式如图[/font]2-1[font=宋体]所示,在该图中表示了保存规则的结构[/font]--[font=宋体]表在用户态和内核态间的对应关系[/font].
[font=宋体]在内核态中,表[/font]ipt_table[font=宋体]中的[/font]private[font=宋体]成员指向的[/font]xt_table_info[font=宋体]保存了该表所管理的规则。用户通过[/font]getsockopt()[font=宋体]从内核态获取表的基本信息及规则内容,并将其保存在用户态中。[/font]
[font=宋体][size=12pt]在用户态中,表[/size][/font][size=12pt]iptc_handle_t[/size][font=宋体][size=12pt]保存了表管理的规则,在该结构中分别由[/size][/font][size=12pt]ipt_getinfo[/size][font=宋体][size=12pt]保存表的基本信息,由[/size][/font][size=12pt]ipt_get_entries[/size][font=宋体][size=12pt]保存表中的规则,在后面会对这些结构体进行详细介绍。为了便于用户对规则的操作,需要将表[/size][/font][size=12pt]iptc_handle_t[/size][font=宋体][size=12pt]内的规则信息由函数[/size][/font][size=12pt]parse_table()[/size][font=宋体][size=12pt]进行相应的处理,其会将规则按照链表形式分类存放,存放的格式如图[/size][/font][size=12pt]2-1[/size][font=宋体][size=12pt]所示,有关用户态中链和规则的结构会在后面介绍。[/size][/font]
[align=center][font=宋体][size=12pt][attach]232010[/attach][/size][/font][/align][font=宋体][size=12pt][font=宋体]当从内核态将表的内容读取到用户空间后,用户就可以对表的内容进行修改,如在表内添加、删除、修改自定义子链等,在已有链内添加、删除、修改规则等。当对表的内容修改完后就对这些内容进行相应处理,然后通过[/font]setsockopt()[font=宋体]更新内核态对应的表空间的内容。[/font]
[font=宋体]为了方便将用户态的表内容更新到内核态,需要对表内的所有规则进行相应的处理,函数[/font]iptcc_compile_table_prep()[font=宋体]主要计算表内链与规则对应的偏移值,然后将所有规则通过函数[/font]iptcc_compile_table()[font=宋体]添加到结构体[/font]ipt_replace[font=宋体]中。内核就是根据[/font]ipt_replace[font=宋体]的内容来更新其表空间的内容的,前面计算的偏移值主要是为了明确规则所处的位置。用户操作内核态表内容的计数值是通过[/font]ipt_counters_info[font=宋体]结构来进行通信的,内核根据从用户态传来的该结构体的值更新相应的内容。[/font]
[font=宋体]用户定制的命令由函数[/font]do_command()[font=宋体]处理,该函数会根据用户的需求修改表[/font]iptc_handle_t[font=宋体]的内容,当对表的内容进行修改后,会同步更新内核态表[/font]ipt_table[font=宋体]的内容,图[/font]2-2[font=宋体]表示了用户设置内核态规则的流程。[/font]
[align=center][font=宋体][attach]232011[/attach][/font][/align]
[/size][/font][/size]
[/size]
[ 本帖最后由 Minit 于 2009-6-11 14:36 编辑 ]
Minit 回复于:2009-06-11 10:20:04
3.
[font=宋体][size=5]用户态规则的管理[/size][/font]
[font=Wingdings][size=5]Ø[/size]
[/font][size=5][font=宋体]表的[/font][font=宋体]结构[/font][font=宋体]:[/font][/size][size=3][font=宋体]用户态中表结构[/font]iptc_handle_t[font=宋体]如下图[/font]3-1[font=宋体]所示,其中的[/font]info[font=宋体]指向[/font]ipt_getinfo[font=宋体]结构,[/font]entries[font=宋体]指向[/font]ipt_get_entries[font=宋体],这两个结构体的内容都是内核态传递过来的,其中[/font]ipt_get_info[font=宋体]保存了表的基本信息,[/font]ipt_get_entries[font=宋体]保存了该表所管理的规则信息,该结构中的[/font]entrytable[font=宋体]所指向的内存位置保存了所有的规则[/font]ipt_entry[font=宋体]。当在用户态中对表内容进行处理后,会把规则内容组织到链中保存,其中[/font]chains[font=宋体]指向了这些链。[/font]chain_iterator_cur[font=宋体]和[/font]rule_iterator_cur[font=宋体]分别指向了当前遍历到的链与规则。[/font][/size]
[size=3]iptc_handle_t[font=宋体]结构的内容实质上与内核态中表结构[/font]ipt_table[font=宋体]所表示的内容是一致的,只是其所存储的空间位置不一样。[/font][/size]
[align=center][attach]232012[/attach][/align]
[size=3][font=宋体][font=Wingdings][size=5]Ø[/size]
[/font][size=5][font=宋体]表中链的[/font][font=宋体]结构[/font][font=宋体]:[/font][/size]
[font=宋体]表[/font]iptc_handle_t[font=宋体]中的[/font]chains[font=宋体]指向该表所管理的所有链,每一个链用一个[/font]chain_head[font=宋体]结构保存,该结构体的内容如下图[/font]3-2[font=宋体]所示,有关该结构体内各个成员的具体作用在此就不做详细分析,其中[/font]counters[font=宋体]记录了该链的统计值,[/font]counter_map[font=宋体]主要表示了对该链的统计值的操作,其在向内核态中设置相应的统计值时起作用。变量[/font]rules[font=宋体]指向了该链所管理的所有规则,这些规则以链表的方式保存,一条规则用一个[/font]rule_head[font=宋体]结构保存。[/font][/font][/size]
[align=center][size=3][font=宋体][attach]232013[/attach][/align]
[font=宋体][font=Wingdings][size=5]Ø[/size]
[/font][size=5][font=宋体]链中规则的结构及遍历:[/font][/size][font=宋体]规则[/font]rule_head[font=宋体]的结构如下图[/font]3-3[font=宋体]所示,在一条规则中,[/font]chain[font=宋体]指针指向该规则所属的链,而[/font]jump[font=宋体]指针指向该规则将要跳向的其他链。[/font]iptcc_rule_type[font=宋体]表示了该规则所属的类型,如标准操作([/font]ACCEPT[font=宋体]、[/font]DROP[font=宋体]等)、扩展动作([/font]SNAT[font=宋体]等)以及跳向其他链等等类型。为了方便内核态与用户态的信息交互,需要在交互前对表的内容进行处理,处理中就利用了链以及规则中的[/font]index[font=宋体],[/font]offset[font=宋体]等变量值,有关处理的细节在此就不做详细分析。[/font][/font]
[align=center][font=宋体][attach]232014[/attach][/align]
[font=宋体][font=宋体]为了满足用户定制的策略,需要对表中的规则进行修改,这就需要实现对表中的规则的遍历,实现遍历的函数主要有:[/font]iptc_first_chain()[font=宋体]、[/font]iptc_next_chain()[font=宋体]、[/font]iptc_first_rule()[font=宋体]、[/font]iptc_next_rule()[font=宋体],通过这些函数可以找到表中的第一条链,当前链的下一条链,链中的第一条规则,当前规则的下一条规则。[/font]
[/font][/font][/font][/size]
[ 本帖最后由 Minit 于 2009-6-11 10:28 编辑 ]
Minit 回复于:2009-06-11 10:20:36
4.
[font=宋体][size=4]用户态规则的解析[/size][/font]
[size=3][font=宋体]用户定制的命令实际上是对[/font]iptc_handle_t[font=宋体]指向的表里面的内容的操作,如下图[/font]4-1[font=宋体]就表示了命令解析的流程,函数[/font]generate_entry()[font=宋体]会按照用户制定的规则匹配条件及相应动作生成一条规则[/font]rule_head[font=宋体],详细生成的流程会在下一节描述。在解析用户命令时,则根据用户指定的表、链及动作,对表的内容进行操作。如添加一条规则时,就会调用[/font]iptc_append_entry()[font=宋体]将规则[/font]rule_head[font=宋体]加到相应的链中去,[/font]iptc_delete_entry()[font=宋体]及[/font]iptc_insert_entry()[font=宋体]则实现对规则的删除与插入。[/font][/size]
[align=center][attach]232015[/attach][/align]
[size=3]
[/size]
[ 本帖最后由 Minit 于 2009-6-11 10:30 编辑 ]
Minit 回复于:2009-06-11 10:21:43
[size=4]5.
[font=宋体]用户态规则的生成[/font][/size]
[size=3][font=宋体]前面提到了在解析规则时,会将用户制定的匹配条件及动作转化为一条规则,转化的详细流程如下图[/font]5-1[font=宋体]所示。从图中可以看出,用户态中规则的存储方式与内核中规则的存储方式是一样的,都是顺序存储。标准匹配条件部分会放在[/font]ipt_entry[font=宋体]结构中,扩展匹配条件部分的转化相对较复杂,首先会调用函数[/font]find_match()[font=宋体]在全局链表[/font]iptables_matches[font=宋体]中查找相应的扩展模块,如果找到了就复制一个该扩展模块到链表[/font]matches[font=宋体]中,[/font]matches[font=宋体]实际上就保存了这条规则中指定的扩展匹配模块,这两个链表在后面讲述扩展模块时还会详细介绍。然后调用函数[/font]find_target()[font=宋体]设置该规则对应的动作,如果不是标准动作则需要查找全局链表[/font]iptables_targets[font=宋体],以找到该动作对应的[/font]iptables_target[font=宋体]。[/font][/size]
[size=3][font=宋体]当前面已经把规则的不同部分作了处理后,下一步就通过函数[/font]generate_entry()[font=宋体]将这些内容整合成一条规则,规则的开始部分标准匹配条件[/font]ipt_entry[font=宋体],然后将[/font]matches[font=宋体]指向的多个[/font]iptables_match[font=宋体]中的[/font]ipt_entry_match[font=宋体]结合在一起,形成规则的扩展匹配条件,最后根据前面处理的动作部分设置[/font]ipt_entry_target[font=宋体],形成规则的动作处理。动作处理中涉及到标准动作与扩展动作的不同处理,处理的具体细节在此不做详细分析。最后形成的规则如下图所示。[/font][/size]
[align=center][font=宋体][size=3][attach]232018[/attach][/size][/font][/align]
[ 本帖最后由 Minit 于 2009-6-11 10:33 编辑 ]
Minit 回复于:2009-06-11 10:22:33
[size=4]6.
[font=宋体]扩展模块[/font]
[/size][font=Wingdings][size=5]Ø[/size]
[/font][size=5][font=宋体]扩展匹配模块[/font][/size][size=3][font=宋体]扩展匹配模块的结构如图[/font]6-1[font=宋体]所示,在该结构中有一个变量[/font]m[font=宋体]指向匹配模块[/font]ipt_entry_match[font=宋体],该结构与内核态中的结构是一样的。用户态中的扩展匹配模块的存储与管理方式与内核态是相似的,模块的注册调用函数[/font]register_match()[font=宋体]实现,该函数将用户设定的[/font]iptables_match[font=宋体]模块添加到全局变量[/font]iptables_matches[font=宋体]指向的双向链表中,该链表如图[/font]6-2[font=宋体]所示。[/font][/size]
[size=3][font=宋体]在扩展匹配模块中定义了一些函数,这些函数主要用于处理跟该模块相关的规则,如其中[/font]parse()[font=宋体]主要处理与该模块相关规则的参数信息,该函数的使用在后面小节会涉及到,这些函数的具体细节,在此不做分析。[/font][/size]
[size=3]
[/size][font=宋体][size=3][/size][/font]
[align=center][attach]232019[/attach][/align]
[align=center][attach]232020[/attach][/align]
[font=Wingdings][size=5]Ø[/size]
[/font][size=5][font=宋体]扩展动作模块[/font][/size][size=3][font=宋体]扩展动作模块的结构如图[/font]6-3[font=宋体]所示,该结构与扩展匹配模块的结构相似,其由全局变量[/font]iptables_targets[font=宋体]指向的链表保存,链表的形式如图[/font]6-4[font=宋体]所示。[/font][/size]
[size=3]
[/size][align=center][attach]232021[/attach][/align][align=center][attach]232022[/attach][/align]
[ 本帖最后由 Minit 于 2009-6-11 10:37 编辑 ]
Minit 回复于:2009-06-11 10:23:19
[size=4]7.
[font=宋体]用户态与内核态之间参数的传递[/font]
[/size][size=3][font=宋体]在扩展模块中参数在用户态与内核态间的传递中,扩展模块的[/font]parse()[font=宋体]会首先将用户定制的匹配参数放置在用户空间的结构体[/font]ipt_XX_info(XX[font=宋体]表示扩展模块的名字,该命名法为通用的[/font])[font=宋体],[/font]ipt_XX_info[font=宋体]的内存位置与扩展模块中[/font]ipt_entry_match(ipt_entry_target)[font=宋体]的[/font]data[font=宋体]内存位置相同,故这两者实际保存用户空间中相同的内容。[/font][/size]
[size=3][font=宋体]当把扩展模块[/font]ipt_entry_match(ipt_entry_target)[font=宋体]的内容传到内核中后,提取内核中扩展模块的[/font]data[font=宋体]内容,并将其强制转化为内核空间的[/font]ipt_XX_info[font=宋体]类型的结构,这样的话,内核态的扩展模块就可以通过[/font]ipt_XX_info[font=宋体]结构获得用户设置的参数,然后就可以调用该模块的处理函数如[/font]match()([font=宋体]或[/font]target())[font=宋体]处理。图[/font]7-1[font=宋体]表示了以扩展匹配模块为例的参数传递过程。[/font][/size]
[align=center][font=宋体][size=3][attach]232023[/attach][/size][/font][/align]
[ 本帖最后由 Minit 于 2009-6-11 10:38 编辑 ]
Minit 回复于:2009-06-11 10:23:54
[size=4]8.
[font=宋体]扩展模块的应用[/font]
[/size][size=3][font=宋体]通过前面的描述,可以看出扩展一个匹配模块需要做的工作。下面以扩展匹配模块为例,扩展动作模块的操作类似,主要包括以下内容:[/font][/size]
[size=3][font=宋体]用户空间:[/font][/size]
[size=3](1).[font=宋体]定义一个[/font]iptables_match[font=宋体]模块并初始化相应的参数值,在模块的加载函数中调用[/font]register_match()[font=宋体]将[/font]iptables_match[font=宋体]模块注册到全局链表[/font]iptables_matches[font=宋体]中;[/font][/size]
[size=3](2).[font=宋体]定义用户态与内核态共用的数据结构[/font]ipt_XX_info[font=宋体],其主要用于交互数据;[/font][/size]
[size=3][font=宋体]内核空间:[/font][/size]
[size=3](1).[font=宋体]定义一个[/font]ipt_match[font=宋体]模块并初始化相应的参数值,在模块的加载函数中调用[/font]xt_register_match()[font=宋体]将[/font]ipt_match[font=宋体]模块注册到[/font]xt_af[font=宋体]的相应链表中;[/font][/size]
[size=3][font=宋体]当完成前面的工作后,就需要修改程序的编译文件及内核配置文件,以目前我分析的内核版本[/font]2.6[font=宋体]为例,则需要修改如下文件:[/font][/size]
[size=3](1).[font=宋体]在[/font]iptables/extensions/Makefile[font=宋体]文件的[/font]PF_EXT_SLIB[font=宋体]中新加模块名[/font]XX[font=宋体];[/font][/size]
[size=3](2).[font=宋体]在[/font]linux/net/ipv4/netfilter/Makefile[font=宋体]中新加一行:[/font]obj-$(CONFIG_IP_NF_MATCH_XX) += ipt_XX.o[/size]
[size=3]
(3).[font=宋体]在[/font]linux/net/ipv4/netfilter/Kconfig[font=宋体]中新加以下行:[/font][/size]
[size=3]
config IP_NF_XX[/size]
[size=3]
tristate "……"[/size]
[size=3]
depends on ……[/size]
[size=3]
help[/size]
[size=3]
…...[/size]
[size=3][/size]
[size=3]
To compile it as a module, choose M here.
If unsure, say N.[/size]
[size=3]
[font=宋体]完成以上步骤后,重新配置内核并选取该模块,编译后即可使用该扩展模块了。[/font][/size]
[size=3][/size]
[size=4]9.
[font=宋体]总结[/font]
[/size][size=3][font=宋体]本文主要目的是分析[/font]netfilter/iptables[font=宋体]实现机制的大框架,很多细节问题并未涉及到,希望通过此分析文档对进一步了解该机制提供帮助,并为使用该机制提供指导。由于自身水平有限,其中存在的问题望读者谅解并不吝指正。[/font][/size]
[ 本帖最后由 Minit 于 2009-6-11 14:35 编辑 ]
Linux-Netfilter&iptables实现机制的分析及应用.pdf
Godbach 回复于:2009-06-11 11:41:38
Minit 兄又出好文章了,有时间了认真学习一下。
dreamice 回复于:2009-06-11 12:00:34
又写新的了阿,强悍
emmoblin 回复于:2009-06-11 12:05:41
不错,能不能出个pdf?
谢谢了
jiangzj123 回复于:2009-06-11 13:57:57
好文,拜读一遍了
jiangzj123 回复于:2009-06-11 13:58:33
好文,拜读一遍了
Minit 回复于:2009-06-11 14:37:07
pdf在7楼提供下载。
希望大家多多交流哈~ 我又抛砖引玉来了。
Godbach 回复于:2009-06-11 16:29:29
引用:原帖由 Minit 于 2009-6-11 14:37 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=7039769&ptid=1117331]
pdf在7楼提供下载。
希望大家多多交流哈~ 我又抛砖引玉来了。
Minit兄谦虚了。应该说是对Netfilter和iptables的研究越来越深了。
scutan 回复于:2009-06-14 22:25:03
写得很好,学习了!
dolphin1987 回复于:2009-06-14 22:27:15
学习了,向伟大的minit致敬!
piginthetree 回复于:2009-06-16 10:19:45
:em09: CU就是牛人多啊
daizhongxian 回复于:2009-06-16 16:55:45
与天书无异!
DreamingCloud 回复于:2009-06-17 09:55:59
好文章。数据结构很清晰,非常有帮助。
DreamingCloud 回复于:2009-06-17 10:09:44
想起以前收藏过一篇 Netfilter实现机制分析,打开PDF一看,原来也是出自LZ之手。
ubuntuer 回复于:2009-06-17 17:47:35
不错不错...学习
jerrymy 回复于:2009-06-18 15:13:43
不得不看!
下了PDF好好研究。多谢了!:em10:
nyquist892004 回复于:2009-06-18 17:46:47
many thanks for your doc, it will be very helpful.
anders0913 回复于:2009-06-19 19:11:30
认真学习~~
cqm 回复于:2009-06-26 13:43:29
不得不看!谢谢楼主
arlikiss 回复于:2009-06-29 12:42:18
所以很方便,下吧!!!
可恶的 回复于:2009-07-04 13:24:38
http://iptables-tutorial.frozentux.net/cn/iptables-tutorial-cn-1.1.19.html
这里有一篇老文章,虽然是好多年以前的,但原理啥的还是一样的,比较详细。
感谢楼主分享。
Godbach 回复于:2009-07-04 14:49:08
恩,其实本版块独孤九贱兄的几篇精华帖,对分写Netfilter和iptables也有很好的指导意义。
s.t_seeyou 回复于:2009-07-04 21:59:18
学习了
ynchnluiti 回复于:2009-07-31 16:42:34
引用:原帖由 Godbach 于 2009-7-4 14:49 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=7058606&ptid=1117331]
恩,其实本版块独孤九贱兄的几篇精华帖,对分写Netfilter和iptables也有很好的指导意义。
赞同。看了很有收获。
sgcqh_82 回复于:2009-08-01 14:52:22
这个贴是好贴啊,收藏了
sgcqh_82 回复于:2009-08-01 15:07:32
太深奥。。看不懂:em02: :em02:
|