歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux之ip_conntrack容易混淆的問題點滴

Linux之ip_conntrack容易混淆的問題點滴

日期:2017/2/28 15:55:18   编辑:Linux教程

再次深入到ip_conntrack的conntrack full問題》最後的一個問題提示

ip_conntrack有一個event機制,可以主動通報ip_conntrack的一些事件,包括追蹤信息到期刪除等事件,通知給誰呢?當然是通知給所有感興趣的模塊了,其中之一就是用戶態進程,這樣用戶態進程得知可以采取一些措施,比如防火牆上設置一些放過規則等,這個通知機制使用了觀察者設計模式。

Linux ip_conntrack的一些細節問題

由於Linux的ip_conntrack具有大量的狀態,而每一種狀態都有一定的超時時間,這些狀態中的個別可以和網絡協議的不同狀態建立映射關系,另一些則不能。如果協議本身是有狀態的,那麼就很方便建立一種映射關系,反之如果協議沒有狀態,那麼就不能建立映射關系。有時候,對於無狀態的協議而言,ip_conntrack的狀態超時時間會帶來一些令人郁悶的問題。

總之,Linux的ip_conntrack機制如果深究起來還真的看點,如果搞防火牆開發,實屬不可不察也。下面就舉幾個例子。

例子舉例

例子1:

對於UDP而言,它本身沒有狀態,無需建立連接,無需確認,純粹就是一個數據報協議,因此ip_conntrack使用經驗值來設定各個狀態的超時時間,但是如果雙方有一段時間沒有發包,那麼當初始接收端再發起一個數據包時,就會給防火牆上的基於ctstate的過濾規則帶來影響,具體參見《再次深入到ip_conntrack的conntrack full問題》。

例子2:

對於UDP而言,如果在Linux防火牆上使用NAT,那麼在數據通信期間,即使NAT規則被刪除或者被修改,該數據流依然會使用老的NAT規則而不是不使用任何規則或者使用新的規則。

例子3:

在早期的內核上,加載ip_conntrack模塊,然後ping一個可以ping通的地址,則在/proc/net/ip_conntrack中卻看不到該連接的追蹤信息,而ping一個根本不可達的地址,反而能看到一個反方向為UNREPLY的追蹤信息。值得注意的是,起碼在2.6.32內核上,這個問題不再存在,而在2.6.9內核上還是存在的,具體哪個版本修正了它,沒有詳細看內核的ChangeLog。

例子4:

對於TCP而言,只要一個連接斷開了,/proc/net/ip_conntrack中的關於該連接的追蹤信息將馬上被刪除,而不會像UDP那樣保留。

針對以上問題的一些解釋

例子1的解釋:

這個沒有什麼好說的,根本原因就是UDP本身沒有狀態,而ip_conntrack將establish狀態強加給了一個UDP連接,所謂的ip_conntrack的establish狀態對於所有的協議都是說有去有回的流,當然對於UDP更是這樣。對於TCP而言,ip_conntrack將不是syn狀態的流量都映射成了establisd狀態(注意不是TCP的established狀態),這也符合上述定義。在ip_conntrack處理的入口的最後:
  1. if (set_reply)
  2. set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
這說明只要set_reply為真就會修改ct的一個狀態位,而set_reply在ip_conntrack_in的resolve_normal_ct調用中就會被設置。
  1. //只要收到反向的包,就會設置IP_CT_ESTABLISHED,且把set_reply設置為1,然後返回到ip_conntrack_in的時候,就會導致ct->status的IPS_SEEN_REPLY_BIT的設置
  2. if (DIRECTION(h) == IP_CT_DIR_REPLY) {
  3. *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
  4. /* Please set reply bit if this packet OK */
  5. *set_reply = 1;
  6. } else {
  7. /* Once we've had two way comms, always ESTABLISHED. */
  8. //只要有IPS_SEEN_REPLY_BIT位被置位,那麼就是IP_CT_ESTABLISHED
  9. if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
  10. DEBUGP("ip_conntrack_in: normal packet for %p\n", h->ctrack);
  11. *ctinfo = IP_CT_ESTABLISHED;
  12. ...
因此可見IP_CT_ESTABLISHED狀態和具體的協議是無關的,對於TCP而言,所有SYN後面的包都會是IP_CT_ESTABLISHED狀態。然而由於TCP本身擁有可以監控連接的狀態,比如close-wait等,因此它在ip_conntrack中又有一些子狀態,這個用於在適當的時候釋放ip_conntrack數據結構,因此只要TCP的ip_conntrack的time-wait子狀態到期,其ip_conntrack數據結構就會被當即釋放,這一切正是因為TCP將其協議狀態映射成了ip_conntrack的子狀態,而這些子狀態知道什麼時候一個tcp流結束了。然而這一切對於UDP以及ICMP而言就沒有這麼幸運了,它們沒有所謂的子狀態,它們只能使用大膽的ip_conntrack狀態。
Copyright © Linux教程網 All Rights Reserved