《鍋來了!!!不要慌~~~》——那些你應該知道的知識(一)

卿本神工,奈何背鍋,明辨真相,且看本章—

《鍋來了!!!不要慌~~~

#####################################################################################################

寫在前面:本文部分內容來自CSDN其他博客,在此聲明並表示感謝。

#####################################################################################################

事件背景

近期有一個業務,因IPS的加入而受影響,將IPS置爲Bypass狀態後,業務恢復。判斷IPS對相關報文進行了阻攔。在此基礎上,通過在F5上抓包,獲得業務可用情況下,數據包信息。以該數據包爲例,總結一下抓包中的各項數據信息。

首先,我們通過wireshark打開數據包,wireshark默認顯示Time Source Destination Length Info這幾項信息,由於判斷數據包是否被正常的發送和接受,我們一般通過Sequence Number和Ack來判斷,於是在此基礎上,增加Sequence number、ack number和TCP Segment Len。增加方法爲選中相應的字段-》右擊-》增加爲列。

#####################################################################################################

分析過程經驗總結:

首先,我們要通過抓包判斷故障的原因,首先應能夠準確定位業務發生故障的部分和我們抓取的數據包哪一部分對應。

windows可以通過netstat -ano 找到PID,在通過tasklist|findstr 3280 命令找到對應的服務。通過服務找對應的端口號也是同理.

linux可通過natstat -nap|mor,查看(未證實)

通過以上方法判斷相應進程和所使用的的源目端口後,在數據包中找到對應的TCP源目回話,通過追蹤TCP流,只看與該回話相關的數據包,排除其他干擾。

如果無法準確定位,只能通過wireshark的分析,看數據包異常部分,再追蹤TCP流。

#####################################################################################################

分析過程知識總結:

本部分解釋TCP數據包的發送和接受過程,如何判斷數據包之間的關聯關係。

通過wireshar打開數據包,追蹤TCP流後,可以發現,這是一個TCP連接,進一步分析,這是一個SSL相關應用。客戶端通過高位端口46929與對方端口443建立連接,應該是訪問對方的https網站或接口。其中SSL連接建立的過程較爲複雜,在此不做展開分析。如果以後碰到SSL建立連接異常的話,可通過次案例進行對比分析。

在此聲明,wireshark中顯示的sequence number和ack number並非真實的相關序列號,而是相對的序列號。相對序列號從0開始,這便於進行數據包的分析。

從圖中可以看出,源地址10.200.x.x與目的地址101.89.x.x建立TCP連接。

##########################################################################

TCP的三次握手

首先是TCP的三次握手,原理如下圖:

在本次案例中,wireshark顯示爲相對序列號,x=0,y=0。所以我們看到的是SYN包,seq=0,ack=0。SYN ACK包,seq=0,ack=1.ACK包,seq=1,ack=1。

之後開始應用層數據的傳遞,見下圖。

############################################################################

MTU與MSS

其中,TCP Segment of a ressembled PDU表明這是一個被切片的數據包。在TCP握手協商過程張,會協商MSS(Maximum Segment Size)。見下圖:

可見,本次協商出的MSS值爲1440字節。這個數據是怎麼計算出來的呢?

最大傳輸單元(Maximum Transmission Unit,MTU)是指一種通信協議承載上層數據報文的最大數據報大小(以字節爲單位)。最大傳輸單元這個參數通常與通信物理接口有關(以太接口、串口、ATM、E1/T1等)。通常來說是指在IP層上能通過的最大報文長度。

在IP協議中,一條傳輸路徑的“路徑的MTU”被定義爲從源地址到目的地址所經過“路徑”上的所有IP接口的MTU的最小值。RFC 1191描述了“路徑最大傳輸單元發現方法”。在這項技術中,源地址將數據報文的DF“Don't Fragment”標記位置位,路徑上任何需要將報文進行分片的設備接口都會將這種數據報丟棄並返回一個“數據報過大”的ICMP響應到源地址,並在這個響應中告知了該接口的MTU值。這樣,源主機就“學習”到了不用進行分片就能通過這條路徑的最大傳輸單元了。

在以太網上,以太網接口缺省的MTU爲1500(最大傳輸單元,這是考慮到早起10M帶寬網絡中的傳輸效率計算出來的),注意這是一個缺省值。所以以太網最大幀長應該是以7字節前導同步碼+1字節幀開始定界符+6字節目的mac+6字節源mac+2字節幀類型+1500+4字節FCS=1526bytes。 (FCS:Frame Check Sequence(幀校驗序列),俗稱幀尾,即計算機網絡數據鏈路層的協議數據單元(幀)的尾部字段,是一段4個字節的循環冗餘校驗碼,CRC。)

在電腦上,通過抓包軟件進行抓包,抓到的是去掉前導同步碼、幀開始分界符、FCS之外的數據,默認情況下是1526-7-1-4=1514字節也就是6字節目的mac+6字節源mac+2字節幀類型+1500=1514bytes。

而MSS=MTU-TCP頭部大小-IP頭部大小=1500-20-20=1460bytes。

可以用ping -l 1472 -f IP地址 來探測,路徑中協商的最小mtu。這裏設置了ping不允許分片,若1472可以ping通,1473不能ping通,則MTU=1472+28=1500bytes,其中28爲icmp包的ip頭長度。一般的ip頭長度爲20.

在我們這個例子中MSS值爲1440字節,可見在路徑中,最小的MTU=1480bytes。

這個值可以在wireshark中看到,找到一個分片的數據包,見下圖:

其中IP層的Totol Length爲1480,等於我們上文分析的MTU的值。

#################################################################

Sequence Number與Acknowledge Number

關於Sequence Number:簡單來講,用來記錄一端作爲發送者一共發送了多少字節的數據包,告訴結接受者我之前已經發送過多大字節的內容了。針對發送者,在之前未發送攜帶有有效數據的數據包,或第一個發送攜帶有有效數據的數據包時,seq將維持不變。只有從第二個發送攜帶有有效數據的數據包開始,seq=原seq+上一次發送的數據包的tcp Segment length。

所以Sequence Number只有在自己發送攜帶有有效數據的數據包是,纔會增加。

關於Acknowledge Number:簡單來講,用來記錄一端作爲接受者告訴發送者我一共收到了多少字節的數據包,進行確認。作爲有效數據包的接受者,用來返回,告訴發送者我一共收到了多少數據。所以ack=原ack+發送者發送的數據包的tcp Segment length。所以,我們要確定接受者返回的ack數據包哪個是用來響應發送者的數據包,需要通過期返回的ack的值來判斷。

通過上面的總結,我們可以發現Sequence Number記錄着發送者之前發過了多少數據,Acknowledge Number記錄着接受者接到了多少數據。

很多人通過確認包的Seq No=發送包的Ack No來尋找其中的對應關係,這同樣可以解釋的通。因爲此次發送數據包一端的ack記錄着他之前接受到了對端發來的多少數據,這也就等於對端一共發了多少數據,而這個數據等於下一次對端返回的確認包中的Seq No.

而ACK確認包中的Ack No.可以推算出=發送者之前發送的數據包的量+這次發送的數據包大小。也就是說ACK=發送者發送的數據包的seq+發送者發送數據包的TCP segment Length.

下面針對圖中的具體案例進行分析。

爲便於解釋,在這裏將A=10.200.x.x B=101.89.x.x。

  • 146—這是這個TCP流中A發送的第一個攜帶有效數據的包,發送的有效的數據長度爲144,之前的包都沒有攜帶數據,所以seq=1+0=1,之前也沒有接收到有效數據,所以ack=1+0=1。

  • 147—B收到該數據包,發送ack包告知我方確認收到上一個包,這是一個單純的ack包,之前B也沒有發送過有效數據。所以seq=1+0=1,ack=原ack+收到的數據包的TCP Segment Length=1+144=145(相當於告知對方受到數據的量)。

  • 148—緊接着,B主動發起Server Hello數據包,這是他第一次發送帶有有效數據的數據包,所以seq=1+0=1,沒有收到新的數據,ack=145+0=145。

  • 149、150—B繼續發送帶有有效數據的數據包,同時可以注意到,這是一個TCP分片的數據包,每個數據包攜帶的有效數據長度爲1440字節。所以149包中的seq=1+148包的有效數據長度=1+1440=1441,150包的seq=1441+149包的有效數據長度=2881.這個過程中沒有收到A發來的其他數據,所以ack沒有變化,維持在145.

  • 151—B繼續發送帶有有效數據的數據包,所以151包的seq=2881+1440=4321,沒有收到新的數據,ack維持不變,ack=145.

  • 152—A向B確認他收到的數據包,152包的seq=146包的seq+146包的有效數據長度=1+144=145。ack=2881,根據分析,ack=2881=1+1440+1440.所以可以判斷,這個ACK確認包是迴應確認收到第148和149包的。

  • 153—這個過程中A,沒有發送其他有效數據(tcp segment length=0),所以seq沒有增長,153包的ack=4321=2881+1440,所以這個包使用來確認收到150包的。

  • 154—與之前的分析同理,ack=5243=4321+922,所以這個ACK確認包是用來回應收到151包。至此由B發送的148、149、150、151都被A確認收到。

繼續分析,進行鞏固,見下圖:

  • 155、156、157—這些包都是A發送帶有有效數據的數據包給B,seq依次增加,155包seq=145=145+0.156包seq=227=145+82.157包seq=227+6=233這個過程中沒有收到B發送的數據包,這個過程ack維持不變。

  • 158、159—這是用來回應確認收到A發送的數據包,可以推理158包用來確認收到155和156包,158包的ack=233=145+82+6。159包的ack=286=233+53.同時注意159包同樣攜帶有效數據,長度爲59個字節。要確認這是不是同時是一個ACK確認包,可以通過TCP層的FLAGS判斷。如下圖

其中ACK:確認標誌。確認編號(Acknowledgement Number)欄有效。大多數情況下該標誌位是置位的。TCP報頭內的確認編號欄內包含的確認編號(w+1,Figure-1)爲下一個預期的序列編號,同時提示遠端系統已經成功接收所有數據。

至此我們應該掌握了關於Sequence Number和Acknowledge Number的計算方法,和數據包的關聯關係。

其實也可以通過wireshark裏面的分析,直接看到ACK包是對哪個包的確認。如下圖:

#####################################################################################################

TCP的四次揮手

TCP四次揮手原理見上圖,一般情況下,服務器返回的ACK包和發送的FIN ACK 包可能是同一個包。

關於三次握手和四次揮手的原理,可見CSDN博客,小書go的整理,此文部分圖片也是其博客中的內容,在此表示感謝。

https://blog.csdn.net/qzcsu/article/details/72861891

#####################################################################################################

針對本次案例的部分解讀

本次業務的實際場景是,服務端會發送一個長報文給客戶端,那麼這個報文有多長呢,下文是相關推斷,沒有經過仔細驗證:

從上圖中可以看出來,第163包,確認了收到第162包後,B端開始持續發送數據,這裏TCP對數據進行了分片,每個分段的TCP Segment Length=1440.

可以通過wireshark看到分片在哪裏結束,如下圖:

跳轉到第179幀,如下圖:

可以看出來,上一次TCP分片,一共分片12段,報文長度爲16421.然而第179幀,同樣也是一個分片的報文,在第190結束,根據上圖的方法,在excel表格中進行統計。

然而這次抓包一共有8519個幀,採用以上的統計方法不現實。

簡單來講,可以看最後一個ack包的ack的值,這代表着他一共接受到的數據的總量。這次抓包中該數值見下圖:

8509幀中,ack number=10107598字節,換算成我們常見的單位也就是10107598bytes=9870.70117KB=9.6393566MB。大約爲10M不到,這與開發人員的描述相符。

同時可以看到,本次TCP交互,從第一個幀到該幀共耗時2.55秒。這與開發人員描述的大概2秒可以將文件下載下來相符。

###################################################################################################

理想總是美好的,在準備了這麼多知識後,下面開始正文

《鍋來了!!!不要慌~~~

本次抓包中存在着部分異常報文,具體見下圖,進行簡單分析:

TCP Previous segment not captured.

第一個異常報文出現在第1691幀,見下圖:

這裏,wireshark解讀,提示爲TCP Previous segment not captured——這是因爲wireshark根據Sequence Number發現,沒有抓到期待的數據報文。

看第1690幀,seq=1931744,tcp segment length=1440,則1691真的seq應該=1931744+1440=1933144.然而1691幀的seq=1940384.

並且我們可以推斷,本次tcp交互協商的mss=1440,則這中間丟了(1940384-1931744)/1440=6,也就是有5個包沒有被抓到,他們分別是:

seq=1933184、1934624、1936064、1937504、1938944的這幾個包。記住這串數字,他們之後還會出現。

這意味着在一個被分片的長報文中,有的數據包沒有被接收到,由於此次是在F5上抓包,相當於處在報文轉發的中間路徑上。那麼這幾個包沒有被抓到,可能是網絡在中間丟了,也可能是wireshark本身沒抓到,也可能是服務器還沒有發,可能是中間網絡延時比較大等等,可能性很多,這個時候網絡基本把鍋背起來了。

下面的1694幀也是相同情況,經過計算,中間也是差了7個包。我們繼續往下看:

這時B端,服務器端還在繼續發送數據,A端有時會迴應ACK,表示收到了哪些數據。

從圖中可以看出,1695幀迴應的是1688幀。1698幀迴應的是1690幀,也就是出現分片沒有被抓取到的前一個幀。而之後由於TCP分片發送的混亂,客戶端不再更新確認收到的數據,也就意味着ACK No.不再增長,於是便出現了Dup ACK。

這裏我們注意到這裏有TCP option出現,在這個例子中是SACK。

SACK

SACK是用來回復告訴發送者有哪些包沒有被確認接受,在下圖中:

A告訴B,我已經從你那邊收到1933184的數據,這個值等於1933184=1931744+1440,是來請確認1690幀的。

然而根據我們前文的分析,我們此次抓包並沒有抓到seq=1933184的數據包,而此時客戶端確告訴服務器我已經從你那邊接收到了1933184的數據幀,由此,wireshark判斷,這一次數據傳遞中出現了亂序,也就是TCP-out-of-order.

除此之外A告訴B,有seq=1940384到1944704,3個包還沒有被確認。我們結合上文的分析來看

這是由於1933184 到1938944這5個包沒有被客戶端收到,所以之後的1940384開始的數據包也不被服務器確認收到。到這裏我們感覺開始找到了數據包出現亂序的源頭。

我們繼續往下開,這時服務器B繼續向A發送數據,如下圖:

1703幀,表示又有一些數據包沒有被wireshark抓到,這無疑將進一步加重此次傳輸的混亂的情況。

TCP Dup ACK

緊接着,來到1704幀,wireshark判斷該幀爲與1698幀重複的ACK包,然而我們點開進一步分析,發現這仍是一個帶有SACK TCP option的數據包。在這個數據包裏標記了除了上一個1698幀,表示的還沒被確認的包以外,還增加了一段,表示1953344幀到1957663幀,也還沒有被確認。由此可見,1704幀與1698幀不是完全相同的,他更新了一些尚未被確認收到的包的信息。從wireshark tcp info中,也表示了這些相關的信息,如下圖:

SLE表示SACK中的Seuqence Left Edge。SRE表示Sequence Right Edge。

由此可見,後面大量的wireshark判斷爲重複ACK的報文,其實都在不停地返回告訴服務器B,有哪些數據還沒有被確認接受。這之中由於SACK最多隻能標記4個沒有被確認接受的片段組,伴隨着越來越多的數據沒有被確認接受,SACK中能表示仍未被確認的片段也在不斷刷新。而這一切的原因都是因爲幀1691前有5個數據包,沒有被本次抓包抓到。除此以外,每個顯示TCP Previous segment not captured的數據包都會進一步加重這個情況。

目前我們繼續針對1691前沒有被抓到的5個數據包,而引起的的混亂進行分析。我們繼續往下看

可以看到,這個情況一直在持續,A不停地發送帶有SACK的 報文,更新哪些還沒被確認。我們繼續向下看,直到一個數據幀引起了我們的注意。

TCP Fast Retransmission

當服務端收到3個或以上重複的ack包時,發送方會假設這個數據包在傳輸過程中丟失了,就會發送tcp fast retransmission, 其他所有正在傳輸的數據包都要靠邊,直到把快速重傳數據包發送出去爲止。在我們這個例子中,dup ack已經發了100個...如果收到三個就能成功觸發重傳的話,可能會對之後的影響小很多。而針對服務端沒有收到3個或以上的TCP Dup Ack包的話,只能等待ACK確認報文的超時時間,再發送TCP Transmission數據包。

幀1928,wireshark判斷服務器B可能是補發了一個seq爲1933184的數據包,這與幀1691中,顯示的有幾個被分片的包沒有被抓到高度吻合。之前的分析見下圖:

“”

TCP Out-Of-Order

於是我們可以發現,從1928幀開始,到之後出現的TCP Out-Of-Order的幾個報文,是服務器在對之前wireshark在1691幀之前沒有抓到的數據包進行重發。

可見,上圖中幾個數字與前文分析的,沒有被抓到的幾個數據包的seq號完全吻合。

在幀1928發出後,被客戶端在1937幀,確認接收到。見下圖:

這個報文確認了seq=1933184的報文被接收到,同樣,這才被wireshark認爲是正確的,與1698相同的ACK確認包。於是之後便沒有了報TCP Dup ACK 1698的報文。隨後的幾個ACK包依次確認了前面沒有被抓到的數據包的報文,分別是1937對應1928、1939對應1931、1942對應1933、1948對應1935和1938。至此引發大混亂開始的5個包,都被確認接受到。

但是由於之後又發生了數據包沒有被抓取到和接收端積累了大量的數據仍未發送確認接受,導致ACK包中的SACK始終有值。

再來看一個例子:

在1750幀,顯示又有TCP分片沒有被抓取到。這包括了(2008064-2005184)/1440=2-1=1,這意味着有1個分片沒有被抓到,也就是seq=2005184+1440=206624的數據包。這同樣會引起與上文相同的問題,會導致TCP Dup ACK和TCP out of order的出現。具體見下圖:

幀1963確認了分片沒有被抓取到的前一個幀1748幀,而之後由於TCP分片發送的混亂,客戶端不再更新確認收到的數據,也就意味着ACK No.不再增長,於是便出現了Dup ACK。

幀1972的Ack No=2009504=2006624+1440+1440。這意味着幀1972確認了幀1961和幀1750.之後便沒有了TCP Dup ACK 1963.

總結一下

抓包中,一旦出現有的TCP/IP分片沒有被抓到,也就是TCP Previous Segment not captured的出現。這便意味着接收端存在着沒有收到的TCP/IP分片,沒有辦法對TCP數據包進行重組,提交上端應用層的情況。在這種情況下,發送端仍然會繼續發送,接收端仍然會繼續接受數據包。當接收端確認了發生分片丟失前的前一個幀以後,由於沒有收到完整序列號的tcp分片,則接收端無法確認之後收到的tcp分片,則ACK確認報文中的Ack

 No值不會增長, 但是會通過發送帶有SACK這個tcp option的ACK確認包的方式告訴發送端,我收到的包中有哪些包沒有被確認接受。這個SACK在變化,Ack No.沒有變化的值,會被wireshark認爲是TCP Dup Ack。而由於SACK只能記錄4組沒有被確認接受的數據包,所以SACK中的SLE和SRE是不斷滾動遞增的。

只有當服務器作爲發送端將客戶端沒有接受到的TCP分片重發,或者也有可能是第一次發送時,這時wireshark會抓到TCP Retransmisson的包,或者是TCP out-of-order的包。只有當接收端回覆ACK確認包,確認收到之前沒有抓取到的TCP分片時,其返回的ACK的Ack No.數字纔會增加。wireshark纔會認爲這個Ack不是Tcp Dup Ack

由於在本例子中,這個TCP報文傳輸的數據量大約有10MB,這中間多次出現了TCP Previous Segment not captured。所以導致抓包中有很多的TCP Dup Ack,TCP out-of-order。究其原因,都是因爲有的TCP分片在客戶端這一側沒有被按照順序的接收到。至於根本原因後文將會作出猜測。

我們繼續向下翻看,直到2096幀,客戶端B返回的ACK不再是SACK,代表不再有沒被確認的報文。

此時ACK的Ack number=2255744=2083幀中的seq+ack=2254304+1440.

這代表着之前服務器端B發送的數據包都被A收到。

在這之後,wireshark分析的數據包恢復正常。沒有再發生TCP亂序、TCP分片順序混亂等現象。

原因猜測

根據前文的分析,我們知道導致本次TCP數據傳輸過程混亂的原因是,一個長報文被分片,而一些TCP分片沒有被服務端按順序的發送給接收端,導致出現了很多TCP亂序和Dup Ack等。這對數據包實際的傳輸速率會造成很大的影響。同時,由於Dup Ack的大量存在,使得IPS誤以爲這是ACK Flood攻擊,將相關報文進行了阻斷,進而影響了業務。

關於TCP分片沒有被按順序的送到接收端的原因,也就是TCP Previous Segment not captured出現的原因,這個可能性有很多,現在未證實的情況下作出以下推測。

發送端服務器層面鏈路層——也就是發送端網卡層面,隊列滿,導致部分TCP分片的丟失,進而導致部分分片沒有被按順序發送,需要之後的重傳。

鏈路層之間,由於本次抓包是在接收方F5上抓包,而且是與公網的服務器進行交互,中間經過的對端數據中心設備、代理軟件、運營商設備等等,都可能導致TCP分片的丟失,或發送的亂序。

在接收端TCP層,本次抓包沒有發現win=0的現象出現,判斷接收端讀取文件的效率不是瓶頸。

綜上所述,判斷故障主要還是集中在鏈路層,和鏈路層中間串接的各類設備上。

至此,本章完。

鍋沒甩掉?敬請期待下一章

《鍋甩了!!!妥妥的~~~》

 

 

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