linux系统收到SYN但不回SYN+ACK问题排查

简介:

一,背景:

今天下午发现线上的一台机器从办公网登录不上且所有tcp端口都telnet不通,但是通过同机房的其它机器却可以正常访问到出问题的机器。于是就立即在这台出问题的server端抓包分析,发现问题如下:
server端收到了本地pc发的SYN包,但是没有回syn+ack包,所以确认是server端系统问题。tcpdump抓包如下:

wKioL1mKiFzyAHTYAAZzy5AQiS4317.jpg


二,排查

1,发现系统没有任何负载

2,网卡也没有丢包

3,iptables策略也都没问题

4,系统的SYN_RECV连接很少,也没超限

5,系统的文件描述符等资源也都没问题

6,messages和dmesg中没有任何提示或者错误信息

7,通过netstat命令查看系统上协议统计信息,发现很多请求由于时间戳的问题被rejected

1
2
3
# netstat -s |grep reject
     2181 passive connections rejected because of  time  stamp
     34 packets rejects in established connections because of timestamp


三,通过google来协助

发现有同样的人遇见这个问题:

是通过调整sysctl -w net.ipv4.tcp_timestamps=0或者sysctl -w net.ipv4.tcp_tw_recycle=0来解决这个问题,于是我就顺藤摸瓜继续查。


而在查询这两个参数的过程中,发现问题原因如下:

发现是 Linux tcp_tw_recycle/tcp_timestamps设置导致的问题。 因为在linux kernel源码中发现tcp_tw_recycle/tcp_timestamps都开启的条件下,60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。经过测试,我这边centos6系统(kernel 2.6.32)和centos7系统(kernel 3.10.0)都有这问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
     源码函数:kernel 2.6.32 tcp_v4_conn_request(),该函数是tcp层三次握手syn包的处理函数(服务端);
     源码片段:
        if  (tmp_opt.saw_tstamp &&
             tcp_death_row.sysctl_tw_recycle &&
             (dst = inet_csk_route_req(sk, req)) != NULL &&
             (peer = rt_get_peer(( struct  rtable *)dst)) != NULL &&
             peer->v4daddr == saddr) {
             if  (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
                 (s32)(peer->tcp_ts - req->ts_recent) >
                             TCP_PAWS_WINDOW) {
                 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
                 goto  drop_and_release;
             }
         }
         
         tmp_opt.saw_tstamp:该socket支持tcp_timestamp
         sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项
         TCP_PAWS_MSL:60s,该条件判断表示该源ip的上次tcp通讯发生在60s内
         TCP_PAWS_WINDOW:1,该条件判断表示该源ip的上次tcp通讯的timestamp 大于 本次tcp


总结:

我这边和其它同事通过公司出口(NAT网关只有1个ip地址)访问问题server,由于timestamp时间为系统启动到当前的时间,故我和其它同事的timestamp肯定不相同;根据上述SYN包处理源码,在tcp_tw_recycle和tcp_timestamps同时开启的条件下,timestamp大的主机访问serverN成功,而timestmap小的主机访问失败。并且,我在办公网找了两台机器可100%重现这个问题。


解决:

# echo "0" > /proc/sys/net/ipv4/tcp_tw_recycle


四,扩展

1,net.ipv4.tcp_timestamps

tcp_timestamps的本质是记录数据包的发送时间。基本的步骤如下:

  1. 发送方在发送数据时,将一个timestamp(表示发送时间)放在包里面

  2. 接收方在收到数据包后,在对应的ACK包中将收到的timestamp返回给发送方(echo back)

  3. 发送发收到ACK包后,用当前时刻now - ACK包中的timestamp就能得到准确的RTT


当然实际运用中要考虑到RTT的波动,因此有了后续的(Round-Trip Time Measurement)RTTM机制。

TCP Timestamps Option (TSopt)具体设计如下

1
2
3
4
5
6
Kind: 8              // 标记唯一的选项类型,比如window scale是3
Length: 10 bytes     // 标记Timestamps选项的字节数
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| Kind=8 | Length=10 | TS Value (TSval) | TS ECho Reply (TSecr) |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    1          1             4                       4

timestamps一个双向的选项,当一方不开启时,两方都将停用timestamps。比如client端发送的SYN包中带有timestamp选项,但server端并没有开启该选项。则回复的SYN-ACK将不带timestamp选项,同时client后续回复的ACK也不会带有timestamp选项。当然,如果client发送的SYN包中就不带timestamp,双向都将停用timestamp。

tcp数据包中timestamps的value是系统开机时间到现在时间的(毫秒级)时间戳。


参数:

0:停用

1:启用(系统默认值)


2,net.ipv4.tcp_tw_recycle

TCP规范中规定的处于TIME_WAIT的TCP连接必须等待2MSL时间。但在linux中,如果开启了tcp_tw_recycle,TIME_WAIT的TCP连接就不会等待2MSL时间(而是rto或者60s),从而达到快速重用(回收)处于TIME_WAIT状态的tcp连接的目的。这就可能导致连接收到之前连接的数据。为此,linux在打开tcp_tw_recycle的情况下,会记录下TIME_WAIT连接的对端(peer)信息,包括IP地址、时间戳等。这样,当内核收到同一个IP的SYN包时,就会去比较时间戳,检查SYN包的时间戳是否滞后,如果滞后,就将其丢掉(认为是旧连接的数据)。这在绝大部分情况下是没有问题的,但是对于我们实际的client-server的服务,访问我们服务的用户一般都位于NAT之后,如果NAT之后有多个用户访问同一个服务,就有可能因为时间戳滞后的连接被丢掉。


参数:

0:停用(系统默认值)

1:启用










本文转自 leejia1989 51CTO博客,原文链接:http://blog.51cto.com/leejia/1954628,如需转载请自行联系原作者
相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
Kubernetes 网络协议 Nacos
OpenAI 宕机思考丨Kubernetes 复杂度带来的服务发现系统的风险和应对措施
Kubernetes 体系基于 DNS 的服务发现为开发者提供了很大的便利,但其高度复杂的架构往往带来更高的稳定性风险。以 Nacos 为代表的独立服务发现系统架构简单,在 Kubernetes 中选择独立服务发现系统可以帮助增强业务可靠性、可伸缩性、性能及可维护性,对于规模大、增长快、稳定性要求高的业务来说是一个较理想的服务发现方案。希望大家都能找到适合自己业务的服务发现系统。
611 99
|
Kubernetes 负载均衡 微服务
Kubernetes 生态系统中的微服务治理
【8月更文第29天】随着微服务架构的普及,管理分布式系统的复杂性也随之增加。Kubernetes 作为容器编排的事实标准,为微服务架构提供了强大的支持。结合像 Istio 这样的服务网格工具,Kubernetes 能够有效地解决微服务治理中的诸多挑战,如服务发现、负载均衡、流量管理和安全策略等。
267 3
|
Ubuntu 安全 Linux
Linux错误排查:解决Ubuntu 20.4执行sudo apt-get update时出现的libnettle.so.6错误。
很有可能在你得到解决方案时,你也学到了不少Linux修复技巧。祝你处理计算机问题时顺利如麻!永远记得,各种问题总是像老鼠一样从意想不到的地方冒出来。但记住,不管它们跑到哪里,最终都逃不过你的捕鼠器。盖起你的计算机,拾起你的代码,大步向前!
451 28
|
监控 数据可视化 Java
调试技巧 - 用Linux命令排查Java问题
总的来说,使用Linux命令来排查Java问题,需要一定的实践经验和理论知识。然而,只要我们愿意花时间深入了解这些工具,我们就能够熟练地使用它们来分析和解决问题。此外,这些工具只是帮助我们定位问题,真正解决问题需要我们对Java和JVM有深入的理解,并能够读懂和分析代码。
611 13
|
Ubuntu 安全 Linux
Linux错误排查:解决Ubuntu 20.4执行sudo apt-get update时出现的libnettle.so.6错误。
很有可能在你得到解决方案时,你也学到了不少Linux修复技巧。祝你处理计算机问题时顺利如麻!永远记得,各种问题总是像老鼠一样从意想不到的地方冒出来。但记住,不管它们跑到哪里,最终都逃不过你的捕鼠器。盖起你的计算机,拾起你的代码,大步向前!
431 18
|
应用服务中间件 Linux 开发者
用的到linux-tomcat端口占用排查-Day5
通过本文的介绍,详细讲解了在CentOS 8系统上排查和解决Tomcat端口占用问题的方法。从使用 `netstat`、`lsof`和 `ss`命令检查端口占用情况,到使用 `ps`和 `top`命令查找和停止占用端口的进程,再到修改Tomcat端口配置,最后介绍了自动化脚本的方法。希望本文能帮助系统管理员和开发者有效地解决端口占用问题,确保Tomcat服务器的正常运行。
563 11
|
Kubernetes 监控 测试技术
k8s学习--基于Ingress-nginx实现灰度发布系统
k8s学习--基于Ingress-nginx实现灰度发布系统
892 2
k8s学习--基于Ingress-nginx实现灰度发布系统
|
Kubernetes Linux 测试技术
|
安全 Linux 文件存储
在Linux中,服务器开不了机怎么解决⼀步步的排查?
在Linux中,服务器开不了机怎么解决⼀步步的排查?
|
运维 监控 网络协议
在Linux中,如何进行网络故障排查?
在Linux中,如何进行网络故障排查?