一、項(xiàng)目簡(jiǎn)介
目的:設(shè)有一臺(tái)PC機(jī)(Host1),一臺(tái)Web服務(wù)器(Host2)提供簡(jiǎn)單的靜態(tài)網(wǎng)頁(yè)訪問(wèn)服務(wù)。通過(guò)RYU控制網(wǎng)絡(luò)流,限制PC訪問(wèn)服務(wù)器的頻率,如兩次訪問(wèn)的間隔不能低于5秒。應(yīng)用場(chǎng)景:
①為 付費(fèi)用戶(hù) 和 免費(fèi)用戶(hù) 提供差異化服務(wù)
②小型站點(diǎn)、個(gè)人站點(diǎn)、未做優(yōu)化站點(diǎn)的負(fù)載緩解
③……在詳細(xì)了解TCP三次握手、四次揮手、RST強(qiáng)制重置,以及HTTP包交互全程的基礎(chǔ)上,本項(xiàng)目達(dá)成了以下特色:限制訪問(wèn)時(shí),返回給PC友好的WEB頁(yè)面提示,而不是僅僅通過(guò)流表把包丟棄,以及由此導(dǎo)致的PC用戶(hù)瀏覽器持續(xù)等待、多次TCP重傳、多次HTTP嘗試。
二、關(guān)鍵技術(shù)分析
本項(xiàng)目中,由于TCP重傳機(jī)制的特殊性,控制器不對(duì)握手和揮手等TCP控制交互階段進(jìn)行控制,只對(duì)HTTP報(bào)文進(jìn)行控制。控制器偽裝了服務(wù)器的角色,好似第三方劫持會(huì)話(huà)。對(duì)于80目的端口的TCP控制交互報(bào)文,控制器通過(guò)packet-out讓其順利轉(zhuǎn)發(fā)。當(dāng)正常訪問(wèn)時(shí),控制器通過(guò)packet-out讓HTTP請(qǐng)求順利轉(zhuǎn)發(fā),同時(shí)下一條從服務(wù)器到PC的反向流表;當(dāng)限制訪問(wèn)時(shí),控制器通過(guò):
①提取計(jì)算Seq、提取計(jì)算Ack、設(shè)置bits協(xié)議標(biāo)志位、設(shè)置window_size來(lái)構(gòu)造一個(gè)TCP報(bào)文;
②同時(shí)依照HTTP協(xié)議構(gòu)造一個(gè)web頁(yè)面數(shù)據(jù)包(訪問(wèn)限制提示頁(yè)面)
③構(gòu)造Ip包
④構(gòu)造Ethernet幀然后按照HTTP -> TCP -> IP -> Ethernet 的順序?qū)訉臃庋b,將其發(fā)回給PC,PC即可顯示限制訪問(wèn)的提示頁(yè)面。一般情況下還不算完,此時(shí)雖然PC瀏覽器退出了等待狀態(tài),但是PC、服務(wù)器雙方的TCP連接仍然保持,仍在占用資源。由此,我通過(guò)巧妙構(gòu)造TCP協(xié)議字段和HTTP協(xié)議字段,利用TCP揮手階段的RST機(jī)制,讓PC端向服務(wù)器主動(dòng)發(fā)起RST報(bào)文,隨后PC端和服務(wù)器會(huì)各自強(qiáng)制斷開(kāi)連接。到此,一次優(yōu)雅的訪問(wèn)限制圓滿(mǎn)結(jié)束,PC、服務(wù)器的資源都不被持續(xù)占用,用戶(hù)也不用茫然地等待,同時(shí)能得到友好的提示!
具體細(xì)節(jié),詳見(jiàn)下方的各項(xiàng)解析,以及下文的實(shí)驗(yàn)演示中的截圖。(可放大觀看)(1)TCP的有趣細(xì)節(jié)
TCP這個(gè)孩子非常執(zhí)著,無(wú)論是握手階段、數(shù)據(jù)通信階段,還是揮手階段,只要沒(méi)有收到ACK,就會(huì)以“翻番”的時(shí)間間隔去重發(fā)數(shù)據(jù)包,1、2、4、8、16、32秒……。開(kāi)發(fā)過(guò)程中,我觀察到如果單純以丟包作為限制手段,TCP會(huì)持續(xù)握手握上五分鐘之久!并且會(huì)持續(xù)下去。平日里我們看到的TCP報(bào)告連接失敗,可能是對(duì)方積極地使用RST給了我們失敗的指示。因此,如果單純地丟包,會(huì)導(dǎo)致PC瀏覽器持續(xù)處于等待網(wǎng)頁(yè)的狀態(tài),即使我們?cè)O(shè)置限制間隔為一分鐘,但其實(shí)一分鐘過(guò)后自動(dòng)打開(kāi)的網(wǎng)頁(yè),是屬于“同一次”訪問(wèn)。RST協(xié)議字段在我這個(gè)項(xiàng)目中,可謂是一個(gè)神器,它是一個(gè)TCP協(xié)議字段,會(huì)讓通信雙方各自強(qiáng)制關(guān)閉連接。RST常出現(xiàn)在連接本身出現(xiàn)嚴(yán)重差錯(cuò)、通信對(duì)端端口不可達(dá)、在已關(guān)閉的socket上收到數(shù)據(jù)等情況。在這里,我們利用了“連接本身出現(xiàn)嚴(yán)重差錯(cuò)”這一條:在HTTP響應(yīng)數(shù)據(jù)包中,我們給TCP設(shè)置一個(gè)錯(cuò)誤的Ack和一個(gè)正確的Seq,使得PC發(fā)起HTTP Request的超時(shí)重傳,此時(shí)RYU會(huì)再次響應(yīng)帶有錯(cuò)誤Ack卻有正確Seq的響應(yīng),這就導(dǎo)致了PC端發(fā)現(xiàn)連接出現(xiàn)嚴(yán)重差錯(cuò),中斷連接!經(jīng)我分析,由于RYU第一次的響應(yīng)是正常的通信過(guò)程,所以PC重傳的HTTP Request中,TCP Ack已經(jīng)累積遞增,然后RYU的第二次響應(yīng)中,有正確的Seq,說(shuō)明已經(jīng)是收到了重傳的HTTP Request,按理說(shuō)它的TCP Ack應(yīng)該累積遞增,但是卻沒(méi)有,而仍然是我們?cè)O(shè)定的錯(cuò)誤Ack。
這就產(chǎn)生了矛盾!因此PC端就主動(dòng)發(fā)起了RST連接中斷,特插圖如下:
(2)最精簡(jiǎn)的HTTP響應(yīng)數(shù)據(jù)
之前我在C++下開(kāi)發(fā)過(guò)一些Socket通信程序,根據(jù)我的積累,僅包含必要信息的最精簡(jiǎn)HTTP需要有如下協(xié)議信息,各信息之間用“ ”分隔,協(xié)議頭與數(shù)據(jù)之間用 分隔:①協(xié)議版本、響應(yīng)狀態(tài)碼:HTTP/1.1 200 OK
②數(shù)據(jù)段長(zhǎng)度:Content-Length: 257
③數(shù)據(jù)內(nèi)容類(lèi)型、編碼:Content-Type: text/html; charset=utf-8
三、項(xiàng)目演示
(1)組網(wǎng)
Mininet:
RYU:
(2)軟件準(zhǔn)備
【 Mininet 】角色:h1 客戶(hù)端(wget、Firefox)、h2服務(wù)器(Python SimpleHTTPServer)
【W(wǎng)ireshark】啟動(dòng)兩個(gè),分別監(jiān)控:s1-eth1(h1)、s1-eth2(h2),并且僅顯示TCP包
[page](3)訪問(wèn)過(guò)程
由于Firefox在發(fā)起HTTP請(qǐng)求時(shí)會(huì)同時(shí)建立兩個(gè)TCP連接,所以我們先以wget來(lái)演示一次HTTP請(qǐng)求的最典型的收發(fā)包情況,再以Firefox來(lái)直觀演示W(wǎng)eb頁(yè)面效果。1. wget 正常訪問(wèn)
2. wget 限制訪問(wèn)
3. Firefox 正常訪問(wèn)
4. Firefox 限制訪問(wèn)
5. Firefox 正常訪問(wèn)、限制訪問(wèn) Web 頁(yè)面
[page]四、核心代碼展示
(1)代碼結(jié)構(gòu)
(2)構(gòu)造HTTP限制訪問(wèn)Web包
HTTP -> TCP -> IP -> Ethernet
(3)控制器偽裝發(fā)包
(4)限制間隔計(jì)時(shí)
19行:Self.oldT 在__init__中初始化86行:檢查是否需要限制訪問(wèn),此處設(shè)定訪問(wèn)間隔為5秒
【同時(shí)對(duì)網(wǎng)絡(luò)延遲造成的正常TCP重傳,設(shè)定0.3秒的容許】205行:刷新最后一次訪問(wèn)成功的時(shí)間time.time() 用于獲取系統(tǒng)當(dāng)前時(shí)間
五、項(xiàng)目心得
這個(gè)項(xiàng)目的開(kāi)發(fā)真是歷經(jīng)坎坷,我也在其中悟到了很多課堂上沒(méi)有涉及到的知識(shí)。通過(guò)多網(wǎng)口同時(shí)抓包,然后加以細(xì)致的分析,從TCP的三次握手、四次揮手,到TCP的Seq、Ack在傳信令、數(shù)據(jù)時(shí)的累加機(jī)制,再到TCP的bits協(xié)議標(biāo)志位,以及RST 這個(gè)連接守護(hù)者。一星一點(diǎn)地細(xì)看發(fā)包流程,然后在腦海中翻閱之前積累的TCP反饋重傳、累積確認(rèn)、滑動(dòng)窗口等機(jī)制,對(duì)流程進(jìn)行細(xì)致的研究。雖然過(guò)程中遇到了一些難以理解的收發(fā)流程,但是我始終相信TCP這個(gè)東西在互聯(lián)網(wǎng)上跑了這么多年,不會(huì)說(shuō)在通信交互的機(jī)制上有什么BUG,一定是流程中出了什么樣的意外情況導(dǎo)致了異常的收發(fā),甚至連接的RST中斷。 細(xì)粒度地分析實(shí)際通信場(chǎng)景、bits協(xié)議標(biāo)志位、Seq、Ack,一定能找到問(wèn)題癥結(jié)所在!通過(guò)這個(gè)小項(xiàng)目,我算是對(duì)TCP的理解更加細(xì)致、深入、實(shí)際了!對(duì)于上方PC端主動(dòng)發(fā)起RST的原因,只是我利用已有的知識(shí)積累,進(jìn)行分析和一點(diǎn)點(diǎn)猜想的結(jié)果,還希望老師、學(xué)長(zhǎng)學(xué)姐、同學(xué)們能給予我一些指導(dǎo),非常感謝!這學(xué)期的SDN課程行至尾聲,還真的是意猶未盡,在北郵能聽(tīng)到這么有前瞻性的課程,真是一大幸事,我想,我們也只有始終站在潮流前端,才能保持優(yōu)秀,引領(lǐng)未來(lái)!