🔗 识别和规避存在损坏的 TCP 窗口缩放的网站
🔗 摘要
互联网上的许多服务器现在都实现了 TCP 窗口缩放(在 RFC1323 中有说明)。TCP 窗口缩放是在 TCP 握手过程中实现的,它允许互联网连接的主机在等待对端确认(ACKnowledge)之前传输更多数据。当与距离超过一百毫秒左右的主机通信时,这一点变得尤为重要。
不幸的是,许多防火墙错误地实现了窗口缩放处理,当从配置为使用 TCP 窗口缩放的服务器连接时会导致问题。下面介绍的症状通常会导致流量传输停止。
默认情况下,大多数现代服务器操作系统都启用了 TCP 窗口缩放。
🔗 症状
-
连接正常完成;
-
可能传输了一些数据;
-
最终连接“挂起”,没有进一步的进展,
-
有时下载的文件可能看起来被截断。
🔗 解释
普通的 TCP 窗口使用 16 位窗口大小运行,默认情况下,在任何时候最多允许 64 KB(65536 字节)的数据在传输中。这对于低延迟链路来说效果很好(因为 TCP 吞吐量可以简单地认为是窗口大小 * RTT;即在收到 ACK 之前会发送(窗口大小)数据,而收到 ACK 需要(RTT)时间),但在高延迟的国际链路上效果不佳。
引入 TCP 窗口缩放是为了让对端能够协商更大的窗口大小,从而在需要 ACK 之前传输更多数据。缩放选项将窗口大小向右移动一定的位数——缩放因子——从而允许更大的窗口。
TCP 缩放因子为 0 表示正常窗口大小(0 - 65536 字节,以一字节为增量);TCP 缩放因子为 1 表示窗口大小为 0 到 131072 字节,以两字节为增量;TCP 缩放因子为 2 表示窗口大小为 0 到 262144 字节,以四字节为增量;依此类推。
问题出现在防火墙或其他数据包检查和过滤设备将其“肮脏的手”伸向数据包流时。对于不理解 TCP 选项(如 TCP 缩放)的防火墙,正确的行为应该是完全移除该选项。然而,一些防火墙正在**清零** TCP 缩放字段。双方都认为对方已确认其发送的缩放因子,而实际上它们确认的是缩放因子 0。然后流量开始正常传输,但双方通告的 TCP 窗口被错误解释。
结果可能难以预测——一些人报告 TCP 性能非常慢;另一些人报告连接在传输一些数据后会停止(随着通告的 TCP 窗口大小的增加,对端认为自己发送的内容与另一方实际解释的内容之间的差异也随之增加。)
台式机与服务器直接通信时这不是什么大问题,因为台式机通常配置有较小的窗口大小和 TCP 缩放因子,因此它们与服务器认为的差异往往不大。现代服务器操作系统倾向于使用更大的窗口大小和 TCP 缩放因子,这往往会加剧问题。
🔗 规避方法
规避方法是在您的 Squid 代理服务器上完全禁用 TCP 窗口缩放。在 Linux 上,可以通过以下方式实现:
- echo 0 > /proc/sys/net/ipv4/tcp_default_win_scale
其他平台会以不同的方式实现。
另一种可能性是为目标网络添加特定路由,强制 TCP 窗口大小最大为 65535。目前 Squid 无法自动完成此操作。
🔗 致谢
感谢 Adrian Chadd 从各种来源收集并整理了本文。
参考资料
-
http://www.faqs.org/rfcs/rfc1323.html - TCP 扩展以获得高性能
-
http://lwn.net/Articles/92727/ - TCP 窗口缩放和损坏的路由器
类别: 知识库
导航: 站点搜索、站点页面、类别、🔼 向上