洞悉linux下的Netfilter&iptables:如何理解連接跟蹤機制?

 如何理解連接跟蹤機制?

 本篇我打算以一個問句開頭,因爲在知識探索的道路上只有多問然後充分調動起思考的機器才能讓自己走得更遠。連接跟蹤定義很簡單:用來記錄和跟蹤連接的狀態。

問:爲什麼又需要連接跟蹤功能呢?

答:因爲它是狀態防火牆NAT的實現基礎。

OK,算是明白了。Neftiler爲了實現基於數據連接狀態偵測的狀態防火牆功能和NAT地址轉換功能才開發出了連接跟蹤這套機制。那就意思是說:如果編譯內核時開啓了連接跟蹤選項,那麼Linux系統就會爲它收到的每個數據包維持一個連接狀態用於記錄這條數據連接的狀態。接下來我們就來研究一下Netfilter的連接跟蹤的設計思想和實現方式。

    之前有一副圖,我們可以很明確的看到:用於實現連接跟蹤入口hook函數以較高的優先級分別被註冊到了netfitlerNF_IP_PRE_ROUTINGNF_IP_LOCAL_OUT兩個hook點上;用於實現連接跟蹤出口hook函數以非常低的優先級分別被註冊到了netfilterNF_IP_LOCAL_INNF_IP_POST_ROUTING兩個hook點上。

其實PRE_ROUTING和LOCAL_OUT點可以看作是整個netfilter的入口,而POST_ROUTING和LOCAL_IN可以看作是其出口。在只考慮連接跟蹤的情況下,一個數據包無外乎有以下三種流程可以走:

一、發送給本機的數據包

流程:PRE_ROUTING----LOCAL_IN---本地進程

二、需要本機轉發的數據包

流程:PRE_ROUTING---FORWARD---POST_ROUTING---外出

三、從本機發出的數據包

流程:LOCAL_OUT----POST_ROUTING---外出


我們都知道在INET層用於表示數據包的結構是大名鼎鼎的sk_buff{}(後面簡稱skb),如果你不幸的沒聽說過這個東東,那麼我強烈的建議你先補一下網絡協議棧的基礎知識再繼續閱讀這篇文章。在skb中有個成員指針nfct,類型是struct nf_conntrack{},該結構定義在include/linux/skbuff.h文件中。該結構記錄了連接記錄被公開應用的計數,也方便其他地方對連接跟蹤的引用。連接跟蹤在實際應用中一般都通過強制類型轉換將nfct轉換成指向ip_conntrack{}類型(定義在include/linux/netfilter_ipv4/ip_conntrack.h裏)來獲取一個數據包所屬連接跟蹤的狀態信息的。即:Neftilter框架用ip_conntrack{}來記錄一個數據包與其連接的狀態關係

同時在include/linux/netfilter_ipv4/ip_conntrack.h文件中還提供了一個非常有用的接口:struct ip_conntrack *ip_conntrack_get(skb, ctinfo)用於獲取一個skb的nfct指針,從而得知該數據包的連接狀態和該連接狀態的相關信息ctinfo。從連接跟蹤的角度來看,這個ctinfo表示了每個數據包的幾種連接狀態:

l  IP_CT_ESTABLISHED

Packet是一個已建連接的一部分,在其初始方向。

l  IP_CT_RELATED

Packet屬於一個已建連接的相關連接,在其初始方向。

l  IP_CT_NEW

Packet試圖建立新的連接

l  IP_CT_ESTABLISHED+IP_CT_IS_REPLY

Packet是一個已建連接的一部分,在其響應方向。

l  IP_CT_RELATED+IP_CT_IS_REPLY

Packet屬於一個已建連接的相關連接,在其響應方向。

    在連接跟蹤內部,收到的每個skb首先被轉換成一個ip_conntrack_tuple{}結構,也就是說ip_conntrack_tuple{}結構纔是連接跟蹤系統所“認識”的數據包。那麼skbip_conntrack_tuple{}結構之間是如何轉換的呢?這個問題沒有一個統一的答案,與具體的協議息息相關。例如,對於TCP/UDP協議,根據“源、目的IP+源、目的端口”再加序列號就可以唯一的標識一個數據包了;對於ICMP協議,根據“源、目的IP+類型+代號”再加序列號纔可以唯一確定一個ICMP報文等等。對於諸如像FTP這種應用層的“活動”協議來說情況就更復雜了。本文不試圖去分析某種具體協議的連接跟蹤實現,而是探究連接跟蹤的設計原理和其工作流程,使大家掌握連接跟蹤的精髓。因爲現在Linux內核更新的太快的都到3.4.x,變化之大啊。就算是2.6.22和2.6.21在連接跟蹤這塊還是有些區別呢。一旦大家理解了連接跟蹤的設計思想,掌握了其神韻,它再怎麼也萬變不離其宗,再看具體的代碼實現時就不會犯迷糊了。俗話說“授人一魚,不如授人一漁”,我們教給大家的是方法。有了方法再加上自己的勤學苦練,那就成了技能,最後可以使得大家在爲自己的協議開發連接跟蹤功能時心裏有數。這也是我寫這個系列博文的初衷和目的。與君共勉。

在開始分析連接跟蹤之前,我們還是站在統帥的角度來俯視一下整個連接跟蹤的佈局。這裏我先用比較粗略的精簡流程圖爲大家做個展示,目的是方便大家理解,好入門。當然,我的理解可能還有不太準確的地方,還請大牛們幫小弟指正。

    我還是重申一下:連接跟蹤分入口和出口兩個點。謹記:入口時創建連接跟蹤記錄,出口時將該記錄加入到連接跟蹤表中。我們分別來看看。

入口:

整個入口的流程簡述如下:對於每個到來的skb,連接跟蹤都將其轉換成一個tuple結構,然後用該tuple去查連接跟蹤表。如果該類型的數據包沒有被跟蹤過,將爲其在連接跟蹤的hash表裏建立一個連接記錄項,對於已經跟蹤過了的數據包則不用此操作。緊接着,調用該報文所屬協議的連接跟蹤模塊的所提供的packet()回調函數,最後根據狀態改變連接跟蹤記錄的狀態。

出口:

整個出口的流程簡述如下:對於每個即將離開Netfilter框架的數據包,如果用於處理該協議類型報文的連接跟蹤模塊提供了helper函數,那麼該數據包首先會被helper函數處理,然後纔去判斷,如果該報文已經被跟蹤過了,那麼其所屬連接的狀態,決定該包是該被丟棄、或是返回協議棧繼續傳輸,又或者將其加入到連接跟蹤表中。


連接跟蹤的協議管理:

    我們前面曾說過,不同協議其連接跟蹤的實現是不相同的。每種協議如果要開發自己的連接跟蹤模塊,那麼它首先必須實例化一個ip_conntrack_protocol{}結構體類型的變量,對其進行必要的填充,然後調用ip_conntrack_protocol_register()函數將該結構進行註冊,其實就是根據協議類型將其設置到全局數組ip_ct_protos[]中的相應位置上。

     ip_ct_protos變量裏保存連接跟蹤系統當前可以處理的所有協議,協議號作爲數組唯一的下標,如下圖所示。

    結構體ip_conntrack_protocol{}中的每個成員,內核源碼已經做了很詳細的註釋了,這裏我就不一一解釋了,在實際開發過程中我們用到了哪些函數再具體分析。


  連接跟蹤的輔助模塊:

    Netfilter的連接跟蹤爲我們提供了一個非常有用的功能模塊:helper。該模塊可以使我們以很小的代價來完成對連接跟蹤功能的擴展。這種應用場景需求一般是,當一個數據包即將離開Netfilter框架之前,我們可以對數據包再做一些最後的處理。從前面的圖我們也可以看出來,helper模塊以較低優先級被註冊到了Netfilter的LOCAL_OUT和POST_ROUTING兩個hook點上。

每一個輔助模塊都是一個ip_conntrack_helper{}結構體類型的對象。也就是說,如果你所開發的協議需要連接跟蹤輔助模塊來完成一些工作的話,那麼你必須也去實例化一個ip_conntrack_helper{}對象,對其進行填充,最後調用ip_conntrack_helper_register{}函數將你的輔助模塊註冊到全局變量helpers裏,該結構是個雙向鏈表,裏面保存了當前已經註冊到連接跟蹤系統裏的所有協議的輔助模塊。

全局helpers變量的定義和初始化在net/netfilter/nf_conntrack_helper.c文件中完成的。

最後,我們的helpers變量所表示的雙向鏈表一般都是像下圖所示的這樣子:

由此我們基本上就可以知道,註冊在Netfilter框架裏LOCAL_OUTPOST_ROUTING兩個hook點上ip_conntrack_help()回調函數所做的事情基本也就很清晰了:那就是通過依次遍歷helpers鏈表,然後調用每個ip_conntrack_helper{}對象的help()函數。


期望連接:

    Netfilter的連接跟蹤爲支持諸如FTP這樣的“活動”連接提供了一個叫做“期望連接”的機制。我們都知道FTP協議服務端用21端口做命令傳輸通道,主動模式下服務器用20端口做數據傳輸通道;被動模式下服務器隨機開一個高於1024的端口,然後客戶端來連接這個端口開始數據傳輸。也就是說無論主、被動,都需要兩條連接:命令通道的連接和數據通道的連接。連接跟蹤在處理這種應用場景時提出了一個“期望連接”的概念,即一條數據連接和另外一條數據連接是相關的,然後對於這種有“相關性”的連接給出自己的解決方案。我們說過,本文不打算分析某種具體協議連接跟蹤的實現。接下來我們就來談談期望連接。

    每條期望連接都用一個ip_conntrack_expect{}結構體類型的對象來表示,所有的期望連接存儲在由全局變量ip_conntrack_expect_list所指向的雙向鏈表中,該鏈表的結構一般如下:

         結構體ip_conntrack_expect{}中的成員及其意義在內核源碼中也做了充分的註釋,這裏我就不逐一介紹了,等到需要的時候再詳細探討。


連接跟蹤表:

    說了半天終於到我們連接跟蹤表拋頭露面的時候了。連接跟蹤表是一個用於記錄所有數據包連接信息的hash散列表,其實連接跟蹤表就是一個以數據包的hash值組成的一個雙向循環鏈表數組,每條鏈表中的每個節點都是ip_conntrack_tuple_hash{}類型的一個對象。連接跟蹤表是由一個全局的雙向鏈表指針變量ip_conntrack_hash[]來表示。爲了使我們更容易理解ip_conntrack_hash[]這個雙向循環鏈表的數組,我們將前面提到的幾個重要的目前還未介紹的結構ip_conntrack_tuple{}ip_conntrack{}ip_conntrack_tuple_hash{}分別介紹一下。

    我們可以看到ip_conntrack_tuple_hash{}僅僅是對ip_conntrack_tuple{}的封裝而已,將其組織成了一個雙向鏈表結構。因此,在理解層面上我們可以認爲它們是同一個東西。

在分析ip_conntrack{}結構時,我們將前面所有和其相關的數據結構都列出來,方便大家對其理解和記憶。

該圖可是說是連接跟蹤部分的數據核心,接下來我們來詳細說說ip_conntrack{}結構中相關成員的意義。

l  ct_general:該結構記錄了連接記錄被公開應用的計數,也方便其他地方對連接跟蹤的引用。

l  status:數據包連接的狀態,是一個比特位圖。

l  timeout:不同協議的每條連接都有默認超時時間,如果在超過了該時間且沒有屬於某條連接的數據包來刷新該連接跟蹤記錄,那麼會調用這種協議類型提供的超時函數。

l  counters:該成員只有在編譯內核時打開了CONFIG_IP_NF_CT_ACCT開完纔會存在,代表某條連接所記錄的字節數和包數。

l  master:該成員指向另外一個ip_conntrack{}。一般用於期望連接場景。即如果當前連接是另外某條連接的期望連接的話,那麼該成員就指向那條我們所屬的主連接。

l  helper:如果某種協議提供了擴展模塊,就通過該成員來調用擴展模塊的功能函數。

l  proto:該結構是ip_conntrack_proto{}類型,和我們前面曾介紹過的用於存儲不同協議連接跟蹤的ip_conntrack_protocol{}結構不要混淆了。前者是個枚舉類型,後者是個結構體類型。這裏的proto表示不同協議爲了實現其自身的連接跟蹤功能而需要的一些額外參數信息。目前這個枚舉類型如下:

   如果將來你的協議在實現連接跟蹤時也需要一些額外數據,那麼可以對該結構進行擴充。

l  help:該成員代表不同的應用爲了實現其自身的連接跟蹤功能而需要的一些額外參數信息,也是個枚舉類型的ip_conntrack_help{}結構,和我們前面剛介紹過的結構體類型ip_conntrack_helpers{}容易混淆。ip_conntrack_proto{}是爲協議層需要而存在的,而ip_conntrack_help{}是爲應用層需要而存在

l  tuplehash:該結構是個ip_conntrack_tuple_hash{}類型的數組,大小爲2。tuplehash[0]表示一條數據流“初始”方向上的連接情況,tuplehash[1]表示該數據流“應答”方向的響應情況,見上圖所示。

    到目前爲止,我們已經瞭解了連接跟蹤設計思想和其工作機制:連接跟蹤是Netfilter提供的一套基礎框架,不同的協議可以根據其自身協議的特殊性在連接跟蹤機制的指導和約束下來開發本協議的連接跟蹤功能,最後將其交給連接跟蹤機制來統一管理。

Netfilter連接跟蹤的詳細流程

    上一篇我們瞭解了連接跟蹤的基本框架和大概流程,本篇我們着重分析一下,數據包在連接跟蹤系統裏的旅程,以達到對連接跟蹤運行原理深入理解的目的。

    連接跟蹤機制在Netfilter框架裏所註冊的hook函數一共就五個:ip_conntrack_defrag()、ip_conntrack_in()、ip_conntrack_local()、ip_conntrack_help()

和ip_confirm()。前幾篇博文中我們知道ip_conntrack_local()最終還是調用了ip_conntrack_in()。這五個hook函數及其掛載點,想必現在大家應該也已經爛熟於心了,如果記不起來請看【上】篇博文。

    在連接跟蹤的入口處主要有三個函數在工作:ip_conntrack_defrag()、ip_conntrack_in()、ip_conntrack_local();在出口處就兩個:ip_conntrack_help()和ip_confirm()。

接下來的事情就變得非常奇妙,請大家將自己當作一個需要轉發的數據包,且是一條新的連接。然後跟隨我去連接跟蹤裏耍一圈吧。在進入連接跟蹤之前,我需要警告大家:連接跟蹤雖然不會改變數據包本身,但是它可能會將數據包丟棄。


我們的旅行的線路圖已經有了:

ip_conntrack_defrag()

    當我們初到連接跟蹤門口的時候,是這位小生來招待我們。這個函數主要是完成IP報文分片的重新組裝,將屬於一個IP報文的多個分片重組成一個真正的報文。關於IP分片,大家可以去閱讀《TCP/IP詳解卷1》瞭解一點基礎,至於IP分片是如何被重新組裝一個完整的IP報文也不是我們的重心,這裏不展開講。該函數也向我們透露了一個祕密,那就是連接跟蹤只跟蹤完整的IP報文,不對IP分片進行跟蹤,所有的IP分片都必須被還原成原始報文,才能進入連接跟蹤系統。

 

ip_conntrack_in()

    該函數的核心是resolve_normal_ct()函數所做的事情,其執行流程如下所示:

在接下來的分析中,需要大家對上一篇文章提到的幾個數據結構:

ip_conntrack{}、ip_conntrack_tuple{}、ip_conntrack_tuple_hash{}和ip_conntrack_protocol{}以及它們的關係必須弄得很清楚,你才能徹底地讀懂resolve_normal_ct()函數是幹什麼。最好手頭再有一份2.6.21的內核源碼,然後打開source insight來對照着閱讀效果會更棒!

第一步:ip_conntrack_in()函數首先根據數據包skb的協議號,在全局數組ip_ct_protos[]中查找某種協議(如TCP,UDP或ICMP等)所註冊的連接跟蹤處理模塊ip_conntrack_protocol{},如下所示。

在結構中,具體的協議必須提供將屬於它自己的數據包skb轉換成ip_conntrack_tuple{}結構的回調函數pkt_to_tuple()和invert_tuple(),用於處理新連接的new()函數等等。

第二步:找到對應的協議的處理單元proto後,便調用該協議提供的錯誤校驗函數(如果該協議提供的話)error來對skb進行合法性校驗。

    第三步:調用resolve_normal_ct()函數。該函數的重要性不言而喻,它承擔連接跟蹤入口處剩下的所有工作。該函數根據skb中相關信息,調用協議提供的pkt_to_tuple()函數生成一個ip_conntrack_tuple{}結構體對象tuple。然後用該tuple去查找連接跟蹤表,看它是否屬於某個tuple_hash{}鏈。請注意,一條連接跟蹤由兩條ip_conntrack_tuple_hash{}鏈構成,一“去”一“回”,參見上一篇博文末尾部分的講解。爲了使大家更直觀地理解連接跟蹤表,我將畫出來,如下圖,就是個雙向鏈表的數組而已。

如果找到了該tuple所屬於的tuple_hash鏈表,則返回該鏈表的地址;如果沒找到,表明該類型的數據包沒有被跟蹤,那麼我們首先必須建立一個ip_conntrack{}結構的實例,即創建一個連接記錄項。

然後,計算tuple的應答repl_tuple,對這個ip_conntrack{}對象做一番必要的初始化後,其中還包括,將我們計算出來的tuple和其反向tuple的地址賦給連接跟蹤ip_conntrack裏的tuplehash[IP_CT_DIR_ORIGINAL]和tuplehash[IP_CT_DIR_REPLY]。

最後,把ip_conntrack->tuplehash[IP_CT_DIR_ORIGINAL]的地址返回。這恰恰是一條連接跟蹤記錄初始方向鏈表的地址。Netfilter中有一條鏈表unconfirmed,裏面保存了所有目前還沒有收到過確認報文的連接跟蹤記錄,然後我們的ip_conntrack->tuplehash[IP_CT_DIR_ORIGINAL]就會被添加到unconfirmed鏈表中。

第四步:調用協議所提供的packet()函數,該函數承擔着最後向Netfilter框架返回值的使命,如果數據包不是連接中有效的部分,返回-1,否則返回NF_ACCEPT。也就是說,如果你要爲自己的協議開發連接跟蹤功能,那麼在實例化一個ip_conntrack_protocol{}對象時必須對該結構中的packet()函數做仔細設計。

雖然我不逐行解釋代碼,只分析原理,但有一句代碼還是要提一下。

resolve_normal_ct()函數中有一行ct = tuplehash_to_ctrack(h)的代碼,參見源代碼。其中h是已存在的或新建立的ip_conntrack_tuple_hash{}對象,ct是ip_conntrack{}類型的指針。不要誤以爲這一句代碼的是在創建ct對象,因爲創建的工作在init_conntrack()函數中已經完成。本行代碼的意思是根據ip_conntrack{}結構體中tuplehash[IP_CT_DIR_ORIGINAL]成員的地址,反過來計算其所在的結構體ip_conntrack{}對象的首地址,請大家注意。

大家也看到ip_conntrack_in()函數只是創建了用於保存連接跟蹤記錄的ip_conntrack{}對象而已,並完成了對其相關屬性的填充和狀態的設置等工作。簡單來說,我們這個數據包目前已經拿到連接跟蹤系統辦法的“綠卡”ip_conntrack{}了,但是還沒有蓋章生效。

 

ip_conntrack_help()

大家只要把我前面關於鉤子函數在五個HOOK點所掛載情況的那張圖記住,就明白ip_conntrack_help()函數在其所註冊的hook點的位置了。當我們這個數據包所屬的協議在其提供的連接跟蹤模塊時已經提供了ip_conntrack_helper{}模塊,或是別人針對我們這種協議類型的數據包提供了擴展的功能模塊,那麼接下來的事兒就很簡單了:

首先,判斷數據包是否拿到“綠卡”,即連接跟蹤是否爲該類型協議的包生成了連接跟蹤記錄項ip_conntrack{};

其次,該數據包所屬的連接狀態不屬於一個已建連接的相關連接,在其響應方向。

兩個條件都成立,就用該helper模塊提供的help()函數去處理我們這個數據包skb。最後,這個help()函數也必須向Netfilter框架返回NF_ACCEPT或NF_DROP等值。任意一個條件不成立則ip_conntrack_help()函數直接返回NF_ACCEPT,我們這個數據包繼續傳輸。

 

ip_confirm()

    該函數是我們離開Netfilter時遇到的最後一個傢伙了,如果我們這個數據包已經拿到了“綠卡”ip_conntrack{},並且我們這個數據包所屬的連接還沒收到過確認報文,並且該連接還未失效。然後,我們這個ip_confirm()函數要做的事就是:

    拿到連接跟蹤爲該數據包生成ip_conntrack{}對象,根據連接“來”、“去”方向tuple計算其hash值,然後在連接跟蹤表ip_conntrack_hash[]見上圖中查找是否已存在該tuple。如果已存在,該函數最後返回NF_DROP;如果不存在,則將該連接“來”、“去”方向tuple插入到連接跟蹤表ip_conntrack_hash[]裏,並向Netfilter框架返回NF_ACCEPT。之所以要再最後纔將連接跟蹤記錄加入連接跟蹤表是考慮到數據包可能被過濾掉。

    至此,我們本次旅行就圓滿結束了。這裏我們只分析了轉發報文的情況。發送給本機的報文流程與此一致,而對於所有從本機發送出去的報文,其流程上唯一的區別就是在調用ip_conntrack_in()的地方換成了ip_conntrack_local()函數。前面說過,ip_conntrack_local()裏面其實調用的還是ip_conntrack_in()。ip_conntrack_local()裏只是增加了一個特性:那就是對於從本機發出的小數據包不進行連接跟蹤。


連接跟蹤系統的初始化流程分析

    有了前面的知識,我們再分析連接跟蹤系統的初始化ip_conntrack_standalone_init()函數就太容易不過了。還是先上ip_conntrack_standalone_init()函數的流程圖:

該函數的核心上圖已經標出來了“初始化連接跟蹤系統”和“註冊連接跟蹤的hook函數”。其他兩塊這裏簡單做個普及,不展開講。至少讓大家明白連接跟蹤爲什麼需要兩中文件系統。

1、  procfs(/proc文件系統)

這是一個虛擬的文件系統,通常掛載在/proc,允許內核以文件的形式向用戶空間輸出內部信息。該目錄下的所有文件並沒有實際存在在磁盤裏,但可以通過cat、more或>shell重定向予以寫入,這些文件甚至可以像普通文件那樣指定其讀寫權限。創建這些文件的內核組件可以說明任何一個文件可以由誰讀取或寫入。但是:用戶不能在/proc目錄下新增,移除文件或目錄

2、  sysctl(/proc/sys目錄)

此接口允許用戶空間讀取或修改內核變量的值。不能用此接口對每個內核變量進行操作:內核應該明確指出哪些變量從此接口對用戶空間是可見的。從用戶空間,你可以用兩種方式訪問sysctl輸出的變量:sysctl系統調用接口;procfs。當內核支持procfs文件系統時,會在/proc中增加一個特殊目錄(/proc/sys),爲每個由sysctl所輸出的內核變量引入一個文件,我們通過對這些文件的讀寫操作就可以影響到內核裏該變量的值了。

    除此之外還有一種sysfs文件系統,這裏就不介紹了,如果你感興趣可以去研讀《Linux設備驅動程序》一書的詳細講解。

    那麼回到我們連接跟蹤系統裏來,由此我們可以知道:連接跟蹤系統向用戶空間輸出一些內核變量,方便用戶對連接跟蹤的某些特性加以靈活控制,如改變最大連接跟蹤數、修改TCP、UDP或ICMP協議的連接跟蹤超時是時限等等。

    注意一點:/proc/sys目錄下的任何一個文件名,對應着內核中有一個一模一樣同名的內核變量。例如,我的系統中該目錄是如下這個樣子:

ip_conntrack_init()函數

    該函數承擔了連接跟蹤系統初始化的絕大部分工作,其流程我們也畫出來了,大家可以對照源碼來一步一步分析。

    第一步:連接跟蹤的表大小跟系統內存相關,而最大連接跟蹤數和連接跟蹤表容量的關係是:最大連接跟蹤數=8×連接跟蹤表容量。代碼中是這樣的:

ip_conntrack_max = 8 × ip_conntrack_htable_size;那麼從上面的圖我們可以看出來,我們可以通過手工修改/proc/sys/net/ipv4/netfilter目錄下同名的ip_conntrack_max文件即可動態修改連接系統的最大連接跟蹤數了。

    第二步:註冊Netfilter所用的sockopt,先不講,以後再說。只要知道是這裏註冊的就行了。

    第三步:爲連接跟蹤hash表ip_conntrack_hash分配內存並進行初始化。並創建連接跟蹤和期望連接跟蹤的高速緩存。

    第四步:將TCPUDPICMP協議的連接跟蹤協議體,根據不同協議的協議號,註冊到全局數組ip_ct_protos[]中,如下所示:

    最後再做一些善後工作,例如註冊DROP這個target所需的功能函數,爲其他諸如NAT這樣的模塊所需的參數ip_conntrack_untracked做初始化,關於這個參數我們在NAT模塊中再詳細討論它。

    這樣,我們連接跟蹤系統的初始化工作就算徹底完成了。有了前幾篇關於連接跟蹤的基礎知識,再看代碼是不是有種神清氣爽,豁然開朗的感覺。

    至於連接跟蹤系統所提供的那五個hook函數的註冊,我想現在的你應該連都不用看就知道它所做的事情了吧。

http://www.360doc.com/content/12/1120/22/706976_249199467.shtml
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章