From affd5e0207a6545687b2d03d4d782901fa68c1fb Mon Sep 17 00:00:00 2001 From: Bill Meier Date: Wed, 6 Oct 2010 14:59:19 +0000 Subject: From Alexis La Goutte: MYSQL: Fix FIELD_PACKET dissection; From me: Two additional fixes for FIELD_PACKET dissection; Revision of the original patch from Alexis to properly dissect a SHOW_FIELDS response message. svn path=/trunk/; revision=34395 --- epan/dissectors/packet-mysql.c | 74 +++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 26 deletions(-) (limited to 'epan/dissectors/packet-mysql.c') diff --git a/epan/dissectors/packet-mysql.c b/epan/dissectors/packet-mysql.c index 31f0af9e98..39a67f22bd 100644 --- a/epan/dissectors/packet-mysql.c +++ b/epan/dissectors/packet-mysql.c @@ -215,8 +215,7 @@ static const value_string mysql_charset_vals[] = { /* collation codes may change over time, recreate with the following SQL -SELECT CONCAT(' {', ID, ',"', CHARACTER_SET_NAME, - ' COLLATE ', COLLATION_NAME, '"},') +SELECT CONCAT(' {', ID, ',"', CHARACTER_SET_NAME, ' COLLATE ', COLLATION_NAME, '"},') FROM INFORMATION_SCHEMA.COLLATIONS ORDER BY ID INTO OUTFILE '/tmp/mysql-collations'; @@ -450,6 +449,7 @@ static int hf_mysql_fld_auto_increment = -1; static int hf_mysql_fld_timestamp = -1; static int hf_mysql_fld_set = -1; static int hf_mysql_fld_decimals = -1; +static int hf_mysql_fld_default = -1; static int hf_mysql_row_length = -1; static int hf_mysql_row_text = -1; @@ -494,6 +494,7 @@ typedef enum mysql_state RESPONSE_OK, RESPONSE_MESSAGE, RESPONSE_TABULAR, + RESPONSE_SHOW_FIELDS, FIELD_PACKET, ROW_PACKET, RESPONSE_PREPARE, @@ -502,16 +503,17 @@ typedef enum mysql_state #ifdef CTDEBUG static const value_string state_vals[] = { - {UNDEFINED, "undefined"}, - {LOGIN, "login"}, - {REQUEST, "request"}, - {RESPONSE_OK, "response OK"}, - {RESPONSE_MESSAGE, "response message"}, - {RESPONSE_TABULAR, "tabular response"}, - {FIELD_PACKET, "field packet"}, - {ROW_PACKET, "row packet"}, - {RESPONSE_PREPARE, "response to PREPARE"}, - {PARAM_PACKET, "parameter packet"}, + {UNDEFINED, "undefined"}, + {LOGIN, "login"}, + {REQUEST, "request"}, + {RESPONSE_OK, "response OK"}, + {RESPONSE_MESSAGE, "response message"}, + {RESPONSE_TABULAR, "tabular response"}, + {RESPONSE_SHOW_FIELDS, "response to SHOW FIELDS"}, + {FIELD_PACKET, "field packet"}, + {ROW_PACKET, "row packet"}, + {RESPONSE_PREPARE, "response to PREPARE"}, + {PARAM_PACKET, "parameter packet"}, {0, NULL} }; #endif @@ -529,7 +531,7 @@ typedef struct mysql_conn_data } mysql_conn_data_t; struct mysql_frame_data { - mysql_state_t state; + mysql_state_t state; }; typedef struct my_stmt_data @@ -991,7 +993,7 @@ void proto_register_mysql(void) { &hf_mysql_fld_type, { "Type", "mysql.field.type", - FT_STRING, BASE_NONE, NULL, 0x0, + FT_UINT8, BASE_DEC, VALS(type_constants), 0x0, "Field: type", HFILL }}, { &hf_mysql_fld_flags, @@ -1064,6 +1066,11 @@ void proto_register_mysql(void) FT_UINT8, BASE_DEC, NULL, 0x0, "Field: decimals", HFILL }}, + { &hf_mysql_fld_default, + { "Default", "mysql.field.default", + FT_STRING, BASE_NONE, NULL, 0x0, + "Field: default", HFILL }}, + { &hf_mysql_row_length, { "length", "mysql.row.length", FT_UINT8, BASE_DEC, NULL, 0x0, @@ -1099,10 +1106,10 @@ void proto_register_mysql(void) "Whether the MySQL dissector should reassemble MySQL buffers spanning multiple TCP segments." " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", &mysql_desegment); - prefs_register_bool_preference(mysql_module, "show_sql_query", - "Show SQL Query string in INFO column", - "Whether the MySQL dissector should display the SQL query string in the INFO column.", - &mysql_showquery); + prefs_register_bool_preference(mysql_module, "show_sql_query", + "Show SQL Query string in INFO column", + "Whether the MySQL dissector should display the SQL query string in the INFO column.", + &mysql_showquery); register_dissector("mysql", dissect_mysql_pdu, proto_mysql); } @@ -1141,7 +1148,7 @@ dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) guint64 generation; proto_item *pi; #endif - struct mysql_frame_data *mysql_frame_data_p; + struct mysql_frame_data *mysql_frame_data_p; /* get conversation, create if neccessary*/ conversation= find_or_create_conversation(pinfo); @@ -1170,11 +1177,22 @@ dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) mysql_frame_data_p = se_alloc(sizeof(struct mysql_frame_data)); mysql_frame_data_p->state = conn_data->state; p_add_proto_data(pinfo->fd, proto_mysql, mysql_frame_data_p); + } else if (conn_data->state != FIELD_PACKET && conn_data->state != ROW_PACKET ) { /* We have seen this frame before. Set the connection state * to whatever state it had the first time we saw this frame * (e.g., based on whatever frames came before it). * The state may change as we dissect this packet. + * XXX: I think the logic of the above else if test is as follows: + * During the first (sequential) dissection pass thru the capture + * file the conversation connection state as of the beginning of each frame + * is saved in the connection_state for that frame. + * Any state changes *within* a mysql "message" (ie: query/response/etc) + * while processing mysql PDUS (aka "packets") in that message must be preserved. + * It appears that FIELD_PACKET & ROW_PACKET are the only two + * state changes which can occur within a mysql message which affect + * subsequent processing within the message. + * Question: Does this logic work OK for a reassembled message ? */ conn_data->state= mysql_frame_data_p->state; } @@ -1543,7 +1561,7 @@ mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset, proto_tree_add_text(req_tree, tvb, offset, strlen, "Table name: %s", tvb_get_ephemeral_string(tvb, offset, strlen)); offset+= strlen; - conn_data->state= RESPONSE_TABULAR; + conn_data->state= RESPONSE_SHOW_FIELDS; break; case MYSQL_PROCESS_KILL: @@ -1695,7 +1713,7 @@ mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data) { gint response_code; - gint strlen; + gint strlen; response_code= tvb_get_guint8(tvb, offset); @@ -1704,7 +1722,7 @@ mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset, conn_data->state= REQUEST; } - else if (response_code == 0xfe && tvb_reported_length_remaining(tvb, offset) < 9) { + else if (response_code == 0xfe && tvb_reported_length_remaining(tvb, offset) < 9) { proto_tree_add_uint_format(tree, hf_mysql_eof, tvb, offset, 1, response_code, "EOF marker (%u)", @@ -1753,6 +1771,7 @@ mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset, break; case FIELD_PACKET: + case RESPONSE_SHOW_FIELDS: offset= mysql_dissect_field_packet(tvb, offset, tree, conn_data); break; @@ -2018,14 +2037,12 @@ mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_co offset += 2; /* charset */ proto_tree_add_item(tree, hf_mysql_fld_length, tvb, offset, 4, TRUE); offset += 4; /* length */ - proto_tree_add_string(tree, hf_mysql_fld_type, tvb, offset, -1, - val_to_str(tvb_get_guint8(tvb, offset), type_constants, "Unknown (%u)")); + proto_tree_add_item(tree, hf_mysql_fld_type, tvb, offset, 1, FALSE); offset++; /* type */ flags = tvb_get_letohs(tvb, offset); - offset += 2; /* flags */ tf = proto_tree_add_uint_format(tree, hf_mysql_fld_flags, tvb, offset, - 2, flags, "Field flags: 0x%016X", flags); + 2, flags, "Field flags: 0x%04X", flags); flags_tree = proto_item_add_subtree(tf, ett_field_flags); proto_tree_add_boolean(flags_tree, hf_mysql_fld_not_null, tvb, offset, 2, flags); proto_tree_add_boolean(flags_tree, hf_mysql_fld_primary_key, tvb, offset, 2, flags); @@ -2039,12 +2056,17 @@ mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_co proto_tree_add_boolean(flags_tree, hf_mysql_fld_auto_increment, tvb, offset, 2, flags); proto_tree_add_boolean(flags_tree, hf_mysql_fld_timestamp, tvb, offset, 2, flags); proto_tree_add_boolean(flags_tree, hf_mysql_fld_set, tvb, offset, 2, flags); + offset += 2; /* flags */ proto_tree_add_item(tree, hf_mysql_fld_decimals, tvb, offset, 1, FALSE); offset++; /* decimals */ offset += 2; /* filler */ + /* default (Only use for show fields) */ + if (tree && tvb_reported_length_remaining(tvb, offset) > 0) { + offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_default); + } return offset; } -- cgit v1.2.3