tcpdump 是 Linux
上最基础也最强大的抓包工具。但大多数工程师只会
tcpdump -i eth0——然后被洪水般的输出淹没。
真正的抓包不是”打开水龙头”,而是精确过滤。在每秒数十万包的线上环境中,写好 BPF 过滤表达式决定了你能不能抓到关键包而不打爆磁盘。捕获策略——滚动文件、大小限制、时间窗口——决定了你能不能在事后找到那几个有问题的包。
一、tcpdump 基础与输出解读
1.1 基本命令
# 最基本的抓包(不推荐在生产环境直接执行)
tcpdump -i eth0
# 推荐的基本用法
tcpdump -i eth0 -n -c 100
# 参数说明:
# -i eth0 指定网卡
# -n 不做 DNS 反解(避免额外 DNS 查询)
# -c 100 抓 100 个包后自动停止
# -nn 不解析端口号(如 80 显示为 80 而非 http)
# -v / -vv 增加输出详细度
# -X 同时显示 hex + ASCII
# -XX 同上,含链路层头部
# -S 显示绝对序列号(不显示相对值)
# -t / -tt 不显示时间 / 显示 Unix 时间戳
# -ttt 显示与上一个包的时间差(极有用)1.2 输出格式解读
tcpdump 输出示例:
14:32:01.123456 IP 10.0.1.5.43210 > 10.0.1.10.80: Flags [S], seq 1234567890, win 65535, options [mss 1460,sackOK,TS val 1000 ecr 0,nop,wscale 7], length 0
│ │ │ │ │ │ │ │ │ │
│ │ 源 IP.端口 │ │ │ 序列号 │ TCP 选项 Payload 长度
│ │ 目标 IP.端口 │ 窗口大小
│ 协议 TCP 标志
时间戳
TCP 标志含义:
[S] SYN
[S.] SYN-ACK
[.] ACK
[P.] PSH-ACK(有数据推送)
[F.] FIN-ACK
[R] RST
[R.] RST-ACK
1.3 常见场景速查
# 抓 HTTP 流量
tcpdump -i eth0 -nn 'tcp port 80'
# 抓 HTTPS 流量(只能看到 TLS 握手,看不到内容)
tcpdump -i eth0 -nn 'tcp port 443'
# 抓 DNS 查询
tcpdump -i eth0 -nn 'udp port 53'
# 抓 SYN 包(分析新连接)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0'
# 抓 RST 包(分析连接异常)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
# 抓指定主机之间的流量
tcpdump -i eth0 -nn 'host 10.0.1.5 and host 10.0.1.10'
# 抓指定子网的流量
tcpdump -i eth0 -nn 'net 10.0.1.0/24'
# 保存到文件(后续用 Wireshark 分析)
tcpdump -i eth0 -nn -w capture.pcap 'tcp port 80'
# 读取 pcap 文件
tcpdump -r capture.pcap -nn二、BPF 过滤语法完整指南
BPF(Berkeley Packet Filter)是 tcpdump 的过滤引擎。过滤表达式在内核层面执行,只有匹配的包才会拷贝到用户空间——这意味着好的过滤表达式能大幅降低 CPU 和内存开销。
2.1 基础元语
BPF 过滤表达式由 "类型 + 方向 + 协议" 三部分组成:
类型(Type):
host 10.0.1.5 主机
net 10.0.1.0/24 网段
port 80 端口
portrange 8000-8100 端口范围
方向(Direction):
src 源
dst 目的
src or dst 源或目的(默认)
src and dst 源且目的
协议(Protocol):
ip IPv4
ip6 IPv6
tcp TCP
udp UDP
icmp ICMP
arp ARP
ether 以太网
组合示例:
src host 10.0.1.5 # 源地址是 10.0.1.5
dst port 80 # 目标端口是 80
tcp src port 443 # TCP 源端口 443
src net 172.16.0.0/12 # 源地址在 172.16.0.0/12 网段
2.2 逻辑运算
AND(与):
tcpdump 'src host 10.0.1.5 and dst port 80'
tcpdump 'tcp and port 443'
OR(或):
tcpdump 'port 80 or port 443'
tcpdump 'host 10.0.1.5 or host 10.0.1.10'
NOT(非):
tcpdump 'not port 22' # 排除 SSH
tcpdump 'not host 10.0.1.1' # 排除网关
括号(注意 Shell 转义):
tcpdump '(port 80 or port 443) and host 10.0.1.5'
tcpdump 'not (port 22 or port 53)' # 排除 SSH 和 DNS
复杂组合:
# 抓 10.0.1.5 到 10.0.1.10 的 HTTP/HTTPS 流量,排除 ACK-only
tcpdump -i eth0 -nn \
'src host 10.0.1.5 and dst host 10.0.1.10 and \
(tcp port 80 or tcp port 443) and \
(tcp[tcpflags] & tcp-push != 0)'
2.3 TCP 标志位过滤
TCP 标志位过滤是诊断 TCP 问题的利器:
TCP 标志位定义:
tcp-fin = 0x01 FIN
tcp-syn = 0x02 SYN
tcp-rst = 0x04 RST
tcp-push = 0x08 PSH
tcp-ack = 0x10 ACK
tcp-urg = 0x20 URG
使用方法:
tcpdump 'tcp[tcpflags] & tcp-syn != 0' # 含 SYN 的包
tcpdump 'tcp[tcpflags] & tcp-rst != 0' # 含 RST 的包
tcpdump 'tcp[tcpflags] & tcp-fin != 0' # 含 FIN 的包
精确匹配:
tcpdump 'tcp[tcpflags] == tcp-syn' # 仅 SYN(不含 ACK)
tcpdump 'tcp[tcpflags] == tcp-syn|tcp-ack' # SYN-ACK
常用诊断场景:
# 只看三次握手的 SYN
tcpdump -i eth0 -nn 'tcp[tcpflags] == tcp-syn'
# 只看 RST(连接被拒绝/异常关闭)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
# 只看 FIN(正常关闭)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-fin != 0'
# 看有数据的包(排除纯 ACK)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-push != 0'
# 看重传(SYN 重传,连接建立失败的征兆)
# 需要配合 -ttt 观察时间间隔
tcpdump -i eth0 -nn -ttt 'tcp[tcpflags] == tcp-syn and dst port 80'
2.4 字节偏移过滤
BPF 允许访问包的任意字节位置,这是高级过滤的核心:
语法: proto[offset:length]
proto: ip, tcp, udp, icmp, ether 等
offset: 从该层头部起始的字节偏移
length: 读取的字节数(1, 2, 或 4)
IP 头部偏移:
ip[0] = Version + IHL
ip[1] = ToS / DSCP
ip[2:2] = Total Length
ip[6:2] = Flags + Fragment Offset
ip[8] = TTL
ip[9] = Protocol (6=TCP, 17=UDP, 1=ICMP)
ip[12:4] = Source IP
ip[16:4] = Destination IP
TCP 头部偏移:
tcp[0:2] = Source Port
tcp[2:2] = Destination Port
tcp[4:4] = Sequence Number
tcp[8:4] = Acknowledgment Number
tcp[12] = Data Offset + Reserved
tcp[13] = TCP Flags
实际案例:
# TTL 为 1 的包(traceroute 发出的包)
tcpdump -i eth0 -nn 'ip[8] == 1'
# IP 分片包(Fragment Offset > 0 或 MF 标志)
tcpdump -i eth0 -nn 'ip[6:2] & 0x3fff != 0'
# DSCP 值为 46 的包(EF/快速转发流量)
tcpdump -i eth0 -nn 'ip[1] >> 2 == 46'
# TCP 窗口为 0 的包(零窗口,流控问题)
tcpdump -i eth0 -nn 'tcp[14:2] == 0'
2.5 应用层过滤
HTTP 请求方法过滤(明文 HTTP):
# GET 请求(TCP payload 前 3 字节是 "GET")
tcpdump -i eth0 -nn -A \
'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
解释:
tcp[12:1] & 0xf0 >> 2 = TCP 数据偏移(头部长度)
从 TCP payload 起始位置开始匹配
0x47455420 = "GET " (ASCII)
# POST 请求
tcpdump -i eth0 -nn -A \
'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354'
# HTTP 响应(以 "HTTP" 开头)
tcpdump -i eth0 -nn -A \
'tcp src port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450'
DNS 查询过滤:
# DNS 查询(QR=0)
tcpdump -i eth0 -nn 'udp port 53 and udp[10] & 0x80 == 0'
# DNS 响应(QR=1)
tcpdump -i eth0 -nn 'udp port 53 and udp[10] & 0x80 != 0'
# DNS NXDOMAIN 响应(RCODE=3)
tcpdump -i eth0 -nn 'udp port 53 and udp[11] & 0x0f == 3'
三、捕获策略
3.1 滚动文件捕获
线上抓包最重要的原则:不要让 pcap 文件无限增长。
# 滚动捕获: 每个文件 100MB,最多保留 10 个文件
tcpdump -i eth0 -nn -w /tmp/capture.pcap \
-C 100 -W 10 \
'tcp port 80 or tcp port 443'
# 参数说明:
# -C 100 每个文件最大 100MB(单位: 百万字节)
# -W 10 最多保留 10 个文件(覆盖最旧的)
#
# 文件命名: capture.pcap0, capture.pcap1, ..., capture.pcap9
# 总磁盘占用上限: 100MB × 10 = 1GB
# 按时间分割: 每 3600 秒(1 小时)一个文件
tcpdump -i eth0 -nn -w /tmp/capture.pcap \
-G 3600 -W 24 \
'tcp port 80'
# 参数说明:
# -G 3600 每 3600 秒轮转一次
# -W 24 最多保留 24 个文件(24 小时的数据)
#
# 配合 -w 的 strftime 格式:
tcpdump -i eth0 -nn -w '/tmp/cap_%Y%m%d_%H%M%S.pcap' \
-G 3600 -W 24 \
'tcp port 80'
# 文件名: cap_20250803_143200.pcap3.2 只捕获头部
大多数网络诊断只需要协议头部,不需要完整的 Payload:
# 只捕获前 96 字节(默认 262144)
tcpdump -i eth0 -nn -s 96 -w capture.pcap 'tcp port 80'
# 只捕获前 68 字节(IP + TCP 头部,无 Payload)
tcpdump -i eth0 -nn -s 68 -w capture.pcap
# 捕获长度选择:
# -s 0 捕获完整包(需要看 Payload 内容时)
# -s 68 只有 IP + TCP 头(连接分析)
# -s 96 含部分 TCP 选项(RTT 分析)
# -s 256 含 HTTP 请求行/响应行
# -s 1500 标准 MTU 完整包
# 意义:
# 线上环境每秒可能有 100K+ 的包
# -s 68 比 -s 0 减少 95% 的磁盘写入
# 对 CPU 和 I/O 的影响显著降低3.3 后台抓包
# 后台抓包(nohup + 限制条件)
nohup tcpdump -i eth0 -nn -w /tmp/debug.pcap \
-C 50 -W 20 -s 256 \
'host 10.0.1.10 and tcp port 8080' \
> /dev/null 2>&1 &
echo $! > /tmp/tcpdump.pid
# 停止抓包
kill $(cat /tmp/tcpdump.pid)
# 定时抓包(抓 5 分钟)
timeout 300 tcpdump -i eth0 -nn -w /tmp/debug.pcap \
'tcp port 80'
# 抓到特定数量后停止
tcpdump -i eth0 -nn -c 10000 -w /tmp/debug.pcap \
'tcp port 80'3.4 时间戳精度
# 高精度时间戳(纳秒级)
tcpdump -i eth0 -nn --time-stamp-precision=nano -w capture.pcap
# 时间戳显示格式:
# -t 不显示时间戳
# -tt Unix 时间戳(秒.微秒)
# -ttt 与上一包的时间差(分析延迟间隔)
# -tttt 日期 + 时间
# -ttttt 与第一个包的时间差
# 延迟分析推荐使用 -ttt:
tcpdump -i eth0 -nn -ttt 'host 10.0.1.10 and tcp port 80' -c 50
# 输出示例:
# 00:00:00.000000 IP 10.0.1.5.43210 > 10.0.1.10.80: Flags [S] ...
# 00:00:00.000342 IP 10.0.1.10.80 > 10.0.1.5.43210: Flags [S.] ...
# 00:00:00.000012 IP 10.0.1.5.43210 > 10.0.1.10.80: Flags [.] ...
# 00:00:00.000089 IP 10.0.1.5.43210 > 10.0.1.10.80: Flags [P.] ...
#
# 从时间差可以看出:
# SYN → SYN-ACK: 342μs(网络 RTT)
# SYN-ACK → ACK: 12μs(本地处理)
# ACK → Data: 89μs(应用层准备数据)四、容器与 Kubernetes 环境抓包
4.1 Docker 容器抓包
# 方法 1: 进入容器网络命名空间
# 获取容器 PID
CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' my-container)
# 在容器的网络命名空间中抓包
nsenter -t $CONTAINER_PID -n tcpdump -i eth0 -nn -c 100
# 方法 2: 使用 docker exec(容器需要有 tcpdump)
docker exec my-container tcpdump -i eth0 -nn -c 100
# 方法 3: 启动一个调试容器共享网络
docker run --rm -it --net=container:my-container \
nicolaka/netshoot tcpdump -i eth0 -nn -c 100
# 方法 4: 在宿主机上抓 veth pair
# 找到容器对应的 veth
VETH=$(ip link | grep -A1 "$(docker exec my-container cat /sys/class/net/eth0/iflink)" | head -1 | awk -F: '{print $2}' | tr -d ' ')
tcpdump -i $VETH -nn -c 1004.2 Kubernetes Pod 抓包
# 方法 1: kubectl debug(推荐,K8s 1.25+)
kubectl debug -it my-pod --image=nicolaka/netshoot \
--target=my-container -- \
tcpdump -i eth0 -nn -c 100 -w /tmp/capture.pcap
# 方法 2: 在 Node 上抓包
# 找到 Pod 所在的 Node
NODE=$(kubectl get pod my-pod -o jsonpath='{.spec.nodeName}')
# SSH 到 Node,找到 Pod 的网络命名空间
# Containerd 环境:
POD_ID=$(crictl pods --name my-pod -q)
CONTAINER_ID=$(crictl ps --pod $POD_ID -q)
CONTAINER_PID=$(crictl inspect $CONTAINER_ID | jq .info.pid)
nsenter -t $CONTAINER_PID -n tcpdump -i eth0 -nn -c 100
# 方法 3: 使用 ksniff(kubectl 插件)
kubectl sniff my-pod -n default -o capture.pcap
# 方法 4: 抓 CNI 接口
# Calico 环境: 接口名通常是 cali*
tcpdump -i cali1234abcd -nn -c 100
# Cilium 环境: 接口名通常是 lxc*
tcpdump -i lxc1234abcd -nn -c 1004.3 Service Mesh 环境
在 Istio/Linkerd 等 Service Mesh 环境中,
请求会经过 Sidecar Proxy (Envoy),抓包需要注意分层:
应用容器 (port 8080)
↓ (iptables 重定向)
Envoy Sidecar (port 15001/15006)
↓
网络 (eth0)
抓包位置选择:
1. eth0: 看到的是 Envoy 发出的流量(mTLS 加密后)
2. lo (127.0.0.1): 看到 Envoy → 应用 的流量(明文)
3. 应用端口: 看到应用实际收到的请求
# 抓 Envoy → 应用的流量(明文)
tcpdump -i lo -nn 'tcp port 8080'
# 抓 Envoy 对外的 mTLS 流量
tcpdump -i eth0 -nn 'tcp port 15001 or tcp port 15006'
# 对比入站和出站延迟
# 入站: Envoy 收到请求
tcpdump -i eth0 -nn -ttt 'tcp port 15006 and tcp[tcpflags] & tcp-push != 0' -c 10
# 出站: Envoy 转发给应用
tcpdump -i lo -nn -ttt 'tcp port 8080 and tcp[tcpflags] & tcp-push != 0' -c 10
五、高级用法
5.1 组合诊断场景
# 场景 1: 诊断 TCP 连接超时
# 抓 SYN 但没有 SYN-ACK 的情况
tcpdump -i eth0 -nn -ttt \
'tcp[tcpflags] == tcp-syn and dst host 10.0.1.10 and dst port 3306' \
-c 20
# 如果 SYN 多次出现但间隔 ~1s/2s/4s/8s → 重传,对端不响应
# 如果立即收到 RST → 端口未监听或被防火墙拒绝
# 场景 2: 诊断 HTTP 5xx 错误
# 抓 HTTP 响应,grep 状态码
tcpdump -i eth0 -nn -A -s 256 \
'tcp src port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450' \
| grep -E 'HTTP/1\.[01] [45][0-9][0-9]'
# 场景 3: 诊断 DNS 解析慢
# 抓 DNS 查询和响应,用 -ttt 看响应时间
tcpdump -i eth0 -nn -ttt 'udp port 53' -c 50
# 查询到响应的时间差如果 >100ms → DNS 服务器慢或网络延迟
# 多次查询同一域名 → 缓存未生效
# 场景 4: 抓取特定 VLAN 的流量
tcpdump -i eth0 -nn 'vlan 100'
# 场景 5: 检测 ARP 风暴
tcpdump -i eth0 -nn 'arp' -c 100 | \
awk '{print $NF}' | sort | uniq -c | sort -rn | head
# 场景 6: 诊断 MTU 问题(ICMP Fragmentation Needed)
tcpdump -i eth0 -nn 'icmp[0] == 3 and icmp[1] == 4'5.2 与其他工具组合
# tcpdump + wireshark: 抓包后分析
tcpdump -i eth0 -nn -w capture.pcap -c 10000 'tcp port 80'
# 然后用 Wireshark 打开 capture.pcap 做流分析
# tcpdump + tshark: 命令行分析
tcpdump -i eth0 -nn -w - 'tcp port 80' | \
tshark -r - -T fields -e ip.src -e ip.dst -e tcp.analysis.retransmission
# tcpdump + awk: 实时统计
# 统计每秒包数
tcpdump -i eth0 -nn -tt 'tcp port 80' 2>/dev/null | \
awk '{split($1,a,"."); print a[1]}' | uniq -c
# tcpdump + grep: 过滤 HTTP Host
tcpdump -i eth0 -nn -A -s 512 'tcp port 80' 2>/dev/null | \
grep -oP 'Host: \K[^\r\n]+'
# tcpdump 输出统计(远程抓包)
# 在远程服务器抓包,通过 SSH 管道传到本地
ssh server 'tcpdump -i eth0 -nn -w - tcp port 80' > remote.pcap
# 或直接在本地 Wireshark 中打开
ssh server 'tcpdump -i eth0 -nn -w - tcp port 80' | \
wireshark -k -i -5.3 多网卡与特殊接口
# 抓所有接口
tcpdump -i any -nn 'tcp port 80'
# 注意: -i any 时看到的是 Linux cooked capture (SLL) 格式
# 不包含以太网帧头,而是 Linux 特有的伪头部
# 列出所有可抓包接口
tcpdump -D
# 输出:
# 1.eth0 [Up, Running]
# 2.lo [Up, Running, Loopback]
# 3.docker0 [Up, Running]
# 4.veth1234 [Up, Running]
# 5.any (Pseudo-device that captures on all interfaces)
# 抓 loopback 流量(本机内部通信)
tcpdump -i lo -nn 'tcp port 6379' # 抓 Redis 通信
# 抓 bridge 接口(Docker 网络)
tcpdump -i docker0 -nn
# 抓 bond 接口
tcpdump -i bond0 -nn六、性能优化与注意事项
6.1 tcpdump 的性能影响
tcpdump 的工作原理:
1. 内核通过 BPF 过滤包
2. 匹配的包从内核态拷贝到用户态
3. tcpdump 格式化并输出/写文件
性能影响因素:
1. 过滤表达式: BPF 在内核态执行,开销极低
但匹配的包越多 → 内核到用户态的拷贝越多
2. -s 参数: 捕获长度越短 → 拷贝的数据越少
3. 输出方式: -w 写文件比终端输出快得多
4. 包速率: >100K pps 时需要注意丢包
线上环境最佳实践:
# 推荐: 精确过滤 + 限制捕获长度 + 写文件 + 限制数量/时间
tcpdump -i eth0 -nn -s 96 -w /tmp/cap.pcap \
-C 100 -W 5 \
'host 10.0.1.10 and tcp port 8080'
# 不推荐: 无过滤 + 完整捕获 + 终端输出
tcpdump -i eth0 # ← 这会让你后悔的
6.2 丢包检测
# tcpdump 退出时会报告丢包统计
tcpdump -i eth0 -nn -c 10000 'tcp port 80'
# 结束后输出:
# 10000 packets captured
# 10234 packets received by filter
# 234 packets dropped by kernel ← 关注这个数字
# 如果 kernel drop > 0:
# 1. 加大缓冲区
tcpdump -i eth0 -nn -B 4096 'tcp port 80'
# -B 4096 设置内核缓冲区为 4MB(默认 ~2MB)
# 2. 减少捕获长度
tcpdump -i eth0 -nn -s 68 'tcp port 80'
# 3. 写文件而不是终端输出
tcpdump -i eth0 -nn -w capture.pcap 'tcp port 80'
# 4. 缩小过滤范围
tcpdump -i eth0 -nn 'src host 10.0.1.5 and dst port 80'
# 5. 检查系统缓冲区设置
sysctl net.core.rmem_max
sysctl net.core.rmem_default
# 可以增大:
# sysctl -w net.core.rmem_max=83886086.3 安全注意事项
1. 权限要求
tcpdump 需要 root 权限或 CAP_NET_RAW capability
# 给非 root 用户抓包能力
setcap cap_net_raw=eip /usr/sbin/tcpdump
2. 捕获文件的安全
pcap 文件可能包含敏感数据(密码、Token、Cookie)
✅ 只捕获头部(-s 68)用于连接分析
✅ 及时删除 pcap 文件
✅ 不要把 pcap 文件放在可公开访问的路径
❌ 不要用 -s 0 抓包后分享 pcap 文件
3. 法律合规
在某些环境中,抓包需要合规审批
企业环境: 遵循公司的安全审计政策
生产环境: 记录抓包的时间、原因、操作人
4. 性能安全
不做限制的 tcpdump 可能影响线上性能
✅ 始终使用 -c 或 -W 限制
✅ 使用 timeout 命令做时间限制
✅ 先在测试环境验证 BPF 表达式
七、实战案例
7.1 案例:连接建立超时排查
# 现象: 应用报 "connection timeout" 连接 10.0.1.10:3306
# 排查步骤:
# 1. 抓 SYN 包
tcpdump -i eth0 -nn -ttt \
'tcp[tcpflags] == tcp-syn and dst host 10.0.1.10 and dst port 3306' \
-c 20
# 观察结果 A: SYN 重传
# 00:00:00.000000 IP 10.0.1.5.43210 > 10.0.1.10.3306: Flags [S] ...
# 00:00:01.003421 IP 10.0.1.5.43210 > 10.0.1.10.3306: Flags [S] ...
# 00:00:02.007892 IP 10.0.1.5.43210 > 10.0.1.10.3306: Flags [S] ...
# → 1秒、2秒间隔 = SYN 重传
# → 对端不响应(防火墙丢弃 / 服务未启动 / Backlog 满)
# 观察结果 B: 立即收到 RST
# 00:00:00.000000 IP 10.0.1.5.43210 > 10.0.1.10.3306: Flags [S] ...
# 00:00:00.000453 IP 10.0.1.10.3306 > 10.0.1.5.43210: Flags [R.] ...
# → 端口未监听或被防火墙主动拒绝
# 2. 在对端同时抓包确认
ssh 10.0.1.10 'tcpdump -i eth0 -nn -ttt \
"tcp port 3306 and host 10.0.1.5" -c 20'
# 如果对端看到 SYN 但没有 SYN-ACK → 服务端问题
# 如果对端看不到 SYN → 中间网络丢弃了7.2 案例:TLS 握手失败
# 现象: curl -k https://10.0.1.10 超时或报 SSL 错误
# 排查:
tcpdump -i eth0 -nn -ttt -v \
'host 10.0.1.10 and tcp port 443' -c 50
# 正常的 TLS 握手:
# → [S] TCP SYN
# ← [S.] TCP SYN-ACK
# → [.] TCP ACK
# → [P.] ClientHello
# ← [P.] ServerHello, Certificate, ServerHelloDone
# → [P.] ClientKeyExchange, ChangeCipherSpec, Finished
# ← [P.] ChangeCipherSpec, Finished
# → [P.] Application Data (HTTP 请求)
# 异常情况:
# 1. ClientHello 后收到 RST → 对端不支持 TLS 或端口配置错
# 2. ClientHello 后无响应 → 对端处理卡住或防火墙
# 3. ServerHello 后断开 → 密码套件不匹配
# 4. Certificate 后客户端发 Alert → 证书验证失败
# 查看 TLS Alert 消息
tcpdump -i eth0 -nn -X \
'host 10.0.1.10 and tcp port 443' -c 50 | \
grep -A2 "Alert"7.3 案例:间歇性丢包
# 现象: 服务偶尔出现 502/504 错误
# 策略: 长时间后台抓包,事后分析
# 1. 启动滚动抓包(保留 2 小时的数据)
nohup tcpdump -i eth0 -nn -s 96 \
-w '/tmp/cap_%Y%m%d_%H%M%S.pcap' \
-G 600 -W 12 \
'host 10.0.1.10 and tcp port 8080' \
> /dev/null 2>&1 &
# 2. 等故障复现后,分析 pcap 文件
# 用 tshark 找出重传包
tshark -r /tmp/cap_*.pcap \
-Y 'tcp.analysis.retransmission' \
-T fields -e frame.time -e ip.src -e ip.dst \
-e tcp.srcport -e tcp.dstport
# 用 tshark 统计重传率
tshark -r /tmp/cap_*.pcap -z io,stat,1,tcp.analysis.retransmission
# 用 tshark 找 RST 包
tshark -r /tmp/cap_*.pcap -Y 'tcp.flags.reset == 1'
# 3. 分析时间分布
# 如果重传集中在某个时间段 → 对端或网络问题
# 如果均匀分布 → 持续性的网络质量问题八、BPF 过滤表达式速查表
┌────────────────────────────────────────────────────────────────┐
│ 场景 │ BPF 过滤表达式 │
├────────────────────────┼──────────────────────────────────────┤
│ 指定主机 │ host 10.0.1.5 │
│ 指定网段 │ net 10.0.1.0/24 │
│ 指定端口 │ port 80 │
│ TCP SYN │ tcp[tcpflags] == tcp-syn │
│ TCP SYN-ACK │ tcp[tcpflags] == tcp-syn|tcp-ack │
│ TCP RST │ tcp[tcpflags] & tcp-rst != 0 │
│ TCP FIN │ tcp[tcpflags] & tcp-fin != 0 │
│ 有数据的包 │ tcp[tcpflags] & tcp-push != 0 │
│ 零窗口 │ tcp[14:2] == 0 │
│ DNS 查询 │ udp port 53 and udp[10] & 0x80 == 0│
│ DNS NXDOMAIN │ udp port 53 and udp[11] & 0x0f == 3│
│ ICMP 不可达 │ icmp[0] == 3 │
│ TTL=1 │ ip[8] == 1 │
│ IP 分片 │ ip[6:2] & 0x3fff != 0 │
│ 排除 SSH │ not port 22 │
│ 排除 SSH 和 DNS │ not (port 22 or port 53) │
│ VLAN 100 │ vlan 100 │
│ ARP │ arp │
│ 指定 MAC 地址 │ ether host aa:bb:cc:dd:ee:ff │
│ 广播包 │ ether broadcast │
│ 包长度 > 1000 │ greater 1000 │
│ 包长度 < 100 │ less 100 │
└────────────────────────┴──────────────────────────────────────┘
九、总结
tcpdump 的精髓不在命令本身,而在于过滤策略和分析思路。
BPF 过滤在内核执行。好的过滤表达式不是可选的优化——在高流量环境中它决定了你能不能成功抓到包。写 BPF 表达式要像写数据库查询一样精确。
线上抓包必须有保护机制。
-C -W(滚动文件限制)、-s(捕获长度限制)、-c或timeout(数量/时间限制)——这三个至少用一个,否则一个 tcpdump 就能打爆你的磁盘。-ttt是最被低估的参数。它显示每个包与上一个包的时间差,让你立即看出”SYN 重传间隔”“DNS 查询到响应的耗时”“数据发送到 ACK 的延迟”。大多数延迟问题用-ttt三秒就能看出来。容器环境抓包要找对接口。
kubectl debug+nsenter是最可靠的方法。理解 veth pair、CNI 接口、Sidecar 拦截的分层,才能在正确的位置抓到正确的包。tcpdump 抓包,Wireshark 分析。tcpdump 的强项是在线过滤和捕获,Wireshark 的强项是图形化分析。用
-w保存 pcap,然后在 Wireshark 中做流分析、RTT 测量、统计图表。
参考文献
- tcpdump(1) man page (tcpdump.org)
- BPF 过滤语法: pcap-filter(7) man page
- McCanne, S. & Jacobson, V. (1993). The BSD Packet Filter: A New Architecture for User-level Packet Capture
- Wireshark Display Filter vs Capture Filter (wiki.wireshark.org)
- Kubernetes Debug Running Pods (kubernetes.io/docs)
上一篇:WebTransport 与 WebCodecs:下一代浏览器传输
下一篇:Wireshark 深度分析:流图、专家信息与协议解析
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【网络工程】BPF 网络诊断:bpftrace 与 bcc 工具实战
系统讲解 eBPF 在网络诊断中的工程应用:bcc 工具集(tcplife/tcpretrans/tcpdrop)的使用场景、bpftrace 自定义网络探针编写、XDP 丢包分析、内核协议栈延迟追踪,建立基于 eBPF 的系统化网络诊断方法。
【网络工程】网络故障排查系统化方法:从现象到根因
系统讲解网络故障排查的方法论:OSI 分层排查法、连通性/性能/间歇性三类故障的诊断路径、排查决策树、工具链选择、真实故障案例复盘,建立从'网络不通'到精确定位根因的工程能力。
【网络工程】ss/netstat/ip 工具链:Socket 状态分析与连接审计
系统讲解 Linux 网络诊断工具链:ss 的过滤语法与性能优势、ip 命令族全景、conntrack 连接追踪、/proc/net/ 文件解读,建立从 Socket 状态到连接审计的工程能力。
【网络工程】eBPF 可编程网络:从包过滤到流量工程
eBPF 正在重新定义网络工程——从传统的 iptables/netfilter 规则堆砌,到可编程、可观测、高性能的网络数据平面。本文系统讲解 eBPF 网络程序类型(XDP/TC/Socket)、Map 数据结构、Cilium 的 eBPF 数据平面实现,以及 eBPF 在负载均衡、可观测性和网络安全中的工程实践。