Chinaunix首页 | 论坛 | 博客
  • 博客访问: 416173
  • 博文数量: 55
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 3458
  • 用 户 组: 普通用户
  • 注册时间: 2014-05-18 20:37
个人简介

哈哈

文章分类

全部博文(55)

分类: LINUX

2014-06-07 12:48:28

helper功能是提供给conntrack是一种扩展功能,供不同类型的应用层(L5)协议的模块来对连接跟踪进行进行功能上的扩展。比如ftp,tftp协议使用helper来进行期望连接的建立和关联。

 

helper功能是建立在Netfilterconntrack的扩展机制上的,是contrack扩展功能中的一种。

 

该功能的代码源文件在如下路径:

net/netfilter/nf_conntrack_helper.c

include/net/netfilter/nf_conntrack_helper.h

 

数据结构定义

struct nf_conntrack_helper

{

    struct hlist_node hnode;  /* Internal use. */

    //helper的名字,iptables扩展match helper会使用


    const char *name; 

    struct module *me; /* pointer to self */
    //协议的期望连接的策略参数,包括最大期望连接数及最大连接超时时间*/


    const struct nf_conntrack_expect_policy *expect_policy;

 

    /* Tuple of things we will help (compared against server response) */
    //元组信息,表示不同协议的helper,使用该元组的一些字段来在Netfilter中查找helper


    struct nf_conntrack_tuple tuple;

 

    /* Function to call when data passes; return verdict, or -1 to invalidate. */
    //不同协议自己实现自己的helper处理函数


    int (*help)(struct sk_buff *skb,

                    unsigned int protoff,

                    struct nf_conn *ct,

                    enum ip_conntrack_info conntrackinfo);

 

    void (*destroy)(struct nf_conn *ct);

 

    int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct);

    unsigned int expect_class_max;

};

 

需要对conntrack进行功能扩展的协议,会初始化一个struct  nf_conntrack_helper 实例,把该实例注册到Netfilter中管理的全局哈希表中。

 

查找helper使用的hash 算法

static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)

{

    return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^

        (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;

}

查找时使用的L3协议类型,L4协议类型及L4协议的源端口三元组信息来查找的helper。因为识别不同的L5协议一般都是通过这三元组来识别的。

 

注册helper实例

Netfilter中定义了一个哈希表来管理和存储不同协议注册的helper实例。

static struct hlist_head *nf_ct_helper_hash __read_mostly;

 

int nf_conntrack_helper_register(struct nf_conntrack_helper *me)

{

/*根据三元组算出hash key*/

    unsigned int h = helper_hash(&me->tuple);

 

    BUG_ON(me->expect_policy == NULL);

    BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);

    BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);

 

    mutex_lock(&nf_ct_helper_mutex);
    /*加入全局hash 表中*/


    hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);

    nf_ct_helper_count++;

    mutex_unlock(&nf_ct_helper_mutex);

 

    return 0;

}

 

注册完helper后,我们来看看是怎么添加helper扩展功能到相应的conntrack的。


conntrackhelper扩展功能的私有数据结构定义如下

 

struct nf_conn_help 
{

    /* Helper. if any */
    
//指向相应的Netfiler中注册的helper实例


    struct nf_conntrack_helper *helper;
    //一些协议执行helper处理时需要的报文信息,存储在这里


    union nf_conntrack_help help;
    //如果有多个相关联的期望连接,链接起来


    struct hlist_head expectations;

 

    /* Current number of expected connections */

    u8 expecting[NF_CT_MAX_EXPECT_CLASSES];

};

 

 

连接建立时给conntrack添加helper扩展功能

struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)

{

    struct nf_conn_help *help;
    //conntrack添加helper扩展功能


    help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);

    if (help)

        INIT_HLIST_HEAD(&help->expectations);

    else

        pr_debug("failed to add helper extension area");

    return help;

}

conntrack关联相关的helper处理

int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags)

{

    int ret = 0;

    struct nf_conntrack_helper *helper;

    struct nf_conn_help *help = nfct_help(ct);

    //根据conntrack的回应方向的连接中的元组信息,在Netfilter中查找注册的helper


 实例

    helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);

    if (helper == NULL) {

        if (help)

            rcu_assign_pointer(help->helper, NULL);

        goto out;

    }

 

    if (help == NULL) {

        help = nf_ct_helper_ext_add(ct, flags);

        if (help == NULL) {

            ret = -ENOMEM;

            goto out;

        }

    } else {

        memset(&help->help, 0, sizeof(help->help));

    }
    //把找到的helperconntrack关联上


    rcu_assign_pointer(help->helper, helper);

out:

    return ret;

}


(未完待续)

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