什么可能导致 TCP/IP 重置 (RST) 标志无法发送?
我有两台 Linux 服务器(让我们将它们命名为 A 和 B),连接到同一个(非托管)交换机。我已在两台服务器上禁用防火墙(所有表中均无规则,所有默认策略均设置为接受)。因此,没有什么可以阻止一台服务器发送任何 TCP/IP 数据包,而另一台服务器按原样接收它们。
现在,在 A 上我们运行 TCP 服务器应用程序,它侦听/接受传入连接,然后循环发送大量数据到连接的客户端。它不会尝试从客户端读取数据,并且如果/当客户端断开连接时,预计在对套接字执行 write() 时会出现 EPIPE 错误。
接下来,在 BI 上运行 nc (netcat) 作为客户端应用程序,连接到 A 上的服务器应用程序,开始接收数据,几秒钟后我按 Ctrl-C 中断此连接。
我看到的是,A 上的服务器应用程序只是挂在 write() 中,它没有 EPIPE 或任何其他错误。
我已经使用 tcpdump 跟踪了 TCP/IP 数据包,这是我所看到的:
- 在中断 B 上的 netcat 后,B 向 A 发送 FIN,A 正确地用 ACK 回复该 FIN - 所以,现在我们有了公平的半开放 TCP连接,下一步没问题
- ,A 尝试使用通常的 ACK 和 PSH,ACK 数据包向客户端发送下一个数据,这也是预期的且正确的,
- 但是,B 不会以任何方式回复这些数据包(虽然我希望它回复带 RST 数据包因为它接收到已经关闭/不存在的 TCP 连接的数据包)
- A 没有收到 ACK,因此它停止发送新数据并开始重新发送旧数据包(此时下一次对 write() 的调用挂起)
我也尝试在 A 上运行 netcat(因此客户端和服务器应用程序都在同一台物理服务器上运行),这样一切都会按预期工作 - 在我使用 Ctrl-C 中断 netcat 后,服务器应用程序立即获得 EPIPE。 tcpdump 显示有 RST 数据包按预期发送。
那么,在这种情况下,什么可能会导致不发送RST呢?
我使用的是 Hardened Gentoo Linux,最新的内核 2.6.39-hardened-r8,没有任何特定的 sysctl 网络相关配置。
注意到这些服务器上有大量的网络活动可能很重要,也可能不重要,netstat -alnp
在任何时刻都会列出大约 5000 个 tcp 连接,我认为每秒大约有 1000 个连接打开和关闭平均的。通常会在内核日志中看到类似这样的内容(但端口号与上面讨论的服务器应用程序使用的端口号不同):
TCP: Possible SYN flooding on port XXXXX. Sending cookies.
net_ratelimit: 19 callbacks suppressed
TCP 会话通常如下所示: http://i54.tinypic.com/1zz10mx.jpg
I've two linux servers (let's name them A and B), connected to same (unmanaged) switch. I've disabled firewall on both servers (no rules in all tables, and all default policies set to ACCEPT). So, nothing should prevent one server to send any TCP/IP packets and another server to receive them as is.
Now, on A we run TCP server application, which listen/accept incoming connections, and then send a lot of data in a loop to connected client(s). It doesn't try to read from client, and expect to get EPIPE error while doing write() to socket if/when client disconnects.
Next, on B I run nc (netcat) as client application, connects to server application on A, begin receiving data, and few seconds later I press Ctrl-C to interrupt this connection.
What I see, is server application on A just hangs in write(), it doesn't got EPIPE or any other error.
I've traced TCP/IP packets using tcpdump, and here is what I see:
- after interrupting netcat on B, B send FIN to A, which correctly reply with ACK to that FIN - so, now we've fair half-open TCP connection, which is ok
- next, A tries to send next data to client with usual ACK and PSH,ACK packets, which is also expected and correct
- BUT, B doesn't reply in any way to these packets (while I expect it to reply with RST packet because it receiving packets to already-closed/non-existing TCP connection)
- A doesn't got ACK, so it stop sending new data and start resending old packets (and at this point next call to write() hangs)
I've also tried to run netcat on A (so both client and server applications runs on same physical server), and this way everything works as expected - server application got EPIPE immediately after I interrupt netcat with Ctrl-C. And tcpdump show there is RST packet sent as expected.
So, what may cause to not sending RST in this case?
I'm using Hardened Gentoo Linux, up-to-date, kernel 2.6.39-hardened-r8, without any specific sysctl network-related configuration.
It may or may not be important to note there is significant network activity on these servers, about 5000 tcp connections listed by netstat -alnp
at any moment, and I think about 1000 connections opens and closes every second in average. It's usual to see in kernel log something like this (but port number is different from used by server application discussed above):
TCP: Possible SYN flooding on port XXXXX. Sending cookies.
net_ratelimit: 19 callbacks suppressed
Here is how TCP session usually looks like: http://i54.tinypic.com/1zz10mx.jpg
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
此行为是我的强化内核中启用功能的结果:
CONFIG_GRKERNSEC_BLACKHOLE:
如果您在此处选择“是”,则不会发送 TCP 重置或 ICMP 目标不可达数据包来响应发送到不存在关联侦听进程的端口的数据包。该功能同时支持IPV4和IPV6,并且可以使Loopback接口免于黑洞。启用此功能可以使主机更能抵御 DoS 攻击,并降低扫描仪的网络可见性。所实现的黑洞功能相当于 FreeBSD 黑洞功能,因为它阻止对所有数据包的 RST 响应,而不仅仅是 SYN。
This behavior is result of enabled feature in my hardened kernel:
CONFIG_GRKERNSEC_BLACKHOLE:
If you say Y here, neither TCP resets nor ICMP destination-unreachable packets will be sent in response to packets sent to ports for which no associated listening process exists. This feature supports both IPV4 and IPV6 and exempts the loopback interface from blackholing. Enabling this feature makes a host more resilient to DoS attacks and reduces network visibility against scanners. The blackhole feature as-implemented is equivalent to the FreeBSD blackhole feature, as it prevents RST responses to all packets, not just SYNs.