netfilternfconntrack模块实现分析.docx
- 文档编号:23273324
- 上传时间:2023-05-15
- 格式:DOCX
- 页数:46
- 大小:161.07KB
netfilternfconntrack模块实现分析.docx
《netfilternfconntrack模块实现分析.docx》由会员分享,可在线阅读,更多相关《netfilternfconntrack模块实现分析.docx(46页珍藏版)》请在冰豆网上搜索。
netfilternfconntrack模块实现分析
netfilter-nf-conntrack-模块实现分析
一.连接记录的存储
相关函数:
staticinlinestructnf_conn*nf_ct_tuplehash_to_ctrack(conststructnf_conntrack_tuple_hash*hash)
staticinlinestructnf_conn*nf_ct_get(conststructsk_buff*skb,enumip_conntrack_info*ctinfo)
nf_conntrack中tuple存储如上图所示。
在structnf_conntrack_tuple_hash中,成员hnode链接入ct->hash[]->first中的。
实际的记录在保存在structnf_conntrack_tuple中。
1.记录的访问:
hlist_nulls_for_each_entry_rcu
c:
\source\s?
defs=hlist_nulls_for_each_entry_rcu
103#definehlist_nulls_for_each_entry_rcu(tpos,pos,head,member)\
104for(pos=rcu_dereference((head)->first);\
105(!
is_a_nulls(pos))&&\
106({tpos=hlist_nulls_entry(pos,typeof(*tpos),member);1;});\
107pos=rcu_dereference(pos->next))
108
参见/net/netfilter/nf_conntrack_core.c__nf_conntrack_find函数;
structnf_conntrack_tuple_hash*h;
structhlist_nulls_node*n;
hlist_nulls_for_each_entry_rcu(h,n,&net->ct.hash[hash],hnnode)
2.记录的添加
84staticinlinevoidhlist_nulls_add_head_rcu(structhlist_nulls_node*n,
85structhlist_nulls_head*h)
86{
87structhlist_nulls_node*first=h->first;
88
89n->next=first;
90n->pprev=&h->first;
91rcu_assign_pointer(h->first,n);
92if(!
is_a_nulls(first))
93first->pprev=&n->next;
94}
参见/net/netfilter/nf_conntrack_core.c:
313staticvoid__nf_conntrack_hash_insert(structnf_conn*ct,
314unsignedinthash,
315unsignedintrepl_hash)
316{
317structnet*net=nf_ct_net(ct);
318
319hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
320&net->ct.hash[hash]);
321hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode,
322&net->ct.hash[repl_hash]);
323}
3.记录的删除
59staticinlinevoidhlist_nulls_del_rcu(structhlist_nulls_node*n)
60{
61__hlist_nulls_del(n);
62n->pprev=LIST_POISON2;
63}
59staticinlinevoid__hlist_nulls_del(structhlist_nulls_node*n)
60{
61structhlist_nulls_node*next=n->next;
62structhlist_nulls_node**pprev=n->pprev;
63*pprev=next;
64if(!
is_a_nulls(next))
65next->pprev=pprev;
66}
二.nf_conntrack模块的初始化
/net/netfilter/nf_conntrack_standalone.c
510staticint__initnf_conntrack_standalone_init(void)
511{
512returnregister_pernet_subsys(&nf_conntrack_net_ops);
513}
473staticintnf_conntrack_net_init(structnet*net)
474{
475intret;
476
477ret=nf_conntrack_init(net);
478if(ret<0)
479gotoout_init;
480ret=nf_conntrack_standalone_init_proc(net);
481if(ret<0)
482gotoout_proc;
483net->ct.sysctl_checksum=1;
484net->ct.sysctl_log_invalid=0;
485ret=nf_conntrack_standalone_init_sysctl(net);
486if(ret<0)
487gotoout_sysctl;
488return0;
489
447-------:
/net/netfilter/nf_conntrack_core.c#nf_conntrack_init
1275intnf_conntrack_init(structnet*net)
1276{
1277intret;
1278
1279if(net_eq(net,&init_net)){
1280ret=nf_conntrack_init_init_net();
1281if(ret<0)
1282gotoout_init_net;
1283}
1284ret=nf_conntrack_init_net(net);
1285if(ret<0)
1286gotoout_net;
1287
1288if(net_eq(net,&init_net)){
1289/*ForusebyREJECTtarget*/
1290rcu_assign_pointer(ip_ct_attach,nf_conntrack_attach);
1291rcu_assign_pointer(nf_ct_destroy,destroy_conntrack);
1292}
1293return0;
1294
-----------------------/net/netfilter/nf_conntrack_core.c#nf_conntrack_init_net
1223staticintnf_conntrack_init_net(structnet*net)
1224{
1225intret;
1226
1227atomic_set(&net->ct.count,0);
1228INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed,0);
1229net->ct.stat=alloc_percpu(structip_conntrack_stat);
1234ret=nf_conntrack_ecache_init(net);
1237net->ct.hash=nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
1238&net->ct.hash_vmalloc,1);
1244ret=nf_conntrack_expect_init(net);
1247ret=nf_conntrack_acct_init(net);
1253#ifdefCONFIG_NET_NS
1254nf_conntrack_untracked.ct_net=&init_net;
1255#endif
1256atomic_set(&nf_conntrack_untracked.ct_general.use,1);
1257/*-andlookitlikeasaconfirmedconnection*/
1258set_bit(IPS_CONFIRMED_BIT,&nf_conntrack_untracked.status);
1259
1260return0;
这个函数所做的主要工作就是初始化net中的net->ct中的成员。
初始化hash表大小,初始化expect链表大小,初始化acct扩展模块。
最后nf_conntrack_untracked.ct_net=&init_net,再设置它的status位为IPS_CONFIRMED_BIT;
三.conntrack的扩展
/include/net/netfilter/nf_conntrack_extend.h
66 structnf_ct_ext_type
67 {
68 /*Destroysrelationships(canbeNULL).*/
69 void(*destroy)(structnf_conn*ct);
70 /*Calledwhenrealloacted(canbeNULL).
71 Contentshasalreadybeenmoved.*/
72 void(*move)(void*new,void*old);
73
74 enumnf_ct_ext_idid;
75
76 unsignedintflags;
77
78 /*Lengthandminalignment.*/
79 u8len;
80 u8align;
81 /*initialsizeofnf_ct_ext.*/
82 u8alloc_size;
83 };
目前conntrack扩展有acct,helper,nat三种。
它存储在*nf_ct_ext_types[NF_CT_EXT_NUM]全局数组中。
以nf_conntrack_acct为例:
/net/netfilter/nf_conntrack_acct.c
初始化
59 staticstructnf_ct_ext_typeacct_extend__read_mostly={
60 .len=sizeof(structnf_conn_counter[IP_CT_DIR_MAX]),
61 .align=__alignof__(structnf_conn_counter[IP_CT_DIR_MAX]),获得对齐方式
62 .id=NF_CT_EXT_ACCT,
63 };
structnf_conn_counter为计数用:
17 structnf_conn_counter{
18 u_int64_tpackets;
19 u_int64_tbytes;
20 };
.len=sizeof(structnf_conn_counter[IP_CT_DIR_MAX]),代表为连接的两个方向都要分配,进行计数。
1.扩展的注册
/net/netfilter/nf_conntrack_acct.c
110 intnf_conntrack_acct_init(structnet*net)
111 {
112 intret;
113
114 net->ct.sysctl_acct=nf_ct_acct;
115
116 if(net_eq(net,&init_net)){
123 ret=nf_ct_extend_register(&acct_extend);
124 if(ret<0){
125 printk(KERN_ERR"nf_conntrack_acct:
Unabletoregisterextension\n");
126 gotoout_extend_register;
127 }
128 }
129
130 ret=nf_conntrack_acct_init_sysctl(net);
131 if(ret<0)
132 gotoout_sysctl;
133
134 return0;
nf_conntrack_acct_init:
114:
25 staticintnf_ct_acct__read_mostly=NF_CT_ACCT_DEFAULT;
nf_conntrack_acct_init:
123:
nf_ct_extend_register
/net/netfilter/nf_conntrack_extend.c
159 /*ThisMUSTbecalledinprocesscontext.*/
160 intnf_ct_extend_register(structnf_ct_ext_type*type)
161 {
162 intret=0;
163
164 mutex_lock(&nf_ct_ext_type_mutex);
165 if(nf_ct_ext_types[type->id]){
166 ret=-EBUSY;
167 gotoout;
168 }
169
170 /*Thisensuresthatnf_ct_ext_create()canallocateenougharea
171 beforeupdatingalloc_size*/
172 type->alloc_size=ALIGN(sizeof(structnf_ct_ext),type->align)
173 +type->len;
174 rcu_assign_pointer(nf_ct_ext_types[type->id],type);
175 update_alloc_size(type);
176 out:
177 mutex_unlock(&nf_ct_ext_type_mutex);
178 returnret;
179 }
第172行对nf_ct_ext的size进行对齐,再加上type->len再赋值给type->alloc_size.即它的大小为2*nf_conn_counter+1*nf_ct_ext;然后再将type保存到nf_ext_types数组中。
对照
可以发现,structnf_ct_ext_type仅仅只是保存了structnf_ct_ext所必要的一些信息而已。
至于为何要对齐,是因为扩展不只是一种,它们的数组结构也不一样,对齐方式都不一样,所以得保存自己的对齐方式,再对齐。
2.添加一个acct扩展
nf_ct_acct_ext_add:
/include/net/netfilter/nf_conntrack_acct.h
28 staticinline
29 structnf_conn_counter*nf_ct_acct_ext_add(structnf_conn*ct,gfp_tgfp)
30 {
31 structnet*net=nf_ct_net(ct);
32 structnf_conn_counter*acct;
33
34 if(!
net->ct.sysctl_acct)
35 returnNULL;
36
37 acct=nf_ct_ext_add(ct,NF_CT_EXT_ACCT,gfp);
38 if(!
acct)
39 pr_debug("failedtoaddaccountingextensionarea");
40
41
42 returnacct;
43 };
/include/net/netfilter/nf_conntrack_extend.h#61
61 #definenf_ct_ext_add(ct,id,gfp)\
62 ((id##_TYPE*)__nf_ct_ext_add((ct),(id),(gfp)))
/net/netfilter/nf_conntrack_extend.c
函数会判断ct->ext是否为NULL,若为NULL则证明这是第一个,所以调用nf_ct_ext_create(),
它分配一个扩展的size并且返回它的起始地址;
对于扩展的管理是先来的放前面。
所以nf_ct_ext:
:
offset[id]会是添加id对应的扩展之前
nf_ct_ext的对齐后的连同以前添加的扩展数据在内的长度。
45 staticvoid*
46 nf_ct_ext_create(structnf_ct_ext**ext,enumnf_ct_ext_idid,gfp_tgfp)
47 {
48 unsignedintoff,len;
49 structnf_ct_ext_type*t;
50
51 rcu_read_lock();
52 t=rcu_dereference(nf_ct_ext_types[id]);
53 BUG_ON(t==NULL);
54 off=ALIGN(sizeof(structnf_ct_ext),t->align);
55 len=off+t->len;
56 rcu_read_unlock();
57
58 *ext=kzalloc(t->alloc_size,gfp);
59 if(!
*ext)
60 returnNULL;
61
62 INIT_RCU_HEAD(&(*ext)->rcu);
63 (*ext)->offset[id]=off;
64 (*ext)->len=len;
65
66 return(void*)(*ext)+off;
67 }
3.查找一个扩展
/include/net/netfilter/nf_conntrack_extend.h#nf_ct_ext_find
38 #definenf_ct_ext_find(ext,id)\
39 ((id##_TYPE*)__nf_ct_ext_find((ext),(id)))
对于acct就强制转换成NF_CT_EXT_ACCT_TYPE
又:
14 #defineNF_CT_EXT_HELPER_TYPEstructnf_conn_help
15 #defineNF_CT_EXT_NAT_TYPEstructnf_conn_nat
16 #defineNF_CT_EXT_ACCT_TYPEstructnf_conn_counter
所以转换成了structnf_conn_counter类型。
31 staticinlinevoid*__nf_ct_ext_find(conststructnf_conn*ct,u8id)
32 {
33 if(!
nf_ct_ext_exist(ct,id))
34 returnNULL;
35
36 return(void*)ct->ext+ct->ext->offset[id];
37 }
根据offset取出值。
四.conntrack的具体实现
以PF_INET为例:
/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
373staticint__initnf_conntrack_l3proto_ipv4_init(void)
374{
375intret=0;
376
377need_conntrack();
378nf_defrag_ipv4_enable();
379
380ret=nf_register_sockopt(&so_getorigdst);
386ret=nf_conntrack_l4proto_register(&nf_conntrack_l4proto_t
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- netfilternfconntrack 模块 实现 分析