简短版本:我的网络上的一台 Windows Server 2012 机器在连接到某些网站时会持续出现间歇性的 TCP RST。不知道它们来自哪里。查看 wireshark 日志以了解我的分析和问题。
长版本:
我们在一台服务器上运行缓存网络代理来为我们的小办公室提供服务。一位同事报告说,在连接到某些网站时会收到很多“连接重置”或“页面无法显示”错误,但刷新通常可以解决问题。
我验证了浏览器的行为,然后更直接地在服务器上尝试了非代理浏览器。但是对有问题的站点的 ping 和 traceroute 并没有显示任何问题,问题似乎仅限于 tcp 连接。
然后我编写了一个脚本来测试受影响的网站,方法是通过 cURL 直接向它们发送 HTTP HEAD 请求并检查它们成功的频率。典型的测试如下所示:(这是非代理的,直接在坏服务器上运行)
C:\sdk\Apache24\htdocs>php rhTest.php
Sending HTTP HEAD requests to "http://www.washingtonpost.com/":
20:21:42: Length: 0 Response Code: NULL (0%)
20:22:02: Length: 0 Response Code: NULL (0%)
20:22:22: Length: 0 Response Code: NULL (0%)
20:22:42: Length: 0 Response Code: NULL (0%)
20:23:02: Length: 3173 Response Code: HTTP/1.1 302 Moved Temporarily (20%)
20:23:22: Length: 3174 Response Code: HTTP/1.1 302 Moved Temporarily (33.33%)
20:23:43: Length: 0 Response Code: NULL (28.57%)
20:24:03: Length: 3171 Response Code: HTTP/1.1 302 Moved Temporarily (37.5%)
20:24:23: Length: 3173 Response Code: HTTP/1.1 302 Moved Temporarily (44.44%)
20:24:43: Length: 3172 Response Code: HTTP/1.1 302 Moved Temporarily (50%)
20:25:03: Length: 0 Response Code: NULL (45.45%)
从长远来看,只有大约 60% 的请求会成功,其余的请求都不会返回任何内容,并且 curl 错误代码为:“cURL 错误 (56):从对等方接收数据时失败” 这种不良行为在我测试的网站中是一致的(没有一个网站曾经“变得更好”),并且这种不良行为非常持久,我已经排除故障一个星期了,同事们也报告说这个问题显然已经存在好几个月了。
我在我们的网络上的其他机器上测试了 HEAD 请求脚本:没有问题,所有连接都通过了我的测试列表上的所有站点。然后我在个人桌面上设置了一个代理,当我通过它运行来自有问题的服务器的 HEAD 请求时,所有连接都通过了。所以不管问题是什么,它都是特定于这台服务器的。
接下来我尝试找出哪些网站表现出了连接重置行为:
- 我们的所有内联网站点 (192.168.xx) 均不会断开连接。
- 我测试过的 ipv6 站点都没有断开连接。(我们是双栈的)
- 只有少数互联网 IPv4 站点会断开连接。
- 每个使用 cloudflare 作为 CDN 的站点(我已经测试过)都会断开连接。(但这个问题似乎并不只出现在 cloudflare 站点上)
这个角度并没有产生任何真正有用的效果,所以接下来我安装了 wireshark 来查看请求失败时发生了什么。失败的 HEAD 请求如下所示:(此处为较大的屏幕截图:https://i.stack.imgur.com/RPywb.jpg)
127 48.709776000 192.168.1.142 192.33.31.56 TCP 66 52667 > http [SYN, ECN, CWR] Seq=0 Win=8192 Len=0 MSS=8960 WS=256 SACK_PERM=1
128 48.728207000 192.33.31.56 192.168.1.142 TCP 66 http > 52667 [SYN, ACK, ECN] Seq=0 Ack=1 Win=42340 Len=0 MSS=1460 SACK_PERM=1 WS=128
129 48.728255000 192.168.1.142 192.33.31.56 TCP 54 52667 > http [ACK] Seq=1 Ack=1 Win=65536 Len=0
130 48.739371000 192.168.1.142 192.33.31.56 HTTP 234 HEAD / HTTP/1.1
131 48.740917000 192.33.31.56 192.168.1.142 TCP 60 http > 52667 [RST] Seq=1 Win=0 Len=0
132 48.757766000 192.33.31.56 192.168.1.142 TCP 60 http > 52667 [ACK] Seq=1 Ack=181 Win=42240 Len=0
133 48.770314000 192.33.31.56 192.168.1.142 TCP 951 [TCP segment of a reassembled PDU]
134 48.807831000 192.33.31.56 192.168.1.142 TCP 951 [TCP Retransmission] http > 52667 [PSH, ACK] Seq=1 Ack=181 Win=42240 Len=897
135 48.859592000 192.33.31.56 192.168.1.142 TCP 951 [TCP Retransmission] http > 52667 [PSH, ACK] Seq=1 Ack=181 Win=42240 Len=897
138 49.400675000 192.33.31.56 192.168.1.142 TCP 951 [TCP Retransmission] http > 52667 [PSH, ACK] Seq=1 Ack=181 Win=42240 Len=897
139 50.121655000 192.33.31.56 192.168.1.142 TCP 951 [TCP Retransmission] http > 52667 [PSH, ACK] Seq=1 Ack=181 Win=42240 Len=897
141 51.564009000 192.33.31.56 192.168.1.142 TCP 951 [TCP Retransmission] http > 52667 [PSH, ACK] Seq=1 Ack=181 Win=42240 Len=897
143 54.452561000 192.33.31.56 192.168.1.142 TCP 951 [TCP Retransmission] http > 52667 [PSH, ACK] Seq=1 Ack=181 Win=42240 Len=897
我是这样理解的(如果我错了请纠正我,这不是我的领域):
- 我们打开与网络服务器的 TCP 连接
- 网络服务器 ACK
- HTTP HEAD 请求已发送
- 有一个 RST 数据包,标记为来自 Web 服务器 IP,它会终止连接。
- Web 服务器发送 ACK
- Web 服务器(尝试)使用有效的 HTTP 数据响应 HEAD 请求(951 字节回复包含正确的 HTTP 标头)
- Web 服务器重新传输(几秒内多次)有效的 HTTP 响应,但由于连接已 RST,因此无法成功
那么,如果 Web 服务器已经发送了有效的 RST,为什么它还要继续尝试满足请求?如果 Web 服务器没有生成 RST,那它到底做了什么?
我尝试过但没有效果的方法:
- 禁用 NIC 组合
- 更换网络适配器(更换的 NIC 已知可以正常工作)
- 分配静态 IP。
- 禁用 ipv6。
- 禁用巨型帧。
- 一天晚上将服务器直接插入我们的调制解调器,绕过我们的交换机和路由器。
- 关闭 Windows 防火墙。
- 通过 netsh 重置 TCP 设置
- 禁用服务器上几乎所有其他服务。(我们主要将其用作文件服务器,但也有 apache 和几个数据库)
- 用头撞击桌子(反复)
我怀疑有些事在服务器上正在生成 RST 数据包,但我无论如何也找不到它。我觉得如果我知道:为什么只有这个服务器?或者为什么只有一些网站?那会很有帮助。虽然我仍然很好奇,但我越来越倾向于从轨道上删除并重新开始。
有想法/建议吗?
-谢谢
答案1
您的数据包捕获有一些不寻常的地方:在传出的 SYN 数据包中设置了 ECN 位。
显式拥塞通知是 IP 协议的扩展,允许主机对网络拥塞做出更快的反应。它于 15 年前首次引入互联网,但当时严重问题首次部署时就注意到了这一点。其中最严重的问题是许多防火墙会丢弃数据包或返回 RST当接收到设置了 ECN 位的 SYN 数据包时。
因此,大多数操作系统默认禁用 ECN,至少对于传出连接而言。因此,我怀疑很多网站(和防火墙供应商!)根本就从来没有修复了防火墙。
直到Windows Server 2012发布。微软已启用默认为 ECN从此操作系统版本开始。
不幸的是,最近没有人对互联网站点对 ECN 的响应进行过任何重大测试,因此很难判断 21 世纪初出现的问题是否仍然存在,但我强烈怀疑它们存在,并且您的流量至少有时正在通过这样的设备。
在我的桌面上启用 ECN,然后启动 Wireshark 后,只用了几秒钟,我就捕获了一个主机示例,该主机向设置了 SYN 和 ECN 的数据包发送了 RST,不过大多数主机似乎工作正常。也许我会自己去扫描互联网……
您可以尝试在服务器上禁用 ECN,看看问题是否解决。这也会使您无法使用 DCTCP,但在小型办公室中,您不太可能这样做或不需要这样做。
netsh int tcp set global ecncapability=disabled