Chinaunix首页 | 论坛 | 博客
  • 博客访问: 271582
  • 博文数量: 72
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 276
  • 用 户 组: 普通用户
  • 注册时间: 2014-07-28 23:52
文章分类

全部博文(72)

文章存档

2017年(20)

2014年(52)

分类: LINUX

2014-10-16 16:54:23

Netfilter 提供了一个基本的报文拦截框架,即hook机制。就是在协议栈中的一些点上嵌入Netfilter的代码,对报文进行拦截。

每个拦截点上注册了一些报文的处理函数,Netfilter根据函数的优先级来顺序执行这些处理函数。注册到该点的处理函数是否被执行由上一个处理函数的返回值来决定。

各个协议的不同处理模块自己实现报文的处理函数,并把自己的处理函数注册到Netfilter提供的框架中去。

下图以IPv4的防火墙为例,具体数据关系图如下:

Netfilter 中定义了一个全局二维数组,来存放注册了的处理函数。

struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;

每个hook点上有一个或多个注册上去的处理函数。

 


每个Netfilter 钩子函数定义如下:

typedef unsigned int nf_hookfn(unsigned int hooknum,

       struct sk_buff *skb,

       const struct net_device *in,

       const struct net_device *out,

       int (*okfn)(struct sk_buff *));

钩子点处理函数的返回值:

#define NF_DROP 0    //丢弃报文

#define NF_ACCEPT 1  //报文通过,继续执行下一个处理

#define NF_STOLEN 2  //报文已经被处理并已经释放

#define NF_QUEUE 3   //报文需要加入队列,直接把报文上送给用户应用进程处理

#define NF_REPEAT 4  //重复执行该处理

#define NF_STOP 5    //结束执行

各个功能的处理函数被封装在结构体 struct nf_hook_ops中,具体定义如下。

struct nf_hook_ops

{

    struct list_head list;

    nf_hookfn *hook;  //钩子处理函数

    struct module *owner;

    u_int8_t pf; //协议族

    unsigned int hooknum; //钩子点

    int priority; //钩子函数优先级,值越小优先级越高

};


注册处理函数:

int  nf_register_hook(struct nf_hook_ops *reg)

{

    struct nf_hook_ops *elem;

    int err;

    //使用互斥锁nf_hook_mutex来保护二维数组下的hook_ops链表

    err = mutex_lock_interruptible(&nf_hook_mutex);

    if (err < 0)

        return err;

//按照hook_op的优先级来把hook_op注册到全局二维数组中去

    list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) 

    {

        if (reg->priority < elem->priority)

            break;

    }

    list_add_rcu(?->list, elem->list.prev);

    mutex_unlock(&nf_hook_mutex);

    return 0;

}

处理函数已经注册到netfilter 中了,下面我们来看看netfilter是怎么找到并执行该处理函数的。

 

在协议栈中相应位置嵌入Netfilter的函数NF_HOOK,来拦截报文送到Netfilter中进行处理。

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

参数:

pf:协议族

hook:协议定义的hook

skb:报文

indev:入接口

outdev:出接口

okfnnetfilter处理完成后来处理报文的函数

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

    NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)

 

#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)        \

({int __ret;        \

    if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) == 1)\

        __ret = (okfn)(skb); //如果netfilter 返回值为1,执行ok函数        \

    __ret;})


static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,

                                             struct sk_buff *skb,

                                             struct net_device *indev,

                                             struct net_device *outdev,

                                             int (*okfn)(struct sk_buff *), int thresh,

                                             int cond)

{

//如果cond1,直接跳过netfilter的处理

    if (!cond)

        return 1;

    return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);

}

int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,

                             struct net_device *indev,

                             struct net_device *outdev,

                             int (*okfn)(struct sk_buff *),

                             int hook_thresh)

{

    struct list_head *elem;

    unsigned int verdict;

    int ret = 0;

 

    rcu_read_lock();

 

//找到hook点的处理函数的链表

    elem = &nf_hooks[pf][hook];

    next_hook:

    //挨个执行处理函数
   
verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,

                                     outdev, &elem, okfn, hook_thresh);

 

     if (verdict == NF_ACCEPT || verdict == NF_STOP) {

         ret = 1;

     } else if (verdict == NF_DROP) {

         kfree_skb(skb);

         ret = -EPERM;

/*如果返回值是要把报文存入用户自定义的队列中(TARGET QUEUE和 NFQUEUE

使用),把verdict字段分成了两个部分,前一部分来定义返回值为入队操作,后半部分

给出入队的队列号*/
      
else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {

        if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn,

                              verdict >> NF_VERDICT_BITS))

            goto next_hook;
    }

    rcu_read_unlock();

    return ret;

}

 

unsigned int nf_iterate(struct list_head *head,

                                    struct sk_buff *skb,

                                    unsigned int hook,

                                    const struct net_device *indev,

                                    const struct net_device *outdev,

                                    struct list_head **i,

                                    int (*okfn)(struct sk_buff *),

                                    int hook_thresh)

{

    unsigned int verdict;

 

    list_for_each_continue_rcu(*i, head) 
    {

        struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;

 

        if (hook_thresh > elem->priority)

            continue;

         //执行注册的hook函数

        verdict = elem->hook(hook, skb, indev, outdev, okfn);

        if (verdict != NF_ACCEPT) 
        {

            if (verdict != NF_REPEAT)

                return verdict;

            *i = (*i)->prev;

        }

    }

    return NF_ACCEPT;

}

(未完待续)



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