SSL Handshake Failure【记一次线上问题处理过程】

记录一次高并发流量下,关于HTTPS问题从出现,到分析,最后解决得整个过程。虽然最后证明了这与协议无关,与TLS无关,但这个过程仍然有很大得借鉴意义。
发挥刨根问底得精神,将问题处理到极致。

从点到线,再从线到面,进而推而广之到空间。

1 现象

客户端抓包:client发送client hello,服务器确认后,没有发送server hello,而是等待超时后,发送FIN包,断开连接。
这里写图片描述

从客户端抓包来看,客户端怀疑服务端未发送server hello,那就再服务端抓包查看 serverhello 和client hello的数量是否一致。

ssl.handshake.type2 server hello 的过滤
ssl.handshake.type
1 client hello 的过滤

考虑一个问题,如果服务端根本没有收到客户端发来的client hello,那么也就没有对应的 server hello,其数量还是一致的。因此,也有可能是中间网络的原因导致服务端未收到client hello,继而服务端等待超时,断开连接。

综上,可能有两个原因导致客户端与服务端抓包看到的现象:

  1. 假设1 :服务端收到了client hello,也回复了server hello,但是客户端没有收到server hello,在TCP三次握手建连后,导致超时断开连接。
  2. 假设2 :客户端发送了client hello,服务端没有收到,在TCP三次握手建连后,导致等待超时。

2 服务端抓包验证

2.1 假设1的验证

为了验证以上两个猜想,只能在服务端抓包看。在茫茫流量包中找到对应的无异于大海捞针,还好,有wireshark强大的过滤功能。
开始利用 ssl.handshake.type == 1ssl.handshake.type ==2 来可以验证服务端在第一种假设情况下,是否回复了server hello。很可惜的是,一切正常,client hello 与server hello 的数量一致,那么范围就缩小了。因此在假设1 的情况下,可以确保我们的服务端应用没问题,肯定是发送了server hello 的。那么接下来就是寻找对应的数据包了,看到了客户端的序列号seq=1tcp.seq == 1,以及client hello中的client random作为过滤条件【后来证明使用client random 过滤是有问题的】,结合客户端出错时间,找出对应的数据流应该不是问题。

遗憾的是,没有找到对应时间点,并且服务端接受client hello,回复server hello 最后等待10秒这样行为的数据包。【心疼自己一秒钟】。

其实还有个思路可以直接判断服务端没有发送server hello,从客户端的抓包来看,服务器发送FIN的序列号为1 ,server hello怎么也得几K的字节量,所以根据这个信息,可以直接判断服务端没有发送server hello!【表扬一下自己的聪明才智!】

2.2 假设2 的验证

那么接下来就只能看第二种假设了:服务端没有收到client hello。那么根据分析,TCP的三次握手应该是有的。那么服务端的行为就应该是TCP三次建连完成,然后空等十秒钟,最后发送fin,断开连接。
根据这个思路,那么继续过滤服务端抓包。tcp.flags.fin == 1,并且是服务端主动发送的FIN包。
根据这个条件,终于看到了想看到的结果。【欢呼】
这里写图片描述

至此,可以得出结论,服务端没有收到客户端发来的client hello。

3 代理【劫持】

一开始分析包的的时候,没有注意代理这个问题,其实很容易就看出来。
关于TTL的文章:IP协议的TTL

  • TTL: 客户端抓包显示收到服务端的TTL是253,但是服务端抓包显示初始TTL的值为64,很明显,中间使用了代理。
  • TTL的减量:TTL为253的包,说明只经过了两个路由(255-2=253),所以可以判断,是客户端内部的代理,基本可以排除是电信运营商的代理(劫持)。

客户端是使用了代理来跟服务端进行https通信的。代理可能是TCP透传或者HTTPS层的代理。

  1. 如果是HTTPS层的代理,但是由于https本来是预防劫持的,上面这种情况可能是客户的代理也有客户的证书与私钥,或者客户端与代理认证的时候不校验合法性,即可通过代理来与我们服务端进行数据交互。
  2. 如果是TCP透传,那么http层的数据是不会发生变化的,比如client hello中的 client random,是不会变化的。可以根据这个判断是否是TCP透传。而https层的代理,就一定会改变,因此在不知道是否有代理的情况下,根据clienthello判断两端数据包是否是同一条数据流的做法是有待商榷的。

4 结论

客户端抓包,显示“服务端”(代理)回复了 ACK client hello,意味着服务器已收到client hello,下一步需要回复server hello,但是真实的服务端抓包并没有收到client hello,此client hello ack 可以明确是中间某代理设备所回复。此时客户端在等待服务端回复server hello,服务端在等待客户端发client hello,客户端服务器双方都进入等待环节直到最后超时,服务端发fin包。

更新:
又看了一下客户端正常的数据包,发现对于 client hello 的ACK每次都会重传一次。
这里写图片描述

从此可以更加肯定的说是中间代理的问题了,也能看出中间代理的工作方式。应该是中间代理在转发client hello 的时候,没有转发成功收到服务端的ACK,就自己私自回复了客户端ACK,导致两端都在等。
刚开始分析包的时候,就注意到了,每个正常的包都会重传一次clienthello 的ACK,并且都是ACK 同一个 client hello消息。当时没有太在意,放过了,哎,做学问还是要严谨、锱铢必较啊。
#5 后续-1

事情并不是像推理的那么简单—之中间代理:
1- 既然上面提到是中间代理在转发过程中存在问题,那么就要证明中间代理确实出了问题。
2- 至于中间代理在收到服务端后发送fin还是先发送fin这个问题,是属于代理的逻辑问题。
3- 如果中间代理转发了client hello,但是服务端没有收到,那问题可能就不是中间代理的问题,而是中间某一环节出了问题。

抓包证明中间代理【与客户详细沟通,这个中间设备是他们的一个内部设备。】的确发送了 client hello 的数据包,而且重传了三次!
重传了3次我们服务器都没有收到!这就麻烦了,这个锅瞬间又被客户甩给了我们。
怎么办?运营商给弄丢了?我们自己会不会在哪一个环节出现问题?
本着遇到问题,先找自己的原因的法则,假设运营商那里不出问题的情况下,我与网络组的同事了解了公司的网络架构,大致就是从运营商来了数据之后,首先经过我们的核心交换机,然后,向后转发给后端的两个LVS,LVS再转给real server。
那么数据流就是经过交换机–LVS—RS,先前已经证明RS没有收到client hello。那么有可能是交换机收到了但没有转发给LVS,或者LVS收到了但没有转发给RS。那就要交换机抓包了,根据网络组同事普及知识,交换机抓包需要镜像抓包到一台设备上才可以,具体操作,网络组同事完成的。同时在两个LVS设备上抓包。
坐等复现了,然后过滤包,找到出错时间点对应的包,发现了问题:交换机上已经向LVS转发了数据包,但是LVS没有收到数据包!

这下,好了,问题出在我们这里了!确定么?NO!最后再说WHY!

难道是线路出现了问题?呵呵,这个最不可能出现问题的地方,当然直接排除了。不可能每次都是同样的错误在同样的握手阶段。
那就只能怀疑到LVS负载上了?嗯,有可能,负载有问题,那就使用单LVS,这里我们使用的双主LVS,并不是主备LVS。使用单LVS后,果然不再出现错误现象。

那么,问题解决了,但是为什么还不知道,总不能为了这个问题修改网络架构,这个代价有点儿大。况且真正的原因还不知道,单LVS只是避免了错误发生,作为研发人员的职责,并不是避免错误发生,而是杜绝错误发生。那就要继续刨根问底了。

继续分析交换机转发与LVS收到的数据包。
对比正常的数据流与异常数据流,公司一位骨灰级大神级人物出场了:观其面相,鬓发已白,年已过半百,深邃的眼神中永远带着慈善的目光 … …
我介绍了事情的来龙去脉,已经截至目前的所有进展以及发现后,大神直接看抓包!
“唉,我发现一个问题,怎么两次数据包过来的MAC地址不一样啊!”
只见大神眉头一紧,在小黑板上画了一下内部的网络架构,说
“为什么同一个数据流上会被交换机在不同的端口发送出去?”
“找交换机厂商问问!”
那么,问题的直接原因定位了,就是同一个数据流上的数据包,被交换机在不同的端口转发给不同的LVS。

交换机是华为的,第二天,华为那边来了人,简单介绍了一下情况,共同讨论了一下,得出的结论是:运营商导致!
因为一个数据流从源到目的,中间要经过运营商不同的设备,运营商那里把同一条流从不同的设备转发给了我们交换机,那么其中的源mac地址就会发生改变,再经过交换机的负载均衡,如果后面有多个LVS,目的MAC也会发生变化。所以这个问题出在 运营商那边的负载规则,因为无法让运营商做调整,所以我们做本地负载优化。

就是让一个数据流在交换机负载时,不拆分到不同的端口进行转发,也就类似于基于流的负载。而一般标准业务都是按照5元组hash来做选路,如果源目mac地址发生变化,那么选路就会发生变化,但是如果在交换机上做基于源IP和源端口的负载,那么同一条流就不会被拆分。!

华为交换机厂家结论:
此节点多个万兆设备接运营商,当时网络规划为防止单板故障引起整个节点网络异常,负载到6个业务板接入运营商,目前这6块业务板卡类型不同,板卡采用的转发芯片不同,hash算法受芯片不同的影响导致此故障现象。

调整后结果: 调整板卡类型相同后,现象消失。

6 问题反思

既然是板卡导致的问题,那么为什么会handshake出现错误,板卡有问题,那么普通的http或者https在成功完成握手后,也会出现这种现象,根据这个推论,去查普通的http以及https在数据传输过程中有没有发送这种错误。

果不其然,http数据传输以及https在数据传输过程中也有reset的情况!

那么,板卡调整后,这些现象也会消失的,于是,再次验证,也消失了,这样,就验证了自己的反思问题。

最终,现象只是ssl handshake failure,其实问题并不是ssl handshake的问题,只是ssl handshake 暴漏了这个问题而已。


结束

【如果对我从事得专业感兴趣:可以关注技术+公众号: 木石说 (mushiwords) 后台留言,有空必回复!】

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值