探测 TCP 乱序问题

💡 原文中文,约3800字,阅读约需9分钟。
📝

内容提要

TCP协议基于IP协议,遇到下载速度慢的问题,抓包发现乱序包。使用traceroute和mtr工具探测乱序节点。利用TCP traceroute原理,保持local port不变探测乱序。测试发现乱序在hop 4到hop 5之间。

🔎

延伸解读

乱序探测的核心思路

文章从TCP两端出发,利用traceroute原理探测乱序节点。关键点在于:对于固定的四元组(源IP、源端口、目的IP、目的端口),网络应保持路径一致。通过固定本地端口,使用TCP traceroute发送不同TTL的包,观察每一跳返回的IP是否唯一,从而判断是否存在多路径导致的乱序。这种方法无需中间设备权限,仅从端点即可定位问题。

工具选择与实现细节

mtr的TCP traceroute功能默认每次使用随机本地端口,导致每次探测的四元组不同,可能探测到所有路径,但无法模拟真实TCP流。作者使用scapy编写脚本,固定本地端口(sport=22334),发送不同TTL的TCP SYN包,并捕获ICMP响应。由于固定端口,不能多线程并发,需串行发送。实际测试中ICMP响应不稳定,需通过循环多次运行并记录日志来收集足够数据。

结果解读与局限性

通过分析日志,过滤无效响应后排序去重,若某一跳出现多个IP,则表明该跳存在多路径。文章示例中hop 5出现两个IP,说明hop 4到hop 5之间存在multipath。但作者最终与网络组确认,该乱序并非导致下载速度慢的根因。这表明该方法能有效发现多路径,但乱序可能由其他因素引起,需结合更多信息综合判断。

❓

Q&A

TCP 乱序问题是怎么发现的?

在遇到 TCP 下载速度很慢的问题时,通过抓包分析发现有很多乱序的包。

traceroute 的工作原理是什么?

traceroute 利用 IP 包的 TTL 字段:发送 TTL=1 的包,第一个路由器将 TTL 减为 0 后丢弃并返回 ICMP 超时消息,从而获知第一个 hop 的 IP;然后发送 TTL=2 的包获知第二个 hop,依此类推,直到收到正确的响应。

mtr 的 TCP traceroute 和 ICMP traceroute 有什么区别?

ICMP traceroute 使用 ICMP 包,没有端口概念,对于 (src ip, dst ip) 路径应一致,每一跳只有一个 IP。TCP traceroute 使用 TCP SYN 包,remote port 可指定,但 local port 每个包随机,导致每次探测四元组不同,可能探测出多条路径,每一跳可能有多个 IP。

如何用 scapy 编写 TCP multipath 探测脚本?

使用 scapy 发送 TTL 递增的 TCP 包,固定 local port(如 sport=22334)和 dport,循环发送并接收回复。如果收到 TCP 包说明到达目的地,否则打印中间 hop 的 IP。代码示例:for i in range(1,20): pkt = IP(dst=hostname, ttl=i)/TCP(sport=22334, dport=9100); reply = sr1(pkt, verbose=0, timeout=5); 根据 reply 判断。

为什么固定 local port 对探测乱序很重要?

固定 local port 可以确保相同的四元组 (src ip, src port, dst ip, dst port) 走同一条路径,从而减少乱序。如果 local port 变化,每次探测的四元组不同,可能走不同路径,无法准确判断乱序发生的节点。

实际测试中如何分析探测结果来定位乱序节点?

通过 bash 循环多次运行探测脚本,将输出重定向到日志文件。然后过滤掉错误包(如包含 '??' 的行),排序去重。理论上每一跳应只有一个 IP,如果某个 hop 出现两个 IP,则说明该跳存在多路径,乱序发生在该跳之前。例如发现 hop 5 有两个 IP,则乱序在 hop 4 到 hop 5 之间。

🏷️

标签

➡️

继续阅读