TT Lab
博客 开始
学习 学习路径 课程

Linux 网络诊断

怎么读抓包 (概念)

在 TT Lab 中继续学习

一句话总结

抓包是判定“谁在说谎”的最终裁判。不过本实验环境没有抓包权限,所以先从概念上掌握读法,实验则用 ss 和 /proc/net 代替。

为什么需要这个

日志是应用的说法,ss 是内核的摘要。两者都不能直接告诉你“数据包实际上是怎么往来的”。因此在下面三种情况下,最终还是需要抓包。

  1. 双方日志各说各话时(客户端说发了,服务器说没收到)
  2. 需要查看重传、分片这类只发生在内核内部的事情时
  3. 需要确认中间设备(代理、LB、NAT)是否在改动什么时

工作原理

tcpdump 的必备选项屈指可数。

tcpdump -nn -i any 'host 10.0.3.11 and tcp port 8080'
tcpdump -nn -i any 'icmp[icmptype] == 3 and icmp[icmpcode] == 4'
tcpdump -nn -i any -w /tmp/cap.pcap -c 2000

读法的核心是 TCP 标志的表示方式。

表示 含义 此时发生了什么
[S] SYN 尝试连接
[S.] SYN+ACK 对方接受
[.] ACK 确认数据
[P.] PSH+ACK 发送数据
[F.] FIN+ACK 开始正常关闭
[R] / [R.] RST 拒绝或强制关闭

有了这张表,两种失败一眼就能分清。

诊断 MTU 黑洞时,要抓 ICMP 类型 3 代码 4(Fragmentation needed)。“为了安全把 ICMP 全部封掉”这种策略本身会成为故障原因,道理就在这里。可以封的只有 echo request/reply 之类,类型 3 代码 4 必须放行。在 IPv6 中,Packet Too Big(类型 2)起同样的作用,在那里甚至没有选择的余地。

在现场遇到的样子

在容器里很难抓包。 像本实验环境这样去除了 capability 后,tcpdump 无法打开套接字。在 Kubernetes 中,标准的绕行方法是用临时容器(kubectl debug)把诊断容器挂到同一个网络命名空间。如果能登录节点,就在节点上指定 Pod 的 veth 抓包。

所以实际工作的顺序就固定为:先用 ss 和 curl -w 尽量缩小范围,只有当双方说法仍有分歧时才动用抓包。 抓包很强大,但代价高。

下一步要做的事

本课程的实验全部不使用抓包。取而代之的是,其中有一步要直接读取 /proc/net/tcp,确认内核持有的套接字状态——这是不抓包时最接近内核真相的方法。