Chinaunix首页 | 论坛 | 博客
  • 博客访问: 23091
  • 博文数量: 5
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 62
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-29 22:52
文章分类
文章存档

2014年(5)

我的朋友
最近访客

分类: LINUX

2014-03-29 23:02:11



netfilter框架概述。

 

 

Netfilter从英文角度可以理解为,“网络数据过滤”,其实理解为“网络数据处”理更为贴切。

Netfilter框架之所以能实现许多强大的功能,

 

通俗的讲,是因为它在内核若干网络转发的关键函数中,设计了许多巧妙的钩子函数(钩子实际上是一个链表,钩子函数是链表上的结点),比如数据转发,由两个主要函数AB函数实现,流程为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.cLine379)的最后,也就是在传入的数据报被处理之前经过这个HOOK。在ip_rcv()中挂接这个HOOK之前,进行的是一些与类型、长度、版本有关的检查。

    经过这个HOOK处理之后,数据报进入ip_rcv_finish()(位于net/ipv4/ip_input.cLine306),进行查路由表的工作,并判断该数据报是发给本地机器还是进行转发。

    在这个HOOK上主要是对数据报作报头检测处理,以捕获异常情况。

         涉及功能(优先级顺序):Conntrack(-200)mangle(-150)DNAT(-100)

 

NF_IP_LOCAL_IN (1)

    目的地为本地主机的数据报在IP数据报本地投递函数ip_local_deliver()(位于net/ipv4/ip_input.cLine290)的最后经过这个HOOK

    经过这个HOOK处理之后,数据报进入ip_local_deliver_finish()(位于net/ipv4/ip_input.cLine219

    这样,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.cLine73)的最后经过这个HOOK

    经过这个HOOK处理之后,数据报进入ip_forward_finish()(位于net/ipv4/ip_forward.cLine44

    另外,在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.cLine339)、以及ip_build_and_send_pkt()(位于net/ipv4/ip_output.cLine122)的最后经过这个HOOK。(在数据报处理中,前者最为常用,后者用于那些不传输有效数据的SYN/ACK包)经过这个HOOK处理后,数据报进入ip_queue_xmit2()(位于net/ipv4/ip_output.cLine281

         另外,在ip_build_xmit_slow()(位于net/ipv4/ip_output.cLine429)和ip_build_xmit()(位于net/ipv4/ip_output.cLine638)中用于进行错误检测;在igmp_send_report()(位于net/ipv4/igmp.cLine195)的最后也经过了这个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.cLine184)的最后经过这个HOOK

    经过这个HOOK处理后,数据报进入ip_finish_output2()(位于net/ipv4/ip_output.cLine160)另外,在函数ip_mc_output()(位于net/ipv4/ip_output.cLine195)中在克隆新的网络缓存skb时,也经过了这个HOOK进行处理。

         涉及功能:mangle(-150)SNAT(100)Conntrack(INT_MAX)

    其中,入口为net_rx_action()(位于net/core/dev.cLine1602),作用是将数据报一个个地从CPU的输入队列中拿出,然后传递给协议处理例程。

    出口为dev_queue_xmit()(位于net/core/dev.cLine1035),这个函数被高层协议的实例使用,以数据结构struct sk_buff *skb的形式在网络设备上发送数据报。

 

 

---------------------------------------------------------------------------------------------------------------------------------

内核开发者可以根据这五个hook,编写自己的钩子函数,实现不同的功能。


根据pywj777的图,可以看出来,内核中的包重组,连接跟踪(当查看netstat时,tcp连接状态),NAT转发,包过滤等技术全部是由netfilter框架中定义的钩子函数实现的。因此根据功能目的,实现自己的钩子函数。

 

---------------------------------------------------------------------------------------------------------------------------------

 

FAQ:

1,数据包是如何过钩子函数的?

比如数据包来到了nf_ip_pre_routing这个钩子,依次遍历钩子函数,如上图,从上至下遍历。

 

2,钩子函数是如何定义各自所在位置的?

钩子函数的数据结构是这个:


可以看出来,钩子函数位置是有其数据结构中的priority决定的,比如ipv4_conntrack_defragpriority-400NF_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 filterconntracknat等都是基于框架实现的功能。



阅读(2014) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

7大爷2014-03-31 09:49:29

不错!