MySQL: Decoding of the header of compressed packets

If client and server have the flag set then compression starts
after the greeting,login,ok.

This comments makes it possible to decode packets which
use the compressed protocol but don't have an compressed
payload.

Ping-Bug: 10342
Change-Id: I710f655c86feb9770556d1ffa69edd728e0374c3
Reviewed-on: https://code.wireshark.org/review/14603
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Daniël van Eeden 2016-03-20 19:32:05 +01:00 committed by Michael Mann
parent 07fb53b063
commit 2e98866171
1 changed files with 68 additions and 1 deletions

View File

@ -171,6 +171,11 @@ void proto_reg_handoff_mysql(void);
#define MYSQL_PARAM_FLAG_STREAMED 0x01
/* Compression states, internal to the dissector */
#define MYSQL_COMPRESS_NONE 0
#define MYSQL_COMPRESS_INIT 1
#define MYSQL_COMPRESS_ACTIVE 2
/* decoding table: command */
static const value_string mysql_command_vals[] = {
{MYSQL_SLEEP, "SLEEP"},
@ -618,6 +623,9 @@ static int hf_mysql_auth_switch_request_status = -1;
static int hf_mysql_auth_switch_request_name = -1;
static int hf_mysql_auth_switch_request_data = -1;
static int hf_mysql_auth_switch_response_data = -1;
static int hf_mysql_compressed_packet_length = -1;
static int hf_mysql_compressed_packet_length_uncompressed = -1;
static int hf_mysql_compressed_packet_number = -1;
static dissector_handle_t mysql_handle;
static dissector_handle_t ssl_handle;
@ -712,6 +720,8 @@ typedef struct mysql_conn_data {
#endif
guint8 major_version;
guint32 frame_start_ssl;
guint32 frame_start_compressed;
guint8 compressed_state;
} mysql_conn_data_t;
struct mysql_frame_data {
@ -1578,6 +1588,24 @@ hf_mysql_refresh, ett_refresh, mysql_rfsh_flags, ENC_BIG_ENDIAN, BMT_NO_APPEND);
return offset;
}
/*
* Decode the header of a compressed packet
* https://dev.mysql.com/doc/internals/en/compressed-packet-header.html
*/
static int
mysql_dissect_compressed_header(tvbuff_t *tvb, int offset, proto_tree *mysql_tree)
{
proto_tree_add_item(mysql_tree, hf_mysql_compressed_packet_length, tvb, offset, 3, ENC_LITTLE_ENDIAN);
offset += 3;
proto_tree_add_item(mysql_tree, hf_mysql_compressed_packet_number, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(mysql_tree, hf_mysql_compressed_packet_length_uncompressed, tvb, offset, 3, ENC_LITTLE_ENDIAN);
offset += 3;
return offset;
}
static int
mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
@ -1635,6 +1663,10 @@ mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
offset = mysql_dissect_response_prepare(tvb, offset, tree, conn_data);
} else if (tvb_reported_length_remaining(tvb, offset+1) > tvb_get_fle(tvb, offset+1, NULL, NULL)) {
offset = mysql_dissect_ok_packet(tvb, pinfo, offset+1, tree, conn_data);
if (conn_data->compressed_state == MYSQL_COMPRESS_INIT) {
/* This is the OK packet which follows the compressed protocol setup */
conn_data->compressed_state = MYSQL_COMPRESS_ACTIVE;
}
} else {
offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
}
@ -2154,8 +2186,14 @@ tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null)
static guint
get_mysql_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
{
int tvb_remain= tvb_reported_length_remaining(tvb, offset);
guint plen= tvb_get_letoh24(tvb, offset);
return plen + 4; /* add length field + packet number */
if ((tvb_remain - plen) == 7) {
return plen + 7; /* compressed header 3+1+3 (len+id+cmp_len) */
} else {
return plen + 4; /* regular header 3+1 (len+id) */
}
}
/* dissector main function: handle one PDU */
@ -2193,6 +2231,8 @@ dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
#endif
conn_data->major_version= 0;
conn_data->frame_start_ssl= 0;
conn_data->frame_start_compressed= 0;
conn_data->compressed_state= MYSQL_COMPRESS_NONE;
conversation_add_proto_data(conversation, proto_mysql, conn_data);
}
@ -2225,6 +2265,12 @@ dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
conn_data->state= mysql_frame_data_p->state;
}
if ((conn_data->frame_start_compressed) && (pinfo->num > conn_data->frame_start_compressed)) {
if (conn_data->compressed_state == MYSQL_COMPRESS_ACTIVE) {
offset = mysql_dissect_compressed_header(tvb, offset, tree);
}
}
if (tree) {
ti = proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, ENC_NA);
mysql_tree = proto_item_add_subtree(ti, ett_mysql);
@ -2278,6 +2324,12 @@ dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
if (packet_number == 1 || (packet_number == 2 && is_ssl)) {
col_set_str(pinfo->cinfo, COL_INFO, "Login Request");
offset = mysql_dissect_login(tvb, pinfo, offset, mysql_tree, conn_data);
if (conn_data->srv_caps & MYSQL_CAPS_CP) {
if (conn_data->clnt_caps & MYSQL_CAPS_CP) {
conn_data->frame_start_compressed = pinfo->num;
conn_data->compressed_state = MYSQL_COMPRESS_INIT;
}
}
} else {
col_set_str(pinfo->cinfo, COL_INFO, "Request");
offset = mysql_dissect_request(tvb, pinfo, offset, mysql_tree, conn_data);
@ -3161,6 +3213,21 @@ void proto_register_mysql(void)
{ "Auth Method Data", "mysql.auth_switch_response.data",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_mysql_compressed_packet_length,
{ "Compressed Packet Length", "mysql.compressed_packet_length",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_mysql_compressed_packet_number,
{ "Compressed Packet Number", "mysql.compressed_packet_number",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_mysql_compressed_packet_length_uncompressed,
{ "Uncompressed Packet Length", "mysql.compressed_packet_length_uncompressed",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
};
static gint *ett[]=