什么导致TCP/IP重置(RST)标志被发送?

166

我正在尝试弄清楚我的应用程序的TCP/IP连接每10分钟(准确地说,是在1-2秒内)为什么会出现问题。我运行了Wireshark并发现,在10分钟的不活动后,另一端会发送一个设置了复位(RST)标志的包。谷歌搜索告诉我“复位标志表示接收方已经变得混乱,因此希望中止连接”,但这有点缺少我需要的详细信息。可能导致这种情况的原因是什么?这是不是由途中的某个路由器负责,或者总是来自于另一端点?

编辑: 我的电脑和另一端之间放置了一个路由器(具体是Linksys WRT-54G),我应该在路由器设置中寻找什么?


18
这是另一个:Comcast - Tom Ritter
2
幸运的是,我不依赖康卡斯特,因为这是在局域网内发生的。虽然我希望我也可以那么轻松地把责任推给别人 ;) - Luke
你解决了这个问题吗?我不能发表评论,因为我没有足够的积分,但我遇到了和你一模一样的问题,正在寻找解决方法。 - user444032
1
这个特定案例是指哪个服务?可能可以在套接字上设置keepalive(从应用程序级别),以便长时间的空闲期不会导致某人(中间或不在中间)由于缺乏资源而试图强制连接重置。 - arielf
2
你说 "Comcast"? :D 看看这个相关的代码库:https://github.com/tylertreat/comcast - joonas.fi
12个回答

103

'路由器'可以做任何事情-特别是NAT,可能涉及对流量进行任意数量的有错误的干预...

设备发送RST的一个原因是响应收到关闭套接字的数据包。

很难给出一个坚定但普遍的答案,因为自TCP诞生以来,每种可能的扭曲都被试验过了,各种人可能会插入RST,试图阻止流量。(例如,一些'国家防火墙'就是这样工作的。)


7
路由器要么有10分钟的TCP连接超时,要么启用了“网关智能数据包检测”。 - David Schwartz
2
暗示路由器可能存在漏洞有点牵强。 - user207421

29

运行一个数据包嗅探器(例如Wireshark)也在同行上,查看是同行发送了RST还是中间有人干扰。


19

需要注意的一件事是,许多Linux netfilter防火墙都配置不正确。

如果你有像这样的东西:

-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 

-A FORWARD -p tcp -j REJECT --reject-with tcp-reset 

如果数据包重新排序,防火墙可能会将数据包视为无效,并因此生成重置,这将破坏本来正常的连接。

在无线网络中,重新排序尤其容易发生。

应该改为:

-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 

-A FORWARD -m state --state INVALID -j DROP 

-A FORWARD -p tcp -j REJECT --reject-with tcp-reset 

基本上,每当你有:

... -m state --state RELATED,ESTABLISHED -j ACCEPT 

它应立即跟随:

... -m state --state INVALID -j DROP

最好丢弃数据包,而不是生成潜在的破坏协议的TCP重置。当证明重置是正确的,因为这样可以消除超时时,重置更好。但是,如果有任何可能无效,则可能会导致此类问题。


1
天啊,伙计,非常感谢你!你修好了我的防火墙!我已经寻找解决方案好几天了。在我的情况下,我使用的是 NetworkManager 和 "ipv4.method = shared",必须将此修复应用于上游接口,该接口上有限制性的 iptables 规则。你是如何或从哪里学到这个的? - David

16

我刚花了很多时间来解决这个问题,但是提出的所有解决方案都没有起作用。

原来我们的系统管理员错误地把两个不相关组的服务器分配了相同的静态IP地址,而这两台服务器位于同一个网络上。最终导致VNC连接不稳定、浏览器需要刷新多次才能获取网页等其他奇怪问题。


3
你是如何解决这个问题的? - Adam

10
以下是相关的TCP重置可能被发送的情况:
  • 不存在的TCP端点:客户端向服务器端发送SYN到不存在的TCP端口或IP。服务器将向客户端发送一个复位。
  • SYN匹配现有的TCP端点:客户端向现有的TCP端点发送SYN,意味着相同的5元组。服务器将向客户端发送一个复位。
  • 接受队列已满:当服务器端的接受队列已满且tcp_abort_on_overflow设置时,服务器将向客户端发送一个复位。
  • 半开连接:当服务器重新启动时。然后之前的所有连接都会从服务器端接收到复位。
  • 防火墙:防火墙可以向客户端或服务器发送复位。
  • Time-Wait终止:当客户端处于时间等待状态时,从服务器端接收到消息后,客户端将向服务器发送一个复位。
  • 中止连接:当客户端中止连接时,它可以向服务器发送一个复位。

9

主动关闭方发送RST,因为它是发送最后一个ACK的一方。所以如果它在错误状态下从被动关闭方接收到FIN,则会发送一个RST数据包,向另一方指示发生了错误。


7
正常关闭时,双方都会发送和接收FIN。这种情况没有问题,因此没有理由让一方发出重置信号。第一句话的意思是合理的。 - user207421
3
[RST, ACK]也可以由未被监听的端口接收到SYN的一方发送。在我遇到的一个情况中,RST/ACK大约在第一个SYN后60秒发出。顺便说一句。 - Les
@MarquisofLorne,第一句话本身可能就不正确。但第二句话中的“处于错误状态”短语使它在某种程度上有效。 - Victor Yarema

8

如果有一个进行NAT操作的路由器,特别是一台资源较少的低端路由器,它将首先使最老的TCP会话过期。为了做到这一点,它在数据包中设置RST标志,有效地告诉接收站(非常不优雅地)关闭连接。这是为了节省资源而做出的。


7
一些防火墙会在连接闲置x分钟后自动断开连接。一些互联网服务提供商也会出于各种原因设置他们的路由器以此方式操作。
如今,你需要优雅地处理这种情况,必要时重新建立连接。

2
连接重新建立得很好,问题在于短暂的断开期间会不必要地触发警报。 - Luke
1
我在使用思科PIX/ASA设备时遇到了问题。它们的超时时间默认设置特别短。通常来说,较便宜的设备在这方面会“更好”(也就是超时时间不会那么快)。 - Brian Knoblauch
2
我甚至会补充一句,从持久连接的角度来看,TCP实际上从未完全可靠。它只是偶尔变得更加明显。另一个有趣的例子:有些人可能会实现逻辑,一旦检测到连接关闭或重置,就将TCP客户端标记为离线。然后有时他们不费心给客户端重新连接的机会。这显然是不完全正确的。 - Victor Yarema

2

这是因为网络中有另一个进程向你的TCP连接发送了RST。

通常情况下,以下情况会发送RST:

  • 使用SO_LINGER选项的套接字关闭时,进程关闭套接字
  • 在不关闭套接字的情况下,进程退出时操作系统正在进行资源清理

在你的情况下,似乎有一个进程连接你的连接(IP + 端口),并在建立连接后持续发送RST。


1
在大多数应用程序中,套接字连接都有一个超时时间。如果客户端和服务器之间在超时时间内没有通信,则连接将被重置,正如您所观察到的那样。 一个很好的例子是FTP服务器,如果您连接到服务器并且仅保持连接而不浏览或下载文件,则服务器将断开您的连接,通常是为了让其他人能够连接。我想这就是您在连接方面遇到的问题。因此,请查看服务器应用程序,如果您从那里获得重置,并查看源代码中是否确实为连接设置了超时。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接