Chinaunix首页 | 论坛 | 博客
  • 博客访问: 318904
  • 博文数量: 49
  • 博客积分: 4045
  • 博客等级: 上校
  • 技术积分: 1195
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-15 12:56
文章分类

全部博文(49)

文章存档

2013年(29)

2010年(6)

2009年(6)

2008年(8)

我的朋友

分类: LINUX

2013-03-07 16:16:48

最近研究了一下Netfilter,也做个总结,总结中参考了几位大侠前面发表的文章:独孤九贱,Minit,godbach等,在此先谢谢大家!
文中有些内容是直接对上面几位的Copy,内中注明了出处,希望小小心得能对大家有所帮助!


目 录
1        前言        4
2        学习框架划分        5
3        钩子函数的注册管理        6
3.1        hook的存储机制        6
3.2        hook的管理机制        7
4        规则表的存储管理        8
4.1        规则表的存储机制        8
4.2        规则的遍历机制        15
4.3        规则表的管理        16
4.3.1        注册        16
4.3.2        查找        17
4.3.3        检测        18
4.3.4        替换        22
4.4        iptables的实现机制        22
4.4.1        命令格式        23
4.4.2        命令解析        23
4.4.3        获取内核规则表        27
4.4.4        按命令进行处理        33
4.4.5        规则表提交到内核        34
4.4.6        内核处理规则表        34
5        Netfilter执行流程        37
5.1.1        钩子函数和挂载点关系        37
5.1.2        执行中函数调用关系        37
6        参考文献        39


1        前言
本文的参考分析的源代码版本是2.6.15,我是边学习边总结,学习的过程中得益于Linux论坛()上大侠们总结分析的文档,他山之石可以攻玉,学习过程中我也会边学边总结,开源的发展在于共享,我也抛块砖,望能引到玉!
由于自身水平有限,且相关的参考资料较少,因此其中的结论不能保证完全正确,如果在阅读本文的过程中发现了问题欢迎及时与作者联系。也希望能有机会和大家多多交流学习心得!
        学习netfilter主要参考了Linux论坛几位大侠的文档,他们分别是:独孤九贱,Godbach,Minitab;文档中参考处或者引用处,我会用紫色注明;

2        学习框架划分
我把Netfilter学习分为三块:
?  钩子函数的注册管理;
?  规则表的存储管理;
?  Netfilter执行流程;
说明:
?  钩子函数的注册管理:
主要说明Netfilter钩子函数的挂载点,hook函数的保存机制,注册方式;
?  规则表的存储管理;
1.        主要描述规则表的存储机制,表,匹配,动作(table,match,target)三者之间的关系;
2.        规则表一些管理操作;
3.        用户态iptables的实现原理;
?  Netfilter执行流程;
通过ip报文的转发执行过程,描述netfilter的执行流,阐述netfilter钩子函数与规则表之间的联系,以及在Ip报文处理过程中的应用;这三块可以用一下图来简单描述:
图2.1 Netfilter的三部分关系.JPG
图2.1 Netfilter的三部分关系
3        钩子函数的注册管理
3.1        hook的存储机制
钩子函数由一个全局二维链表数组nf_hooks 保存,其按照协议族归类存储,在每个协
议族中,根据钩子点顺序排列,在钩子点内则根据钩子函数的优先级依次排列。钩子函数的
存储图如下图3-1所示,链表中的每个节点都是一个nf_hook_ops 结构,nf_hook_ops 实际存
储了钩子函数的内容,其结构如图3-2 所示。在相应的钩子点调用钩子函数时,则根据协议
族和钩子点找到相应的链表入口,然后依次调用该链中的每一个钩子函数对数据包进行操
作。
图3-1 钩子函数的全局存储.JPG
图3-1 钩子函数的全局存储
图3-2 钩子函数的链表.JPG
图3-2 钩子函数的链表
3.2        hook的管理机制
如果需要在相应的钩子点挂载钩子函数,则需要首先定义一个nf_hook_ops 结构,在其
中实现实际的钩子函数,再调用函数nf_register_hook()将该钩子函数注册到图3-1 所示的二
维链表中,nf_register_hook()函数的定义如下:
nf_register_hook.JPG

4        规则表的存储管理
4.1        规则表的存储机制
(以下内容参考: )
规则表(也可以叫规则集)在内核是顺序存储的,涉及到的结构体大概有这么几个:
ipt_table、ipt _table_info、ipt_entry、ipt_entry_matches、ipt_entry_target;这几个结构之间的包含关系如下图:
图4-1:规则集各个结构体之间的关系.JPG
图4-1:规则集各个结构体之间的关系
各个结构体具体内容如下:
1.        Struct ipt_table
Struct ipt_table.JPG

2.        struct ipt_table_info
struct ipt_table_info.JPG

3.        struct ipt_entry
struct ipt_entry.JPG

4.        struct ipt_entry_match
struct ipt_entry_match.JPG

5.        struct ipt_entry_target
struct ipt_entry_target.JPG

6.        struct ipt_match
struct ipt_match.JPG

7.        struct ipt_target
struct ipt_target.JPG
各个结构具体内容包含关系如下图:
图4-2 规则集结构体内容关系.JPG
图4-2 规则集结构体内容关系

在 Netfilter 中规则是顺序存储的,一条规则主要包括三个部分:ipt_entry、ipt_entry_matches、ipt_entry_target。ipt_entry_matches 由多个ipt_entry_match组成,ipt_entry结构主要保存标准匹配的内容,ipt_entry_match 结构主要保存扩展匹配的内容,ipt_entry_target 结构主要保存规则的动作。在ipt_entry 中还保存有与遍历规则相关的变量target_offset 与next_offset,通过target_offset 可以找到规则中动作部分ipt_entry_target 的位置,通过next_offset可以找到下一条规则的位置。规则的存储如下图4-3 所示:
图4-3 规则的存储.JPG
图4-3 规则的存储
ipt_entry 结构如下图4-4 所示,其成员ip 指向结构ipt_ip,该结构主要保存规则中标
准匹配的内容(IP、mask、interface、proto 等),target_offset 的值等于ipt_entry 的长度与
ipt_entry_matches 的长度之和,next_offset 的值等于规则中三个部分的长度之和。通过
target_offset与next_offset可以实现规则的遍历。
图4-4 ipt_entry结构.JPG
图4-4 ipt_entry结构
ipt_entry_match 主要保存规则中扩展匹配内容(tos、ttl、time 等),其是Netfilter 中内
核与用户态交互的关键数据结构,在其内核部分由一个函数指针指向一个ipt_match结构,
该结构体中包含了对包做匹配的函数,是真正对包做匹配的地方。ipt_entry_target 结构与
ipt_entry_match结构很类似。
图4-5 ipt_entry_match结构.JPG
图4-5 ipt_entry_match结构
图4-6 ipt_entry_target 结构.JPG
图4-6 ipt_entry_target 结构
4.2        规则的遍历机制
在 Netfilter 中,函数ipt_do_table()实现了规则的遍历(该函数的具体分析见5 Netfilter执行流程),这里主要针对遍历的几个关键点说明;
1.        查找到规则起点:
该函数根据传入的参数table 和hook找到相应的规则起点,即第一个ipt_entry的位置,主要通过函数get_entry()实现。
get_entry.JPG
2.        匹配每条规则,处理相应动作:
标准匹配是通过函数ip_packet_match()实现的,该函数主要对包的五元组信息进行匹
配,扩展匹配则通过宏IPT_MATCH_ITERATE 实现,该宏的定义分析如下:
IPT_MATCH_ITERATE.JPG
宏IPT_MATCH_ITERATE 依次调用各个ipt_entry_match所指向的ipt_match中match()处理数据包,在for 循环中使用了terget_offset位置变量查找match的位置。
在对数据包进行了匹配后,接着需要进行相应的动作处理,通过函数ipt_get_target()获取规则动作ipt_entry_target的位置:
ipt_entry_target.JPG
如果还需要继续遍历下一条规则,则继续执行以下语句以找到下一条规则的开始位置:
继续下一条.JPG

4.3        规则表的管理
4.3.1        注册
表,匹配,动作的注册函数分别是:ipt_register_table、ipt_register_match、ipt_register_target;他们的实现在在ip_tables.c中;
每一个表,匹配,动作的注册都是以单独模块来实现的,即如果用户定义一条新的规则,提交到内核中后,内核通过检查会发现,没有该项规则,则根据注册名字分别申请模块,分别进行相应的表,匹配,动作的创建;
如函数do_replace中的代码:
do_replace中的代码.JPG
上面三个注册函数实现比较简单,可以参考:

4.3.2        查找
规则集在内核中顺序存放,具体规则的查找是遍历规则集,通过匹配给定的关键字找到目标规则;函数find_match即实现该功能,源码如下:
find_match.JPG
其中list_for_each_entry是一个宏,具体定义如下:
list_for_each_entry.JPG

4.3.3        检测
检测主要有函数translate_table函数来完成,该函数源码分析如下:
translate_table 1.JPG
translate_table 2.JPG

该函数完成了两个功能:
1.        规则表的检查;检查分为两种:一种是基本检查(基本检测主要是基于IP报文五元组的检查),第二种是规则自身的检查,即通过宏IPT_ENTRY_ITERATE间接调用check_entry实现遍历检查每一个规则,check_entry源码如下:
check_entry.JPG
规则内容具体的检查包括两个方面:
1)        对每个匹配的检查,通过宏IPT_MATCH_ITERATE调用函数check_match;
2)        对动作进行检查,如果没有自定义的动作,则调用标准模板的检查函数standard_check;否则调用动作自身的检查函数t->u.kernel.target->checkentry;
下面具体分析下其中的宏IPT_MATCH_ITERATE和check_match:
IPT_MATCH_ITERATE源码分析见(4.2):

check_match源码分析:
check_match.JPG
函数translate_table在检查完毕后还做了一件事情:Hook_entries和underflows的复制,在函数:check_entry_size_and_hooks中完成该功能,而该函数是通过宏IPT_ENTRY_ITERATE间接调用;check_entry_size_and_hooks源码分析如下:
check_entry_size_and_hooks.JPG
4.3.4        替换
原理很简单,分两步:1. 获取老的规则集;2. 用给定的新规则集替换老的;
实现函数:replace_table,源码如下:
replace_table.JPG
阅读(680) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~