建立TCP需要三次握手才能建立斤葱,而斷開連接則需要四次握手。整個(gè)過程如下圖所示:
1、TCP連接建立——三次握手
幾個(gè)概念:
【1】seq:序號(hào)矿卑,占4個(gè)字節(jié),范圍[0,4284967296],由于TCP是面向字節(jié)流的沃饶,在一個(gè)1個(gè)TCP連接中傳送字節(jié)流中的每一個(gè)字節(jié)都按照順序編號(hào)母廷,此外序號(hào)是循環(huán)使用的。
【2】ACK: 僅當(dāng)ACK=1時(shí)確認(rèn)字段才有效糊肤,當(dāng)ACK=0時(shí)確認(rèn)字段無(wú)效琴昆,并且TCP規(guī)定,在連接建立后所有的傳送報(bào)文段都必須要把ACK置為1轩褐。
【3】SYN:同步序列號(hào)椎咧,用來(lái)發(fā)起一個(gè)連接。當(dāng)SYN=1而ACK=0時(shí)表明這是一個(gè)請(qǐng)求報(bào)文段把介;若對(duì)方同意連接勤讽,則響應(yīng)報(bào)文中SYN=1,ACK=1拗踢。
【4】FIN :用來(lái)釋放一個(gè)連接脚牍,當(dāng)FIN=1表示此報(bào)文段的發(fā)送方已經(jīng)發(fā)送完畢。并要求釋放鏈接巢墅。
1.1诸狭、3次握手過程
服務(wù)端的TCP進(jìn)程先創(chuàng)建傳輸控制塊TCB券膀,準(zhǔn)備接受客戶端進(jìn)程的連接請(qǐng)求,然后服務(wù)端進(jìn)程處于LISTEN狀態(tài)驯遇,等待客戶端的連接請(qǐng)求芹彬,如有,則作出響應(yīng)叉庐。
1舒帮、客戶端的TCP進(jìn)程也首先創(chuàng)建傳輸控制模塊TCB,然后向服務(wù)端發(fā)出連接請(qǐng)求報(bào)文段陡叠,該報(bào)文段首部中的SYN=1玩郊,ACK=0,同時(shí)選擇一個(gè)初始序號(hào) seq=i枉阵。TCP規(guī)定译红,SYN=1的報(bào)文段不能攜帶數(shù)據(jù),但要消耗掉一個(gè)序號(hào)兴溜。這時(shí)侦厚,TCP客戶進(jìn)程進(jìn)入SYN—SENT(同步已發(fā)送)狀態(tài),這是 TCP連接的第一次握手昵慌。
2假夺、服務(wù)端收到客戶端發(fā)來(lái)的請(qǐng)求報(bào)文后淮蜈,如果同意建立連接斋攀,則向客戶端發(fā)送確認(rèn)。確認(rèn)報(bào)文中的SYN=1梧田,ACK=1淳蔼,確認(rèn)號(hào)ack=i+1,同時(shí)為自己 選擇一個(gè)初始序號(hào)seq=j裁眯。同樣該報(bào)文段也是SYN=1的報(bào)文段鹉梨,不能攜帶數(shù)據(jù),但同樣要消耗掉一個(gè)序號(hào)穿稳。這時(shí)存皂,TCP服務(wù)端進(jìn)入SYN—RCVD(同步收到)狀態(tài),這是TCP連接的第二次握手逢艘。
3旦袋、TCP客戶端進(jìn)程收到服務(wù)端進(jìn)程的確認(rèn)后,還要向服務(wù)端給出確認(rèn)它改。確認(rèn)報(bào)文段的ACK=1疤孕,確認(rèn)號(hào)ack=j+1,而自己的序號(hào)為seq=i+1央拖。 TCP的標(biāo)準(zhǔn)規(guī)定祭阀,ACK報(bào)文段可以攜帶數(shù)據(jù)鹉戚,但如果不攜帶數(shù)據(jù)則不消耗序號(hào),因此专控,如果不攜帶數(shù)據(jù)抹凳,則下一個(gè)報(bào)文段的序號(hào)仍為seq=i+1。這時(shí)伦腐,TCP連接已經(jīng)建立却桶,客戶端進(jìn)入ESTABLISHED(已建立連接)狀態(tài)。這是TCP連接的第三次握手蔗牡,可以看出第三次握手客戶端已經(jīng)可以發(fā)送攜帶數(shù)據(jù)的報(bào)文段了颖系。
當(dāng)服務(wù)端收到確認(rèn)后,也進(jìn)入ESTABLISHED(已建立連接)狀態(tài)辩越。
1.2嘁扼、關(guān)于第三次握手的解釋
前倆比較容易理解,第三次握手看似多余其實(shí)不然黔攒,這主要是為了防止已失效的請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端而產(chǎn)生連接的誤判趁啸。
比如:客戶端發(fā)送了一個(gè)連接請(qǐng)求報(bào)文段A到服務(wù)端,但是在某些網(wǎng)絡(luò)節(jié)點(diǎn)上長(zhǎng)時(shí)間滯留了督惰,而后客戶端又超時(shí)重發(fā)了一個(gè)連接請(qǐng)求報(bào)文段B到該服務(wù)端不傅,而后正常建立連接,數(shù)據(jù)傳輸完畢赏胚,并釋放了連接访娶。但是請(qǐng)求報(bào)文段A延遲了一段時(shí)間后,又到了服務(wù)端觉阅,這本是一個(gè)早已失效的報(bào)文段崖疤,但是服務(wù)端收到后會(huì)誤以為客戶端又發(fā)出了一次連接請(qǐng)求,于是向客戶端發(fā)出確認(rèn)報(bào)文段典勇,并同意建立連接劫哼。那么問題來(lái)了,假如這里沒有三次握手割笙,這時(shí)服務(wù)端只要發(fā)送了確認(rèn)权烧,新的連接就建立了,但由于客戶端沒有發(fā)出建立連接的請(qǐng)求伤溉,因此不會(huì)理會(huì)服務(wù)端的確認(rèn)般码,也不會(huì)向服務(wù)端發(fā)送數(shù)據(jù),而服務(wù)端卻認(rèn)為新的連接已經(jīng)建立了谈火,并在一直等待客戶端發(fā)送數(shù)據(jù)侈询,這樣服務(wù)端就會(huì)一直等待下去,直到超出迸此#活計(jì)數(shù)器的設(shè)定值扔字,而將客戶端判定為出了問題囊嘉,才會(huì)關(guān)閉這個(gè)連接。這樣就浪費(fèi)了很多服務(wù)器的資源革为。而如果采用三次握手扭粱,客戶端就不會(huì)向服務(wù)端發(fā)出確認(rèn),服務(wù)端由于收不到確認(rèn)震檩,就知道客戶端沒有要求建立連接琢蛤,從而不建立該連接。
2抛虏、 缺陷引起的SYN Flood
2.1博其、SYN Flood 攻擊
SYN-Flood攻擊是當(dāng)前網(wǎng)絡(luò)上最為常見的DDoS攻擊,也是最為經(jīng)典的拒絕服務(wù)攻擊迂猴,它就是利用了TCP協(xié)議實(shí)現(xiàn)上的一個(gè)缺陷慕淡,通過向網(wǎng)絡(luò)服務(wù)所在端口發(fā)送大量的偽造源地址的攻擊報(bào)文,就可能造成目標(biāo)服務(wù)器中的半開連接隊(duì)列被占滿沸毁,從而阻止其他合法用戶進(jìn)行訪問峰髓。這種攻擊早在1996年就被發(fā)現(xiàn),但至今仍然顯示出強(qiáng)大的生命力息尺。很多操作系統(tǒng)携兵,甚至防火墻、路由器都無(wú)法有效地防御這種攻擊搂誉,而且由于它可以方便地偽造源地址徐紧,追查起來(lái)非常困難。它的數(shù)據(jù)包特征通常是勒葱,源發(fā)送了大量的SYN包浪汪,并且缺少三次握手的最后一步握手ACK回復(fù)巴柿。
原理:攻擊者首先偽造地址對(duì)服務(wù)器發(fā)起SYN請(qǐng)求凛虽,服務(wù)器回應(yīng)(SYN+ACK)包,而真實(shí)的IP會(huì)認(rèn)為广恢,我沒有發(fā)送請(qǐng)求凯旋,不作回應(yīng)。服務(wù)器沒有收到回應(yīng)钉迷,這樣的話至非,服務(wù)器不知 道(SYN+ACK)是否發(fā)送成功,默認(rèn)情況下會(huì)重試5次(tcp_syn_retries)糠聪。這樣的話荒椭,對(duì)于服務(wù)器的內(nèi)存,帶寬都有很大的消耗舰蟆。攻擊者如果處于公網(wǎng)趣惠,可以偽造IP的話狸棍,對(duì)于服務(wù)器就很難根據(jù)IP來(lái)判斷攻擊者,給防護(hù)帶來(lái)很大的困難味悄。
2.2草戈、SYN Flood 防護(hù)措施
2.2.1. 無(wú)效連接監(jiān)視釋放
這種方法不停的監(jiān)視系統(tǒng)中半開連接和不活動(dòng)連接,當(dāng)達(dá)到一定閾值時(shí)拆除這些連接侍瑟,釋放系統(tǒng)資源唐片。這種絕對(duì)公平的方法往往也會(huì)將正常的連接的請(qǐng)求也會(huì)被釋放掉,“傷敵一千涨颜,自損八百”费韭。
2.2.2. 延緩TCB分配方法
SYN Flood關(guān)鍵是利用了,SYN數(shù)據(jù)報(bào)文一到庭瑰,系統(tǒng)立即分配TCB資源揽思,從而占用了系統(tǒng)資源,因此有倆種技術(shù)來(lái)解決這一問題见擦。
Syn Cache技術(shù)
這種技術(shù)在收到SYN時(shí)不急著去分配TCB钉汗,而是先回應(yīng)一個(gè)ACK報(bào)文,并在一個(gè)專用的HASH表中(Cache)中保存這種半開連接鲤屡,直到收到正確的ACK報(bào)文再去分配TCB损痰。
Syn Cookie技術(shù)
Syn Cookie技術(shù)則完全不使用任何存儲(chǔ)資源,它使用一種特殊的算法生成Sequence Number酒来,這種算法考慮到了對(duì)方的IP卢未、端口、己方IP堰汉、端口的固定信息辽社,以及對(duì)方無(wú)法知道而己方比較固定的一些信息,如MSS翘鸭、時(shí)間等滴铅,在收到對(duì)方的ACK報(bào)文后,重新計(jì)算一遍就乓,看其是否與對(duì)方回應(yīng)報(bào)文中的(Sequence Number-1)相同汉匙,從而決定是否分配TCB資源。
2.2.3. 使用SYN Proxy防火墻
原理:對(duì)試圖穿越的SYN請(qǐng)求進(jìn)行驗(yàn)證之后才放行生蚁。
3噩翠、經(jīng)歷狀態(tài)
3.1 Client端所經(jīng)歷的狀態(tài)
3.2 Server端所經(jīng)歷的狀態(tài)
4、常見問題:
4.1邦投、為什么連接的時(shí)候是三次握手伤锚,關(guān)閉的時(shí)候卻是四次握手?
答:因?yàn)楫?dāng)Server端收到Client端的SYN連接請(qǐng)求報(bào)文后志衣,可以直接發(fā)送SYN+ACK報(bào)文屯援。其中ACK報(bào)文是用來(lái)應(yīng)答的剂娄,SYN報(bào)文是用來(lái)同步的。但是關(guān)閉連接時(shí)玄呛,當(dāng)Server端收到FIN報(bào)文時(shí)阅懦,很可能并不會(huì)立即關(guān)閉SOCKET,所以只能先回復(fù)一個(gè)ACK報(bào)文徘铝,告訴Client端耳胎,”你發(fā)的FIN報(bào)文我收到了”。只有等到我Server端所有的報(bào)文都發(fā)送完了惕它,我才能發(fā)送FIN報(bào)文怕午,因此不能一起發(fā)送。故需要四步握手淹魄。
4.2郁惜、為什么存在TIME_WAIT狀態(tài)?
答:1甲锡、可靠的終止TCP連接
第一個(gè)原因很好理解兆蕉。假設(shè)用于確認(rèn)服務(wù)端FIN報(bào)文段的客戶端ACK報(bào)文段丟失,那么服務(wù)器將重發(fā)FIN報(bào)文段缤沦。因此客戶端應(yīng)停留在某個(gè)狀態(tài)以處理重復(fù)收到的報(bào)文段(即向服務(wù)器重發(fā)ACK報(bào)文段)虎韵。否則,客戶端將以復(fù)位報(bào)文段來(lái)回應(yīng)服務(wù)器缸废,服務(wù)器則認(rèn)為這是一個(gè)錯(cuò)誤包蓝,因?yàn)樗谕氖且粋€(gè)ACK確認(rèn)報(bào)文段。
2企量、保證讓遲來(lái)的TCP報(bào)文段有足夠的時(shí)間被識(shí)別并丟棄
4.3测萎、TCP第三次握手失敗怎么辦?
在此届巩,將《TCP/IP協(xié)議族》中每一個(gè)狀態(tài)的轉(zhuǎn)換偽代碼整理下:
可以看出當(dāng)失敗時(shí)服務(wù)器并不會(huì)重傳ack報(bào)文硅瞧,而是直接發(fā)送RTS報(bào)文段,進(jìn)入CLOSED狀態(tài)姆泻。這樣做的目的是為了防止SYN洪泛攻擊零酪。
4.4、為什么不能用兩次握手進(jìn)行連接
我們知道拇勃,3次握手完成兩個(gè)重要的功能,既要雙方做好發(fā)送數(shù)據(jù)的準(zhǔn)備工作(雙方都知道彼此已準(zhǔn)備好)孝凌,也要允許雙方就初始序列號(hào)進(jìn)行協(xié)商方咆,這個(gè)序列號(hào)在握手過程中被發(fā)送和確認(rèn)。現(xiàn)在把三次握手改成僅需要兩次握手蟀架,死鎖是可能發(fā)生的瓣赂。作為例子榆骚,考慮計(jì)算機(jī)S和C之間的通信,假定C給S發(fā)送一個(gè)連接請(qǐng)求分組煌集,S收到了這個(gè)分組妓肢,并發(fā)送了確認(rèn)應(yīng)答分組。按照兩次握手的協(xié)定苫纤,S認(rèn)為連接已經(jīng)成功地建立了碉钠,可以開始發(fā)送數(shù)據(jù)分組【砭校可是喊废,C在S的應(yīng)答分組在傳輸中被丟失的情況下,將不知道S是否已準(zhǔn)備好栗弟,不知道S建立什么樣的序列號(hào)污筷,C甚至懷疑S是否收到自己的連接請(qǐng)求分組。在這種情況下乍赫,C認(rèn)為連接還未建立成功瓣蛀,將忽略S發(fā)來(lái)的任何數(shù)據(jù)分組,只等待連接確認(rèn)應(yīng)答分組雷厂。而S在發(fā)出的分組超時(shí)后揪惦,重復(fù)發(fā)送同樣的分組。這樣就形成了死鎖罗侯。
5器腋、小知識(shí)
a.默認(rèn)情況下(不改變socket選項(xiàng)),當(dāng)你調(diào)用close(or closeSocket钩杰,以下說close不再重復(fù))時(shí)纫塌,如果發(fā)送緩沖中還有數(shù)據(jù),TCP會(huì)繼續(xù)把數(shù)據(jù)發(fā)送完讲弄。
b.發(fā)送了FIN只是表示這端不能繼續(xù)發(fā)送數(shù)據(jù)(應(yīng)用層不能再調(diào)用send發(fā)送)措左,但是還可以接收數(shù)據(jù)。
c.應(yīng)用層如何知道對(duì)端關(guān)閉避除?通常怎披,在最簡(jiǎn)單的阻塞模型中,當(dāng)你調(diào)用recv時(shí)瓶摆,如果返回0凉逛,則表示對(duì)端關(guān)閉。在這個(gè)時(shí)候通常的做法就是也調(diào)用close群井,那么TCP層就發(fā)送FIN状飞,繼續(xù)完成四次握手。如果你不調(diào)用close,那么對(duì)端就會(huì)處于FIN_WAIT_2狀態(tài)诬辈,而本端則會(huì)處于CLOSE_WAIT狀態(tài)酵使。
d.在很多時(shí)候,TCP連接的斷開都會(huì)由TCP層自動(dòng)進(jìn)行焙糟,例如你CTRL+C終止你的程序口渔,TCP連接依然會(huì)正常關(guān)閉。
6穿撮、TIME_WAIT狀態(tài)
a.從以上TCP連接關(guān)閉的狀態(tài)轉(zhuǎn)換圖可以看出缺脉,主動(dòng)關(guān)閉的一方在發(fā)送完對(duì)對(duì)方FIN報(bào)文的確認(rèn)(ACK)報(bào)文后,會(huì)進(jìn)入TIME_WAIT狀態(tài)混巧。TIME_WAIT狀態(tài)也稱為2MSL狀態(tài)枪向。
b.什么是2MSL?MSL即Maximum Segment Lifetime咧党,也就是報(bào)文最大生存時(shí)間秘蛔,引用《TCP/IP詳解》中的話:“它(MSL)是任何報(bào)文段被丟棄前在網(wǎng)絡(luò)內(nèi)的最長(zhǎng)時(shí)間“猓”那么深员,2MSL也就是這個(gè)時(shí)間的2倍。其實(shí)我覺得沒必要把這個(gè)MSL的確切含義搞明白蛙埂,你所需要明白的是倦畅,當(dāng)TCP連接完成四個(gè)報(bào)文段的交換時(shí),主動(dòng)關(guān)閉的一方將繼續(xù)等待一定時(shí)間(2-4分鐘)绣的,即使兩端的應(yīng)用程序結(jié)束叠赐。
c.為什么需要2MSL?根據(jù)《TCP/IP詳解》和《The TCP/IP Guide》中的說法屡江,有兩個(gè)原因:
其一芭概,保證發(fā)送的ACK會(huì)成功發(fā)送到對(duì)方,如何保證惩嘉?我覺得可能是通過超時(shí)計(jì)時(shí)器發(fā)送罢洲。這個(gè)就很難用代碼演示了。
其二文黎,報(bào)文可能會(huì)被混淆惹苗,意思是說,其他時(shí)候的連接可能會(huì)被當(dāng)作本次的連接耸峭。直接引用《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.
d.TIME_WAIT狀態(tài)所帶來(lái)的影響:
當(dāng)某個(gè)連接的一端處于TIME_WAIT狀態(tài)時(shí)桩蓉,該連接將不能再被使用。事實(shí)上抓艳,對(duì)于我們比較有現(xiàn)實(shí)意義的是触机,這個(gè)端口將不能再被使用帚戳。某個(gè)端口處于TIME_WAIT狀態(tài)(其實(shí)應(yīng)該是這個(gè)連接)時(shí)玷或,這意味著這個(gè)TCP連接并沒有斷開(完全斷開)儡首,那么,如果你bind這個(gè)端口偏友,就會(huì)失敗蔬胯。對(duì)于服務(wù)器而言,如果服務(wù)器突然crash掉了位他,那么它將無(wú)法再2MSL內(nèi)重新啟動(dòng)氛濒,因?yàn)閎ind會(huì)失敗。解決這個(gè)問題的一個(gè)方法就是設(shè)置socket的SO_REUSEADDR選項(xiàng)鹅髓。這個(gè)選項(xiàng)意味著你可以重用一個(gè)地址舞竿。
7、各種狀態(tài)解析
FIN_WAIT_1: FIN_WAIT_1和FIN_WAIT_2狀態(tài)的真正含義都是表示等待對(duì)方的FIN報(bào)文窿冯。而這兩種狀態(tài)的區(qū)別是: FIN_WAIT_1狀態(tài)實(shí)際上是當(dāng)SOCKET在ESTABLISHED狀態(tài)時(shí)骗奖,它想主動(dòng)關(guān)閉連接,向?qū)Ψ桨l(fā)送了FIN報(bào)文醒串,此時(shí)該SOCKET即進(jìn)入到FIN_WAIT_1狀態(tài)执桌。而當(dāng)對(duì)方回應(yīng)ACK報(bào)文后,則進(jìn)入到FIN_WAIT_2狀態(tài)芜赌,當(dāng)然在實(shí)際的正常情況下仰挣,無(wú)論對(duì)方何種情況下,都應(yīng)該馬上回應(yīng)ACK報(bào)文缠沈,所以FIN_WAIT_1狀態(tài)一般是比較難見到的膘壶,而FIN_WAIT_2狀態(tài)還有時(shí)常常可以用netstat看到洲愤。(主動(dòng)方)
FIN_WAIT_2:上面已經(jīng)詳細(xì)解釋了這種狀態(tài)颓芭,實(shí)際上FIN_WAIT_2狀態(tài)下的SOCKET,表示半連接禽篱,也即有一方要求close連接畜伐,但另外一方告訴對(duì)方,我暫時(shí)還有點(diǎn)數(shù)據(jù)需要傳送給你(ACK信息)躺率,稍后再關(guān)閉連接玛界。(主動(dòng)方)
TIME_WAIT: 表示收到了對(duì)方的FIN報(bào)文,并發(fā)送出了ACK報(bào)文悼吱,就等2MSL后即可回到CLOSED可用狀態(tài)了慎框。如果FIN_WAIT_1狀態(tài)下,收到了對(duì)方同時(shí)帶FIN標(biāo)志和ACK標(biāo)志的報(bào)文時(shí)后添,可以直接進(jìn)入到TIME_WAIT狀態(tài)笨枯,而無(wú)須經(jīng)過FIN_WAIT_2狀態(tài)。(主動(dòng)方)
CLOSING(比較少見): 這種狀態(tài)比較特殊,實(shí)際情況中應(yīng)該是很少見馅精,屬于一種比較罕見的例外狀態(tài)严嗜。正常情況下,當(dāng)你發(fā)送FIN報(bào)文后洲敢,按理來(lái)說是應(yīng)該先收到(或同時(shí)收到)對(duì)方的 ACK報(bào)文览祖,再收到對(duì)方的FIN報(bào)文舰攒。但是CLOSING狀態(tài)表示你發(fā)送FIN報(bào)文后,并沒有收到對(duì)方的ACK報(bào)文,反而卻也收到了對(duì)方的FIN報(bào)文耐薯。什么情況下會(huì)出現(xiàn)此種情況呢偎巢?其實(shí)細(xì)想一下血淌,也不難得出結(jié)論:那就是如果雙方幾乎在同時(shí)close一個(gè)SOCKET的話注祖,那么就出現(xiàn)了雙方同時(shí)發(fā)送FIN報(bào)文的情況,也即會(huì)出現(xiàn)CLOSING狀態(tài)询一,表示雙方都正在關(guān)閉SOCKET連接隐孽。
CLOSE_WAIT: 這種狀態(tài)的含義其實(shí)是表示在等待關(guān)閉。怎么理解呢家凯?當(dāng)對(duì)方close一個(gè)SOCKET后發(fā)送FIN報(bào)文給自己缓醋,你系統(tǒng)毫無(wú)疑問地會(huì)回應(yīng)一個(gè)ACK報(bào)文給對(duì)方,此時(shí)則進(jìn)入到CLOSE_WAIT狀態(tài)绊诲。接下來(lái)呢送粱,實(shí)際上你真正需要考慮的事情是查看你是否還有數(shù)據(jù)發(fā)送給對(duì)方,如果沒有的話掂之,那么你也就可以close這個(gè)SOCKET抗俄,發(fā)送FIN報(bào)文給對(duì)方,也即關(guān)閉連接世舰。所以你在CLOSE_WAIT狀態(tài)下动雹,需要完成的事情是等待你去關(guān)閉連接。(被動(dòng)方)
LAST_ACK: 這個(gè)狀態(tài)還是比較容易好理解的跟压,它是被動(dòng)關(guān)閉一方在發(fā)送FIN報(bào)文后胰蝠,最后等待對(duì)方的ACK報(bào)文。當(dāng)收到ACK報(bào)文后震蒋,也即可以進(jìn)入到CLOSED可用狀態(tài)了茸塞。(被動(dòng)方)
CLOSED: 表示連接中斷。