netfilter+iptable分析.docx
- 文档编号:3620329
- 上传时间:2022-11-24
- 格式:DOCX
- 页数:130
- 大小:2.09MB
netfilter+iptable分析.docx
《netfilter+iptable分析.docx》由会员分享,可在线阅读,更多相关《netfilter+iptable分析.docx(130页珍藏版)》请在冰豆网上搜索。
netfilter+iptable分析
(一)HOOK的实现
structlist_headnf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
1.Netfilter-IPv4中的HOOK
Netfilter模块需要使用HOOK来启用函数的动态钩接,它在IPv4中定义了五个HOOK(位于文件include/linux/netfilter_ipv4.h,Line39),分别对应0-4的hooknum。
/*IPHooks*/
/*Afterpromiscdrops,checksumchecks.*/
#defineNF_IP_PRE_ROUTING0
/*Ifthepacketisdestinedforthisbox.*/
#defineNF_IP_LOCAL_IN1
/*Ifthepacketisdestinedforanotherinterface.*/
#defineNF_IP_FORWARD2
/*Packetscomingfromalocalprocess.*/
#defineNF_IP_LOCAL_OUT3
/*Packetsabouttohitthewire.*/
#defineNF_IP_POST_ROUTING4
简单地说,数据报经过各个HOOK的流程如下:
数据报从进入系统,进行IP校验以后,首先经过第一个HOOK函数NF_IP_PRE_ROUTING进行处理;然后就进入路由代码,其决定该数据报是需要转发还是发给本机的;若该数据报是发被本机的,则该数据经过HOOK函数NF_IP_LOCAL_IN处理以后然后传递给上层协议;若该数据报应该被转发则它被NF_IP_FORWARD处理;经过转发的数据报经过最后一个HOOK函数NF_IP_POST_ROUTING处理以后,再传输到网络上。
本地产生的数据经过HOOK函数NF_IP_LOCAL_OUT处理后,进行路由选择处理,然后经过NF_IP_POST_ROUTING处理后发送出去。
•NF_IP_PRE_ROUTING(0)
数据报在进入路由代码被处理之前,数据报在IP数据报接收函数ip_rcv()(位于net/ipv4/ip_input.c,Line379)的最后,也就是在传入的数据报被处理之前经过这个HOOK。
在ip_rcv()中挂接这个HOOK之前,进行的是一些与类型、长度、版本有关的检查。
经过这个HOOK处理之后,数据报进入ip_rcv_finish()(位于net/ipv4/ip_input.c,Line306),进行查路由表的工作,并判断该数据报是发给本地机器还是进行转发。
在这个HOOK上主要是对数据报作报头检测处理,以捕获异常情况。
涉及功能(优先级顺序):
Conntrack(-200)、mangle(-150)、DNAT(-100)
•NF_IP_LOCAL_IN
(1)
目的地为本地主机的数据报在IP数据报本地投递函数ip_local_deliver()(位于net/ipv4/ip_input.c,Line290)的最后经过这个HOOK。
经过这个HOOK处理之后,数据报进入ip_local_deliver_finish()(位于net/ipv4/ip_input.c,Line219)这样,IPTables模块就可以利用这个HOOK对应的INPUT规则链表来对数据报进行规则匹配的筛选了。
防火墙一般建立在这个HOOK上。
涉及功能:
mangle(-150)、filter(0)、SNAT(100)、Conntrack(INT_MAX-1)
•NF_IP_FORWARD
(2)
目的地非本地主机的数据报,包括被NAT修改过地址的数据报,都要在IP数据报转发函数ip_forward()(位于net/ipv4/ip_forward.c,Line73)的最后经过这个HOOK。
经过这个HOOK处理之后,数据报进入ip_forward_finish()(位于net/ipv4/ip_forward.c,Line44)
另外,在net/ipv4/ipmr.c中的ipmr_queue_xmit()函数(Line1119)最后也会经过这个HOOK。
(ipmr为多播相关,估计是在需要通过路由转发多播数据时的处理)这样,IPTables模块就可以利用这个HOOK对应的FORWARD规则链表来对数据报进行规则匹配的筛选了。
涉及功能:
mangle(-150)、filter(0)
•NF_IP_LOCAL_OUT(3)
本地主机发出的数据报在IP数据报构建/发送函数ip_queue_xmit()(位于net/ipv4/ip_output.c,Line339)、以及ip_build_and_send_pkt()(位于net/ipv4/ip_output.c,Line122)的最后经过这个HOOK。
(在数据报处理中,前者最为常用,后者用于那些不传输有效数据的SYN/ACK包)经过这个HOOK处理后,数据报进入ip_queue_xmit2()(位于net/ipv4/ip_output.c,Line281)另外,在ip_build_xmit_slow()(位于net/ipv4/ip_output.c,Line429)和ip_build_xmit()(位于net/ipv4/ip_output.c,Line638)中用于进行错误检测;在igmp_send_report()(位于net/ipv4/igmp.c,Line195)的最后也经过了这个HOOK,进行多播时相关的处理。
这样,IPTables模块就可以利用这个HOOK对应的OUTPUT规则链表来对数据报进行规则匹配的筛选了。
涉及功能:
Conntrack(-200)、mangle(-150)、DNAT(-100)、filter(0)
•NF_IP_POST_ROUTING(4)
所有数据报,包括源地址为本地主机和非本地主机的,在通过网络设备离开本地主机之前,在IP数据报发送函数ip_finish_output()(位于net/ipv4/ip_output.c,Line184)的最后经过这个HOOK。
经过这个HOOK处理后,数据报进入ip_finish_output2()(位net/ipv4/ip_output.c,Line160)另外,在函数ip_mc_output()(位于net/ipv4/ip_output.c,Line195)中在克隆新的网络缓存skb时,也经过了这个HOOK进行处理。
涉及功能:
mangle(-150)、SNAT(100)、Conntrack(INT_MAX)
2.HOOK的调用
HOOK的调用是通过宏NF_HOOK实现的。
这里先调用list_empty函数检查HOOK点存储数组nf_hooks是否为空,为空则表示没有HOOK注册,则直接调用okfn继续处理。
如果不为空,则转入nf_hook_slow()函数。
nf_hook_slow()函数(位于net/core/netfilter.c,Line449)的工作主要是读nf_hook数组遍历所有的nf_hook_ops结构,并调用nf_hookfn()处理各个数据报。
下面说明一下NF_HOOK的各个参数:
•indev:
输入设备,收到数据报的网络设备net_device数据结构指针,即数据报到达的接口。
用于NF_IP_PRE_ROUTING和NF_IP_LOCAL_IN两个HOOK
•outdev:
输出设备,数据报离开本地所要使用的网络设备的net_device数据结构指针。
用于NF_IP_LOCAL_OUT和NF_IP_POST_ROUTING两个HOOK
•注意:
在通常情况下,在一次HOOK调用中,indev和outdev中只有一个参数会被使用
3.HOOK点的实现
对应于各个不同协议的不同HOOK点是由一个二维数组nf_hooks存储的(位于net/core/netfilter.c,Line47),具体的HOOK点则由数据结构nf_hook_ops(位于include/linux/netfilter.h,Line44)实现。
4.HOOK的注册和注销
HOOK的注册和注销分别是通过nf_register_hook()函数和nf_unregister_hook()函数(分别位于net/core/netfilter.c,Line60,76)实现的,其参数均为一个nf_hook_ops结构,二者的实现也非常简单。
nf_register_hook()的工作是首先遍历nf_hools[][],由HOOK的优先级确定在HOOK链表中的位置,然后根据优先级将该HOOK的nf_hook_ops加入链表;nf_unregister_hook()的工作更加简单,其实就是将该HOOK的nf_hook_ops从链表中删除。
(二)IPTables系统
1.表-规则系统
IPTables是基于Netfilter基本架构实现的一个可扩展的数据报高级管理系统,利用table、chain、rule三级来存储数据报的各种规则。
系统预定义了三个table:
•filter:
数据报过滤表(文件net/ipv4/netfilter/iptable_filter.c)
监听NF_IP_LOCAL_IN、NF_IP_FORWARD和NF_IP_LOCAL_OUT三个HOOK,作用是在所有数据报传递的关键点上对其进行过滤。
•nat:
网络地址转换表
监听NF_IP_PRE_ROUTING、NF_IP_POST_ROUTING和NF_IP_LOCAL_OUT三个HOOK,作用是当新连接的第一个数据报经过时,在nat表中决定对其的转换操作;而后面的其它数据报都将根据第一个数据报的结果进行相同的转换处理。
•mangle:
数据报修改表(位于net/ipv4/netfilter/iptable_mangle.c)
监听NF_IP_PRE_ROUTING和NF_IP_LOCAL_OUT两个HOOK,作用是修改数据报报头中的一些值。
2.表的实现
表的基本数据结构是ipt_table
•unsignedintvalid_hooks;这个位图有两个作用:
一是检查Netfilter中哪些HOOK对应着合法的entries;二是用来为ipt_match以及ipt_target数据结构中的checkentry()函数核算可能的HOOK。
•structipt_replace*table;的数据结构是被用户空间用来替换一个表的。
?
?
?
?
staticstructxt_tablepacket_filter={
.name="filter",
.valid_hooks=FILTER_VALID_HOOKS,
.me=THIS_MODULE,
.af=AF_INET,
};
#defineFILTER_VALID_HOOKS((1< (1< staticstructxt_tablenat_table={ .name="nat", .valid_hooks=NAT_VALID_HOOKS, .me=THIS_MODULE, .af=AF_INET, }; #defineNAT_VALID_HOOKS((1< (1< (1< staticstructxt_tablepacket_mangler={ .name="mangle", .valid_hooks=MANGLE_VALID_HOOKS, .me=THIS_MODULE, .af=AF_INET, }; #defineMANGLE_VALID_HOOKS((1< (1< (1< (1< (1< •ipt_table_info(位于net/ipv4/netfilter/ip_tables.c,Line86)是实际描述规则表的数据结构: 3.规则的实现 IPTables中的规则表可以在用户空间中使用,但它所采用的数据结构与内核空间中的是一样的,只不过有些成员不会在用户空间中使用。 一个完整的规则由三个数据结构共同实现,分别是: •一个ipt_entry结构,存储规则的整体信息; •0或多个ipt_entry_match结构,存放各种match,每个结构都可以存放任意的数据, 这样也就拥有了良好的可扩展性; •1个ipt_entry_target结构,存放规则的target,类似,每个结构也可以存放任意的数据。 下面将依次对这三个数据结构进行分析: i.存储规则整体的结构ipt_entry,其形式是一个链表 其成员如下: •`structipt_ipip;`: 这是对其将要进行匹配动作的IP数据报报头的描述,其定义于include/linux/netfilter_ipv4/ip_tables.h,Line122,其成员包括源/目的IP及其掩码,出入端口及其掩码,协议族、标志/取反flag等信息。 •`unsignedintnfcache;`: HOOK函数返回的cache标识,用以说明经过这个规则后数据报的状态,其可能值有三个,定义于include/linux/netfilter.h,Line23: #defineNFC_ALTERED0x8000//已改变 #defineNFC_UNKNOWN0x4000//不确定 另一个可能值是0,即没有改变。 •`u_int16_ttarget_offset;`: 指出了target的数据结构ipt_entry_target的起始位置,即从ipt_entry的起始地址到match存储结束的位置 •`u_int16_tnext_offset;`: 指出了整条规则的大小,也就是下一条规则的起始地址,即ipt_entry的起始地址到match偏移再到target存储结束的位置。 •`unsignedintcomefrom;`: 所谓的“backpointer”,据引用此变量的代码(主要是net/ipv4/netfilter/ip_tables.c中)来看,它应该是指向数据报所经历的上一个规则地址,由此实现对数据报行为的跟踪。 •`structipt_counterscounters;`: 说明了匹配这个规则的数据报的计数以及字节计数(定义于include/linux/netfilter_ipv4/ip_tables.h,Line100) •`unsignedcharelems[0];`: 表示扩展的match开始的具体位置(因为它是大小不确定的),当然,如果不存在扩展的match那么就是target的开始位置。 ii.扩展match的存储结构ipt_entry_match 其中描述match大小的`u_int16_tmatch_size;`,从涉及这个变量的源码看来,在使用的时候需要注意使用一个宏IPT_ALIGN(位于include/linux/netfilter_ipv4/ip_tables.h,Line445)来进行4的对齐处理(0x3&0xfffffffc),这应该是由于match、target扩展后大小的不确定性决定的。 在结构中,用户空间与内核空间为不同实现,内核空间中的描述拥有更多的信息。 在用户空间中存放的仅仅是match的名称,而在内核空间中存放的则是一个指向ipt_match结构的指针。 其中几个重要成员: •`int(*match)(……);`: 指向用该match进行匹配时的匹配函数的指针,match相关的核心实现。 返回0时hotdrop置1,立即丢弃数据报;返回非0表示匹配成功。 •`int(*checkentry)(……);`: 当试图插入新的match表项时调用这个指针所指向的函数,对新的match表项进行有效性检查,即检查参数是否合法;如果返回false,规则就不会被接受(譬如,一个TCP的match只会TCP包,而不会接受其它)。 •`void(*destroy)(……);`: 当试图删除一个使用这个match的表项时,即模块释放时,调用这个指针所指向的函数。 我们可以在checkentry中动态地分配资源,并在destroy中将其释放。 例子: mac_mt_reg staticstructxt_matchmac_mt_reg={ .name="mac", .revision=0, .family=NFPROTO_UNSPEC, .match=mac_mt, .matchsize=sizeof(structxt_mac_info), .hooks=(1< (1< .me=THIS_MODULE, }; iii.扩展target的存储结构ipt_entry_target structxt_entry_target { union{ struct{ __u16target_size; /*Usedbyuserspace*/ charname[XT_FUNCTION_MAXNAMELEN-1]; __u8revision; }user; struct{ __u16target_size; /*Usedinsidethekernel*/ structxt_target*target; }kernel; /*Totallength*/ __u16target_size; }u; unsignedchardata[0]; }; 而target的实际使用中,是用一个结构ipt_standard_target专门来描述,这才是实际的target描述数据结构(位于include/linux/netfilter_ipv4/ip_tables.h,Line94),它实际上就是一个ipt_entry_target加一个verdict。 其中成员verdict这个变量是一个很巧妙的设计,也是一个非常重要的东东,其值的正负有着不同的意义。 我没有找到这个变量的中文名称,在内核开发者的新闻组中称这个变量为“amagicnumber”。 它的可能值包括IPT_CONTINUE、IPT_RETURN以及前文所述的NF_DROP等值,那它的作用是什么呢? ? ? ? ? ? ? ? ••由于IPTables是在用户空间中执行的,也就是说Netfilter/IPTables这个框架需要用户态与内核态之间的数据交换以及识别。 而在具体的程序中,verdict作为`structipt_standard_target`的一个成员,也是对于`structipt_entry_target`中的target()函数的返回值。 这个返回值标识的是target()所对应的执行动作,包括系统的默认动作以及外部提交的自定义动作。 ••但是,在用户空间中提交的数据往往是类似于“ACCPET”之类的字符串,在程序处理时则是以`#defineNF_ACCEPT1`的形式来进行的;而实际上,以上那些执行动作是以链表的数据结构进行存储的,在内核空间中表现为偏移。 ••于是,verdict实际上描述了两个本质相同但实现不同的值: 一个是用户空间中的执行动作,另一个则是内核空间中在链表中的偏移——而这就出现了冲突。 ••解决这种冲突的方法就是: 用正值表示内核中的偏移,而用负值来表示数据报的那些默认动作,而外部提交的自定义动作则也是用正值来表示。 这样,在实际使用这个verdict时,我们就可以通过判断值的正负来进行相应的处理了。 •位于net/ipv4/netfilter/ip_tables.h中的函数ipt_do_table()中有一个典型的verdict使用(Line335,其中v是一个verdict的实例): if(v! =IPT_RETURN){ verdict=(unsigned)(-v)-1; break; } 其中的IPT_RETURN定义为: #defineIPT_RETURN(-NF_MAX_VERDICT-1) 而宏NF_MAX_VERDICT实际上就是: #defineNF_MAX_VERDICTNF_REPEAT 这样,实际上IPT_RETURN的值就是-NF_REPEAT-1,也就是对应REPEAT,这就是对执行动作的实际描述;而我们可以看到,在下面对verdict进行赋值时,它所使用的值是`(unsigned)(-v)-1`,这就是在内核中实际对偏移进行定位时所使用的值。 一个完整的规则由三个数据结构共同实现,分别是: 1个ipt_entry,0或多个ipt_entry_match,1个ipt_entry_target 从上图中不难发现, match的定位如下: •起始地址为: 当前规则(起始)地址+sizeof(structipt_entry); •结束地址为: 当前规则(起始)地址+ipt_entry->target_offset; •每一个match的大小为: ipt_entry_match->u.match_size。 target的定位则为: •起始地址为match的结束地址, 即: 当前规则(起始)地址+ipt_entry->target_offset; •结束地址为下一条规则的起始地址, 即: 当前规则(起始)地址+ipt_entry->next_offset; •每一个target的大小为: ipt_entry_target->u.target_size。 这些对于理解match以及target相关函数的实现是很有必要明确的。 同时,include/linux/netfilter_ipv4/ip_tables.h中提供了三个“helperfunctions”,可用于使对于entry、tartget和match的操作变得方便,分别是: •函数ipt_get_target(): Line274,作用是取得target的起始地址,也就是上面所说的当前规则(起始)地址+ipt_entry->target_offset; •宏IPT_MATCH_ITERATE(): Line281,作用是遍历规则的所有match,并执行同一个(数 中)给定的函数。 其参数为一个ipt_entry_match结构和一个函
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- netfilter iptable 分析