天天看點

《TCP IP 詳解卷1:協定》閱讀筆記 - 第十三章

閱讀須知:筆記為閱讀《TCP IP 詳解卷1:協定》後摘抄的一些知識點,其間也有加入一些根據英文原版的自己翻譯和結合網上知識後的了解,是以有些段落之間并不能夠串聯上或者知識點與書上略有差别(基本差别不大,參考的資料屬 RFC官方文檔

)。

第十三章:TCP連接配接管理

TCP是一種面向連接配接的單點傳播協定,在發送資料之前,通信雙方必須在彼此建立一條連接配接;這與UDP的無連接配接不同,UDP無需通信雙方發送資料之前建立連接配接。所有TCP需要處理多種TCP狀态時需要面對的問題,比如連接配接的建立、傳輸、終止,以及無警告的情況下重新啟動,這也是TCP與UDP之間的主要差別之一。

TCP連接配接的建立和終止過程

一個TCP連接配接由一個4元組構成,它們分别是兩個IP位址和兩個端口号。更準确地說,一個TCP連接配接是由一對端點或套接字構成,其中通信的每一端都由一對(IP位址,端口号)所唯一辨別。

一個TCP連接配接通常分為3個階段:建立連接配接、資料傳輸(連接配接已建立)、關閉連接配接。下面描述一次TCP連接配接的建立和關閉過程。

《TCP IP 詳解卷1:協定》閱讀筆記 - 第十三章

連接配接過程:

  1. 用戶端發送一個SYN封包段(即一個在TCP頭部的SYN位字段置位的TCP/IP資料包),并指明自己想要連接配接的端口号和它的用戶端初始序列号(記為ISN(c))。

  2. 伺服器接收到用戶端發送的SYN封包段後,也發送自己的SYN封包段作為響應,并包含了伺服器的初始序列号ISN(s)。為了确認用戶端的SYN,伺服器将用戶端SYN封包段中包含的ISN(c)數值加1後作為傳回的ACK數值。是以,每發送一個SYN,序列号就會自動加1。

  3. 用戶端接收到伺服器發送的SYN封包段後,為了确認伺服器的SYN,用戶端将ISN(s)的數值加1後作為傳回的ACK數值。

  4. 至此,連接配接被建立,以上過程也被稱為三次握手。TCP通信可進入資料傳輸階段。

關閉過程:

  1. 連接配接的主動關閉者(此例中是用戶端)發送一個FIN位字段置位的TCP/IP資料包指明希望斷開連接配接及接收者希望看到的自己目前序列号K。FIN封包段還包含了一個ACK段用于确認對方最近一次發來的資料L。

  2. 連接配接的被動關閉者(此例中是伺服器)将K的數值加1作為響應的ACK值,以表明它已經成功接收到主動關閉着發送的FIN。被動發送者将身份轉變為主動關閉者,發送自己的FIN封包段,序列号為L,ACK為K+1。

  3. 目前的主動關閉者(此時是用戶端)發送一個FINA位字段置位的TCP/IP資料包指明希望斷開連接配接,FIN封包段序列号為L,ACK為K+1。

  4. 目前的被動關閉者(此時是伺服器)接收到資訊後,将L加1後作為ACK,将K作為Seq,回應給主動關閉者,以确認上一個FIN。

  5. 至此,連接配接被關閉。

由于TCP的雙工通信特性,TCP支援半關閉。TCP的半關閉操作是指僅關閉資料流的一個傳輸方向,而另一方扔在傳輸資料直到它被關閉為止。

文中還讨論過TCP通信雙方同時打開與同時關閉的情況:假設主機A的應用程式通過本地7777端口向主機B的8888端口發送一個主動打開請求,同時,主機B的應用程式也通過本地8888端口向主機A的7777端口發送一個主動打開請求。

過程如下圖:

《TCP IP 詳解卷1:協定》閱讀筆記 - 第十三章

通信的雙方同時扮演用戶端和伺服器的角色。在同時打開時,與正常的連接配接建立過程相比,需要增加一個封包段;在同時關閉時,與正常關閉相似,隻是封包段的順序是交叉的。

初始序列号的存在由于以下2個原因:

  1. 在連接配接打開時,任何擁有何時的IP位址、端口号、符合邏輯的序列号以及正确校驗和的封包都将被對方接收。

  2. TCP封包段在經過網絡路由有可能會存在延遲抵達和排序混亂的情況。

在發送用于建立連接配接的SYN之前,通信雙方會選擇一個初始序列号。初始序列号會随時間而改變,是以每個連接配接都擁有不同的初始序列号。[RFC0793]指出初始序列号可被視為一個32位的計數器,計數器的值每4微秒加1,以防止出現于其他連接配接的序列号重疊的情況。

在連接配接建立逾時的時候,連接配接的打開方會産生指數回退行為:用戶端TCP為了建立連接配接而頻繁發送SYN封包段,首個封包段發送後3s發送第二個,第二個封包段之後6s發送第三個,第三個封包段12s後發送第四個...

并且一些系統可配置發送初始SYN的次數,通常選擇一個較小的數值5。比如在Linux中,系統配置變量net.ipv4.tcp_syn_retries表示了在一次主動打開申請中嘗試重新發送SYN封包段的最大次數;net.ipv4.tcp_synack_retries則表示響應對方的一個主動打開請求時嘗試重新發送SYN+ACK封包段的最大次數。

當TCP發現一個到達的封包段對于相關連接配接而言是不正确的時候,TCP就會發送一個重置封包段,該封包段将TCP頭部的RST位字段置位。書本列出以下場景來證明重置封包段的用途:

  1. 針對不存在端口的連接配接請求:回憶之前學習的UDP,當資料報遇到目的地不可達的情況會生成一個ICMP目的不可達的消息;而對于TCP則使用重置封包來代替相關工作。

  2. 終止一條連接配接:發送FIN的終止連接配接方法有時被稱為有序釋放;通過發送一個RST封包段也可以終止一條連接配接,被稱為終止釋放。終止連接配接可以為應用程式提供兩大特性:1.任何排隊的資料都将被抛棄,一個重置封包段會被立即發送出去;2.重置封包段的接收方會說明通信另一端采用了終止的方式而不是正常關閉。

  3. 半開連接配接:通信一方的主機(例如伺服器)奔潰的情況下,隻要不嘗試通過半開連接配接傳輸資料,正常工作的一端(用戶端)将不會檢測出另一端已經奔潰。伺服器重新開機後,用戶端再次連接配接,由于伺服器對收到的封包無法做出處理,會響應一個重置封包段,之後兩端之間的連接配接将被關閉以重建立立。

  4. 時間等待錯誤:

TCP狀态

《TCP IP 詳解卷1:協定》閱讀筆記 - 第十三章

箭頭表示因封包段傳輸、接收以及計時器逾時而引發的狀态轉換;粗箭頭表示典型的用戶端的行為;虛線箭頭表示典型的伺服器行為。

針對上面的狀态圖,再看正常的TCP連接配接建立和關閉過程中用戶端和伺服器經曆的狀态變化:

《TCP IP 詳解卷1:協定》閱讀筆記 - 第十三章

值得注意的是狀态TIME_WAIT(2MSL)也稱為2MSL等待狀态,在該狀态中,TCP将會等待兩倍于最大段生存期(MSL)的時間,也被稱作加倍等待。每個實作都必須為最大段生存期選擇一個數值,它代表任何封包段在被丢棄之前再網絡中允許存在的最長時間。

TCP段文報以IP資料報的形式傳輸,IP資料報擁有TTL字段和跳數限制字段,也就限制了IP資料報的有效生存時間。[RFC0793]将最大段生存期設為2分鐘,然而在大多數的實作中,該數值可修改。

假設已經設定了MSL的數值,按照規則:當TCP執行一個主動關閉并發送最終的ACK時,連接配接必須處于TIME_WAIT狀态并持續兩倍于最大生存期的時間,這樣就能夠讓TCP重新發送最終的ACK以避免出現丢失的情況。另一個影響是,當TCP處于等待狀态時,通信雙方将該連接配接定義為不可重新使用。隻有當2MSL等待結束時,才可以建立新的連接配接執行個體。

當連接配接處于2MSL等待狀态時,任何延遲到達的封包段都将被丢棄。為了防止處于TIME_WAIT狀态下的系統奔潰或者重新開機,[RFC0793]指出在崩潰或者重新開機後TCP協定應當在建立新的連接配接之前等待相當于一個MSL的時間(靜默時間)。

TCP選項

TCP頭部包含多個選項,整個選項清單是有網際網路編号配置設定機構(IANA)維護的。每個選項的頭一個位元組為"種類",指明了該選項的類型。根據[RFC1122],不能被了解的選項會被簡單的忽略掉。種類值為0或者1的選項僅占一個位元組,其他選項會根據種類來确定自身的位元組數len,選項的總長度包括了種類和len個位元組。需要注意的是,TCP頭部的長度應該是32比特的倍數,因為TCP頭部長度字段是以此為機關的。

如一些TCP選項:

種類  |  長度(len)  |        名稱        |    描述
0        1                  EOL             選項清單結束
1        1                  NOP             無操作(用于填充)
2        4                  MSS             最大段大小
3        3                  WSOPT           視窗縮放因子(視窗左移量)
4        2             SACK-Permitted       發送者支援SACK選項
5        可變                SACK            SACK阻塞(接收到亂序資料)
6        10                 TSOPT           時間戳選項
28       4                  UTO             使用者逾時(一段空閑時間後的終止)
29       可變              TCP-AO            認證選項(使用多種算法)
253      可變             Experimental       保留供實驗所用
254      可變             Experimental       保留供實驗所用           

最大段大小(MSS)是指TCP協定所允許的從對方接收到的最大封包段,也是通信對方在發送資料時能夠使用的最大封包段。根據[RFC0879],該選項隻記錄TCP資料的位元組數而不包括其他相關的TCP與IP頭部。

當建立一條TCP連接配接時,通信的每一方都要在SYN封包段的MSS選項中說明自已允許的最大段大小,在沒有事先指明的情況下,最大段大小的預設數值為536位元組。其計算:(576/IPv4資料報(最小)-20/IPv4基本頭部(最小)-20/TCP基本頭部(最小)=536)。根據以太網中最大傳輸單元與網際網路路徑最大傳輸單元的典型數值1500來算,最大段大小數值為1460,這也是IPv4協定族的典型值。

選擇确認選項(SACK)用于發送方了解接收方的資料接收情況(1.由于采用累積ACK确認,TCP不能正确地确認之前已經接收的資料;2.由于資料的接收是無序的進而導緻接收的資料序列号是不連續的),以在封包段丢失或被接收方遺漏時更換的進行重傳工作。

SACK資訊儲存于ASCK選項中,包含了接收方已經成功接收的資料塊的序列号範圍,每個範圍被稱為一個SACK塊,由一對32位的序列号表示,是以,一個SACK選項包含了n個SACK塊,長度為(8n+2)個位元組,增加的2個位元組用于儲存SACK選項的種類與長度。由于TCP頭部選項的空間有限,是以一個封包段中發送的最大SACK塊數目為3。雖然隻有SYN封包段才能包含"允許選擇确認"選項,但隻要發送方已經發送了該選項,SACK塊就能夠通過任何封包段發送出去。

視窗縮放選項能夠有效的将TCP視窗大小字段的範圍從16位增加至30位[RFC1323],TCP頭部不需要改變視窗大小字段的大小,仍維持16位的數值。同時,使用另一個選項作為這16位數值的比例因子,該比例因子能夠使視窗字段值有效地左移,比如:将視窗數值擴大至原先的2的s次方倍,s為比例因子。視窗的移動數值是由TCP通信方根據接收緩存的大小自動選取的。一個位元組的移動可以用0至14來計數,計數0表示沒有任何比例,最大比例數值是14,它能夠提供最大為1073725440位元組(65535*2的14次方)的視窗,是以TCP使用一個32位的值來維護這個"真實"的視窗大小。該選項隻能出現于一個SYN封包段中,是以當連接配接建立以後比例因子是與方向綁定的。為了保證視窗調整,通信雙方都需要在SYN封包段中包含該選項,且每個方向的比例因子可各不相同。主動打開連接配接的一方利用自已的SYN中發送該選項,但被動打開連接配接的一方隻能在接收到的SYN中指出該選項時才能發送。如果主動打開連接配接的一方發送了一個非0的比例因子但卻沒有接收到來自對方的視窗縮放選項,它會将自已發送與接收的比例因子數值都設為0。

時間戳選項要求發送方在每個封包段中添加2個4位元組的時間戳數值。接收方在确認中反映這些數值,允許發送方針對每個收到的ACK估算TCP連接配接的往返時間。當時有時間戳選項時,發送方将一個32位的數值填充到時間戳字段作為時間戳的第一個部分;接收方則将收到的時間戳數值原封不動的填充至第二部分的時間戳回顯重試字段(TSER或TSecr)。使用時間戳選項的TCP頭部會增加10位元組(8位元組用于儲存2個時間戳數值,2位元組用于指明選項數值和長度)。使用時間戳選項可讓接收者避免接收舊封包段和判斷封包段正确性,時間戳選項使用擴充的這種方法被稱為防回繞序列号(高速傳輸的環境中,如果重傳時間差小于MSL)。

使用者逾時逾時選項是數值指明了TCP發送者在确認對方未能成功接收資料之前願意等待該資料ACK确認的時間。根據[RFCO793]描述,USER_TIMEOUT是TCP協定本地配置的一個參數,使用者逾時選項允許TCP通信方将自已的USER_TIMEOUT數值告知連接配接的對方,這樣就友善了TCP接收方調整自已的行為。NAT裝置也能夠解釋這些資訊以幫助設定它們的連接配接活動計時器。

認證選項目的在于增強與替換較早的TCP-MD5機制[RFC2385],它使用一種加密雜湊演算法以及TCP連接配接上分共同維護的一個秘密值來認證每一個封包段。TCP認證選項不僅提供各種加密算法,還使用“帶内”信令來确認密鑰是否改變,是以它與TCP-MD5相比有很大的提高。然而,該選項未提供一個全面密鑰管理方案...也就是說,通信雙方不得不采用一種方法在TCP認證選項運作之前建立出一套共享密鑰。

TCP相關 

TCP的路徑最大傳輸機關發現 

TCP正常的路徑最大傳輸單元(MTU)發現過程如下:一個連接配接建立時,TCP使用對外接口的最大傳輸單元的最小值,或者根據通信對方聲明的最大段大小來選擇發送方的最大段大小(SMSS)。

TCP路徑MTU發現遵循以下規則:

  1. 路徑最大傳輸單元發現不允許TCP發送方有超過另一方所聲明的最大段大小的行為。

  2. 如果對方沒有指明最大段大小的數值,發送方将采用預設的536位元組。

  3. 如果收到PTB消息,TCP就會減少段的大小,然後用修改過的段大小進行重傳(在網絡傳輸過程中,如果中間鍊路的最大傳輸單元小于兩端通信節點的,路徑MTU發現機制能夠找出合适的段大小以供傳輸使用)。

值得注意的是,一條連接配接的兩個方向的路徑最大傳輸單元是不同的。

重置封包段的使用例子

時間等待錯誤過程如下圖:

《TCP IP 詳解卷1:協定》閱讀筆記 - 第十三章

如上圖,當FIN封包被發送且用戶端已經進入TIME_WAIT狀态時,如果這時候伺服器發送了一個如圖上的"舊"的封包段(Seq=L-100,ACK=K-200),用戶端會響應一個ACK(ACK=L,Seq=K)說明最新資料的資訊,然而伺服器接收到這個封包後它已經是關閉狀态了,是以伺服器響應一個RST封包段,告訴客戶機(提前)關閉連接配接。

TCP伺服器選項

對于伺服器的設計而言,TCP也存在一些影響:

如果主機是多宿主主機,可以為本地IP位址指定一個單一的位址,并且隻有被該接口接收到的連接配接才能夠被接受。而哪一個程序該處理接收到的封包段則有4元組(目的IP、目的端口号、源IP、源端口号)多路分解後決定。

與UDP伺服器相似,TCP服務也可以限制對本地IP位址的請求,如sock -s 10.0.0.1 8888,限制隻能使用到達本地IPv4位址10.0.0.1的8888端口才能收到連接配接資訊。

[RFC0793]描述,TCP的抽象接口函數允許一台伺服器為一個指定的外部節點或者一個未被指定的外部節點執行被動打開。然而套接字API并未提供實作的函數,于是,伺服器不必指定用戶端的節點,而是等待連接配接的到來,然後檢查用戶端的IP位址和端口号。

一個并行伺服器會為每個用戶端配置設定一個新的程序或線程,這樣負責偵聽的伺服器能夠始終準備着處理下一個到來的連接配接請求,在偵聽伺服器正在建立一個新程序時,或作業系統忙于運作其他高優先級的程序時,或伺服器可能正在被僞造的連接配接請求攻擊時,多個連接配接請求可以回到達。針對以上情況,作業系統通常會維護連接配接列隊來做請求數量的控制。如Linux中,連接配接列隊遵循以下規則:

  1. 當一個連接配接請求到達,檢查系統範圍的參數net.ipv4.tcp_max_syn_backlog(預設1000)。如果處于SYN_RCVD狀态的連接配接數目超過這一門檻值,進入的連接配接将被拒絕。

  2. 每個處于偵聽狀态下的節點都擁有一個固定長度的連接配接列隊。其中的連接配接已經被TCP完全接受(即已完成三次握手),但未被應用程式接受。應用程式會對這個列隊做出限制,通常稱為未完成連接配接(backlog),backlog的數目必須在0與系統指定的最大值之間,該最大值為net.core.somaxconn,預設值128(含)。

  3. 如果偵聽節點的列隊中仍然有空間配置設定給新的連接配接,TCP子產品會應答SYN并完成連接配接。知道接收到三次握手中的第三個封包段之後,與偵聽節點相關的應用程式才會知道新的連接配接。這種情況下,用戶端可能會認為伺服器已經準備好接收資料了,然而伺服器隻是TCP子產品構成了連接配接,應用程式并未收到相關連接配接,這時的TCP子產品将會把接收的資料存入隊列中。

  4. 如果隊列中沒有足夠的空間配置設定給新的連接配接,TCP會延遲對SYN做出響應,進而給應用程式處理的時間。如果系統變量nex.ipv4.tcp_abort_on_已經被設定,新進入的連接配接會被重置封包段重新置位。

在隊列溢出的情況下,發送重置封包段通常是不可取的,而且預設情況4下該功能是關閉的。用戶端在交換SYN期間如果收到一個重置封包段,它可能認為伺服器是不存在的,而不是處于繁忙狀态。是以,正常的操作是應當阻止應用程式再去服務那些進入的連接配接。

相關攻擊

SYN泛洪,一種TCP拒絕服務攻擊,在這種攻擊中一個或多個惡意的用戶端産生一系列TCP連接配接嘗試(SYN封包段),并将它們發送給一台伺服器,它們通常采用"僞造"的源IP位址。伺服器會為每一條連接配接配置設定一定數量的連接配接資源,由于連接配接尚未完全建立,伺服器為了維護大量的半打開連接配接會在耗盡自身記憶體後拒絕為後續的合法連接配接請求服務。

針對SYN泛洪,一種稱為SYN cookies的機制做出以下處理:當一個SYN到達時,這條連接配接存儲的大部分資訊都會被編碼并儲存在SYN+ACK封包段的序列号字段。采用SYN cookies的目标主機不需要為進入的連接配接請求配置設定任何存儲資源,隻有當SYN+ACK封包段本身被确認後才會配置設定真正的記憶體。在這種情況下,所有重要的連接配接參數都能夠重新獲得,同時連接配接也能夠被設定位ESTABLISHED狀态。

有一種是攻擊影響路徑MTU發現過程,僞造ICMP PTB消息迫使通信雙方采用非常小的資料報進行傳輸,進而降低通信的性能。

還有種破壞甚至劫持TCP連接配接的攻擊,該攻擊通常包含的第一步是使兩個之前正在通信的TCP節點"失去同步"。這樣他們就使用了不正确的序列号,稱為序列号攻擊。至少有兩種方法實作上述攻擊:在連接配接建立過程中引發不正确的狀态傳輸;在ESTABLISHED狀态下産生額外的資料。

欺騙攻擊,這類攻擊所涉及的TCP封包段由攻擊者精心定制,目的在于破壞或改變現有TCP連接配接的行為。攻擊者可能生成一個僞造的重置封包段并将其發送給一個TCP通信節點,假設與連接配接相關的4元組以及校驗和都是正确的,序列号也處于正确的範圍,就會造成連接配接的任意一端失敗。相關的防禦技術包括:使用TCP-AO選項;要求重置封包段擁有一個特殊的序列号以代替處于某一範圍的序列号了要求時間戳選項具有特定的數值;使用其他形式的cookie檔案,讓非關鍵的資料依賴于更加準确的連接配接資訊或一個秘密數值。 

繼續閱讀