iptables--狀態機制

1.概述

狀態機制是 iptables 中特殊的一部分,其實它不應該叫狀態機制,因爲它只是一種連接跟蹤機制。連接跟蹤可以讓 Netfilter 知道某個特定連接的狀態。運行連接跟蹤的防火牆稱作帶有狀態機制的防火牆,以下簡稱爲狀態防火牆。狀態防火牆比非狀態防火牆要安全,因爲它允許我們編寫更嚴密的規則。在 iptables 裏,包是和被跟蹤連接的四種不同狀態有關的。它們是NEW,ESTABLISHED,
RELATED 和INVALID。所有在內核中由 Netfilter 的特定框架做的連接跟蹤稱作 conntrack。conntrack 中有許多用來處理 TCP,
UDP 或 ICMP 協議的部件。這些模塊從數據包中提取詳細的、唯一的信息,因此能保持對每一個數據流的跟蹤。這些信息也告知 conntrack 流當前的狀態。例如,UDP 流一般由他們的目的地址、源地址、目的端口和源端口唯一確定。
除了本地產生的包由 OUTPUT 鏈處理外,所有連接跟蹤都是在 PREROUTING 鏈裏進行處理的,意思就是, iptables 會在 PREROUTING 鏈裏從新計算所有的狀態。如果我們發送一個流的初始化包,狀態就會在 OUTPUT 鏈裏被設置爲 NEW,當我們收到迴應的包時,狀態就會在 PREROUTING 鏈裏被設置爲 ESTABLISHED。如果第一個包不是本地產生的,那就會在PREROUTING 鏈裏被設置爲 NEW 狀態。綜上,所有狀態的改變和計算都是在 nat 表中的 PREROUTING 鏈和 OUTPUT 鏈裏完成的。

2.conntrack記錄

查看文件/proc/net/ip_conntrack 裏的 conntrack 記錄。這些記錄表示的是當前被跟蹤的連接。

tcp 6 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,說明這個連接還沒有收到任何迴應。最後,是希望接收的應答包的信息,他們的地址和端口和前面是相反的。
當一個連接在兩個方向上都有傳輸時,conntrack 記錄就刪除[UNREPLIED]標誌,然後重置。在末尾有 [ASSURED]的記錄說明兩個方向已沒有流量。這樣的記錄是確定的,在連接跟蹤表滿時,是不會被刪除的,沒有[ASSURED]的記錄就要被刪
除。連接跟蹤表能容納多少記錄是被一個變量控制的,它可由內核中的 ip-sysctl 函數設置。默認值取決於你的內存大小,128MB 可以包含 8192 條目錄,256MB 是 16376 條。你也可以在 /proc/sys/net/ipv4/ip_conntrack_max 裏查看/設置。

3.用戶空間的狀態

包的狀態依據 IP 所包含的協議不同而不同,但在內核外部,也就是用戶空間裏,只有 4 種狀態:NEW,ESTABLISHED,RELATED 和 INVALID。它們主要是和狀態匹配一起使用。下面就簡要地介紹以下這幾種狀態:

State(狀態) Explanation(註釋)
NEW 說明這個包是我們看到的第一個包。意思就是,這是 conntrack模塊看到的某個連接第一個包,它即將被匹配了。比如,我們看到一個 SYN 包,是我們所留意的連接的第一個包,就要匹配它。第一個包也可能不是 SYN 包,但它仍會被認爲是 NEW 狀態。這樣做有時會導致一些問題,但對某些情況是有非常大的幫助的。例如,在我們想恢復某條從其他的防火牆丟失的連接時,或者某個連接已經超時,但實際上並未關閉時。
ESTABLISHED 已經注意到兩個方向上的數據傳輸,而且會繼續匹配這個連接的包。處於 ESTABLISHED 狀態的連接是非常容易理解的。只要發送並接到應答,連接就是 ESTABLISHED 的了。一個連接要從NEW 變爲 ESTABLISHED,只需要接到應答包即可,不管這個包是發往防火牆的,還是要由防火牆轉發的。ICMP 的錯誤和重定向等信息包也被看作是 ESTABLISHED,只要它們是我們所發出的信息的應答。
RELATED 是個比較麻煩的狀態。當一個連接和某個已處於ESTABLISHED 狀態的連接有關係時,就被認爲是 RELATED 的了。換句話說,一個連接要想是 RELATED 的,首先要有一個 ESTABLISHED的連接。這個 ESTABLISHED 連接再產生一個主連接之外的連接,這個新的連接就是 RELATED 的了,當然前提是 conntrack 模塊要能理解 RELATED。ftp 是個很好的例子,FTP-data 連接就是和FTP-control 有 RELATED 的。還有其他的例子,比如,通過 IRC 的DCC 連接。有了這個狀態,ICMP 應答、FTP 傳輸、DCC 等才能穿過防火牆正常工作。注意,大部分還有一些 UDP 協議都依賴這個機制。這些協議是很複雜的,它們把連接信息放在數據包裏,並且要求這些信息能被正確理解。
INVALID 說明數據包不能被識別屬於哪個連接或沒有任何狀態。有幾個原因可以產生這種情況,比如,內存溢出,收到不知屬於哪個連接的 ICMP 錯誤信息。一般地,我們 DROP 這個狀態的任何東西。

這些狀態可以一起使用,以便匹配數據包。這可以使我們的防火牆非常強壯和有效。以前,我們經常打開 1024 以上的所有端口來放行應答的數據。現在,有了狀態機制,就不需再這樣了。因爲我們可以只開放那些有應答數據的端口,其他的都可以關閉。這樣就安全多了。

4.TCP連接

一個 TCP 連接是經過三次握手協商連接信息才建立起來的。整個會話由一個 SYN包開始,然後是一個 SYN/ACK 包,最後是一個 ACK 包,此時,會話才建立成功,能夠發送數據。最大的問題在於連接跟蹤怎樣控制這個過程。其實非常簡單。
默認情況下,連接跟蹤基本上對所有的連接類型做同樣的操作。看看下面的圖片,我們就能明白在連接的不同階段,流是處於什麼狀態的。就如你看到的,連接跟蹤的代碼不是從用戶的觀點來看待 TCP 連接建立的流程的。連接跟蹤一看到 SYN包,就認爲這個連接是 NEW 狀態,一看到返回的 SYN/ACK 包,就認爲連接是ESTABLISHED 狀態。如果你仔細想想第二步,應該能理解爲什麼。有了這個特殊處理,NEW 和 ESTABLISHED 包就可以發送出本地網絡,且只有 ESTABLISHED 的連接纔能有迴應信息。如果把整個建立連接的過程中傳輸的數據包都看作 NEW,那麼三次握手所用的包都是 NEW 狀態的,這樣我們就不能阻塞從外部到本地網絡的連接了。因爲即使連接是從外向內的,但它使用的包也是 NEW 狀態的,而且爲了其他連接能正常傳輸,我們不得不允許 NEW 狀態的包返回並進入防火牆。

下面介紹 TCP 連接在建立連接過程中的狀態:
建立連接過程

tcp 6 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 6 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 6 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 分鐘。之所以留這個時間,是爲了讓數據包能完全通過各種規則的檢查,也是爲了數據包能通過擁擠的路由器,從而到達目的地。
如果連接是被 RST 包重置的,就直接變爲 CLOSE 了。這意味着在關閉之前只有10 秒的默認時間。RST 包是不需要確認的,它會直接關閉連接。針對 TCP 連接,還有其他一些狀態我們沒有談到。下面給出一個完整的狀態列表和超時值。內部狀態如下:

State Timeout value
NONE 30 minutes
ESTABLISHED 5 days
SYN_SENT 2 minutes
SYN_RECV 60 seconds
FIN_WAIT 2 minutes
TIME_WAIT 2 minutes
CLOSE 10 seconds
CLOSE_WAIT 12 hours
LAST_ACK 30 seconds
LISTEN> 2 minutes

這些值不是絕對的,可以隨着內核的修訂而變化,也可以通過/proc/sys/net/ipv4/netfilter/ip_ct_tcp_*的變量更改。這些默認值都是經過實踐檢驗的。它們的單位是 jiffies(百分之一秒),所以 3000 就代表 30 秒。

5.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秒是短了點兒,但對大部分應用足夠了。只要遇到這個連接的包穿過防火牆,超時值就會被重置爲默認值,所有的狀態都是這樣的。

6.ICMP連接

ICMP 也是一種無狀態協議,它只是用來控制而不是建立連接。常用的回顯請求和應答(Echo request and reply),有兩種狀態 NEW 和 ESTABLISHED 。
比如 ping 命令。
ICMP連接
主機向目標發送一個回顯請求,防火牆就認爲這個包處於 NEW 狀態。目標迴應一個回顯應答,防火牆就認爲包處於 ESTABLISHED 了。當回顯請求被髮送時,ip_conntrack 裏就有這樣的記錄了:

icmp 1 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 的,如下圖:
ICMP不可達
我們發送了一個 SYN 包到某一地址,防火牆認爲它的狀態是 NEW。但是,目標網絡有問題不可達,路由器就會返回網絡不可達的信息,這是 RELATED 的。連接跟蹤會認出這個錯誤信息是哪個連接的,連接會中斷,同時相應的記錄刪除會被刪除。

7.缺省的連接操作

有時,conntrack 機制並不知道如何處理某個特殊的協議,尤其是在它不瞭解這
個協議或不知道協議如何工作時,比如,NETBLT,MUX 還有 EGP。這種情況下,conntrack 使用缺省的操作。這種操作很象對 UDP 連接的操作,就是第一個包被認作 NEW,其後的應答包等等數據都是 ESTABLISHED。 使用缺省操作的包的超時值都是一樣的,600 秒,也就是 10 分鐘。當然,這個值可以通過/proc/sys/net/ipv4/netfilter/ip_ct_generic_timeout 更改,以便適應你的通信量,尤其是在耗時較多、流量巨大的情況下,比如使用衛星等

8.複雜協議和連接跟蹤

有些協議比其他協議更復雜,這裏複雜的意思是指連接跟蹤機制很難正確地跟蹤它們,比如,ICQ、IRC 和 FTP,它們都在數據包的數據域裏攜帶某些信息,這些信息用於建立其他的連接。

溫馨提示:
以上文章描述如有不清晰之處,歡迎在評論區評論,如有時間,會第一時間回覆,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章