連接跟蹤詳解


簡介        

       狀態機制是iptables中特殊的一部分,其實它不應該叫狀態機制,因為它只是一種連接跟蹤機制。但 是,很多人都認可狀態機制這個名字。文中我也或多或或少地用這個名字來表示和連接跟蹤相同的意思。這 不應該引起什么混亂的。連接跟蹤可以讓Netfilter知道某個特定連接的狀態。運行連接跟蹤的防火牆稱作 帶有狀態機制的防火牆,以下簡稱為狀態防火牆。狀態防火牆比非狀態防火牆要安全,因為它允許我們編寫 更嚴密的規則。

在iptables里,包是和被跟蹤連接的四種不同狀態有關的。它們是NEW,ESTABLISHED,RELATED和INVALID。 后面我們會深入地討論每一個狀態。使用--state匹配操作,我們能很容易地控制 “誰或什么能發起新的會話”。

所有在內核中由Netfilter的特定框架做的連接跟蹤稱作conntrack(譯者注:就是connection tracking 的首字母縮寫)。conntrack可以作為模塊安裝,也可以作為內核的一部分。大部分情況下,我們想要,也 需要更詳細的連接跟蹤,這是相比於缺省的conntrack而言。也因為此,conntrack中有許多用來處理TCP, UDP或ICMP協議的部件。這些模塊從數據包中提取詳細的、唯一的信息,因此能保持對每一個數據流的跟 蹤。這些信息也告知conntrack流當前的狀態。例如,UDP流一般由他們的目的地址、源地址、目的端口和源 端口唯一確定。

在以前的內核里,我們可以打開或關閉重組功能。然而,自從iptables和Netfilter,尤其是連接跟蹤被 引入內核,這個選項就被取消了。因為沒有包的重組,連接跟蹤就不能正常工作。現在重組已經整合入 conntrack,並且在conntrack啟動時自動啟動。不要關閉重組功能,除非你要關閉連接跟蹤。

除了本地產生的包由OUTPUT鏈處理外,所有連接跟蹤都是在PREROUTING鏈里進行處理的,意思就是, iptables會在PREROUTING鏈里從新計算所有的狀態。如果我們發送一個流的初始化包,狀態就會在OUTPUT鏈 里被設置為NEW,當我們收到回應的包時,狀態就會在PREROUTING鏈里被設置為ESTABLISHED。如果第一個包不是本地產生的,那就會在PREROUTING鏈里被設置為NEW狀 態。綜上,所有狀態的改變和計算都是在nat表中的PREROUTING鏈和OUTPUT鏈里完成的。

conntrack記錄

 

       我們先來看看怎樣閱讀/proc/net/ip_conntrack里的conntrack記錄。這些記 錄表示的是當前被跟蹤的連接。如果安裝了ip_conntrack模塊,cat /proc/net/ip_conntrack 的顯示類似:

tcp      117 SYN_SENT src=192.168.1.6 dst=192.168.1.9 sport=32775 \     dport=22 [UNREPLIED] src=192.168.1.9 dst=192.168.1.6 sport=22 \     dport=32775 use=2

 

 

 

      conntrack模塊維護的所有信息都包含在這個例子中了,通過它們就可以知道某個特定的連接處於什么狀 態。首先顯示的是協議,這里是tcp,接着是十進制的6(譯者注:tcp的協議類型代碼是6)。之后的117是 這條conntrack記錄的生存時間,它會有規律地被消耗,直到收到這個連接的更多的包。那時,這個值就會 被設為當時那個狀態的缺省值。接下來的是這個連接在當前時間點的狀態。上面的例子說明這個包處在狀態 SYN_SENT,這個值是iptables顯示的,以便我們好理解,而內部用的值稍有不同。SYN_SENT說明我們正在觀 察的這個連接只在一個方向發送了一TCP SYN包。再下面是源地址、目的地址、源端口和目的端口。其 中有個特殊的詞UNREPLIED,說明這個連接還沒有收到任何回應。最后,是希望接收的應答包的信息,他們 的地址和端口和前面是相反的。

        連接跟蹤記錄的信息依據IP所包含的協議不同而不同,所有相應的值都是在頭文件linux/include/netfilter-ipv4/ip_conntrack*.h中定義的。IP、TCP、UDP、ICMP協 議的缺省值是在linux/include/netfilter-ipv4/ip_conntrack.h里定義的。具 體的值可以查看相應的協議,但我們這里用不到它們,因為它們大都只在conntrack內部使用。隨着狀態的 改變,生存時間也會改變。

       當一個連接在兩個方向上都有傳輸時,conntrack記錄就刪除[UNREPLIED]標志,然后重置。在末尾有 [ASSURED]的記錄說明兩個方向已沒有流量。這樣的記錄是確定的,在連接跟蹤表滿時,是不會被刪除的, 沒有[ASSURED]的記錄就要被刪除。連接跟蹤表能容納多少記錄是被一個變量控制的,它可由內核中的ip- sysctl函數設置。默認值取決於你的內存大小,128MB可以包含8192條目錄,256MB是16376條。你也可以在 /proc/sys/net/ipv4/ip_conntrack_max里查看、設置。

連接跟蹤具體分析

TCP

 

 

        一個TCP連接是經過三次握手協商連接信息才建立起來的。整個會話由一個SYN包開始,然后是一個 SYN/ACK包,最后是一個ACK包,此時,會話才建立成功,能夠發送數據。最大的問題在於連接跟蹤怎樣控制 這個過程。其實非常簡單。

默認情況下,連接跟蹤基本上對所有的連接類型做同樣的操作。看看下面的圖片,我們就能明白在連接 的不同階段,流是處於什么狀態的。就如你看到的,連接跟蹤的代碼不是從用戶的觀點來看待TCP連接建立 的流程的。連接跟蹤一看到SYN包,就認為這個連接是NEW狀態,一看到返回的SYN/ACK包,就認為連接是 ESTABLISHED狀態。如果你仔細想想第二步,應該能理解為什么。有了這個特殊處理,NEW和ESTABLISHED包 就可以發送出本地網絡,且只有ESTABLISHED的連接才能有回應信息。如果把整個建立連接的過程中傳輸的 數據包都看作NEW,那么三次握手所用的包都是NEW狀態的,這樣我們就不能阻塞從外部到本地網絡的連接 了。因為即使連接是從外向內的,但它使用的包也是NEW狀態的,而且為了其他連接能正常傳輸,我們不得 不允許NEW狀態的包返回並進入防火牆。更復雜的是,針對TCP連接內核使用了很多內部狀態,它們的定義在 RFC 793 - Transmission Control Protocol的21-23頁。但好在我們在用 戶空間用不到。后面我們會詳細地介紹這些內容。

 

正如你看到的,以用戶的觀點來看,這是很簡單的。但是,從內核的角度看這一塊還有點困難的。我們 來看一個例子。認真考慮一下在/proc/net/ip_conntrack里,連接的狀態是如何 改變的。

tcp      117 SYN_SENT src=192.168.1.5 dst=192.168.1.35 sport=1031 \     dport=23 [UNREPLIED] src=192.168.1.35 dst=192.168.1.5 sport=23 \     dport=1031 use=1

 

 

從上面的記錄可以看出,SYN_SENT狀態被設置了,這說明連接已經發出一個SYN包,但應答還沒發送過 來,這可從[UNREPLIED]標志看出。

tcp      57 SYN_RECV src=192.168.1.5 dst=192.168.1.35 sport=1031 \     dport=23 src=192.168.1.35 dst=192.168.1.5 sport=23 dport=1031 \     use=1

 

 

現在我們已經收到了相應的SYN/ACK包,狀態也變為SYN_RECV,這說明最初發出的SYN包已正確傳輸,並 且SYN/ACK包也到達了防火牆。 這就意味着在連接的兩方都有數據傳輸,因此可以認為兩個方向都有相應的 回應。當然,這是假設的。

tcp      431999 ESTABLISHED src=192.168.1.5 dst=192.168.1.35 \     sport=1031 dport=23 src=192.168.1.35 dst=192.168.1.5 \     sport=23 dport=1031 use=1

 

 

現在我們發出了三步握手的最后一個包,即ACK包,連接也就進入ESTABLISHED狀態了。再傳輸幾個數據 包,連接就是[ASSURED]的了。

下面介紹TCP連接在關閉過程中的狀態。

      如上圖,在發出最后一個ACK包之前,連接(指兩個方向)是不會關閉的。注意,這只是針對一般的情 況。連接也可以通過發送關閉,這用在拒絕一個連接的時候。在RST包發送之后,要經過預先設定的一段時 間,連接才能斷掉。

    連接關閉后,進入TIME_WAIT狀態,缺省時間是2分鍾。之所以留這個時間,是為了讓數據包能完全通過 各種規則的檢查,也是為了數據包能通過擁擠的路由器,從而到達目的地。

UDP

        UDP連接是無狀態的,因為它沒有任何的連接建立和關閉過程,而且大部分是無序列號的。以某個順序收 到的兩個數據包是無法確定它們的發出順序的。但內核仍然可以對UDP連接設置狀態。我們來看看是如何跟 蹤UDP連接的,以及conntrack的相關記錄。

 

      從上圖可以看出,以用戶的角度考慮,UDP連接的建立幾乎與TCP的一樣。雖然conntrack信息看起來有點 兒不同,但本質上是一樣的。下面我們先來看看第一個UDP包發出后的conntrack記錄。

udp      17 20 src=192.168.1.2 dst=192.168.1.5 sport=137 dport=1025 \
    [UNREPLIED] src=192.168.1.5 dst=192.168.1.2 sport=1025 \
    dport=137 use=1   

從前兩個值可知,這是一個UDP包。第一個是協議名稱,第二個是協議號,第三個是此狀態的生存時間, 默認是30秒。接下來是包的源、目地址和端口,還有期待之中回應包的源、目地址和端口。[UNREPLIED]標 記說明還未收到回應。

udp      17 170 src=192.168.1.2 dst=192.168.1.5 sport=137 \     dport=1025 src=192.168.1.5 dst=192.168.1.2 sport=1025 \     dport=137 use=1

 

 

        一旦收到第一個包的回應,[UNREPLIED]標記就會被刪除,連接就被認為是ESTABLISHED的,但在記錄里 並不顯示ESTABLISHED標記。相應地,狀態的超時時間也變為180秒了。在本例中,只剩170秒了,10秒后, 就會減少為160秒。有個東西是不可少的,雖然它可能會有些變化,就是前面提過的[ASSURED]。要想變為 [ASSURED]狀態,連接上必須要再有些流量。

udp      17 175 src=192.168.1.5 dst=195.22.79.2 sport=1025 \     dport=53 src=195.22.79.2 dst=192.168.1.5 sport=53 \     dport=1025 [ASSURED] use=1

 

 

      可以看出來,[ASSURED]狀態的記錄和前面的沒有多大差別,除了標記由[UNREPLIED]變成[ASSURED]。如 果這個連接持續不了180秒,那就要被中斷。180秒是短了點兒,但對大部分應用足夠了。只要遇到這個連接 的包穿過防火牆,超時值就會被重置為默認值,所有的狀態都是這樣的。

ICMP 

       ICMP也是一種無狀態協議,它只是用來控制而不是建立連接。ICMP包有很多類型,但只有四種類型有應 答包,它們是回顯請求和應答(Echo request and reply),時間戳請求和應答(Timestamp request and reply),信息請求和應答(Information request and reply),還有地址掩碼請求和應答(Address mask request and reply),這些包有兩種狀態,NEW和ESTABLISHED 。時間戳請求和信息請求已經廢除不用了,回顯請求還是常用的,比如ping命令就用的到,地址掩碼請 求不太常用,但是可能有時很有用並且值得使用。看看下面的圖,就可以大致了解ICMP連接的NEW和ESTABLISHED狀態了。

 

       如圖所示,主機向目標發送一個回顯請求,防火牆就認為這個包處於NEW狀態。 目標回應一個回顯應答,防火牆就認為包處於ESTABLISHED了。當回顯請求被發送 時,ip_conntrack里就有這樣的記錄了:

icmp     25 src=192.168.1.6 dst=192.168.1.10 type=8 code=0 \     id=33029 [UNREPLIED] src=192.168.1.10 dst=192.168.1.6 \     type=0 code=0 id=33029 use=1

 

 

       可以看到,ICMP的記錄和TCP、UDP的有點區別,協議名稱、超時時間和源、目地址都一樣,不同之處在 於沒有了端口,而新增了三個新的字段:type,code和id。字段type說明ICMP的類型。code說明ICMP的代 碼,這些代碼在附錄ICMP類型里有說明。id是ICMP包的ID。每個ICMP包被發送時都被分配一個ID,接受方把同樣的ID 分配給應答包,這樣發送方能認出是哪個請求的應答。

[UNREPLIED]的含義和前面一樣,說明數的傳輸只發生在一個方向上,也就是說未收到應答。再往后,是 應答包的源、目地址,還有相應的三個新字段,要注意的是type和code是隨着應答包的不同而變化的,id和 請求包的一樣。

和前面一樣,應答包被認為是ESTABLISHED的。然而,在應答包之后,這個ICMP 連接就不再有數據傳輸了。所以,一旦應答包穿過防火牆,ICMP的連接跟蹤記錄就被銷毀了。

以上各種情況,請求被認為NEW,應答是ESTABLISHED。 換句話說,就是當防火牆看到一個請求包時,就認為連接處於NEW狀態,當有應答 時,就是ESTABLISHED狀態。

ICMP的缺省超時是30秒,可以在/proc/sys/net/ipv4/netfilter/ip_ct_icmp_timeout中修改。這個值是比較合適 的,適合於大多數情況。

ICMP的另一個非常重要的作用是,告訴UDP、TCP連接或正在努力建立的連接發生了什么,這時ICMP應答 被認為是RELATED的。主機不可達和網絡不可達就是這樣的例子。當試圖連接某台機 子不成功時(可能那台機子被關上了),數據包所到達的最后一台路由器就會返回以上的ICMP信息,它們就 是RELATED的,如下圖:

 

       我們發送了一個SYN包到某一地址,防火牆認為它的狀態是NEW。但是,目標網絡 有問題不可達,路由器就會返回網絡不可達的信息,這是RELATED的。連接跟蹤會認 出這個錯誤信息是哪個連接的,連接會中斷,同時相應的記錄刪除會被刪除。

當UDP連接遇到問題時,同樣會有相應的ICMP信息返回,當然它們的狀態也是RELATED ,如下圖:

 

      我們發送一個UDP包,當然它是NEW的。但是,目標網絡被一些防火牆或路由器所 禁止。我們的防火牆就會收到網絡被禁止的信息。防火牆知道它是和哪個已打開的UDP連接相關的,並且把 這個信息(狀態是RELATED)發給它,同時,把相應的記錄刪除。客戶機收到網絡被 禁止的信息,連接將被中斷。

缺省的連接操作

 

      有時,conntrack機制並不知道如何處理某個特殊的協議,尤其是在它不了解這個協議或不知道協議如何 工作時,比如,NETBLT,MUX還有EGP。這種情況下,conntrack使用缺省的操作。這種操作很象對UDP連接的 操作,就是第一個包被認作NEW,其后的應答包等等數據都是 ESTABLISHED。

使用缺省操作的包的超時值都是一樣的,600秒,也就是10分鍾。當然,這個值可以通過/proc/sys/net/ipv4/netfilter/ip_ct_generic_timeout更改,以便適應你的通信 量,尤其是在耗時較多、流量巨大的情況下,比如使用衛星等。

復雜協議和連接跟蹤

 

       有些協議比其他協議更復雜,這里復雜的意思是指連接跟蹤機制很難正確地跟蹤它們,比如,ICQ、IRC 和FTP,它們都在數據包的數據域里攜帶某些信息,這些信息用於建立其他的連接。因此,需要一些特殊的 helper來完成工作。

下面以FTP作為例子。FTP協議先建立一個單獨的連接——FTP控制會話。我們通過這個連接發布命令,其 他的端口就會打開以便傳輸和這個命令相關的數據。這些連接的建立方法有兩種:主動模式和被動模式。先 看看主動模式,FTP客戶端發送端口和IP地址信 息給服務器端,然后,客戶端打開這個端口,服務器端從它自己的20端口(FTP-Data端口號)建立與這個端 口的連接,接着就可以使用這個連接發送數據了。

問題在於防火牆不知道這些額外的連接(相對於控制會話而言),因為這些連接在建立時的磋商信息都 在協議數據包的數據域內,而不是在可分析的協議頭里。因此,防火牆就不知道是不是該放這些從服務器到 客戶機的連接過關。

解決的辦法是為連接跟蹤模塊增加一個特殊的helper,以便能檢測到那些信息。這樣,那些從FTP服務器 到客戶機的連接就可以被跟蹤了,狀態是RELATED,過程如下圖所示:

 

       被動FTP工作方式下,data連接的建立過程和主動FTP的相反。客戶機告訴服務器需要某些數據,服務器 就把地址和端口發回給客戶機,客戶機據此建立連接接受數據。如果FTP服務器在防火牆后面,或你對用戶 限制的比較嚴格,只允許他們訪問HTTP和FTP,而封閉了其他所有端口,為了讓在Internet是的客戶機能訪 問到FTP,也需要增加上面提到的helper。下面是被動模式下data連接的建立過程:

 



 



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM