Wireshark 和 Tcpdump 是最常用的網(wǎng)絡(luò)抓包和分析工具,更是分析網(wǎng)絡(luò)性能必不可少的利器。
tcpdump 僅支持命令行格式使用,常用在 Linux 服務(wù)器中抓取和分析網(wǎng)絡(luò)包
Wireshark 除了可以抓包外,還提供了可視化分析網(wǎng)絡(luò)包的圖形頁面,在Window環(huán)境下使用
所以,這兩者實(shí)際上是搭配使用的,先用 tcpdump 命令在 Linux 服務(wù)器上抓包,接著把抓包的文件拖出到 Windows 電腦后,用 Wireshark 可視化分析。
一、Wireshark
1 Wireshark簡介
Wireshark是使用最廣泛的一款開源抓包軟件,常用來檢測網(wǎng)絡(luò)問題、攻擊溯源、或者分析底層通信機(jī)制。
它使用WinPCAP作為接口,直接與網(wǎng)卡進(jìn)行數(shù)據(jù)報(bào)文交換。
2 Wireshark抓包原理
Wireshark使用的環(huán)境大致分為兩種,一種是電腦直連互聯(lián)網(wǎng)的單機(jī)環(huán)境,另外一種就是應(yīng)用比較多的互聯(lián)網(wǎng)環(huán)境,也就是連接交換機(jī)的情況。
「單機(jī)情況」下,Wireshark直接抓取本機(jī)網(wǎng)卡的網(wǎng)絡(luò)流量; 「交換機(jī)情況」下,Wireshark通過端口鏡像、ARP欺騙等方式獲取局域網(wǎng)中的網(wǎng)絡(luò)流量。
端口鏡像:利用交換機(jī)的接口,將局域網(wǎng)的網(wǎng)絡(luò)流量轉(zhuǎn)發(fā)到指定電腦的網(wǎng)卡上。
ARP欺騙:交換機(jī)根據(jù)MAC地址轉(zhuǎn)發(fā)數(shù)據(jù),偽裝其他終端的MAC地址,從而獲取局域網(wǎng)的網(wǎng)絡(luò)流量。
3 Wireshark使用
3.1 選擇網(wǎng)卡
打開 Wireshark 后,會(huì)直接進(jìn)入「網(wǎng)卡選擇界面」,WLAN 是我連接無線的網(wǎng)卡,我們抓一下這個(gè)網(wǎng)卡的流量,雙擊網(wǎng)卡名,自動(dòng)開始抓包。

3.2 停止抓包

3.3 保存數(shù)據(jù)
點(diǎn)擊右上角的「文件」,選擇「保存」,可以保存抓包的數(shù)據(jù)

也可以直接點(diǎn)擊工具欄的保存按鈕

4 案例1: Wireshark抓MySQL TCP 數(shù)據(jù)包
我們一直在使用 MySQL,但我們很少會(huì)考慮 MySQL Connector Java 是怎么和 MySQL 交互的,實(shí)際發(fā)送給 MySQL 的 SQL 語句又是怎樣的。
這里我們通過一個(gè)案例來使用 Wireshark 來觀察、分析應(yīng)用程序與 MySQL 交互的整個(gè)流程。
背景:有一個(gè)數(shù)據(jù)導(dǎo)入程序需要導(dǎo)入大量的數(shù)據(jù),想到了使用 Spring JdbcTemplate 的批量操作功能進(jìn)行數(shù)據(jù)批量導(dǎo)入,但是發(fā)現(xiàn)性能非常差,和普通的單條 SQL 執(zhí)行性能差不多。對于批量操作,我們希望程序可以把多條 insert SQL 語句合并成一條,或至少是一次性提交多條語句到數(shù)據(jù)庫,以減少和 MySQL 交互次數(shù)、提高性能。那么,我們的程序是這樣運(yùn)作的嗎?
4.1 先啟動(dòng)Wireshark后選擇某個(gè)需要捕獲的網(wǎng)卡。
由于我們連接的是本地的 MySQL,因此選擇 loopback 回環(huán)網(wǎng)卡:

4.2 Wireshark 捕捉這個(gè)網(wǎng)卡的所有網(wǎng)絡(luò)流量
我們可以在上方的顯示過濾欄輸入 tcp.port == 6657,來過濾出所有 6657 端口的 TCP 請求(因?yàn)槲覀兪峭ㄟ^ 6657 端口連接 MySQL 的)。
可以看到,程序運(yùn)行期間和 MySQL 有大量交互。因?yàn)?Wireshark 直接把 TCP 數(shù)據(jù)包解析為了 MySQL 協(xié)議,所以下方窗口可以直接顯示 MySQL 請求的 SQL 查詢語句。我們看到,testuser 表的每次 insert 操作,插入的都是一行記錄:

如果列表中的 Protocol 沒有顯示 MySQL 的話,你可以手動(dòng)點(diǎn)擊 Analyze 菜單的 Decode As 菜單,然后加一條規(guī)則,把 6657 端口設(shè)置為 MySQL 協(xié)議:

4.3 分析
從上面抓包的數(shù)據(jù)可以看出,我們的程序并不是在做批量插入操作,和普通的單條循環(huán)插入沒有區(qū)別。
這里原因其實(shí)在于 rewriteBatchedStatements 參數(shù)。我們修改連接字符串,并將其值設(shè)置為 true:
datasource.url=jdbc:mysql://localhost:6657/common_mistakes?characterEncoding=UTF-8&useSSL=false&rewriteBatchedStatements=true
4.4 把rewriteBatchedStatements設(shè)置為true,重新抓包
可以看到:
這次 insert SQL 語句被拼接成了一條語句(如第二個(gè)紅框所示);
這個(gè) TCP 包因?yàn)樘蟊环指畛闪?11 個(gè)片段傳輸,#699 請求是最后一個(gè)片段,其實(shí)際內(nèi)容是 insert 語句的最后一部分內(nèi)容(如第一和第三個(gè)紅框顯示)。

4.5 查看整個(gè) TCP 連接的所有數(shù)據(jù)包
為了查看整個(gè) TCP 連接的所有數(shù)據(jù)包,你可以在請求上點(diǎn)擊右鍵,選擇 Follow->TCP Stream:

打開后可以看到,從 MySQL 認(rèn)證開始到 insert 語句的所有數(shù)據(jù)包的內(nèi)容:

查看最開始的握手?jǐn)?shù)據(jù)包可以發(fā)現(xiàn),TCP 的最大分段大?。∕SS)是 16344 字節(jié),而我們的 MySQL 超長 insert 的數(shù)據(jù)一共 138933 字節(jié),因此被分成了 11 段傳輸,其中最大的一段是 16332 字節(jié),低于 MSS 要求的 16344 字節(jié)。

5 案例2:客戶端和 MySQL 握手過程
一般而言,客戶端和 MySQL 進(jìn)行認(rèn)證,認(rèn)證(握手)過程分為三步。
5.1 首先,服務(wù)端給客戶端主動(dòng)發(fā)送握手消息:

Wireshark 已經(jīng)把消息的字段做了解析,你可以對比官方文檔的協(xié)議格式一起查看。HandshakeV10 消息體的第一個(gè)字節(jié)是消息版本 0a,見圖中紅色框標(biāo)注的部分。前面四個(gè)字節(jié)是 MySQL 的消息頭,其中前三個(gè)字節(jié)是消息體長度(16 進(jìn)制 4a=74 字節(jié)),最后一個(gè)字節(jié)是消息序列號(hào)。
5.2 然后,客戶端給服務(wù)端回復(fù)的 HandshakeResponse41 消息體,包含了登錄的用戶名和密碼

可以看到,用戶名是 string[NUL]類型的,說明字符串以 00 結(jié)尾代表字符串結(jié)束。關(guān)于 MySQL 協(xié)議中的字段類型,你可以參考這里。
5.3 最后,服務(wù)端回復(fù)的 OK 消息,代表握手成功

這樣分析下來,我們可以發(fā)現(xiàn)使用 Wireshark 觀察客戶端和 MySQL 的認(rèn)證過程,非常方便。而如果不借助 Wireshark 工具,我們只能一個(gè)字節(jié)一個(gè)字節(jié)地對照協(xié)議文檔分析內(nèi)容。
其實(shí),各種 CS 系統(tǒng)定義的通訊協(xié)議本身并不深?yuàn)W,甚至可以說對著協(xié)議文檔寫通訊客戶端是體力活。以前做loT開發(fā)時(shí),對著各種類型的設(shè)備協(xié)議文檔寫通訊客戶端確實(shí)是就是個(gè)體力活,屬于會(huì)者不難,難著不會(huì),就是剛開始時(shí)入門難一些。
這段經(jīng)歷涉及到了netty,見 Netty系列文章
二 Tcpdump
1 Tcpdump簡介
Linux作為網(wǎng)絡(luò)服務(wù)器,特別是作為路由器和網(wǎng)關(guān)時(shí),數(shù)據(jù)的采集和分析是不可少的。TcpDump是Linux中強(qiáng)大的網(wǎng)絡(luò)數(shù)據(jù)采集分析工具之一。
tcpdump可以根據(jù)使用者需求對網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)包進(jìn)行捕獲的抓包工具,windows平臺(tái)有wireshark等工具,tcpdump可以將網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)包的“包頭”全部捕獲過來進(jìn)行分析,其支持網(wǎng)絡(luò)層、特定的傳輸協(xié)議、數(shù)據(jù)發(fā)送和接收的主機(jī)、網(wǎng)卡和端口的過濾,并提供and、or、not等語句進(jìn)行邏輯組合捕獲數(shù)據(jù)包或去掉不用的信息。
2 Tcpdump命令選項(xiàng)和捕獲主機(jī)到主機(jī)的數(shù)據(jù)包
-a #將網(wǎng)絡(luò)地址和廣播地址轉(zhuǎn)變成名字
-A #以ASCII格式打印出所有分組,并將鏈路層的頭最小化
-b #數(shù)據(jù)鏈路層上選擇協(xié)議,包括ip/arp/rarp/ipx都在這一層
-c #指定收取數(shù)據(jù)包的次數(shù),即在收到指定數(shù)量的數(shù)據(jù)包后退出tcpdump
-d #將匹配信息包的代碼以人們能夠理解的匯編格式輸出
-dd #將匹配信息包的代碼以c語言程序段的格式輸出
-ddd #將匹配信息包的代碼以十進(jìn)制的形式輸出
-D #打印系統(tǒng)中所有可以監(jiān)控的網(wǎng)絡(luò)接口
-e #在輸出行打印出數(shù)據(jù)鏈路層的頭部信息
-f #將外部的Internet地址以數(shù)字的形式打印出來,即不顯示主機(jī)名
-F #從指定的文件中讀取表達(dá)式,忽略其他的表達(dá)式
-i #指定監(jiān)聽網(wǎng)絡(luò)接口
-l #使標(biāo)準(zhǔn)輸出變?yōu)榫彌_形式,可以數(shù)據(jù)導(dǎo)出到文件
-L #列出網(wǎng)絡(luò)接口已知的數(shù)據(jù)鏈路
-n #不把網(wǎng)絡(luò)地址轉(zhuǎn)換為名字
-N 不輸出主機(jī)名中的域名部分,例如www.baidu.com只輸出www
-nn #不進(jìn)行端口名稱的轉(zhuǎn)換
-P #不將網(wǎng)絡(luò)接口設(shè)置為混雜模式
-q #快速輸出,即只輸出較少的協(xié)議信息
-r #從指定的文件中讀取數(shù)據(jù),一般是-w保存的文件
-w #將捕獲到的信息保存到文件中,且不分析和打印在屏幕
-s #從每個(gè)組中讀取在開始的snaplen個(gè)字節(jié),而不是默認(rèn)的68個(gè)字節(jié)
-S #將tcp的序列號(hào)以絕對值形式輸出,而不是相對值
-T #將監(jiān)聽到的包直接解析為指定的類型的報(bào)文,常見的類型有rpc(遠(yuǎn)程過程調(diào)用)和snmp(簡單網(wǎng)絡(luò)管理協(xié)議)
-t #在輸出的每一行不打印時(shí)間戳
-tt #在每一行中輸出非格式化的時(shí)間戳
-ttt #輸出本行和前面以后之間的時(shí)間差
-tttt #在每一行中輸出data處理的默認(rèn)格式的時(shí)間戳
-u #輸出未解碼的NFS句柄
-v #輸出稍微詳細(xì)的信息,例如在ip包中可以包括ttl和服務(wù)類型的信息
-vv#輸出相信的保報(bào)文信息
3 tcpdump表達(dá)式
3.1 關(guān)于數(shù)據(jù)類型的關(guān)鍵字 包括host、port、net:
host 192.168.130.1表示一臺(tái)主機(jī),
net 192.168.130.0表示一個(gè)網(wǎng)絡(luò)網(wǎng)段,
port 80 指明端口號(hào)為80,在這里如果沒有指明數(shù)據(jù)類型,那么默認(rèn)就是host
3.2 數(shù)據(jù)傳輸方向的關(guān)鍵字 包括src、dst、dst or src、dst and src,這些關(guān)鍵字指明了傳輸?shù)姆较?,比?/p>
src 192.168.130.1說明數(shù)據(jù)包源地址是192.168.130.1。
dst net 192.168.130.0指明目的網(wǎng)絡(luò)地址是192.168.130.0,
默認(rèn)是監(jiān)控主機(jī)對主機(jī)的src和dst,即默認(rèn)監(jiān)聽本機(jī)和目標(biāo)主機(jī)的所有數(shù)據(jù)。
3.3 協(xié)議關(guān)鍵字 包括ip、arp、rarp、udp
3.4 其他關(guān)鍵字 運(yùn)算類型:or、and、not、!
輔助功能型:gateway、less、broadcast、greater
4 Tcpdump捕獲方式
#tcpdump [協(xié)議類型] [源或目標(biāo)] [主機(jī)名稱或IP] [or/and/not/!條件組合] [源或目標(biāo)] [主機(jī)名或IP] [or/and/not/!條件組合] [端口] [端口號(hào)] …… [or/and/not/!條件組合] [條件]
tcpdump ip dst 192.168.56.1 and src 192.168.56.210 and port 80 and host ! www.baidu.com
4.1 監(jiān)聽指定網(wǎng)卡ens33的所有傳輸數(shù)據(jù)包
tcpdump -i ens33

4.2 捕獲主機(jī)192.168.130.151經(jīng)過網(wǎng)卡ens33的所有數(shù)據(jù)包
tcpdump -i ens33 host 192.168.130.151
只檢測192.168.130.151這個(gè)主機(jī)發(fā)過來的包,其他的自動(dòng)過濾

4.3 捕獲主機(jī) 192.168.130.151 和主機(jī)192.168.130.152或192.168.130.153的所有通信數(shù)據(jù)包
tcpdump host 192.168.130.151 and /(192.168.130.152 or 192.168.130.153/)
4.4 捕獲主機(jī)node9與其他主機(jī)之間(不包括 www.baidu.com)通信的ip數(shù)據(jù)包
tcpdump ip host node9 and not www.baidu.com
4.5 捕獲源主機(jī)node10發(fā)送的所有的經(jīng)過ens33網(wǎng)卡的所有數(shù)據(jù)包
tcpdump -i ens33 src node10
4.6 捕獲所有發(fā)送到主機(jī)www.baidu.com的數(shù)據(jù)包
tcpdump -i ens33 dst host www.baidu.com
4.7 監(jiān)聽主機(jī)192.168.56.1和192.168.56.210之間ip協(xié)議的80端口的且排除www.baidu.com通信的所有數(shù)據(jù)包:
tcpdump ip dst 192.168.56.1 and src 192.168.56.210 and port 80 and host ! baidu.com
也可以寫成tcpdump ip dst 192.168.56.1 and src 192.168.56.210 and port 80 and host not www.baidu.com,即not和!都是相同的取反的意思
4.8 捕獲主機(jī)192.168.56.210接收和發(fā)出的tcp協(xié)議的ssh的數(shù)據(jù)包
tcpdump tcp port 22 and host 192.168.56.210
4.9 監(jiān)聽本機(jī)udp的53端口的數(shù)據(jù)包
tcpdump udp port 53
監(jiān)聽本機(jī)udp的53端口的數(shù)據(jù)包,udp是dns協(xié)議的端口,這也是一個(gè)dns域名解析的完整過程