2 * Routines for mysql packet dissection
4 * Huagang XIE <huagang@intruvert.com>
6 * MySQL 4.1+ protocol by Axel Schwenke <axel@mysql.com>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * Copied from packet-tftp.c
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 * the protocol spec at
32 * http://public.logicacmg.com/~redferni/mysql/MySQL-Protocol.html
33 * http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol
34 * and MySQL source code
37 /* create extra output for conversation tracking */
38 /* #define CTDEBUG 1 */
45 #include <epan/packet.h>
46 #include <epan/conversation.h>
47 #include <epan/emem.h>
49 #include <epan/dissectors/packet-tcp.h>
50 #include <epan/prefs.h>
51 #include <epan/expert.h>
53 /* port for protocol registration */
54 #define TCP_PORT_MySQL 3306
56 /* client/server capabilities */
57 #define MYSQL_CAPS_LP 0x0001
58 #define MYSQL_CAPS_FR 0x0002
59 #define MYSQL_CAPS_LF 0x0004
60 #define MYSQL_CAPS_CD 0x0008
61 #define MYSQL_CAPS_NS 0x0010
62 #define MYSQL_CAPS_CP 0x0020
63 #define MYSQL_CAPS_OB 0x0040
64 #define MYSQL_CAPS_LI 0x0080
65 #define MYSQL_CAPS_IS 0x0100
66 #define MYSQL_CAPS_CU 0x0200
67 #define MYSQL_CAPS_IA 0x0400
68 #define MYSQL_CAPS_SL 0x0800
69 #define MYSQL_CAPS_II 0x1000
70 #define MYSQL_CAPS_TA 0x2000
71 #define MYSQL_CAPS_RS 0x4000
72 #define MYSQL_CAPS_SC 0x8000
75 #define MYSQL_FLD_NOT_NULL_FLAG 0x0001
76 #define MYSQL_FLD_PRI_KEY_FLAG 0x0002
77 #define MYSQL_FLD_UNIQUE_KEY_FLAG 0x0004
78 #define MYSQL_FLD_MULTIPLE_KEY_FLAG 0x0008
79 #define MYSQL_FLD_BLOB_FLAG 0x0010
80 #define MYSQL_FLD_UNSIGNED_FLAG 0x0020
81 #define MYSQL_FLD_ZEROFILL_FLAG 0x0040
82 #define MYSQL_FLD_BINARY_FLAG 0x0080
83 #define MYSQL_FLD_ENUM_FLAG 0x0100
84 #define MYSQL_FLD_AUTO_INCREMENT_FLAG 0x0200
85 #define MYSQL_FLD_TIMESTAMP_FLAG 0x0400
86 #define MYSQL_FLD_SET_FLAG 0x0800
88 /* extended capabilities: 4.1+ client only */
89 #define MYSQL_CAPS_MS 0x0001
90 #define MYSQL_CAPS_MR 0x0002
93 #define MYSQL_STAT_IT 0x0001
94 #define MYSQL_STAT_AC 0x0002
95 #define MYSQL_STAT_MR 0x0004
96 #define MYSQL_STAT_MU 0x0008
97 #define MYSQL_STAT_BI 0x0010
98 #define MYSQL_STAT_NI 0x0020
99 #define MYSQL_STAT_CR 0x0040
100 #define MYSQL_STAT_LR 0x0080
101 #define MYSQL_STAT_DR 0x0100
102 #define MYSQL_STAT_BS 0x0200
104 /* bitfield for MYSQL_REFRESH */
105 #define MYSQL_RFSH_GRANT 1 /* Refresh grant tables */
106 #define MYSQL_RFSH_LOG 2 /* Start on new log file */
107 #define MYSQL_RFSH_TABLES 4 /* close all tables */
108 #define MYSQL_RFSH_HOSTS 8 /* Flush host cache */
109 #define MYSQL_RFSH_STATUS 16 /* Flush status variables */
110 #define MYSQL_RFSH_THREADS 32 /* Flush thread cache */
111 #define MYSQL_RFSH_SLAVE 64 /* Reset master info and restart slave thread */
112 #define MYSQL_RFSH_MASTER 128 /* Remove all bin logs in the index and truncate the index */
114 /* MySQL command codes */
115 #define MYSQL_SLEEP 0 /* not from client */
117 #define MYSQL_INIT_DB 2
118 #define MYSQL_QUERY 3
119 #define MYSQL_FIELD_LIST 4
120 #define MYSQL_CREATE_DB 5
121 #define MYSQL_DROP_DB 6
122 #define MYSQL_REFRESH 7
123 #define MYSQL_SHUTDOWN 8
124 #define MYSQL_STATISTICS 9
125 #define MYSQL_PROCESS_INFO 10
126 #define MYSQL_CONNECT 11 /* not from client */
127 #define MYSQL_PROCESS_KILL 12
128 #define MYSQL_DEBUG 13
129 #define MYSQL_PING 14
130 #define MYSQL_TIME 15 /* not from client */
131 #define MYSQL_DELAY_INSERT 16 /* not from client */
132 #define MYSQL_CHANGE_USER 17
133 #define MYSQL_BINLOG_DUMP 18 /* replication */
134 #define MYSQL_TABLE_DUMP 19 /* replication */
135 #define MYSQL_CONNECT_OUT 20 /* replication */
136 #define MYSQL_REGISTER_SLAVE 21 /* replication */
137 #define MYSQL_STMT_PREPARE 22
138 #define MYSQL_STMT_EXECUTE 23
139 #define MYSQL_STMT_SEND_LONG_DATA 24
140 #define MYSQL_STMT_CLOSE 25
141 #define MYSQL_STMT_RESET 26
142 #define MYSQL_SET_OPTION 27
143 #define MYSQL_STMT_FETCH 28
145 /* MySQL cursor types */
147 #define MYSQL_CURSOR_TYPE_NO_CURSOR 0
148 #define MYSQL_CURSOR_TYPE_READ_ONLY 1
149 #define MYSQL_CURSOR_TYPE_FOR_UPDATE 2
150 #define MYSQL_CURSOR_TYPE_SCROLLABLE 4
153 /* decoding table: command */
154 static const value_string mysql_command_vals[] = {
155 {MYSQL_SLEEP, "SLEEP"},
156 {MYSQL_QUIT, "Quit"},
157 {MYSQL_INIT_DB, "Use Database"},
158 {MYSQL_QUERY, "Query"},
159 {MYSQL_FIELD_LIST, "Show Fields"},
160 {MYSQL_CREATE_DB, "Create Database"},
161 {MYSQL_DROP_DB , "Drop Database"},
162 {MYSQL_REFRESH , "Refresh"},
163 {MYSQL_SHUTDOWN , "Shutdown"},
164 {MYSQL_STATISTICS , "Statistics"},
165 {MYSQL_PROCESS_INFO , "Process List"},
166 {MYSQL_CONNECT , "Connect"},
167 {MYSQL_PROCESS_KILL , "Kill Server Thread"},
168 {MYSQL_DEBUG , "Dump Debuginfo"},
169 {MYSQL_PING , "Ping"},
170 {MYSQL_TIME , "Time"},
171 {MYSQL_DELAY_INSERT , "Insert Delayed"},
172 {MYSQL_CHANGE_USER , "Change User"},
173 {MYSQL_BINLOG_DUMP , "Send Binlog"},
174 {MYSQL_TABLE_DUMP, "Send Table"},
175 {MYSQL_CONNECT_OUT, "Slave Connect"},
176 {MYSQL_REGISTER_SLAVE, "Register Slave"},
177 {MYSQL_STMT_PREPARE, "Prepare Statement"},
178 {MYSQL_STMT_EXECUTE, "Execute Statement"},
179 {MYSQL_STMT_SEND_LONG_DATA, "Send BLOB"},
180 {MYSQL_STMT_CLOSE, "Close Statement"},
181 {MYSQL_STMT_RESET, "Reset Statement"},
182 {MYSQL_SET_OPTION, "Set Option"},
183 {MYSQL_STMT_FETCH, "Fetch Data"},
187 /* decoding table: exec_flags */
188 static const value_string mysql_exec_flags_vals[] = {
189 {MYSQL_CURSOR_TYPE_NO_CURSOR, "Defaults"},
190 {MYSQL_CURSOR_TYPE_READ_ONLY, "Read-only cursor"},
191 {MYSQL_CURSOR_TYPE_FOR_UPDATE, "Cursor for update"},
192 {MYSQL_CURSOR_TYPE_SCROLLABLE, "Scrollable cursor"},
196 /* charset: pre-4.1 used the term 'charset', later changed to 'collation' */
197 static const value_string mysql_charset_vals[] = {
232 /* collation codes may change over time, recreate with the following SQL
234 SELECT CONCAT(' {', ID, ',"', CHARACTER_SET_NAME, ' COLLATE ', COLLATION_NAME, '"},')
235 FROM INFORMATION_SCHEMA.COLLATIONS
237 INTO OUTFILE '/tmp/mysql-collations';
240 static const value_string mysql_collation_vals[] = {
241 {3, "dec8 COLLATE dec8_swedish_ci"},
242 {4, "cp850 COLLATE cp850_general_ci"},
243 {5, "latin1 COLLATE latin1_german1_ci"},
244 {6, "hp8 COLLATE hp8_english_ci"},
245 {7, "koi8r COLLATE koi8r_general_ci"},
246 {8, "latin1 COLLATE latin1_swedish_ci"},
247 {9, "latin2 COLLATE latin2_general_ci"},
248 {10, "swe7 COLLATE swe7_swedish_ci"},
249 {11, "ascii COLLATE ascii_general_ci"},
250 {14, "cp1251 COLLATE cp1251_bulgarian_ci"},
251 {15, "latin1 COLLATE latin1_danish_ci"},
252 {16, "hebrew COLLATE hebrew_general_ci"},
253 {20, "latin7 COLLATE latin7_estonian_cs"},
254 {21, "latin2 COLLATE latin2_hungarian_ci"},
255 {22, "koi8u COLLATE koi8u_general_ci"},
256 {23, "cp1251 COLLATE cp1251_ukrainian_ci"},
257 {25, "greek COLLATE greek_general_ci"},
258 {26, "cp1250 COLLATE cp1250_general_ci"},
259 {27, "latin2 COLLATE latin2_croatian_ci"},
260 {29, "cp1257 COLLATE cp1257_lithuanian_ci"},
261 {30, "latin5 COLLATE latin5_turkish_ci"},
262 {31, "latin1 COLLATE latin1_german2_ci"},
263 {32, "armscii8 COLLATE armscii8_general_ci"},
264 {33, "utf8 COLLATE utf8_general_ci"},
265 {36, "cp866 COLLATE cp866_general_ci"},
266 {37, "keybcs2 COLLATE keybcs2_general_ci"},
267 {38, "macce COLLATE macce_general_ci"},
268 {39, "macroman COLLATE macroman_general_ci"},
269 {40, "cp852 COLLATE cp852_general_ci"},
270 {41, "latin7 COLLATE latin7_general_ci"},
271 {42, "latin7 COLLATE latin7_general_cs"},
272 {43, "macce COLLATE macce_bin"},
273 {44, "cp1250 COLLATE cp1250_croatian_ci"},
274 {47, "latin1 COLLATE latin1_bin"},
275 {48, "latin1 COLLATE latin1_general_ci"},
276 {49, "latin1 COLLATE latin1_general_cs"},
277 {50, "cp1251 COLLATE cp1251_bin"},
278 {51, "cp1251 COLLATE cp1251_general_ci"},
279 {52, "cp1251 COLLATE cp1251_general_cs"},
280 {53, "macroman COLLATE macroman_bin"},
281 {57, "cp1256 COLLATE cp1256_general_ci"},
282 {58, "cp1257 COLLATE cp1257_bin"},
283 {59, "cp1257 COLLATE cp1257_general_ci"},
284 {63, "binary COLLATE binary"},
285 {64, "armscii8 COLLATE armscii8_bin"},
286 {65, "ascii COLLATE ascii_bin"},
287 {66, "cp1250 COLLATE cp1250_bin"},
288 {67, "cp1256 COLLATE cp1256_bin"},
289 {68, "cp866 COLLATE cp866_bin"},
290 {69, "dec8 COLLATE dec8_bin"},
291 {70, "greek COLLATE greek_bin"},
292 {71, "hebrew COLLATE hebrew_bin"},
293 {72, "hp8 COLLATE hp8_bin"},
294 {73, "keybcs2 COLLATE keybcs2_bin"},
295 {74, "koi8r COLLATE koi8r_bin"},
296 {75, "koi8u COLLATE koi8u_bin"},
297 {77, "latin2 COLLATE latin2_bin"},
298 {78, "latin5 COLLATE latin5_bin"},
299 {79, "latin7 COLLATE latin7_bin"},
300 {80, "cp850 COLLATE cp850_bin"},
301 {81, "cp852 COLLATE cp852_bin"},
302 {82, "swe7 COLLATE swe7_bin"},
303 {83, "utf8 COLLATE utf8_bin"},
304 {92, "geostd8 COLLATE geostd8_general_ci"},
305 {93, "geostd8 COLLATE geostd8_bin"},
306 {94, "latin1 COLLATE latin1_spanish_ci"},
307 {99, "cp1250 COLLATE cp1250_polish_ci"},
308 {192, "utf8 COLLATE utf8_unicode_ci"},
309 {193, "utf8 COLLATE utf8_icelandic_ci"},
310 {194, "utf8 COLLATE utf8_latvian_ci"},
311 {195, "utf8 COLLATE utf8_romanian_ci"},
312 {196, "utf8 COLLATE utf8_slovenian_ci"},
313 {197, "utf8 COLLATE utf8_polish_ci"},
314 {198, "utf8 COLLATE utf8_estonian_ci"},
315 {199, "utf8 COLLATE utf8_spanish_ci"},
316 {200, "utf8 COLLATE utf8_swedish_ci"},
317 {201, "utf8 COLLATE utf8_turkish_ci"},
318 {202, "utf8 COLLATE utf8_czech_ci"},
319 {203, "utf8 COLLATE utf8_danish_ci"},
320 {204, "utf8 COLLATE utf8_lithuanian_ci"},
321 {205, "utf8 COLLATE utf8_slovak_ci"},
322 {206, "utf8 COLLATE utf8_spanish2_ci"},
323 {207, "utf8 COLLATE utf8_roman_ci"},
324 {208, "utf8 COLLATE utf8_persian_ci"},
325 {209, "utf8 COLLATE utf8_esperanto_ci"},
326 {210, "utf8 COLLATE utf8_hungarian_ci"},
331 /* allowed MYSQL_SHUTDOWN levels */
332 static const value_string mysql_shutdown_vals[] = {
334 {1, "wait for connections to finish"},
335 {2, "wait for transactions to finish"},
336 {8, "wait for updates to finish"},
337 {16, "wait flush all buffers"},
338 {17, "wait flush critical buffers"},
339 {254, "kill running queries"},
340 {255, "kill connections"},
345 /* allowed MYSQL_SET_OPTION values */
346 static const value_string mysql_option_vals[] = {
347 {0, "multi statements on"},
348 {1, "multi statements off"},
353 static int proto_mysql = -1;
355 /* dissector configuration */
356 static gboolean mysql_desegment = TRUE;
357 static gboolean mysql_showquery = FALSE;
359 /* expand-the-tree flags */
360 static gint ett_mysql = -1;
361 static gint ett_server_greeting = -1;
362 static gint ett_login_request = -1;
363 static gint ett_caps = -1;
364 static gint ett_extcaps = -1;
365 static gint ett_stat = -1;
366 static gint ett_request = -1;
367 static gint ett_refresh = -1;
368 static gint ett_field_flags = -1;
370 /* protocol fields */
371 static int hf_mysql_caps_server = -1;
372 static int hf_mysql_caps_client = -1;
373 static int hf_mysql_cap_long_password = -1;
374 static int hf_mysql_cap_found_rows = -1;
375 static int hf_mysql_cap_long_flag = -1;
376 static int hf_mysql_cap_connect_with_db = -1;
377 static int hf_mysql_cap_no_schema = -1;
378 static int hf_mysql_cap_compress = -1;
379 static int hf_mysql_cap_odbc = -1;
380 static int hf_mysql_cap_local_files = -1;
381 static int hf_mysql_cap_ignore_space = -1;
382 static int hf_mysql_cap_change_user = -1;
383 static int hf_mysql_cap_interactive = -1;
384 static int hf_mysql_cap_ssl = -1;
385 static int hf_mysql_cap_ignore_sigpipe = -1;
386 static int hf_mysql_cap_transactions = -1;
387 static int hf_mysql_cap_reserved = -1;
388 static int hf_mysql_cap_secure_connect = -1;
389 static int hf_mysql_extcaps_client = -1;
390 static int hf_mysql_cap_multi_statements = -1;
391 static int hf_mysql_cap_multi_results = -1;
392 static int hf_mysql_server_language = -1;
393 static int hf_mysql_server_status = -1;
394 static int hf_mysql_stat_it = -1;
395 static int hf_mysql_stat_ac = -1;
396 static int hf_mysql_stat_mr = -1;
397 static int hf_mysql_stat_mu = -1;
398 static int hf_mysql_stat_bi = -1;
399 static int hf_mysql_stat_ni = -1;
400 static int hf_mysql_stat_cr = -1;
401 static int hf_mysql_stat_lr = -1;
402 static int hf_mysql_stat_dr = -1;
403 static int hf_mysql_stat_bs = -1;
404 static int hf_mysql_refresh = -1;
405 static int hf_mysql_rfsh_grants = -1;
406 static int hf_mysql_rfsh_log = -1;
407 static int hf_mysql_rfsh_tables = -1;
408 static int hf_mysql_rfsh_hosts = -1;
409 static int hf_mysql_rfsh_status = -1;
410 static int hf_mysql_rfsh_threads = -1;
411 static int hf_mysql_rfsh_slave = -1;
412 static int hf_mysql_rfsh_master = -1;
413 static int hf_mysql_packet_length = -1;
414 static int hf_mysql_packet_number = -1;
415 static int hf_mysql_request = -1;
416 static int hf_mysql_command = -1;
417 static int hf_mysql_error_code = -1;
418 static int hf_mysql_error_string = -1;
419 static int hf_mysql_sqlstate = -1;
420 static int hf_mysql_message = -1;
421 static int hf_mysql_payload = -1;
422 static int hf_mysql_server_greeting = -1;
423 static int hf_mysql_protocol = -1;
424 static int hf_mysql_version = -1;
425 static int hf_mysql_login_request = -1;
426 static int hf_mysql_max_packet = -1;
427 static int hf_mysql_user = -1;
428 static int hf_mysql_table_name = -1;
429 static int hf_mysql_schema = -1;
430 static int hf_mysql_thread_id = -1;
431 static int hf_mysql_salt = -1;
432 static int hf_mysql_salt2 = -1;
433 static int hf_mysql_charset = -1;
434 static int hf_mysql_passwd = -1;
435 static int hf_mysql_unused = -1;
436 static int hf_mysql_affected_rows = -1;
437 static int hf_mysql_insert_id = -1;
438 static int hf_mysql_num_warn = -1;
439 static int hf_mysql_thd_id = -1;
440 static int hf_mysql_stmt_id = -1;
441 static int hf_mysql_query = -1;
442 static int hf_mysql_shutdown = -1;
443 static int hf_mysql_option = -1;
444 static int hf_mysql_num_rows = -1;
445 static int hf_mysql_param = -1;
446 static int hf_mysql_num_params = -1;
447 static int hf_mysql_exec_flags4 = -1;
448 static int hf_mysql_exec_flags5 = -1;
449 static int hf_mysql_exec_iter = -1;
450 static int hf_mysql_binlog_position = -1;
451 static int hf_mysql_binlog_flags = -1;
452 static int hf_mysql_binlog_server_id = -1;
453 static int hf_mysql_binlog_file_name = -1;
454 static int hf_mysql_eof = -1;
455 static int hf_mysql_num_fields = -1;
456 static int hf_mysql_extra = -1;
457 static int hf_mysql_fld_catalog = -1;
458 static int hf_mysql_fld_db = -1;
459 static int hf_mysql_fld_table = -1;
460 static int hf_mysql_fld_org_table = -1;
461 static int hf_mysql_fld_name = -1;
462 static int hf_mysql_fld_org_name = -1;
463 static int hf_mysql_fld_charsetnr = -1;
464 static int hf_mysql_fld_length = -1;
465 static int hf_mysql_fld_type = -1;
466 static int hf_mysql_fld_flags = -1;
467 static int hf_mysql_fld_not_null = -1;
468 static int hf_mysql_fld_primary_key = -1;
469 static int hf_mysql_fld_unique_key = -1;
470 static int hf_mysql_fld_multiple_key = -1;
471 static int hf_mysql_fld_blob = -1;
472 static int hf_mysql_fld_unsigned = -1;
473 static int hf_mysql_fld_zero_fill = -1;
474 static int hf_mysql_fld_binary = -1;
475 static int hf_mysql_fld_enum = -1;
476 static int hf_mysql_fld_auto_increment = -1;
477 static int hf_mysql_fld_timestamp = -1;
478 static int hf_mysql_fld_set = -1;
479 static int hf_mysql_fld_decimals = -1;
480 static int hf_mysql_fld_default = -1;
481 static int hf_mysql_row_text = -1;
484 static const value_string type_constants[] =
486 {0x00, "FIELD_TYPE_DECIMAL" },
487 {0x01, "FIELD_TYPE_TINY" },
488 {0x02, "FIELD_TYPE_SHORT" },
489 {0x03, "FIELD_TYPE_LONG" },
490 {0x04, "FIELD_TYPE_FLOAT" },
491 {0x05, "FIELD_TYPE_DOUBLE" },
492 {0x06, "FIELD_TYPE_NULL" },
493 {0x07, "FIELD_TYPE_TIMESTAMP" },
494 {0x08, "FIELD_TYPE_LONGLONG" },
495 {0x09, "FIELD_TYPE_INT24" },
496 {0x0a, "FIELD_TYPE_DATE" },
497 {0x0b, "FIELD_TYPE_TIME" },
498 {0x0c, "FIELD_TYPE_DATETIME" },
499 {0x0d, "FIELD_TYPE_YEAR" },
500 {0x0e, "FIELD_TYPE_NEWDATE" },
501 {0x0f, "FIELD_TYPE_VARCHAR" },
502 {0x10, "FIELD_TYPE_BIT" },
503 {0xf6, "FIELD_TYPE_NEWDECIMAL" },
504 {0xf7, "FIELD_TYPE_ENUM" },
505 {0xf8, "FIELD_TYPE_SET" },
506 {0xf9, "FIELD_TYPE_TINY_BLOB" },
507 {0xfa, "FIELD_TYPE_MEDIUM_BLOB"},
508 {0xfb, "FIELD_TYPE_LONG_BLOB" },
509 {0xfc, "FIELD_TYPE_BLOB" },
510 {0xfd, "FIELD_TYPE_VAR_STRING" },
511 {0xfe, "FIELD_TYPE_STRING" },
512 {0xff, "FIELD_TYPE_GEOMETRY" },
516 typedef enum mysql_state
524 RESPONSE_SHOW_FIELDS,
533 static const value_string state_vals[] = {
534 {UNDEFINED, "undefined"},
536 {REQUEST, "request"},
537 {RESPONSE_OK, "response OK"},
538 {RESPONSE_MESSAGE, "response message"},
539 {RESPONSE_TABULAR, "tabular response"},
540 {RESPONSE_SHOW_FIELDS, "response to SHOW FIELDS"},
541 {FIELD_PACKET, "field packet"},
542 {ROW_PACKET, "row packet"},
543 {RESPONSE_PREPARE, "response to PREPARE"},
544 {RESPONSE_PARAMETERS, "parameters in response to PREPARE"},
545 {RESPONSE_FIELDS, "fields in response to PREPARE"},
550 typedef struct mysql_conn_data
554 guint16 clnt_caps_ext;
556 guint16 stmt_num_params;
557 guint16 stmt_num_fields;
562 guint8 major_version;
565 struct mysql_frame_data {
569 typedef struct my_stmt_data
575 /* function prototypes */
576 static void dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
577 static guint get_mysql_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset);
578 static void dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
579 static int mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
580 static int mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
581 static int mysql_dissect_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
582 static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
583 static int mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
584 static int mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
585 static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree);
586 static int mysql_dissect_caps_server(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
587 static int mysql_dissect_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
588 static int mysql_dissect_ext_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps);
589 static int mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
590 static int mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
591 static int mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree);
592 static int mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data);
593 static gint my_tvb_strsize(tvbuff_t *tvb, int offset);
594 static int tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null);
596 /* dissector entrypoint, handles TCP-desegmentation */
598 dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
600 tcp_dissect_pdus(tvb, pinfo, tree, mysql_desegment, 3,
601 get_mysql_pdu_len, dissect_mysql_pdu);
605 /* dissector helper: length of PDU */
607 get_mysql_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
609 guint plen= tvb_get_letoh24(tvb, offset);
610 return plen + 4; /* add length field + packet number */
613 /* dissector main function: handle one PDU */
615 dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
617 proto_tree *mysql_tree= NULL;
619 conversation_t *conversation;
622 gboolean is_response;
623 mysql_conn_data_t *conn_data;
625 mysql_state_t conn_state_in, conn_state_out, frame_state;
629 struct mysql_frame_data *mysql_frame_data_p;
631 /* get conversation, create if neccessary*/
632 conversation= find_or_create_conversation(pinfo);
634 /* get associated state information, create if neccessary */
635 conn_data= conversation_get_proto_data(conversation, proto_mysql);
637 conn_data= se_alloc(sizeof(mysql_conn_data_t));
638 conn_data->srv_caps= 0;
639 conn_data->clnt_caps= 0;
640 conn_data->clnt_caps_ext= 0;
641 conn_data->state= UNDEFINED;
642 conn_data->stmts= g_hash_table_new(g_int_hash, g_int_equal);
644 conn_data->generation= 0;
646 conn_data->major_version= 0;
647 conversation_add_proto_data(conversation, proto_mysql, conn_data);
650 mysql_frame_data_p = p_get_proto_data(pinfo->fd, proto_mysql);
651 if (!mysql_frame_data_p) {
652 /* We haven't seen this frame before. Store the state of the
653 * conversation now so if/when we dissect the frame again
654 * we'll start with the same state.
656 mysql_frame_data_p = se_alloc(sizeof(struct mysql_frame_data));
657 mysql_frame_data_p->state = conn_data->state;
658 p_add_proto_data(pinfo->fd, proto_mysql, mysql_frame_data_p);
660 } else if (conn_data->state != FIELD_PACKET && conn_data->state != ROW_PACKET ) {
661 /* We have seen this frame before. Set the connection state
662 * to whatever state it had the first time we saw this frame
663 * (e.g., based on whatever frames came before it).
664 * The state may change as we dissect this packet.
665 * XXX: I think the logic of the above else if test is as follows:
666 * During the first (sequential) dissection pass thru the capture
667 * file the conversation connection state as of the beginning of each frame
668 * is saved in the connection_state for that frame.
669 * Any state changes *within* a mysql "message" (ie: query/response/etc)
670 * while processing mysql PDUS (aka "packets") in that message must be preserved.
671 * It appears that FIELD_PACKET & ROW_PACKET are the only two
672 * state changes which can occur within a mysql message which affect
673 * subsequent processing within the message.
674 * Question: Does this logic work OK for a reassembled message ?
676 conn_data->state= mysql_frame_data_p->state;
680 ti = proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, ENC_NA);
681 mysql_tree = proto_item_add_subtree(ti, ett_mysql);
682 proto_tree_add_item(mysql_tree, hf_mysql_packet_length, tvb, offset, 3, ENC_LITTLE_ENDIAN);
686 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
688 if (pinfo->destport == pinfo->match_uint) {
694 packet_number = tvb_get_guint8(tvb, offset);
695 proto_tree_add_item(mysql_tree, hf_mysql_packet_number, tvb, offset, 1, ENC_NA);
699 conn_state_in= conn_data->state;
700 frame_state = mysql_frame_data_p->state;
701 generation= conn_data->generation;
703 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conversation: %p", conversation);
704 PROTO_ITEM_SET_GENERATED(pi);
705 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "generation: %" G_GINT64_MODIFIER "d", generation);
706 PROTO_ITEM_SET_GENERATED(pi);
707 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "conn state: %s (%u)",
708 val_to_str(conn_state_in, state_vals, "Unknown (%u)"),
710 PROTO_ITEM_SET_GENERATED(pi);
711 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "frame state: %s (%u)",
712 val_to_str(frame_state, state_vals, "Unknown (%u)"),
714 PROTO_ITEM_SET_GENERATED(pi);
719 if (packet_number == 0) {
720 col_set_str(pinfo->cinfo, COL_INFO, "Server Greeting");
721 offset = mysql_dissect_greeting(tvb, pinfo, offset, mysql_tree, conn_data);
723 col_set_str(pinfo->cinfo, COL_INFO, "Response");
724 offset = mysql_dissect_response(tvb, pinfo, offset, mysql_tree, conn_data);
727 if (packet_number == 1) {
728 col_set_str(pinfo->cinfo, COL_INFO, "Login Request");
729 offset = mysql_dissect_login(tvb, pinfo, offset, mysql_tree, conn_data);
731 col_set_str(pinfo->cinfo, COL_INFO, "Request");
732 offset = mysql_dissect_request(tvb, pinfo, offset, mysql_tree, conn_data);
737 conn_state_out= conn_data->state;
738 ++(conn_data->generation);
739 pi= proto_tree_add_text(mysql_tree, tvb, offset, 0, "next proto state: %s (%u)",
740 val_to_str(conn_state_out, state_vals, "Unknown (%u)"),
742 PROTO_ITEM_SET_GENERATED(pi);
745 /* remaining payload indicates an error */
746 if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
747 ti = proto_tree_add_item(mysql_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
748 expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME - dissector is incomplete");
754 mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset,
755 proto_tree *tree, mysql_conn_data_t *conn_data)
762 proto_item *greeting_tree= NULL;
764 protocol= tvb_get_guint8(tvb, offset);
766 if (protocol == 0xff) {
767 return mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
770 conn_data->state= LOGIN;
773 tf = proto_tree_add_item(tree, hf_mysql_server_greeting, tvb, offset, -1, ENC_NA);
774 greeting_tree = proto_item_add_subtree(tf, ett_server_greeting);
777 if (check_col(pinfo->cinfo, COL_INFO)) {
778 col_append_fstr(pinfo->cinfo, COL_INFO, " proto=%d", protocol) ;
780 proto_tree_add_item(greeting_tree, hf_mysql_protocol, tvb, offset, 1, ENC_NA);
785 strlen = tvb_strsize(tvb,offset);
786 if (check_col(pinfo->cinfo, COL_INFO)) {
787 col_append_fstr(pinfo->cinfo, COL_INFO, " version=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
789 proto_tree_add_item(greeting_tree, hf_mysql_version, tvb, offset, strlen, ENC_NA);
790 conn_data->major_version = 0;
791 for (ver_offset = 0; ver_offset < strlen; ver_offset++) {
792 guint8 ver_char = tvb_get_guint8(tvb, offset + ver_offset);
793 if (ver_char == '.') break;
794 conn_data->major_version = conn_data->major_version * 10 + ver_char - '0';
798 /* 4 bytes little endian thread_id */
799 proto_tree_add_item(greeting_tree, hf_mysql_thread_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
803 strlen = tvb_strsize(tvb,offset);
804 proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb, offset, strlen, ENC_NA);
807 /* rest is optional */
808 if (!tvb_reported_length_remaining(tvb, offset)) return offset;
811 offset = mysql_dissect_caps_server(tvb, offset, greeting_tree, &conn_data->srv_caps);
813 /* rest is optional */
814 if (!tvb_reported_length_remaining(tvb, offset)) return offset;
816 proto_tree_add_item(greeting_tree, hf_mysql_server_language, tvb, offset, 1, ENC_NA);
817 offset += 1; /* for charset */
819 offset = mysql_dissect_server_status(tvb, offset, greeting_tree);
821 /* 13 bytes unused */
822 proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb, offset, 13, ENC_NA);
825 /* 4.1+ server: rest of salt */
826 if (tvb_reported_length_remaining(tvb, offset)) {
827 strlen = tvb_strsize(tvb,offset);
828 proto_tree_add_item(greeting_tree, hf_mysql_salt2, tvb, offset, strlen, ENC_NA);
837 mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset,
838 proto_tree *tree, mysql_conn_data_t *conn_data)
843 proto_item *login_tree= NULL;
845 /* after login there can be OK or DENIED */
846 conn_data->state = RESPONSE_OK;
849 tf = proto_tree_add_item(tree, hf_mysql_login_request, tvb, offset, -1, ENC_NA);
850 login_tree = proto_item_add_subtree(tf, ett_login_request);
853 offset = mysql_dissect_caps_client(tvb, offset, login_tree, &conn_data->clnt_caps);
855 if (conn_data->clnt_caps & MYSQL_CAPS_CU) /* 4.1 protocol */
857 offset = mysql_dissect_ext_caps_client(tvb, offset, login_tree, &conn_data->clnt_caps_ext);
859 proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 4, ENC_LITTLE_ENDIAN);
862 proto_tree_add_item(login_tree, hf_mysql_charset, tvb, offset, 1, ENC_NA);
863 offset += 1; /* for charset */
865 offset += 23; /* filler bytes */
867 } else { /* pre-4.1 */
868 proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 3, ENC_LITTLE_ENDIAN);
873 strlen = my_tvb_strsize(tvb, offset);
874 if (check_col(pinfo->cinfo, COL_INFO)) {
875 col_append_fstr(pinfo->cinfo, COL_INFO, " user=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
877 proto_tree_add_item(login_tree, hf_mysql_user, tvb, offset, strlen, ENC_NA);
880 /* rest is optional */
881 if (!tvb_reported_length_remaining(tvb, offset)) return offset;
883 /* password: asciiz or length+ascii */
884 if (conn_data->clnt_caps & MYSQL_CAPS_SC) {
885 strlen = tvb_get_guint8(tvb, offset);
888 strlen = my_tvb_strsize(tvb, offset);
890 if (tree && strlen > 1) {
891 proto_tree_add_item(login_tree, hf_mysql_passwd, tvb, offset, strlen, ENC_NA);
895 /* optional: initial schema */
896 if (conn_data->clnt_caps & MYSQL_CAPS_CD)
898 strlen= my_tvb_strsize(tvb,offset);
903 if (check_col(pinfo->cinfo, COL_INFO)) {
904 col_append_fstr(pinfo->cinfo, COL_INFO, " db=%s", tvb_get_ephemeral_string(tvb, offset, strlen));
906 proto_tree_add_item(login_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
915 mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset,
916 proto_tree *tree, mysql_conn_data_t *conn_data)
920 proto_item *tf = NULL, *ti;
921 proto_item *req_tree = NULL;
924 tf = proto_tree_add_item(tree, hf_mysql_request, tvb, offset, 1, ENC_NA);
925 req_tree = proto_item_add_subtree(tf, ett_request);
928 opcode = tvb_get_guint8(tvb, offset);
929 if (check_col(pinfo->cinfo, COL_INFO)) {
930 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(opcode, mysql_command_vals, "Unknown (%u)"));
932 proto_tree_add_item(req_tree, hf_mysql_command, tvb, offset, 1, ENC_NA);
933 proto_item_append_text(tf, " %s", val_to_str(opcode, mysql_command_vals, "Unknown (%u)"));
940 if (conn_data->stmts) {
941 g_hash_table_destroy(conn_data->stmts);
942 conn_data->stmts = NULL;
946 case MYSQL_PROCESS_INFO:
947 conn_data->state = RESPONSE_TABULAR;
952 conn_data->state = RESPONSE_OK;
955 case MYSQL_STATISTICS:
956 conn_data->state = RESPONSE_MESSAGE;
960 case MYSQL_CREATE_DB:
962 strlen = my_tvb_strsize(tvb, offset);
963 proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
965 conn_data->state = RESPONSE_OK;
969 strlen = my_tvb_strsize(tvb, offset);
970 proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, strlen, ENC_NA);
971 if (mysql_showquery) {
972 if (check_col(pinfo->cinfo, COL_INFO))
973 col_append_fstr(pinfo->cinfo, COL_INFO, " { %s } ", tvb_get_ephemeral_string(tvb, offset, strlen));
976 conn_data->state = RESPONSE_TABULAR;
979 case MYSQL_STMT_PREPARE:
980 strlen = my_tvb_strsize(tvb, offset);
981 proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, strlen, ENC_NA);
983 conn_data->state = RESPONSE_PREPARE;
986 case MYSQL_STMT_CLOSE:
987 if (conn_data->stmts) {
988 gint stmt = tvb_get_letohl(tvb, offset);
989 g_hash_table_remove(conn_data->stmts, &stmt);
991 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
993 conn_data->state = REQUEST;
996 case MYSQL_STMT_RESET:
997 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
999 conn_data->state = RESPONSE_OK;
1002 case MYSQL_FIELD_LIST:
1003 strlen = my_tvb_strsize(tvb, offset);
1004 proto_tree_add_item(req_tree, hf_mysql_table_name, tvb, offset, strlen, ENC_NA);
1006 conn_data->state = RESPONSE_SHOW_FIELDS;
1009 case MYSQL_PROCESS_KILL:
1010 proto_tree_add_item(req_tree, hf_mysql_thd_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1012 conn_data->state = RESPONSE_OK;
1015 case MYSQL_CHANGE_USER:
1016 strlen = tvb_strsize(tvb, offset);
1017 proto_tree_add_item(req_tree, hf_mysql_user, tvb, offset, strlen, ENC_NA);
1020 strlen = tvb_strsize(tvb, offset);
1021 proto_tree_add_item(req_tree, hf_mysql_passwd, tvb, offset, strlen, ENC_NA);
1024 strlen = my_tvb_strsize(tvb, offset);
1025 proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, strlen, ENC_NA);
1028 conn_data->state= RESPONSE_OK;
1034 proto_item *rfsh_tree;
1036 tff = proto_tree_add_item(req_tree, hf_mysql_refresh, tvb, offset, 1, ENC_NA);
1037 rfsh_tree = proto_item_add_subtree(tff, ett_refresh);
1038 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_grants, tvb, offset, 1, ENC_NA);
1039 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_log, tvb, offset, 1, ENC_NA);
1040 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_tables, tvb, offset, 1, ENC_NA);
1041 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_hosts, tvb, offset, 1, ENC_NA);
1042 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_status, tvb, offset, 1, ENC_NA);
1043 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_threads, tvb, offset, 1, ENC_NA);
1044 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_slave, tvb, offset, 1, ENC_NA);
1045 proto_tree_add_item(rfsh_tree, hf_mysql_rfsh_master, tvb, offset, 1, ENC_NA);
1049 conn_data->state= RESPONSE_OK;
1052 case MYSQL_SHUTDOWN:
1053 proto_tree_add_item(req_tree, hf_mysql_shutdown, tvb, offset, 1, ENC_NA);
1055 conn_data->state = RESPONSE_OK;
1058 case MYSQL_SET_OPTION:
1059 proto_tree_add_item(req_tree, hf_mysql_option, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1061 conn_data->state = RESPONSE_OK;
1064 case MYSQL_STMT_FETCH:
1065 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1068 proto_tree_add_item(req_tree, hf_mysql_num_rows, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1070 conn_data->state = RESPONSE_TABULAR;
1073 case MYSQL_STMT_SEND_LONG_DATA:
1074 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1077 proto_tree_add_item(req_tree, hf_mysql_param, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1081 strlen = tvb_reported_length_remaining(tvb, offset);
1082 if (tree && strlen > 0) {
1083 proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, strlen, ENC_NA);
1086 conn_data->state = REQUEST;
1089 case MYSQL_STMT_EXECUTE:
1090 proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1093 if (conn_data->major_version >= 5) {
1094 proto_tree_add_item(req_tree, hf_mysql_exec_flags5, tvb, offset, 1, ENC_NA);
1096 proto_tree_add_item(req_tree, hf_mysql_exec_flags4, tvb, offset, 1, ENC_NA);
1100 proto_tree_add_item(req_tree, hf_mysql_exec_iter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1104 /* FIXME: rest needs metadata about statement */
1106 strlen = tvb_reported_length_remaining(tvb, offset);
1107 if (tree && strlen > 0) {
1108 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, strlen, ENC_NA);
1109 expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME: execute dissector incomplete");
1113 conn_data->state= RESPONSE_TABULAR;
1116 case MYSQL_BINLOG_DUMP:
1117 proto_tree_add_item(req_tree, hf_mysql_binlog_position, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1120 proto_tree_add_item(req_tree, hf_mysql_binlog_flags, tvb, offset, 2, ENC_NA);
1123 proto_tree_add_item(req_tree, hf_mysql_binlog_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1126 /* binlog file name ? */
1127 strlen = tvb_reported_length_remaining(tvb, offset);
1128 if (tree && strlen > 0) {
1129 proto_tree_add_item(req_tree, hf_mysql_binlog_file_name, tvb, offset, strlen, ENC_NA);
1133 conn_data->state = REQUEST;
1135 /* FIXME: implement replication packets */
1136 case MYSQL_TABLE_DUMP:
1137 case MYSQL_CONNECT_OUT:
1138 case MYSQL_REGISTER_SLAVE:
1139 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
1140 expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_WARN, "FIXME: implement replication packets");
1141 offset += tvb_reported_length_remaining(tvb, offset);
1142 conn_data->state = REQUEST;
1146 ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA);
1147 expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "Unknown/invalid command code");
1148 offset += tvb_reported_length_remaining(tvb, offset);
1149 conn_data->state = UNDEFINED;
1157 mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset,
1158 proto_tree *tree, mysql_conn_data_t *conn_data)
1162 gint server_status = 0;
1164 response_code = tvb_get_guint8(tvb, offset);
1166 if (response_code == 0xff ) {
1167 offset = mysql_dissect_error_packet(tvb, pinfo, offset+1, tree);
1168 conn_data->state= REQUEST;
1171 else if (response_code == 0xfe && tvb_reported_length_remaining(tvb, offset) < 9) {
1173 proto_tree_add_item(tree, hf_mysql_eof, tvb, offset, 1, ENC_NA);
1177 /* pre-4.1 packet ends here */
1178 if (tvb_reported_length_remaining(tvb, offset)) {
1179 proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1180 server_status = tvb_get_letohs(tvb, offset+2);
1181 offset = mysql_dissect_server_status(tvb, offset+2, tree);
1184 if (conn_data->state == FIELD_PACKET) {
1185 conn_data->state= ROW_PACKET;
1186 } else if (conn_data->state == ROW_PACKET) {
1187 if (server_status & MYSQL_STAT_MU) {
1188 conn_data->state= RESPONSE_TABULAR;
1190 conn_data->state= REQUEST;
1192 } else if (conn_data->state == PREPARED_PARAMETERS) {
1193 if (conn_data->stmt_num_fields > 0) {
1194 conn_data->state= PREPARED_FIELDS;
1196 conn_data->state= REQUEST;
1198 } else if (conn_data->state == PREPARED_FIELDS) {
1199 conn_data->state= REQUEST;
1201 /* This should be an unreachable case */
1202 conn_data->state= REQUEST;
1206 else if (response_code == 0) {
1207 if (conn_data->state == RESPONSE_PREPARE) {
1208 offset = mysql_dissect_response_prepare(tvb, offset, tree, conn_data);
1209 } else if (tvb_reported_length_remaining(tvb, offset+1) > tvb_get_fle(tvb, offset+1, NULL, NULL)) {
1210 offset = mysql_dissect_ok_packet(tvb, pinfo, offset+1, tree, conn_data);
1212 offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
1217 switch (conn_data->state) {
1218 case RESPONSE_MESSAGE:
1219 if ((strlen = tvb_reported_length_remaining(tvb, offset))) {
1220 proto_tree_add_item(tree, hf_mysql_message, tvb, offset, strlen, ENC_NA);
1223 conn_data->state = REQUEST;
1226 case RESPONSE_TABULAR:
1227 offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data);
1231 case RESPONSE_SHOW_FIELDS:
1232 case RESPONSE_PREPARE:
1233 case PREPARED_PARAMETERS:
1234 offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
1238 offset = mysql_dissect_row_packet(tvb, offset, tree);
1241 case PREPARED_FIELDS:
1242 offset = mysql_dissect_field_packet(tvb, offset, tree, conn_data);
1246 proto_tree_add_string(tree, hf_mysql_payload, tvb, offset, -1,
1247 "unknown/invalid response");
1248 offset += tvb_reported_length_remaining(tvb, offset);
1249 conn_data->state = UNDEFINED;
1258 mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo,
1259 int offset, proto_tree *tree)
1261 if (check_col(pinfo->cinfo, COL_INFO)) {
1262 col_append_fstr(pinfo->cinfo, COL_INFO, " Error %d", tvb_get_letohs(tvb, offset));
1264 proto_tree_add_item(tree, hf_mysql_error_code, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1267 if (tvb_get_guint8(tvb, offset) == '#')
1270 proto_tree_add_item(tree, hf_mysql_sqlstate, tvb, offset, 5, ENC_NA);
1274 proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, ENC_NA);
1275 offset += tvb_reported_length_remaining(tvb, offset);
1282 mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset,
1283 proto_tree *tree, mysql_conn_data_t *conn_data)
1286 guint64 affected_rows;
1290 col_append_str(pinfo->cinfo, COL_INFO, " OK" );
1292 fle = tvb_get_fle(tvb, offset, &affected_rows, NULL);
1293 proto_tree_add_uint64(tree, hf_mysql_affected_rows, tvb, offset, fle, affected_rows);
1296 fle= tvb_get_fle(tvb, offset, &insert_id, NULL);
1297 if (tree && insert_id) {
1298 proto_tree_add_uint64(tree, hf_mysql_insert_id, tvb, offset, fle, insert_id);
1302 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1303 offset = mysql_dissect_server_status(tvb, offset, tree);
1305 /* 4.1+ protocol only: 2 bytes number of warnings */
1306 if (conn_data->clnt_caps & conn_data->srv_caps & MYSQL_CAPS_CU) {
1307 proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1312 /* optional: message string */
1313 if (tvb_reported_length_remaining(tvb, offset) > 0) {
1314 strlen = tvb_reported_length_remaining(tvb, offset);
1315 proto_tree_add_item(tree, hf_mysql_message, tvb, offset, strlen, ENC_NA);
1319 conn_data->state = REQUEST;
1325 mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree)
1328 proto_item *stat_tree;
1331 tf= proto_tree_add_item(tree, hf_mysql_server_status, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1332 stat_tree= proto_item_add_subtree(tf, ett_stat);
1333 proto_tree_add_item(stat_tree, hf_mysql_stat_it, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1334 proto_tree_add_item(stat_tree, hf_mysql_stat_ac, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1335 proto_tree_add_item(stat_tree, hf_mysql_stat_mr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1336 proto_tree_add_item(stat_tree, hf_mysql_stat_mu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1337 proto_tree_add_item(stat_tree, hf_mysql_stat_bi, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1338 proto_tree_add_item(stat_tree, hf_mysql_stat_ni, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1339 proto_tree_add_item(stat_tree, hf_mysql_stat_cr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1340 proto_tree_add_item(stat_tree, hf_mysql_stat_lr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1341 proto_tree_add_item(stat_tree, hf_mysql_stat_dr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1342 proto_tree_add_item(stat_tree, hf_mysql_stat_bs, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1351 mysql_dissect_caps_server(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps)
1354 proto_item *cap_tree;
1356 *caps= tvb_get_letohs(tvb, offset);
1359 tf = proto_tree_add_item(tree, hf_mysql_caps_server, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1360 cap_tree= proto_item_add_subtree(tf, ett_caps);
1361 proto_tree_add_item(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1362 proto_tree_add_item(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1363 proto_tree_add_item(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1364 proto_tree_add_item(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1365 proto_tree_add_item(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1366 proto_tree_add_item(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1367 proto_tree_add_item(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1368 proto_tree_add_item(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1369 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1370 proto_tree_add_item(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1371 proto_tree_add_item(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1372 proto_tree_add_item(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1373 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1374 proto_tree_add_item(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1375 proto_tree_add_item(cap_tree, hf_mysql_cap_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1376 proto_tree_add_item(cap_tree, hf_mysql_cap_secure_connect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1384 mysql_dissect_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *caps)
1387 proto_item *cap_tree;
1389 *caps= tvb_get_letohs(tvb, offset);
1392 tf = proto_tree_add_item(tree, hf_mysql_caps_client, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1393 cap_tree= proto_item_add_subtree(tf, ett_caps);
1394 proto_tree_add_item(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1395 proto_tree_add_item(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1396 proto_tree_add_item(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1397 proto_tree_add_item(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1398 proto_tree_add_item(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1399 proto_tree_add_item(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1400 proto_tree_add_item(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1401 proto_tree_add_item(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1402 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1403 proto_tree_add_item(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1404 proto_tree_add_item(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1405 proto_tree_add_item(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1406 proto_tree_add_item(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1407 proto_tree_add_item(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1408 proto_tree_add_item(cap_tree, hf_mysql_cap_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1409 proto_tree_add_item(cap_tree, hf_mysql_cap_secure_connect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1416 mysql_dissect_ext_caps_client(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *ext_caps)
1419 proto_item *extcap_tree;
1420 *ext_caps= tvb_get_letohs(tvb, offset);
1422 tf = proto_tree_add_item(tree, hf_mysql_extcaps_client, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1423 extcap_tree = proto_item_add_subtree(tf, ett_extcaps);
1424 proto_tree_add_item(extcap_tree, hf_mysql_cap_multi_statements, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1425 proto_tree_add_item(extcap_tree, hf_mysql_cap_multi_results, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1434 mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset,
1435 proto_tree *tree, mysql_conn_data_t *conn_data)
1438 guint64 num_fields, extra;
1440 col_append_str(pinfo->cinfo, COL_INFO, " TABULAR" );
1442 fle = tvb_get_fle(tvb, offset, &num_fields, NULL);
1443 proto_tree_add_uint64(tree, hf_mysql_num_fields, tvb, offset, fle, num_fields);
1446 if (tvb_reported_length_remaining(tvb, offset)) {
1447 fle = tvb_get_fle(tvb, offset, &extra, NULL);
1448 proto_tree_add_uint64(tree, hf_mysql_extra, tvb, offset, fle, extra);
1453 conn_data->state = FIELD_PACKET;
1455 conn_data->state = ROW_PACKET;
1463 * Add length encoded string to tree
1466 mysql_field_add_lestring(tvbuff_t *tvb, int offset, proto_tree *tree, int field)
1471 offset += tvb_get_fle(tvb, offset, &lelen, &is_null);
1473 proto_tree_add_string(tree, field, tvb, offset, 4, "NULL");
1476 proto_tree_add_item(tree, field, tvb, offset, (int)lelen, ENC_NA);
1477 offset += (int)lelen;
1484 mysql_dissect_field_packet(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_)
1487 proto_item *flags_tree;
1489 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_catalog);
1490 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_db);
1491 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_table);
1492 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_table);
1493 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_name);
1494 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_name);
1495 offset +=1; /* filler */
1497 proto_tree_add_item(tree, hf_mysql_fld_charsetnr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1498 offset += 2; /* charset */
1500 proto_tree_add_item(tree, hf_mysql_fld_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1501 offset += 4; /* length */
1503 proto_tree_add_item(tree, hf_mysql_fld_type, tvb, offset, 1, ENC_NA);
1504 offset += 1; /* type */
1506 tf = proto_tree_add_item(tree, hf_mysql_fld_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1507 flags_tree = proto_item_add_subtree(tf, ett_field_flags);
1508 proto_tree_add_item(flags_tree, hf_mysql_fld_not_null, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1509 proto_tree_add_item(flags_tree, hf_mysql_fld_primary_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1510 proto_tree_add_item(flags_tree, hf_mysql_fld_unique_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1511 proto_tree_add_item(flags_tree, hf_mysql_fld_multiple_key, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1512 proto_tree_add_item(flags_tree, hf_mysql_fld_blob, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1513 proto_tree_add_item(flags_tree, hf_mysql_fld_unsigned, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1514 proto_tree_add_item(flags_tree, hf_mysql_fld_zero_fill, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1515 proto_tree_add_item(flags_tree, hf_mysql_fld_binary, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1516 proto_tree_add_item(flags_tree, hf_mysql_fld_enum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1517 proto_tree_add_item(flags_tree, hf_mysql_fld_auto_increment, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1518 proto_tree_add_item(flags_tree, hf_mysql_fld_timestamp, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1519 proto_tree_add_item(flags_tree, hf_mysql_fld_set, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1520 offset += 2; /* flags */
1522 proto_tree_add_item(tree, hf_mysql_fld_decimals, tvb, offset, 1, ENC_NA);
1523 offset += 1; /* decimals */
1525 offset += 2; /* filler */
1527 /* default (Only use for show fields) */
1528 if (tree && tvb_reported_length_remaining(tvb, offset) > 0) {
1529 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_default);
1536 mysql_dissect_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree)
1538 while (tvb_reported_length_remaining(tvb, offset) > 0) {
1539 offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_row_text);
1547 mysql_dissect_response_prepare(tvbuff_t *tvb, int offset, proto_tree *tree, mysql_conn_data_t *conn_data)
1549 /* 0, marker for OK packet */
1551 proto_tree_add_item(tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1553 proto_tree_add_item(tree, hf_mysql_num_fields, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1554 conn_data->stmt_num_fields = tvb_get_letohs(tvb, offset);
1556 proto_tree_add_item(tree, hf_mysql_num_params, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1557 conn_data->stmt_num_params = tvb_get_letohs(tvb, offset);
1561 proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1563 if (conn_data->stmt_num_params > 0)
1564 conn_data->state = PREPARED_PARAMETERS;
1565 else if (conn_data->stmt_num_fields > 0)
1566 conn_data->state = PREPARED_FIELDS;
1568 conn_data->state = REQUEST;
1570 return offset + tvb_reported_length_remaining(tvb, offset);
1576 get length of string in packet buffer
1581 offset current offset
1584 deliver length of string, delimited by either \0 or end of buffer
1587 length of string found, including \0 (if present)
1591 my_tvb_strsize(tvbuff_t *tvb, int offset)
1593 gint len = tvb_strnlen(tvb, offset, -1);
1595 len = tvb_reported_length_remaining(tvb, offset);
1597 len++; /* the trailing \0 */
1604 read "field length encoded" value from packet buffer
1608 tvb in packet buffer
1609 offset in offset in buffer
1610 res out where to store FLE value, may be NULL
1611 is_null out where to store ISNULL flag, may be NULL
1614 read FLE from packet buffer and store its value and ISNULL flag
1615 in caller provided variables
1621 tvb_get_fle(tvbuff_t *tvb, int offset, guint64 *res, guint8 *is_null)
1625 prefix = tvb_get_guint8(tvb, offset);
1639 *res = tvb_get_letohs(tvb, offset+1);
1643 *res = tvb_get_letohl(tvb, offset+1);
1647 *res = tvb_get_letoh64(tvb, offset+1);
1657 /* protocol registration */
1658 void proto_register_mysql(void)
1660 static hf_register_info hf[]=
1662 { &hf_mysql_packet_length,
1663 { "Packet Length", "mysql.packet_length",
1664 FT_UINT24, BASE_DEC, NULL, 0x0,
1667 { &hf_mysql_packet_number,
1668 { "Packet Number", "mysql.packet_number",
1669 FT_UINT8, BASE_DEC, NULL, 0x0,
1672 { &hf_mysql_request,
1673 { "Request Command", "mysql.request",
1674 FT_NONE, BASE_NONE, NULL, 0x0,
1677 { &hf_mysql_command,
1678 { "Command", "mysql.command",
1679 FT_UINT8, BASE_DEC, VALS(mysql_command_vals), 0x0,
1682 { &hf_mysql_error_code,
1683 { "Error Code", "mysql.error_code",
1684 FT_UINT16, BASE_DEC, NULL, 0x0,
1687 { &hf_mysql_error_string,
1688 { "Error message", "mysql.error.message",
1689 FT_STRING, BASE_NONE, NULL, 0x0,
1690 "Error string in case of MySQL error message", HFILL }},
1692 { &hf_mysql_sqlstate,
1693 { "SQL state", "mysql.sqlstate",
1694 FT_STRING, BASE_NONE, NULL, 0x0,
1697 { &hf_mysql_message,
1698 { "Message", "mysql.message",
1699 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1702 { &hf_mysql_server_greeting,
1703 { "Server Greeting", "mysql.server_greeting",
1704 FT_NONE, BASE_NONE, NULL, 0x0,
1707 { &hf_mysql_protocol,
1708 { "Protocol", "mysql.protocol",
1709 FT_UINT8, BASE_DEC, NULL, 0x0,
1710 "Protocol Version", HFILL }},
1712 { &hf_mysql_version,
1713 { "Version", "mysql.version",
1714 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1715 "MySQL Version", HFILL }},
1717 { &hf_mysql_caps_server,
1718 { "Server Capabilities", "mysql.caps.server",
1719 FT_UINT16, BASE_HEX, NULL, 0x0,
1720 "MySQL Capabilities", HFILL }},
1722 { &hf_mysql_caps_client,
1723 { "Client Capabilities", "mysql.caps.client",
1724 FT_UINT16, BASE_HEX, NULL, 0x0,
1725 "MySQL Capabilities", HFILL }},
1727 { &hf_mysql_cap_long_password,
1728 { "Long Password","mysql.caps.lp",
1729 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LP,
1732 { &hf_mysql_cap_found_rows,
1733 { "Found Rows","mysql.caps.fr",
1734 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_FR,
1737 { &hf_mysql_cap_long_flag,
1738 { "Long Column Flags","mysql.caps.lf",
1739 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LF,
1742 { &hf_mysql_cap_connect_with_db,
1743 { "Connect With Database","mysql.caps.cd",
1744 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CD,
1747 { &hf_mysql_cap_no_schema,
1748 { "Don't Allow database.table.column","mysql.caps.ns",
1749 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_NS,
1752 { &hf_mysql_cap_compress,
1753 { "Can use compression protocol","mysql.caps.cp",
1754 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CP,
1757 { &hf_mysql_cap_odbc,
1758 { "ODBC Client","mysql.caps.ob",
1759 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_OB,
1762 { &hf_mysql_cap_local_files,
1763 { "Can Use LOAD DATA LOCAL","mysql.caps.li",
1764 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LI,
1767 { &hf_mysql_cap_ignore_space,
1768 { "Ignore Spaces before '('","mysql.caps.is",
1769 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IS,
1772 { &hf_mysql_cap_change_user,
1773 { "Speaks 4.1 protocol (new flag)","mysql.caps.cu",
1774 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CU,
1777 { &hf_mysql_cap_interactive,
1778 { "Interactive Client","mysql.caps.ia",
1779 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IA,
1782 { &hf_mysql_cap_ssl,
1783 { "Switch to SSL after handshake","mysql.caps.sl",
1784 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SL,
1787 { &hf_mysql_cap_ignore_sigpipe,
1788 { "Ignore sigpipes","mysql.caps.ii",
1789 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_II,
1792 { &hf_mysql_cap_transactions,
1793 { "Knows about transactions","mysql.caps.ta",
1794 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_TA,
1797 { &hf_mysql_cap_reserved,
1798 { "Speaks 4.1 protocol (old flag)","mysql.caps.rs",
1799 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_RS,
1802 { &hf_mysql_cap_secure_connect,
1803 { "Can do 4.1 authentication","mysql.caps.sc",
1804 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SC,
1807 { &hf_mysql_extcaps_client,
1808 { "Extended Client Capabilities", "mysql.extcaps.client",
1809 FT_UINT16, BASE_HEX, NULL, 0x0,
1810 "MySQL Extended Capabilities", HFILL }},
1812 { &hf_mysql_cap_multi_statements,
1813 { "Supports multiple statements","mysql.caps.ms",
1814 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MS,
1817 { &hf_mysql_cap_multi_results,
1818 { "Supports multiple results","mysql.caps.mr",
1819 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MR,
1822 { &hf_mysql_login_request,
1823 { "Login Request", "mysql.login_request",
1824 FT_NONE, BASE_NONE, NULL, 0x0,
1827 { &hf_mysql_max_packet,
1828 { "MAX Packet", "mysql.max_packet",
1829 FT_UINT24, BASE_DEC, NULL, 0x0,
1830 "MySQL Max packet", HFILL }},
1832 { &hf_mysql_charset,
1833 { "Charset", "mysql.charset",
1834 FT_UINT8, BASE_DEC, VALS(mysql_collation_vals), 0x0,
1835 "MySQL Charset", HFILL }},
1837 { &hf_mysql_table_name,
1838 { "Table Name", "mysql.table_name",
1839 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1843 { "Username", "mysql.user",
1844 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1845 "Login Username", HFILL }},
1848 { "Schema", "mysql.schema",
1849 FT_STRING, BASE_NONE, NULL, 0x0,
1850 "Login Schema", HFILL }},
1853 { "Salt", "mysql.salt",
1854 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1858 { "Salt", "mysql.salt2",
1859 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1862 { &hf_mysql_thread_id,
1863 { "Thread ID", "mysql.thread_id",
1864 FT_UINT32, BASE_DEC, NULL, 0x0,
1865 "MySQL Thread ID", HFILL }},
1867 { &hf_mysql_server_language,
1868 { "Server Language", "mysql.server_language",
1869 FT_UINT8, BASE_DEC, VALS(mysql_collation_vals), 0x0,
1870 "MySQL Charset", HFILL }},
1872 { &hf_mysql_server_status,
1873 { "Server Status", "mysql.server_status",
1874 FT_UINT16, BASE_HEX, NULL, 0x0,
1875 "MySQL Status", HFILL }},
1877 { &hf_mysql_stat_it,
1878 { "In transaction", "mysql.stat.it",
1879 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_IT,
1882 { &hf_mysql_stat_ac,
1883 { "AUTO_COMMIT", "mysql.stat.ac",
1884 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_AC,
1887 { &hf_mysql_stat_mr,
1888 { "More results", "mysql.stat.mr",
1889 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MR,
1892 { &hf_mysql_stat_mu,
1893 { "Multi query - more resultsets", "mysql.stat.mu",
1894 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MU,
1897 { &hf_mysql_stat_bi,
1898 { "Bad index used", "mysql.stat.bi",
1899 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BI,
1902 { &hf_mysql_stat_ni,
1903 { "No index used", "mysql.stat.ni",
1904 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_NI,
1907 { &hf_mysql_stat_cr,
1908 { "Cursor exists", "mysql.stat.cr",
1909 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_CR,
1912 { &hf_mysql_stat_lr,
1913 { "Last row sebd", "mysql.stat.lr",
1914 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_LR,
1917 { &hf_mysql_stat_dr,
1918 { "database dropped", "mysql.stat.dr",
1919 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_DR,
1922 { &hf_mysql_stat_bs,
1923 { "No backslash escapes", "mysql.stat.bs",
1924 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BS,
1927 { &hf_mysql_refresh,
1928 { "Refresh Option", "mysql.refresh",
1929 FT_UINT8, BASE_HEX, NULL, 0x0,
1932 { &hf_mysql_rfsh_grants,
1933 { "reload permissions", "mysql.rfsh.grants",
1934 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_GRANT,
1937 { &hf_mysql_rfsh_log,
1938 { "flush logfiles", "mysql.rfsh.log",
1939 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_LOG,
1942 { &hf_mysql_rfsh_tables,
1943 { "flush tables", "mysql.rfsh.tables",
1944 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_TABLES,
1947 { &hf_mysql_rfsh_hosts,
1948 { "flush hosts", "mysql.rfsh.hosts",
1949 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_HOSTS,
1952 { &hf_mysql_rfsh_status,
1953 { "reset statistics", "mysql.rfsh.status",
1954 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_STATUS,
1957 { &hf_mysql_rfsh_threads,
1958 { "empty thread cache", "mysql.rfsh.threads",
1959 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_THREADS,
1962 { &hf_mysql_rfsh_slave,
1963 { "flush slave status", "mysql.rfsh.slave",
1964 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_SLAVE,
1967 { &hf_mysql_rfsh_master,
1968 { "flush master status", "mysql.rfsh.master",
1969 FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_MASTER,
1973 { "Unused", "mysql.unused",
1974 FT_STRING, BASE_NONE, NULL, 0x0,
1978 { "Password", "mysql.passwd",
1979 FT_BYTES, BASE_NONE, NULL, 0x0,
1982 { &hf_mysql_payload,
1983 { "Payload", "mysql.payload",
1984 FT_BYTES, BASE_NONE, NULL, 0x0,
1985 "Additional Payload", HFILL }},
1987 { &hf_mysql_affected_rows,
1988 { "Affected Rows", "mysql.affected_rows",
1989 FT_UINT64, BASE_DEC, NULL, 0x0,
1992 { &hf_mysql_insert_id,
1993 { "Last INSERT ID", "mysql.insert_id",
1994 FT_UINT64, BASE_DEC, NULL, 0x0,
1997 { &hf_mysql_num_warn,
1998 { "Warnings", "mysql.warnings",
1999 FT_UINT16, BASE_DEC, NULL, 0x0,
2003 { "Thread ID", "mysql.thd_id",
2004 FT_UINT32, BASE_DEC, NULL, 0x0,
2007 { &hf_mysql_stmt_id,
2008 { "Statement ID", "mysql.stmt_id",
2009 FT_UINT32, BASE_DEC, NULL, 0x0,
2013 { "Statement", "mysql.query",
2014 FT_STRING, BASE_NONE, NULL, 0x0,
2017 { &hf_mysql_shutdown,
2018 { "Shutdown Level", "mysql.shutdown",
2019 FT_UINT8, BASE_DEC, VALS(mysql_shutdown_vals), 0x0,
2023 { "Option", "mysql.option",
2024 FT_UINT16, BASE_DEC, VALS(mysql_option_vals), 0x0,
2028 { "Parameter", "mysql.param",
2029 FT_UINT16, BASE_DEC, NULL, 0x0,
2032 { &hf_mysql_num_params,
2033 { "Number of parameter", "mysql.num_params",
2034 FT_UINT16, BASE_DEC, NULL, 0x0,
2037 { &hf_mysql_num_rows,
2038 { "Rows to fetch", "mysql.num_rows",
2039 FT_UINT32, BASE_DEC, NULL, 0x0,
2042 { &hf_mysql_exec_flags4,
2043 { "Flags (unused)", "mysql.exec_flags",
2044 FT_UINT8, BASE_DEC, NULL, 0x0,
2047 { &hf_mysql_exec_flags5,
2048 { "Flags", "mysql.exec_flags",
2049 FT_UINT8, BASE_DEC, VALS(mysql_exec_flags_vals), 0x0,
2052 { &hf_mysql_exec_iter,
2053 { "Iterations (unused)", "mysql.exec_iter",
2054 FT_UINT32, BASE_DEC, NULL, 0x0,
2057 { &hf_mysql_binlog_position,
2058 { "Binlog Position", "mysql.binlog.position",
2059 FT_UINT32, BASE_DEC, NULL, 0x0,
2060 "Position to start at", HFILL }},
2062 { &hf_mysql_binlog_flags,
2063 { "Binlog Flags", "mysql.binlog.flags",
2064 FT_UINT16, BASE_HEX, NULL, 0x0,
2065 "(currently not used; always 0)", HFILL }},
2067 { &hf_mysql_binlog_server_id,
2068 { "Binlog server id", "mysql.binlog.server_id",
2069 FT_UINT16, BASE_HEX, NULL, 0x0,
2070 "server_id of the slave", HFILL }},
2072 { &hf_mysql_binlog_file_name,
2073 { "Binlog file name", "mysql.binlog.file_name",
2074 FT_STRINGZ, BASE_NONE, NULL, 0x0,
2078 { "EOF marker", "mysql.eof",
2079 FT_UINT8, BASE_DEC, NULL, 0x0,
2082 { &hf_mysql_num_fields,
2083 { "Number of fields", "mysql.num_fields",
2084 FT_UINT64, BASE_DEC, NULL, 0x0,
2088 { "Extra data", "mysql.extra",
2089 FT_UINT64, BASE_DEC, NULL, 0x0,
2092 { &hf_mysql_fld_catalog,
2093 { "Catalog", "mysql.field.catalog",
2094 FT_STRING, BASE_NONE, NULL, 0x0,
2095 "Field: catalog", HFILL }},
2098 { "Database", "mysql.field.db",
2099 FT_STRING, BASE_NONE, NULL, 0x0,
2100 "Field: database", HFILL }},
2102 { &hf_mysql_fld_table,
2103 { "Table", "mysql.field.table",
2104 FT_STRING, BASE_NONE, NULL, 0x0,
2105 "Field: table", HFILL }},
2107 { &hf_mysql_fld_org_table,
2108 { "Original table", "mysql.field.org_table",
2109 FT_STRING, BASE_NONE, NULL, 0x0,
2110 "Field: original table", HFILL }},
2112 { &hf_mysql_fld_name,
2113 { "Name", "mysql.field.name",
2114 FT_STRING, BASE_NONE, NULL, 0x0,
2115 "Field: name", HFILL }},
2117 { &hf_mysql_fld_org_name,
2118 { "Original name", "mysql.field.org_name",
2119 FT_STRING, BASE_NONE, NULL, 0x0,
2120 "Field: original name", HFILL }},
2122 { &hf_mysql_fld_charsetnr,
2123 { "Charset number", "mysql.field.charsetnr",
2124 FT_UINT16, BASE_DEC, VALS(mysql_collation_vals), 0x0,
2125 "Field: charset number", HFILL }},
2127 { &hf_mysql_fld_length,
2128 { "Length", "mysql.field.length",
2129 FT_UINT32, BASE_DEC, NULL, 0x0,
2130 "Field: length", HFILL }},
2132 { &hf_mysql_fld_type,
2133 { "Type", "mysql.field.type",
2134 FT_UINT8, BASE_DEC, VALS(type_constants), 0x0,
2135 "Field: type", HFILL }},
2137 { &hf_mysql_fld_flags,
2138 { "Flags", "mysql.field.flags",
2139 FT_UINT16, BASE_HEX, NULL, 0x0,
2140 "Field: flags", HFILL }},
2142 { &hf_mysql_fld_not_null,
2143 { "Not null", "mysql.field.flags.not_null",
2144 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_NOT_NULL_FLAG,
2145 "Field: flag not null", HFILL }},
2147 { &hf_mysql_fld_primary_key,
2148 { "Primary key", "mysql.field.flags.primary_key",
2149 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_PRI_KEY_FLAG,
2150 "Field: flag primary key", HFILL }},
2152 { &hf_mysql_fld_unique_key,
2153 { "Unique key", "mysql.field.flags.unique_key",
2154 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNIQUE_KEY_FLAG,
2155 "Field: flag unique key", HFILL }},
2157 { &hf_mysql_fld_multiple_key,
2158 { "Multiple key", "mysql.field.flags.multiple_key",
2159 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_MULTIPLE_KEY_FLAG,
2160 "Field: flag multiple key", HFILL }},
2162 { &hf_mysql_fld_blob,
2163 { "Blob", "mysql.field.flags.blob",
2164 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BLOB_FLAG,
2165 "Field: flag blob", HFILL }},
2167 { &hf_mysql_fld_unsigned,
2168 { "Unsigned", "mysql.field.flags.unsigned",
2169 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNSIGNED_FLAG,
2170 "Field: flag unsigned", HFILL }},
2172 { &hf_mysql_fld_zero_fill,
2173 { "Zero fill", "mysql.field.flags.zero_fill",
2174 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ZEROFILL_FLAG,
2175 "Field: flag zero fill", HFILL }},
2177 { &hf_mysql_fld_binary,
2178 { "Binary", "mysql.field.flags.binary",
2179 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BINARY_FLAG,
2180 "Field: flag binary", HFILL }},
2182 { &hf_mysql_fld_enum,
2183 { "Enum", "mysql.field.flags.enum",
2184 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ENUM_FLAG,
2185 "Field: flag enum", HFILL }},
2187 { &hf_mysql_fld_auto_increment,
2188 { "Auto increment", "mysql.field.flags.auto_increment",
2189 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_AUTO_INCREMENT_FLAG,
2190 "Field: flag auto increment", HFILL }},
2192 { &hf_mysql_fld_timestamp,
2193 { "Timestamp", "mysql.field.flags.timestamp",
2194 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_TIMESTAMP_FLAG,
2195 "Field: flag timestamp", HFILL }},
2197 { &hf_mysql_fld_set,
2198 { "Set", "mysql.field.flags.set",
2199 FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_SET_FLAG,
2200 "Field: flag set", HFILL }},
2202 { &hf_mysql_fld_decimals,
2203 { "Decimals", "mysql.field.decimals",
2204 FT_UINT8, BASE_DEC, NULL, 0x0,
2205 "Field: decimals", HFILL }},
2207 { &hf_mysql_fld_default,
2208 { "Default", "mysql.field.default",
2209 FT_STRING, BASE_NONE, NULL, 0x0,
2210 "Field: default", HFILL }},
2212 { &hf_mysql_row_text,
2213 { "text", "mysql.row.text",
2214 FT_STRING, BASE_NONE, NULL, 0x0,
2215 "Field: row packet text", HFILL }},
2221 &ett_server_greeting,
2231 module_t *mysql_module;
2233 proto_mysql = proto_register_protocol("MySQL Protocol", "MySQL", "mysql");
2234 proto_register_field_array(proto_mysql, hf, array_length(hf));
2235 proto_register_subtree_array(ett, array_length(ett));
2237 mysql_module = prefs_register_protocol(proto_mysql, NULL);
2238 prefs_register_bool_preference(mysql_module, "desegment_buffers",
2239 "Reassemble MySQL buffers spanning multiple TCP segments",
2240 "Whether the MySQL dissector should reassemble MySQL buffers spanning multiple TCP segments."
2241 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2243 prefs_register_bool_preference(mysql_module, "show_sql_query",
2244 "Show SQL Query string in INFO column",
2245 "Whether the MySQL dissector should display the SQL query string in the INFO column.",
2248 register_dissector("mysql", dissect_mysql_pdu, proto_mysql);
2251 /* dissector registration */
2252 void proto_reg_handoff_mysql(void)
2254 dissector_handle_t mysql_handle;
2255 mysql_handle = create_dissector_handle(dissect_mysql, proto_mysql);
2256 dissector_add_uint("tcp.port", TCP_PORT_MySQL, mysql_handle);