分类: LINUX
2017-08-10 18:26:28
helper功能是提供给conntrack是一种扩展功能,供不同类型的应用层(L5)协议的模块来对连接跟踪进行进行功能上的扩展。比如ftp,tftp协议使用helper来进行期望连接的建立和关联。
helper功能是建立在Netfilter中conntrack的扩展机制上的,是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的。
conntrack的helper扩展功能的私有数据结构定义如下
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));
}
//把找到的helper和conntrack关联上
rcu_assign_pointer(help->helper, helper);
out:
return ret;
}
(未完待续)