1. 程式人生 > 其它 >Linux命令拾遺-網路抓包工具

Linux命令拾遺-網路抓包工具

原創:打碼日記(微信公眾號ID:codelogs),歡迎分享,轉載請保留出處。

簡介

Linux中有很多抓包工具,如ngrep、tcpdump與tshark等,它們有很多用法與使用場景,下面我將結合例子講解各工具的用法以及它們的使用場景。

本系列文章索引
Linux命令拾遺-入門篇
Linux命令拾遺-文字處理篇
Linux命令拾遺-軟體資源觀測
Linux命令拾遺-硬體資源觀測
Linux命令拾遺-剖析工具
Linux命令拾遺-動態追蹤工具
Linux命令拾遺-理解系統負載
Linux命令拾遺-top中的%nice是啥

ngrep

ngrep是一款抓包工具,它將抓到的包資料以文字形式直接顯示出來,非常適用於包資料包含文字的抓包分析(如HTTP、MySQL),如下:

抓HTTP請求

有時我們會遇到這種場景,服務方提供http介面給呼叫方使用,呼叫方傳遞一個引數值,服務方收到的結果不一樣!
這種情況,有可能是呼叫方的請求方式有問題,也有可能是服務方有請求攔截器導致問題,如何辨別問題是在哪一方呢?這時用ngrep抓包工具確認一下包內容再合適不過了,如下:

# -d any表示抓取所有網絡卡的資料包
# -W byline 一般用於HTTP抓包,方便檢視
$ ngrep -d any -W byline port 8080


如上,ngrep會將非可見字元顯示為.,所以上面http請求每行後都有個.,指的是HTTP協議換行符\r\n中的\r,而最前面的T代表這是TCP協議的包。

抓取SQL

# 抓取3961埠,過濾出包資料中帶select的網路包,即查詢SQL
# -A 2 匹配包之後的2個包也顯示出來
$ ngrep -d any -A 2 'select' port 3961


可以發現,mysql回包都有.def.這樣的字樣,我們可以根據這個來判斷mysql響應包。

ngrep帶上-T引數,可以額外打印出前後兩個包的間隔時間,這樣我們根據回包的間隔時間,就能大概看到SQL查詢的耗時了,如下:

# -W single讓包資料在一行上顯示,便於awk等文字工具處理
# -s 200 包大小最多抓200位元組,多餘資料不顯示
# -T 打印出兩個包之間的間隔時間,單位秒
# awk部分指令碼邏輯是,一直抓包直到發現回包慢於1秒時停止
$ ngrep -d any -W single -s 200 -T 'select|def' port 3961 \
    | awk '{print} $1~/T/ && /.def./ && $2>1 && $2<1000 {exit(0)}'

tcpdump

tcpdump是一個通用抓包工具,一般用它來抓各種協議的網路包資料,然後再使用wireshark分析,如下:

抓取3961埠網路包

# -c 10000表示最多抓1萬個包
$ tcpdump -i any -s 0 -c 10000 tcp and port 3961 -w ./target.cap

# -G 600 表示600s儲存一個抓包檔案,避免單檔案太大
$ tcpdump -i any -s 0 -G 600 tcp and port 3961 -w ./target_%Y_%m%d_%H%M_%S.pcap

wireshark分析

抓取的target.cap是mysql的網路包資料,它是二進位制的,無法直接檢視,需要使用wireshark分析,下載地址如下:
https://www.wireshark.org/download.html

預設情況下,wireshark認為3306埠的資料包是MySQL協議的,而上面我們mysql埠是3961,導致wireshark無法將包資料識別為MySQL協議,顯示的是TCP原始資料,不方便檢視,所以我們需要告訴wireshark使用MySQL協議解析3961埠資料包,如下:

a. 先decode as...相應埠使用MySQL協議解析:

...

b. 輸入mysql.query contains "id=24218",檢視SQL中包含id=24218的資料包,如下:

網路慢還是後端處理慢?


為方便分析耗時,一般建議在wireshark上再新增如下兩列:

  • tcpDelta = tcp.time_delta,表示在當前tcp連線中,當前包相對上一個包的時間差。
  • ack_rtt = tcp.analysis.ack_rtt,表示tcp中的ack包,相對其資料包的時間差。

如下,找耗時最大的包:

...

...

...

發現對於select sleep(2.0)這條SQL,服務端回覆ack很快,而在回覆資料包時變慢,說明是慢在MySQL處理上,而非網路裡,因為如果網路慢的話,ack應該也會變慢的。

tshark

tshark是wireshark工具的命令列版本,使用的方法與wireshark是類似的,如下:

# -i any 任意網絡卡的資料都抓取
# -f 指定抓什麼協議,什麼埠
# -d 類似wireshark的decode as,將3961解析為mysql協議
# -Y 類似wireshark上面的顯示過濾器
# -T 指定資料輸出格式,fields表示tab分隔格式
# -e 指定輸出的欄位
# -E header=y 指定輸出標題行
$ sudo tshark -ni any -f 'tcp and port 3961' -d 'tcp.port==3961,mysql' \
    -T fields  -e frame.number -e frame.time_epoch -e frame.time_delta_displayed  \
    -e ip.src -e tcp.srcport -e tcp.dstport -e ip.dst -e tcp.stream -e tcp.len -e tcp.nxtseq \
    -e tcp.time_delta -e tcp.analysis.ack_rtt \
    -e _ws.col.Info -e mysql.query -E header=y > packets.tsv

# 檢視抓包資料
$ csvlook -It packets.tsv | less -iSFX
| frame.number | frame.time_epoch     | frame.time_delta_displayed | ip.src    | tcp.srcport | tcp.dstport | ip.dst    | tcp.stream | tcp.len | tcp.nxtseq | tcp.time_delta | tcp.analysis.ack_rtt | _ws.col.Info                                                                     | mysql.query                                                                     |
| ------------ | -------------------- | -------------------------- | --------- | ----------- | ----------- | --------- | ---------- | ------- | ---------- | -------------- | -------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| 1            | 1639287428.374886956 | 0.000000000                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 5       | 6          | 0.000000000    |                      | Request Ping                                                                     |                                                                                 |
| 2            | 1639287428.375043740 | 0.000156784                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 0       | 1          | 0.000156784    | 0.000156784          | 3961 → 39262 [ACK] Seq=1 Ack=6 Win=512 Len=0 TSval=696789627 TSecr=696789627     |                                                                                 |
| 3            | 1639287428.375268878 | 0.000225138                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 11      | 12         | 0.000225138    |                      | Response OK                                                                      |                                                                                 |
| 4            | 1639287428.375289961 | 0.000021083                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 0       | 6          | 0.000021083    | 0.000021083          | 39262 → 3961 [ACK] Seq=6 Ack=12 Win=512 Len=0 TSval=696789627 TSecr=696789627    |                                                                                 |
| 5            | 1639287428.375886139 | 0.000596178                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 55      | 61         | 0.000596178    |                      | Request Query                                                                    | select id from app_log al order by id desc limit 1                              |
| 6            | 1639287428.375906403 | 0.000020264                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 0       | 12         | 0.000020264    | 0.000020264          | 3961 → 39262 [ACK] Seq=12 Ack=61 Win=512 Len=0 TSval=696789628 TSecr=696789628   |                                                                                 |
| 7            | 1639287428.377206294 | 0.001299891                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 76      | 88         | 0.001299891    |                      | Response                                                                         |                                                                                 |
| 8            | 1639287428.377226652 | 0.000020358                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 0       | 61         | 0.000020358    | 0.000020358          | 39262 → 3961 [ACK] Seq=61 Ack=88 Win=512 Len=0 TSval=696789629 TSecr=696789629   |                                                                                 |
| 9            | 1639287428.378921659 | 0.001695007                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 84      | 145        | 0.001695007    |                      | Request Query                                                                    | select id,log_info,create_time,update_time,add_time from app_log where id=27371 |
| 10           | 1639287428.378942384 | 0.000020725                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 0       | 88         | 0.000020725    | 0.000020725          | 3961 → 39262 [ACK] Seq=88 Ack=145 Win=512 Len=0 TSval=696789631 TSecr=696789631  |                                                                                 |
| 11           | 1639287428.380450661 | 0.001508277                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 412     | 500        | 0.001508277    |                      | Response                                                                         |                                                                                 |
| 12           | 1639287428.380471636 | 0.000020975                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 0       | 145        | 0.000020975    | 0.000020975          | 39262 → 3961 [ACK] Seq=145 Ack=500 Win=509 Len=0 TSval=696789633 TSecr=696789633 |                                                                                 |
| 13           | 1639287430.051942681 | 1.671471045                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 22      | 167        | 1.671471045    |                      | Request Query                                                                    | select sleep(2.0)                                                               |
| 14           | 1639287430.051972761 | 0.000030080                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 0       | 500        | 0.000030080    | 0.000030080          | 3961 → 39262 [ACK] Seq=500 Ack=167 Win=512 Len=0 TSval=696791304 TSecr=696791304 |                                                                                 |
| 15           | 1639287432.053394353 | 2.001421592                | 127.0.0.1 | 3961        | 39262       | 127.0.0.1 | 0          | 65      | 565        | 2.001421592    |                      | Response                                                                         |                                                                                 |
| 16           | 1639287432.053520674 | 0.000126321                | 127.0.0.1 | 39262       | 3961        | 127.0.0.1 | 0          | 0       | 167        | 0.000126321    | 0.000126321          | 39262 → 3961 [ACK] Seq=167 Ack=565 Win=512 Len=0 TSval=696793306 TSecr=696793305 |

並且,tshark也可以直接分析tcpdump抓到的包資料,如下:

# -Y 類似於wireshark中的顯示過濾器
$ tshark -d 'tcp.port==3961,mysql' -Y 'mysql.query contains "id=21"' -r target.cap -T fields -e frame.number -e mysql.query
5       select id,log_info,create_time,update_time,add_time from app_log where id=21527
13      select id,log_info,create_time,update_time,add_time from app_log where id=21518
25      select id,log_info,create_time,update_time,add_time from app_log where id=21007
52      select id,log_info,create_time,update_time,add_time from app_log where id=21505

# tshark包還附帶一個editcap命令
# 可用於擷取抓包資料的一段時間範圍
$ editcap -F libpcap -A "2013-07-20 23:00:00" -B "2013-07-20 23:20:00" input.pcap output.pcap

pcap-filter與wireshark-filter

ngreptcpdumptshark -f使用的都是pcap-filter語法,用於抓取網路包時,對抓到的網路包進行過濾,如下是tcpdump使用pcap-filter的一些常見語法。

# 抓取指定主機的資料包
$ tcpdump -ni any host 210.27.48.1
# 抓取來自210.27.48.1主機和23埠的tcp包
$ tcpdump -ni any tcp src host 210.27.48.1 and port 23 
# 抓取來自網路10.234.10.0/24的主機發來的目的埠是80或8080的tcp包
$ tcpdump -ni any tcp src net 10.234.10.0/24 and dst port '(80 or 8080)'
# 抓tcp協議的rst包
$ tcpdump -ni any -s0 tcp and 'tcp[13] & 4 != 0 ' -vvv
# 抓tcp協議的fin包
$ tcpdump -ni any -s0 tcp and 'tcp[13] & 1 != 0 ' -vvv

詳細語法可以man pcap-filter檢視,或訪問:https://wiki.wireshark.org/CaptureFilters

而wireshark介面上的顯示過濾器,以及tshark -Y使用的都是wireshark-filter語法,用於對已抓取的資料包進行進一步過濾分析,如下是tshark使用wireshark-filter的一些常見語法。

# 過濾指定主機與指定埠資料包
$ tshark -Y 'ip.addr==127.0.0.1 and tcp.port==3961'
# 解析為http協議,並使用http協議欄位過濾
$ tshark -d 'tcp.port==8080,http' -Y 'http.request.uri contains "/get"'
# 解析為mysql協議,並使用mysql協議欄位過濾
$ tshark -d 'tcp.port==3961,mysql' -Y 'mysql.query contains "id=21"'

詳細語法可以man wireshark-filter檢視,或訪問:https://wiki.wireshark.org/DisplayFilters

總結

可見,使用ngrep、tcpdump、tshark分析網路問題是非常有幫助的,一定要在工作中多多嘗試使用,熟悉它們的各種用法。

之前也寫過一些文章,總結了Linux中常用的網路工具命令,如:ping、telnet、nslookup、curl等,感興趣也可以看下:
常用網路命令總結
還在胡亂設定連線空閒時間?
我都調通了,為啥你不行?

往期內容

Linux命令拾遺-入門篇
原來awk真是神器啊
Linux文字命令技巧(上)
Linux文字命令技巧(下)
字元編碼解惑