服务器在会话协商期间以空包响应导致客户端给出格式错误的包错误

MaQ*_*eod 14 mysql

我正在尝试连接到远程 mysql 服务器。这 100% 的时间都会发生。

客户端:mysql Ver 14.14 Distrib 5.7.12,Win32 (AMD64)
服务器:5.0.95

这是我得到的错误:

C:\>mysql -h example.com -P 3306 -D prod_rcadb -u username -p
Enter password: **********
ERROR 2027 (HY000): Malformed packet
Run Code Online (Sandbox Code Playgroud)

与 mysqladmin 相同的错误:

C:\>mysqladmin -h example.com -P 3306 -u username -p version
Enter password: **********
mysqladmin: connect to server at '10.106.24.79' failed
error: 'Malformed packet'
Run Code Online (Sandbox Code Playgroud)

所以我拿了一个 pcap,只是为了了解那次谈话的样子。

TCP握手:

1              2016-04-14 11:18:48.910690         0.000000              137.69.150.80                     10.106.24.79       TCP        66                51157?3306 [SYN] Seq=0 Win=8192 Len=0 MSS=1428 WS=256 SACK_PERM=1   8192
2              2016-04-14 11:18:49.019893         0.109203              10.106.24.79                       137.69.150.80     TCP        66                3306?51157 [SYN, ACK] Seq=0 Ack=1 Win=5840 Len=0 MSS=1460 SACK_PERM=1 WS=256           5840
3              2016-04-14 11:18:49.019893         0.000000              137.69.150.80                     10.106.24.79       TCP        54                51157?3306 [ACK] Seq=1 Ack=1 Win=65536 Len=0          256
Run Code Online (Sandbox Code Playgroud)

Mysql连接协商:

4              2016-04-14 11:18:49.144696         0.124803              10.106.24.79                       137.69.150.80     MySQL  110        Server Greeting proto=10 version=5.0.95            23
5              2016-04-14 11:18:49.144696         0.000000              137.69.150.80                     10.106.24.79       MySQL  119         Login Request user=bigdata   256<br>
6              2016-04-14 11:18:49.144696         0.000000              10.106.24.79                       137.69.150.80     TCP        60                3306?51157 [ACK] Seq=57 Ack=66 Win=5888 Len=0        23
7              2016-04-14 11:18:49.316301         0.171605              10.106.24.79                       137.69.150.80     MySQL  60           Response                23
Run Code Online (Sandbox Code Playgroud)

因此客户端在 TCP 级别连接,服务器向我们提供支持的选项和状态:

Server Capabilities: 0xa22c
.... .... .... ...0 = Long Password: Not set
.... .... .... ..0. = Found Rows: Not set
.... .... .... .1.. = Long Column Flags: Set
.... .... .... 1... = Connect With Database: Set
.... .... ...0 .... = Don't Allow database.table.column: Not set
.... .... ..1. .... = Can use compression protocol: Set
.... .... .0.. .... = ODBC Client: Not set
.... .... 0... .... = Can Use LOAD DATA LOCAL: Not set
.... ...0 .... .... = Ignore Spaces before '(': Not set
.... ..1. .... .... = Speaks 4.1 protocol (new flag): Set
.... .0.. .... .... = Interactive Client: Not set
.... 0... .... .... = Switch to SSL after handshake: Not set
...0 .... .... .... = Ignore sigpipes: Not set
..1. .... .... .... = Knows about transactions: Set
.0.. .... .... .... = Speaks 4.1 protocol (old flag): Not set
1... .... .... .... = Can do 4.1 authentication: Set
Server Language: latin1 COLLATE latin1_swedish_ci (8)
Run Code Online (Sandbox Code Playgroud)

客户端请求登录:

.... .... .... ...1 = Long Password: Set
.... .... .... ..0. = Found Rows: Not set
.... .... .... .1.. = Long Column Flags: Set
.... .... .... 0... = Connect With Database: Not set
.... .... ...0 .... = Don't Allow database.table.column: Not set
.... .... ..0. .... = Can use compression protocol: Not set
.... .... .0.. .... = ODBC Client: Not set
.... .... 1... .... = Can Use LOAD DATA LOCAL: Set
.... ...0 .... .... = Ignore Spaces before '(': Not set
.... ..1. .... .... = Speaks 4.1 protocol (new flag): Set
.... .0.. .... .... = Interactive Client: Not set
.... 0... .... .... = Switch to SSL after handshake: Not set
...0 .... .... .... = Ignore sigpipes: Not set
..1. .... .... .... = Knows about transactions: Set
.0.. .... .... .... = Speaks 4.1 protocol (old flag): Not set
1... .... .... .... = Can do 4.1 authentication: Set
Extended Client Capabilities: 0x81be
.... .... .... ...0 = Multiple statements: Not set
.... .... .... ..1. = Multiple results: Set
.... .... .... .1.. = PS Multiple results: Set
.... .... .... 1... = Plugin Auth: Set
.... .... ...1 .... = Connect attrs: Set
.... .... ..1. .... = Plugin Auth LENENC Client Data: Set
.... .... 1... .... = Session variable tracking: Set
1000 0001 .0.. .... = Unused: 0x0204
Run Code Online (Sandbox Code Playgroud)

服务器确认,然后发送一个响应,它本质上是空的......

Packet Length: 1
Packet Number: 2
EOF marker: 254
Run Code Online (Sandbox Code Playgroud)

这会立即导致客户端 FIN 并关闭套接字:

8              2016-04-14 11:18:49.316301         0.000000              137.69.150.80                     10.106.24.79       TCP        54                51157?3306 [FIN, ACK] Seq=66 Ack=62 Win=65536 Len=0            256
9              2016-04-14 11:18:49.332901         0.016600              10.106.24.79                       137.69.150.80     TCP        60                3306?51157 [ACK] Seq=62 Ack=67 Win=5888 Len=0        23
10           2016-04-14 11:18:49.391904         0.059003              10.106.24.79                       137.69.150.80     TCP        60                3306?51157 [FIN, ACK] Seq=62 Ack=67 Win=5888 Len=0              23
11           2016-04-14 11:18:49.391904         0.000000              137.69.150.80                     10.106.24.79       TCP        54                51157?3306 [ACK] Seq=67 Ack=63 Win=65536 Len=0     256
Run Code Online (Sandbox Code Playgroud)

所以连接客户端不喜欢服务器发送的那个空包。

对于来自同一客户端的同一版本的另一个 mysql 服务器,我没有得到这个。下面是服务器 2 对登录请求的响应包:

Packet Length: 7
Packet Number: 2
Affected Rows: 0
Server Status: 0x0002
.... .... .... ...0 = In transaction: Not set
.... .... .... ..1. = AUTO_COMMIT: Set
.... .... .... .0.. = More results: Not set
.... .... .... 0... = Multi query - more resultsets: Not set
.... .... ...0 .... = Bad index used: Not set
.... .... ..0. .... = No index used: Not set
.... .... .0.. .... = Cursor exists: Not set
.... .... 0... .... = Last row sent: Not set
.... ...0 .... .... = database dropped: Not set
.... ..0. .... .... = No backslash escapes: Not set
.... .0.. .... .... = Session state changed: Not set
.... 0... .... .... = Query was slow: Not set
...0 .... .... .... = PS Out Params: Not set
Run Code Online (Sandbox Code Playgroud)

我自己不管理这个数据库,但如果你有关于在日志中查找内容的建议,我可以请求该信息。

关于为什么我从服务器收到一个空包的任何想法?

MaQ*_*eod 13

我认为是空的数据包实际上不是,它是一个旧的身份验证切换请求

Payload
1     [fe]
Fields
status (1) -- 0xfe
Returns
Protocol::AuthSwitchResponse with old password hash
Example
01 00 00 02 fe
Run Code Online (Sandbox Code Playgroud)

如果您查看实际的字节字符串,则wireshark 解析的 1, 2, 254 实际上是 01 00 00 02 fe。

所以这不是误会,服务器完全理解并正确响应,客户端正确终止,因为它无法协商。该协议不是太旧,因为它在 4.1 中发生了变化,因此 5.0 和 5.7 都可以完美地相互理解。这应该是更清晰的错误消息。

客户端太新,无法使用 --skip-secure-auth (参考)。他们故意取消了在 5.7 之前谈判的能力。

所以我的选择是允许在服务器上使用新密码(这是用户特定的配置,而不是全局服务器选项)或使用旧的二进制文件。

具体的配置问题是基于给我的用户名。在过去的某个时候,使用此用户名的人使用的是旧客户端,他们更改了密码方法

B.5.2.4 Client does not support authentication protocol

The current implementation of the authentication protocol uses a password hashing algorithm that is incompatible with that used by older (pre-4.1) clients. Attempts to connect to a 4.1 or newer server with an older client may fail with the following message:

shell> mysql
Client does not support authentication protocol requested
by server; consider upgrading MySQL client

To deal with this problem, the preferred solution is to upgrade all client programs to use a 4.1.1 or newer client library. If that is not possible, use one of the following approaches:

    To connect to the server with a pre-4.1 client program, use an account that still has a pre-4.1-style password.

    Reset the password to pre-4.1 style for each user that needs to use a pre-4.1 client program. This can be done using the SET PASSWORD statement and the OLD_PASSWORD() function. As of MySQL 5.6.6, it is also necessary to first ensure that the authentication plugin for the account is mysql_old_password:

    mysql> UPDATE mysql.user SET plugin = 'mysql_old_password'
    mysql> WHERE User = 'some_user' AND Host = 'some_host';
    mysql> FLUSH PRIVILEGES;
    mysql> SET PASSWORD FOR
        -> 'some_user'@'some_host' = OLD_PASSWORD('new_password');
Run Code Online (Sandbox Code Playgroud)