一份快速實用的 tcpdump 命令參考手冊

至秦發表於2015-09-18

對於 tcpdump 的使用,大部分管理員會分成兩類。有一類管理員,他們熟知  tcpdump 和其中的所有標記;另一類管理員,他們僅瞭解基本的使用方法,剩下事情都要藉助參考手冊才能完成。出現這種情況的原因在於, tcpdump 是一個相當高階的命令,使用的時候需要對網路的工作機制有相當深入的瞭解。

在今天的文章中,我想提供一個快速但相當實用的 tcpdump 參考。我會談到基本的和一些高階的使用方法。我敢肯定我會忽略一些相當酷的命令,歡迎你補充在評論部分。

在我們深入瞭解以前,最重要的是瞭解  tcpdump 是用來做什麼的。 tcpdump 命令用來儲存和記錄網路流量。你可以用它來觀察網路上發生了什麼,並可用來解決各種各樣的問題,包括和網路通訊無關的問題。除了網路問題,我經常用 tcpdump 解決應用程式的問題。如果你發現兩個應用程式之間無法很好工作,可以用  tcpdump  觀察出了什麼問題。 tcpdump 可以用來抓取和讀取資料包,特別是當通訊沒有被加密的時候。

基礎知識

瞭解 tcpdump ,首先要知道 tcpdump中使用的標記(flag)。在這個章節中,我會涵蓋到很多基本的標記,這些標記在很多場合下會被用到。

不轉換主機名、埠號等

通常情況下, tcpdump  會嘗試查詢和轉換主機名和埠號。

你可以通過 -n 標記關閉這個功能。我個人總是使用這個標記,因為我喜歡使用 IP 地址而不是主機名,主機名和埠號的轉換經常會帶來困擾。但是,知道利用  tcpdump  轉換或者不轉換的功能還是相當有用的,特別是有些時候,知道源流量(source traffic)來自哪個伺服器是相當重要的。

增加詳細資訊

增加一個簡單 -v 標記,輸出會包含更多資訊,例如一個 IP 包的生存時間(ttl, time to live)、長度和其他的選項。

tcpdump  的詳細資訊有三個等級,你可以通過在命令列增加 v 標記的個數來獲取更多的資訊。通常我在使用 tcpmdump 的時候,總是使用最高等級的詳細資訊,因為我希望看到所有資訊,以免後面會用到。

指定網路介面

通常情況下,如果不指定網路介面, tcpdump  在執行時會選擇編號最低的網路介面,一般情況下是 eth0,不過因系統不同可能會有所差異。

你可以用 -i 標記來指定網路介面。在大多數 Linux 系統上,any 這一特定的網路介面名用來讓  tcpdump  監聽所有的介面。我發現這在排查伺服器(擁有多個網路介面)的問題特別有用,尤其是牽扯到路由的時候。

寫入檔案

tcpdump  執行結果會輸出在螢幕上。

但很多時候,你希望把  tcpdump  的輸出結果儲存在檔案中,最簡單的方法就是利用 -w 標記。如果你後續還會檢查這些網路資料,這樣做就特別有用。將這些資料存成一個檔案的好處,就是你可以多次讀取這個儲存下來的檔案,並且可以在這個網路流量的快照上使用其它標記或者過濾器(我們後面會討論到)。

通常這些資料被快取而不會被寫入檔案,直到你用 CTRL+C 結束 tcpdump 命令的時候。

讀取檔案

一旦你將輸出存成檔案,就必然需要讀取這個檔案。要做到這點,你只需要在 -r 標記後指定這個檔案的存放路徑。

一個小提醒,如果你熟悉 wireshark 這類網路診斷工具,也可以利用它們來讀取  tcpdump  儲存的檔案。

指定抓包大小

較新版本的  tcpdump  通常可以截獲 65535 位元組,但某些情況下你不需要截獲預設大小的資料包。執行  tcpdump  時,你可以通過 -s 標記來指定快照長度。

指定抓包數量

tcpdump  會一直執行,直至你用 CTRL+C 讓它退出。

你也可以通過 -c 標記後面加上抓包的數量,讓  tcpdump  在抓到一定數量的資料包後停止操作。當你不希望看到  tcpdump  的輸出大量出現在螢幕上,以至於你無法閱讀的時候,就會希望使用這個標記。當然,通常更好的方法是藉助過濾器來截獲特定的流量。

基礎知識彙總

你可以將以上這些基礎的標記組合起來使用,來讓  tcpdump  提供你所需要的資訊。

過濾器

介紹完基礎的標記後,我們該介紹過濾器了。 tcpdump  可以通過各式各樣的表示式,來過濾所擷取或者輸出的資料。我在這篇文章裡會給出一些簡單的例子,以便讓你們瞭解語法規則。你們可以查詢  tcpdump  幫助中的 pcap-filter 章節,瞭解更為詳細的資訊。

查詢特定主機的流量

執行上述命令, tcpdump  會像前面一樣把結果輸出到螢幕上,不過只會顯示源 IP 或者目的 IP 地址是 10.0.3.1 的資料包。通過增加主機 10.0.3.1 引數,我們可以讓  tcpdump  過濾掉源和目的地址不是 10.0.3.1 的資料包。

只顯示源地址為特定主機的流量

前面的例子顯示了源和目的地址是 10.0.3.1 的流量,而上面的命令只顯示資料包源地址是 10.0.3.1 的流量。這是通過在 host 前面增加 src 引數來實現的。這個額外的過濾器告訴  tcpdump  查詢特定的源地址。 反過來通過 dst 過濾器,可以指定目的地址。

過濾源和目的埠

通過類似 and 操作符,你可以在  tcpdump  上使用更為複雜的過濾器描述。這個就類似 if 語句,你就這麼想吧。這個例子中,我們使用 and 操作符告訴  tcpdump  只輸出埠號是 22 和 60738 的資料包。這點在分析網路問題的時候很有用,因為可以通過這個方法來關注某一個特定會話(session)的資料包。

你可以用兩種方式來表示 and 操作符,and 或者 && 都可以。我個人傾向於兩個都使用,特別要記住在使用 && 的時候,要用單引號或者雙引號包住表示式。在 BASH 中,你可以使用 && 執行一個命令,該命令成功後再執行後面的命令。通常,最好將表示式用引號包起來,這樣會避免不預期的結果,特別當過濾器中有一些特殊字元的時候。

查詢兩個埠號的流量

你可以用 or 或者 || 操作符來過濾結果。在這個例子中,我們使用 or 操作符去截獲傳送和接收埠為 80 或 443 的資料流。這在 Web 伺服器上特別有用,因為伺服器通常有兩個開放的埠,埠號 80 表示 http 連線,443 表示 https。

查詢兩個特定埠和來自特定主機的資料流

前面的例子用來排查多埠的協議問題,是非常有效的。如果 Web 伺服器的資料流量相當大, tcpdump  的輸出可能有點混亂。我們可以通過增加 host 引數進一步限定輸出。在這種情況下,我們通過把 or 表示式放在括號中來保持 or 描述。

在一個過濾器中,你可以多次使用括號。在下面的例子中,下面命令可以限定截獲滿足如下條件的資料包:傳送或接收埠號為 80 或 443,主機來源於 10.0.3.169 或者 10.0.3.1,且目的地址是 10.0.3.246。

理解輸出結果

開啟  tcpdump  的所有選項去截獲網路流量是相當困難的,但一旦你拿到這些資料你就要對它進行解讀。在這個章節,我們將涉及如何判斷源/目的 IP 地址,源/目的埠號,以及 TCP 協議型別的資料包。當然這些是相當基礎的,你從  tcpdump  裡面獲取的資訊也遠不止這些。不過這篇文章主要是粗略的介紹,我們會關注在這些基礎知識上。我建議你們可以通過幫助頁獲取更為詳細的資訊。

判斷源和目的地址

判斷源和目的地址和埠號相當簡單。

從上面的輸出,我們可以看到源 IP 地址是 10.0.3.246,源埠號是 56894, 目的 IP 地址是 192.168.0.92,埠號是 22。一旦你理解  tcpdump  格式後,這些資訊很容易判斷。如果你還沒有猜到格式,你可以按照 src-ip.src-port > dest-ip.dest-port: Flags[S] 格式來分析。源地址位於 > 前面,後面則是目的地址。你可以把 > 想象成一個指向目的地址的箭頭符號。

判斷資料包型別

從上面的例子,我們可以判斷這個資料包是一個 SYN 資料包。我們是通過  tcpdump  輸出中的 [S] 標記欄位得出這個結論,不同型別的資料包有不同型別的標記。不需要深入瞭解 TCP 協議中的資料包型別,你就可以通過下面的速查表來加以判斷。

  • [S] – SYN (開始連線)
  • [.] – 沒有標記
  • [P] – PSH (資料推送)
  • [F] – FIN (結束連線)
  • [R] – RST (重啟連線)

在這個版本的  tcpdump  輸出中,[S.] 標記代表這個資料包是 SYN-ACK 資料包。

不好的例子

上面顯示了一個不好的通訊例子,在這個例子中“不好”,代表通訊沒有建立起來。我們可以看到 10.0.3.246 發出一個 SYN 資料包給 主機 192.168.0.92,但是主機並沒有應答。

好的例子

好的例子應該向上面這樣,我們看到典型的 TCP 3次握手。第一資料包是 SYN 包,從主機 10.0.3.246 傳送給 主機192.168.0.110,第二個包是 SYN-ACK 包,主機192.168.0.110 回應 SYN 包。最後一個包是一個 ACK 或者 SYN – ACK – ACK 包,是主機 10.0.3.246 回應收到了 SYN – ACK 包。從上面看到一個 TCP/IP 連線成功建立。

資料包檢查

用十六進位制和 ASCII 碼列印資料包

排查應用程式網路問題的通常做法,就是用  tcpdump  的 -XX 標記列印出 16 進位制和 ASCII 碼格式的資料包。這是一個相當有用的命令,它可以讓你看到源地址,目的地址,資料包型別以及資料包本身。但我不是這個命令輸出的粉絲,我認為它太難讀了。

只列印 ASCII 碼格式的資料包

我傾向於只列印 ASCII 格式資料,這可以幫助我快速定位資料包中傳送了什麼,哪些是正確的,哪些是錯誤的。你可以通過 -A 標記來實現這一點。

從上面的輸出,你可以看到我們成功獲取了一個 http 的 GET 請求包。如果網路通訊沒有被加密,用人類可閱讀的格式打出包中資料,對於解決應用程式的問題是很有幫助。如果你排查一個網路通訊被加密的問題,列印包中資料就不是很有用。不過如果你有證書的話,你還是可以使用 ssldump 或者 wireshark

非 TCP 資料流

雖然這篇文章主要採用 TCP 傳輸來講解  tcpdump ,但是  tcpdump  絕對不是隻能抓 TCP 資料包。它還可以用來獲取其他型別的資料包,例如 ICMP、 UDP 和 ARP 包。下面是一些簡單的例子,說明  tcpdump  可以截獲非 TCP 資料包。

ICMP 資料包

UDP 資料包

如果你覺得有好例子進一步說明  tcpdump  命令,請在評論中補充。

打賞支援我翻譯更多好文章,謝謝!

打賞譯者

打賞支援我翻譯更多好文章,謝謝!

任選一種支付方式

一份快速實用的 tcpdump 命令參考手冊 一份快速實用的 tcpdump 命令參考手冊

相關文章