第3章:tcpdump 命令行抓包——Linux 下必会的抓包工具
说到抓包,很多新手第一反应是 Wireshark。但在服务器、嵌入式、或者没有图形界面的环境里,tcpdump 才是真正的王者。我最早接触它是在一次线上服务延迟排查中,没法装图形工具,全靠 tcpdump 拉流量分析。嗯,从那以后我就把它当成随身“听诊器”了。
这一章我们直接上手 tcpdump,从常用选项到过滤表达式,再到保存 pcap 文件,把抓包基础打扎实。别看它命令行黑乎乎,用熟了比 Wireshark 还顺手。
3.1 基本用法与常用选项
tcpdump 的语法很简单:tcpdump [选项] [过滤表达式]。不加任何选项,默认抓第一个网卡的所有包。但这样会刷屏,我们得学会控制。
| 选项 | 作用 | 我的常用场景 |
|---|---|---|
-i eth0 | 指定抓取 eth0 网卡 | 多网卡机器选接口 |
-n | 不解析域名,只显示 IP | 避免 DNS 延迟,抓包更快 |
-nn | 不解析域名+不解析端口名 | 我排查时必加,少干扰 |
-c 100 | 抓 100 个包后自动停止 | 测试场景,防止刷屏 |
-s 0 | 抓完整包(默认 262144 字节) | 分析 payload 时用 |
-w file.pcap | 保存成 pcap 文件 | 保留证据,后续分析 |
-r file.pcap | 读取 pcap 文件 | 离线分析或分享抓包 |
-v / -vv / -vvv | 增加输出详细度 | 查协议细节时用 -vv |
个人习惯组合:tcpdump -i any -nn -c 100 -s 0。any 可以抓所有接口流量,-nn 避免 DNS 干扰,-c 控制包量。我调试时经常先跑这个组合看看大局。
避坑提醒:我曾经在抓大流量时忘了加 -c,结果终端刷了几十万行卡死,不得不强杀进程。所以非永久监听一定要加 -c 或 -G 轮转保存。
3.2 捕获过滤表达式——BPF 语法
tcpdump 最强大的地方是它的过滤能力,底层用的是 Berkeley Packet Filter(BPF)。说白了就是写一个“条件”,让内核只把符合条件的包丢给用户态。效率极高。
表达式由原语(primitive)和连接词(and/or/not)组成。常用的原语按类型分:
| 类型 | 示例 | 含义 |
|---|---|---|
| 主机 | host 192.168.1.1 | 匹配源或目标 IP 为 192.168.1.1 |
| 网络 | net 10.0.0.0/8 | 匹配 10.x.x.x 网段 |
| 端口 | port 80 | 匹配源或目标端口 80 |
| 协议 | tcp / udp / icmp | 只抓该协议包 |
| 方向 | src port 53 | 只抓源端口 53(DNS 响应) |
3.3 组合过滤:从简单到实战
单条原语不够用,得组合。比如我要抓从 192.168.1.100 发往 10.0.0.1 的 HTTP 请求:
tcpdump -i eth0 -nn tcp and host 192.168.1.100 and host 10.0.0.1 and port 80
其实可以简写成 tcp and src 192.168.1.100 and dst 10.0.0.1 and port 80。我个人更爱用 host 加方向,可读性好一点。你想想看,如果你只关心目标端口 443,可以用 dst port 443,少抓很多无关包。
注意:过滤表达式里不要乱加括号,tcpdump 对括号的转义很敏感。建议用单引号把整个表达式包起来,比如 tcpdump 'tcp and port 80',避免 shell 解释特殊字符。
3.4 保存 pcap 文件——把证据留下来
抓包最重要的目的是回放分析。tcpdump 保存 pcap 文件的命令是:
tcpdump -i eth0 -nn -s 0 -w capture.pcap port 443
这会生成一个标准 pcap 文件,可以用 Wireshark、tshark 或者 tcpdump 自己打开:
tcpdump -r capture.pcap -nn
保存时我建议:
- 始终加
-s 0抓完整包,否则裁剪后的包无法分析应用层数据。 - 使用
-C 100让文件到达 100MB 后自动轮转,避免单文件过大。 - 配合
-W 10限制轮转文件总数,防止磁盘写爆。
举个例子,监控 DNS 流量,每 100MB 轮转,最多保留 5 个文件:
tcpdump -i eth0 -nn -s 0 -C 100 -W 5 -w dns_trace.pcap port 53
这是我线上常用的一招。有一次排查 DNS 解析慢,直接这样抓了 10 分钟,然后拉下来用 Wireshark 看响应时间分布,一目了然。
3.5 本章知识体系
3.6 实战小案例:抓一次 HTTP 请求的完整流程
假设你想看看 wget 请求 www.example.com 时到底发了什么包。可以这样:
- 先确定接口:
ip addr看哪个网卡有流量。 - 写过滤表达式:抓目标端口 80,并且只抓与目标 IP 相关的包(先 ping 一下得到 IP)。
- 保存 pcap,不刷屏:
tcpdump -i eth0 -nn -s 0 -c 20 -w http_test.pcap host 93.184.216.34 and port 80
- 在另一个终端执行
wget http://www.example.com。 - 抓完 20 个包后 tcpdump 自动退出,查看文件:
tcpdump -r http_test.pcap -nn -vv
你会看到三次握手、HTTP GET 请求、响应以及挥手。我用这个案例教过入门同事,他们都说比看文档好理解多了。
小技巧:如果想看 HTTP 协议内容,可以加 -A 参数以 ASCII 格式打印包 payload,或者保存后用 Wireshark 的“Follow TCP Stream”功能。我个人偏爱后者,因为可读性更好。
3.7 常见错误与排查
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 抓了几万个包什么都没看到 | 过滤表达式写错了 | 先不加表达式跑一次确认接口有流量 |
| 保存的 pcap 在 Wireshark 里打不开 | tcpdump 版本低,格式不兼容 | 用 file 命令查看真实格式,升级 tcpdump |
| “Permission denied” | 普通用户无权限 | 加 sudo 或者赋予 CAP_NET_RAW 能力 |
| 抓包文件太大导致磁盘满 | 没加 -c 或 -C 轮转 | 生产环境必须加轮转参数,配合监控报警 |
我记得有一次同事在线上服务器抓包,忘了加 -c,又没进 root 用户,结果权限报错后还被领导批评。从那以后我的抓包脚本都会写一行检查权限的提示。
tcpdump 的命令行艺术就在这几个选项和表达式的组合里。你多练几次,形成自己的“组合拳”,以后遇到网络问题,手指自然就敲出来了。