现象:andriod无法连接服务器,iphone可以连接服务器
在公司抓包分析过一次Andriod 偶尔无法与服务器建立连接的问题,起初的测试反映,当运维过去查看的时候,又可以访问,而用iphone手机访问也没有问题,故没有引起重视,而是认为是wfii的原因,因为那片区域全是测试,每个测试双有好几个手机,故在那片加了几个ap接入点,而没有过多久,测试还是抱怨不断,而后认真的得抓包分析了一下,终于重现到了问题。
先说一下公司的环境
办公司环境(网段172)--路由器(nat)--公网--防火墙(nat)--机房内网(网段10)
为什么每次andriod偶尔无法访问,而iphone确没有碰到过,只能对二个设备访问服务器时抓包对比分析。
以下是andriod无法连接时的异常抓包:
219.143.2.115.54047 > 10.2.8.10.http: Flags [S], cksum 0xb237 (correct), seq 1325015326, win 14600, options [mss 1460,sackOK,TS val 457758 ecr 0,nop,wscale 2], length 0
15:57:39.710510 IP (tos 0x0, ttl 63, id 32009, offset 0, flags [DF], proto TCP (6), length 60)
219.143.2.115.51688 > 10.2.8.10.http: Flags [S], cksum 0x1981 (correct), seq 2323482410, win 14600, options [mss 1460,sackOK,TS val 457852 ecr 0,nop,wscale 2], length 0
15:57:42.921079 IP (tos 0x0, ttl 63, id 9660, offset 0, flags [DF], proto TCP (6), length 60)
219.143.2.115.57349 > 10.2.8.10.http: Flags [S], cksum 0x2149 (correct), seq 518181460, win 14600, options [mss 1460,sackOK,TS val 458492 ecr 0,nop,wscale 2], length 0
15:57:42.925062 IP (tos 0x0, ttl 63, id 10422, offset 0, flags [DF], proto TCP (6), length 60)
219.143.2.115.53499 > 10.2.8.10.http: Flags [S], cksum 0x0063 (correct), seq 1103880027, win 14600, options [mss 1460,sackOK,TS val 458492 ecr 0,nop,wscale 2], length 0
15:57:45.260916 IP (tos 0x0, ttl 63, id 55517, offset 0, flags [DF], proto TCP (6), length 60)
219.143.2.115.54047 > 10.2.8.10.http: Flags [S], cksum 0xad85 (correct), seq 1325015326, win 14600, options [mss 1460,sackOK,TS val 458960 ecr 0,nop,wscale 2], length 0
15:57:45.660809 IP (tos 0x0, ttl 63, id 18309, offset 0, flags [DF], proto TCP (6), length 60)
219.143.2.115.45331 > 10.2.8.10.http: Flags [S], cksum 0x0e2b (correct), seq 1938537879, win 14600, options [mss 1460,sackOK,TS val 459040 ecr 0,nop,wscale 2], length 0
15:57:45.733034 IP (tos 0x0, ttl 63, id 32010, offset 0, flags [DF], proto TCP (6), length 60)
219.143.2.115.51688 > 10.2.8.10.http: Flags [S], cksum 0x14cd (correct), seq 2323482410, win 14600, options [mss 1460,sackOK,TS val 459056 ecr 0,nop,wscale 2], length 0
以下是iphone抓包的结果
16:36:03.770763 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [S], seq 2604085590, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 672936356 ecr 0,sackOK,eol], length 0
16:36:03.870792 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [S], seq 2604085590, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 672936456 ecr 0,sackOK,eol], length 0
16:36:03.970639 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [S], seq 2604085590, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 672936556 ecr 0,sackOK,eol], length 0
16:36:04.070785 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [S], seq 2604085590, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 672936656 ecr 0,sackOK,eol], length 0
16:36:04.173111 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [S], seq 2604085590, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 672936756 ecr 0,sackOK,eol], length 0
16:36:04.274707 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [S], seq 2604085590, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 672936855 ecr 0,sackOK,eol], length 0
16:36:04.475541 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [S], seq 2604085590, win 65535, options [mss 1460,sackOK,eol], length 0
16:36:04.475557 IP 10.2.8.10.http > 219.143.2.115.13386: Flags [S.], seq 3500626396, ack 2604085591, win 14600, options [mss 1460,nop,nop,sackOK], length 0
16:36:04.505347 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [.], ack 1, win 65535, length 0
16:36:04.505563 IP 219.143.2.115.13386 > 10.2.8.10.http: Flags [P.], seq 1:350, ack 1, win 65535, length 349
从二次抓包结果看出,andriod多次syn后,服务器始终没有响应,而iphone多次syn后,连接成功了,但是不合理是为什么syn重试这么次才连建立成功。
初步简单的对比了一下这二种的包的区别,发现是Tcp扩展选项的占的字节数不样,为了32位对齐,andriod就一个nop填充(wscale 3个字节,填充了一个nop,andriod使用了linux内核,合并了timestamp和sack),iphone确有5个填充(wsack 3个字节,填充一个字节,sack二个字节,填充二个字节,timestamp十个字节,填充二个字节)。
当时第一感觉是不是防火墙因为tcp选项的不同而有什么动作,为什么iphone没有影响,干脆我打开andriod的控制台,手工关了rfc 1323定义的tcp扩展选项。把以三个选项全部置0。
/proc/sys/net/ipv4/tcp_timestamps
/proc/sys/net/ipv4/tcp_sack
/proc/sys/net/ipv4/tcp_window_scaling
然后让测试用Andriod用这台手机测试,测试多次,问题没有重现。问题差不多可以定位在这个扩展,不同能去更改所有的Andriod手机的这几个选项,只能去调整服务器。
在netstat -s 发现很多Timestamp(passive connections rejected because of time stamp)的Syn包丢失,突然想起之前网上看到timestamp引起包丢失的问题,在rfc1323文档也有定义,rfc1323定了timestamp扩展以后,为了防止syn重传,当一个tcp连接释放以后,如果开启tcp_tw_recycle,在timewait时间里,如果还有该ip syn包到达服务器,而且timestamp是之前的间,linux会认为是重试的syn包,故而会直接drop掉,这种情况通常发生在nat环境里,尤其一个公司通过nat多个共享上网,而且多人频繁访问同一个应用服务。为什么iphone的没有偶尔连接失败的情况,我再仔细分析iphone抓包时,才发现原因如下图,
iphone在重试几次无法连接的时候,发现无法建立连接的时候,会自动的把包的Timestamp关掉。从这点可以看出,iphone tcp协议栈设计还是比linux考虑的全面。
解决方法:关闭服务器的tcp_tw_recycle
echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle
来源:oschina
链接:https://my.oschina.net/u/727579/blog/156182