網路與 IP

tcpdump 抓包命令詳解:引數、過濾表示式與排障用法

tcpdump 是 Linux 伺服器上的命令列抓包工具,最常用的寫法是 tcpdump -i eth0 -nn -c 100 'tcp and host 198.51.100.7 and port 443':-i 選網路卡,-nn 不做名稱解析,-c 抓夠就停,引號裡是過濾條件。要細看就加 -w 存成 pcap 檔案,下載到電腦上用 Wireshark 開啟。

作者 頂聯產品團隊發布於 8 分鐘閱讀

tcpdump 抓包的基本格式是 tcpdump -i 網路卡 引數 '過濾表示式'。比如在伺服器上只看 198.51.100.7 存取本機 443 連接埠的 TCP 包:tcpdump -i eth0 -nn -c 50 'tcp and host 198.51.100.7 and port 443'。-i 指定網路卡,-nn 不把位址和連接埠換成名字,-c 50 抓夠 50 個包自動停止,引號裡是 BPF 過濾表示式。需要事後細看時,加 -w 檔名.pcap 把原始報文存下來,下載到電腦上用 Wireshark 分析。本文範例位址均取自文件專用網段:伺服器 203.0.113.10,客戶端 198.51.100.7。

tcpdump 是什麼軟體:安裝、許可權和選網路卡

tcpdump 是一款開源的命令列抓包工具,由 Tcpdump Group 維護,底層用 libpcap 庫收包,能在 Linux、BSD、macOS 上執行。它把經過網路卡的報文逐個解析成一行文字,也可以把原始報文寫成 pcap 檔案。它的過濾語法(BPF)和 Wireshark 的捕獲過濾器是同一套,在 tcpdump 裡寫熟的條件可以直接拿到 Wireshark 裡用。

apt install tcpdump      # Debian、Ubuntu
dnf install tcpdump      # RHEL、Rocky、AlmaLinux 8 及以後,老版本用 yum
tcpdump --version        # 檢視 tcpdump 和 libpcap 的版本
tcpdump -D               # 列出可以抓包的網路卡

抓包需要 root 許可權,或者由管理員單獨授予抓包能力。最容易出錯的一步是選網路卡,抓錯了網路卡,過濾條件寫得再對也是一片空白:

要看的流量 在哪塊網路卡上抓 說明
伺服器的公網業務 配著公網 IP 的業務網路卡,如 eth0、eno1 用 ip -br addr 查哪塊網路卡上有這個位址
不確定從哪塊網路卡進出 -i any 所有網路卡一起抓,但不開混雜模式;較新的版本會在每行前標出網路卡名和 In、Out 方向;經過 bond、網橋或 VLAN 子介面的包可能出現兩次
本機存取本機 -i lo 存取 127.0.0.1 或本機自己的 IP,包都不經過物理網路卡
鏈路聚合 整體看 bond0,看具體走哪條鏈路就抓成員口 cat /proc/net/bonding/bond0 查成員網路卡
KVM 虛擬機器 宿主機上對應的 vnet 網路卡 virsh domiflist 虛擬機器名 查虛擬機器和 vnet 的對應關係
Docker 容器 容器的網路名稱空間 用下面的 nsenter 命令,容器裡不用裝 tcpdump
# 進入名為 web 的容器的網路名稱空間,用宿主機上的 tcpdump 抓它的 eth0
nsenter -t "$(docker inspect -f '{{.State.Pid}}' web)" -n tcpdump -i eth0 -nn -c 20

tcpdump 引數詳解:常用的 15 個

引數 作用 用法與注意
-i eth0 指定網路卡 不寫時自動選一塊已啟用的非迴環網路卡,容易選錯,建議每次都寫上
-n、-nn 不做名稱解析 -n 不把 IP 反查成主機名,-nn 連連接埠和協議也顯示數字。不同版本對單個 -n 是否轉換連接埠名處理不一,習慣寫 -nn 最穩妥。不加時每個位址都要做 DNS 反查,輸出變慢,還會產生額外的 DNS 流量
-c 100 抓夠 N 個包後退出 防止忘了停止;和 -w 一起用時,寫夠 N 個包就退出
-w 檔案.pcap 把原始報文寫入檔案 螢幕上不再逐行列印;tcpdump 4.99 起可以加 --print 邊存邊看,老版本沒有這個選項
-r 檔案.pcap 讀取抓包檔案 可以再加過濾條件,從大檔案裡篩出一部分
-s 128 每個包只擷取前 N 位元組 -s 0 表示完整長度,較新的版本預設就抓完整的包(262144 位元組);只看報頭時截短,檔案小,也不留業務內容
-v、-vv 顯示更多報頭欄位 TTL、IP ID、總長度、TCP 選項等,排查 TTL 和分片問題時用
-e 顯示二層幀頭 列印源、目的 MAC 和 VLAN 標籤,用來核對閘道器 MAC、查位址衝突
-A、-X 顯示報文內容 -A 按 ASCII 顯示,-X 按十六進位制加 ASCII 顯示,用來看明文 HTTP 請求頭、Redis 命令
-tttt、-ttt 時間戳格式 -tttt 帶日期,方便和日誌對時間;-ttt 顯示與上一個包的間隔
-l 行緩衝輸出 輸出接管道交給 grep、tee 時加上,否則結果要攢一大塊才出來
-Q in、-Q out 只抓一個方向 Linux 上可用,部分平台不支援
-p 不把網路卡設為混雜模式 只收本機該收的包:發給本機的單播,以及廣播、組播
-B 8192 核心抓包緩衝區大小,單位 KiB 大流量下統計裡出現 dropped by kernel 時調大
-C、-G、-W 按大小或時間輪轉檔案 見後文“用 -w 儲存”一節

幾個常用組合:

tcpdump -i eth0 -nn -c 20 icmp                                   # 看 ping 的請求和應答
tcpdump -i eth0 -nn -tttt -l 'udp port 53' | tee /tmp/dns.txt    # 帶日期時間,同時存一份文字
tcpdump -i eth0 -nn -A -s 0 'tcp dst port 80'                    # 看明文 HTTP 請求頭
tcpdump -i eth0 -nn -e -c 10 arp                                 # 帶 MAC 位址看 ARP 請求和應答

過濾表示式:抓取指定 IP 和連接埠的 TCP 包

過濾表示式由三類關鍵字組合而成:物件(host、net、port、portrange)、方向(src、dst,不寫表示兩個方向都算)、協議(tcp、udp、icmp、arp、ip6),再用 and、or、not 連起來。常見需求的寫法:

需求 表示式
與某個 IP 有關的所有包,雙向 host 198.51.100.7
只看這個 IP 發來的包 src host 198.51.100.7
只看發往本機 22 連接埠的包 dst port 22
指定 IP 和連接埠的 TCP 包 tcp and host 198.51.100.7 and port 3306
某個網段 net 198.51.100.0/24
一段連續連接埠 portrange 30000-30100
這個 IP 的 80 或 443 連接埠 host 198.51.100.7 and (port 80 or port 443)
DNS 查詢 udp port 53
只看新建連線的 SYN tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn
只看 RST tcp[tcpflags] & tcp-rst != 0
ICMP 不可達 icmp[icmptype] == icmp-unreach
IPv6 位址 ip6 and host 2001:db8::10
排除自己的 SSH 會話 not (host 192.0.2.5 and port 22)

寫的時候注意四點:

  1. 整個表示式用單引號括起來。括號、!、& 在 shell 裡有特殊含義,不加引號會被 shell 先解釋掉,報語法錯誤。
  2. and 和 or 的優先順序相同,從左到右結合。host 198.51.100.7 and port 80 or port 443 實際含義是“(這個 IP 且 80 連接埠) 或 所有人的 443 連接埠”,會抓進一大堆無關的包。想表達“這個 IP 的 80 或 443”,必須加括號。
  3. port 不分 TCP 和 UDP。port 443 同時匹配 TCP 443 和 UDP 443(HTTP/3 走 UDP 443),只要 TCP 就寫成 tcp port 443 或 tcp and port 443。
  4. 按抓包點看到的位址寫條件。客戶端在 NAT 後面時,伺服器上看到的是它出口的公網 IP,而不是它的內網位址;拿不準就先只按連接埠過濾,看清位址後再收緊。

在所有網路卡上找某個 IP 的流量,是排查多網路卡伺服器時的常用寫法:

tcpdump -i any -nn host 198.51.100.7

看懂輸出:一行 TCP 包裡有什麼

一次 HTTPS 連線的開頭,在伺服器上抓到的輸出是這樣的(範例):

10:15:02.381245 IP 198.51.100.7.51544 > 203.0.113.10.443: Flags [S], seq 2814473922, win 64240, options [mss 1460,sackOK,TS val 1520637 ecr 0,nop,wscale 7], length 0
10:15:02.381290 IP 203.0.113.10.443 > 198.51.100.7.51544: Flags [S.], seq 90233411, ack 2814473923, win 65160, options [mss 1460,sackOK,TS val 88123 ecr 1520637,nop,wscale 7], length 0
10:15:02.412870 IP 198.51.100.7.51544 > 203.0.113.10.443: Flags [.], ack 1, win 502, options [nop,nop,TS val 1520668 ecr 88123], length 0
10:15:02.413511 IP 198.51.100.7.51544 > 203.0.113.10.443: Flags [P.], seq 1:518, ack 1, win 502, options [nop,nop,TS val 1520669 ecr 88123], length 517

從左到右依次是:時間戳;IP 表示 IPv4(IPv6 顯示 IP6);源位址.源連接埠 > 目的位址.目的連接埠,最後一段數字是連接埠;Flags 是 TCP 標誌;seq 和 ack 是序號和確認號,握手之後 tcpdump 預設改用相對值,加 -S 顯示原始值;win 是接收視窗;length 是這個包攜帶的資料位元組數,不含報頭。

標誌位裡 S 是 SYN(發起連線),點號是 ACK,P 是 PSH(攜帶資料),F 是 FIN(正常關閉),R 是 RST(強制復位)。所以 [S] 是連線請求,[S.] 是伺服器同意建連,[R.] 是拒絕或強制斷開。

ICMP 和 UDP 的輸出更簡單,ping 的序號和連接埠不可達都直接寫在行裡:

10:20:11.004512 IP 198.51.100.7 > 203.0.113.10: ICMP echo request, id 3021, seq 17, length 64
10:20:11.004560 IP 203.0.113.10 > 198.51.100.7: ICMP echo reply, id 3021, seq 17, length 64
10:21:40.770031 IP 203.0.113.10 > 198.51.100.7: ICMP 203.0.113.10 udp port 9999 unreachable, length 36

用 -w 儲存到檔案:-c、-C、-G 控制大小

螢幕輸出適合邊抓邊看,複雜問題要存下來,交給 Wireshark 看重傳、時序和協議細節:

# 寫夠 5000 個包自動退出,檔名帶上日期時間
tcpdump -i eth0 -nn -c 5000 -w /tmp/api-$(date +%m%d-%H%M).pcap 'tcp port 8080'

# 每 300 秒換一個檔案,寫滿 12 個(共 1 小時)後自動退出
tcpdump -i eth0 -nn -G 300 -W 12 -w '/tmp/cap-%Y%m%d-%H%M%S.pcap' 'host 198.51.100.7'

# 從已有的檔案裡只挑出 RST 包,另存一個小檔案
tcpdump -nn -r /tmp/cap-20261222-101500.pcap -w /tmp/rst.pcap 'tcp[tcpflags] & tcp-rst != 0'

# 直接按文字檢視檔案內容
tcpdump -nn -r /tmp/rst.pcap | head -20

幾個容易踩的坑:

  • -w 寫的是二進位制 pcap,不是文字。把螢幕輸出重定向成 tcpdump ... > a.pcap,得到的是文字,Wireshark 打不開;反過來,-w 的檔案用 cat 看是亂碼,要用 tcpdump -r 或 Wireshark 讀。
  • 用 -G 時檔名裡要帶時間格式。不帶 %H%M%S 這類佔位符,每個新檔案都會覆蓋上一個。按大小輪轉用 -C,單位是百萬位元組,配合 -W 限制檔案個數,寫滿後從第一個開始覆蓋。
  • 先估算檔案有多大。1 Gbps 的流量跑滿時每秒 125 MB,完整抓包一分鐘就是約 7.5 GB。只需要看連線建立、重傳、時序這些報頭資訊時,加 -s 128 截短,一般夠裝下乙太網、IP 和 TCP 報頭,檔案能小一個數量級,也不會把業務內容留在磁碟上。
  • 看清停止時的統計。按 Ctrl+C 後,tcpdump 會列印抓到、過濾透過和被核心丟棄的包數。dropped by kernel 不為 0,是 tcpdump 自己沒來得及收,屬於漏抓,不能當成網路丟包;處理辦法是收緊過濾條件、改成寫檔案而不是列印、用 -B 加大緩衝區。

連接埠不通、丟包:兩端同時抓包定位

單點抓包只能說明“這裡看到了什麼”,要回答“包丟在哪”,最有效的辦法是兩端同時抓,用同一組條件對照。

連接埠不通:伺服器和客戶端各抓一份

# 伺服器 203.0.113.10 上:-i any 能看出包從哪塊網路卡進出
tcpdump -i any -nn 'host 198.51.100.7 and tcp port 8080'

# 客戶端 198.51.100.7 上:同時開始抓,再從另一個視窗發起連線
tcpdump -i eth0 -nn 'host 203.0.113.10 and tcp port 8080'
nc -zv -w 3 203.0.113.10 8080

判斷依據有一個前提:在 Linux 上,tcpdump 看到的入方向包發生在本機防火牆處理之前,出方向包則是已經透過了本機防火牆的。對照兩端的輸出:

客戶端看到 伺服器看到 結論 下一步
SYN 反覆重發(Linux 上間隔約 1、2、4 秒) 沒有任何包 包在路上被丟:安全組、機房 ACL、上游防火牆或路由 從伺服器往外逐段排查
SYN 重發 收到 SYN,沒有回應 多半是本機防火牆把 SYN 丟了 查 iptables、nftables 或 firewalld 的入方向規則
收到 [R.] 收到 SYN,回了 [R.] 連接埠上沒有程式監聽 用 ss -lntp 'sport = :8080' 確認服務是否在執行、監聽在哪個位址
SYN 重發 收到 SYN,也發出了 [S.] 回程出了問題:回包從別的網路卡或別的源 IP 發出、路由不對稱被沿途的狀態防火牆丟棄,或交換器的源位址校驗丟掉了源 IP 不屬於該連接埠的包 用 ip route get 198.51.100.7 看回包從哪塊網路卡、用哪個源位址發出
收到 ICMP 不可達 回了 ICMP,或者伺服器上什麼也沒看到 被 REJECT 規則拒絕,或路由不可達 看 ICMP 包的源位址,就知道是哪台裝置拒絕的

第四行最容易被忽略:伺服器明明回了包,客戶端卻收不到,問題不在應用,也不在入方向的防火牆,而在回程。多網路卡、多 IP 的伺服器尤其要查這一項。

丟包:對照 ping 序號判斷去程還是回程

ping 的每個請求都帶遞增的序號,兩端一對就知道丟在哪個方向:

# 1. 伺服器上開始抓,同時存一份文字
tcpdump -i eth0 -nn -l 'icmp and host 198.51.100.7' | tee /tmp/icmp.txt

# 2. 客戶端上發 200 個 ping,記下最後統計的收到數
ping -c 200 -i 0.2 203.0.113.10

# 3. 伺服器上按 Ctrl+C 停止,統計收到的請求數、發出的應答數,並找出缺了哪些序號
grep -c 'echo request' /tmp/icmp.txt
grep -c 'echo reply' /tmp/icmp.txt
awk '/echo request/{for(i=1;i<=NF;i++) if($i=="seq"){s=$(i+1)+0; if(p && s!=p+1) print "缺少 " p+1 " 到 " s-1; p=s}}' /tmp/icmp.txt

假設客戶端顯示 200 個只收到 188 個,對照伺服器上的計數:

伺服器收到請求 伺服器發出應答 客戶端收到 結論
200 200 188 丟在回程,即伺服器到客戶端方向
188 188 188 丟在去程,即客戶端到伺服器方向
200 188 188 伺服器自己沒回:有 ICMP 限速規則或者系統過忙

確定方向之後,把抓包點往中間移動,例如客戶端的出口閘道器、機房邊界裝置,或者在交換器上做連接埠映象,範圍就能逐步縮小。還要注意,不少網路裝置會對 ICMP 限速或低優先順序處理,ping 丟包不一定代表業務丟包;業務是 TCP 的,用 -w 抓一段業務流量,在 Wireshark 裡看重傳比例,結論更可靠。

在管理系統裡怎麼落地

抓包之前,先要知道該在哪台機器、哪個連接埠上抓。Toplink DCIM 的即時流量圖帶異常檢測,網路 TOP 排行能快速定位高佔用的節點;伺服器列表裡直接顯示它接在哪台交換器的哪個連接埠、連接埠速率和 VLAN,需要在交換器側查計數或配映象時,可以在交換器管理裡開啟瀏覽器終端,會話全程錄影。

上面“伺服器回了 SYN-ACK、客戶端卻收不到”的情況,在開啟了源位址校驗的機房裡有一個常見原因:伺服器私自加了一個沒有分配給它的 IP,交換器只放行源 IP 屬於該連接埠的流量,用這個位址回的包被直接丟棄。到 IP 位址管理裡核對這台伺服器名下分配了哪些位址,比在伺服器上反覆抓包更快。如果網路已經斷到 SSH 登不上,就透過 IPMI 遠端管理開啟 VNC 控制檯,在伺服器本地執行 tcpdump 並寫入檔案,等網路恢復後再下載分析。

常見問題

tcpdump 抓包會影響伺服器效能嗎?

加了過濾條件、寫入檔案時開銷很小。在大流量網路卡上不加過濾、把每個包都列印到終端,會明顯佔用 CPU,經 SSH 回傳的輸出還會製造更多流量。生產環境抓包要加過濾,用 -c 或 -G、-W 限定範圍,只看報頭時用 -s 截短。

tcpdump 能抓到 HTTPS 的內容嗎?

能抓到包,但內容是加密的:看得到雙方 IP、連接埠、握手時序,通常還能從 TLS 握手裡看到存取的域名(SNI),看不到 URL 和正文。要分析明文,得在 TLS 終止之後的環節抓,例如反向代理到後端的明文段,或者把會話金鑰匯出給 Wireshark 解密。

Windows 上能用 tcpdump 嗎?

tcpdump 主要用在 Linux、BSD、macOS 上,Windows 上一般不用它,而是裝 Wireshark。Wireshark 自帶命令列版 tshark,用 -i 選網路卡、-f 寫捕獲過濾條件、-w 儲存檔案,捕獲過濾語法和 tcpdump 相同。

想看看在你的機房裡怎麼用?

從一次產品示範開始,梳理你的業務鏈路。

查看價格
服務熱線 400-112-2951

讓我們聊聊你的 IDC 業務

掃碼新增企業微信,預約產品示範或申請試用。

Toplink 企業微信二維碼

長按儲存或使用企業微信 / 微信掃描

也可致電
400-112-2951
Telegram
@TopLink88