TCP狀態(tài)機

在網(wǎng)絡(luò)協(xié)議棧中, 目前只有tcp提供了一種面向連接的可靠性數(shù)據(jù)傳輸?!《煽啃?,無非就是保證,我發(fā)給你的,你一定要收到。確保中間的通信過程中,不會丟失數(shù)據(jù)和亂序?!≡冢裕茫斜WC可靠性數(shù)據(jù)傳輸?shù)膶崿F(xiàn)來看, 超時重傳、序列號及數(shù)據(jù)的應(yīng)答 這三個特征 就是實現(xiàn)可靠性的最基本保證,而對于tcp窗口大小等等設(shè)置,也是保證可靠性的一個方面。所有的目的只為一個,保證傳輸數(shù)據(jù)的完整性。 為了解決傳輸線路的不穩(wěn)定性造成數(shù)據(jù)包的丟失情況,tcp 使用了發(fā)送方超時重傳和接收方數(shù)據(jù)應(yīng)答的策略。概括而言,就是一種“狀態(tài)協(xié)議“,保證通信雙方數(shù)據(jù)收發(fā)的一致性。

tcp協(xié)議

報文結(jié)構(gòu)

源端口:表明發(fā)送端所使用的端口號,用于目標(biāo)主機回應(yīng)。
目的端口:表明要連接的目標(biāo)主機的端口號。
序號:
表明發(fā)送的數(shù)據(jù)包的順序,一般為上次發(fā)送包中的順序號+1。
若該數(shù)據(jù)包是整個TCP連接中的第一個包(SYN包),則該值是隨機生成的。
確認(rèn)號:
表明本端TCP已經(jīng)接收到的數(shù)據(jù),其值表示期待對端發(fā)送的下一個字節(jié)的序號。
實際上告訴對方,在這個序號減1以前的字節(jié)已正確接收。
若該數(shù)據(jù)包是整個TCP連接中的第一個包(SYN包),則確認(rèn)號一般為0。
數(shù)據(jù)偏移:
表示以32位(4字節(jié))為單位的TCP分組頭的總長度(首部長度),用于確定用戶數(shù)據(jù)區(qū)的起始位置。
在沒有可變內(nèi)容的情況下,TCP頭部的大小為20字節(jié),對應(yīng)該值為5。
標(biāo)志位:
緊急標(biāo)志位(URG):開啟時表明此數(shù)據(jù)包處于緊急狀態(tài)應(yīng)該優(yōu)先處理
確認(rèn)標(biāo)志位(ACK):開啟時表明確認(rèn)號有效,否則忽略確認(rèn)號
推送標(biāo)志位(PSH):開啟時表明應(yīng)該盡快交付給應(yīng)用進程,而不必等到緩存區(qū)填滿才推送,比如 telnet 的場景
復(fù)位標(biāo)志位(RST):開啟時表明TCP連接出現(xiàn)連接出現(xiàn)錯誤,數(shù)據(jù)包非法拒絕連接
同步標(biāo)志位(SYN):開啟時表明連接建立的標(biāo)志
終止標(biāo)志位(FIN):開啟時表明釋放一個連接
窗口大?。罕砻髌谕邮艿降臄?shù)據(jù)包字節(jié)數(shù),用于擁塞控制。
校驗和:實現(xiàn)對TCP報文頭以及數(shù)據(jù)區(qū)進行校驗。
緊急指針:在緊急狀態(tài)下(URG打開),指出窗口中緊急數(shù)據(jù)的位置(末端)。
選項(可變):用于支持一些特殊的變量,比如最大分組長度(MSS)。
填充:用于保證可變選項為32 bit的整數(shù)倍。
備注:一般情況下TCP 頭部為20字節(jié),加上20字節(jié)的 IP頭部,一個數(shù)據(jù)包至少包含40字節(jié)的頭部

tcp狀態(tài)機

image.png

下面簡析一下 TCP的各個狀態(tài)。

TCP_CLOSE:關(guān)閉狀態(tài), 一個新建的TCP socket 會處于該狀態(tài)。

TCP_LISTEN: 監(jiān)聽狀態(tài),一般服務(wù)器端套接字在調(diào)用Listen系統(tǒng)調(diào)用后即處于該狀態(tài)。

TCP_SYN_SENT:同步信號已經(jīng)發(fā)送狀態(tài),這個狀態(tài)一般是指客戶端發(fā)送SYN(建立連接的同步)數(shù)據(jù)包后所處的狀態(tài)(tcp三次握手的第一個包)。在接收到遠端服務(wù)器端的應(yīng)答后,即從該狀態(tài)進入TCP_ESTABLISHED狀態(tài)。

TCP_SYN_RECEIVED:同步信號已經(jīng)接受狀態(tài),服務(wù)器端在接受到遠端客戶端SYN數(shù)據(jù)包后,進行相應(yīng)的處理(創(chuàng)建通信套接字等),然后發(fā)送應(yīng)答數(shù)據(jù)包(tcp三次握手的第二個包),并將新創(chuàng)建的通信套接字狀態(tài)設(shè)置為TCP_SYN_RECEIVED,在接受到客戶端的應(yīng)答后,即進入TCP_ESTABLISED狀態(tài)。

TCP_ESTABLISED:建立連接狀態(tài),這是雙方進行正常通信所處的狀態(tài)。

TCP_FIN_WAIT_1:本地發(fā)送FIN(用于結(jié)束連接的)數(shù)據(jù)包后即可進入該狀態(tài),等待對方的應(yīng)答。一般一端發(fā)送完其所要發(fā)送的數(shù)據(jù)后,即可發(fā)送FIN數(shù)據(jù)包,此時發(fā)送通道被關(guān)閉,但仍可繼續(xù)接受遠端發(fā)送的數(shù)據(jù)包。在接受到遠端發(fā)送的對于FIN數(shù)據(jù)包的應(yīng)答后,將進入TCP_FIN_WAIT_2狀態(tài)。

TCP_FIN_WAIT_2:進入該狀態(tài)表示本地已經(jīng)接受到遠端發(fā)送的對于本地之前發(fā)送的FIN數(shù)據(jù)包的應(yīng)答。進入該狀態(tài)后,本地仍然可以繼續(xù)接受遠端發(fā)送給本地的數(shù)據(jù)包。在接受到遠端發(fā)送的FIN數(shù)據(jù)包后(表示遠端也已經(jīng)發(fā)送完數(shù)據(jù)),本地將發(fā)送一個應(yīng)答數(shù)據(jù)包,并進入TCP_TIME_WAIT狀態(tài)。TCP_TIME_WAIT狀態(tài)存在的時間被稱為2MSL時間,這一方面是為避免本地發(fā)送的應(yīng)答數(shù)據(jù)包丟失,另一方面避免一個新創(chuàng)建的套接字接收到舊套接字中遺留的數(shù)據(jù)包。

TCP_TIME_WAIT:該轉(zhuǎn)狀態(tài)唄稱為2MSL等待狀態(tài)。如果在此期間接收到遠端發(fā)送的FIN數(shù)據(jù)包,則表示之前在TCP_FIN_WAIT_2狀態(tài)發(fā)送的ACK應(yīng)答數(shù)據(jù)包在傳輸中丟失或者長時間被延遲,從而造成了遠端重新發(fā)送了FIN數(shù)據(jù)包,此時重復(fù)ACK應(yīng)答數(shù)據(jù)包。一旦2MSL時間到期,則將進入TCP_CLOSED狀態(tài),即完成關(guān)閉操作。

TCP_CLOSE_WAIT:該狀態(tài)存在于后關(guān)閉的一端。當(dāng)接收到遠端發(fā)送的FIN數(shù)據(jù)包后,本地發(fā)送一個ACK應(yīng)答數(shù)據(jù)包,并將該套接字狀態(tài)從TCP_ESTABLISED設(shè)置為TCP_CLOSE_WAIT。本地可以繼續(xù)向遠端發(fā)送數(shù)據(jù)包,在發(fā)送完所有的數(shù)據(jù)后,本地將發(fā)送一個FIN數(shù)據(jù)包關(guān)閉本地發(fā)送通道,并將狀態(tài)設(shè)置為TCP_LAST_ACK狀態(tài),等待遠端對FIN數(shù)據(jù)包的應(yīng)答數(shù)據(jù)包。

TCP_CLOSING:如果通信雙方同時發(fā)送FIN數(shù)據(jù)包,則同時進行關(guān)閉操作,則雙方將同時進入TCP_CLOSING狀態(tài)。具體的,本地發(fā)送一個FIN數(shù)據(jù)包以結(jié)束本地數(shù)據(jù)包發(fā)送,如果在等待應(yīng)答期間,接收到遠端發(fā)送的FIN數(shù)據(jù)包,則本地將狀態(tài)設(shè)置為TCP_CLOSING狀態(tài)。在接收到應(yīng)答后,再繼續(xù)裝入到TCP_CLOSE_WAIT狀態(tài)。

TCP_LAST_ACK:作為后關(guān)閉的一方,在發(fā)送FIN數(shù)據(jù)包后,即進入TCP_LAST_ACK狀態(tài)。此時等待遠端發(fā)送應(yīng)答數(shù)據(jù)包,在接收到應(yīng)答數(shù)據(jù)包后,即完成關(guān)閉操作,進入TCP_CLOSE狀態(tài)。

關(guān)于tcp中time_wait狀態(tài)的4個問題

1.time_wait狀態(tài)是什么

簡單來說:time_wait狀態(tài)是四次揮手中server向client發(fā)送FIN終止連接后進入的狀態(tài)。下圖為tcp四次揮手過程



能夠看到time_wait狀態(tài)存在于client收到serverFin并返回ack包時的狀態(tài)
當(dāng)處于time_wait狀態(tài)時,我們無法創(chuàng)建新的連接,由于port被占用。

2.為什么會有time_wait狀態(tài)

time_wait存在的原因有兩點
1.可靠的終止TCP連接。
可靠的終止TCP連接,若處于time_wait的client發(fā)送給server確認(rèn)報文段丟失的話,server將在此又一次發(fā)送FIN報文段,那么client必須處于一個可接收的狀態(tài)就是time_wait而不是close狀態(tài)。
2.保證讓遲來的TCP報文段有足夠的時間被識別并丟棄。
保證遲來的TCP報文段有足夠的時間被識別并丟棄,linux 中一個TCPport不能打開兩次或兩次以上。當(dāng)client處于time_wait狀態(tài)時我們將無法使用此port建立新連接,假設(shè)不存在time_wait狀態(tài),新連接可能會收到舊連接的數(shù)據(jù)。

time_wait持續(xù)的時間是2MSL,保證舊的數(shù)據(jù)能夠丟棄。由于網(wǎng)絡(luò)中的數(shù)據(jù)最大存在MSL(maxinum segment lifetime)

3.哪一方會有time_wait狀態(tài)

time_wait狀態(tài)是一般有client的狀態(tài)。 并且會占用port,有時產(chǎn)生在server端,由于server主動斷開連接或者發(fā)生異常

4.怎樣避免time_wait狀態(tài)占用資源

假設(shè)是client,我們一般不用操心,由于client一般選用暫時port。再次創(chuàng)建連接會新分配一個port。
除非指定client使用某port,只是一般不須要這么做。
假設(shè)是server主動關(guān)閉連接后異常終止。則由于它總是使用用一個知名serverport號,所以連接的time_wait狀態(tài)將導(dǎo)致它不能重新啟動。只是我們能夠通過socket的選項SO_REUSEADDR來強制進程馬上使用處于time_wait狀態(tài)的連接占用的port。
通過socksetopt設(shè)置后,即使sock處于time_wait狀態(tài),與之綁定的socket地址也能夠馬上被重用。
此外也能夠通過改動內(nèi)核參數(shù)/proc/sys/net/ipv4/tcp_tw/recycle來高速回收被關(guān)閉的socket,從而是tcp連接根本不進入time_wait狀態(tài),進而同意應(yīng)用程序馬上重用本地的socket地址。

tcp攻擊

所謂SYN 洪泛攻擊,就是利用SYNACK 報文的時候,服務(wù)器會為客戶端請求分配緩存,那么黑客(攻擊者),就可以使用一批虛假的ip向服務(wù)器大量地發(fā)建立TCP 連接的請求,服務(wù)器為這些虛假ip分配了緩存后,處在SYN_RCVD狀態(tài),存放在半連接隊列中;另外,服務(wù)器發(fā)送的請求又不可能得到回復(fù)(ip都是假的,能回復(fù)就有鬼了),只能不斷地重發(fā)請求,直到達到設(shè)定的時間/次數(shù)后,才會關(guān)閉。

服務(wù)器不斷為這些半開連接分配資源(但從未使用),導(dǎo)致服務(wù)器的連接資源被消耗殆盡,不過所幸,我們可以使用SYN Cookie進行有效地防御。

所謂的SYN Cookie防御系統(tǒng),與前面接收到SYN 報文就分配緩存不同,此時暫不分配資源;同時利用SYN 報文的源和目的地IP和端口,以及服務(wù)器存儲的一個秘密數(shù),使用它們進行散列,得到server_isn,然后附著在SYNACK 報文中發(fā)送給客戶端,接下來就是對ACK 報文進行判斷,如果其返回的ack字段正好等于server_isn + 1,說明這是一個合法的ACK,那么服務(wù)器才會為其生成一個具有套接字的全開的連接。


cookie防御
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容