Chinaunix首页 | 论坛 | 博客
  • 博客访问: 365702
  • 博文数量: 166
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-21 17:29
文章分类

全部博文(166)

文章存档

2015年(60)

2014年(99)

2013年(7)

我的朋友

分类: LINUX

2014-03-17 15:58:35

原文地址:nf_hook_ops 钩子的注册 作者:

nf_hook_ops 钩子的注册

filter表的初始化函数static int __init init(void)中除了有一个nf_register_hook函数注册一个tables外,还由nf_register_hook函数注册了3hook

 

1    nf_hook_ops数据结构 netfilter.h

struct nf_hook_ops
{
        struct list_head list;                        //链表成员
        /* User fills in from here down. */
        nf_hookfn *hook;                        //钩子函数指针
        struct module *owner;
        int pf;                                        //协议簇,对于ipv4而言,是PF_INET
        int hooknum;                                //hook类型
        /* Hooks are ordered in ascending priority. */
        int priority;                                //优先级
};

 

list成员用于维护Netfilter hook的列表。
hook
成员是一个指向nf_hookfn类型的函数的指针,该函数是这个hook被调用时执行的函数。nf_hookfn同样在linux/netfilter.h中定义。
pf
这个成员用于指定协议族。有效的协议族在linux/socket.h中列出,但对于IPv4我们使用协议族PF_INET

hooknum这个成员用于指定安装的这个函数对应的具体的hook类型:

        NF_IP_PRE_ROUTING    在完整性校验之后,选路确定之前
        NF_IP_LOCAL_IN        在选路确定之后,且数据包的目的是本地主机
        NF_IP_FORWARD        目的地是其它主机地数据包
        NF_IP_LOCAL_OUT        来自本机进程的数据包在其离开本地主机的过程中
        NF_IP_POST_ROUTING    在数据包离开本地主机“上线”之前

  struct nf_hook_ops只是存储勾子的数据结构,而真正存储这些勾子供协议栈调用的是nf_hooks,从定义可以看出,它其实就是二维数组的链表。
        struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; [net\filter\core.c]
        其中NFPROTO_NUMPROTO表示勾子关联的协议,NF_MAX_HOOKS表示勾子应用的位置,可选值在每个协议模块内部定义,这些值代表了勾子函数在协议流程中应用的位置。

再看看它的初始化,仍以filter表为例

static struct nf_hook_ops ipt_ops[]
= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_FILTER },
    { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_FORWARD, NF_IP_PRI_FILTER },
    { { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
                NF_IP_PRI_FILTER }
};

 

 

2  int nf_register_hook函数   netfilter.c

注册实际上就是在一个nf_hook_ops链表中再插入一个nf_hook_ops结构

int nf_register_hook(struct nf_hook_ops *reg)

{

      struct list_head *i;

 

      spin_lock_bh(&nf_hook_lock);

      list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {

           if (reg->priority < ((struct nf_hook_ops *)i)->priority)

                 break;

      }

      list_add_rcu(®->list, i->prev);

      spin_unlock_bh(&nf_hook_lock);

 

      synchronize_net();

      return 0;

}

list_for_each 函数遍历当前待注册的钩子的协议pfHook类型所对应的链表,其首地址是&nf_hooks[reg->pf][reg->hooknum],如果当前待注册钩子的优先级小于匹配的的节点的优先级,则找到了待插入的位置,也就是说,按优先级的升序排列。

list_add_rcu
把当前节点插入到查到找的适合的位置,这样,完成后,所有pf协议下的hooknum类型的钩子,都被注册到&nf_hooks[reg->pf][reg->hooknum]为首的链表当中了。

内核同时还提供了nf_register_hooks()和nf_unregister_hooks(),将reg重复注册n次或将reg从nf_hooks中注销n次。当勾子函数注册完成后,nf_hooks的结构如图所示:

3ipt_hook钩子函数   iptable_raw.c

注册nf_hook_ops,也就向内核注册了一个钩子函数,这些函数有ipt_hookipt_local_hookipt_route_hookipt_local_out_hook等。

前面在nf_iterate()里调用的钩子函数就是它了

下面是ipt_hook函数的定义:

static unsigned int

ipt_hook(unsigned int hook,          /* hook */

       struct sk_buff **pskb,

       const struct net_device *in,

       const struct net_device *out,

       int (*okfn)(struct sk_buff *))     /* 默认处理函数 */

{

  /* 参数&packet_filter是由注册该的表(filter)决定的,也有可能是&packet_raw */

      return ipt_do_table(pskb, hook, in, out, &packet_filter, NULL);

}

实际上是直接调用ipt_do_table(ip_tables.c)函数

接下来就是根据table里面的entry来处理数据包了

一个table就是一组防火墙规则的集合

而一个entry就是一条规则,每个entry由一系列的matches和一个target组成

一旦数据包匹配了该某个entry的所有matches,就用target来处理它

Match又分为两部份,一部份为一些基本的元素,如来源/目的地址,进/出网口,协议等,对应了struct ipt_ip,我们常常将其称为标准的match,另一部份match则以插件的形式存在,是动态可选择,也允许第三方开发的,常常称为扩展的match,如字符串匹配,p2p匹配等。同样,规则的target也是可扩展的。这样,一条规则占用的空间,可以分为:struct ipt_ip+n*match+n*target,(n表示了其个数,这里的match指的是可扩展的match部份)

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