Linux netfilter 学习笔记 之二 ip 层netfilter的hook 注册以及执行hook函数的概要分析

来源:互联网 发布:淘宝法国代购店铺推荐 编辑:程序博客网 时间:2024/05/14 08:05

基于linux2.6.21

上一节分析了hook机制,本节简单介绍下三层防火墙借助hook机制,实现的总体框架

 

1 三层netfilter hook点的注册与注销

我们知道使用iptables,添加规则时需要指定表,在iptables中有filter、nat、mangle三张表,因为我们接下来几节分析的内容也是从这三个table表加上连接跟踪,此处我们也已这四个模块来将,而不是按HOOK点的分类来分析

1.1 filter机制相关的hook注册注册

Filter表主要在以下几个hook点上其作用:

NF_IP_LOCAL_IN、NF_IP_FORWARD、NF_IP_LOCAL_OUT

即只在数据包的接收、数据包的发送及数据包的转发时进行过滤,filter表相关的hook点的注册是在iptables filter模块初始化时注册的,定义的hook_ops结构体变量如下:

static struct nf_hook_ops ipt_ops[] = {

{

.hook= ipt_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_IN,

.priority= NF_IP_PRI_FILTER,

},

{

.hook= ipt_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_FORWARD,

.priority= NF_IP_PRI_FILTER,

},

{

.hook= ipt_local_out_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_OUT,

.priority= NF_IP_PRI_FILTER,

},

};

通过上面的定义我们知道,相应的hook函数分别为ipt_hook、ipt_local_out_hook(关于这两个函数的具体执行过程暂且不分析,后面分析)。

然后通过调用nf_register_hook进行注册,调用nf_unregister_hook进行注销

 

1.2 nat机制相关的hook注册注册

 

nat表主要在以下几个hook点上其作用:

NF_IP_PRE_ROUTING、NF_IP_POST_ROUTING、NF_IP_LOCAL_OUT、NF_IP_LOCAL_IN

其中NF_IP_PRE_ROUTING、NF_IP_LOCAL_OUT为目的地址转发,而NF_IP_POST_ROUTING、NF_IP_LOCAL_IN为源地址转换。

 

/* Before packet filtering, change destination */

static struct nf_hook_ops ip_nat_in_ops = {

.hook= ip_nat_in,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_PRE_ROUTING,

.priority= NF_IP_PRI_NAT_DST,

};

 

/* After packet filtering, change source */

static struct nf_hook_ops ip_nat_out_ops = {

.hook= ip_nat_out,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_POST_ROUTING,

.priority= NF_IP_PRI_NAT_SRC,

};

 

/* After conntrack, adjust sequence number */

static struct nf_hook_ops ip_nat_adjust_out_ops = {

.hook= ip_nat_adjust,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_POST_ROUTING,

.priority= NF_IP_PRI_NAT_SEQ_ADJUST,

};

 

/* Before packet filtering, change destination */

static struct nf_hook_ops ip_nat_local_out_ops = {

.hook= ip_nat_local_fn,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_OUT,

.priority= NF_IP_PRI_NAT_DST,

};

 

/* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */

static struct nf_hook_ops ip_nat_local_in_ops = {

.hook= ip_nat_fn,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_IN,

.priority= NF_IP_PRI_NAT_SRC,

};

 

/* After conntrack, adjust sequence number */

static struct nf_hook_ops ip_nat_adjust_in_ops = {

.hook= ip_nat_adjust,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_IN,

.priority= NF_IP_PRI_NAT_SEQ_ADJUST,

};

 

1.3 mangle机制相关的hook注册与注销

 

主要定义了以下个hook_ops变量,mangle表主要在NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN、NF_IP_FORWARD、NF_IP_LOCAL_OUT、NF_IP_POST_ROUTING等hook点起作用

static struct nf_hook_ops ipt_ops[] = {

{

.hook= ipt_route_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_PRE_ROUTING, 

.priority= NF_IP_PRI_MANGLE,

},

{

.hook= ipt_route_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_IN,

.priority= NF_IP_PRI_MANGLE,

},

{

.hook= ipt_route_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_FORWARD,

.priority= NF_IP_PRI_MANGLE,

},

{

.hook= ipt_local_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_OUT,

.priority= NF_IP_PRI_MANGLE,

},

{

.hook= ipt_route_hook,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_POST_ROUTING,

.priority= NF_IP_PRI_MANGLE,

},

};

 

1.4 连接跟踪模块相关的hook注册与注销

 

主要定义了以下个hook_ops变量,连接跟踪模块主要在NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN、、NF_IP_LOCAL_OUT、NF_IP_POST_ROUTING等hook点起作用,连接跟踪模块是实现nat的基础,也是实现ALG功能的基础。

static struct nf_hook_ops ip_conntrack_defrag_ops = {

.hook= ip_conntrack_defrag,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_PRE_ROUTING,

.priority= NF_IP_PRI_CONNTRACK_DEFRAG,

};

 

static struct nf_hook_ops ip_conntrack_in_ops = {

.hook= ip_conntrack_in,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_PRE_ROUTING,

.priority= NF_IP_PRI_CONNTRACK,

};

 

static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = {

.hook= ip_conntrack_defrag,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_OUT,

.priority= NF_IP_PRI_CONNTRACK_DEFRAG,

};

 

static struct nf_hook_ops ip_conntrack_local_out_ops = {

.hook= ip_conntrack_local,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_OUT,

.priority= NF_IP_PRI_CONNTRACK,

};

 

/* helpers */

static struct nf_hook_ops ip_conntrack_helper_out_ops = {

.hook= ip_conntrack_help,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_POST_ROUTING,

.priority= NF_IP_PRI_CONNTRACK_HELPER,

};

 

static struct nf_hook_ops ip_conntrack_helper_in_ops = {

.hook= ip_conntrack_help,

.owner= THIS_MODULE,

.pf= PF_INET,

.hooknum= NF_IP_LOCAL_IN,

.priority= NF_IP_PRI_CONNTRACK_HELPER,

};

 

 

2 三层netfilter hook点的调用

 

上面是三层netfilter相关的hook点的注册,下面我们需要知道三层netfilter的hook回调函数是在哪些函数里调用的。我们主要分析ip协议在五个hook点的调用

 

 

上图便是五个hook点调用的地方,对应于代码,我们来分析一下。

 

2.1 PRE_ROUTING 

看这个名字,我们知道在这里执行hook回调函数时,数据包还没有经过路由,对于ip报文来说,在ip_rcv函数里,只是对数据包进行了合理性检查,还没有对数据包进行查找路由操作,所以PRE_ROUTINGhook点的回调函数的调用,即是在该函数的末尾通过调用函数NF_HOOK实现

return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,

       ip_rcv_finish);

 

2.2 LOCAL_IN

当进入该hook点之前,数据包已经进行了路由操作,通过对协议栈的流程分析我们知道,在 ip_rcv_finish进行了路由选择后,对于属于本地接收的报文会调用函数ip_local_deliver,那很显然,LOCAL_IN HOOK点的回调函数的调用执行,肯定是在这个函数的末尾执行的了。函数片断如下:

 

return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,

       ip_local_deliver_finish);

 

2.3 FORWARD

在进行了路由后,对于需要转发的数据,通过调用函数dst_input(skb),间接调用函数 ip_forward进行数据转发操作(关于为何会调用到ip_forward及ip_local_deliver,这是通过建立路由缓存时填充dst_entry指针实现的)。所以该HOOK点的hook回调函数的执行也是在该函数的末尾通过调用NF_HOOK实现的。

return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,

       ip_forward_finish);

 

 

2.4 LOCAL_OUT

对于该hook点,是本地发送数据的hook调用,由于本地发送的数据既可以是UDP数据也可以是TCP数据,亦可以是组播数据。所以OUThook点的调用函数不止一处。其代码书写如下:

return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,

       dst_output);

 

一般是本地数据找到路由之后,且没有调用skb->dst.out准备将数据包发送出去之前调用NF_HOOK

2.5 POST_ROUTING

 

在函数经过了FORWARD或者OUT节点后,就会通过skb->dst.out,执行到函数ip_output,所以函数

 

return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,

            ip_finish_output,

    !(IPCB(skb)->flags & IPSKB_REROUTED));

 

 

 

以上就是ip层netfilter涉及的hook_ops的注册以及调用,后面我们分析的xt_table表中的规则匹配、连接跟踪、nat操作、mangle操作,均是由上面五个hook点的NF_HOOK函数的调用而触发的。以下章节则侧重于表匹配、连接跟踪、nat转换的实现分析。本节将总的调用起点分析了一下,后面我们将针对每一个模块的实现进行分析。

1 0
原创粉丝点击