Linux連接跟蹤源碼分析報告_第1頁
Linux連接跟蹤源碼分析報告_第2頁
Linux連接跟蹤源碼分析報告_第3頁
已閱讀5頁,還剩17頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

Linux連接跟蹤源碼分析IPConnectiontracking連接跟蹤用來跟蹤和記錄連接狀態(tài),是netfilter的一部份,也是通過在hook點上注冊相應(yīng)的結(jié)構(gòu)來工作的。無論是發(fā)送,接收,還是轉(zhuǎn)發(fā)的數(shù)據(jù)包,都要經(jīng)過兩個conntrack模塊。第一個conntrack點的優(yōu)先級是最高的,所有數(shù)據(jù)包進(jìn)入netfilter后都會首先被它處理,其作用是創(chuàng)建ip_conntrack結(jié)構(gòu)。而最后一個conntrack的優(yōu)先級最低,總是在數(shù)據(jù)包離開netfilter之前做最后的處理,它的作用是將該數(shù)據(jù)包的連接跟蹤結(jié)構(gòu)添加到系統(tǒng)的連接狀態(tài)表中ip_conntarck結(jié)構(gòu)ip_conntrack.h內(nèi)核中用一個ip_conntrack結(jié)構(gòu)來描述一個連接的狀態(tài)structip_conntrack{—/*nf_conntrack結(jié)構(gòu)定義于include/linux/skbuff.h,Line89,其中包括一個計數(shù)器use和一個destroy函數(shù)。計數(shù)器use對本連接記錄的公開引用次數(shù)進(jìn)行計數(shù)*/structnf_conntrackct_general;/*其中的IP_CT_DIR_MAM一個枚舉類型ip_conntrack_dir(位于include/linux/netfilter_ipv4/ip_conntrack_tuple.h,Line65)的第3個成員,從這個結(jié)構(gòu)實例在源碼中的使用看來,實際上這是定義了兩個tuple多元組的hash表項tuplehash[IP_CT_DIR_ORIGINAL/0]和tuplehash[IP_CT_DIR_REPLY/1],利用兩個不同方向的tuple定位一個連接,同時也可以方便地對ORIGINALS及REPLUM個方向進(jìn)行追溯*/structip_conntrack_tuple_hashtuplehash[IP_CT_DIR_MAX];/*這是一個位圖,是一個狀態(tài)域。在實際的使用中,它通常與一個枚舉類型ip_conntrack_status(位于include/linux/netfilter_ipv4/ip_conntrack.h,Line33)進(jìn)行位運算來判斷連接的狀態(tài)。其中主要而狀態(tài)包亍舌:IPS_EXPECTED(_BIT)表示一個預(yù)期的連接IPS_SEEN_REPLY(_BIT)表示一個雙向的連接

IPS_ASSURED(_BIT)表示這個連接即使發(fā)生超時也不能提早被刪除IPS_CONFIRMED(_BIT)表示這個連接已經(jīng)被確認(rèn)(初始包已經(jīng)發(fā)出)*/unsignedlongstatus;/*其類型timer_list位于include/linux/timer.h,Line11,其核心是一個處理函數(shù)。這個成心示當(dāng)發(fā)生連接超時時,將調(diào)用此處理函數(shù)*/structtimer_listtimeout;/*所謂“預(yù)期的連接”的鏈表,其中存放的是我們所期望的其它相關(guān)連接*/structlist_headsibling_list;/*目前的預(yù)期連接數(shù)量*/unsignedintexpecting;/*結(jié)構(gòu)ip_conntrack_expect位于ip_conntrack.h,這個結(jié)構(gòu)用于彳務(wù)一個預(yù)期的連接分配給現(xiàn)有的連接,也就是說本連接是這個master的一個預(yù)期連接*/structip_conntrack_expect*master;/*helper模塊。這個結(jié)構(gòu)定義于ip_conntrack_helper.h,這個模塊提供了一個可以用于擴(kuò)展Conntrack功能的卷口。經(jīng)過梧接跟蹤HOOK勺每個數(shù)據(jù)報都將被發(fā)給每個已經(jīng)注冊的helper模塊(注冊以及卸載函數(shù)分別為ip_conntrack_helper_register()以及ip_conntrack_helper_unregister(),分別位于ip_conntrack_core.c)。這樣我們就可以進(jìn)行一些動態(tài)的連接管理了*/structip_conntrack_helper*helper;/*一系歹U的nf_ct_info類型(定義于include/linux/skbuff.h,Line92,實際上就是nf_conntrack結(jié)構(gòu))的結(jié)構(gòu),每個結(jié)構(gòu)對應(yīng)于某種狀態(tài)的連接。這一系列的結(jié)構(gòu)會被sk_buff結(jié)構(gòu)的nfct指針?biāo)茫枋隽怂信c此連接有關(guān)系的數(shù)據(jù)報。其狀態(tài)由枚舉類型ip_conntrack_info定義(位于include/linux/netfilter_ipv4/ip_conntrack.h,Line12)共有5個成員:IP_CT_ESTABLISHEDIP_CT_ESTABLISHEDIP_CT_RELATEDIP_CT_NEWIP_CT_IS_REPLYIP_CT_NUMBER數(shù)據(jù)報屆于一個新的連接,但此連接與一個現(xiàn)有連接相關(guān)(預(yù)期連接);或者是ICMP錯誤數(shù)據(jù)報屆于一個新的連接數(shù)據(jù)報屆于一個連接的回復(fù)不同IP_CT類型的數(shù)量,這里為乙NEW仗存于一個方向上*/structnf_ct_infoinfos[IP_CT_NUMBER];/*為其他模塊保留的部分*/unionip_conntrack_protoproto;unionip_conntrack_helphelp;#ifdefCONFIG_IP_NF_NAT_NEEDEDstruct(structip_nat_infoinfo;unionip_conntrack_nat_helphelp;#ifdefined(CONFIG_IP_NF_TARGET_MASQUERADE)||\defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)intmasq_index;#endif#ifdefined(CONFIG_IP_NF_RTSP)||defined(CONFIG_IP_NF_RTSP_MODULE)structip_nat_rtsp_infortsp_info;#endif}nat;#endif/*CONFIG_IP_NF_NAT_NEEDED*/#ifdefined(CONFIG_IP_NF_CONNTRACK_MARK)unsignedlongmark;#endif};structip_conntrack_tuple_hash結(jié)構(gòu)描述鏈表中的節(jié)點,這個數(shù)組包含“初始”和“應(yīng)答”兩個成員(tuplehash[IP_CT_DIR_ORIGINAL]和tuplehash[IP_CT_DIR_REPLY]),所以,當(dāng)一個婦包進(jìn)入連接跟蹤模塊后,先根據(jù)這個數(shù)據(jù)包的套接字對轉(zhuǎn)換成一個“初始的”tuple,賦值給tuplehash[IP_CT_DIR_ORIGINAL],然后對這個數(shù)據(jù)包“取反”,計算出“應(yīng)答”的tuple,賦值給tuplehash[IP_CT_DIR_REPLY],這樣,一條完整的連接已經(jīng)躍然紙上了。enumip_conntrack_dir(一一IP_CT_DIR_ORIGINAL,IP_CT_DIR_REPLY,IP_CT_DIR_MAX};連接跟蹤表Netfilter用“來源地址/來源端口+目的地址/目的端口”,即一個“tuple”,來唯一標(biāo)識一個連接。用一張連接跟蹤表來描述所有的連接狀態(tài),該表用了hash算法。hash表用一個全局指針來描述(ip_conntrack_core.c)structlist_head*ip_conntrack_hash;表的大小,即hash節(jié)點的個數(shù)由ip_conntrack_htable_size全局變量決定,默認(rèn)是根據(jù)內(nèi)存計算出來的。而每個hash節(jié)點乂是一條鏈表的首部,所以,連接跟蹤表就是一個由ip_conntrack_htable_size條鏈表構(gòu)成的一個hash表,整個連接跟蹤表大小使用全局變量ip_conntrack_max描述,與hash表的關(guān)系是ip_conntrack_max=8*ip_conntrack_htable_size。鏈表的每個節(jié)點,都是一個ip_conntrack_tuple_hash結(jié)構(gòu):structip_conntrack_tuple_hash(~/*用來組織鏈表*/structlist_headlist;/*用來描述一個tuple*/structip_conntrack_tupletuple;/*this==&ctrack->tuplehash[DIRECTION(this)].*/structip_conntrack*ctrack;};一實際描述一個tuple的是ip_conntrack_tuple結(jié)構(gòu)ip_conntrack_tuple.hstructip_conntrack_tuple(一一/*源*/structip_conntrack_manipsrc;/*Thesearethepartsofthetuplewhicharefixed.*/struct(/*目的地址*/u_int32_tip;union(/*Addotherprotocolshere.*/u_int64_tall;struct(u_int16_tport;}tcp;struct(u_int16_tport;}udp;struct(u_int8_ttype,code;}icmp;struct(u_int16_tprotocol;u_int8_tversion;u_int32_tkey;}gre;struct(u_int16_tspi;}esp;}u;/*協(xié)議類型*/u_int16_tprotonum;}dst;};對于所有IP協(xié)議,協(xié)議類型、源地址、目的地址這三個參數(shù)是識別連接所必須的,具體到各個協(xié)議,就要提取出各協(xié)議的唯一特征數(shù)據(jù),如TCPUDP的源端口、目的端口,ICMP的ID、TYPECOD眸值,這些值就是tuple結(jié)構(gòu)要處理的數(shù)據(jù)。各協(xié)議相關(guān)數(shù)據(jù)是以聯(lián)合(union)形式定義在tuple結(jié)構(gòu)中的,netfilter缺省支持TCPUD^PICMPft、議,如果還要支持其他IP協(xié)議,如GREESPAHSCTFP^,需要在聯(lián)合中添加相應(yīng)的協(xié)議參數(shù)值。ip_conntrack_manip木日ip_conntrack_manip_protoip_conntrack_tuple.hstructip_conntrack_manip(一一u_int32_tip;unionip_conntrack_manip_protou;};unionip_conntrack_manip_proto(~/*Addotherprotocolshere.*/u_int32_tall;struct(u_int16_tport;}tcp;struct(u_int16_tport;}udp;struct(u_int16_tid;}icmp;struct(u_int32_tkey;}gre;struct(u_int16_tspi;}esp;};Netfilter將每一個數(shù)據(jù)包轉(zhuǎn)換成tuple,再根據(jù)tuple計算出hash值,這樣,就可以使用ip_conntrack_hash[hash_id]找到hash表中鏈表的入口,并組織鏈表;找到hash表中鏈表入口后,如弟鏈表中不存在此tuple”,則是一個新連接,就把tuple插入到鏈表的合適位置;兩個節(jié)點tuple[ORIGINAL]和tuple[REPLY]雖然是分開的,在兩個鏈表當(dāng)中,但是如前所述,它們同時乂被封裝在ip_conntrack結(jié)構(gòu)的tuplehash數(shù)組中連接跟蹤初始化初始化函數(shù)init()調(diào)用init_or_cleanup(1)函數(shù)ip_conntrack_standalone.cstaticint__initinit(void){—returninit_or_cleanup(1);}init_or_cleanup()函數(shù)intinit_or_cleanup函數(shù),(ip_conntrack_standalone.c)參數(shù)為1貝U執(zhí)行init,為0則執(zhí)行clean,它主要忝三件工作:調(diào)用ip_conntrack_init()初始化連接跟蹤表的相關(guān)變量,見3.2初始化proc文件索統(tǒng)節(jié)點為連接跟蹤注冊hookstaticintinit_or_cleanup(intinit){structproc_dir_entry*proc;intret=0;if(!init)gotocleanup;/*初始化連接跟蹤的一些變量和數(shù)據(jù)結(jié)構(gòu),如連接跟蹤表的大小,Hash表的大小等*/ret=ip_conntrack_init();if(ret<0)gotocleanup_nothing;/*初始化proc文件系統(tǒng)*/proc=proc_net_create("ip_conntrack”,0440,list_conntracks);proc=proc_net_create("ip_clear_dnsconntrack",0644,clear_dns_conntracks);if(!proc)gotocleanup_init;proc->owner=THIS_MODULE;/*為連接跟蹤注冊hook,一共六個,所在的hook點、注冊的hook函數(shù)和優(yōu)先級分別如下(和最開始的圖是一致的):NFIPPREROUTINGipconntrackdefragNFIPPRICONNTRACKDEFRAGip_conntrack_inNF_IP_PRI_CONNTRACKNFIPLOCALOUTipconntrackdefragNFIPPRICONNTRACKDEFRAGip_conntrack_localNF_IP_PRI_CONNTRACKNFIPPOSTROUTINGip_refragNF_IP_PRI_LASTNF_IP_LOCAL_INip_confirmNF_IP_PRI_LAST-1優(yōu)先級的順序為:NF_IP_PRI_FIRST(最高)NF_IP_PRI_CONNTRACK_DEFRAGNF_IP_PRI_CONNTRACKNF_IP_PRI_MANGLENF_IP_PRI_NAT_DSTNF_IP_PRI_FILTERNF_IP_PRI_NAT_SRCNF_IP_PRI_LAST(最低)我們知道,LOCAL_OUTPRE_ROUTING可以看作是netfilter的入口,而POST_ROUTINGLOCAL_IN<以看作是出口。也就是說,在每個數(shù)據(jù)包剛一進(jìn)入netfilter之后首先都會調(diào)用ip_conntrack_defrag做分片處理,緊接著就是對收到的和發(fā)出的數(shù)據(jù)包分別進(jìn)行ip_conntrack_in和ip_conntrack_loacl(ip_conntrack_loacl里還是調(diào)用了ip_conntrack_in)。而在數(shù)據(jù)包即將離開netfilter之前,會對進(jìn)入主機(jī)的數(shù)據(jù)包進(jìn)行ip_confirm處理,對發(fā)出的數(shù)據(jù)包進(jìn)行ip_refrag處理(ip_refrag里也會調(diào)用ip_confirm)。這就是整個連接跟蹤模塊在netfilter中的分布情況。另外,我們分析的是2.6.8的內(nèi)核,在linux2.6.12中,這個地方還增加了兩個hook,分別是ip_conntrack_helper_out_ops和ip_conntrack_helper_in_ops<將helper模塊相關(guān)的處理提前了。*/ret=nf_register_hook(&ip_conntrack_defrag_ops);if(ret<0)(printk("ip_conntrack:can'tregisterpre-routingdefraghook.\n");gotocleanup_proc;}—ret=nf_register_hook(&ip_conntrack_defrag_local_out_ops);if(ret<0)(printk("ip_conntrack:can'tregisterlocal_outdefraghook.\n");gotocleanup_defragops;}—ret=nf_register_hook(&ip_conntrack_in_ops);if(ret<0)(printk("ip_conntrack:can'tregisterpre-routinghook.\n");gotocleanup_defraglocalops;}ret=nf_register_hook(&ip_conntrack_local_out_ops);if(ret<0)(printk("ip_conntrack:can'tregisterlocalouthook.\n");gotocleanup_inops;}ret=nf_register_hook(&ip_conntrack_out_ops);if(ret<0)(printk("ip_conntrack:can'tregisterpost-routinghook.\n");gotocleanup_inandlocalops;}ret=nf_register_hook(&ip_conntrack_local_in_ops);if(ret<0)(printk("ip_conntrack:can'tregisterlocalinhook.\n");gotocleanup_inoutandlocalops;}#ifdefCONFIG_SYSCTLip_ct_sysctl_header=register_sysctl_table(ip_ct_net_table,0);if(ip_ct_sysctl_header==NULL)(printk("ip_conntrack:can'tregistertosysctl.\n");gotocleanup;}#endifreturnret;cleanup:#ifdefCONFIG_SYSCTLunregister_sysctl_table(ip_ct_sysctl_header);#endifnf_unregister_hook(&ip_conntrack_local_in_ops);cleanup_inoutandlocalops:nf_unregister_hook(&ip_conntrack_out_ops);cleanup_inandlocalops:nf_unregister_hook(&ip_conntrack_local_out_ops);cleanup_inops:nf_unregister_hook(&ip_conntrack_in_ops);cleanup_defraglocalops:nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);cleanup_defragops:nf_unregister_hook(&ip_conntrack_defrag_ops);cleanup_proc:proc_net_remove("ip_conntrack");proc_net_remove("ip_clear_dnsconntrack");cleanup_init:ip_conntrack_cleanup();cleanup_nothing:returnret;}ip_conntrack_init()函數(shù)ip_conntrack_init函數(shù)(ip_conntrack_core.c)用于初始化連接跟蹤的包括hash表相關(guān)參數(shù)在內(nèi)一些重要的變量:int__initip_conntrack_init(void){—一unsignedinti;intret;/*Ideafromtcp.c:use1/16384ofmemory.Oni386:32MB*machinehas256buckets.>=1GBmachineshave8192buckets.*//*如果指定hash表的大小則用制定值,否則根據(jù)內(nèi)存計算*/if(hashsize){ip_conntrack_htable_size=hashsize;}else{ip_conntrack_htable_size=(((num_physpages<<PAGE_SHIFT)/16384)/sizeof(structlist_head));if(num_physpages>(1024*1024*1024/PAGE_SIZE))ip_conntrack_htable_size=8192;if(ip_conntrack_htable_size<16)ip_conntrack_htable_size=16;}ip_conntrack_max=8*ip_conntrack_htable_size;#ifdefCONFIG_MIPS_BRCMip_conntrack_max=0;#endifprintk("ip_conntrackversion%s(%ubuckets,%dmax)""-%Zdbytesperconntrack\n",IP_CONNTRACK_VERSION,ip_conntrack_htable_size,ip_conntrack_max,sizeof(structip_conntrack));/*注冊socket選項*/ret=nf_register_sockopt(&so_getorigdst);if(ret!=0)(printk(KERN_ERR"Unabletoregisternetfiltersocketoption\n");returnret;}/*為hash表分配連續(xù)內(nèi)存貞*/ip_conntrack_hash=vmalloc(sizeof(structlist_head)*ip_conntrack_htable_size);if(!ip_conntrack_hash)(printk(KERN_ERR"Unabletocreateip_conntrack_hash\n");gotoerr_unreg_sockopt;}/*分配高速緩存*/ip_conntrack_cachep=kmem_cache_create("ip_conntrack",sizeof(structip_conntrack),0,SLAB_HWCACHE_ALIGN,NULL,NULL);if(!ip_conntrack_cachep)(printk(KERN_ERR"Unabletocreateip_conntrackslabcache\n");gotoerr_free_hash;}/*Don'tNEEDlockhere,butgoodformanyway.*/WRITE_LOCK(&ip_conntrack_lock);/*netfilter中對每個要進(jìn)行跟蹤的IP協(xié)議定義了一個ip_conntrack_protocol結(jié)構(gòu),每個IP協(xié)議的連接跟蹤處理就是要填寫這樣一個結(jié)構(gòu),這里的ip_conntrack_protocol_tcp,ip_conntrack_protocol_udp都是這個結(jié)構(gòu),用list_append將這些需要跟蹤的協(xié)議組織成鏈表*/list_append(&protocol_list,&ip_conntrack_protocol_tcp);list_append(&protocol_list,&ip_conntrack_protocol_udp);list_append(&protocol_list,&ip_conntrack_protocol_icmp);list_append(&protocol_list,&ip_conntrack_protocol_esp);WRITE_UNLOCK(&ip_conntrack_lock);/*初始化hash表*/for(i=0;i<ip_conntrack_htable_size;i++)INIT_LIST_HEAD(&ip_conntrack_hash[i]);/*Forusebyipt_REJECT*/ip_ct_attach=ip_conntrack_attach;/*Setupfakeconntrack:-toneverbedeleted,notinanyhashes*/atomic_set(&ip_conntrack_untracked.ct_general.use,1);/*-andlookitlikeasaconfirmedconnection*/set_bit(IPS_CONFIRMED_BIT,&ip_conntrack_untracked.status);/*-andpreparethectinfofieldforREJECT&NAT.*/ip_conntrack_s[IP_CT_NEW].master=ip_conntrack_s[IP_CT_RELATED].master=ip_conntrack_s[IP_CT_RELATED+IP_CT_IS_REPLY].master=&ip_conntrack_untracked.ct_general;returnret;err_free_hash:vfree(ip_conntrack_hash);err_unreg_sockopt:nf_unregister_sockopt(&so_getorigdst);return-ENOMEM;}協(xié)議的擴(kuò)展,ip_conntrack_protocol結(jié)構(gòu)各種協(xié)議使用一個全局的協(xié)議列表存放,即protocol_list(ip_conntrack_core.h),使用結(jié)構(gòu)ip_conntrack_protocol來表示(ip_conntrack_protocol.h)structip_conntrack_protocol{/*Nextpointer.*/structlist_headlist;/*Protocolnumber.*/u_int8_tproto;/*Protocolname*/constchar*name;/*其指向函數(shù)的作用是將協(xié)議加入到ip_conntrack_tuple的dst子結(jié)構(gòu)中*/int(*pkt_to_tuple)(conststructsk_buff*skb,unsignedintdataoff,structip_conntrack_tuple*tuple);/*其指向函數(shù)的作用是將源和目的多元組中協(xié)議部分的值進(jìn)行互換,包括IP地址、端口等*/int(*invert_tuple)(structip_conntrack_tuple*inverse,conststructip_conntrack_tuple*orig);/*打印多元組中的協(xié)議信息*/unsignedint(*print_tuple)(char*buffer,conststructip_conntrack_tuple*);/*打印整個連接記錄*/unsignedint(*print_conntrack)(char*buffer,conststructip_conntrack*);/*判斷數(shù)據(jù)包是否合法,并調(diào)整相應(yīng)連接的信息,也就是實現(xiàn)各協(xié)議的狀態(tài)檢測,對于UDF^本身是無連接的協(xié)議的判斷比較簡單,netfilter建立一個虛擬連接,每個新發(fā)包都是合法包,只等待回應(yīng)包到后連接都結(jié)束;但對于TCP之類的有狀態(tài)協(xié)議必須檢查數(shù)據(jù)是否符合協(xié)議的狀態(tài)轉(zhuǎn)換過程,這是靠一個狀態(tài)轉(zhuǎn)換數(shù)組實現(xiàn)的。返回數(shù)據(jù)報的verdict值*/int(*packet)(structip_conntrack*conntrack,conststructsk_buff*skb,enumip_conntrack_infoctinfo);/*當(dāng)此協(xié)議的一個新連接發(fā)生時,調(diào)用其指向的這個函數(shù),調(diào)用返回true時再繼續(xù)調(diào)用packet()函數(shù)*/int(*new)(structip_conntrack*conntrack,conststructsk_buff*skb);/*刪除一個連接狀態(tài)*/void(*destroy)(structip_conntrack*conntrack);/*判斷是否有數(shù)據(jù)報匹配預(yù)期的連接*/int(*exp_matches_pkt)(structip_conntrack_expect*exp,conststructsk_buff*skb);/*指向模塊本身,統(tǒng)計模塊是否被使用*/structmodule*me;};要編寫自己的IP協(xié)議跟蹤模塊,先要分析這些協(xié)議頭中哪些信息可以用來唯一識別連接,作NAT時要修改哪些信息,把這些信息添加到ip_conntrack_tuple結(jié)構(gòu)的聯(lián)合中;然后填寫該協(xié)議的ip_conntrack_protocol結(jié)構(gòu),實現(xiàn)結(jié)構(gòu)中的內(nèi)部函數(shù);最后在ip_conntrack_init()函數(shù)中用list_append()將此結(jié)構(gòu)掛接到協(xié)議跟蹤鏈表中,tE可以在各”的模塊初始化時用ipconntrackprotocolregister()和ipconntrackprotocolunregister()扁加/刪除斯、議。--

5.兩個主要的連接跟蹤函數(shù):ip_conntrack_in()5.和ip_confirm()ip_conntrack_in()函數(shù)ip_conntrack_core.c接收倒的數(shù)據(jù)包進(jìn)入Netfilter后,首先進(jìn)行分片處理,然后就會調(diào)用ip_conntrack_in函數(shù),ip_conntrack_in主要完成的工作就是判斷數(shù)據(jù)包是否已在連接跟蹤表中,如果不在,則為數(shù)據(jù)包分配ip_conntrack,并初始化它,然后,為這個數(shù)據(jù)包設(shè)置連接狀態(tài)。unsignedintip_conntrack_in(unsignedinthooknum,structsk_buff**pskb,conststructnet_device*in,conststructnet_device*out,int(*okfn)(structsk_buff*)){_structip_conntrack*ct;enumip_conntrack_infoctinfo;structip_conntrack_protocol*proto;intset_reply;intret;/*分片包會在前一個Hook中被處理,事實上,并不會觸發(fā)該條件*/if((*pskb)->nh.iph->frag_off&htons(IP_OFFSET)){returnNF_ACCEPT;if(net_ratelimit()){printk(KERN_ERR"ip_conntrack_in:Fragofproto%u(hook=%u)\n”,(*pskb)->nh.iph->protocol,hooknum);}returnNF_DROP;}/*將當(dāng)前數(shù)據(jù)包設(shè)置為未修改*/(*pskb)->nfcache|=NFC_UNKNOWN;/*判斷當(dāng)前數(shù)據(jù)包是否已被檢查過了*/if((*pskb)->nfct)returnNF_ACCEPT;/*根據(jù)當(dāng)前數(shù)據(jù)包的協(xié)議,查找與之相應(yīng)的structip_conntrack_protocol結(jié)構(gòu)*/proto=ip_ct_find_proto((*pskb)->nh.iph->protocol);/*如果是icmp錯誤報文*/if((*pskb)->nh.iph->protocol==IPPROTO_ICMP&&icmp_error_track(*pskb,&ctinfo,hooknum))returnNF_ACCEPT;/*在全局的連接表中,查找與當(dāng)前包相匹配的連接結(jié)構(gòu),返回的是structip_conntrack*類型指針,它用于描述一個數(shù)據(jù)包的連接狀態(tài)*/if(!(ct=resolve_normal_ct(*pskb,proto,&set_reply,hooknum,&ctinfo)))returnNF_ACCEPT;if(IS_ERR(ct))returnNF_DROP;IP_NF_ASSERT((*pskb)->nfct);/*如果注冊了相應(yīng)的協(xié)議的ip_conntrack_protocol結(jié)構(gòu),則在這里調(diào)用其中的packet函數(shù)做一些檢查*/ret=proto->packet(ct,*pskb,ctinfo);if(ret==-1)(/*Invalid*/nf_conntrack_put((*pskb)->nfct);(*pskb)->nfct=NULL;returnNF_ACCEPT;}/*如果注冊了相應(yīng)協(xié)議的ip_conntrack_helper結(jié)構(gòu),則在這里調(diào)用其help函數(shù)*/if(ret!=NF_DROP&&ct->helper)(ret=ct->helper->help(*pskb,ct,ctinfo);if(ret==-1)(/*Invalid*/nf_conntrack_put((*pskb)->nfct);(*pskb)->nfct=NULL;returnNF_ACCEPT;}}if(set_reply)set_bit(IPS_SEEN_REPLY_BIT,&ct->status);returnret;}連接跟蹤模塊將所有支持的協(xié)議,都使用structip_conntrack_protocol結(jié)構(gòu)封裝,注冊至全局鏈表中,這里首先調(diào)用函數(shù)ip_ct_find_proto根據(jù)當(dāng)前數(shù)據(jù)resolve_normal_ct函數(shù)進(jìn)包的協(xié)議值,找到協(xié)議注冊對應(yīng)的模塊。然后調(diào)用resolve_normal_ct函數(shù)進(jìn).2resolve_normal_ct()函數(shù)ip_conntrack_core.c函數(shù)判斷數(shù)據(jù)包在連接跟蹤表是否存在,如果不存在,則為數(shù)據(jù)包分配相應(yīng)的連接跟蹤節(jié)點空間并初始化,然后設(shè)置連接狀態(tài)。staticinlinestructip_conntrack*resolve_normal_ct(structsk_buff*skb,structip_conntrack_protocol*proto,int*set_reply,unsignedinthooknum,enumip_conntrack_info*ctinfo)(一一structip_conntrack_tupletuple;structip_conntrack_tuple_hash*h;IP_NF_ASSERT((skb->nh.iph->frag_off&htons(IP_OFFSET))==0);/*將數(shù)據(jù)包轉(zhuǎn)換成tuple*/if(!get_tuple(skb->nh.iph,skb,skb->nh.iph->ihl*4,&tuple,proto))returnNULL;/*查找對應(yīng)的tuple在連接跟蹤表中是否存在*/h=ip_conntrack_find_get(&tuple,NULL);/*如果不存在,初始化該連接*/if(!h)(h=init_conntrack(&tuple,proto,skb);if(!h)returnNULL;if(IS_ERR(h))return(void*)h;}/*判斷連接方向*/if(DIRECTION(h)==IP_CT_DIR_REPLY)(*ctinfo=IP_CT_ESTABLISHED+IP_CT_IS_REPLY;/*PleasesetreplybitifthispacketOK*/*set_reply=1;}else(/*Oncewe'vehadtwowaycomms,alwaysESTABLISHED.*/if(test_bit(IPS_SEEN_REPLY_BIT,&h->ctrack->status))(DEBUGP("ip_conntrack_in:normalpacketfor%p\n",h->ctrack);*ctinfo=IP_CT_ESTABLISHED;}elseif(test_bit(IPS_EXPECTED_BIT,&h->ctrack->status)){DEBUGP("ip_conntrack_in:relatedpacketfor%p\n",h->ctrack);*ctinfo=IP_CT_RELATED;}else{DEBUGP("ip_conntrack_in:newpacketfor%p\n",h->ctrack);*ctinfo=IP_CT_NEW;}*set_reply=0;}/*設(shè)置skb的對應(yīng)成員,如使用計數(shù)器、數(shù)據(jù)包狀態(tài)標(biāo)記*/skb->nfct=&h->ctrack->infos[*ctinfo];returnh->ctrack;}獲取tuple結(jié)構(gòu)ip_conntrack_core.cget_tuple()函數(shù)將數(shù)據(jù)包轉(zhuǎn)換成tuple結(jié)構(gòu)intget_tuple(conststructiphdr*iph,conststructsk_buff*skb,unsignedintdataoff,structip_conntrack_tuple*tuple,conststructip_conntrack_protocol*protocol){/*Neverhappen*/if(iph->frag_off&htons(IP_OFFSET)){printk("ip_conntrack_core:Fragofproto%u.\n",iph->protocol);return0;}/*設(shè)置來源、目的地址和協(xié)議號*/tuple->src.ip=iph->saddr;tuple->dst.ip=iph->daddr;tuple->tonum=iph->protocol;tuple->src.u.all=tuple->dst.u.all=0;/*這里根據(jù)協(xié)議的不同調(diào)用各自的函數(shù)*/returnprotocol->pkt_to_tuple(skb,dataoff,tuple)以tcp協(xié)議為例,ip_conntrack_proto_tcp.c:staticinttcp_pkt_to_tuple(conststructsk_buff*skb,unsignedintdataoff,structip_conntrack_tuple*tuple){一一structtcphdrhdr;/*Actuallyonlyneedfirst8bytes.*/if(skb_copy_bits(skb,dataoff,&hdr,8)!=0)return0;/*根據(jù)報頭的端口信息,設(shè)置tuple對應(yīng)成員*/tuple->src.u.tcp.port=hdr.source;tuple->dst.u.tcp.port=hdr.dest;return1;}搜索hash表要對Hash表進(jìn)行遍歷,首要需要找到hash表的入口,然后來遍歷該入口指向的鏈表。每個鏈表的節(jié)點是structip_conntrack_tuple_hash,它封裝了tuple,所謂封裝,就是把待查找的tuple與節(jié)點中已存的tuple相比較。structip_conntrack_tuple_hash*ip_conntrack_find_get(conststructip_conntrack_tuple*tuple,conststructip_conntrack*ignored_conntrack){structip_conntrack_tuple_hash*h;READ_LOCK(&ip_conntrack_lock);/*查找整個hash表,返回一個節(jié)點*/h=__ip_conntrack_find(tuple,ignored_conntrack);/*找到Em計數(shù)器*/-if(h)atomic_inc(&h->ctrack->ct_general.use);READ_UNLOCK(&ip_conntrack_lock);returnh;}計算hash值,是調(diào)用hash_conntrack函數(shù),根據(jù)數(shù)據(jù)包對應(yīng)的tuple實現(xiàn)的:staticstructip_conntrack_tuple_hash*__ip_conntrack_find(conststructip_conntrack_tuple*tuple,conststructip_conntrack*ignored_conntrack)structip_conntrack_tuple_hash*h;/*計算tuple的hash值,這樣,tuple對應(yīng)的hash表入口即為ip_conntrack_hash[hash],也就是鏈表的首節(jié)點*/unsignedinthash=hash_conntrack(tuple);MUST_BE_READ_LOCKED(&ip_conntrack_lock);/*找到鏈表入口后遍歷鏈表,返回一個節(jié)點。比較函數(shù)是conntrack_tuple_cmp()*/h=LIST_FIND(&ip_conntrack_hash[hash],conntrack_tuple_cmp,structip_conntrack_tuple_hash*,tuple,ignored_conntrack);returnh;}init_conntrack()函數(shù)ip_conntrack_core.cstaticstructip_conntrack_tuple_hash*init_conntrack(conststructip_conntrack_tuple*tuple,structip_conntrack_protocol*protocol,structsk_buff*skb){—structip_conntrack*conntrack;structip_conntrack_tuplerepl_tuple;size_thash;structip_conntrack_expect*expected;inti;staticunsignedintdrop_next;/*如果計算hash值的隨機(jī)數(shù)種子沒有被初始化,則初始化之*/if(!ip_conntrack_hash_rnd_initted){get_random_bytes(&ip_conntrack_hash_rnd,4);ip_conntrack_hash_rnd_initted=1;}/*計算hash值*/hash=hash_conntrack(tuple);/*判斷連接跟蹤表是否已滿*/if(ip_conntrack_max&&atomic_read(&ip_conntrack_count)>=ip_conntrack_max){/*Trydroppingfromrandomchain,orelsefromthechainabouttoputinto(incasethey'retryingtobombonehashchain).*/unsignedintnext=(drop_next++)%ip_conntrack_htable_size;if(!early_drop(&ip_conntrack_hash[next])&&!early_drop(&ip_conntrack_hash[hash])){#ifdefined(CONFIG_MIPS_BRCM)/*Sorry,wehavetokickoneoutregardless.*/while(!regardless_drop(&ip_conntrack_hash[next]))next=(drop_next++)%ip_conntrack_htable_size;#elseif(net_ratelimit())printk(KERN_WARNING"ip_conntrack:tablefull,dropping""packet.\n");returnERR_PTR(-ENOMEM);#endif}}/*根據(jù)當(dāng)前的tuple取反,計算該數(shù)據(jù)包的“應(yīng)答”的tuple*/if(!invert_tuple(&repl_tuple,tuple,protocol)){DEBUGP("Can'tinverttuple.\n");returnNULL;}/*為數(shù)據(jù)包對應(yīng)的連接分配空間*/conntrack=kmem_cache_alloc(ip_conntrack_cachep,GFP_ATOMIC);if(!conntrack){DEBUGP("Can'tallocateconntrack.\n");returnERR_PTR(-ENOMEM);}/*初始化該結(jié)構(gòu),使用計數(shù)器累加,設(shè)置destroy函數(shù)指針,設(shè)置兩個方向的tuple*/memset(conntrack,0,sizeof(*conntrack));atomic_set(&conntrack->ct_general.use,1);conntrack->ct_general.destroy=destroy_conntrack;conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple=*tuple;conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack=conntrack;conntrack->tuplehash[IP_CT_DIR_REPLY].tuple=repl_tuple;conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack=conntrack;for(i=0;i<IP_CT_NUMBER;i++)conntrack->infos[i].master=&conntrack->ct_general;/*創(chuàng)建一個該協(xié)議對應(yīng)的ip_conntrack_protocol結(jié)構(gòu)*/if(!protocol->new(conntrack,skb)){kmem_cache_free(ip_conntrack_cachep,conntrack);returnNULL;}/*初始化時間計數(shù)器,并設(shè)置超時初始函數(shù)*/init_timer(&conntrack->timeout);conntrack->timeout.data=(unsignedlong)conntrack;conntrack->timeout.function=death_by_timeout;/*初始化預(yù)期連接鏈表*/INIT_LIST_HEAD(&conntrack->sibling_list);WRITE_LOCK(&ip_conntrack_lock);/*NeedfindinganddeletingofexpectedONLYifwewinrace*/READ_LOCK(&ip_conntrack_expect_tuple_lock);/*在預(yù)期禰接表中查集,有沒有配配的而期連童*/expected=LIST_FIND(&ip_conntrack_expect_list,expect_cmp,structip_conntrack_expect*,tuple);READ_UNLOCK(&ip_conntrack_expect_tuple_lock);/*Ifmasterisnotinhashtableyet(ie.packethasn'tleftthismachineyet),howcanotherendknowaboutexpected?Hencethesearenotthedroidsyouarelookingfor(ifmasterctnevergotconfirmed,we'dholdareferencetoitandweirdthingswouldhappentofuturepackets).*/if(expected&&!is_confirmed(expected->expectant))expected=NULL;/*如果沒有找到期望的連接,則搜索相關(guān)的helper結(jié)構(gòu)*/if(!expected)conntrack->helper=ip_ct_find_helper(&repl_tuple);/*Iftheexpectationisdying,thenthisisaloser.*/if(expected&&expected->expectant->helper->timeout&&!del_timer(&expected->timeout))expected=NULL;if(expected)(DEBUGP("conntrack:expectationarrivesct=%pexp=%p\n",conntrack,expected);/*Welcome,Mr.Bond.We'vebeenexpectingyou...*/__set_bit(IPS_EXPECTED_BIT,&conntrack->status);conntrack->master=expected;expected->sibling=conntrack;#ifCONFIG_IP_NF_CONNTRACK_MARKconntrack->mark=expected->expectant->mark;#endifLIST_DELETE(&ip_conntrack_expect_list,expected);expected->expectant->expecting--;nf_conntrack_get(&master_ct(conntrack)->infos[0]);}一atomic_inc(&ip_conntrack_count);WRITE_UNLOCK(&ip_conntrack_lock);if(expected&&expected->expectfn)expected->expectfn(conntrack);/*返回初始方向的hash節(jié)點*/return&conntrack->tuplehash[IP_CT_DIR_ORIGINAL];}ip_confirm函數(shù)ip_conntrack_standalone.cip_confirm直接返回ip_conntrack_confirm(),而ip_conntrack_confirm()里乂調(diào)用了__ip_conntrack_confirm()函數(shù)staticunsignedintip_confirm(unsignedinthooknum,structsk_buff**pskb,conststructnet_device*in,conststructnet_device*out,int(*okfn)(structsk_buff*)){_/*We'veseenitcomingouttheotherside:confirmit*/returnip_conntrack_confirm(*pskb);}staticinlineintip_conntrack_confirm(structsk_buff*skb){if(skb->nfct&&!is_confirmed((structip_conntrack*)skb->nfct->master))return__ip_conntrack_confirm(skb->nfct);returnNF_ACCEPT;}在數(shù)據(jù)包穿過filter到達(dá)post_routing或local_in節(jié)點時,__ip_conntrack_confirm函數(shù)將該連接正式加入連接狀態(tài)表中int__ip_conntrack_confirm(structnf_ct_info*nfct){unsignedinthash,repl_hash;structip_conntrack*ct;enumip_conntrack_infoctinfo;ct=__ip_conntrack_get(nfct,&ctinfo);/*ipt_REJECTusesip_conntrack_attachtoattachrelatedICMP/TCPRSTpacketsinotherdirection.ActualpacketwhichcreatedconnectionwillbeIP_CT_NEWorforanexpectedconnection,IP_CT_RELATED.*/if(CTINFO2DIR(ctinfo)!=IP_CT_DIR_ORIGINAL)returnNF_ACCEPT;hash=hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);repl_hash=hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);/*We'renotinhashtable,andwerefusetosetuprelatedconnectionsforunconfirmedconns.ButpacketcopiesandREJECTwillgivespuriouswarningshere.*//*IP_NF_ASSERT(atomic_read(&ct->ct_general.use)==1);*//*Noexternalreferencesmeansnooneelsecouldhaveconfirmedus.*/IP_NF_ASSERT(!is_confirmed(ct));DEBUGP("Confirmingconntrack%p\n”,ct);WRITE_LOCK(&ip_conntrack_lock);/*Seeifthere'soneinthelistalready,includingreverse:NATcouldhavegrabbeditwithoutrealizing,sincewe'renotinthehash.Ifthereis,welostrace.*/if(!LIST_FIND(&ip_conntrack_hash[hash],conntrack_tuple_cmp,structip_conntrack_tuple_hash*,&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,NULL)&&!LIST_FIND(&ip_conntrack_hash[repl_hash],conntrack_tuple_cmp,structip_conntrack_tuple_hash*,&ct->tuplehash[IP_CT_DIR_REPLY].tuple,NULL)){list_prepend(&ip_conntrack_hash[hash],&ct->tuplehash[IP_CT_DIR_ORIGINAL]);list_prepend(&ip_conntrack_hash[repl_hash],&ct->tuplehash[IP_CT_DIR_REPLY]);/*Timerrelativetoconfirmationtime,notoriginalsettingtime,otherwisewe'dgettimerwrapinweirddelaycases.*/ct->timeout.expires+=jiffies;add_timer(&ct->timeout);atomic_inc(&ct->ct_general.use);set_bit(IPS_CONFIRMED_BIT,&ct->status);WRITE_UNLOCK(&ip_conntrack_lock);returnNF_ACCEPT;}—WRITE_UNLOCK(&ip_conntrack_lock);returnNF_DROP;}6.具體協(xié)議的連接跟蹤源碼分析前面是conntrack的總體框架,下面以tftp為例分析其具體實現(xiàn)相關(guān)的文件:ip_conntrack_tftp.cip_conntrack_tftp.hhelper和expect結(jié)構(gòu)ip_conntrack_helper結(jié)構(gòu)每個使用動態(tài)地址和端口的協(xié)議一般都定義了數(shù)據(jù)結(jié)構(gòu)ip_conntrack_helper,并把它放到一個全局的鏈表中。這類協(xié)議一般都會有控制連物和數(shù)據(jù)連物兩個不同的連接,如FTP協(xié)議等。structip_conntrack_helper{一一structlist_headlist;/*鏈表頭*/constchar*name;/*模塊的名稱*/unsignedcharflags;structmodule*me;/*指向模塊本身*/unsignedintmax_expected;/*期望的連接數(shù)的最大值*/unsignedinttimeout;/*超時位*/structip_conntrack_tupletuple;structip_conntrack_tuplemask;int(*help)(structsk_buff*skb,structip_conntrack*ct,enumip_conntrack_infoconntrackinfo);};tftp的init()初始化將協(xié)議對應(yīng)的ip_conntrack_helper結(jié)構(gòu)數(shù)組初始化,并鏈接到全局鏈表里staticint__initinit(void){—inti,ret;char*tmpname;if(!ports[0])ports[0]=TFTP_PORT;for(i=0;(i<MAX_PORTS)&&ports[i];i++){/*Createhelperstructure*/memset(&tftp[i],0,sizeof(structip_conntrack_helper));tftp[i].tonum=IPPROTO_UDP;/*協(xié)議號17*/tftp[i].tuple.src.u.udp.port=htons(ports[i]);/*源端口500*/tftp[i].tonum=0xFFFF;tftp[i].mask.src.u.udp.port=0xFFFF;tftp[i].max_expected=1;tftp[i].timeout=0;tftp[i].flags=IP_CT_HELPER_F_REUSE_EXPECT;tftp[i].me=THIS_MODULE;tftp[i].help=tftp_help;/*tftp_help函數(shù),最重要的部分*/tmpname=&tftp_names[i][0];if(ports[i]==TFTP_PORT)sprintf(tmpname,"tftp");elsesprintf(tmpname,"tftp-%d",i);tftp[i].name=tmpname;DEBUGP("port#%d:%d\n",i,ports[i]);/*將tftp的helper結(jié)構(gòu)注冊到一個全局鏈表&helpter里*/ret=ip_conntrack_helper_register(&tftp[i]);if(ret){printk("ERRORregisteringhelperforport%d\n",ports[i]);fini();return(ret);}ports_c++;return(0);ip_conntrack_expect結(jié)構(gòu)結(jié)構(gòu)定義在ip_conntrack.h,ip_conntrack里的master變量就是這個結(jié)構(gòu),它的作用后面再說structip_conntrack_expect{一一/*鏈表頭,在被某連接引用之前,所有expect結(jié)構(gòu)都由此鏈表維護(hù)*/structlist_headlist;/*引用計數(shù)*/atomic_tuse;/*主連切勺預(yù)期的子連接的鏈表*/structlist_headexpected_list;/*期待者,"■即預(yù)期連接對切勺主連接,換句話說就是將此連接當(dāng)作是其預(yù)期連接的連接...*/structip_conntrack*expectant;/*預(yù)期連童對應(yīng)的真實的子連接*/structip_conntrack*sibling;/*連接的tuple值*/structip_conntrack_tuplect_tuple;/*定時器*/structtimer_listtimeout;/*預(yù)期連接的tuple和masK搜索預(yù)期連接時要用到的*/structip_conntrack_tupletuple,mask;/*預(yù)期連接函數(shù),一般是NULL有特殊需要時才定義*/int(*expectfn)(structip_conntrack*new);/*TCP協(xié)議時,主連接中扁述子連接的數(shù)據(jù)起始處對應(yīng)的序列號值*/u_int32_tseq;/*跟蹤*個多連接IP層協(xié)議相關(guān)的數(shù)據(jù)*/unionip_conntrack_expect_protoproto;/*跟蹤^不多連接應(yīng)用層協(xié)議相關(guān)的數(shù)據(jù)*/unionip_conntrack_expect_helphelp;};6.2數(shù)據(jù)包在連接跟蹤模塊中的行進(jìn)過程ip_conntrack_in階段數(shù)據(jù)包進(jìn)入netfilter后,首先會調(diào)用ip_conntrack_in()函數(shù),確認(rèn)數(shù)據(jù)包未被檢查過后,首先確定數(shù)據(jù)包使用的協(xié)議類型,如果是ICMP錯誤報文的話要做特別處理:proto=ip_ct_find_proto((*pskb)->nh.iph->protocol);proto是一個ip_conntrack_protocol指針,該函數(shù)根據(jù)sk_buff的protocol字段在全局的protocol_list變量里搜索匹配的ip_conntrack_protocol結(jié)構(gòu),bcm源碼里注冊了esp,gre,icmp,tcp,udp等協(xié)議這里返回的是udp協(xié)議的ip_conntrack_protocol結(jié)構(gòu)ip_conntrack_protocol_udp接下來就要在連接跟蹤表內(nèi)查找屆于該數(shù)據(jù)包的連接狀態(tài),如果能找到,說明該數(shù)據(jù)包是之前某連接的后續(xù)報文,那么只需要做一些標(biāo)記處理就可以放行了,如果找不到,說明是一個新的連接,那么就創(chuàng)建一個新的連接狀態(tài),然后仍然放行(連接跟蹤只是跟蹤記錄連接狀態(tài),不修改也不過濾)。將找到的,或者新建的連接狀態(tài)返回給參數(shù)ct,ct就是一個ip_conntrack指針。ct=resolve_normal_ct(*pskb,proto,&set_reply,hooknum,&ctinfo)前面說了連接跟蹤表是一個采用hash算法的鏈表數(shù)組,搜索hash表藥先獲取該連接的tuple結(jié)構(gòu),一般包括協(xié)議、來源/目的地址、來源/目的端口等,因不同協(xié)議而異(參考前面對tuple結(jié)構(gòu)的描述)。resolve_normal_ct調(diào)用get_tuple函數(shù)獲取報文的tuple結(jié)構(gòu),返回到第四個參數(shù)&tuple里:get_tuple(skb->nh.iph,skb,skb->nh.iph->ihl*4,&tuple,proto)tftp使用udp協(xié)議,固定端口是69。然后就調(diào)用函數(shù):h=ip_conntrack_find_get(&tuple,NULL)在連接跟蹤表里查找連接,h是一個ip_conntrack_tuple_hash指針,是鏈表的一個節(jié)點查找的時候先計算hash值hash=hash_conntrack(tuple)根據(jù)hash值找到鏈表的入口,然后遍歷鏈表比較tupleLIST_FIND(&ip_conntrack_hash[hash],conntrack_tuple_cmp,structip_conntrack_tuple_hash*,tuple,ignored_conntrack);查不到就新建一個連接,查到了就跳過這一步,這里假設(shè)是第一個數(shù)據(jù)包,那么肯定查不到h=init_conntrack(&tuple,proto,skb)新建連接時首先也要計算hash值(乂算一遍),為了將來決定將它放入哪條鏈用hash=hash_conntrack(tuple)接下來計算相反方向的tuple,即repl_tupleinvert_tuple(&repl_tuple,tuple,protocol)只是而單的將來/目的顛倒而已一個完整的連接狀態(tài)是包括兩個方向的tuple的,可以看到在ip_conntrack結(jié)構(gòu)中structip_conntrack_tuple_hashtuplehash[IP_CT_DIR_MAX]定義了一個conntrack_tuple_hash數(shù)組,它包括tuplehash[IP_CT_DIR_ORIGINAL]和tuplehash[IP_CT_DIR_REPLY]兩個元素然后就要為新的連接創(chuàng)建一個ip_conntrack結(jié)構(gòu)了atomic_set(&conntrack->ct_general.use,1);conntrack->ct_general.destroy=destroy_conntrack;conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple=*tuple;conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack=conntrack;conntrack->tuplehash[IP_CT_DIR_REPLY].tuple=repl_tuple

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論