在 Linux 命令列中使用 tcpdump 抓包
tcpdump
是一款靈活、功能強大的抓包工具,能有效地幫助排查網路故障問題。
以我作為管理員的經驗,在網路連線中經常遇到十分難以排查的故障問題。對於這類情況,tcpdump
便能派上用場。
tcpdump
是一個命令列實用工具,允許你抓取和分析經過系統的流量資料包。它通常被用作於網路故障分析工具以及安全工具。
tcpdump
是一款強大的工具,支援多種選項和過濾規則,適用場景十分廣泛。由於它是命令列工具,因此適用於在遠端伺服器或者沒有圖形介面的裝置中收集資料包以便於事後分析。它可以在後臺啟動,也可以用 cron 等定時工具建立定時任務啟用它。
本文中,我們將討論 tcpdump
最常用的一些功能。
1、在 Linux 中安裝 tcpdump
tcpdump
支援多種 Linux 發行版,所以你的系統中很有可能已經安裝了它。用下面的命令檢查一下是否已經安裝了 tcpdump
:
$ which tcpdump
/usr/sbin/tcpdump
$ sudoyum install -y tcpdump
tcpdump
依賴於 libpcap
,該庫檔案用於捕獲網路資料包。如果該庫檔案也沒有安裝,系統會根據依賴關係自動安裝它。
現在你可以開始抓包了。
2、用 tcpdump 抓包
使用 tcpdump
抓包,需要管理員許可權,因此下面的示例中絕大多數命令都是以 sudo
首先,先用 tcpdump -D
命令列出可以抓包的網路介面:
$ sudotcpdump-D
1.eth0
2.virbr0
3.eth1
4.any(Pseudo-device that captures on all interfaces)
5.lo[Loopback]
如上所示,可以看到我的機器中所有可以抓包的網路介面。其中特殊介面 any
可用於抓取所有活動的網路介面的資料包。
我們就用如下命令先對 any
介面進行抓包:
$ sudotcpdump-i any
tcpdump: verbose output suppressed
listening on any,link-type LINUX_SLL (Linux cooked), capture size262144 bytes
09:56:18.293641 IP rhel75.localdomain.ssh>192.168.64.1.56322:Flags[P.], seq 3770820720:3770820916, ack 3503648727, win 309, options [nop,nop,TS val 76577898 ecr 510770929], length 196
09:56:18.293794 IP 192.168.64.1.56322> rhel75.localdomain.ssh:Flags[.], ack 196, win 391, options [nop,nop,TS val 510771017 ecr 76577898], length 0
09:56:18.295058 IP rhel75.59883> gateway.domain:2486+ PTR?1.64.168.192.in-addr.arpa.(43)
09:56:18.310225 IP gateway.domain > rhel75.59883:2486NXDomain*0/1/0(102)
09:56:18.312482 IP rhel75.49685> gateway.domain:34242+ PTR?28.64.168.192.in-addr.arpa.(44)
09:56:18.322425 IP gateway.domain > rhel75.49685:34242NXDomain*0/1/0(103)
09:56:18.323164 IP rhel75.56631> gateway.domain:29904+ PTR?1.122.168.192.in-addr.arpa.(44)
09:56:18.323342 IP rhel75.localdomain.ssh>192.168.64.1.56322:Flags[P.], seq 196:584, ack 1, win 309, options [nop,nop,TS val 76577928 ecr 510771017], length 388
09:56:18.323563 IP 192.168.64.1.56322> rhel75.localdomain.ssh:Flags[.], ack 584, win 411, options [nop,nop,TS val 510771047 ecr 76577928], length 0
09:56:18.335569 IP gateway.domain > rhel75.56631:29904NXDomain*0/1/0(103)
09:56:18.336429 IP rhel75.44007> gateway.domain:61677+ PTR?98.122.168.192.in-addr.arpa.(45)
09:56:18.336655 IP gateway.domain > rhel75.44007:61677*1/0/0 PTR rhel75.(65)
09:56:18.337177 IP rhel75.localdomain.ssh>192.168.64.1.56322:Flags[P.], seq 584:1644, ack 1, win 309, options [nop,nop,TS val 76577942 ecr 510771047], length 1060
---- SKIPPING LONG OUTPUT -----
09:56:19.342939 IP 192.168.64.1.56322> rhel75.localdomain.ssh:Flags[.], ack 1752016, win 1444, options [nop,nop,TS val 510772067 ecr 76578948], length 0
^C
9003 packets captured
9010 packets received by filter
7 packets dropped by kernel
$
tcpdump
會持續抓包直到收到中斷訊號。你可以按 Ctrl+C
來停止抓包。正如上面示例所示,tcpdump
抓取了超過 9000 個數據包。在這個示例中,由於我是通過 ssh
連線到伺服器,所以 tcpdump
也捕獲了所有這類資料包。-c
選項可以用於限制 tcpdump
抓包的數量:
$ sudotcpdump-i any -c 5
tcpdump: verbose output suppressed,use-v or-vv for full protocol decode
listening on any,link-type LINUX_SLL (Linux cooked), capture size262144 bytes
11:21:30.242740 IP rhel75.localdomain.ssh>192.168.64.1.56322:Flags[P.], seq 3772575680:3772575876, ack 3503651743, win 309, options [nop,nop,TS val 81689848 ecr 515883153], length 196
11:21:30.242906 IP 192.168.64.1.56322> rhel75.localdomain.ssh:Flags[.], ack 196, win 1443, options [nop,nop,TS val 515883235 ecr 81689848], length 0
11:21:30.244442 IP rhel75.43634> gateway.domain:57680+ PTR?1.64.168.192.in-addr.arpa.(43)
11:21:30.244829 IP gateway.domain > rhel75.43634:57680NXDomain0/0/0(43)
11:21:30.247048 IP rhel75.33696> gateway.domain:37429+ PTR?28.64.168.192.in-addr.arpa.(44)
5 packets captured
12 packets received by filter
0 packets dropped by kernel
$
如上所示,tcpdump
在抓取 5 個數據包後自動停止了抓包。這在有些場景中十分有用 —— 比如你只需要抓取少量的資料包用於分析。當我們需要使用過濾規則抓取特定的資料包(如下所示)時,-c
的作用就十分突出了。
在上面示例中,tcpdump
預設是將 IP 地址和埠號解析為對應的介面名以及服務協議名稱。而通常在網路故障排查中,使用 IP 地址和埠號更便於分析問題;用 -n
選項顯示 IP 地址,-nn
選項顯示埠號:
$ sudotcpdump-i any -c5 -nn
tcpdump: verbose output suppressed,use-v or-vv for full protocol decode
listening on any,link-type LINUX_SLL (Linux cooked), capture size262144 bytes
23:56:24.292206 IP 192.168.64.28.22>192.168.64.1.35110:Flags[P.], seq 166198580:166198776, ack 2414541257, win 309, options [nop,nop,TS val 615664 ecr 540031155], length 196
23:56:24.292357 IP 192.168.64.1.35110>192.168.64.28.22:Flags[.], ack 196, win 1377, options [nop,nop,TS val 540031229 ecr 615664], length 0
23:56:24.292570 IP 192.168.64.28.22>192.168.64.1.35110:Flags[P.], seq 196:568, ack 1, win 309, options [nop,nop,TS val 615664 ecr 540031229], length 372
23:56:24.292655 IP 192.168.64.1.35110>192.168.64.28.22:Flags[.], ack 568, win 1400, options [nop,nop,TS val 540031229 ecr 615664], length 0
23:56:24.292752 IP 192.168.64.28.22>192.168.64.1.35110:Flags[P.], seq 568:908, ack 1, win 309, options [nop,nop,TS val 615664 ecr 540031229], length 340
5 packets captured
6 packets received by filter
0 packets dropped by kernel
如上所示,抓取的資料包中顯示 IP 地址和埠號。這樣還可以阻止 tcpdump
發出 DNS 查詢,有助於在網路故障排查中減少資料流量。
現在你已經會抓包了,讓我們來分析一下這些抓包輸出的含義吧。
3、理解抓取的報文
tcpdump
能夠抓取並解碼多種協議型別的資料報文,如 TCP、UDP、ICMP 等等。雖然這裡我們不可能介紹所有的資料報文型別,但可以分析下 TCP 型別的資料報文,來幫助你入門。更多有關 tcpdump
的詳細介紹可以參考其 幫助手冊。tcpdump
抓取的 TCP 報文看起來如下:
08:41:13.729687 IP 192.168.64.28.22>192.168.64.1.41916:Flags[P.], seq 196:568, ack 1, win 309, options [nop,nop,TS val 117964079 ecr 816509256], length 372
具體的欄位根據不同的報文型別會有不同,但上面這個例子是一般的格式形式。
第一個欄位 08:41:13.729687
是該資料報文被抓取的系統本地時間戳。
然後,IP
是網路層協議型別,這裡是 IPv4
,如果是 IPv6
協議,該欄位值是 IP6
。
192.168.64.28.22
是源 ip 地址和埠號,緊跟其後的是目的 ip 地址和其埠號,這裡是 192.168.64.1.41916
。
在源 IP 和目的 IP 之後,可以看到是 TCP 報文標記段 Flags [P.]
。該欄位通常取值如下:
< 如顯示不全,請左右滑動 >
值 | 標誌型別 | 描述 |
---|---|---|
S | SYN | Connection Start |
F | FIN | Connection Finish |
P | PUSH | Data push |
R | RST | Connection reset |
. | ACK | Acknowledgment |
該欄位也可以是這些值的組合,例如 [S.]
代表 SYN-ACK
資料包。
接下來是該資料包中資料的序列號。對於抓取的第一個資料包,該欄位值是一個絕對數字,後續包使用相對數值,以便更容易查詢跟蹤。例如此處 seq 196:568
代表該資料包包含該資料流的第 196 到 568 位元組。
接下來是 ack 值:ack 1
。該資料包是資料傳送方,ack 值為 1。在資料接收方,該欄位代表資料流上的下一個預期位元組資料,例如,該資料流中下一個資料包的 ack 值應該是 568。
接下來欄位是接收視窗大小 win 309
,它表示接收緩衝區中可用的位元組數,後跟 TCP 選項如 MSS(最大段大小)或者視窗比例值。更詳盡的 TCP 協議內容請參考 Transmission Control Protocol(TCP) Parameters。
最後,length 372
代表資料包有效載荷位元組長度。這個長度和 seq 序列號中位元組數值長度是不一樣的。
現在讓我們學習如何過濾資料報文以便更容易的分析定位問題。
4、過濾資料包
正如上面所提,tcpdump
可以抓取很多種型別的資料報文,其中很多可能和我們需要查詢的問題並沒有關係。舉個例子,假設你正在定位一個與 web 伺服器連線的網路問題,就不必關係 SSH 資料報文,因此在抓包結果中過濾掉 SSH 報文可能更便於你分析問題。
tcpdump
有很多引數選項可以設定資料包過濾規則,例如根據源 IP 以及目的 IP 地址,埠號,協議等等規則來過濾資料包。下面就介紹一些最常用的過濾方法。
協議
在命令中指定協議便可以按照協議型別來篩選資料包。比方說用如下命令只要抓取 ICMP 報文:
$ sudotcpdump-i any -c5 icmp
tcpdump: verbose output suppressed,use-v or-vv for full protocol decode
listening on any,link-type LINUX_SLL (Linux cooked), capture size262144 bytes
然後再開啟一個終端,去 ping 另一臺機器:
$ ping opensource.com
PING opensource.com (54.204.39.132)56(84) bytes of data.
64 bytes from ec2-54-204-39-132.compute-1.amazonaws.com (54.204.39.132): icmp_seq=1 ttl=47time=39.6 ms
回到執行 tcpdump
命令的終端中,可以看到它篩選出了 ICMP 報文。這裡 tcpdump
並沒有顯示有關 opensource.com
的域名解析資料包:
09:34:20.136766 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request,id20361, seq 1, length 64
09:34:20.176402 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply,id20361, seq 1, length 64
09:34:21.140230 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request,id20361, seq 2, length 64
09:34:21.180020 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply,id20361, seq 2, length 64
09:34:22.141777 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request,id20361, seq 3, length 64
5 packets captured
5 packets received by filter
0 packets dropped by kernel
主機
用 host
引數只抓取和特定主機相關的資料包:
$ sudotcpdump-i any -c5 -nn host 54.204.39.132
tcpdump: verbose output suppressed,use-v or-vv for full protocol decode
listening on any,link-type LINUX_SLL (Linux cooked), capture size262144 bytes
09:54:20.042023 IP 192.168.122.98.39326>54.204.39.132.80:Flags[S], seq 1375157070, win 29200, options [mss 1460,sackOK,TS val 122350391 ecr 0,nop,wscale 7], length 0
09:54:20.088127 IP 54.204.39.132.80>192.168.122.98.39326:Flags[S.], seq 1935542841, ack 1375157071, win 28960, options [mss 1460,sackOK,TS val 522713542 ecr 122350391,nop,wscale 9], length 0
09:54:20.088204 IP 192.168.122.98.39326>54.204.39.132.80:Flags[.], ack 1, win 229, options [nop,nop,TS val 122350437 ecr 522713542], length 0
09:54:20.088734 IP 192.168.122.98.39326>54.204.39.132.80:Flags[P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122350438 ecr 522713542], length 112: HTTP: GET / HTTP/1.1
09:54:20.129733 IP 54.204.39.132.80>192.168.122.98.39326:Flags[.], ack 113, win 57, options [nop,nop,TS val 522713552 ecr 122350438], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel
如上所示,只抓取和顯示與 54.204.39.132
有關的資料包。
埠號
tcpdump
可以根據服務型別或者埠號來篩選資料包。例如,抓取和 HTTP 服務相關的資料包:
$ sudotcpdump-i any -c5 -nn port 80
tcpdump: verbose output suppressed,use-v or-vv for full protocol decode
listening on any,link-type LINUX_SLL (Linux cooked), capture size262144 bytes
09:58:28.790548 IP 192.168.122.98.39330>54.204.39.132.80:Flags[S], seq 1745665159, win 29200, options [mss 1460,sackOK,TS val 122599140 ecr 0,nop,wscale 7], length 0
09:58:28.834026 IP 54.204.39.132.80>192.168.122.98.39330:Flags[S.], seq 4063583040, ack 1745665160, win 28960, options [mss 1460,sackOK,TS val 522775728 ecr 122599140,nop,wscale 9], length 0
09:58:28.834093 IP 192.168.122.98.39330>54.204.39.132.80:Flags[.], ack 1, win 229, options [nop,nop,TS val 122599183 ecr 522775728], length 0
09:58:28.834588 IP 192.168.122.98.39330>54.204.39.132.80:Flags[P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122599184 ecr 522775728], length 112: HTTP: GET / HTTP/1.1
09:58:28.878445 IP 54.204.39.132.80>192.168.122.98.39330:Flags[.], ack 113, win 57, options [nop,nop,TS val 522775739 ecr 122599184], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel
IP 地址/主機名
同樣,你也可以根據源 IP 地址或者目的 IP 地址或者主機名來篩選資料包。例如抓取源 IP 地址為 192.168.122.98
的資料包:
$ sudotcpdump-i any -c5 -nn src