我有一个 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 数据包中的时间戳对我来说似乎是有效的,所以我不确定它们为什么会导致问题,或者它们是否是根本原因。
我在这里放了一个匿名 pcap https://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 论坛上发布了这个,但事后看来这可能是一个更合适的位置。希望借出线索。
就我而言,以下命令修复了 Linux 服务器缺少 SYN/ACK 回复的问题:
sysctl -w net.ipv4.tcp_tw_recycle=0
Run Code Online (Sandbox Code Playgroud)
我认为这比禁用 TCP 时间戳更正确,因为 TCP 时间戳毕竟很有用(PAWS、窗口缩放等)。
上的文档tcp_tw_recycle
明确指出不建议启用它,因为许多 NAT 路由器会保留时间戳,因此PAWS 会启动,因为来自同一 IP 的时间戳不一致。
Run Code Online (Sandbox Code Playgroud)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.