使用 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 查看结果:

mysql client

图中基于 Protocol 列进行排序(忽略过多的 TCP ACK 消息),可以看出,TCP 握手成功后,服务端首先发送了 Greeting 消息(No.9),附带了协议版本和服务器版本,之后客户端发送了 Login Request,但由于 MySQL 客户端和服务器之间默认使用信道加密,后面的消息都为 TLSv1.3,因此这些消息都为密文。

使用非加密的方式重新进行连接:

➜  ~ mysql -ucanal -pcanal -h127.0.0.1 --ssl-mode=DISABLED

使用 wireshark 查看结果:

mysql client --ssl-mode=DISABLE

同样基于 Protocol 列排序,可以看到现在 MySQL 的交互清晰展现了出来,下面详细看下各个包的内容。

Frame 9

Frame 9

TCP 连接建立之后,服务器首先给客户端发送 Greeting 消息,告诉客户端自己的版本、分配的连接ID、服务器的能力(Capabilities)、认证插件等信息。可以理解为 MySQL 的握手是由 Server 端发起的。

Frame 13

Frame 13

客户端将登录信息(username/passwd)及客户端具有的能力、最大发送包大小等信息发送给服务端。

Frame 17

Frame 17

Auth Switch Request 的解释参照 Protocol::AuthSwitchRequest

Frame 21

Frame 21

服务器对用户发送来的用户名密码进行验证,返回验证成功的消息,该消息也意味着 MySQL 协议握手的结束。

Frame 25

Frame 25

客户端在握手成功之后发起了一个 sql 请求,wireshark 对该消息的 payload 未能解析出来,但从包的二进制内容中可以看出,客户端进行了如下请求:

select @@version_comment limit 1;

Frame 29

Frame 29

wireshark 对服务器的响应也存在一些问题,不过从二进制内容后面对应的 ASCII 码中可以看出,服务器返回了 Homebrew。在客户端直接查询进行验证:

select version comment

至此,mysql 连接的过程分析完毕。附上本文分析的 pcap 文件: tcpdump_3306_2021-10-11-1633935657.pcap

一些技巧

  1. 使用 Wireshark 的 TCP Stream 可以跟踪一个命令所有交互的包,方便在一堆包中定位需要的信息:

mysql tcp stream

mysql tcp stream result

  1. wireshark 根据端口号识别响应的协议,假设 MySQL server 监听在 3303,则需要进行如下设置:

wireshark mysql tcp port setting