概述
凌晨两点,你被电话吵醒。订单系统大面积超时,但 CPU 正常、内存正常、磁盘 IO 正常。重启服务没用,回滚也没用。你盯着监控大盘,一切指标都是绿的,唯独用户在骂。
十有八九,是网络层面的问题。这时候你需要的是一双能看见数据包的眼睛。
tcpdump 就是这双眼睛。它不是什么新工具——1990 年代就有了——但到今天仍然是 Linux 上最硬核的网络诊断手段。说直白点:如果你只会看监控图表、不会抓包,那遇到网络层问题时你就是个瞎子。
这篇文章不讲花哨的概念,就讲实战:tcpdump 怎么抓、BPF 过滤器怎么写、pcap 文件怎么用 Wireshark 分析、TCP 三次握手和 TLS 握手在抓包里长什么样、以及那些我踩过坑才学会的技巧。
tcpdump 基础:先搞懂你在抓什么
什么是抓包
网卡收到的每一个数据帧,正常情况下只有操作系统内核会处理,用户态程序看不到原始内容。抓包就是把网卡的混杂模式(promiscuous mode)打开,让内核把所有流经网卡的数据包副本都交给抓包工具。
打个比方:正常情况下网卡像个只读收件箱的快递员,只把发给你的包裹送上门。开了混杂模式后,它变成监控摄像头,把整条街上经过的所有包裹都拍下来——不管是不是给你的。
tcpdump vs Wireshark:分工不同
| 对比维度 | tcpdump | Wireshark |
|---|---|---|
| 运行环境 | 服务器命令行,SSH 即可 | 需要图形界面 |
| 资源占用 | 极低(几 MB 内存) | 较高(GUI 程序) |
| 核心能力 | 捕获+保存 pcap | 深度协议解析+交互式分析 |
| 过滤语法 | BPF(Berkeley Packet Filter) | 显示过滤器(Display Filter) |
| 适用场景 | 生产服务器实时抓包、长期后台捕获 | 本地分析 pcap 文件、协议细节排查 |
| 自动化 | 可写成脚本、对接告警 | 不适合自动化 |
实际工作中的标准流程:服务器上用 tcpdump 抓包保存成 pcap 文件,scp 下载到本地,用 Wireshark 打开分析。这个组合我在过去七年里用了不下五百次。
安装与权限
大多数 Linux 发行版预装了 tcpdump。检查一下:
which tcpdump || echo "未安装"
tcpdump --version
没装的话:
# Debian/Ubuntu
sudo apt-get install -y tcpdump
# CentOS/RHEL
sudo yum install -y tcpdump
权限管理是个坑。tcpdump 需要 CAP_NET_RAW 能力才能抓包,默认只有 root 能用。但生产环境你不可能给每个人都 root 权限。推荐做法是配置 sudo 白名单:
# 创建专用 sudoers 配置
sudo visudo -f /etc/sudoers.d/tcpdump
# 内容:允许 ops 组的成员免密运行 tcpdump
%ops ALL=(root) NOPASSWD: /usr/sbin/tcpdump
这样运维人员用 sudo tcpdump 就能抓包,不需要完整 root 权限。别图省事直接 chmod +s /usr/sbin/tcpdump——那是给所有用户开了 root 后门。
核心参数速查
先列一张表,后面逐个展开。
| 参数 | 全称 | 作用 | 示例 |
|---|---|---|---|
-i | interface | 指定网卡 | tcpdump -i eth0 |
-n | numeric | 不解析主机名 | tcpdump -n |
-nn | 不解析主机名和端口名 | tcpdump -nn | |
-v | verbose | 详细输出(可叠加 -vv -vvv) | tcpdump -vvv |
-c | count | 抓 N 个包后停止 | tcpdump -c 100 |
-w | write | 保存为 pcap 文件 | tcpdump -w out.pcap |
-r | read | 读取 pcap 文件 | tcpdump -r out.pcap |
-s | snaplen | 截断长度(默认 262144) | tcpdump -s 0(不截断) |
-A | ASCII | 以 ASCII 显示包内容 | tcpdump -A |
-X | hex+ASCII | 十六进制+ASCII 显示 | tcpdump -X |
-G | rotate | 按时间轮转文件 | tcpdump -G 60 -w out_%Y%m%d_%H%M%S.pcap |
-W | count | 轮转文件数量上限 | tcpdump -W 10 -G 60 -w out.pcap |
-D | list | 列出可用网卡 | tcpdump -D |
常用参数组合
# 最常用的生产抓包命令
sudo tcpdump -i eth0 -nn -s 0 -w capture.pcap
# 实时看 HTTP 流量(仅文本协议适用)
sudo tcpdump -i eth0 -nn -A -s 0 'tcp port 80'
# 抓 1000 个包就停
sudo tcpdump -i eth0 -nn -c 1000 -w capture.pcap
# 按小时轮转,最多保留 24 个文件
sudo tcpdump -i eth0 -nn -s 0 -G 3600 -W 24 -w /var/log/tcpdump/capture_%Y%m%d_%H.pcap
-n 和 -nn 为什么重要
不加 -n,tcpdump 会尝试把 IP 地址反解成主机名。在生产环境中,这意味着每抓一个包都要发一个 DNS 查询。如果你正在排查的就是 DNS 问题——恭喜,你的抓包工具本身制造了 DNS 风暴。
加 -nn 更彻底:连端口号都不解析。不加的话 tcpdump 会把 443 显示成 https,看起来方便,但在写过滤规则时容易混淆。-nn 强制全数字输出,干净利落。
BPF 过滤器:精准捕获的艺术
BPF(Berkeley Packet Filter)是 tcpdump 的过滤引擎。它在内核态运行,不符合规则的数据包直接被丢弃,不会拷贝到用户态。这意味着 BPF 过滤的性能极高——你可以用 BPF 在万兆网卡上实时过滤而不丢包。
过滤语法基础
BPF 过滤表达式由三部分组成:
类型 方向 协议 值
host src tcp 192.168.1.100
| 组成部分 | 可选值 | 说明 |
|---|---|---|
| 类型 | host、net、port、portrange | 指定按什么维度过滤 |
| 方向 | src、dst、src or dst(默认) | 指定源或目的 |
| 协议 | tcp、udp、icmp、arp、ip、ip6、ether | 限定协议 |
| 逻辑 | and、or、not | 组合条件 |
常用过滤示例
# 抓特定主机的所有流量
sudo tcpdump -i eth0 -nn host 10.0.0.5
# 抓源 IP 为 10.0.0.5 的流量
sudo tcpdump -i eth0 -nn src host 10.0.0.5
# 抓目的端口为 443 的 TCP 流量
sudo tcpdump -i eth0 -nn 'tcp dst port 443'
# 抓两个主机之间的通信
sudo tcpdump -i eth0 -nn 'host 10.0.0.5 and host 10.0.0.6'
# 抓 DNS 查询(UDP 53)
sudo tcpdump -i eth0 -nn 'udp port 53'
# 抓 ICMP(ping)
sudo tcpdump -i eth0 -nn icmp
# 排除 SSH 自身的流量(避免抓包产生循环)
sudo tcpdump -i eth0 -nn 'not port 22'
# 抓特定网段
sudo tcpdump -i eth0 -nn 'net 10.0.0.0/24'
# 组合过滤:10.0.0.5 到 10.0.0.6 的 443 端口流量
sudo tcpdump -i eth0 -nn 'host 10.0.0.5 and host 10.0.0.6 and tcp port 443'
TCP 标志位过滤
这是排查连接问题的关键。TCP 报文头中有 6 个标志位,BPF 可以精确过滤:
| 标志位 | BPF 写法 | 含义 |
|---|---|---|
| SYN | tcp[tcpflags] & tcp-syn != 0 | 连接请求 |
| ACK | tcp[tcpflags] & tcp-ack != 0 | 确认 |
| FIN | tcp[tcpflags] & tcp-fin != 0 | 关闭连接 |
| RST | tcp[tcpflags] & tcp-rst != 0 | 重置连接 |
| PSH | tcp[tcpflags] & tcp-push != 0 | 推送数据 |
| URG | tcp[tcpflags] & tcp-urg != 0 | 紧急数据 |
# 只抓 SYN 包(看谁在发起连接)
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'
# 只抓 RST 包(连接被重置)
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
# 只抓 FIN 包(谁在关闭连接)
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-fin != 0'
实测发现,SYN 过滤在排查连接超时问题时极为高效。有一次我遇到一个微服务偶发超时,监控看不出异常。用 SYN 过滤抓了五分钟,发现客户端在 SYN 发出后等了 3 秒没收到 SYN-ACK,然后重试——服务端确实没回。进一步排查发现是服务端 conntrack 表满了。
抓包大小过滤
# 抓大于 1400 字节的包(排查大包分片问题)
sudo tcpdump -i eth0 -nn 'greater 1400'
# 抓小于 60 字节的包(可能是异常的 ACK 包)
sudo tcpdump -i eth0 -nn 'less 60'
过滤器的常见陷阱
陷阱一:括号没引号包裹
# 错误写法——shell 会吃掉括号
sudo tcpdump -i eth0 host 10.0.0.5 and (port 80 or port 443)
# 正确写法——用引号包裹
sudo tcpdump -i eth0 'host 10.0.0.5 and (port 80 or port 443)'
陷阱二:方向写反
src host 10.0.0.5 是源 IP 是 10.0.0.5,dst host 10.0.0.5 是目的 IP 是 10.0.0.5。写反了就是抓错方向,对着空气分析半天。
陷阱三:忘了排除 SSH 流量
SSH 到服务器上跑 tcpdump,tcpdump 本身的输出也会经过 SSH 通道。如果不排除 22 端口,你会抓到自己的 SSH 流量,在终端上形成正反馈循环,刷屏到死。
# 保险写法
sudo tcpdump -i eth0 -nn 'not port 22 and not port 53' -w capture.pcap
抓包策略:生产环境不能瞎抓
磁盘和性能考量
在万兆网卡上全量抓包,一分钟就能产生几个 GB 的数据。如果不加过滤直接抓,磁盘很快就会被撑满。这不是理论——我见过有人 tcpdump -i eth0 -w capture.pcap 挂了一晚上,第二天早上发现 / 分区 100%,业务全部挂了。
生产抓包铁律:
- 永远加过滤条件,哪怕只是排除 SSH 流量
- 用
-c限制包数量,或者用-G+-W做轮转 - 写到专用目录,别写 /tmp——容器环境 /tmp 可能是 tmpfs,吃内存
- 监控磁盘剩余空间,写个简单脚本兜底
# 安全的生产抓包方案
sudo mkdir -p /var/log/tcpdump
sudo tcpdump -i eth0 -nn -s 0 \
-G 300 -W 48 \
-w /var/log/tcpdump/capture_%Y%m%d_%H%M%S.pcap \
'host 10.0.0.5 and tcp port 443'
# -G 300:每 5 分钟轮转一个文件
# -W 48:最多保留 48 个文件(4 小时)
# 过滤特定主机和端口,不会抓到无关流量
snaplen 的坑
-s 参数控制每个包截取多少字节。默认值在不同版本不同:
- 老版本默认 68 或 96 字节——只能看到头部
- 新版本默认 262144 字节——基本是全包
如果你用老版本 tcpdump 抓 TLS 握手,证书包经常超过 1500 字节,snaplen 设小了就截断了 ServerHello 里的证书链。排查 TLS 问题时一定加 -s 0:
# -s 0 表示不截断,抓完整包
sudo tcpdump -i eth0 -nn -s 0 -w tls_capture.pcap 'tcp port 443'
Wireshark 分析:从 pcap 到根因
tcpdump + Wireshark 协同工作流
# 步骤1:服务器上抓包
sudo tcpdump -i eth0 -nn -s 0 -w /tmp/capture.pcap 'host 10.0.0.5 and tcp port 443'
# 步骤2:下载到本地
scp user@server:/tmp/capture.pcap ./
# 步骤3:本地用 Wireshark 打开
wireshark capture.pcap &
如果你不想每次都 scp,可以用 SSH 管道实时传输:
# 远程抓包,本地直接用 Wireshark 打开
ssh user@server 'sudo tcpdump -i eth0 -nn -s 0 -w - "host 10.0.0.5"' | wireshark -k -i -
这条命令在 macOS 和 Linux 上都能用。-w - 让 tcpdump 把 pcap 数据写到 stdout,管道传给 Wireshark 的 stdin,-k -i - 让 Wireshark 从 stdin 读取并立即开始。实测延迟在 1-2 秒左右,排查实时问题非常顺手。
Wireshark 显示过滤器
注意:Wireshark 的显示过滤器和 tcpdump 的 BPF 过滤器语法完全不同。这是新手最常见的困惑。
| 对比 | BPF(tcpdump) | Display Filter(Wireshark) |
|---|---|---|
| IP 地址 | host 10.0.0.5 | ip.addr == 10.0.0.5 |
| 端口 | port 443 | tcp.port == 443 |
| TCP SYN | tcp[tcpflags] & tcp-syn != 0 | tcp.flags.syn == 1 |
| TCP RST | tcp[tcpflags] & tcp-rst != 0 | tcp.flags.reset == 1 |
| 协议 | tcp | tcp |
| 组合 | and / or / not | and / or / not(同) |
常用的 Wireshark 显示过滤器:
# 只看 HTTP 请求
http.request
# 只看 TLS 握手
tls.handshake
# 只看 TCP 重传
tcp.analysis.retransmission
# 只看 TCP 重复 ACK
tcp.analysis.duplicate_ack
# 查看特定 HTTP 路径
http.request.uri contains "api/order"
# 查看特定 TCP 流
tcp.stream eq 42
# 查看连接重置
tcp.flags.reset == 1
右键追踪 TCP 流
这是 Wireshark 最常用的功能。在一个 TCP 数据包上右键 → Follow → TCP Stream,Wireshark 会把这条 TCP 连接的所有数据包按时间顺序拼成一段对话,左边是客户端发的,右边是服务端发的。
对于 HTTP 等明文协议,这个功能让你能像读聊天记录一样看到完整的请求-响应过程。但 TLS 流量是加密的,追踪 TCP 流只能看到加密后的数据。
协议解析实战
TCP 三次握手在抓包里长什么样
一个正常的 TCP 连接建立过程,抓包看是这样的:
10:30:01.123456 IP 10.0.0.5.54321 > 10.0.0.6.443: Flags [S], seq 1234567890, win 64240, [mss 1460,sackOK,TS val 1234567890 ecr 0,nop,wscale 7], length 0
10:30:01.123567 IP 10.0.0.6.443 > 10.0.0.5.54321: Flags [S.], seq 9876543210, ack 1234567891, win 65160, [mss 1460,sackOK,TS val 9876543210 ecr 1234567890,nop,wscale 7], length 0
10:30:01.123578 IP 10.0.0.5.54321 > 10.0.0.6.443: Flags [.], ack 9876543211, win 502, length 0
解读:
| 步骤 | 标志 | 含义 |
|---|---|---|
| 第1包 | [S] (SYN) | 客户端:“我想连你,我的序号是 1234567890” |
| 第2包 | [S.] (SYN+ACK) | 服务端:“收到,我同意,我的序号是 9876543210,确认你的 1234567891” |
| 第3包 | [.] (ACK) | 客户端:“收到你的确认,连接建立” |
标志位速查:
[S]= SYN[.]= ACK[S.]= SYN + ACK[P.]= PSH + ACK(有数据要传)[F.]= FIN + ACK(我要关了)[R.]= RST + ACK(连接异常,重置)[R]= RST(直接重置,不含 ACK)
排查 TCP 连接超时
如果服务超时但不知道是哪一层的问题,先抓 SYN 包:
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0' -c 100
正常情况下,每个 SYN 后面应该紧跟一个 SYN-ACK。如果只看到 SYN 没有 SYN-ACK,说明:
| 现象 | 可能原因 | 下一步 |
|---|---|---|
| SYN 发出,无任何回应 | 防火墙丢弃、路由不通、服务未启动 | 检查 iptables 规则、路由表、服务状态 |
| SYN 发出,收到 RST | 服务未监听该端口、被 TCP wrapper 拒绝 | 检查 ss -tlnp 确认端口监听状态 |
| SYN 发出,SYN-ACK 返回但后续无 ACK | 客户端问题,可能 NAT 超时或路由不对称 | 在客户端抓包对比 |
| 大量 SYN 无 SYN-ACK | 服务端 SYN backlog 满了(SYN flood 攻击或突发连接) | 检查 netstat -s | grep SYNs |
排查 TLS 握手失败
TLS 握手比 TCP 复杂得多。一次完整的 TLS 1.2 握手需要 2 个 RTT:
# 抓 TLS 握手流量
sudo tcpdump -i eth0 -nn -s 0 -w tls.pcap 'tcp port 443'
用 Wireshark 打开后,过滤 tls.handshake,你会看到:
| 步骤 | 消息 | 方向 | 内容 |
|---|---|---|---|
| 1 | ClientHello | 客户端→服务端 | 支持的密码套件、TLS 版本、SNI(域名) |
| 2 | ServerHello | 服务端→客户端 | 选定的密码套件、TLS 版本 |
| 3 | Certificate | 服务端→客户端 | 服务器证书链 |
| 4 | ServerKeyExchange | 服务端→客户端 | DH 参数(如使用 ECDHE) |
| 5 | ServerHelloDone | 服务端→客户端 | “我的消息发完了” |
| 6 | ClientKeyExchange | 客户端→服务端 | 客户端的 DH 参数 |
| 7 | ChangeCipherSpec | 客户端→服务端 | “后续消息开始加密” |
| 8 | Finished | 客户端→服务端 | 加密的握手完成验证 |
| 9 | ChangeCipherSpec | 服务端→客户端 | “我也要开始加密了” |
| 10 | Finished | 服务端→客户端 | 加密的握手完成验证 |
常见 TLS 问题排查:
场景一:证书过期
在 Wireshark 中过滤 tls.handshake.type == 11(Certificate),展开证书详情,检查 validity.not_after 字段。如果发现证书已过期,就是这个问题。
tcpdump 命令行也能看:
# 用 tshark 解析 TLS 证书
tshark -r tls.pcap -Y "tls.handshake.type == 11" -T fields -e tls.handshake.certificate
场景二:SNI 不匹配
SNI(Server Name Indication)是客户端在 ClientHello 中携带的目标域名。如果服务端配置了多个虚拟主机但 SNI 没配对,可能返回错误的证书。过滤 tls.handshake.type == 1(ClientHello)查看 SNI 字段:
tshark -r tls.pcap -Y "tls.handshake.type == 1" -T fields -e tls.handshake.extensions_server_name
场景三:密码套件协商失败
如果 ClientHello 发出后直接收到 Alert 消息,说明密码套件没谈拢。检查 ClientHello 中的 Cipher Suites 列表和服务端支持的列表是否交集为空。
HTTP 流量分析
虽然现在大部分流量都走 HTTPS 了,但内部服务间的 HTTP 通信仍然常见。用 -A 参数可以直接看到 HTTP 内容:
sudo tcpdump -i eth0 -nn -A -s 0 'tcp port 80 and host 10.0.0.5'
输出中你会看到类似这样的内容:
GET /api/v1/orders?status=pending HTTP/1.1
Host: order-service.internal
User-Agent: curl/7.81.0
Accept: */*
Connection: keep-alive
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 142
{"orders": [...]}
但别在生产环境长期开 -A 输出到终端——不仅性能差,还可能把敏感信息(token、密码)暴露在终端日志里。
DNS 问题排查
DNS 是网络问题的高发区。一条 DNS 查询的抓包很简单:
sudo tcpdump -i eth0 -nn -l 'udp port 53' | grep -E 'A\?|AAAA\?'
-l 是行缓冲模式,让输出实时刷新。A? 表示 A 记录查询,AAAA? 表示 IPv6 查询。
# 抓 DNS 查询和响应
sudo tcpdump -i eth0 -nn 'udp port 53' -c 20
输出示例:
12:30:01.123 IP 10.0.0.5.43210 > 8.8.8.8.53: 45231+ A? api.example.com. (33)
12:30:01.156 IP 8.8.8.8.53 > 10.0.0.5.43210: 45231 2/0/0 A 93.184.216.34, A 93.184.216.35 (69)
45231+中的+表示递归查询2/0/0表示 2 个回答记录、0 个权威记录、0 个附加记录- 如果看到响应是
0/0/0或0/1/0(NXDOMAIN),说明域名不存在
实战案例
案例一:服务间调用偶发 502
现象:A 服务调 B 服务的 HTTP 接口,偶发 502 Bad Gateway,频率约千分之一。
排查过程:
# 在 B 服务所在机器抓包
sudo tcpdump -i eth0 -nn -s 0 -w 502.pcap 'host <A的IP> and tcp port 8080'
等复现后用 Wireshark 打开,过滤 tcp.analysis.retransmission or tcp.analysis.duplicate_ack or tcp.flags.reset == 1,发现:
- TCP 三次握手正常
- 客户端发送 HTTP 请求后,服务端 ACK 了但没返回数据
- 客户端等待 15 秒后发送 FIN 关闭连接
- Nginx(反向代理)在 B 服务超时后返回 502
根因:B 服务的连接池配置太小,高峰期连接被排队等待,超过 Nginx 的 proxy_read_timeout。不需要改网络,调大连接池即可。
案例二:跨机房延迟突增
现象:北京机房到上海机房的 RPC 调用,平时 30ms,突然变成 200ms+。
# 双向抓包
sudo tcpdump -i eth0 -nn -s 0 -w latency.pcap 'host <上海机房IP>'
Wireshark 打开后用 tcp.analysis.ack_rtt 过滤器查看 RTT 分布。发现部分包的 ACK RTT 超过 200ms,且这些包的 TTL 值比正常包多了 3 跳。
根因:动态路由策略变更,部分流量绕行了额外 3 跳,导致延迟增加。联系网络组修正路由策略后恢复。
案例三:ARP 欺骗导致间歇性断网
现象:某台服务器间歇性无法访问网关,每次持续 10-30 秒自动恢复。
# 抓 ARP 包
sudo tcpdump -i eth0 -nn arp
正常情况下,ARP 缓存有效期内不会频繁发 ARP 请求。但抓包发现:
14:20:01 IP (via eth0) arp who-has 10.0.0.1 tell 10.0.0.5
14:20:01 IP (via eth0) arp reply 10.0.0.1 is-at 00:11:22:33:44:55 ← 正常网关MAC
14:20:03 IP (via eth0) arp reply 10.0.0.1 is-at 66:77:88:99:aa:bb ← 异常MAC!
根因:另一台机器配置了错误 IP,ARP 响应抢先覆盖了正确网关的 MAC 地址,导致流量发往错误机器。修正那台机器的 IP 配置后恢复正常。
tshark:命令行版的 Wireshark
不是所有场景都能用 GUI。tshark 是 Wireshark 的命令行版本,支持完整的协议解析能力,适合在服务器上直接分析 pcap 文件。
# 安装
sudo apt-get install -y tshark # Debian/Ubuntu
sudo yum install -y wireshark # CentOS/RHEL(包含 tshark)
# 统计 pcap 中的协议分布
tshark -r capture.pcap -q -z io,phs
# 提取所有 HTTP 请求的 URL
tshark -r capture.pcap -Y "http.request" -T fields -e http.host -e http.request.uri
# 统计 TCP 重传
tshark -r capture.pcap -Y "tcp.analysis.retransmission" | wc -l
# 查看 TLS SNI
tshark -r capture.pcap -Y "tls.handshake.type == 1" -T fields -e tls.handshake.extensions_server_name
# 统计各 IP 的包数量(Top 10)
tshark -r capture.pcap -q -z conv,ip | sort -t'|' -k1 -rn | head -10
高级技巧
用 ngrep 抓特定内容
如果你只想看包含特定字符串的流量,ngrep 比 tcpdump 方便:
# 安装
sudo apt-get install -y ngrep
# 抓包含 "error" 的 HTTP 流量
sudo ngrep -d eth0 -W byline 'error' 'tcp port 80'
# 抓包含特定 token 的请求
sudo ngrep -d eth0 -W byline 'Authorization: Bearer eyJ...' 'tcp port 443'
但注意,ngrep 只对明文协议有效。HTTPS 流量加密了,ngrep 看不到内容。
用 ss + tcpdump 联合诊断
先看当前连接状态,再针对性抓包:
# 查看与 10.0.0.6 的所有连接
ss -tn state established '( dst 10.0.0.6 )'
# 查看 TIME-WAIT 状态的连接数量
ss -tn state time-wait | wc -l
# 查看 SYN-RECV 状态的连接(可能遭受 SYN flood)
ss -tn state syn-recv | wc -l
如果发现大量 SYN-RECV 状态的连接,说明服务端收到了 SYN 但没收到第三个 ACK。可能是攻击,也可能是中间网络丢包。
抓包性能基准
在万兆网卡上抓包,性能取决于 BPF 过滤的复杂度和 snaplen:
# 用 dropwatch 看 BPF 过滤丢包情况
sudo dropwatch -l kas
# 如果看到大量 "kfree_skb" 在 __netif_receive_skb_core,
# 说明内核在 BPF 过滤前就丢包了,需要降低抓包量
如果确实需要全量抓包但性能跟不上,考虑用 PF_RING 或 AF_PACKET 的 mmap 模式。这些技术可以绕过内核拷贝,直接从网卡 DMA 到用户态内存。Facebook 的 fbtaxii 体系和 Netflix 的内部工具都用了类似技术。
生产环境注意事项
别抓全量流量。万兆网卡全量抓包几分钟就几十 GB,而且生产环境的流量里可能有敏感信息(API token、用户数据)。精确过滤是你的第一道安全措施。
pcap 文件含敏感信息。pcap 文件包含完整的网络数据,HTTPS 之外的所有内容都是明文。别把 pcap 文件放在公开可访问的地方,别通过不安全的渠道传输。用完就删。
长时间抓包要轮转。用
-G+-W组合做时间轮转和数量限制,防止磁盘被撑满。容器环境中抓宿主机流量。在容器里抓包只能看到容器命名空间内的流量。要抓宿主机流量,需要用
hostNetwork: true或者直接在宿主机上运行 tcpdump。
# 在 K8s Pod 中抓包(需要 hostNetwork 或特权模式)
kubectl exec -it <pod> -- tcpdump -i eth0 -nn -c 100
# 在宿主机上抓 Pod 流量
# 先找到 Pod 的 veth pair
kubectl get pod <pod> -o jsonpath='{.status.podIP}'
# 然后在宿主机上抓这个 IP 的流量
sudo tcpdump -i eth0 -nn 'host <pod-IP>'
- 时区问题。tcpdump 输出的时间戳默认是本地时间。如果服务器和你的时区不同,时间戳会差几个小时。用
-tttt可以显示日期:
# 显示完整日期时间
sudo tcpdump -i eth0 -nn -tttt
# 输出:2026-07-14 10:30:01.123456 IP ...
总结
tcpdump 和 Wireshark 是 SRE 排查网络问题的核心工具组合。tcpdump 负责在生产服务器上高效捕获,Wireshark 负责在本地深度解析。两者配合的流程很简单:服务器抓包 → scp 下载 → Wireshark 分析。
核心经验:
- BPF 过滤器是你的第一道防线,不仅能减少无关流量,还能防止磁盘被撑满。写过滤表达式时用引号包裹括号。
- TCP 标志位过滤是排查连接问题的关键。SYN 过滤看谁在发连接、RST 过滤看谁在拒绝连接、FIN 过滤看谁在关连接。
-nn是生产标配,避免 DNS 反解产生的性能损耗和干扰。-s 0确保 TLS 握手包不被截断,大证书链经常超过 1500 字节。- pcap 文件包含敏感信息,HTTPS 之外全是明文,用完即删。
- tshark 在无 GUI 环境下替代 Wireshark,支持完整的协议解析和字段提取。
- 长时间抓包必须用
-G+-W轮转,否则你会在某天凌晨被告警吵醒——不是因为业务故障,而是因为磁盘满了。
抓包能力的提升没有捷径,就是多练。下次遇到网络问题,别急着重启服务,先抓个包看看——十次有八次,答案就在 pcap 里。
参考资料与致谢
本文在撰写过程中参考了以下资料,感谢原作者的贡献:
- tcpdump 官方手册 — tcpdump.org,BPF 过滤语法和命令参数的权威文档
- Wireshark 用户指南 — Wireshark.org,显示过滤器和协议解析的完整文档
- tcpdump 抓包实战技巧 — CSDN,生产环境 tcpdump 使用经验和排查案例
- 网络分析双雄:Tcpdump 结合 Wireshark 协议分析实战指南 — CSDN,tcpdump 与 Wireshark 协同工作流的实践总结
- 网络安全分析:tcpdump 命令精准筛选 pcap 包 — CSDN,BPF 高级过滤技巧和 pcap 文件分析