2014年(5)
分类: LINUX
2014-03-29 23:02:11
netfilter框架概述。
Netfilter从英文角度可以理解为,“网络数据过滤”,其实理解为“网络数据处”理更为贴切。
Netfilter框架之所以能实现许多强大的功能,
通俗的讲,是因为它在内核若干网络转发的关键函数中,设计了许多巧妙的钩子函数(钩子实际上是一个链表,钩子函数是链表上的结点),比如数据转发,由两个主要函数A和B函数实现,流程为A->B ,现在改变为A->钩子函数->B。
专业的讲,Netfilter框架为每种网络协议()定义一套HOOK函数。这些HOOK函数在数据报经过协议栈的几个关键点时被调用(NF_IP_PRE_ROUTING (0),NF_IP_LOCAL_IN (1),NF_IP_FORWARD (2),NF_IP_LOCAL_OUT (3),NF_IP_POST_ROUTING (4)),在这几个点中,协议栈将数据报及HOOK函数标号作为参数,传递给Netfilter框架。对于它在网络堆栈中增加的这些HOOK,内核的任何模块可以对每种协议的一个或多个HOOK进行注册,实现挂接。这样当某个数据报被传递给Netfilter框架时,内核能检测到是否有任何模块对该协议和HOOK函数进行了注册。若注册了,则调用该模块的注册时使用的回调函数,这样这些模块就有机会检查、修改、丢弃该数据报及指示Netfilter将该数据报传入用户空间的队列。这样,HOOK提供了一种方便的机制:在数据报通过Linux内核的不同位置上截获和操作处理数据报。
---------------------------------------------------------------------------------------------------------------------------------
数据包进入ip协议栈后,以此进入这些函数,ip_rcv(),ip_local_deliver(),ip_forward(),ip_queue_xmit(),ip_finish_output()
五个HOOK。
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)
其中,入口为net_rx_action()(位于net/core/dev.c,Line1602),作用是将数据报一个个地从CPU的输入队列中拿出,然后传递给协议处理例程。
出口为dev_queue_xmit()(位于net/core/dev.c,Line1035),这个函数被高层协议的实例使用,以数据结构struct sk_buff *skb的形式在网络设备上发送数据报。
---------------------------------------------------------------------------------------------------------------------------------
内核开发者可以根据这五个hook,编写自己的钩子函数,实现不同的功能。
根据pywj777的图,可以看出来,内核中的包重组,连接跟踪(当查看netstat时,tcp连接状态),NAT转发,包过滤等技术全部是由netfilter框架中定义的钩子函数实现的。因此根据功能目的,实现自己的钩子函数。
---------------------------------------------------------------------------------------------------------------------------------
FAQ:
1,数据包是如何过钩子函数的?
比如数据包来到了nf_ip_pre_routing这个钩子,依次遍历钩子函数,如上图,从上至下遍历。
2,钩子函数是如何定义各自所在位置的?
钩子函数的数据结构是这个:
可以看出来,钩子函数位置是有其数据结构中的priority决定的,比如ipv4_conntrack_defrag的priority是-400(NF_IP_PRI_CONNTRACK_DEFRAG = -400,具体查看netfilter_ipv4.h)。
根据规定,遍历时是从最小值到最大值依次遍历 。
3,哪个函数遍历的钩子函数链表?
linux内核里,是靠 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) 这个宏来遍历钩子函数的,经过查看内核源码,宏NF_HOOK调用了宏NF_HOOK_THRESH,之后,
宏NF_HOOK_THRESH,调用了函数nf_hook_thresh(),函数nf_hook_thresh()判断完钩子函数列表不为空后,便调用nf_hook_slow(),进行遍历。
从nf_hook_slow()函数可以看出,首先进行基本定义,再上了个读锁,之后通过函数nf_iterate()进行遍历,传入基本参数,根据返回值做最后处理,最后返回ret。
函数nf_iterate()使用list.h头文件内的遍历链表的函数遍历。
至此,我所认为的netfilter框架就是这样,其余的如packet filter,conntrack,nat等都是基于框架实现的功能。