JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

封包擷取與 Wireshark

ping 與 traceroute 告訴你哪裡不對勁;封包擷取則讓你逐位元組地讀到真正的對話。這篇說明如何把封包從線路上抓下來、用 Wireshark 把它們解碼,以及為什麼一個好的過濾條件就是成敗的關鍵。

從症狀走向真正的位元組

本階前幾篇給了你兩支手電筒。ping 告訴你某台主機是否回應、以及一次來回要花多久;traceroute 則藉由濫用 TTL 來描出路徑。兩者都屬於主動量測:你打進探測流量,再看反彈回來的是什麼。它們很適合回答「它還活著嗎?有多遠?」這類問題,但給的是摘要。當真正的抱怨是「頁面載入到一半就卡住」時,摘要就不夠了。你得親自讀那場對話。

這正是封包擷取所做的事。它不送探測封包,而是悄悄地把通過某個介面的每一個訊框都複製一份,交給你一份忠實的逐字稿:真正的封包,連同你的機器實際送出或收到的每一個標頭與位元組。這是純粹的被動量測——你不添加任何自己的流量,你只是聆聽。負責記錄的工具是 tcpdump(一個小巧的命令列擷取引擎)或某種圖形化的擷取程式;負責解碼、讓你能讀懂它的工具則是 Wireshark。把封包擷取想成在你自己這條線路上的一個側錄器,把通話錄下來,好讓你能慢動作重播。

為什麼一份擷取是分層的,就跟網路一樣

在 Wireshark 裡打開一個擷取到的封包,你會看到最有用的一件事:它展開成一疊可以逐層攤開的列。這並非巧合——這正是基礎階提過的封裝,終於變得看得見了。每一層都把上面那一層用自己的標頭包起來,就像層層相套的信封,而 Wireshark 只是按順序把它們一層層剝開。位元組從沒改變過;這工具只是替你讀出每一層上的標籤。

ONE PACKET, AS WIRESHARK UNFOLDS IT
-----------------------------------------------------------
Frame 42: 74 bytes captured                  <- capture metadata (time, length)
  Ethernet II  src a4:.. dst 3c:..  type IPv4   <- link layer  (MAC addresses)
    IPv4   src 192.168.1.10  dst 93.184.216.34  <- network layer (IP addresses)
      TCP  src port 51514  dst port 443         <- transport layer (ports)
           [SYN]  seq=0  win=64240
        (no payload yet -- this is just the handshake opening)

outermost header read first  ->  innermost payload last
Wireshark 一層層剝開一個封包。乙太網路包著 IPv4、IPv4 包著 TCP——正是你在基礎階遇過的層層相套的信封,現在出現在螢幕上。

由上而下讀,最外層是帶有 MAC 位址的連結層訊框(在這條線路上下一跳是誰),接著是帶有來源與目的位址的 IP 標頭(在整個網際網路裡的哪個位置),再來是帶有連接埠號的 TCP 區段(兩端各自的哪個程式)。連接埠就是街道地址後面的那個門牌號。你點得愈深,它回答的問題就愈具體:同一個封包同時告訴你那一跳、那台主機、那個程式,因為每一層都留下了自己的標頭。

過濾條件:把一切都擷取下來是個錯誤

一台繁忙的機器一秒可以收送數萬個封包。把它們全部擷取下來,你會被淹沒——硬碟塞滿、工具卡頓,而你在意的那一次往返,成了一堆無關雜訊裡的一根針。把令人沮喪的擷取與真正有用的擷取區分開來的本事就是過濾,而它有兩種截然不同的型態,初學者經常把它們搞混。

第一種是擷取過濾條件,也就是著名的 BPF 過濾條件(Berkeley 封包過濾器)。它決定哪些封包根本會不會被記錄下來,在資料被複製到你的工具之前,就在核心底層套用——所以它很省,而且會把不符合的東西永久丟掉。它的語法精簡,以主機/連接埠為導向:「tcp port 443」、「host 93.184.216.34」、「udp port 53 and not src net 10.0.0.0/8」。當你已經大致知道要什麼、而那條線路又太忙無法全錄時,就用擷取過濾條件。

第二種是顯示過濾條件,Wireshark 在事後把它套用到你已經有的一份擷取上。它豐富得多,因為到那時每個欄位都已經被解碼了:你可以寫「http.response.code == 404」、用「tcp.flags.syn == 1 && tcp.flags.ack == 0」找出連線的開啟,或用「tcp.analysis.retransmission」只浮出 Wireshark 認為被重送的那些封包。經驗法則:擷取過濾條件(BPF)限制你記錄了什麼,而且拿不回來;顯示過濾條件只是把列藏起來,你可以隨意更改。拿不準時,就用 BPF 擷取得寬鬆一點,再用顯示過濾條件收窄。

從頭到尾追蹤一場對話

單一一條 TCP 連線散落在一份擷取裡,它的封包與其他數百個交錯在一起。Wireshark 最受喜愛的功能「追蹤 TCP 串流」會把某一條連線的封包蒐集起來,按順序把位元組串流重新組合,並把真正的對話呈現給你看——你送出的那個 HTTP 請求,以及回來的那個回覆,全是可讀的文字。分層逐字稿的價值就在這裡兌現:你不再盯著一個個孤立的封包,而開始讀一段對白。

  1. 開始擷取(若線路繁忙,加上像「host example.com」這樣的 BPF 過濾條件),接著去做那件出問題的事——載入頁面、送出訊息——然後停止。
  2. 套用一個顯示過濾條件來找出那條連線,例如「tcp.port == 443」,並找出開頭的 SYN。
  3. 確認那次三向交握:先 SYN、再 SYN-ACK、再 ACK。如果你根本沒看到 SYN-ACK 回來,問題就出在連對方伺服器都搆不到——那是路由、防火牆或 DNS 的問題,而不是應用程式。
  4. 在那條連線中的任一封包上按右鍵,選擇「追蹤 TCP 串流」,把請求與回覆當成純文字讀出來。
  5. 掃視麻煩的徵兆:重送與重複的 ACK 代表丟包;請求與回覆之間隔了一大段時間,代表伺服器正在思考;連線重設(RST)代表有一方突然掛斷了。

留意這把問題收窄了多少。如果交握瞬間完成、回覆卻花了兩秒,那麼網路沒問題,是伺服器慢。如果你看到請求送出去、接著在回覆之前出現一陣重送,那就是路徑在丟包、而 TCP 正在復原。擷取不只是說「慢」;它伸出手指指向問題。這份本事——把一句含糊的抱怨變成某個具體的層、某個具體的成因——正是本階最後一篇所要立基的東西。

擷取看不見什麼——以及該改用什麼

封包擷取很強大,但要誠實面對它的極限。最大的一項:加密。回想一下,TCP 可靠但不安全,它本身不加密任何東西——加密是 TLS 做的。所以當你追蹤一條通往 HTTPS 伺服器的串流時,你能讀到三向交握、IP 位址、連接埠、封包大小與時序,以及 TLS 的建立過程。但真正的 HTTP 請求與回覆是密文。你能看出一場對話發生過、它有多大、有多快,卻看不出說了什麼——除非你握有那段工作階段的金鑰。擷取看得到信封,看不到加密信封裡的信。

擷取也無法規模化。把一台機器一分鐘的流量完整逐字記錄下來沒問題;把一座資料中心裡每一條鏈路都完整逐字記錄下來則很荒謬——那份紀錄會比流量本身還大。這正是第一篇在「深而窄」與「廣而淺」之間畫出的那道鴻溝。要取得全網路的能見度,你改用摘要而非逐字稿:像 NetFlow 與 sFlow 這樣的流量紀錄,會為每一場對話只留一小行(誰跟誰、用哪些連接埠、多少位元組與封包),而非每一個位元組;SNMP 則從每台裝置上輪詢計數器。那整個「永遠開著的摘要」的世界,就是網路遙測,而可觀測性正是事後向它提問的本事。

最後一點誠實,技術性較低,卻同樣重要:窺看別人的流量並不是一件中性的事。即使你在技術上拿得到存取權,一份擷取裡可能藏著密碼、個人資料與私人訊息,把它錄下來可能觸法、或違反職場規範。誠實的準則很簡單——只擷取你自己的流量,或你被明確授權檢查的流量,並把存下來的檔案當成它本來就是的那種敏感紀錄來對待。