最近,我在系统中超融合的虚拟机中发现一个问题,即访问部分服务时会出现无法访问的问题。
现象
[root@test-mtu ~] curl http://bilibili.com # 正常访问
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr/>Powered by Tengine<hr><center>tengine</center>
</body>
</html>
[root@test-mtu ~] curl -v https://bilibili.com # 访问失败
* Trying 8.134.50.24:443...
* Connected to baidu.com (8.134.50.24) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: Connection reset by peer in connection to bilibili.com:443
* Closing connection 0
curl: (35) OpenSSL SSL_connect: Connection reset by peer in connection to bilibili.com:443
简单总结为:
ping 或者 curl bilibili.com、baidu.com这些是没有问题的
但是用scp、rysnc、访问https服务就会存在访问不通的问题
排查
使用curl命令访问 http://bilibili.com
和https://bilibili.com
并且使用tcpdump进行抓包
tcpdump -nne -w ./cap -i eth0 host bilibili.com
后面使用wireshark进行分析
可以看到上面的1-10是正常的http,11-21是出现错误的https请求
注意里面的第16个包,信息为 [TCP Previous segment not captured]
表示前一个tcp包的数据没有被捕获,说明可以前一个数据包丢失了或者tcpdump没有捕获到对应的tcp包,但是后者应该不可能,首先在上面的http请求中tcpdump完整地捕获到了所有的tcp包,然后curl https
请求时确实会出现访问失败的问题,所以可以断定是tcp数据包存在丢失的问题。
同时因为16、17的包出现问题,系统没有收到TLS握手时的 server hello
,以为第13个包发送失败,在第18、19个包就是重新发送了[TCP Dup ACK 13#1]
TLS握手流程如下,在客户端发送 Client Hello
后,服务器应该返回Server Hello
和对应的证书信息
修复
后续发现时网卡的mtu配置错误了,该虚拟机的默认配置为 8950 ,在默认情况下,应该要配置跟路由器一致的mtu值
使用该命令来确认对应网关的mtu值
[root@test-mtu ~] ping -M do -S mtu值 网关ip
后续把mtu修改为1450(跟我的路由器一致时),该问题就解决了,可以正常访问服务
总结
我在查看第16个包时,发现它的ack为518,刚好跟第14个包(Client Hello)的确认要求一致(ack=1+tcp.len=517=518)
,并且在客户端发送的SYN包的MSS为8910,所以感觉就是MTU的配置导致系统以为该包是存在错误的
MSS 是 TCP 协议中的一个概念,它表示 TCP 数据包每次能够传输的最大数据量。MSS 是在建立 TCP 连接时协商确定的,它的值通常要小于 MTU。因为 TCP 数据包在传输过程中需要添加 TCP 头部和 IP 头部,所以 MSS = MTU - IP 头部大小 - TCP 头部大小。例如,在以太网中 MTU 为 1500 字节,IP 头部通常是 20 字节,TCP 头部通常是 20 字节,那么 MSS = 1500 - 20 - 20 =1460 字节。