天天看點

TCP斷開時的狀态與Linux nf_conntrack

題目有點大了,但是難免有一些憤怒!

我們的網關産品目前處在系統測試階段,不太順利,是太不順利!各方面都在懈怠,包括我!我除了懈怠,還在找機會逆襲!順便蔑視一下測試者,希望産生一種想象,即他發現的問題其實不是問題,而是因為他的無知所導緻!就在昨天,機會來了,我便氣揚了!

       很多人覺得我是下三層網絡的專家,對于TCP之類的無權問津,但是我對TCP除了辱罵還是辱罵!因為它太複雜了,作為一個低層的設施,如果太複雜,應用層 的複雜空間便小了!程式設計的人,特别是socket程式設計的人,總是将IP以及網卡作為一個黑盒子,而着重看待TCP,他們對UDP是不屑一顧的,也不會關注 什麼非合作UDP流量。這是搞通訊網絡和人和程式設計的人的本質差別,畢竟分工不同。但是我也是從研究TCP開始的,起初我并無法觸及路由器之類的東西,更不 曉得什麼流量工程,可是到了後來當我懂了IP以後,我發現IP是多麼的美妙,可以讓人瞬間高潮!而TCP,就是一團亂麻,在産品系統測試的時候,一個 TCP的疑難雜症可以讓一個研發人員折騰一下午甚至好幾天,而這幾天時間,測試人員爽了,沒什麼事,可以聊天,看新聞,這是多麼悲哀,讓人沒法釋懷!真 TMD想給測試人員上椅刑!旋轉升降座椅一定會爆炸,菊花殘,滿地傷,花落人斷腸!

       隻可惜,昨天的事在我憤怒狀态時,徹底滅了這種格局!事情是這樣的。

用戶端A:128.129.1.2

網關外網口(連接配接用戶端):128.129.1.1

網關内網口(連接配接伺服器):192.168.220.223

伺服器:192.168.30.75

網關上做NAT的redirect轉換,将通路伺服器的流量重定向到本地的apache伺服器,apache伺服器行使正向代理功能(正向代理是一個重要概念,請深入了解)。規則如下:

iptables -t nat -A PREROUTING -d 192.168.30.75 -j REDIRECT --to-ports 80

多麼簡單的規則,然而多麼痛的領悟。

測試人員,嚴格說是黑盒測試人員(非白盒),測試功能就算了,不影響業務就可以了,偏偏要搞什麼抓包,關鍵是抓包還誤會我們!問題如下:

連接配接的建立以及資料的傳輸,均經過了代理,但是連接配接的拆除卻沒有被NAT,直接forward出去了,導緻192.168.30.75伺服器直接接收到了源IP位址為128.129.1.2的資料包。這是怎麼回事?!

       實際上,這是毫無影響的,隻要應用程式能夠堅持足夠長的時間!

       我發現,這是伺服器30.75主動斷開的連接配接,也就是它主動發送了FIN,此後用戶端發送了ACK,然而用戶端遲遲沒有發送自己方面的FIN,過了兩分鐘 才發送了FIN/ACK,此時連接配接隻是單方面斷開了。此時,在用戶端沒有發送FIN之前,它處在CLOSE_WAIT狀态。由于目前的産品是基于前一個産 品建構的,在前一個産品中,我由于一些特殊的原因将conntrack的和TCP相關的timeout都減到了足夠小,比如我将TCP的 conntrack的establish的timeout減少到了120秒(預設是5天),是以斷開連接配接時的各狀态timeout更小,是以在兩分鐘 内,conntrack早就删除了!

       此時用戶端的FIN來了,由于conntrack已經删除,網關會為其建立一個新的conntrack嗎?這要看有沒有設定loose,我當然設定了,也 就是不再以syn為建立新conntrack的依據,按理說,Linux網關會建立一個新的conntrack,然而它攜帶了fin标志!這就意味着 Linux不會建立新的conntrack!是以資料包就直接forward了。但是這不會造成什麼影響!因為攜帶fin的資料包擁有自己的控制通道 timeout期限。到期後會自動轉換,這是和establish狀态的截然不同!這是為什麼呢?

       這樣從TCP/IP的設計說起。有一種設計方案叫做帶内控制,也就是控制通道和資料通道共享一條網絡路徑,TCP協定就是這種設計的典型,另一種就是 IP,比如ICMP就是IP的控制協定,然而你不能說IP不是一種完全的帶内控制,它雖然和TCP有所差別,那隻是因為它的無狀态所緻!

       TCP的控制通道用标志來區分,攜帶SYN,FIN的資料段都是控制段,Linux的conntrack對TCP的行為就是以這種控制标志為依據的,如果 來了一個establish的資料包-沒有syn,沒有fin,沒有查找到conntrack,在設定loose标志的情況下,Linux為建立一個新的 conntrack項,然後對于控制信号,比如fin段,就不同了,Linux不會建立。然而這并不影響終端的結果,雖然由于Linux沒有NAT成功導 緻了資料不會正确到達伺服器,可是由于已經fin了,終端會自動用timeout處理。

       但是一定要注意方向,這可能會稍微帶來一些問題。如果主動發出的FIN被攔截,會有大問題嗎?不會的,因為主動發出FIN的一端不管它會不會被攔截,都會更改狀态,而被動關閉的那一端雖然收不到FIN,也會行使逾時重傳限制權利,雖然可能慢一點。

       持續饑餓!保持饑餓!

 本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1670776

繼續閱讀