服务器上出现大量的SYN_RECV或者SYN_SENT状态的TCP连接的问题分析
情况:服务器程序在某一时刻,程序端口正常在运行,telnet程序的端口无法打开,但是客户端请求能正常连接;
针对出现这一系列的故障,百思不得其解,然后查日志,数据抓包,然后在处理过程中针对SYN_RECV的相关问题,分享给大家,仅供参考;
等灵异的问题处理完成,再把结果和处理的过程分享给大家;
[stock@localhost ~]$ netstat -an | grep SYN_RECV 如下是显示的一部分
tcp 0 0 222.186.14.x:8080 117.136.1.144:29326 SYN_RECV
tcp 0 0 222.186.14.x:8080 117.136.31.149:31339 SYN_RECV
tcp 0 0 222.186.14.x:8080 117.136.31.149:31403 SYN_RECV
tcp 0 0 222.186.14.x:8080 211.137.119.5:29882 SYN_RECV
tcp 0 0 222.186.14.x:8080 123.151.172.2:16151 SYN_RECV
tcp 0 0 222.186.14.x:8080 1.197.233.48:36075 SYN_RECV
tcp 0 0 222.186.14.x:8080 117.136.8.83:23834 SYN_RECV
tcp 0 0 222.186.14.x:8080 117.136.20.6:48201 SYN_RECV
tcp 0 0 222.186.14.x:8080 117.136.35.16:22842 SYN_RECV
[stock@localhost ~]$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 500 当前建立的连接是500个
SYN_RECV 307 SYN_RECV同步空闲字符接收到的状态,主要是为了等待第三次握手
[stock@localhost ~]$
根据以上的问题,首先我们来判断SYN_RECV是怎么产生的尼?
SYN_RCVD是TCP三次握手的中间状态,是服务端口如应用服务器端口,收到SYN包并发送[SYN,ACK]包后所处的状态。这时如果再收到ACK的包,就完成了三次握手,建立起TCP连接。
SYN_RCVD包产生的原因主要有两种可能:
第一种可能:客户端或者请求端没有收到服务器的SYN_ACK包,
第二种可能:客户端或者请求端收到服务器的SYN_ACK包,但是客户端没有返回给服务端ACK;
分析且如何切如何判断这两种问题:
针对第一种问题:客户端或者请求端无法收到服务器端发送过来的syn ack数据包,第一种基本可以简单的判断,可以判断网络是否通畅,是否网络有安全设置,如最简单的是使用ping来查看;
针对第二种问题:这种问题少文有点复杂,一种是服务端发送的ACK客户端拒绝接受,比如SYN Flood类型的DOS/DDOS攻击;还有一种可能是,客户端或者请求端收到的SYN,ACK包不合法,一般的SYN包目的服务地址和应答的SYN,ACK包的源地址不同。如果在这种情况下只配置了DNAT而不进行SNAT的服务网络环境下容易出现,主要是由于inbound(SYN包)和outbound([SYN,ACK]包)的包穿越了不同的网关/防火墙/负载均衡器,从而导致[SYN,ACK]路由到互联网的源地址(一般是防火墙的出口地址)与SYN包的目的地址(服务的虚拟IP)不同,这时客户机无法将SYN包和[SYN,ACK]包关联在一起,从而会认为已发出的SYN包还没有被应答,于是继续等待应答包。这样服务器端的连接一直保持在SYN_RCVD状态(半开连接)直到超时。
附:TCP的三次握手,四次端口
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器 进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据.
TCP的四次断开:
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
原文链接:http://www.rsyslog.net/archives/164
正常情况下,出现SYN_SENT的state应该很少,并且短暂
如果一个连接长时间处在SYN_SENT,有可能是没连上,比如端口没有打开
如果发现有很多SYN_SENT出现,那一般有这么几种情况
一是你要访问的网站不存在或线路不好
二是用扫描软件扫描一个网段的机器,也会出出现很多SYN_SENT,另外就是可能中了病毒了,例如中了"冲击波",病毒发作时会扫描其它机器,这样会有很多SYN_SENT出现。
https://blog.csdn.net/icebergliu1234/article/details/104737407
如何制造一个长时间处于SYN_SENT状态的socket?长时间的定义是超过3秒吧, 至少有时间能开个终端,用netstat看一下
比如A发送SYN_SENT给B,假如B是一台电脑,那么在B的防火墙里把TCP相关的端口deny掉。A进入SYN_SENT状态后得不到应答,就会进入RTO状态,在该状态指数退避的后期重传周期可能长达十数秒,应该足够你观测了。
iptables -D INPUT --protocol tcp --sport 22 --tcp-flags ALL SYN,ACK -j DROP
telnet 127.0.0.1 22
通过这样的方式,就可以制造出SYN_SENT状态的socket了。