关于Linux内核4.12之前版本中, tcp_tw_recycle开启后NAT环境总是出问题的分析
isn = TCP_SKB_CB(skb)->when;
if(!isn){
......
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; } }
补充:这里有条件 !isn, 没有特别懂这个isn是干嘛的,(如果非要牵强的解释,貌似isn是上面提到的初始化序列号, 但是吧,又觉得不太对,因为tcp_skb_cb里when后面的解释是用来计算 RTT的(路由往返时间)感觉这东西跟时间戳有关??(当然,在connect中,SEQ非要算时延,也是可以的吧? +1 = 4MS,不过乱糟糟的,wireshark里面有个raw_seq,又不知道是咋整出来的?所以理论上,不为0的可能性很大,所以这个判断条件,是会命中的),不过肯定不是IS SYNC标识,因为 TCP_SKB_CB中,有个TCP_FLAGS的属性,这个应该是那些各种SYN ACK FIN之类的标志)
这里可以大概看出来,如果数据包中的option属性中,包含了tstamp(也就是如果client如果开了时间戳),且本地(服务端)tw_recycle属性也开启了,就从 inet_csk_route_req中取出 f14, 这里的inet_csk_route_req,有介绍说是出路由缓存,大概意思就是跟本次连接有关的上次传输(或者连接???)的信息吧???
然后紧接着比较了f14的目标IP和本次请求的来源IP, 按照出路由,那么目标IP肯定是NAT的外网IP, 而本次请求的来源IP,自然也是NAT的IP
那么,只看IP地址相同,就会进入tcp_peer_is_proven,这里面会检查时间戳,自然就会出现如果时间戳有差异,会被API服务器丢弃连接的情况了。
这个问题,其实很多人都在网上有分析过,但是,看了不少文章,很少有人把per-host PAWS检查明确的解释为只检查两次连接的IP,就会继续检查时间戳。
当然,这个问题,也是因为自己对内核的一些逻辑实在不清楚导致的,也许大家的知识储备中,对这种情况十分清楚,导致文章里,也仅是一笔带过。
这个分析里,依然很多细节都不清楚:
PAWS具体是为了解决什么问题?
SEQ到底如何递增到最大值?
INET_CSK_ROUTE_REQ函数的具体功能和逻辑是什么?
这些留待之后有时间,再继续深入了。