3. tcpdump 核心用法:从安装到实战抓 HTTP
抓包分析这行当,tcpdump 是绕不过去的工具。说实话,我见过不少新人一上来就装 Wireshark,觉得图形界面友好。但等你到了生产环境,没图形界面、没鼠标、甚至带宽都快被撑爆的时候,tcpdump 才是你的救命稻草。今天我就带你把这把瑞士军刀玩明白。
本章核心目标:学会 tcpdump 的安装、基础语法、5 个最常用参数,并能独立抓取 HTTP 请求包。
3.1 安装 tcpdump
不同系统安装方式略有差异,但都很简单。我个人习惯在 Linux 服务器上直接用包管理器搞定。
| 系统 | 安装命令 |
|---|---|
| Ubuntu / Debian | sudo apt-get install tcpdump |
| CentOS / RHEL | sudo yum install tcpdump |
| macOS | brew install tcpdump(系统自带旧版) |
| Windows | 安装 WinPcap 或 Npcap,再配合 Wireshark 自带 |
小提示:安装完后先跑一下 tcpdump --version 确认版本。我遇到过 CentOS 6 上默认装的是 3.x 老版本,有些参数行为不一样,建议升级到 4.x 以上。
3.2 基础语法
tcpdump 的语法其实就一句话:
tcpdump [参数] [表达式]
参数控制「怎么抓」,表达式控制「抓什么」。你想想看,这就像钓鱼——参数决定你用多粗的线、多大的钩,表达式决定你在哪个水域下竿。
一个最基础的抓包命令长这样:
sudo tcpdump -i eth0
这表示监听 eth0 网卡上的所有流量。嗯,这里要注意:不加任何过滤条件的话,你会被海量数据淹没。我刚开始学的时候就这么干过,结果终端刷屏刷到怀疑人生。
3.3 五大常用参数详解
tcpdump 参数很多,但真正高频使用的就 5 个。我把它们列出来,每个都说说我的使用心得。
| 参数 | 作用 | 示例 |
|---|---|---|
-i |
指定监听的网卡接口 | -i eth0、-i any |
-n |
不解析域名,直接显示 IP | -n 避免 DNS 查询拖慢抓包 |
-X |
以十六进制和 ASCII 显示包内容 | -X 看应用层数据 |
-w |
将抓到的包写入文件 | -w capture.pcap |
-r |
从文件读取包进行分析 | -r capture.pcap |
3.3.1 -i:选对网卡
首先你得知道机器上有哪些网卡。用 tcpdump -D 可以列出所有可用接口。
$ tcpdump -D
1.eth0 [Up, Running]
2.lo [Up, Running, Loopback]
3.any (Pseudo-device that captures on all interfaces)
我个人习惯用 -i any 来抓所有接口的流量,省得来回切换。但要注意,any 接口在某些模式下(比如混杂模式)行为略有不同,生产环境建议指定具体网卡。
3.3.2 -n:别让 DNS 拖后腿
这个参数我几乎每次都加。为什么?因为 tcpdump 默认会做反向 DNS 查询,把 IP 解析成域名。这在网络不通或 DNS 慢的时候,会让抓包变得奇慢无比。
我曾经在排查一个 DNS 故障时,忘了加 -n,结果 tcpdump 自己卡在 DNS 查询上,包都抓不全。从那以后,-n 就成了我的肌肉记忆。
# 不加 -n,tcpdump 会尝试解析域名
sudo tcpdump -i eth0
# 加 -n,直接显示 IP,速度快 10 倍
sudo tcpdump -i eth0 -n
3.3.3 -X:看穿包的内容
-X 参数会同时显示十六进制和 ASCII 内容。这对分析应用层协议特别有用,比如 HTTP 的请求头和响应体。
sudo tcpdump -i eth0 -n -X port 80
输出大概长这样:
0x0000: 4500 0054 3a2b 4000 4006 1c3c 0a00 0002 E..T:+@.@..<....
0x0010: 0a00 0001 0050 9a7b 0000 0000 0000 0000 .....P.{........
0x0020: 5002 2000 3f3f 0000 4745 5420 2f20 4854 P..??..GET./.HT
0x0030: 5450 2f31 2e31 0d0a 486f 7374 3a20 7777 TP/1.1..Host:.ww
0x0040: 772e 6578 616d 706c 652e 636f 6d0d 0a0d w.example.com...
0x0050: 0a .
看到右边那列了吗?GET / HTTP/1.1 和 Host: www.example.com 清清楚楚。这就是 HTTP 请求的原始内容。
注意:-X 会输出大量数据,如果流量很大,建议先保存到文件再用 -r 分析,否则终端会刷爆。
3.3.4 -w 和 -r:保存与回放
这两个参数是黄金搭档。-w 把包存成 pcap 文件,-r 读回来分析。
# 抓包并保存
sudo tcpdump -i eth0 -n -w http_capture.pcap port 80
# 事后分析
tcpdump -r http_capture.pcap -n -X
为什么推荐先保存再分析?原因有三:
- 不影响现场:抓包时 CPU 和内存开销最小化
- 反复分析:同一个包可以用不同参数看多次
- 分享协作:把 pcap 发给同事,大家用 Wireshark 一起看
我记得有一次线上故障,我现场抓了 5 分钟的包,保存下来后慢慢分析,最终定位到一个第三方 SDK 发了异常大的请求体。如果当时直接终端看,根本来不及反应。
3.4 实战:抓取 HTTP 包
理论讲完了,咱们直接上手。下面是一个完整的 HTTP 抓包实战流程。
3.4.1 场景描述
假设我们要抓取本机访问 http://example.com 的 HTTP 请求和响应。目标:看到完整的请求头和响应头。
3.4.2 步骤一:启动抓包
sudo tcpdump -i eth0 -n -X -w http_demo.pcap port 80 or port 443
这里我加了 port 80 or port 443,只抓 HTTP 和 HTTPS 流量。HTTPS 虽然内容加密,但握手过程和 IP 信息还是有分析价值的。
3.4.3 步骤二:发起请求
另开一个终端,用 curl 模拟请求:
curl http://example.com
3.4.4 步骤三:停止抓包
按 Ctrl+C 停止 tcpdump。你会看到类似这样的统计:
9 packets captured
18 packets received by filter
0 packets dropped by kernel
注意看 packets dropped by kernel,如果这个数字很大,说明你的抓包缓冲区不够,需要加 -B 参数调大。
3.4.5 步骤四:分析结果
tcpdump -r http_demo.pcap -n -X
你会看到类似这样的输出:
13:45:22.123456 IP 192.168.1.100.54321 > 93.184.216.34.80: Flags [S], seq 1234567890, ...
13:45:22.123789 IP 93.184.216.34.80 > 192.168.1.100.54321: Flags [S.], seq 987654321, ...
13:45:22.124012 IP 192.168.1.100.54321 > 93.184.216.34.80: Flags [.], ack 1, ...
13:45:22.124256 IP 192.168.1.100.54321 > 93.184.216.34.80: Flags [P.], seq 1:78, ack 1, ...
0x0000: 4745 5420 2f20 4854 5450 2f31 2e31 0d0a GET./.HTTP/1.1..
0x0010: 486f 7374 3a20 6578 616d 706c 652e 636f Host:.example.co
0x0020: 6d0d 0a55 7365 722d 4167 656e 743a 2063 m..User-Agent:.c
0x0030: 7572 6c2f 372e 3638 2e30 0d0a 4163 6365 url/7.68.0..Acce
0x0040: 7074 3a20 2a2f 2a0d 0a0d 0a pt:.*/*....
看懂了吗?前三行是 TCP 三次握手,第四行开始才是 HTTP 请求内容。右边 ASCII 区能看到完整的 GET / HTTP/1.1 和请求头。
实战技巧:如果只想看 HTTP 请求行和响应行,可以用 -A 参数只显示 ASCII 内容,比 -X 更清爽。
3.5 本章知识体系
下面这张图帮你梳理 tcpdump 的核心脉络:
3.6 避坑指南
最后分享几个我踩过的坑,你遇到了能少走弯路。
坑一:权限不足
tcpdump 需要 root 权限才能抓包。如果你忘了加 sudo,会报错 permission denied。我刚开始用的时候经常犯这个错,后来直接 alias 了一个 sudo tcpdump 的快捷命令。
坑二:缓冲区溢出
在高流量环境下,tcpdump 默认缓冲区可能不够,导致丢包。你会看到 packets dropped by kernel 不为 0。解决办法是加 -B 4096 把缓冲区设到 4MB。
坑三:表达式写错
tcpdump 的表达式语法比较严格。比如 port 80 and host 192.168.1.1 和 port 80 && host 192.168.1.1 是等价的,但 and 和 && 不能混用。我建议统一用 and、or、not,可读性更好。
好了,tcpdump 的核心用法就这些。记住五个参数:-i 选网卡、-n 禁 DNS、-X 看内容、-w 存文件、-r 读文件。配合端口过滤,抓 HTTP 包就是分分钟的事。