掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
這是一篇關(guān)于tcpdump的文章,分為使用tcpdump、解讀輸出兩部分。其中“解讀輸出”部分中關(guān)于分片的解釋是個(gè)人認(rèn)為最有價(jià)值的,當(dāng)然如果你肯花30分鐘自己動(dòng)手抓個(gè)包嘗試用本文介紹的方式還原IP、TCP頭部肯定會(huì)對(duì)你調(diào)試網(wǎng)絡(luò)程序有幫助(成為老司機(jī)專治各種網(wǎng)絡(luò)疑難雜癥想想是不是挺激動(dòng)?)。

網(wǎng)站設(shè)計(jì)制作過程拒絕使用模板建站;使用PHP+MYSQL原生開發(fā)可交付網(wǎng)站源代碼;符合網(wǎng)站優(yōu)化排名的后臺(tái)管理系統(tǒng);成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)收費(fèi)合理;免費(fèi)進(jìn)行網(wǎng)站備案等企業(yè)網(wǎng)站建設(shè)一條龍服務(wù).我們是一家持續(xù)穩(wěn)定運(yùn)營了10余年的創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司。
使用tcpdump
格式:tcpdump [選項(xiàng)] [表達(dá)式]
我常用的選項(xiàng)
表達(dá)式用來過濾數(shù)據(jù)包,特別是加上X選項(xiàng)(輸出數(shù)據(jù)包的詳細(xì)內(nèi)容會(huì)讓你的屏幕快速飛過~~),如果不指定表達(dá)式基本上是刷屏的速度。我一般會(huì)限制協(xié)議類型、主機(jī)地址或者端口。比如抓取HTTP數(shù)據(jù)包,我會(huì)tcpdump -X -i eth0 -vvvv -n port 80,指定抓取80端口的數(shù)據(jù)(對(duì)端80和本機(jī)80)
解讀tcpdump輸出
提到網(wǎng)絡(luò)就不能不提ISO分層模型、TCP/IP分層模型,這兩部分的內(nèi)容教材的太多了我就不絮叨了。從現(xiàn)實(shí)意義上說其實(shí)網(wǎng)絡(luò)只有三層。物理層和數(shù)據(jù)鏈路層就是指網(wǎng)卡所以我們無需關(guān)心;IP層、TCP/UDP、應(yīng)用層這三部分是我們最常接觸到的,其實(shí)它們是指一個(gè)東西。比如看一個(gè)HTTP GET請(qǐng)求。
這是用tcpdump抓到的一個(gè)GET請(qǐng)求,
***行,12:53:07.156463 IP (tos 0x2,ECT(0), ttl 64, id 22767, offset 0, flags [DF], proto TCP (6), length 577)
輸出了當(dāng)前時(shí)間(本機(jī))、IP頭部信息;
第二行,192.168.200.1.59222 > 192.168.200.10.80: Flags [P.], cksum 0x98a6 (correct), seq 966819399:966819924, ack 3158680476, win 4096, options [nop,nop,TS val 341138922 ecr 204637], length 525
說明了這個(gè)數(shù)據(jù)包是從 192.168.200.1的59222端口發(fā)送到 192.168.200.10的80端口,后面是TCP頭部信息。
第三行可不是“實(shí)際內(nèi)容”,它是整個(gè)數(shù)據(jù)包的16進(jìn)制輸出和對(duì)應(yīng)的ASCII(包括IP頭部和TCP頭部)。
所以網(wǎng)絡(luò)分層其實(shí)就是指一個(gè)數(shù)據(jù)包擁有不同的頭部。這種設(shè)計(jì)是一種封裝,通過劃分“層”讓應(yīng)用更容易開發(fā)。我們來剖析一下IP頭和TCP頭,掌握了這部分內(nèi)容就算得上“精通網(wǎng)絡(luò)”了(我沒說錯(cuò),是精通~~)。
IP頭部
盜用一下wiki的圖(遍地都是這種圖我就不自己畫了)
最小的IP頭部是20個(gè)字節(jié)(不包含選項(xiàng)),上圖中每一行4個(gè)字節(jié)(32個(gè)bit),一共6行(***一行大小不固定,最多40個(gè)字節(jié)。)。
結(jié)合我們的例子,其實(shí)tcpdump已經(jīng)幫我們把關(guān)鍵的IP信息輸出了。
我們直接看16進(jìn)制的數(shù)據(jù)(驗(yàn)證tcpdump輸出的IP信息和16進(jìn)制表示的數(shù)據(jù)包是否吻合),每16bit一組。
- 4502 0241 58ef 4000 4006 ce68 c0a8 c801
下面這段推翻了網(wǎng)絡(luò)上很多傳言(好吧,好像包括Wiki)
每個(gè)以太網(wǎng)卡都有MTU(***傳輸單元)的限制,這個(gè)表示網(wǎng)卡每次可以接收一個(gè)數(shù)據(jù)包的大小。所以即便IP數(shù)據(jù)包可以達(dá)到2^32=65535字節(jié)也不能一次發(fā)送這么大的數(shù)據(jù)包。每個(gè)IP數(shù)據(jù)包的大小被限制在1500個(gè)字節(jié)(最常見的MTU大小),除去最小的IP頭部(20)、最小TCP頭部(20)還剩下1460字節(jié),這就是一個(gè)IP數(shù)據(jù)包可以攜帶的準(zhǔn)確數(shù)據(jù)。如果超過這個(gè)設(shè)定就必須“分片”。
如果你是UDP協(xié)議基本上是自己考慮分片,UDP協(xié)議本身不會(huì)重傳,重組。所以一般用UDP協(xié)議都是“一槍頭買賣”——在一個(gè)數(shù)據(jù)包里包含所有信息不進(jìn)行分片。(如果你用UDP協(xié)議一般傳送數(shù)據(jù)不要操過1380否則程序就必須考慮處理分片——也就是MTU-***IP頭60字節(jié)-***TCP頭60字節(jié))
如果是TCP就很幸運(yùn)了,TCP會(huì)幫你做分片和重組。(后面會(huì)講)
因?yàn)門CP已經(jīng)考慮過分片了所以IP數(shù)據(jù)包無需再次分片,“標(biāo)志”字段基本上都是——4(不分片)。(大家可以抓一下163之類的網(wǎng)站看看HTML被分段傳送的時(shí)候***行有沒有4000)
用一段代碼表示如何自己構(gòu)造IP數(shù)據(jù)包
對(duì)于同一個(gè)TCP會(huì)話來說IP頭是非常固定的。
TCP頭部
最小的TCP頭部是20個(gè)字節(jié)(不包含選項(xiàng)),上圖中每一行4個(gè)字節(jié)(32個(gè)bit),一共6行(***一行大小不固定,最多40個(gè)字節(jié)。)。
結(jié)合我們的例子,其實(shí)tcpdump已經(jīng)幫我們把關(guān)鍵的IP信息輸出了。
注意這里的length是指數(shù)據(jù)的大小不包括IP頭和TCP頭
我們直接看16進(jìn)制的數(shù)據(jù),每16bit一組。
e756 0050 39a0 7e47 bc45 a39c
TCP約定通訊雙方三次握手的時(shí)候發(fā)送端會(huì)隨機(jī)生成一個(gè)seq號(hào)通過***個(gè)SYN協(xié)議發(fā)送給對(duì)端,對(duì)端也會(huì)隨機(jī)生成一個(gè)seq號(hào)同時(shí)設(shè)置ack+1響應(yīng)對(duì)端。發(fā)送端則回復(fù)seq=自己seq+1,ack=對(duì)端 seq+1。通俗的說法,seq是自己的序號(hào),ack是期望對(duì)端發(fā)送的數(shù)據(jù),所以如果你拿到一個(gè)數(shù)據(jù)包seq=1024,ack=522;那么只要回復(fù)一條seq=522,ack=1025就可以實(shí)現(xiàn)“TCP會(huì)話劫持”(是不是很可怕?相當(dāng)于不但可以探測到你的通話內(nèi)容還可以“無縫介入”到你的談話,***冒充對(duì)方而不會(huì)產(chǎn)生任何違和感)。
第三行8018 1000 98a6 0000 0101 080a 1455
FIN=0x01,表示數(shù)據(jù)已經(jīng)發(fā)送完了可以釋放連接了,用于關(guān)閉TCP連接
SYN=0x02,這個(gè)太喜聞樂見了,用于TCP握手
RST=0x04,直接關(guān)閉TCP連接(不經(jīng)過FIN)
PUSH=0x08,官方的解釋“盡快交給應(yīng)用不等待緩沖區(qū)裝滿”,其實(shí)這個(gè)標(biāo)志位會(huì)一直存在。只要你傳送數(shù)據(jù)一定會(huì)有這個(gè)標(biāo)志位。
ACK=0x10,確認(rèn)數(shù)據(jù)
tcpdump會(huì)分別用一個(gè)大寫字母輸出在Flags選項(xiàng),比如例子中是“P”表示設(shè)置了push位,又因?yàn)橛衋ck 3158680476所以一定有ACK標(biāo)志位。不難算出PUSH+ACK=8+10=18
這個(gè)TCP包是32個(gè)字節(jié),上面已經(jīng)介紹了20個(gè)字節(jié)所以還有12個(gè)字節(jié)(6組),它們用來表示TCP的選項(xiàng)。
TCP常見的選項(xiàng)包括
0 (1字節(jié))什么都沒有
1(1字節(jié)) 什么都沒有,經(jīng)常用于“填充”
上面的兩個(gè)其實(shí)是同一個(gè)意思。
2 ***報(bào)文段長度(4字節(jié))一般出現(xiàn)在三次握手的SYN包中,用于說明自己可以接收到的***報(bào)文長度(一般是MTU-40,就是以太網(wǎng)***傳輸單元-最小IP-最小TCP。這也印證了前面的說法——IP永遠(yuǎn)不分片,TCP負(fù)責(zé)分片。)
3 窗口擴(kuò)大因子(4字節(jié)),取值0-14?;瑒?dòng)窗口***值是2^16(65535),如果在一個(gè)“高延時(shí)高帶寬”(也叫長肥管道 )網(wǎng)絡(luò)中這個(gè)值會(huì)顯的特別小(所有的廣域網(wǎng)或者乃至整個(gè)互聯(lián)網(wǎng)都是這種網(wǎng)絡(luò))。所以新增擴(kuò)大因子用來擴(kuò)大窗口的大小,它表示TCP窗口左移的位數(shù)(實(shí)際窗口大小=窗口*2^窗口多擴(kuò)大因子)。
8:時(shí)間戳(10字節(jié))對(duì)端的時(shí)間戳(4字節(jié))自己的時(shí)間戳(4字節(jié))。這個(gè)選項(xiàng)主要用來測量回路時(shí)間(RTT),也是TCP做為流量控制的一個(gè)關(guān)鍵手段。
例子中0101沒有意義,08表示這是時(shí)間戳選項(xiàng)(類型),后面0a是值所占字節(jié)(選項(xiàng)的整個(gè)長度,包括表示類型的1個(gè)字節(jié)表示長度的一個(gè)字節(jié)),1455 5dea(341138922) 四個(gè)字節(jié)表示發(fā)送端的時(shí)間戳,0003 1f5d(204637) 四個(gè)字節(jié)表示回顯的時(shí)間戳。(對(duì)應(yīng)tcpdump輸出中的options [nop,nop,TS……])
用一段代碼表示如何構(gòu)造TCP包
對(duì)于一個(gè)TCP會(huì)話來說response、control、seq、ack是變化的,滑動(dòng)窗口大小則會(huì)隨著是否網(wǎng)絡(luò)擁塞產(chǎn)生變化。
后面就是實(shí)際的HTTP協(xié)議的內(nèi)容了,4745 5420,0x47是G的ASCII、0x45是E的ASCII、0x54是T的ASCII、0x20是空格。。。。。后面就自己讀吧
總結(jié)
《TCP/IP協(xié)議詳解》中很大部分章節(jié)是在介紹tcpdump的輸出、IP頭部、TCP頭部(甚至可以說是三卷書都是在說這個(gè)),掌握tcpdump對(duì)于我們做網(wǎng)絡(luò)分析或者系統(tǒng)調(diào)試是非常有幫助的。大家玩的愉快。
高能預(yù)警
哥講tcpdump是為了下一篇——《手把手教你做ARP病毒》。史上最難殺死的ARP病毒橫行數(shù)十年依然如此無敵,作為一名老司機(jī)我要手把手教你做病毒,分分鐘讓你的網(wǎng)絡(luò)陷入癱瘓(還可以讓你“精準(zhǔn)”打擊網(wǎng)絡(luò)內(nèi)任何一個(gè)人——讓她上不了網(wǎng)然后偽裝成老司機(jī)修電腦)。
【本文是專欄作者邢森的原創(chuàng)文章,轉(zhuǎn)載請(qǐng)聯(lián)系作者本人獲取授權(quán)】
戳這里,看該作者更多好文

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流