您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Linux Tcp內(nèi)核協(xié)議棧Packet Drill基本原理是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
Linux TCP 內(nèi)核協(xié)議棧是一個非常復(fù)雜的實現(xiàn), 不但沉淀了過去20多年的設(shè)計與實現(xiàn),同時還在不停的更新。相關(guān)的RFC與優(yōu)化工作一直還在進行中。如何研究和學(xué)習(xí)Linux TCP內(nèi)核協(xié)議棧這樣一塊硬骨頭就成了一大難題。
當(dāng)然最重要也是最基本的還是要閱讀相關(guān)的RFC和內(nèi)核中的代碼實現(xiàn)。這個是最最基本的要求。想要馴服TCP 內(nèi)核協(xié)議棧這樣的monster 僅僅瀏覽和靜態(tài)分析代碼是完全不夠的。因為整個實現(xiàn)中充斥著各種邊界條件和異常的處理(這里有部分原因是因為TCP協(xié)議本身設(shè)計造成的),尤其是TCP是有狀態(tài)的協(xié)議, 很多邊界條件的觸發(fā)需要一系列的報文來構(gòu)成,同時還需要滿足時延等其它條件。
幸運的是Google在2013年替大家解決了這個難題。Google 在2013 年發(fā)布了TCP 內(nèi)核協(xié)議棧 測試工具 Packet Drill。這個工具是名副其實,大大的簡化了學(xué)習(xí)和測試TCP 內(nèi)核協(xié)議棧的難度?;究梢噪S心所欲的觸摸TCP 內(nèi)核協(xié)議棧的每個細(xì)節(jié)。Google的這件工具真是造福了人類。
使用Packet Drill, 用戶可以隨心所欲的構(gòu)造報文序列,可以指定所有的報文格式(類似tcpdump語法)然后通過TUN接口和目標(biāo)系統(tǒng)的TCP 內(nèi)核協(xié)議棧來通信, 并對接收到的來自目標(biāo)系統(tǒng)TCP 內(nèi)核協(xié)議棧 的報文進行校驗,來確定是否通過測試。再進一步結(jié)合wireshark+Packet Drill 用戶可以獲得最直觀而且具體的體驗。每個報文的每個細(xì)節(jié)都在掌控之中,溜得飛起,人生瞬間到達了巔峰。
Packet Drill 基本原理
TUN 網(wǎng)絡(luò)設(shè)備
TUN 是Linux 下的虛擬網(wǎng)絡(luò)設(shè)備, 可以直通到網(wǎng)絡(luò)層。使得應(yīng)用程序可以直接收發(fā)IP報文。
Packet Drill 腳本解析/執(zhí)行引擎
首先 Packet Drill 腳本必須要被解析和分解為 通過傳統(tǒng)socket 接口收發(fā)報文的部分和通過TUN接口收發(fā)報文的部分
在傳統(tǒng)socket 接口執(zhí)行對應(yīng)的動作。
在TUN接口執(zhí)行對應(yīng)的動作,并對收到的數(shù)據(jù)進行比對。
在本文中 socket 接口主要扮演的是 server side的角色。TUN接口扮演的是client的角色。因而我們可以通過TUN接口完全掌控我們將要發(fā)送出去的IP報文,并受到TCP協(xié)議棧的反饋。并和預(yù)設(shè)數(shù)據(jù)進行比對。
Packet Drill 語法簡介
相對時間順序
Packet Drill 每一個事件(發(fā)送/接收/發(fā)起系統(tǒng)調(diào)用)都有相對前后事件的時間便宜。一般使用+number 來表達。例如+0 就是在之前的事件結(jié)束之后立即發(fā)起。+.1 表示為在之前時間結(jié)束0.1秒之后發(fā)起。以此類推
系統(tǒng)調(diào)用
Packet Drill 中集成了系統(tǒng)調(diào)用, 可以通過腳本來完成例如 socket,bind, read,write,getsocketoption 等等系統(tǒng)調(diào)用。熟悉socket 編程的同學(xué)很容易理解并使用。
報文的發(fā)送與接受
通過內(nèi)核棧側(cè)。可以通過調(diào)用系統(tǒng)調(diào)用 read/write 來完成報文的發(fā)送與接受。但是因為tcp是有狀態(tài)的協(xié)議棧,所以內(nèi)核棧本身也會根據(jù)協(xié)議棧所處狀態(tài)發(fā)送報文(例如ACK/SACK).
TUN 設(shè)備側(cè). Packet Drill 使用 < 表示發(fā)送報文, 使用 > 表示接收報文。
報文的格式描述
報文格式的表達比較類似tcpdump。例如 S 0:0(0) win 1000表示syn包 win大小為1000, 同時tcp的選項 mss (max segment size)為1000.
下面我們通過2個例子來進一步學(xué)習(xí)
Handshake and Teardown
我們通過packet drill的腳本 復(fù)習(xí)一下這個經(jīng)典的流程。
首選來回顧一下 TCP協(xié)議標(biāo)準(zhǔn)的 handshake 和 treardown 流程
接下來我們結(jié)合packet drill 的腳本來重現(xiàn) 整個過程
//創(chuàng)建server側(cè)socket, server側(cè)socket 將通過內(nèi)核協(xié)議棧來通信 // 注意這里使用的是傳統(tǒng)的系統(tǒng)調(diào)用 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 //設(shè)置對應(yīng)的socket options // 注意這里使用的是傳統(tǒng)的系統(tǒng)調(diào)用 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 //bind socket // 注意這里使用的是傳統(tǒng)的系統(tǒng)調(diào)用 +0 bind(3, ..., ...) = 0 //listen on the socket // 注意這里使用的是傳統(tǒng)的系統(tǒng)調(diào)用 +0 listen(3, 1) = 0 // client側(cè)(TUN)發(fā)送 syn 握手的第一個報文 // 注意這里的語法 syn seq都是相對的,從0開始。 +0 < S 0:0(0) win 1000 <mss 1000> // client側(cè)(TUN)期望收到的報文格式 syn+ack 且 ack.no=ISN(c)+1 // 參考標(biāo)準(zhǔn)流程圖 最后的<...> 表示任何tcp option都可以 // 這里是握手的第二步 +0 > S. 0:0(0) ack 1 <...> // client側(cè)(TUN)發(fā)送 ack 報文 seq = ISN(c)+1, ack = ISN(c) +1 // 這里是握手的第三步 +.1 < . 1:1(0) ack 1 win 1000 //握手成功,server側(cè) socket 返回 established socket //這時通過accept 系統(tǒng)調(diào)用拿到這個stream 的socket +0 accept(3, ..., ...) = 4 //server側(cè)向stream 寫入 10 bytes //通過系統(tǒng)調(diào)用來完成寫操作 +0 write(4, ..., 10)=10 //client側(cè)期望收到receive 10 bytes +0 > P. 1:11(10) ack 1 //client側(cè)應(yīng)答 ack 表示接收到 10 bytes +.0 < . 1:1(0) ack 11 win 1000 // client 關(guān)閉連接 發(fā)送fin包 +0 < F. 1:1(0) ack 11 win 4000 // client側(cè)期望接收到server端的對于fin的ack報文 // 這里由內(nèi)核協(xié)議棧發(fā)回。ack = server seq +1, seq = server ack // 參考標(biāo)準(zhǔn)流程圖 +.005 > . 11:11(0) ack 2 // server 關(guān)閉連接 通過系統(tǒng)調(diào)用完成 +0 close(4) = 0 // client期望接收到的fin包格式 +0 > F. 11:11(0) ack 2 // client 發(fā)送server端fin包的應(yīng)答ack包 +0 < . 2:2(0) ack 12 win 4000
至此, 我們純手動的完成了全部的發(fā)起和關(guān)閉連接的過程。然后我們用wireshark 來驗證一下
通過結(jié)合packetdrill與wireshark 使得每一步都在我們的掌控之中,
SACK
我們將使用packet drill 來探索一些更為復(fù)雜的案例。例如內(nèi)核協(xié)議棧對于 SACK中各種排列組合的響應(yīng)。
SACK 是TCP協(xié)議中優(yōu)化重傳機制的一個重要選項(該選項一般都在報頭的options部分)。
最原始的情況下如果發(fā)送方對于 每一個報文接受到ACK之后再發(fā)送下一個報文, 效率將是極為低下的。引入滑動窗口之后允許發(fā)送方一次發(fā)送多個報文 但是如果中間某個報文丟失(沒有收到其對應(yīng)的ACK)那么從那個報文開始,其后所有發(fā)送過的報文都要被重新發(fā)送一次。造成了極大的浪費。
SACK 是一種優(yōu)化措施, 用來避免不必要的重發(fā), 告知發(fā)送方那些報文已經(jīng)收到,不用再重發(fā)。tcp 的選項中允許帶有最多3個SACK的options。也就是三個已經(jīng)收到了得報文區(qū)間信息。說了這么多, 還是有一些抽象, 我們來看一個具體的示例。
示例說明
在下面的這個例子中, 我們需要發(fā)送報文的順序是 1,3,5,6,8,4,7,2 也就是測試一下內(nèi)核tcp協(xié)議棧的SACK邏輯是否如同RFC中所描述的一樣。
// 初始化部分建立服務(wù)器端socket, 不再贅述 +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 // Client 端發(fā)送 握手報文以及接受服務(wù)器響應(yīng),不再贅述。這里注意激活了SACK +.1 < S 0:0(0) win 50000 <mss 1000, sackOK,nop,nop,nop,wscale 7> +0 > S. 0:0(0) ack 1 win 32000 <mss 1000,nop,nop,sackOK> +0 < . 1:1(0) ack 1 win 50000 // Server 端就緒 +.1 accept(3, ..., ...) = 4 //發(fā)送報文1 +0 < . 1:1001(1000) ack 1 win 50000 //發(fā)送報文3, 報文2 被調(diào)整到最后發(fā)送 +0 < . 2001:3001(1000) ack 1 win 50000 //發(fā)送報文5 報文4 被調(diào)整亂序 +0 < . 4001:5001(1000) ack 1 win 50000 //發(fā)送報文6 +0 < . 5001:6001(1000) ack 1 win 50000 //發(fā)送報文8 報文7 被調(diào)整亂序 +0 < P. 7001:8001(1000) ack 1 win 50000 //發(fā)送報文4 +0 < . 3001:4001(1000) ack 1 win 50000 //發(fā)送報文7 +0 < . 6001:7001(1000) ack 1 win 50000 // 接收到第一個報文的ACK +0 > . 1:1(0) ack 1001 // 接收到SACK, 報告收到了亂序的報文3,但是沒報文2。 +0 > . 1:1(0) ack 1001 win 31000 <nop,nop,sack 2001:3001> // 接收到SACK, 報告收到了亂序的報文3,報文5,但是沒報文2。沒報文4 +0 > . 1:1(0) ack 1001 win 31000 <nop,nop,sack 4001:5001 2001:3001> // 接收到SACK, 報告收到了亂序的報文3,報文5,但是沒報文2。沒報文4 +0 > . 1:1(0) ack 1001 win 31000 <nop,nop,sack 4001:6001 2001:3001> // 接收到SACK, 報告收到了亂序的報文3,報文5,6, 報文8,但是沒報文2。沒報文4,沒報文7 +0 > . 1:1(0) ack 1001 win 31000 <nop,nop,sack 7001:8001 4001:6001 2001:3001> // 接收到SACK, 報告收到了亂序的報文3,4,5,6, 報文8,但是沒報文2。沒報文7 +0 > . 1:1(0) ack 1001 win 31000 <nop,nop,sack 2001:6001 7001:8001> // 接收到SACK, 報告收到了亂序的報文3,4,5,6,7,8,但是沒報文2 +0 > . 1:1(0) ack 1001 win 31000 <nop,nop,sack 2001:8001> //發(fā)送報文2 至此所有報文完結(jié) +0 < . 1001:2001(1000) ack 1 win 50000 +0 > . 1:1(0) ack 8001`
隨后我們再來用wireshark 驗證一下。
果然完全匹配。
Packet Drill 其實還有非常復(fù)雜而且更精巧的玩法, 可以充分測試各種邊界條件。以后有機會再和大家進一步分享
“Linux Tcp內(nèi)核協(xié)議棧Packet Drill基本原理是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。