一、TCP連接的ISN
之前我們說過初始建立TCP連接的時候的系列號(ISN)是隨機選擇的,那么這個系列號為什么不采用一個固定的值呢?主要有兩方面的原因
- 防止同一個連接的不同實例(different instantiations/incarnations of the same connection)的數據包混淆。
同一個連接的不同實例是怎么回事呢?之前我們說過(源IP、源端口號、目的地址、目的端口號)這個四元組唯一標識一個TCP連接,當一個TCP連接在經歷四次揮手關閉時,假如有一個數據包延遲特別大,而這個連接在關閉后又馬上以相同的四元組建立起來,那么先前這個連接的TCP數據包到達的時候,如果系列號還落在接收窗內,那么這個數據包就可能會被錯誤接收。因此RFC0793指出ISN應該每4μs自增1,從而防止同一個連接的不同實例的數據包混淆。另外對數據完整性要求比較高的應該同時在應用層添加校驗。
- 防止TCP系列號欺騙
TCP系列號欺騙如下圖所示,假設A是服務器,B是擁有特殊權限的客戶端,C是攻擊者,第一條消息C冒充B來向服務器A請求建立連接,此時C發出的數據包的IP地址會填寫成B的;第二條消息假設A沒有其他手段來驗證B,而僅僅根據IP地址判斷C發過來的建立連接的請求是B發過來的,因此向B發送SYN+ACK,此時假設B被C進行了DOS攻擊或者處於其他異常狀態而不能響應第二條消息(如果B處於正常狀態會響應一個RST包來重啟TCP連接,后面我們講解RST數據包);第三條消息假如C能正確的猜測出A在第二條消息中的ISN,就可以冒充B和A完成三次握手的過程,讓A誤以為和B建立了連接。接下來C就可以冒充B給A發送一些危險數據或者指令而實現攻擊。
因此假如ISN僅僅是依靠時間來增長還不夠安全,因此RFC1948又提出了一個ISN隨機生成的算法
ISN = M + F(localhost, localport, remotehost, remoteport)
其中M是一個計時器,這個計時器每隔4毫秒加1。 F是一個Hash算法,根據源IP、目的IP、源端口、目的端口生成一個隨機數值。要保證hash算法不能被外部輕易推算得出,用MD5算法是一個比較好的選擇。具體到linux的實現中,F采用MD5進行Hash,另外還會在F這個函數中帶入一個隨機的net_secret安全碼進一步安全性,linux中M計時器則是每64ns加1。
二、連接超時
當一個TCP連接請求超時的時候,比如對應目標IP的主機掛掉的時候,會觸發SYN數據包的重傳,重傳的時間間隔按照
指數退避(exponential backoff)
算法增長,還記得我們之前說過得SYN和FIN數據包是在邏輯上占有一個byte的是,也就會消耗一個系列號,消耗系列號意味着能進行重傳,沒有數據的ACK確認包因為不消耗系列號即使傳輸過程中出錯也不會觸發ACK數據包的重傳。后續TCP重傳部分我們會進一步介紹TCP的重傳和指數退避。
在linux中net.ipv4.tcp_syn_retries變量表示TCP主動連接端SYN數據包的最大重傳次數,net.ipv4.tcp_synack_retries表示TCP連接的被動端響應的SYN+ACK包的最大重傳次數。也可以通過TCP_SYNCNT的socket選項單獨設置某一個TCP連接SYN重傳次數。
我們觀察一下下圖中SYN重傳的過程,首先發出No 1的SYN包,在1s內沒有收到SYN-ACK包,觸發SYN重傳即No 2包,后續又分別以2s/4s/8s/16s/32s的間隔進行SYN的重傳,直到No 7包進行第6次重傳依舊沒有收到SYN-ACK回復(net.ipv4.tcp_syn_retries默認配置值為6),客戶端放棄連接。
三、長連接與短連接
TCP連接類型又可以分為
長連接和
短連接
- 短連接:Client方與Server每進行一次報文收發時才進行通訊連接,收發完畢后立即斷開連接。此種方式常用於一點對多點通訊,比如多個Client連接一個Server.優點是管理起來比較簡單,存在的連接都是有用的連接,不需要額外的控制手段
- 長連接:Client方與Server方先建立通訊連接,連接建立后不斷開,然后再進行報文發送和接收。這種方式下由於通訊連接一直存在,可以用下面命令查看連接是否建立:netstat –f inet|grep 端口號(如5678)。此種方式常用於點對點通訊。
補充說明
1、linux中計算ISN的過程可以參考相關代碼tcp_v4_init_sequence

