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

全部博文(72)

文章存档

2017年(20)

2014年(52)

分类: LINUX

2014-10-16 16:54:42

1、通信机制


如图所示,netfilter和用户空间进行通信使用的是两个socket的系统调用,把用户空间的地址传给内核,内核使用copy_from_user 和 copy_to_user来进行数据的传递。

 

我们先来看一下系统调用setsockopt getsock_opt的定义。

 

#include           

#include 

int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

 

sockfd指向一个打开的套接口描述符,level一般是标识协议。optname是命令字,optval指向一个地址,通过它来传递/存储数据。optlen是要传递数据的长度.

2Netfliter 提供的框架

基于socksetoptsockgetopt系统调用的机制,Netfilte提供了一个基本框架,允许不同协议的防火墙来自己实现自己和用户空间的通信函数。

 

1)、数据结构定义:

struct nf_sockopt_ops

{

    struct list_head list;

    u_int8_t pf;
    /*
最小和最大set 命令字*/


    int set_optmin;

    int set_optmax;
    /*处理socksetopt系统调用的函数,由防火墙自己实现*/


    int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len);

    int (*compat_set)(struct sock *sk, int optval,void __user *user, unsigned int len);
    /*最小和最大get 命令字*/


    int get_optmin;

    int get_optmax;
    /*处理sockgetopt系统调用的函数,由防火墙自己实现*/


    int (*get)(struct sock *sk, int optval, void __user *user, int *len);

    int (*compat_get)(struct sock *sk, int optval,

    void __user *user, int *len);

 

    /* Use the module struct to lock set/get code in place */

    struct module *owner;

};

 

Netfilter中每个协议自己初始化一个自己的nf_sockopt_ops实例,把它注册到netfilter管理的链表中。用户空间发起和内核通信时,Netfilter根据各个协议的命令字范围来找到相应的

nf_sockopt_ops实例,调用实例中对应的set/get处理函数,来进行数据的处理。

 

static LIST_HEAD(nf_sockopts);

 

2)、注册nf_sockopt_ops

int nf_register_sockopt(struct nf_sockopt_ops *reg)

{

    struct nf_sockopt_ops *ops;

    int ret = 0;

 

    if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)

        return -EINTR;
    /*检查要注册的nf_sockopt_ops的命令字范围是否和已注册的重复*/

    list_for_each_entry(ops, &nf_sockopts, list) {

        if (ops->pf == reg->pf

            && (overlap(ops->set_optmin, ops->set_optmax,

            reg->set_optmin, reg->set_optmax)

            || overlap(ops->get_optmin, ops->get_optmax,
            reg->get_optmin, reg->get_optmax))) {

                NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",

                ops->set_optmin, ops->set_optmax,

                ops->get_optmin, ops->get_optmax,

                reg->set_optmin, reg->set_optmax,

                reg->get_optmin, reg->get_optmax);

                ret = -EBUSY;

                goto out;

        }

    }

 

/*nf_sockopt_ops实例加入到netfilter管理的全局链表上*/

    list_add(?->list, &nf_sockopts);

out:

    mutex_unlock(&nf_sockopt_mutex);

    return ret;

}

 

3)、查找对应命令字的处理nf_sockopt_ops

static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,int val, int get)

{

    struct nf_sockopt_ops *ops;

 

    if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)

        return ERR_PTR(-EINTR);

 

    list_for_each_entry(ops, &nf_sockopts, list) {
        /*协议要一样*/

        if (ops->pf == pf) {

            if (!try_module_get(ops->owner))

                goto out_nosup;
            /*命令字必须在对应nf_sockopt_ops定义的范围内*/

            if (get) {

                if (val >= ops->get_optmin &&

                    val < ops->get_optmax)

                    goto out;

            } else {

                if (val >= ops->set_optmin &&

                    val < ops->set_optmax)

                        goto out;

            }

            module_put(ops->owner);

        }

    }

out_nosup:

    ops = ERR_PTR(-ENOPROTOOPT);

out:

    mutex_unlock(&nf_sockopt_mutex);
    /*返回找到的nf_sockopt_ops*/

    return ops;

}

 
3IptableNetfilter的通信

注册的nf_sockopt_ops

1)、初始化nf_sockopt_ops实例

static struct nf_sockopt_ops ipt_sockopts = {

    .pf = PF_INET,

    .set_optmin = IPT_BASE_CTL,

    .set_optmax = IPT_SO_SET_MAX+1,

    .set = do_ipt_set_ctl,//后续详细介绍该函数

 

    .get_optmin = IPT_BASE_CTL,

    .get_optmax = IPT_SO_GET_MAX+1,

    .get = do_ipt_get_ctl,

    .owner = THIS_MODULE,

};

 

2)、注册nf_sockopt_ops

static int __init ip_tables_init(void)

{

。。。。。。

ret = nf_register_sockopt(&ipt_sockopts);

。。。。。。

}


(未完待续)

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