TCP/IP協議中,在建立連接的時候ISN序號分配問題?
:
假設現在有兩個連接要建立,連接A和連接B,那首先肯定要給他們各分配一個32位的序號。問題1:首先我有一點疑問就是,兩個連接是獨立分開的,也就是說,這兩個連接就算他們的初始序號一樣應該也是可以的吧?就算初始序號不一樣,那之後傳數據也會出現序號一樣的可能性,比如:連接A的INS(初始序號)為100,連接B為105,都是以客戶端的序號為準,建立連接之後他們的序號各自為101和106,然後開始發數據,假設A發15位元組(純數據,首部不算),B發10位元組,所以下一個序列號就變成一樣的了,都是116 。所以連接與連接之間的序號重複應該是允許的吧?如果不,上面那個現象該如何解釋呢
問題2:《TCP/IP協議詳解 卷一》說,「ISN每4ms加1,這樣選擇序號的目的在於防止在網路中被延遲的分組在以後被重複傳輸,而導致某個連接的一端對它作錯誤的判斷。「 這句話感覺講得不夠具體,作為新手的我,實在想像不出來為什麼要這樣做。因為如果我的問題1的結論成立,那每個連接的ISN一樣也不要緊呀。就算我的問題1不成立,那如果兩個連接是並行的,運行時差肯定小於4ms,那他們的INS還是一樣的咯問題3:題外話,3次握手,第三次握手的時候,客戶端要向伺服器端發一個ACK確認號,如果在客戶端已經發出去之後,但還未到達伺服器端,伺服器離線斷網了,那此時客戶端如何知道?客戶端肯定以為連接建立成功了,這種情況該如何處理呢?新手,請見諒,這幾個疑問在網上搜了很久,但發現網上的tcp資料不是你抄他,就是他抄書,無奈,望大神解答~萬分感謝!
問題1、2:
一個TCP session 由 source IP + source Port + destination IP + destination Port 唯一決定,一般也稱為 TCP socket,所以即使每個TCP session 的ISN(Initial Sequence Number )都是相同的也無妨,TCP可以將不同socket的數據提交給不同的應用進程,而不會造成混淆。
但是如果ISN採用靜止的、不變的數字,會有以下潛在問題:
1) Bogus TCP Reset
大型防火牆的工作原理就是一旦發現有訪問blocked website,則需要重置這個連接,步驟如下:偽造一個TCP reset,包含IP欄位、TCP欄位的偽造,發送給客戶端,因為所有欄位都是可以接受的,所以客戶端接受這個reset消息並重置TCP連接。因為流量途徑防火牆,所以包括IP Header 、TCP Header的信息都能得到,所以很容易偽造。
對於不能接觸到流量的任何第三方能否也可以偽造一個TCP Reset呢?理論上也是可以的,對於靜態的欄位如 source/destination IP/Port 這個比較容易偽造,最難的就是 TCP sequence number ,至少偽造的序列號位於對方的 slide window 窗口之內,而如果採用靜態ISN,則相對容易構造一個TCP Reset,然後將一個TCP session 重置了,這很顯然不利於安全。
而如果採用隨著時間而增長的ISN,由於這個ISN是一個動態的值,所以偽造TCP sequence number 難度增加,所以這個動態增長的ISN一方面是出於安全的考慮。
2)Ambignity of TCP Port Reused
由於允許一個剛釋放的TCP Port重用,如果已釋放的TCP session 與 新建立的TCP session 四原組完全一致,則存在老的session 的數據依然在路上,新的session 也在路上,這樣對方就會被弄迷糊,而無法判斷誰是真正的合法數據。如採用動態增長的ISN,則避免相鄰的兩個TCP session 的 sequence number 的重疊,不會造成誤會。
問題3:
客戶端握手的ACK由於伺服器端斷網而丟棄,此時客戶端為 established 狀態,伺服器端為SYN_Receive狀態,客戶端發送的數據由於伺服器端的斷網也被丟棄,客戶端啟動超時重傳(timeout retransmit),就這麼一直重傳下去,如果到達 retransmit retry limit ,則reset 這個TCP連接。如果沒有到達retransmit retry limit 而伺服器端網路恢復,則伺服器端接收客戶端的ACK + Data,伺服器端切換到 established 狀態,並將緩存的數據提交給應用程序。來一個一個解答(源IP,源埠,目的IP,目的埠,協議號),這五個要素組成一個五元組。協議號都是TCP的話說是四元也行。不同的五元組,它們的SN完全是獨立的空間,互相不干擾,所以是多少都是可以的。但是這裡有個安全問題,如果你使用固定的其實,那麼一個攻擊者就有可能猜出你的SN號序列,然後插入到你的TCP連接當中。我們知道IP協議並不安全,一個發送者可以很容易偽造自己的源IP地址來發送數據包,即使他沒有辦法在你和目標中間建立偵聽,他也可以通過推測你們兩者的ISN來發送可以混進TCP連接的數據,造成很嚴重的安全問題。所以現代操作系統會根據不同的五元組,創建獨立的ISN空間,同一時間建立的五元組不同的連接,會使用不同的ISN,這是為了安全。那麼第二個問題,這個ISN遞增,在現在的實現當中,是針對同一個五元組的。TCP不允許你在同一個源埠和目的埠之間建立兩個相同的連接,但是當前一個連接關閉或者建立失敗時候,是可以允許你重新使用這個源埠和對方的目的埠來建立連接的,在允許快速復用埠號的時候(開啟SO_REUSEADDR選項)這個時間間隔可能非常短,保證這樣的連接可以正確建立,在許多高性能伺服器當中是非常重要的。在這時候就遇到了一個問題,前一個連接剛剛結束,由於網路可能出現迴環等故障,有可能有前一個連接的一些重傳的數據包,會在我重新建立連接之後再到達,那麼,我要如何區分我收到的數據包是來自舊的連接,還是新的連接呢?如果我們處理錯了這個關係,就可能導致連接狀態異常。TCP當中區分舊數據還是新數據,是依靠SN的不斷遞增的關係的,SN是32位整數,我們以當前允許接受的最小SN作為分界線,最小SN + 2^31(SN空間的一半)作為另一個分界線,分成向前的一半和向後的一半。如果收到了向前的一半中的數據,我們認為這個數據是對方新發送給我們的,我們需要處理;如果收到了向後的一半中的數據,我們認為這是一個由於網路延遲等原因而重複出現的老數據,需要忽略。那麼新建立的連接也是這樣,為了區分新連接和老連接,我們需要讓老連接的數據全部都在我的ISN的前面一半,這樣它們就可以被安全忽略,為了盡量讓老連接數據到來時能夠成功被區分,我的ISN應該取老連接最後一個SN + 1,這樣可以保證所有的老連接上的數據包都能儘可能跟新連接區分開。(注意使用完全隨機的ISN是不行的,有一半概率這個ISN會選到老連接數據的那一半,按照TCP的協議,在對方仍然處於TIME_WAIT或者CLOSE_WAIT的狀態下,這個SYN包會被當作老的連接的數據而丟棄掉,這樣連接就建立不起來了。)但是我們也不可能讓五元組上的ISN一直都保持著老的SN+1的值,這樣會導致我們的ISN很容易被猜出,引起安全問題,所以選擇在4ms左右的時候遞增1,這樣攻擊者就會很難猜出完全正確的SN的數值。第三個問題,客戶端的確會認為連接成功建立,但是伺服器端在沒有收到ACK時,會重傳SYN+ACK的第二次握手,客戶端收到重傳會重新回復ACK,這樣就成功建立起了連接。如果網路徹底中斷了,伺服器重傳若干次SYN+ACK之後連接會失敗,而客戶端的確會認為連接成功建立了,如果它就這樣什麼數據都不發送也沒有超時機制的話,的確會有問題。但一般客戶端都需要主動發送一些數據,比如心跳檢測,當發送數據時由於對面已經沒有連接狀態,不會回復ACK(或者直接回復RST),這樣客戶端就會重置這個不正確的連接。
1. 兩個連接那四元組一定不同啊,這就可以區分了,序列號只是為了標識同連接內包的順序的。2. 與一一樣,這句話的前提是同一個連接的包,不同連接的包確實沒有限制。不同連接確實可以ISN一樣,但這會帶來其它問題,暫且不表。3. 確實是以為鏈接建立成功了。客戶端會直接發數據,然而伺服器端並不會響應數據的ACK,於是導致超時。實際上有的協議棧實現在第三個包ACK時直接帶數據。但從客戶端來看,這個連接確實是成功建立了。
1,協議棧收到一個報文後首先根據IP頭部中的源IP目的IP和tcp頭部中的源port目的port找到對應的tcp連接,然後才開始處理序列號2,同一台機器如果初始序列號都從一個固定的值開始,更有可能造成困擾,比如,A和B建立了一個連接,發送一些數據後斷開連接,其中一些報文在這個過程中發生了重傳而且還存在於網路之中,之後AB之間又建立了一個連接但IP及port四元組跟上次一樣,那麼上一個連接的重傳報文如果這時才到達接收端,如果序列號又在合理區間的話接收端可能會以為是本次連接的正常報文。如果取一個變化的初始序列號,可以降低這種可能性。3,客戶端不發送數據的話就永遠不知道伺服器掉線了,除非開啟了tcp的keepalive
推薦閱讀:
※路由器wan口和lan口連接在一起 是什麼機制和原理?
※使用WIN7,有哪些系統設置可以讓外觀使用之類的體現高逼格?
※二層交換機和三層交換怎麼設置命令?兩台PC網段不一樣。
※用C++、Python、Ruby寫爬蟲的比較?