惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
酷 壳 – CoolShell
酷 壳 – CoolShell
Forbes - Security
Forbes - Security
S
Schneier on Security
Cyberwarzone
Cyberwarzone
L
Lohrmann on Cybersecurity
NISL@THU
NISL@THU
T
Tenable Blog
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
Schneier on Security
Schneier on Security
K
Kaspersky official blog
AI
AI
Help Net Security
Help Net Security
Hacker News: Ask HN
Hacker News: Ask HN
Security Archives - TechRepublic
Security Archives - TechRepublic
T
Threatpost
Attack and Defense Labs
Attack and Defense Labs
I
Intezer
The Cloudflare Blog
博客园 - 叶小钗
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
IT之家
IT之家
Recent Announcements
Recent Announcements
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
aimingoo的专栏
aimingoo的专栏
The GitHub Blog
The GitHub Blog
宝玉的分享
宝玉的分享
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
O
OpenAI News
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
Microsoft Security Blog
Microsoft Security Blog
B
Blog
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
D
Docker
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
阮一峰的网络日志
阮一峰的网络日志
雷峰网
雷峰网
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
Google Developers Blog

祈雨的笔记

安全多方计算MPC spark原理解析 kueue执行源码分析 spark on k8s执行源码分析 spark-operator源码解析 系统压测遇到的缓存击穿问题 我的世界PC与安卓联机 蚂蚁金服流量投放平台的AIG改造 G1大对象致Old区占用率高 日志打印导致接口响应率下跌分析 Groovy加载类导致OOM分析 ERROR日志打印导致CPU满载 记OceanBase死锁超时 应用发版期间服务响应超时 Ark Serverless初探 系统优化复盘一二三 The user specified as a definer does not exist Kong网关初探 API网关选型调研 CPU火焰图常用工具 配置中心选型调研 root操作Nginx导致用户组错误 基于Proxifier使用代理 FastJSON字段智能匹配踩坑 Nacos初探 记一次Nginx服务器CPU满荷载故障 基于券系统分库分表的思考 limit不参与SQL成本计算致索引失效 Linux常用性能监控命令 golang低版本http2偶现400 hostname in certificate didn't match 常见对称加密原理以及应用 记一次mysql执行DDL导致锁表 mysql磁盘占用查看 mysql对text字段update致磁盘增长 elasticsearch报错index read-only TIME_WAIT与Http的Keep-Alive 记一次TIME_WAIT导致连接数报警 记一次生产事故OOM问题排查 redis分布式锁RedissonLock的实现细节 webservice复杂加密签名(2)java调用 webservice复杂加密签名(1)SoapUI mysql延时关联 利用中间人拦截实现APP内H5窜改 MySQL表字符集不同导致关联查询索引失效 通过SSH隧道远程办公 数据落盘方案 BeanDefinitionRegistryPostProcessor扩展 mysql空间索引 HTTPS攻击 spring循环依赖过程解析 elasticsearch性能优化 mysql IS NULL 使用索引 mysql字符集utf8mb4失效踩坑 常用加密算法 xml与javaBean转换 初探InnoDB MVCC源码实现 mysql索引原理 redis之list源码分析 redis之key过期源码分析 redis之string源码分析 redis之hash源码分析 线程池之ThreadPoolExecutor mysql数据页结构 Using temporary与Using filesort mysql回表致索引失效 springboot(28)HTTP连接池 定时任务之ScheduledThreadPoolExecutor elasticsearch常用script聚合 elasticsearch实现like查询 elasticsearch实现乐观锁 elasticsearch准实时原理 springboot(27)自定义缓存读写机制CachingConfigurerSupport optimizer tracing arthas常用命令 HTTP和HTTPS详解 redis集群选举机制 kafka消息重试 一点压力测试的经验 kafka架构概念 explain分析sql语句字段的解释 JVM问题分析处理手册 logstash过滤器(2)date logstash过滤器(3)dissect logstash编码器(1)json logstash编码器(2)multiline logstash表达式 logstash输入(1)通用选项 logstash输入(3)file logstash过滤器(1)通用选项 logstash输入(2)stdin logstash安装 记一次前端vConsole导致JSON序列化错误排查 解决多个异步操作嵌套问题 fastjson反序列化失败autoType is not support RTMP串流服务 POI自动调整列宽错误 Nginx+Lua实现动态黑名单 使用curl命令模拟POST和GET请求 ResponseEntity下载文件
tcp_tw_recycle引起的TCP握手失败
祈雨的笔记 · 2020-07-04 · via 祈雨的笔记

背景

测试环境的一台Nginx服务器,最近一直被前端同事吐槽网络有问题,经常出现访问HTTP请求时超时,哪怕是静态文件也经常超时。

刚开始以为是公司网络抽风了,也就没放在心上,但持续了一个星期,而且复现率很高,这才反应过来应该不是网络的锅。于是在请求客户端与Nginx服务器上均作了抓包。

本地客户端抓包结果如下图1,请求Nginx服务器TCP握手时超时。结果似乎很明朗,客户端TCP握手的SYN请求丢包导致多次重试,直到重试超时而TCP握手失败。看上去似乎就是网络问题,但这复现率也太高了,于是在服务器上也做了一次抓包。

图2为Nginx服务器抓包图,显示服务器接收到了TCP握手请求,但是未做应答,直到客户端重试超时结束。很明显,并不是网络丢包而导致的TCP握手失败,而是某种机制导致的服务器直接抛弃了客户端的请求报文。

image

image

复现

准备

准备两个Client机器(192.168.50.150、192.168.50.160)以及一个Server机器(118.24.117.115),并且两个Client机器均处于同一个NAT网关下(116.239.x.x)。

image

启用两个Client机器TIME-WAIT连接快速回收,编辑文件/etc/sysctl.conf,添加或修改以下参数:

1
net.ipv4.tcp_tw_recycle = 1

然后执行命令使sysctl.conf的参数生效:

1
2
3
[root@VM_0_10_centos ~]# /sbin/sysctl -p
[root@VM_0_10_centos ~]# cat /proc/sys/net/ipv4/tcp_tw_recycle
1

复现步骤

  1. Client1机器请求Server,Client1抓包和Server抓包如下两张图,TCP握手成功:

image

image

  1. Client2机器请求Server,Client2抓包和Server抓包如下两张图,TCP握手成功:

image

image

  1. Client1机器再次请求Server,Client1抓包和Server抓包如下两张图,TCP握手失败,复现成功:

image

image

通过netstat -s命令查看网络统计时,可以发现每次复现出TCP握手失败后,如下的一行统计值都会对应增长。

1
2
[root@VM_0_10_centos ~]# netstat -s | grep timestamp
2143 packets rejects in established connections because of timestamp

原理

PAWS机制

Per-host PAWS机制

PAWS uses the same TCP Timestamps option as the RTTM mechanism described earlier, and assumes that every received TCP segment (including data and ACK segments) contains a timestamp SEG.TSval whose values are monotone non-decreasing in time. The basic idea is that a segment can be discarded as an old duplicate if it is received with a timestamp SEG.TSval less than some timestamp recently received on this connection.

PAWS机制是基于客户端IP而非客户端IP+端口号的,当服务端开启了net.ipv4.tcp_tw_recycle后,服务端会对SYN报文做时间戳检查。每当快速回收TIME_WAIT连接后,会在60秒缓存该客户端IP的TSval时间戳。在这60秒内如果同一个IP再发起SYN请求时,会校验新请求的TSval是否大于缓存的TSval,保证同一个请求方IP的TSval时间戳是递增的。而对于非递增的SYN请求则直接丢弃处理。

TSval并非真正的时间戳,而是由时间戳依据一定算法算出来的一个值,与时间戳有同等的特性,即随时间单调递增;

如上复现操作时的图,由于Client1和Client2处于同一个NAT网关下,对于Server来说,Client1和Client2的IP相同均为NAT网关的IP。

  1. 当Client1请求Server时,IP(116.239.x.x)的时间戳值TSval为1853021;
  2. 当Client2请求Server时,IP(116.239.x.x)的时间戳值TSval为1927141;
  3. 当Client1再次请求Server时,IP(116.239.x.x)的时间戳值TSval为1864558;

当步骤3请求时,对于Server来说,IP(116.239.x.x)的TSval时间戳小于上次请求的时间戳,因此该SYN请求直接被丢弃了,导致TCP握手失败。

Linux内核的实现

Linux内核源码中,对于PAWS机制的实现很简单,如果客户端的TCP报文中启用了timestamp option,且服务端启用了net.ipv4.tcp_tw_recycle,则会触发PAWS机制检查。

tcp_ipv4.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
...










if (tmp_opt.saw_tstamp &&
tcp_death_row.sysctl_tw_recycle &&
(dst = inet_csk_route_req(sk, &fl4, req)) != NULL &&
fl4.daddr == saddr) {
if (!tcp_peer_is_proven(req, dst, true)) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
goto drop_and_release;
}
}

...
}

tcp_metrics.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool paws_check)
{
struct tcp_metrics_block *tm;
bool ret;

if (!dst)
return false;

rcu_read_lock();
tm = __tcp_get_metrics_req(req, dst);
if (paws_check) {
if (tm &&

(u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL &&

(s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW)
ret = false;
else
ret = true;
} else {
if (tm && tcp_metric_get(tm, TCP_METRIC_RTT) && tm->tcpm_ts_stamp)
ret = true;
else
ret = false;
}
rcu_read_unlock();

return ret;
}

解决

关闭TCP的TIME_WAIT快速回收功能即可:编辑文件/etc/sysctl.conf,添加或修改以下参数:

1
net.ipv4.tcp_tw_recycle = 0

然后执行命令使sysctl.conf的参数生效:

1
2
3
[root@VM_0_10_centos ~]# /sbin/sysctl -p
[root@VM_0_10_centos ~]# cat /proc/sys/net/ipv4/tcp_tw_recycle
0

疑问

查看Linux内核源码后发现,触发PAWS机制检查的前提条件之一是客户端的TCP请求携带了timestamp option,如下图1。但是当使用Windows操作系统时,客户端默认关闭了timestamp option,通过抓包也显示TCP请求中未携带timestamp option,却依然触发了PAWS机制,如下图2。

image

image

参考

  1. Linux内核协议栈丢弃SYN报文的主要场景剖析
  2. Tcp tw recycle打开导致60s内不能两个用户同时登录
  3. 开启tcp_tw_recycle内核参数在NAT环境会丢包