
TCP建立連接的三次握手過程,以及關閉連接的四次握手過程

貼一個telnet建立連接,斷開連接的使用wireshark捕獲的packet截圖。

1、建立連接協議(三次握手)
(1)客戶 端發送一個帶SYN標志的TCP報文到server。這是三次握手過程中的報文1。
(2) server端回應client的,這是三次握手中的第2個報文。這個報文同一時候帶ACK標志和SYN標志。
因此它表示對剛才clientSYN報文的回應。同一時候又標志SYN給client,詢問client是否准備好進行數據通 訊。
(3) 客戶必須再次回應服務段一個ACK報文,這是報文段3。
2、連接終止協議(四次握手)
因為TCP連 接是全雙工的,因此每一個方向都必須單獨進行關閉。這原則是當一方完畢它的數據發送任務后就能發送一個FIN來終止這個方向的連接。收到一個 FIN僅僅意味着這一方向上沒有數據流動。一個TCP連接在收到一個FIN后仍能發送數據。首先進行關閉的一方將運行主動關閉。而還有一方運行被動關閉。
(1) TCP客 戶端發送一個FIN。用來關閉客戶到server的數據傳送(報文段4)。
(2) server收到這個FIN。它發回一個ACK,確認序號為收到的序號加1(報文段5)。
和SYN一樣。一個FIN將占用一個序號。
(3) server關閉client的連接,發送一個FIN給client(報文段6)。
(4) 客戶段發回ACK報文確認。並將確認序號設置為收到序號加1(報文段7)。
CLOSED: 這個沒什么好說的了,表示初始狀態。
LISTEN: 這個也是很easy理解的一個狀態。表示server端的某個SOCKET處 於監聽狀態,能夠接受連接了。
SYN_RCVD: 這個狀態表示接受到了SYN報文。在正常情況下,這個狀態是server端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態。非常短暫,基本上用netstat你是非常難看到這樣的狀態的,除非你特意寫了一個client測試程序。有益將三次TCP握手過程中最后一個ACK報文不予發送。因此這樣的狀態時,當收到client的ACK報文 后,它會進入到ESTABLISHED狀態。
SYN_SENT: 這個狀態與SYN_RCVD遙想呼應。當clientSOCKET運行CONNECT連接時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀態,並等待服務端的發送三次握手中的第2個報文。
SYN_SENT狀態表示client已發送SYN報文。
ESTABLISHED:這個easy理解了,表示連接已經建立了。
FIN_WAIT_1: 這個狀態要好好解釋一下,事實上FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的差別是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連接,向對方發送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。
而當對方回應ACK報文后,則進入到FIN_WAIT_2狀態。當然在實際的正常情況下,不管對方何種情況下,都應該立即回應ACK報文,所以FIN_WAIT_1狀態通常是比較難見到的。而FIN_WAIT_2狀態還有時經常能夠用netstat看到。
FIN_WAIT_2:上面已經詳解了這樣的狀態,實際上FIN_WAIT_2狀態下的SOCKET。表示半連接,也即有一方要求close連接,但另外還告訴對方,我臨時還有點數據須要傳送給你,稍后再關閉連接。
TIME_WAIT: 表示收到了對方的FIN報文。並發送出了ACK報文,就等2MSL后就可以回到CLOSED可用狀態了。假設FIN_WAIT_1狀態下。收到了對方同一時候帶FIN標志和ACK標志的報文時,能夠直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。
CLOSING: 這樣的狀態比較特殊。實際情況中應該是非常少見,屬於一種比較罕見的例外狀態。
正常情況下,當你發送FIN報文后,按理來說是應該先收到(或同一時候收到)對方的ACK報文,再收到對方的FIN報文。
可是CLOSING狀態表示你發送FIN報文后,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。
什么情況下會出現此種情況呢?事實上細想一下。也不難得出結論:那就是假設兩方差點兒在同一時候close一個SOCKET的話。那么就出現了兩方同一時候發送FIN報文的情況,也即會出現CLOSING狀態,表示兩方都正在關閉SOCKET連接。
CLOSE_WAIT: 這樣的狀態的含義事實上是表示在等待關閉。怎么理解呢?當對方close一個SOCKET后發送FIN報文給自己,你系統毫無疑問地會回應一個ACK報文給對方。此時則進入到CLOSE_WAIT狀態。接下來呢。實際上你真正須要考慮的事情是察看你是否還有數據發送給對方,假設沒有的話,那么你也就能夠close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下。須要完畢的事情是等待你去關閉連接。
LAST_ACK: 這個狀態還是比較easy好理解的。它是被動關閉一方在發送FIN報文后,最后等待對方的ACK報文。當收到ACK報文后,也即能夠進入到CLOSED可用狀態了。
補充:
a. 默認情況下(不改變socket選項)。當你調用close( or closesocket,下面說close不再反復)時。假設發送緩沖中還有數據,TCP會繼續把數據發送完。
b. 發送了FIN僅僅是表示這端不能繼續發送數據(應用層不能再調用send發送),可是還能夠接收數據。
c. 應用層怎樣知道對端關閉?通常。在最簡單的堵塞模型中,當你調用recv時,假設返回0,則表示對端關閉。在這個時候通常的做法就是也調用close,那么TCP層就發送FIN。繼續完畢四次握手。
假設你不調用close,那么對端就會處於FIN_WAIT_2狀態,而本端則會處於CLOSE_WAIT狀態。這個能夠寫代碼試試。
d. 在非常多時候。TCP連接的斷開都會由TCP層自己主動進行。比如你CTRL+C終止你的程序,TCP連接依舊會正常關閉。你能夠寫代碼試試。
1、 為什么建立連接協議是三次握手,而關閉連接卻是四次握手呢?
這是由於服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求后。它能夠把ACK和SYN(ACK起應答作用。而SYN起同步作用)放在一個報文里來發送。但關閉連接時,當收到對方的FIN報文通知時,它只表示對方沒有數據發送給你了。但未必你所有的數據都所有發送給對方了。所以你能夠未必會立即會關閉SOCKET,也即你可能還須要發送一些數據給對方之后,再發送FIN報文給對方來表示你允許如今能夠關閉連接了。所以它這里的ACK報文和FIN報文多數情況下都是分開發送的。
2、 為什么TIME_WAIT狀態還須要等2MSL后才干返回到CLOSED狀態?
什么是2MSL?MSL即Maximum Segment Lifetime,也就是報文最大生存時間,引用《TCP/IP具體解釋》中的話:“它(MSL)是不論什么報文段被丟棄前在網絡內的最長時間。”那么。2MSL也就是這個時間的2倍,當TCP連接完畢四個報文段的交換時,主動關閉的一方將繼續等待一定時間(2-4分鍾),即使兩端的應用程序結束。比如在上面的telnet程序client關閉后。使用netstat查看的結果:
C:\>netstat -na | find "172.29.21.25"
TCP 172.29.132.60:2795 172.29.21.25:23 TIME_WAIT
為什么須要這個2MSL呢,
第一,盡管兩方都允許關閉連接了,並且握手的4個報文也都協調和發送完成,按理能夠直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣);可是由於我們必需要假想網絡是不可靠的,你無法保證你最后發送的ACK報文會一定被對方收到,因此對方處於LAST_ACK狀態下的SOCKET可能會由於超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的ACK報文。
第二。報文可能會被混淆。意思是說。其它時候的連接可能會被當作本次的連接。直接引用《The TCP/IP Guide》的說法:The second is to provide a “buffering period” between the end of this connection and any subsequent ones. If not for this period, it is possible that packets from different connections could be mixed, creating confusion.
當某個連接的一端處於TIME_WAIT狀態時。該連接將不能再被使用。其實,對於我們比較有現實意義的是,這個port將不能再被使用。某個port處於TIME_WAIT狀態(其實應該是這個連接)時,這意味着這個TCP連接並沒有斷開(全然斷開),那么。假設你bind這個port,就會失敗。對於server而言,假設server突然crash掉了,那么它將無法在2MSL內又一次啟動,由於bind會失敗。解決問題的一個方法就是設置socket的SO_REUSEADDR選項。這個選項意味着你能夠重用一個地址。
當建立一個TCP連接時。server端會繼續用原有port監聽,同一時候用這個port與client通信。
而client默認情況下會使用一個隨機port與server端的監聽port通信。
有時候,為了server端的安全性,我們須要對client進行驗證,即限定某個IP某個特定port的client。
client能夠使用bind來使用特定的port。
對於server端,當設置了SO_REUSEADDR選項時。它能夠在2MSL內啟動並listen成功。可是對於client。當使用bind並設置SO_REUSEADDR時,假設在2MSL內啟動,盡管bind會成功,可是在windows平台上connect會失敗。而在linux上則不存在這個問題。(我的實驗平台:winxp, ubuntu7.10)
要解決windows平台的這個問題,能夠設置SO_LINGER選項。SO_LINGER選項決定調用close時TCP的行為。SO_LINGER涉及到linger結構體,假設設置結構體中l_onoff為非0。l_linger為0,那么調用close時TCP連接會立馬斷開。TCP不會將發送緩沖中未發送的數據發送,而是馬上發送一個RST報文給對方。這個時候TCP連接(關閉時)就不會進入TIME_WAIT狀態。
如你所見。這樣做盡管攻克了問題。可是並不安全。通過以上方式設置SO_LINGER狀態,等同於設置SO_DONTLINGER狀態。
當TCP連接發生一些物理上的意外情況時,比如網線斷開,linux上的TCP實現會依舊覺得該連接有效,而windows則會在一定時間后返回錯誤信息。
這似乎能夠通過設置SO_KEEPALIVE選項來解決,只是不知道這個選項是否對於全部平台都有效。
3. 為什么不能用兩次握手進行連接?
我們知道。3次握手完畢兩個重要的功能。既要兩方做好發送數據的准備工作(兩方都知道彼此已准備好),也要同意兩方就初始序列號進行協商,這個序列號在握手過程中被發送和確認。
如今把三次握手改成僅須要兩次握手。死鎖是可能發生的。
作為樣例。考慮計算機S和C之間的通信,假定C給S發送一個連接請求分組,S收到了這個分組,並發送了確認應答分組。依照兩次握手的協定,S覺得連接已經成功地建立了,能夠開始發送數據分組。但是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S是否已准備好。不知道S建立什么樣的序列號。C甚至懷疑S是否收到自己的連接請求分組。在這樣的情況下,C覺得連接還未建立成功,將忽略S發來的不論什么數據分組,僅僅等待連接確認應答分組。而S在發出的分組超時后,反復發送相同的分組。這樣就形成了死鎖。
4、為何ISN是隨機的
DoS攻擊
DoS攻擊、DDoS攻擊和DRDoS攻擊相信大家已經早有耳聞了吧!DoS是Denial of Service的簡寫就是拒絕服務,而DDoS就是Distributed Denial of Service的簡寫就是分布式拒絕服務,而DRDoS就是Distributed Reflection Denial of Service的簡寫,這是分布反射式拒絕服務的意思。
只是這3中攻擊方法最厲害的還是DDoS,那個DRDoS攻擊盡管是新近出的一種攻擊方法。但它僅僅是DDoS攻擊的變形,它的唯一不同就是不用占據大量的“肉雞”。
這三種方法都是利用TCP三次握手的漏洞進行攻擊的。所以對它們的防御辦法都是差點兒相同的。
DoS攻擊是最早出現的,它的攻擊方法說白了就是單挑,是比誰的機器性能好、速度快。可是如今的科技飛速發展。一般的站點主機都有十幾台主機,並且各個主機的處理能力、內存大小和網絡速度都有飛速的發展,有的網絡帶寬甚至超過了千兆級別。
這樣我們的一對一單挑式攻擊就沒有什么作用了。搞不好自己的機子就會死掉。
舉個這種攻擊樣例,假如你的機器每秒可以發送10個攻擊用的數據包,而被你攻擊的機器(性能、網絡帶寬都是頂尖的)每秒可以接受並處理100攻擊數據包,那樣的話,你的攻擊就什么用處都沒有了,並且很有死機的可能。要知道。你若是發送這種1Vs1的攻擊,你的機器的CPU占用率是90%以上的,你的機器要是配置不夠高的話,那你就死定了。
只是,科技在發展,黑客的技術也在發展。正所謂道高一尺,魔高一仗。
經過無數次當機,黑客們最終又找到一種新的DoS攻擊方法。這就是DDoS攻擊。它的原理說白了就是群毆。用好多的機器對目標機器一起發動 DoS攻擊。但這不是非常多黑客一起參與的,這樣的攻擊僅僅是由一名黑客來操作的。這名黑客不是擁有非常多機器,他是通過他的機器在網絡上占據非常多的“肉雞”,而且控制這些“肉雞”來發動DDoS攻擊,要不然怎么叫做分布式呢。還是剛才的那個樣例,你的機器每秒能發送10攻擊數據包,而被攻擊的機器每秒可以接受100的數據包。這樣你的攻擊肯定不會起作用。而你再用10台或很多其它的機器來對被攻擊目標的機器進行攻擊的話,嘿嘿!結果我就不說了。
DRDoS分布反射式拒絕服務攻擊這是DDoS攻擊的變形,它與DDoS的不同之處就是DrDoS不須要在攻擊之前占據大量的“肉雞”。它的攻擊原理和Smurf攻擊原理相近,只是DRDoS是能夠在廣域網上進行的。而Smurf攻擊是在局域網進行的。它的作用原理是基於廣播地址與回應請求的。一台計算機向還有一台計算機發送一些特殊的數據包如ping請求時,會接到它的回應;假設向本網絡的廣播地址發送請求包,實際上會到達網絡上全部的計算機,這時就會得到全部計算機的回應。
這些回應是須要被接收的計算機處理的,每處理一個就要占用一份系統資源,假設同一時候接到網絡上全部計算機的回應,接收方的系統是有可能吃不消的。就象遭到了DDoS攻擊一樣。只是是沒有人笨到自己攻擊自己。只是這樣的方法被黑客加以改進就具有非常大的威力了。
黑客向廣播地址發送請求包。全部的計算機得到請求后,卻不會把回應發到黑客那里,而是發到被攻擊主機。這是由於黑客冒充了被攻擊主機。黑客發送請求包所用的軟件是能夠偽造源地址的。接到偽造數據包的主機會依據源地址把回應發出去,這當然就是被攻擊主機的地址。黑客同一時候還會把發送請求包的時間間隔減小,這樣在短時間能發出大量的請求包,使被攻擊主機接到從被欺騙計算機那里傳來的洪水般的回應,就像遭到了DDoS攻擊導致系統崩潰。駭客借助了網絡中全部計算機來攻擊受害者,而不須要事先去占據這些被欺騙的主機,這就是Smurf攻擊。
而DRDoS攻擊正是這個原理,黑客相同利用特殊的發包工具,首先把偽造了源地址的SYN連接請求包發送到那些被欺騙的計算機上,依據TCP三次握手的規則,這些計算機會向源IP發出SYN+ACK或RST包來響應這個請求。同Smurf攻擊一樣。黑客所發送的請求包的源IP地址是被攻擊主機的地址,這樣受欺騙的主機就都會把回應發到被攻擊主機處,造成被攻擊主機忙於處理這些回應而癱瘓。
解釋:
SYN:(Synchronize sequence numbers)用來建立連接,在連接請求中,SYN=1,ACK=0。連接響應時,SYN=1。ACK=1。即。SYN和ACK來區分Connection Request和Connection Accepted。
RST:(Reset the connection)用於復位因某種原因引起出現的錯誤連接,也用來拒絕非法數據和請求。
假設接收到RST位時候,通常發生了某些錯誤。
ACK:(Acknowledgment field significant)置1時表示確認號(Acknowledgment Number)為合法。為0的時候表示數據段不包括確認信息,確認號被忽略。
設我們要准備建立連接。server正處於正常的接聽狀態。
第一步:我們也就是client發送一個帶SYN位的請求,向server表示須要連接。如果請求包的序列號為10,那么則為:SYN=10,ACK=0。然后等待server的回應。
第二步:server接收到這種請求包后,查看是否在接聽的是指定的port,假設不是就發送RST=1回應。拒絕建立連接。假設接收請求包,那么server發送確認回應。SYN為server的一個內碼,假設為100。ACK位則是client的請求序號加1。本例中發送的數據是:SYN=100。ACK=11,用這種數據回應給我們。向我們表示,server連接已經准備好了,等待我們的確認。這時我們接收到回應后。分析得到的信息,准備發送確認連接信號到server。
第三步:我們發送確認建立連接的信息給server。確認信息的SYN位是server發送的ACK位。ACK位是server發送的SYN位加1。
即:SYN=11。ACK=101。
這樣我們的連接就建立起來了。
DDoS到底怎樣攻擊?
眼下最流行也是最好用的攻擊方法就是使用SYN-Flood進行攻擊,SYN-Flood也就是SYN洪水攻擊。SYN-Flood不會完畢TCP三次握手的第三步,也就是不發送確認連接的信息給server。這樣,server無法完畢第三次握手,但server不會馬上放棄。server會不停的重試並等待一定的時間后放棄這個未完畢的連接,這段時間叫做SYN timeout,這段時間大約30秒-2分鍾左右。若是一個用戶在連接時出現故障導致server的一個線程等待1分鍾並非什么大不了的問題。可是若有人用特殊的軟件大量模擬這樣的情況。那后果就可想而知了。
一個server若是處理這些大量的半連接信息而消耗大量的系統資源和網絡帶寬。這樣server就不會再有空余去處理普通用戶的正常請求(由於客戶的正常請求比率非常小)。這樣這個server就無法工作了,這樣的攻擊就叫做:SYN-Flood攻擊。
到眼下為止,進行DDoS攻擊的防御還是比較困難的。首先,這樣的攻擊的特點是它利用了TCP/IP協議的漏洞。除非你不用TCP/IP,才有可能全然抵御住DDoS攻擊。
只是這不等於我們就沒有辦法阻擋DDoS攻擊,我們能夠盡力來降低DDoS的攻擊。
以下就是一些防御方法:
1.確保server的系統文件是最新的版本號。並及時更新系統補丁。
2.關閉不必要的服務。
3.限制同一時候打開的SYN半連接數目。
4.縮短SYN半連接的time out 時間。
5.正確設置防火牆
6.禁止對主機的非開放服務的訪問
7.限制特定IP地址的訪問
8.啟用防火牆的防DDoS的屬性
9.嚴格限制對外開放的server的向外訪問
10.執行port映射程序禍port掃描程序,要認真檢查特權port和非特權port。
11.認真檢查網絡設備和主機/server系統的日志。僅僅要日志出現漏洞或是時間變更,那這台機器就可能遭到了攻擊。
12.限制在防火牆外與網絡文件共享。
這樣會給黑客截取系統文件的機會,主機的信息暴露給黑客,無疑是給了對方入侵的機會。