我有一个 TCP 服务器正在监听运行 Ubuntu 12.04.3(内核 3.8.0-31-generic)的计算机(“服务器”)。它接收来自 2 台不同客户端计算机的连接。计算机 A 运行 Ubuntu 12.04.4(3.11.0-17-generic),计算机 B 运行 Ubuntu 11.10(3.0.0-32-server)。
如果服务器上启用了 TCP 时间戳 (sysctl net.ipv4.tcp_timestamps=1),则有时会“忽略”来自机器 A 的 SYN 数据包。使用服务器上的 tcpdump(在非混杂模式下),我可以看到 SYN 正常到达,并且校验和正确 - 只是没有响应 - 没有 SYN/ACK 也没有 RST。机器 A 在放弃之前多次重新传输 SYN。在机器 A 上运行的客户端软件(在本例中为 wget)立即重试新的连接并成功,立即获得 SYN/ACK。
机器 B 与同一台服务器没有问题,并且其流量看起来很正常 - 它也使用与机器 A 相同的 TCP 选项(从我从捕获文件中看到的情况来看)。禁用服务器上的 TCP 时间戳可使一切正常运行。
然而,被忽略的 SYN 数据包中的时间戳对我来说似乎是有效的,所以我不确定它们为什么会导致问题,或者它们是否是根本原因。
我在这里放了一个匿名的 pcaphttps://www.dropbox.com/s/onimdkbyx9lim70/server-machineA.pcap。该图是在服务器 (10.76.0.74) 上拍摄的,显示机器 A (10.4.0.76) 成功执行 HTTP GET(数据包 1 至 10),然后 1 秒后再次尝试获取相同的 URL(数据包 11 至 17),但其 SYN 被忽略。数据包 18 至 27 是另一个成功案例。
我怀疑这个问题与“为什么服务器不会发送 SYN/ACK 数据包来响应 SYN 数据包“虽然禁用时间戳是一种解决方法,但我想了解发生了什么。这只是一个错误吗?
没有运行本地防火墙。服务器处理相当多的 TCP 连接(一次大约 32K),但有大量的可用内存/CPU。在 pcap 中显示的测试时,机器 A 和服务器之间没有其他 TCP 连接。没有迹象表明服务器应用程序的接受队列突然填满(除此之外,我猜这应该会影响两个客户端)。由于在服务器上获取的 pcap 中数据包看起来正常,因此似乎没有中间的网络设备破坏了设备。
我最初在 ubuntu 论坛上发布了此帖,但事后看来,这可能是更合适的位置。希望能提供线索。
答案1
就我而言,以下命令修复了 Linux 服务器缺少 SYN/ACK 回复的问题:
sysctl -w net.ipv4.tcp_tw_recycle=0
我认为这比禁用 TCP 时间戳更正确,因为 TCP 时间戳毕竟是有用的(PAWS、窗口缩放等)。
文档tcp_tw_recycle
明确指出,不建议启用它,因为许多 NAT 路由器会保留时间戳,因此PAWS因为来自同一 IP 的时间戳不一致。
tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4) Enable fast recycling of TIME_WAIT sockets. Enabling this option is not recommended for devices communicating with the general Internet or using NAT (Network Address Translation). Since some NAT gateways pass through IP timestamp values, one IP can appear to have non-increasing timestamps. See RFC 1323 (PAWS), RFC 6191.