Tcpdump 抓包与网络排查指南
在日常的系统运维、容器排查和微服务调试中,网络问题(如连接超时、丢包、重传、协议错误)是最棘手的问题之一。tcpdump 是一款强大且经典的命令行网络抓包工具,它能够截获流经网卡的网络数据包,并支持极其丰富的过滤规则。
接口超时、连接被拒绝、偶发断流、TLS 握手停滞,应用日志往往只记录最终失败,而 tcpdump 能回答更基础的问题:客户端是否真的发包、报文是否抵达服务器、服务器是否响应、响应是否返回客户端、连接在哪个阶段关闭。抓包的价值是建立证据链,而不是用一段输出替代判断。
本文整理了 tcpdump 的核心参数、高频实战过滤表达式、抓包前的准备、容器环境下的抓包技巧、受控抓包与证据交接,以及如何配合 Wireshark 进行深度分析。
1. 核心常用参数速查
在执行 tcpdump 命令时,合理搭配参数可以帮助我们快速、清晰地观察数据流,或者将数据保存到文件中。
| 参数 | 说明 | 建议与备注 |
|---|---|---|
-i <interface> | 指定监听的网卡接口(如 eth0, any) | any 表示监听所有网卡,但在某些系统上可能不支持混杂模式 |
-n | 不把 IP 地址解析为主机名 | 必带参数,避免 DNS 解析带来延迟和干扰 |
-nn | 不把端口号解析为服务名(如 80 不解析为 http) | 必带参数,直接显示数字端口 |
-c <count> | 抓取指定数量的数据包后自动退出 | 生产环境抓包时建议带上,防止刷屏或撑爆磁盘 |
-s <snaplen> | 设置抓取每个数据包的字节数 | 默认 snaplen 为 262144 字节;-s 0 表示不截断、抓取完整数据包。排查应用层协议(如 HTTP/gRPC)时必须完整抓取,见下方 snaplen 分级建议 |
-v, -vv, -vvv | 输出更详细的报文协议信息 | 级别越高,输出的信息越详细(如 TTL、TOS、TCP 选项等) |
-e | 打印链路层头部(源/目的 MAC 地址) | 排查 ARP、二层转发问题时使用 |
-tttt | 以可读的绝对时间打印时间戳 | 便于与应用、Nginx、内核日志对齐 |
-S | 显示绝对 TCP 序列号(默认显示相对序列号) | 交接文件时通常不必开启,会增加会话关联风险 |
-X | 以 Hex(十六进制)和 ASCII 格式打印数据包内容 | 适合排查明文协议(如 HTTP, Redis, Memcached)的内容 |
-A | 仅以 ASCII 码格式打印数据包内容 | 适合快速查看 HTTP 请求体或响应体中的文本 |
-w <file.pcap> | 将抓取到的原始数据包写入 .pcap 文件 | 生产标准做法,保存后可下载到本地用 Wireshark 深度分析 |
-r <file.pcap> | 从保存的 .pcap 文件中读取并分析数据包 | 离线分析时使用,不会改变原始证据 |
-C <size> | 每 size 百万字节轮转一个新文件 | 配合 -w 使用,长时间抓包必备 |
-W <count> | 最多保留 count 个轮转文件 | 配合 -C 做有限环形抓取,防止耗尽磁盘 |
2. 高频实战过滤表达式
tcpdump 强大的核心在于其过滤表达式(Filter Expression)。通过合理组合限定词,我们可以从海量流量中精确筛选出目标报文。
基础过滤(按 IP、端口、协议)
# 1. 监听指定网卡上所有经过特定 IP 的流量(源或目的)
tcpdump -i eth0 -nn host 192.168.1.100
# 2. 监听特定源 IP 或目的 IP 的流量
tcpdump -i eth0 -nn src 192.168.1.100
tcpdump -i eth0 -nn dst 192.168.1.200
# 3. 监听特定端口的流量(TCP 或 UDP)
tcpdump -i eth0 -nn port 80
tcpdump -i eth0 -nn src port 8080
# 4. 监听特定网段的流量
tcpdump -i eth0 -nn net 10.244.0.0/16
# 5. 监听特定协议(tcp, udp, icmp, arp 等)
tcpdump -i eth0 -nn icmp
逻辑组合过滤(and, or, not)
通过逻辑运算符,可以构建非常复杂的过滤场景:
# 1. 抓取来自 192.168.1.100 且目的端口是 80 或 443 的 TCP 报文
tcpdump -i eth0 -nn 'tcp and src host 192.168.1.100 and (dst port 80 or dst port 443)'
# 2. 抓取网卡上除了 SSH (22) 之外的所有流量,防止抓包数据刷屏
tcpdump -i eth0 -nn 'not port 22'
# 3. 抓取主机 A 与主机 B 之间通信的所有非 ICMP 报文
tcpdump -i eth0 -nn 'host 192.168.1.10 and host 192.168.1.20 and not icmp'
过滤表达式是 BPF 过滤器,会在内核侧尽量丢弃无关报文。生产环境应先用有限报文(-c)确认过滤条件正确,再决定是否保存 PCAP,不要直接全量抓取后再分析。
3. 抓包前的准备:定义问题与确定网卡
一次抓包前至少记录:故障时间范围、源和目标地址、端口、域名、请求 ID、复现方式、抓包位置。结论要描述可观察事实,例如"服务器网卡未看到该五元组 SYN",而不是直接写"中间网络丢包"——后者还需要客户端、服务器和中间设备计数共同证明。
确认本机 tcpdump 与网卡盘点
先确认本机 tcpdump 版本、可见网卡和地址。不同版本支持的选项略有差异,实际参数以本机帮助为准。
#!/usr/bin/env bash
set -euo pipefail
command -v tcpdump
tcpdump --version
tcpdump --help | sed -n '1,80p'
ip -brief link
ip -brief address
如需安装 tcpdump,应使用发行版受控软件仓库并走变更流程。抓包本身通常需要 root 或 CAP_NET_RAW/CAP_NET_ADMIN 能力,不应把无限制 sudo 权限交给业务账号。
确认流量真正从哪块网卡离开
多网卡、策略路由、VPN、容器 overlay 环境里,默认路由不一定承载目标请求。先解析目标,再询问内核到该地址会选什么路径。
TARGET="<目标域名或服务器IP>"
getent ahosts "$TARGET"
ip route get <服务器IP>
ip rule show
ip route get 的输出包括源地址、下一跳和输出接口。若客户端经 NAT、四层代理或负载均衡转发,服务器看到的源地址可能不是最终用户 IP;应先用网关日志确认实际对端。
把监听 socket 对应到服务进程
# 查看目标端口的 TCP 连接与监听 socket 归属(此命令只读,但查看进程名通常需要足够权限)
sudo ss -Htanp '( sport = :<端口> or dport = :<端口> )'
sudo ss -Hlunp '( sport = :<端口> or dport = :<端口> )'
服务处于 LISTEN 只能证明本机有进程监听;监听地址、策略路由、防火墙、ACL 和服务本身健康状态仍可能导致外部连接失败。
4. 生产运维高频实战场景
场景一:排查 HTTP 明文请求与响应体
当怀疑微服务之间的 HTTP 调用参数有问题时,可以直接在终端打印 ASCII 内容:
# 抓取 8080 端口的 HTTP 流量,并以 ASCII 打印,限制抓取 100 个包
tcpdump -i eth0 -nn -A -s 0 port 8080 -c 100
明文 HTTP 的头部本身也可能携带敏感令牌,只有在获得授权且确实需要时才使用 ASCII 输出。
场景二:排查 TCP 三次握手与连接重置(RST)
当客户端报 Connection reset by peer 或 Connection refused 时,我们需要观察 TCP 标志位(Flags):
# 抓取所有带有 RST 标志位的 TCP 报文(常用于排查连接被异常中断)
tcpdump -i any -nn 'tcp[tcpflags] & tcp-rst != 0'
# 抓取所有带有 SYN 或 FIN 标志位的报文(排查连接建立与释放)
tcpdump -i any -nn 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0'
连接建立异常最重要的是对比两端是否看到同一报文。下列过滤器同时保留初始 SYN、SYN-ACK、RST 和 FIN,适合完整观察三次握手和异常终止:
# 同时保留 SYN、SYN-ACK、RST、FIN 四类报文
tcpdump -i <网卡名> -nn -vv 'tcp port <端口> and (tcp[tcpflags] & (tcp-syn|tcp-ack) = tcp-syn or tcp[tcpflags] & (tcp-syn|tcp-ack) = (tcp-syn|tcp-ack) or tcp[tcpflags] & tcp-rst != 0 or tcp[tcpflags] & tcp-fin != 0)'
判断顺序是:客户端是否发出 SYN → 服务器是否收到同一 SYN → 服务器是否发出 SYN-ACK → 客户端是否 ACK → 是否很快出现 RST 或重复 SYN。看到单个 SYN 不足以说明丢包,必须对照时间、重传间隔与另一端抓包。
仅提取复位报文时,适合定位谁主动拒绝连接:
# 限定五元组抓 RST,缩小范围避免误判
tcpdump -i <网卡名> -nn -vv 'host <客户端IP> and host <服务器IP> and tcp port <端口> and tcp[tcpflags] & tcp-rst != 0'
RST 可能来自应用、内核、负载均衡或中间安全设备。应把报文源 MAC/IP、TTL、接口和同时段服务日志一起核对,不能只凭看到 RST 推断具体进程。
场景三:排查 DNS 解析异常
当系统报错 Temporary failure in name resolution,怀疑 DNS 慢或解析失败:
# 监听 53 端口(DNS 默认端口)的 UDP 报文,查看解析请求与回复
tcpdump -i any -nn udp port 53
# 同时抓 UDP 与 TCP 的 53 端口(大响应或区域传输走 TCP),并限定 DNS 服务器
tcpdump -i <网卡名> -nn -vv '(udp port 53 or tcp port 53) and host <DNS服务器IP>'
场景四:排查 ICMP 与二层邻居
ICMP 不等于业务可用,但 destination-unreachable、time-exceeded 或 fragmentation-needed 都是有效的路径证据。IPv6 环境还要观察 ICMPv6。
# 抓取与目标服务器相关的 ICMP/ICMPv6 报文
tcpdump -i <网卡名> -nn -vv '(icmp or icmp6) and host <服务器IP>'
同二层网段连接失败时,ARP 或邻居表能帮助判断问题是否停在二层:
# -e 显示 MAC 地址,观察 ARP 请求与响应
tcpdump -i <网卡名> -enn -vv 'arp or icmp6'
# 查看本机邻居表
ip neigh show dev <网卡名>
频繁 ARP 请求却没有响应可能指向 VLAN、对端网卡、重复 IP 或交换网络方向,但仍需交换机 MAC 表、端口状态和对端主机证据确认。
5. 受控抓包目录与磁盘保护
不要把未过滤 PCAP 放进业务日志目录或 /tmp,更不能无限制抓取直到磁盘写满。下面脚本创建仅所有者可读写的目录,在剩余空间不足时退出,不会删除既有文件。
#!/usr/bin/env bash
set -euo pipefail
CAPTURE_DIR="<抓包目录>"
MIN_FREE_MIB="2048"
install -d -m 0700 "$CAPTURE_DIR"
FREE_MIB="$(df -Pm "$CAPTURE_DIR" | awk 'NR==2 {print $4}')"
if (( FREE_MIB < MIN_FREE_MIB )); then
echo "insufficient free space: $FREE_MIB MiB" >&2
exit 1
fi
date -Is > "$CAPTURE_DIR/capture-started-at.txt"
保存前应约定保留周期与访问范围。若文件需要交给外部厂商,不应直接发送完整 PCAP;先确认授权,再根据目标改用头部抓取、双方受控分析或脱敏流程。
抓取期间应由业务方执行一次明确复现。停止时优先 Ctrl-C,让 tcpdump 正常写入文件尾;强制 kill -9 可能得到不完整文件。
6. 环形抓取:无法立即复现的偶发故障
长时间抓取必须限制文件大小和数量。-C 按文件大小轮转,-W 限制轮转数量;-C 的单位是百万字节,实际空间仍要预留。下面脚本抓取固定头部并限制十二个文件,防止单次故障取证耗尽磁盘。
#!/usr/bin/env bash
set -euo pipefail
INTERFACE="<网卡名>"
CAPTURE_DIR="<抓包目录>"
FILTER='host <客户端IP> and host <服务器IP> and tcp port <端口>'
install -d -m 0700 "$CAPTURE_DIR"
df -Pm "$CAPTURE_DIR"
exec sudo tcpdump -i "$INTERFACE" -nn -s 256 -C 100 -W 12 -w "$CAPTURE_DIR/incident.pcap" "$FILTER"
轮转会覆盖较早文件,告警后应及时固化目标时间窗口。不要依赖无限 PCAP 做长期审计;长期观测更适合使用流量指标、日志和按需取证。
7. 容器与 Kubernetes 环境下的抓包技巧
在 Kubernetes (K8s) 或 Docker 容器环境中,由于容器内通常没有安装 tcpdump,且容器网络通过 Network Namespace 进行了隔离,直接在宿主机上执行 tcpdump -i eth0 往往抓不到容器内部的局部流量。容器流量可能经过 veth、bridge、CNI、隧道或 eBPF 路径,先查看容器网络命名空间,确认容器看到的 IP 和路由。
方法一:定位容器网卡,在宿主机抓包(Docker)
-
获取容器的 PID:
docker inspect --format '{{.State.Pid}}' <container_id_or_name> # 假设输出为 12345 -
先确认容器内的网络视图:
CONTAINER_ID="<容器ID或名称>" PID="$(docker inspect -f '{{.State.Pid}}' "$CONTAINER_ID")" echo "container pid=$PID" sudo nsenter -t "$PID" -n ip -brief address sudo nsenter -t "$PID" -n ip route -
利用
nsenter进入容器的网络命名空间(推荐,最硬核且绿色的方式,无需在容器内安装任何工具):# 进入 PID 为 12345 的容器网络命名空间,并在其中执行宿主机的 tcpdump nsenter -t 12345 -n tcpdump -i any -nn -w /tmp/container_traffic.pcap
方法二:使用 K8s 临时容器(Ephemeral Containers)抓包
在 Kubernetes 1.23+ 中,可以使用 kubectl debug 启动一个带有 tcpdump 的临时工具容器,并共享目标 Pod 的网络命名空间:
# 往目标 Pod 中注入一个包含 tcpdump 的 netshoot 镜像容器,并直接开始抓包
kubectl debug -it <pod_name> -n <namespace> --image=nicolaka/netshoot -- tcpdump -i any -nn -c 50
# 指定 --target 共享具体容器的网络命名空间(多容器 Pod 场景)
kubectl debug -n <命名空间> -it pod/<Pod名> --target=<容器名> --image=<受信任调试镜像> -- tcpdump -i any -nn -s 256 'tcp port <端口>'
临时调试容器会创建集群资源,执行前必须确认 RBAC、镜像来源、审计和清理策略。
8. TLS、HTTP 与 UDP 的抓取策略
TLS:只看握手,不碰私钥
TLS 通常不能从 PCAP 直接得到业务正文。排障重点是 TCP 建立、ClientHello/ServerHello 是否出现、握手后是否关闭;不要复制私钥或会话密钥到不受控机器。
# 只抓头部(-s 512 足够覆盖 ClientHello/ServerHello),保存后离线分析
tcpdump -i <网卡名> -nn -s 512 -vvv -w <抓包目录>/tls-$(date +%Y%m%d-%H%M%S).pcap 'host <服务器IP> and tcp port 443'
HTTP:明文内容按授权使用
明文 HTTP 的头部本身也可能携带敏感令牌。只有在获得授权、且确实需要时才使用 ASCII 输出。
tcpdump -i <网卡名> -nn -s 512 -A 'host <客户端IP> and host <服务器IP> and tcp port 80'
UDP:不套用 TCP 结论
UDP 没有 TCP 握手和重传语义。分析 UDP 时应看请求响应是否成对出现、时间间隔、长度和 ICMP 错误,而不是套用 TCP 结论。
tcpdump -i <网卡名> -nn -vv -s 256 'udp and host <服务器IP> and port <端口>'
9. 网卡 offload 带来的观察偏差
GRO、GSO、TSO 会让主机抓包显示合并后的大段数据或看似错误的校验和,这不等于线上坏包。先只读查看 offload 状态。
# 只读检查与抓包观察相关的 offload 特性
ethtool -k <网卡名> | grep -E 'tcp-segmentation-offload|generic-segmentation-offload|generic-receive-offload|rx-checksumming|tx-checksumming'
为对照而关闭 offload 会影响整块网卡上的吞吐和 CPU 使用,属于高风险变更。只有在维护窗口、确认影响范围、记录原状态并准备回滚后才可执行。
# 临时关闭 offload 以对照抓包结果(高风险变更,需维护窗口)
ethtool -K <网卡名> gro off gso off tso off
ethtool -k <网卡名> | grep -E 'generic-receive-offload|generic-segmentation-offload|tcp-segmentation-offload'
回滚必须按变更前真实状态恢复,不能假定所有特性原本均为 on:
# 按变更前记录的真实状态恢复
ethtool -K <网卡名> gro <原gro状态> gso <原gso状态> tso <原tso状态>
ethtool -k <网卡名>
10. 配合 Wireshark 进行深度分析
虽然 tcpdump 可以在终端输出报文,但对于复杂的 TCP 粘包、乱序重传、SSL/TLS 握手排查,图形化工具 Wireshark 才是终极利器。
生产标准抓包与分析工作流
-
在服务器上抓包并保存为 pcap 文件(限制大小或数量,防止撑爆磁盘):
# 抓取 eth0 上 10000 个包,保存到 /tmp/target.pcap tcpdump -i eth0 -nn -s 0 -c 10000 -w /tmp/target.pcap -
将 pcap 文件下载到本地:
# 在本地终端执行 scp 下载 scp user@server_ip:/tmp/target.pcap ./ -
使用 Wireshark 打开分析:
- Follow TCP Stream:在任意 TCP 包上右键,选择
Follow->TCP Stream,可以完整还原应用层的明文会话(如 Redis 命令、HTTP 报文)。 - 查看重传与丢包:在上方过滤器输入
tcp.analysis.flags,Wireshark 会自动高亮标出所有的重传包(Retransmission)、乱序包(Out-of-Order)和 ACK 丢失,帮您快速定位网络链路质量问题。
- Follow TCP Stream:在任意 TCP 包上右键,选择
离线阅读与 tshark 提取
离线读取不改变原始证据。-tttt 输出可读的绝对时间,便于和应用、Nginx、内核日志对齐:
# 读取前先验证 pcap 文件可正常打开
tcpdump -r <抓包文件>.pcap -c 1 >/dev/null
echo "pcap basic read check passed"
# -tttt 打印绝对时间,便于与业务日志对齐
tcpdump -nn -tttt -r <抓包文件>.pcap 'host <客户端IP> and host <服务器IP> and tcp port <端口>'
如需保留绝对序列号,可增加 -S;绝对序列号会增加会话关联风险,交接文件时通常没有必要。
安装 Wireshark 工具集时,tshark 可在命令行提取其 TCP 分析结果。字段随版本变化,先确认字段存在,再把结果当作辅助证据而非最终根因:
# 查看当前版本可用的 tcp.analysis 字段
tshark -G fields | grep 'tcp.analysis' | head -n 30
# 提取重传与零窗口事件,便于批量比对
tshark -r <抓包文件>.pcap -Y 'tcp.analysis.retransmission or tcp.analysis.fast_retransmission or tcp.analysis.zero_window' -T fields -e frame.time -e ip.src -e tcp.srcport -e ip.dst -e tcp.dstport -e tcp.analysis.retransmission -e tcp.analysis.zero_window
所谓重传可能来自真实丢包、乱序、抓包点漏包、ACK 延迟或网卡 offload 造成的观察差异。强结论至少应证明发送端同一段重复发送,并在接收端或网络设备侧找到对应缺失或错误证据。
11. 证据固化与交接
抓完后校验 PCAP、限制权限并记录哈希。哈希用于保证交接文件未被改动,不替代敏感数据授权。
#!/usr/bin/env bash
set -euo pipefail
PCAP="<抓包文件>.pcap"
test -s "$PCAP"
chmod 0600 "$PCAP"
tcpdump -r "$PCAP" -c 1 >/dev/null
sha256sum "$PCAP" > "$PCAP.sha256"
ls -lh "$PCAP" "$PCAP.sha256"
完成记录至少包括:抓包点、网卡、过滤表达式、起止时间、时钟来源、复现动作、请求 ID、PCAP 哈希、两端握手对比和同时段系统日志。
tcpdump 结束时会报告 packets dropped by kernel;该计数非零时,PCAP 不能被当作完整流量真相,应重新缩小过滤条件、提高资源或在更合适的点抓取。真正可交接的结论不是"抓到了几个包",而是用双端或多点证据把故障明确缩小到客户端主机、服务监听、主机网络栈、二层邻居、路径某段、负载均衡或应用协议阶段,并说明仍未证实的部分。
12. 常见现象与证据矩阵
把现象翻译成可验证的证据,而不是直接下结论:
- 客户端连续发送 SYN、服务器侧始终没有同一五元组的 SYN:优先确认客户端出口路由、网关、ACL、负载均衡 VIP 和抓包点是否位于正确服务器;不能仅凭服务器没有报文就断言某一跳丢弃。
- 服务器收到了 SYN 但没有 SYN-ACK:检查监听地址、服务进程、内核连接队列、主机防火墙与策略路由,并查看是否由同机安全代理接管了端口。
- 服务器发出 SYN-ACK 而客户端没有看到:检查回程路由、反向 NAT、状态防火墙和客户端所在网络。
- 三次握手完成但请求仍超时:转向应用层——是否有 TLS ClientHello/ServerHello,是否在 HTTP 请求后停止,服务端是否持续向客户端发送数据,客户端窗口是否变成零,连接是否由任意一方发送 FIN 或 RST。
- 代理型架构:应在客户端到网关、网关到后端两个连接分别抓包;网关看到前半段正常不能证明后半段正常。
抓包的时间戳要与系统时钟一起对齐。两端主机时间相差数秒时,很容易把一个正常的握手误读为乱序或超时。若涉及多台节点,记录 NTP 或 Chrony 同步状态、时区和日志时间格式;不要通过人工"估算差不多"合并证据。
13. 高流量环境中的抓包策略
高 PPS 或高带宽主机上,tcpdump 可能因为内核缓冲、用户态消费速度和磁盘吞吐不足而丢包。结束时的 tcpdump 统计应被保留:捕获数、内核接收数、内核丢弃数分别说明不同阶段的观察质量。若内核丢弃不为零,先进一步收窄 BPF 条件、减小 snaplen、缩短窗口、把输出写入更快且受控的本地磁盘,或者改到流量更小的入口点;不要首先提高抓包缓冲就认定问题已解决。
抓包对业务的影响不仅是 CPU 和磁盘。全量抓取可能让页面缓存被 PCAP 挤占,影响数据库或模型服务读取;以 -A 输出到终端会放大 I/O;在容器宿主机的 any 接口抓取会看到多份镜像流量,既增加负载也提高误判概率。生产取证优先选择精确网卡、精确五元组和有限文件轮转,并把"为何需要完整载荷"作为需要批准的单独问题。