歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux資訊 >> 更多Linux

iptables的狀態檢測機制

1.什麼是狀態檢測 每個網絡連接包括以下信息:源地址、目的地址、源端口和目的端口,叫作套接字對(socket pairs);協議類型、連接狀態(TCP協議)和超時時間等。防火牆把這些信息叫作狀態(stateful),能夠檢測每個連接狀態的防火牆叫作狀態包過濾防火牆。它除了能夠完成簡單包過濾防火牆的包過濾工作外,還在自己的內存中維護一個跟蹤連接狀態的表,比簡單包過濾防火牆具有更大的安全性。 iptables中的狀態檢測功能是由state選項來實現的。對這個選項,在iptables的手冊頁中有以下描述: state 這個模塊能夠跟蹤分組的連接狀態(即狀態檢測)。 --state state 這裡,state是一個用逗號分割的列表,表示要匹配的連接狀態。有效的狀態選項包括:INVAILD,表示分組對應的連接是未知的; ESTABLISHED,表示分組對應的連接已經進行了雙向的分組傳輸,也就是說連接已經建立;NEW,表示這個分組需要發起一個連接,或者說,分組對應的連接在兩個方向上都沒有進行過分組傳輸;RELATED,表示分組要發起一個新的連接,但是這個連接和一個現有的連接有關,例如:FTP的數據傳輸連接和控制連接之間就是RELATED關系。 對於本地產生分組,在PREROUTING或者OUTPUT鏈中都可以對連接的狀態進行跟蹤。在進行狀態檢測之前,需要重組分組的分片。這就是為什麼在iptables中不再使用ipchains的ip_always_defrag開關。 UDP和TCP連接的狀態表由/proc/net/ip_conntrack進行維護。稍後我們再介紹它的內容。 狀態表能夠保存的最大連接數保存在/proc/sys/net/ipv4/ip_conntrack_max中。它取決於硬件的物理內存。 2.iptables的狀態檢測是如何工作的? 2.1.iptables概述 在討論iptables狀態檢測之前,我們先大體看一下整個netfilter框架。如果要在兩個網絡接口之間轉發一個分組,這個分組將以以下的順序接收規則鏈的檢查: PREROUTING鏈 如果必要對這個分組進行目的網絡地址轉換(DNAT)和mangle處理。同時,iptables的狀態檢測機制將重組分組,並且以以下某種方式跟蹤其狀態: 分組是否匹配狀態表中的一個已經實現(ESTABLISHED)的連接。 它是否是和狀態表中某個UDP/TCP連接相關(RELATED)的一個ICMP分組。 這個分組是否要發起一個新(NEW)的連接。 如果分組和任何連接無關,就被認為是無效(INVALID)的。 FORWARD鏈 把分組的狀態和過濾表中的規則進行匹配,如果分組與所有的規則都無法匹配,就使用默認的策略進行處理。 POSTROUTING鏈 如果有必要,就對分組進行源網絡地址轉換(SNAT), 注意:所有的分組都必須和過濾表的規則進行比較。如果你修改了規則,要拒絕所有的網絡流量,那麼即使分組的狀態匹配狀態表中的一個ESTABLISHED條目,也將被拒絕。 下面,我們對UDP、TCP和ICMP三個協議分別進行分析。 2.2.UDP連接 UDP(用戶數據包協議)是一種無狀態協議,以為這個協議沒有序列號。不過,這並不意味著我們不能跟蹤UDP連接。雖然沒有序列號,但是我們還可以使用其它的一些信息跟蹤UDP連接的狀態。下面是狀態表中關於UDP連接的條目: udp 17 19 src=192.168.1.2 dst=192.168.1.50 sport=1032 dport=53 [UNREPLIED] src=192.168.1.50 dst=192.168.1.2 sport=53 dport=1032 use=1 這個狀態表項只有在iptables過濾規則允許建立新的連接時,才能建立。以下的規則可以產生這類狀態表項,這兩條規則只允許向外的UDP連接: iptables -A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT iptables -A OUTPUT -P udp -m state --state NEW,ESTABLISHED -j ACCEPT 上面的狀態表項包含如下信息: 連接的協議是UDP(IP協議號17)。 這個狀態表項還有19秒中就超時。 發起連接方向上的源、目的地址和源、目的端口。 應答方向上的源、目的地址和源、目的端口。這個連接使用UNREPLIED標記,表示還沒有收到應答。 UDP連接的超時時間在/usr/src/Linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c文件中設置,如果改變了這個值,需要重新編譯Linux內核源代碼才能生效。下面是UDP連接超時時間的相關的源代碼: #define UDP_TIMEOUT (30*HZ) #define UDP_STREAM_TIMEOUT (180*HZ) 一個UDP請求等待應答的時間是30*HZ(這個值一般是30秒)。在上面的例子中,等待的時間已經消耗了11秒,還剩余19秒,如果在這段時間之內沒有收到應答分組,這個表項就會被刪除。一旦收到了應答,這個值就被重置為30,UNREPLIED標志也被刪除。這個表項編程如下形式: udp 17 28 src=192.168.1.2 dst=192.168.1.50 sport=1032 dport=53 src=192.168.1.50 dst=192.168.1.2 sport=53 dport=1032 use=1 如果在這一對源、目的地址和源、目的端口上,發生了多個請求和應答,這個表項就作為一個數據流表項,它的超時時間是180秒。這種情況下,這個表項就變成如下形式: udp 17 177 src=192.168.1.2 dst=192.168.1.50 sport=1032 dport=53 src=192.168.1.50 dst=192.168.1.2 sport=53 dport=1032 [ASSURED] use=1 這時我們看到這個表項使用ASSURED標志。一旦連接表項使用ASSURED標志,那麼即使在網絡負沉重的情況下,也不會被丟棄。如果狀態表已經飽和,當新的連接到達時,使用UNREPLIED標志的表項會受被丟棄。 2.3.TCP連接 一個TCP連接是通過三次握手的方式完成的。首先,客戶程序發出一個同步請求(發出一個SYN分組);接著,服務器端回應一個SYNACK分組;最後返回一個ACK分組,連接完成。整個過程如下所示: Client Server SYN ---> <--- SYN+ACK ACK ---> <--- ACK ACK ---> ......... ......... SYN和ACK是由TCP分組頭的標志決定的。在每個TCP分組頭還有32位的序列號和應答號用於跟蹤會話。 為了跟蹤一個TCP連接的狀態,你需要使用下面這樣的規則: iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT 2.3.1.連接建立過程中狀態表的變化 下面,我們詳細討論在連接建立的每個階段中,狀態表發生的變化: 一旦一個初始SYN分組進入OUTPUT鏈,並且輸出規則允許這個分組建立一個新的連接,狀態表的相關表項將如下所示: cp 6 119 SYN_SENT src=140.208.5.62 dst=207.46.230.218 sport=1311 dport=80 [UNREPLIED] src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1311 use=1 其中,TCP連接狀態是SYN_SENT,連接被標記為UNREPLIED。 現在,我們等待SYN+ACK分組的響應。一旦得到響應,這個TCP連接表項就變為: tcp 6 57 SYN_RECV src=140.208.5.62 dst=207.46.230.218 sport=1311 dport=80 src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1311 use=1 連接的狀態變為SYN_RECV,UNREPLIED標志被清除。 現在我們需要等待完成握手的ACK分組。ACK分組到達後,我們首先對其序列號進行一些檢查,如果正確,就把這個連接的狀態變為ESTABLISHED,並且使用ASSURED標記這個連接。這時,這個連接的狀態如下所示: cp 6 431995 ESTABLISHED src=140.208.5.62 dst=207.46.230.218 sport=1311 dport=80 src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1311 [ASSURED] use=1 2.3.2.透視狀態表 上面,我們涉及了很多CP連接的狀態。現在,我們分析一下TCP連接的狀態檢測。實際上,狀態表只知道NEW、ESTABLISHED、RELATED和INVALID。 要注意:狀態檢測的狀態不等於TCP狀態。當一個SYN分組的響應SYN+ACK分組到達,Netfilter的狀態檢測模塊就會認為連接已經建立。但是,這時還沒有完成三次握手,因此TCP連接還沒有建立。 另外,包過濾規則不能刪除狀態表中的表項,只有連接超時,對應的狀態表項才會被刪除。ACK分組能夠建立一個NEW狀態表項。向防火牆之後一台並不存在主機發送ACK分組,並不會返回RST分組,可以證明這個結論。因此,你需要使用以下的規則明確新的TCP連接應該是SYN分組建立的: iptables -A INPUT -p tcp !--syn -m state --state NEW -j DROP 這樣可以阻止空會話的繼續進行。 2.3.3.超時 所謂狀態表項的超時值是指每個表項存在的最大時間,這些超時值的大小在/usr/src/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c文件中設置。以下是相關的代碼: static unsigned long tcp_timeouts[] = { 30 MINS, /* TCP_CONNTRACK_NONE, */ 5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */ 2 MINS, /* TCP_CONNTRACK_SYN_SENT, */ 60 SECS, /* TCP_CONNTRACK_SYN_RECV, */ 2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */ 2 MINS, /* TCP_CONNTRACK_TIME_WAIT, */ 10 SECS, /* TCP_CONNTRACK_CLOSE, */ 60 SECS, /* TCP_CONNTRACK_CLOSE_WAIT, */ 30 SECS, /* TCP_CONNTRACK_LAST_ACK, */ 2 MINS, /* TCP_CONNTRACK_LISTEN, */ }; 2.3.4.連接的中斷 關閉一個TCP連接可以有兩種方式。第一種類似於建立TCP連接的三次握手。一旦一個TCP會話完成,要終止會話的一方首先發出一個FIN為1的分組。接收方TCP確認這個FIN分組,並同志自己這邊的應用程序不要在接收數據了。這個過程可以如下所示: Client Server ......... ......... FIN+ACK ---> <--- ACK <--- FIN+ACK ACK ---> 在這個過程之中或者之後,狀態表的連接狀態變為TIME_WAIT。在默認情況下,2分鐘之後從狀態表刪除。 除此之外,還有其它關閉中斷的方式。TCP會話的任何一方發出一個RST標志為1的分組,可以快速斷開一個TCP連接。而且,RST分組不需要應答。在這種情況下,狀態表項的狀態變為CLOSE,10秒之後被刪除。和http連接經常通過這種方式中斷,如果一個連接很長時間沒有請求了,服務器端就會發出一個 RST分組中斷連接。 2.4.ICMP 在iptables看來,只有四種ICMP分組,這些分組類型可以被歸為NEW、ESTABLISHED兩類: ECHO請求(ping,8)和ECHO應答(pong,0)。 時間戳請求(13)和應答(14)。 信息請求(15)和應答(16)。 地址掩碼請求(17)和應答(18)。 這些ICMP分組類型中,請求分組屬於NEW,應答分組屬於ESTABLISHED。而其它類型的ICMP分組不基於請求/應答方式,一律被歸入RELATED。 我們先看一個簡單的例子: iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED, RELATED -j ACCEPT iptables -A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT 這鏈條規則進行如下的過濾: 一個ICMP echo請求是一個NEW連接。因此,允許ICMP echo請求通過OUTPUT鏈。 當對應的應答返回,此時連接的狀態是ESTABLISED,因此允許通過INPUT鏈。而INPUT鏈沒有NEW狀態,因此不允許echo請求通過INPUT鏈。也就是說,這兩條規則允許內部主機ping外部主機,而不允許外部主機ping內部主機。 一個重定向ICMP(5)分組不是基於請求/應答方式的,因此屬於RELATED。INPUT和OUTPUT鏈都允許RELATED狀態的連接,因此重定向(5)分組可以通過INPUT和OUTPUT鏈。 3.FTP協議的狀態檢測 上面,我們比較詳細地介紹了iptables的態檢測機制。現在,我們以FTP狀態檢測為例介紹如何使用iptables進行連接狀態檢測。 首先,你需要加載ip_conntrack_ftp模塊。使用如下規則就可以允許建立FTP控制連接(這裡沒有考慮IMCP問題): iptables -A INPUT -p tcp --sport 21 -m state --state ESTABLESED -j ACCEPT iptables -A OUTPUT -p tcp --dport 21 -m state --state NEW,ESTABLISED -j ACCEPT 除了控制連接之外,FTP協議還需要一個數據通道,不過,數據連接可以通過主動和被動兩種模式建立,我們需要分別討論。 3.1.主動模式 在主動模式下,客戶程序在控制通道上,使用PORT命令告訴FTP服務器自己這邊的數據傳輸端口,然後FTP從20端口向這個端口發起一個連接。連接建立後,服務器端和客戶端就可以使用這個連接傳輸數據了,例如:傳誦的文件、ls等命令的結果等。因此,在主動模式下FTP數據傳輸通道是反向建立的,它從 FTP服務器端向客戶端發起。 在主動模式下,客戶端使用的數據傳輸端口是不固定的,因此我們需要在規則中使用端口范圍。由於客戶端使用的端口都是大於1024的,這並不會降低系統的安全性。 在iptables 中,有一個專門跟蹤FTP狀態的模塊--ip_conntrack_ftp。這個模塊能夠識別出PORT命令,並從中提取端口號。這樣,FTP數據傳輸連接就被歸入RELATED狀態,它和向外的FTP控制連接相關,因此我們不需要在INPUT鏈中使用NEW狀態。下面的規則可以實現我們的意圖: iptables -A INPUT -p tcp --sport 20 -m state --state ESTABLISED,RELATED -j ACCEPT iptables -A OUTPUT -p tcp --dport 20 -m state --state ESTABLISED -j ACCEPT 3.2.被動模式 和主動模式相反,在被動模式下,指定連接端口的PORT命令是服務器端發出的。FTP服務器通過PORT命令告訴客戶端自己使用的FTP數據傳輸端口,然後等待客戶端建立數據傳輸連接。在被動模式下,建立數據傳輸連接的方向和建立控制連接的方向是相同的。因此,被動模式具有比主動模式更好的安全性。 由於ip_conntrack_ftp模塊能夠從PORT命令提取端口,因此我們在OUTPUT鏈中也不必使用NEW狀態,下面的規則可以實現對被動模式下的FTP狀態檢測: iptables -A INPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED,RELATED -j ACCEPT 綜合以上的分析,我們可以得到FTP連接的狀態檢測規則,對於主動模式的FTP,需要下面的iptables規則: iptables -A INPUT -p tcp --sport 21 -m state --state ESTABLESED -j ACCEPT iptables -A OUTPUT -p tcp --dport 21 -m state --state NEW,ESTABLISED -j ACCEPT iptables -A INPUT -p tcp --sport 20 -m state --state ESTABLISED,RELATED -j ACCEPT iptables -A OUTPUT -p tcp --dport 20 -m state --state ESTABLISED -j ACCEPT 對於被動模式的FTP連接,需要使用如下iptables規則 iptables -A INPUT -p tcp --sport 21 -m state --state ESTABLESED -j ACCEPT iptables -A OUTPUT -p tcp --dport 21 -m state --state NEW,ESTABLISED -j ACCEPT iptables -A INPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED,RELATED -j ACCEPT 本文中提到的狀態檢測,在iptables中實際叫作連接跟蹤(Connection tracking),出於自己的習慣,我在本文中一律改為狀態檢測




Copyright © Linux教程網 All Rights Reserved