使用 tcpdump 和 wireshark 分析 MySQL 协议握手过程
使用 tcpdump 对 MySQL 进行抓包是一种定位线上问题的重要手段,如结合 pt-query-digest 识别慢查询;使用 wireshark 对报文内容进行分析,这对很多 MySQL Compatible 的产品非常重要。本文使用 tcpdump 和 wireshark 对 MySQL 的握手过程进行抓包分析。
实验环境
OS: macOS Big Sur
MySQL version: 8.0.25
tcpdump version tcpdump version 4.9.3 -- Apple version 100
libpcap version 1.9.1
LibreSSL 2.8.3
Wireshark Version 3.4.8
Step 1 抓包
MySQL server 监听默认端口号 3306,使用如下命令抓包
➜ ~ sudo tcpdump -X -i any src port 3306 or dst port 3306 -w tcpdump_3306_"`date +"%Y-%m-%d-%s"`".pcap
tcpdump: data link type PKTAP
tcpdump: listening on any, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
使用 Ctrl + C
即可停止抓包,查看生成的包文件
➜ ~ ll
total 32
-rw-r--r-- 1 root staff 15K Oct 11 14:44 tcpdump_3306_2021-10-11-1633934437.pcap
Step 2 使用 wireshark 进行分析
首先对 client 连接服务端请求进行分析,对应的命令为:
➜ ~ mysql -ucanal -pcanal -h127.0.0.1
使用 wireshark 查看结果:
图中基于 Protocol 列进行排序(忽略过多的 TCP ACK 消息),可以看出,TCP 握手成功后,服务端首先发送了 Greeting 消息(No.9),附带了协议版本和服务器版本,之后客户端发送了 Login Request,但由于 MySQL 客户端和服务器之间默认使用信道加密,后面的消息都为 TLSv1.3,因此这些消息都为密文。
使用非加密的方式重新进行连接:
➜ ~ mysql -ucanal -pcanal -h127.0.0.1 --ssl-mode=DISABLED
使用 wireshark 查看结果:
同样基于 Protocol 列排序,可以看到现在 MySQL 的交互清晰展现了出来,下面详细看下各个包的内容。
Frame 9
TCP 连接建立之后,服务器首先给客户端发送 Greeting 消息,告诉客户端自己的版本、分配的连接ID、服务器的能力(Capabilities)、认证插件等信息。可以理解为 MySQL 的握手是由 Server 端发起的。
Frame 13
客户端将登录信息(username/passwd)及客户端具有的能力、最大发送包大小等信息发送给服务端。
Frame 17
Auth Switch Request 的解释参照 Protocol::AuthSwitchRequest。
Frame 21
服务器对用户发送来的用户名密码进行验证,返回验证成功的消息,该消息也意味着 MySQL 协议握手的结束。
Frame 25
客户端在握手成功之后发起了一个 sql 请求,wireshark 对该消息的 payload 未能解析出来,但从包的二进制内容中可以看出,客户端进行了如下请求:
select @@version_comment limit 1;
Frame 29
wireshark 对服务器的响应也存在一些问题,不过从二进制内容后面对应的 ASCII 码中可以看出,服务器返回了 Homebrew
。在客户端直接查询进行验证:
至此,mysql 连接的过程分析完毕。附上本文分析的 pcap 文件: tcpdump_3306_2021-10-11-1633935657.pcap
一些技巧
- 使用 Wireshark 的 TCP Stream 可以跟踪一个命令所有交互的包,方便在一堆包中定位需要的信息:
- wireshark 根据端口号识别响应的协议,假设 MySQL server 监听在 3303,则需要进行如下设置: