tcpdump —— 网络问题的最终证据

运维工具手册 02-进程与网络诊断 5.6 KB 原文

tcpdump —— 网络问题的最终证据

分类:02 进程与网络诊断 适用:Linux(libpcap),2.4/4.99 之后语法基本稳定 一句话:应用说没收到、网络说发了,只有抓包能判案。

1. 它解决什么问题

  • 请求到底有没有到达这台机器?
  • TCP 三次握手有没有完成?谁先 RST?
  • 是不是真的丢包、重传、乱序?
  • HTTP 请求/响应内容对不对(明文协议)。

2. 安装与权限

apt install -y tcpdump
dnf install -y tcpdump

# 普通用户抓包(避免全程 root)
setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
# 或
groupadd pcap && usermod -aG pcap $USER

容器内抓包需要 NET_RAW + NET_ADMIN,或直接在宿主机抓 veth。

3. 最常用的六条命令

tcpdump -i any -nn -c 100                 # 任意网卡,100 个包,不解析
tcpdump -i eth0 -nn port 80               # 80 端口
tcpdump -i eth0 -nn host 10.0.0.5         # 某 IP 的所有流量
tcpdump -i eth0 -nn -w /tmp/cap.pcap      # 写文件,后续用 Wireshark 分析
tcpdump -r /tmp/cap.pcap -nn -A           # 读文件,按 ASCII 显示
tcpdump -i eth0 -nn -s0 -A port 80        # 抓完整包并直接看内容

4. 参数详解

参数 作用 说明
-i <if> 指定网卡 any 抓所有(但链路层信息缺失)
-nn 不解析主机名和端口名 必加,否则 DNS 反查拖慢
-c <n> 抓 n 个包后退出 控制量
-s <n> 抓取长度(snaplen) -s0 抓完整包,旧默认 96 字节会截断
-w <file> 写 pcap 排障首选,先存后析
-r <file> 读 pcap
-A 以 ASCII 显示载荷 看 HTTP 明文
-X 十六进制 + ASCII 看二进制协议
-e 显示链路层头(MAC) 排查 ARP/二层问题
-v/-vv/-vvv 详细程度 -vv 看 TTL、窗口、校验和
-l 行缓冲 配合管道 `
-Q in/out 只抓进/出方向 区分请求与响应
-Z <user> 抓完降权到指定用户 安全加固
-B <kb> 内核缓冲大小 高流量防丢包
-G <s> -C <MB> -W <n> 按时间/大小轮转 长时间抓包
-D 列出可用网卡
-p 非混杂模式 只抓本机流量

5. 过滤器语法(BPF)

这是 tcpdump 的核心。表达式写在最后,建议用单引号包住。

基础

host 10.0.0.5                  # 源或目的
src host 10.0.0.5              # 仅源
dst host 10.0.0.5              # 仅目的
net 10.0.0.0/24                # 网段
port 80                        # 源或目的端口
src port 8080
dst port 443
portrange 8000-9000

组合

# 与、或、非
host 10.0.0.5 and port 3306
host 10.0.0.5 and not port 22
'( port 80 or port 443 ) and host 10.0.0.5'

括号必须转义或用引号包住,否则被 shell 解释。

协议与标志位

tcp                                  # 所有 TCP
udp
icmp
arp
ip proto 6                          # 协议号
tcp[tcpflags] & tcp-syn != 0        # 只看 SYN
tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)   # SYN+ACK
tcp[tcpflags] & tcp-rst != 0        # 只看 RST
tcp[13] & 2 != 0                    # 等价写法(13 是 flags 偏移)
ip[8] < 64                          # TTL < 64(判断是否经过路由)

按包长过滤

greater 1000           # 大于 1000 字节
less 100               # 小于 100 字节

6. 输出怎么读

14:32:01.123456 IP 10.0.0.5.51234 > 10.0.0.9.80: Flags [S], seq 123456789, win 29200, options [mss 1460,sackOK,TS val 123 ecr 0,nop,wscale 7], length 0
14:32:01.123987 IP 10.0.0.9.80 > 10.0.0.5.51234: Flags [S.], seq 987654321, ack 123456790, win 28960, options [mss 1460,sackOK,TS val 456 ecr 123,nop,wscale 7], length 0
14:32:01.124123 IP 10.0.0.5.51234 > 10.0.0.9.80: Flags [.], ack 1, win 229, length 0
标志 含义
[S] SYN
[S.] SYN+ACK
[.] ACK
[P.] PSH+ACK(有数据)
[F.] FIN+ACK
[R] RST
[R.] RST+ACK
  • length 0 表示无载荷(握手包)。
  • 只看握手三条就能判断连接是否建立:有 S 无 S. → 服务端没回(防火墙 drop 或没监听)。

7. 实战场景

7.1 判断请求是否到达本机

# 本机(服务端)抓
tcpdump -i any -nn -c 20 'tcp port 8080 and host 10.0.0.5'
  • 完全无包 → 没到这台机器:查 DNS、路由、安全组、SLB。
  • 有 SYN 无 SYN+ACK → 本机没监听或被本机防火墙 drop。
  • 有 SYN 立即 RST → 端口未监听(RST 是内核回的)。
  • 三次握手完成但无后续 → 应用层没处理。

7.2 抓 RST 是谁发的

tcpdump -i any -nn 'tcp[tcpflags] & tcp-rst != 0' -c 20

看 RST 的方向:从服务端发出 → 服务端主动拒绝(连接队列满、keepalive 超时、应用崩溃);从客户端发出 → 客户端放弃。

7.3 看 HTTP 请求内容

tcpdump -i eth0 -nn -s0 -A 'tcp port 80 and host 10.0.0.5' | grep -E '^(GET|POST|HTTP|Host:|Cookie:)'

HTTPS 只能看到 SNI 和证书(除非有私钥解密):

tcpdump -i eth0 -nn -s0 -A 'tcp port 443' | grep -i 'host:'

7.4 长时间抓包(轮转,防爆盘)

tcpdump -i eth0 -nn -s0 -w /data/cap/$(hostname)-%Y%m%d-%H%M.pcap \
  -G 600 -Z root 'port 8080' &
# 每 600 秒切一个新文件,%Y%m%d 由 -G 触发时按 strftime 展开

配合清理:

find /data/cap -name '*.pcap' -mtime +2 -delete

7.5 定位丢包与重传

tcpdump -i eth0 -nn -vv 'host 10.0.0.5 and tcp' -c 200 > /tmp/tcp.txt
grep -c 'retrans' /tmp/tcp.txt        # 粗略看重传提示(需 -vv 且较新版本)

精确分析建议存 pcap 后用 Wireshark 的 tcp.analysis.retransmission 过滤。

7.6 抓特定网段排除干扰

tcpdump -i eth0 -nn 'net 10.0.0.0/24 and not port 22 and not port 53' -c 500

8. 常见坑

  1. packets dropped by kernel:抓包速率超过内核缓冲,加大 -B 40960 或缩小过滤范围。丢包时结论就不可信了。
  2. -i any 抓不到链路层:any 是伪设备,-e 的 MAC 信息缺失,二层问题必须指定真实网卡。
  3. 默认 snaplen 会截断:老版本默认 96 字节,看 HTTP body 必须 -s0。
  4. 不加 -nn 极慢:每个包都做反向 DNS,高流量时直接卡死。
  5. 只抓到一个方向:交换机/网卡 offload 导致,或路由不对称。需要双向时在两台机器分别抓。
  6. 容器内 -i any 只看到容器网卡:要抓宿主机侧 veth,或 nsenter -t <pid> -n。
  7. 生产抓包有性能和安全风险:限制 -c、过滤条件、时长;pcap 里可能含明文密码,注意脱敏与留存合规。
  8. tcp port 80 不含 HTTP/2、gRPC over 其他端口,按实际端口抓。
  9. TLS 1.3 抓不到证书明文(除 SNI),别指望从包里看域名以外的东西。
  10. -w 时不要再加 -A/-X:会污染 pcap 文件,读不出来。

9. 配套:tshark

# 统计 HTTP 状态码
tshark -r cap.pcap -Y 'http.response' -T fields -e http.response.code | sort | uniq -c
# 找重传
tshark -r cap.pcap -Y 'tcp.analysis.retransmission' | head
# 提取 SNI
tshark -r cap.pcap -Y 'tls.handshake.extensions_server_name' \
  -T fields -e tls.handshake.extensions_server_name | sort -u

10. 速查表

tcpdump -i any -nn -c 100
tcpdump -i eth0 -nn port 80
tcpdump -i eth0 -nn host 10.0.0.5 and port 3306
tcpdump -i eth0 -nn -s0 -w /tmp/cap.pcap
tcpdump -r /tmp/cap.pcap -nn -A
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0 and host 10.0.0.5'
tcpdump -i eth0 -nn -Q in port 8080
tcpdump -i eth0 -nn -B 40960 -s0 -w /data/cap.pcap 'port 8080'
tcpdump -D                          # 列出网卡