注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

Linux Netfilter 分析二  

2013-10-04 15:22:08|  分类: Linux |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
//轉
三、HOOK的实现
1. Netfilter-IPv4中的HOOK

        Netfilter模块需要使用HOOK来启用函数的动态钩接,它在IPv4中定义了五个HOOK(位于文件include/linux/netfilter_ipv4.h,Line 39),分别对应0-4的hooknum

简单地说,数据报经过各个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处理后发送出去。

    总之,这五个HOOK所组成的Netfilter-IPv4数据报筛选体系如图
http://blog.chinaunix.net/photo/24896_061206192311.jpg
(注:下面所说Netfilter/IPTables均基于IPv4,不再赘述)
详细地说,各个HOOK及其在IP数据报传递中的具体位置如图
http://blog.chinaunix.net/photo/24896_061206192340.jpg

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的形式在网络设备上发送数据报。
2. HOOK的调用

        HOOK的调用是通过宏NF_HOOK实现的,其定义位于include/linux/Netfilter.h,Line122:

#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) /

(list_empty(&nf_hooks[(pf)][(hook)]) /

? (okfn)(skb) /

: nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))

    这里先调用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()处理各个数据报。

即HOOK的调用过程如图所示

http://blog.chinaunix.net/photo/24896_061206192356.jpg

下面说明一下NF_HOOK的各个参数:

pf:协议族标识,相关的有效协议族列表位于include/linux/socket.h,Line 178。对于IPv4,应该使用协议族PF_INET;

hook:HOOK标识,即前面所说5个HOOK对应的hooknum;

skb:是含有需要被处理包的sk_buuff数据结构的指针。sk_buff是Linux网络缓存,指那些linux内核处理IP分组报文的缓存,即套接字缓冲区。

网卡收到IP分组报文后,将它们放入sk_buff,然后再传送给网络堆栈,网络堆栈几乎一直要用到sk_buff。其定义在include/linux/skbuff.h,Line 129,下面列出我认为对分析有意义的部分成员:

`struct sock *sk;`:指向创建分组报文的socket;

`struct timeval stamp;`:分组报文到达系统的时间;

下面是三个union,存放的是各层中各种协议的报文头指针:

h对应传输层的报头

nh对应网络层的报头

mac对应MAC层的报头

`unsigned int len;`:套接字缓存所代表的报文长度,即从`unsigned char *data;`的位置算起的当前有效报文长度。

`unsigned char pkt_type,`:表示报文的类型,具体类型定义在include/linux/if_packet.h,Line24:

#define PACKET_HOST 0 // 发送到本机的报文

#define PACKET_BROADCAST 1 // 广播报文

#define PACKET_MULTICAST 2 // 多播报文

#define PACKET_OTHERHOST 3 // 表示目的地非本机但被本机 接收的报文

#define PACKET_OUTGOING 4 // 离开本机的报文

/* These ones are invisible by user level */

#define PACKET_LOOPBACK 5 // 本机发给自己的报文

#define PACKET_FASTROUTE 6 // 快速路由报文

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中只有一个参数会被使用

okfn:下一步要处理的函数。即如果有HOOK函数,则处理完所有的HOOK函数,且所有向该HOOK注册过的筛选函数都返回NF_ACCEPT时,调用这个函数继续处理;如果没有注册任何HOOK,则直接调用此函数。其5个参数将由宏NF_HOOK传入。
  评论这张
 
阅读(586)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017