/* packet-mysql.c * Routines for mysql packet dissection * * Huagang XIE * * MySQL 4.1+ protocol by Axel Schwenke * MariaDB protocol by Georg Richter * & Diego Dupin * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Copied from packet-tftp.c * * SPDX-License-Identifier: GPL-2.0-or-later * * * the protocol specifications * For MySQL at * https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html * For MariaDB at * https://mariadb.com/kb/en/clientserver-protocol/ * and MySQL source code */ /* create extra output for conversation tracking */ /* #define CTDEBUG 1 */ #include "config.h" #include #include #include #include #include #include "packet-tcp.h" #include "packet-tls-utils.h" void proto_register_mysql(void); void proto_reg_handoff_mysql(void); /* port for protocol registration */ #define TCP_PORT_MySQL 3306 /* MariaDB Server >= 10.0 sends a 5.5.5- prefix for the version, since replication doesn't support a two digit version number. Version 5.5.5 was never released in MySQL and MariaDB */ #define MARIADB_RPL_VERSION_HACK "5.5.5-" /* client/server capabilities * Docs: https://dev.mysql.com/doc/dev/mysql-server/latest/group__group__cs__capabilities__flags.html * Source: https://github.com/mysql/mysql-server/blob/8.0/include/mysql_com.h */ #define MYSQL_CAPS_LP 0x0001 /* CLIENT_LONG_PASSWORD/CLIENT_IS_MYSQL */ #define MYSQL_CAPS_FR 0x0002 /* CLIENT_FOUND_ROWS */ #define MYSQL_CAPS_LF 0x0004 /* CLIENT_LONG_FLAG */ #define MYSQL_CAPS_CD 0x0008 /* CLIENT_CONNECT_WITH_DB */ #define MYSQL_CAPS_NS 0x0010 /* CLIENT_NO_SCHEMA */ #define MYSQL_CAPS_CP 0x0020 /* CLIENT_COMPRESS */ #define MYSQL_CAPS_OB 0x0040 /* CLIENT_ODBC */ #define MYSQL_CAPS_LI 0x0080 /* CLIENT_LOCAL_FILES */ #define MYSQL_CAPS_IS 0x0100 /* CLIENT_IGNORE_SPACE */ #define MYSQL_CAPS_CU 0x0200 /* CLIENT_PROTOCOL_41 */ #define MYSQL_CAPS_IA 0x0400 /* CLIENT_INTERACTIVE */ #define MYSQL_CAPS_SL 0x0800 /* CLIENT_SSL */ #define MYSQL_CAPS_II 0x1000 /* CLIENT_IGNORE_SPACE */ #define MYSQL_CAPS_TA 0x2000 /* CLIENT_TRANSACTIONS */ #define MYSQL_CAPS_RS 0x4000 /* CLIENT_RESERVED */ #define MYSQL_CAPS_SC 0x8000 /* CLIENT_SECURE_CONNECTION */ /* field flags */ #define MYSQL_FLD_NOT_NULL_FLAG 0x0001 #define MYSQL_FLD_PRI_KEY_FLAG 0x0002 #define MYSQL_FLD_UNIQUE_KEY_FLAG 0x0004 #define MYSQL_FLD_MULTIPLE_KEY_FLAG 0x0008 #define MYSQL_FLD_BLOB_FLAG 0x0010 #define MYSQL_FLD_UNSIGNED_FLAG 0x0020 #define MYSQL_FLD_ZEROFILL_FLAG 0x0040 #define MYSQL_FLD_BINARY_FLAG 0x0080 #define MYSQL_FLD_ENUM_FLAG 0x0100 #define MYSQL_FLD_AUTO_INCREMENT_FLAG 0x0200 #define MYSQL_FLD_TIMESTAMP_FLAG 0x0400 #define MYSQL_FLD_SET_FLAG 0x0800 /* extended capabilities: 4.1+ client only * * These are libmysqlclient flags and NOT present * in the protocol: * CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) * CLIENT_REMEMBER_OPTIONS (1UL << 31) */ #define MYSQL_CAPS_MS 0x0001 /* CLIENT_MULTI_STATMENTS */ #define MYSQL_CAPS_MR 0x0002 /* CLIENT_MULTI_RESULTS */ #define MYSQL_CAPS_PM 0x0004 /* CLIENT_PS_MULTI_RESULTS */ #define MYSQL_CAPS_PA 0x0008 /* CLIENT_PLUGIN_AUTH */ #define MYSQL_CAPS_CA 0x0010 /* CLIENT_CONNECT_ATTRS */ #define MYSQL_CAPS_AL 0x0020 /* CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA */ #define MYSQL_CAPS_EP 0x0040 /* CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS */ #define MYSQL_CAPS_ST 0x0080 /* CLIENT_SESSION_TRACK */ #define MYSQL_CAPS_DE 0x0100 /* CLIENT_DEPRECATE_EOF */ #define MYSQL_CAPS_RM 0x0200 /* CLIENT_OPTIONAL_RESULTSET_METADATA */ #define MYSQL_CAPS_ZS 0x0400 /* CLIENT_ZSTD_COMPRESSION_ALGORITHM */ #define MYSQL_CAPS_QA 0x0800 /* CLIENT_QUERY_ATTRIBUTES */ #define MYSQL_CAPS_MF 0x1000 /* MULTI_FACTOR_AUTHENTICATION */ #define MYSQL_CAPS_CE 0x2000 /* CLIENT_CAPABILITY_EXTENSION */ #define MYSQL_CAPS_UNUSED 0xC000 /* status bitfield */ #define MYSQL_STAT_IT 0x0001 #define MYSQL_STAT_AC 0x0002 #define MYSQL_STAT_MU 0x0004 #define MYSQL_STAT_MR 0x0008 #define MYSQL_STAT_BI 0x0010 #define MYSQL_STAT_NI 0x0020 #define MYSQL_STAT_CR 0x0040 #define MYSQL_STAT_LR 0x0080 #define MYSQL_STAT_DR 0x0100 #define MYSQL_STAT_BS 0x0200 #define MYSQL_STAT_MC 0x0400 #define MYSQL_STAT_QUERY_WAS_SLOW 0x0800 #define MYSQL_STAT_PS_OUT_PARAMS 0x1000 #define MYSQL_STAT_TRANS_READONLY 0x2000 #define MYSQL_STAT_SESSION_STATE_CHANGED 0x4000 /* bitfield for MYSQL_REFRESH */ #define MYSQL_RFSH_GRANT 1 /* Refresh grant tables */ #define MYSQL_RFSH_LOG 2 /* Start on new log file */ #define MYSQL_RFSH_TABLES 4 /* close all tables */ #define MYSQL_RFSH_HOSTS 8 /* Flush host cache */ #define MYSQL_RFSH_STATUS 16 /* Flush status variables */ #define MYSQL_RFSH_THREADS 32 /* Flush thread cache */ #define MYSQL_RFSH_SLAVE 64 /* Reset master info and restart slave thread */ #define MYSQL_RFSH_MASTER 128 /* Remove all bin logs in the index and truncate the index */ /* MySQL command codes (enum_server_command in mysql-server.git:include/my_command.h) */ #define MYSQL_SLEEP 0 /* not from client */ #define MYSQL_QUIT 1 #define MYSQL_INIT_DB 2 #define MYSQL_QUERY 3 #define MYSQL_FIELD_LIST 4 #define MYSQL_CREATE_DB 5 #define MYSQL_DROP_DB 6 #define MYSQL_REFRESH 7 #define MYSQL_SHUTDOWN 8 #define MYSQL_STATISTICS 9 #define MYSQL_PROCESS_INFO 10 #define MYSQL_CONNECT 11 /* not from client */ #define MYSQL_PROCESS_KILL 12 #define MYSQL_DEBUG 13 #define MYSQL_PING 14 #define MYSQL_TIME 15 /* not from client */ #define MYSQL_DELAY_INSERT 16 /* not from client */ #define MYSQL_CHANGE_USER 17 #define MYSQL_BINLOG_DUMP 18 /* replication */ #define MYSQL_TABLE_DUMP 19 /* replication */ #define MYSQL_CONNECT_OUT 20 /* replication */ #define MYSQL_REGISTER_SLAVE 21 /* replication */ #define MYSQL_STMT_PREPARE 22 #define MYSQL_STMT_EXECUTE 23 #define MYSQL_STMT_SEND_LONG_DATA 24 #define MYSQL_STMT_CLOSE 25 #define MYSQL_STMT_RESET 26 #define MYSQL_SET_OPTION 27 #define MYSQL_STMT_FETCH 28 #define MYSQL_DAEMON 29 #define MYSQL_BINLOG_DUMP_GTID 30 /* replication */ #define MYSQL_RESET_CONNECTION 31 #define MYSQL_CLONE 32 #define MYSQL_SUBSCRIBE_GROUP_REPLICATION_STREAM 33 /* MySQL Native Cloning Commands */ #define MYSQL_CLONE_COM_INIT 1 #define MYSQL_CLONE_COM_ATTACH 2 #define MYSQL_CLONE_COM_REINIT 3 #define MYSQL_CLONE_COM_EXECUTE 4 #define MYSQL_CLONE_COM_ACK 5 #define MYSQL_CLONE_COM_EXIT 6 /* decoding table: clone command */ static const value_string mysql_clone_command_vals[] = { {MYSQL_CLONE_COM_INIT, "Init"}, {MYSQL_CLONE_COM_ATTACH, "Attach"}, {MYSQL_CLONE_COM_REINIT, "Re-init"}, {MYSQL_CLONE_COM_EXECUTE, "Execute"}, {MYSQL_CLONE_COM_ACK, "Ack"}, {MYSQL_CLONE_COM_EXIT, "Exit"}, {0, NULL} }; /* MySQL Native Cloning Responses */ #define MYSQL_CLONE_COM_RES_LOCS 1 #define MYSQL_CLONE_COM_RES_DATA_DESC 2 #define MYSQL_CLONE_COM_RES_DATA 3 #define MYSQL_CLONE_COM_RES_PLUGIN 4 #define MYSQL_CLONE_COM_RES_CONFIG 5 #define MYSQL_CLONE_COM_RES_COLLATION 6 #define MYSQL_CLONE_COM_RES_PLUGIN_V2 7 #define MYSQL_CLONE_COM_RES_CONFIG_V3 8 #define MYSQL_CLONE_COM_RES_COMPLETE 99 #define MYSQL_CLONE_COM_RES_ERROR 100 /* decoding table: clone command */ static const value_string mysql_clone_response_vals[] = { {MYSQL_CLONE_COM_RES_LOCS, "Remote Resource Locator"}, {MYSQL_CLONE_COM_RES_DATA_DESC, "Remote Data Descriptor"}, {MYSQL_CLONE_COM_RES_DATA, "Remote Data"}, {MYSQL_CLONE_COM_RES_PLUGIN, "Plugin V1"}, {MYSQL_CLONE_COM_RES_CONFIG, "Config"}, {MYSQL_CLONE_COM_RES_COLLATION, "Collation"}, {MYSQL_CLONE_COM_RES_PLUGIN_V2, "Plugin V2"}, {MYSQL_CLONE_COM_RES_CONFIG_V3, "Plugin V3"}, {MYSQL_CLONE_COM_RES_COMPLETE, "Complete"}, {MYSQL_CLONE_COM_RES_ERROR, "Error"}, {0, NULL} }; /* MariaDB specific commands */ #define MARIADB_STMT_BULK_EXECUTE 250 /* MariaDB bulk execute flags */ #define MARIADB_BULK_AUTOID 64 #define MARIADB_BULK_SEND_TYPES 128 /* MariaDB extended capabilities */ #define MARIADB_CAPS_PR 0x0001 /* MARIADB_CLIENT_PROGRESS */ #define MARIADB_CAPS_CM 0x0002 /* MARIADB_CLIENT_COM_MULTI */ #define MARIADB_CAPS_BO 0x0004 /* MARIADB_CLIENT_STMT_BULK_OPERATIONS */ #define MARIADB_CAPS_EM 0x0008 /* MARIADB_CLIENT_EXTENDED_METADATA */ #define MARIADB_CAPS_ME 0x0010 /* MARIADB_CLIENT_CACHE_METADATA */ /* MariaDB bulk indicators */ #define MARIADB_INDICATOR_NONE 0 #define MARIADB_INDICATOR_NULL 1 #define MARIADB_INDICATOR_DEFAULT 2 #define MARIADB_INDICATOR_IGNORE 3 #define MARIADB_INDICATIR_IGNORE_ROW 4 /* MySQL cursor types */ #define MYSQL_CURSOR_TYPE_NO_CURSOR 0 #define MYSQL_CURSOR_TYPE_READ_ONLY 1 #define MYSQL_CURSOR_TYPE_FOR_UPDATE 2 #define MYSQL_CURSOR_TYPE_SCROLLABLE 4 /* MySQL parameter flags -- used internally by the dissector */ #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 #define MYSQL_COMPRESS_PAYLOAD 3 /* Generic Response Codes */ #define MYSQL_RESPONSE_OK 0x00 #define MYSQL_RESPONSE_ERR 0xFF #define MYSQL_RESPONSE_EOF 0xFE #define MYSQL_RESPONSE_INFILE 0xFB /* mariadb extended keys */ #define MARIADB_EXT_META_TYPE 0 #define MARIADB_EXT_META_FORMAT 1 /* decoding table: command */ static const value_string mysql_command_vals[] = { {MYSQL_SLEEP, "SLEEP"}, {MYSQL_QUIT, "Quit"}, {MYSQL_INIT_DB, "Use Database"}, {MYSQL_QUERY, "Query"}, {MYSQL_FIELD_LIST, "Show Fields"}, {MYSQL_CREATE_DB, "Create Database"}, {MYSQL_DROP_DB , "Drop Database"}, {MYSQL_REFRESH , "Refresh"}, {MYSQL_SHUTDOWN , "Shutdown"}, {MYSQL_STATISTICS , "Statistics"}, {MYSQL_PROCESS_INFO , "Process List"}, {MYSQL_CONNECT , "Connect"}, {MYSQL_PROCESS_KILL , "Kill Server Thread"}, {MYSQL_DEBUG , "Dump Debuginfo"}, {MYSQL_PING , "Ping"}, {MYSQL_TIME , "Time"}, {MYSQL_DELAY_INSERT , "Insert Delayed"}, {MYSQL_CHANGE_USER , "Change User"}, {MYSQL_BINLOG_DUMP , "Send Binlog"}, {MYSQL_TABLE_DUMP, "Send Table"}, {MYSQL_CONNECT_OUT, "Slave Connect"}, {MYSQL_REGISTER_SLAVE, "Register Slave"}, {MYSQL_STMT_PREPARE, "Prepare Statement"}, {MYSQL_STMT_EXECUTE, "Execute Statement"}, {MYSQL_STMT_SEND_LONG_DATA, "Send BLOB"}, {MYSQL_STMT_CLOSE, "Close Statement"}, {MYSQL_STMT_RESET, "Reset Statement"}, {MYSQL_SET_OPTION, "Set Option"}, {MYSQL_STMT_FETCH, "Fetch Data"}, {MYSQL_DAEMON, "Daemon"}, {MYSQL_BINLOG_DUMP_GTID, "Send Binlog GTID"}, {MYSQL_RESET_CONNECTION, "Reset Connection"}, {MYSQL_CLONE, "Native cloning"}, {MYSQL_SUBSCRIBE_GROUP_REPLICATION_STREAM, "Subscribe Group Replication Stream"}, {MARIADB_STMT_BULK_EXECUTE, "Execute Bulk Statement"}, {0, NULL} }; static value_string_ext mysql_command_vals_ext = VALUE_STRING_EXT_INIT(mysql_command_vals); /* decoding table: exec_flags */ static const value_string mysql_exec_flags_vals[] = { {MYSQL_CURSOR_TYPE_NO_CURSOR, "Defaults"}, {MYSQL_CURSOR_TYPE_READ_ONLY, "Read-only cursor"}, {MYSQL_CURSOR_TYPE_FOR_UPDATE, "Cursor for update"}, {MYSQL_CURSOR_TYPE_SCROLLABLE, "Scrollable cursor"}, {0, NULL} }; /* decoding table: new_parameter_bound_flag */ static const value_string mysql_new_parameter_bound_flag_vals[] = { {0, "Subsequent call"}, {1, "First call or rebound"}, {0, NULL} }; /* static const value_string mariadb_bulk_flags_vals[] = { {MARIADB_BULK_AUTOID, "Return auto generated IDs"}, {MARIADB_BULK_SEND_TYPES, "Send types to server"}, {0, NULL} }; */ static const value_string mariadb_bulk_indicator_vals[] = { {MARIADB_INDICATOR_NONE, "Not set"}, {MARIADB_INDICATOR_NULL, "Null Value"}, {MARIADB_INDICATOR_DEFAULT, "Default Value"}, {MARIADB_INDICATOR_IGNORE, "Don't Update Value"}, {MARIADB_INDICATIR_IGNORE_ROW, "Ignore Row"}, {0, NULL} }; /* decoding table: exec_time_sign */ static const value_string mysql_exec_time_sign_vals[] = { {0, "Positive"}, {1, "Negative"}, {0, NULL} }; #if 0 /* charset: pre-4.1 used the term 'charset', later changed to 'collation' */ static const value_string mysql_charset_vals[] = { {1, "big5"}, {2, "czech"}, {3, "dec8"}, {4, "dos" }, {5, "german1"}, {6, "hp8"}, {7, "koi8_ru"}, {8, "latin1"}, {9, "latin2"}, {9, "swe7 "}, {10, "usa7"}, {11, "ujis"}, {12, "sjis"}, {13, "cp1251"}, {14, "danish"}, {15, "hebrew"}, {16, "win1251"}, {17, "tis620"}, {18, "euc_kr"}, {19, "estonia"}, {20, "hungarian"}, {21, "koi8_ukr"}, {22, "win1251ukr"}, {23, "gb2312"}, {24, "greek"}, {25, "win1250"}, {26, "croat"}, {27, "gbk"}, {28, "cp1257"}, {29, "latin5"}, {0, NULL} }; #endif /* collation codes may change over time, recreate with the following SQL SELECT CONCAT(' {', ID, ',"', CHARACTER_SET_NAME, ' COLLATE ', COLLATION_NAME, '"},') FROM INFORMATION_SCHEMA.COLLATIONS ORDER BY ID INTO OUTFILE '/tmp/mysql-collations'; Last Update from MySQL 8.0.20 */ static const value_string mysql_collation_vals[] = { {3, "dec8 COLLATE dec8_swedish_ci"}, {4, "cp850 COLLATE cp850_general_ci"}, {5, "latin1 COLLATE latin1_german1_ci"}, {6, "hp8 COLLATE hp8_english_ci"}, {7, "koi8r COLLATE koi8r_general_ci"}, {8, "latin1 COLLATE latin1_swedish_ci"}, {9, "latin2 COLLATE latin2_general_ci"}, {10, "swe7 COLLATE swe7_swedish_ci"}, {11, "ascii COLLATE ascii_general_ci"}, {14, "cp1251 COLLATE cp1251_bulgarian_ci"}, {15, "latin1 COLLATE latin1_danish_ci"}, {16, "hebrew COLLATE hebrew_general_ci"}, {20, "latin7 COLLATE latin7_estonian_cs"}, {21, "latin2 COLLATE latin2_hungarian_ci"}, {22, "koi8u COLLATE koi8u_general_ci"}, {23, "cp1251 COLLATE cp1251_ukrainian_ci"}, {25, "greek COLLATE greek_general_ci"}, {26, "cp1250 COLLATE cp1250_general_ci"}, {27, "latin2 COLLATE latin2_croatian_ci"}, {29, "cp1257 COLLATE cp1257_lithuanian_ci"}, {30, "latin5 COLLATE latin5_turkish_ci"}, {31, "latin1 COLLATE latin1_german2_ci"}, {32, "armscii8 COLLATE armscii8_general_ci"}, {33, "utf8 COLLATE utf8_general_ci"}, {36, "cp866 COLLATE cp866_general_ci"}, {37, "keybcs2 COLLATE keybcs2_general_ci"}, {38, "macce COLLATE macce_general_ci"}, {39, "macroman COLLATE macroman_general_ci"}, {40, "cp852 COLLATE cp852_general_ci"}, {41, "latin7 COLLATE latin7_general_ci"}, {42, "latin7 COLLATE latin7_general_cs"}, {43, "macce COLLATE macce_bin"}, {44, "cp1250 COLLATE cp1250_croatian_ci"}, {45, "utf8mb4 COLLATE utf8mb4_general_ci"}, {46, "utf8mb4 COLLATE utf8mb4_bin"}, {47, "latin1 COLLATE latin1_bin"}, {48, "latin1 COLLATE latin1_general_ci"}, {49, "latin1 COLLATE latin1_general_cs"}, {50, "cp1251 COLLATE cp1251_bin"}, {51, "cp1251 COLLATE cp1251_general_ci"}, {52, "cp1251 COLLATE cp1251_general_cs"}, {53, "macroman COLLATE macroman_bin"}, {57, "cp1256 COLLATE cp1256_general_ci"}, {58, "cp1257 COLLATE cp1257_bin"}, {59, "cp1257 COLLATE cp1257_general_ci"}, {63, "binary COLLATE binary"}, {64, "armscii8 COLLATE armscii8_bin"}, {65, "ascii COLLATE ascii_bin"}, {66, "cp1250 COLLATE cp1250_bin"}, {67, "cp1256 COLLATE cp1256_bin"}, {68, "cp866 COLLATE cp866_bin"}, {69, "dec8 COLLATE dec8_bin"}, {70, "greek COLLATE greek_bin"}, {71, "hebrew COLLATE hebrew_bin"}, {72, "hp8 COLLATE hp8_bin"}, {73, "keybcs2 COLLATE keybcs2_bin"}, {74, "koi8r COLLATE koi8r_bin"}, {75, "koi8u COLLATE koi8u_bin"}, {77, "latin2 COLLATE latin2_bin"}, {78, "latin5 COLLATE latin5_bin"}, {79, "latin7 COLLATE latin7_bin"}, {80, "cp850 COLLATE cp850_bin"}, {81, "cp852 COLLATE cp852_bin"}, {82, "swe7 COLLATE swe7_bin"}, {83, "utf8 COLLATE utf8_bin"}, {92, "geostd8 COLLATE geostd8_general_ci"}, {93, "geostd8 COLLATE geostd8_bin"}, {94, "latin1 COLLATE latin1_spanish_ci"}, {99, "cp1250 COLLATE cp1250_polish_ci"}, {192, "utf8 COLLATE utf8_unicode_ci"}, {193, "utf8 COLLATE utf8_icelandic_ci"}, {194, "utf8 COLLATE utf8_latvian_ci"}, {195, "utf8 COLLATE utf8_romanian_ci"}, {196, "utf8 COLLATE utf8_slovenian_ci"}, {197, "utf8 COLLATE utf8_polish_ci"}, {198, "utf8 COLLATE utf8_estonian_ci"}, {199, "utf8 COLLATE utf8_spanish_ci"}, {200, "utf8 COLLATE utf8_swedish_ci"}, {201, "utf8 COLLATE utf8_turkish_ci"}, {202, "utf8 COLLATE utf8_czech_ci"}, {203, "utf8 COLLATE utf8_danish_ci"}, {204, "utf8 COLLATE utf8_lithuanian_ci"}, {205, "utf8 COLLATE utf8_slovak_ci"}, {206, "utf8 COLLATE utf8_spanish2_ci"}, {207, "utf8 COLLATE utf8_roman_ci"}, {208, "utf8 COLLATE utf8_persian_ci"}, {209, "utf8 COLLATE utf8_esperanto_ci"}, {210, "utf8 COLLATE utf8_hungarian_ci"}, {211, "utf8 COLLATE utf8_sinhala_ci"}, {212, "utf8 COLLATE utf8_german2_ci"}, {213, "utf8 COLLATE utf8_croatian_ci"}, {214, "utf8 COLLATE utf8_unicode_520_ci"}, {215, "utf8 COLLATE utf8_vietnamese_ci"}, {223, "utf8 COLLATE utf8_general_mysql500_ci"}, {224, "utf8mb4 COLLATE utf8mb4_unicode_ci"}, {225, "utf8mb4 COLLATE utf8mb4_icelandic_ci"}, {226, "utf8mb4 COLLATE utf8mb4_latvian_ci"}, {227, "utf8mb4 COLLATE utf8mb4_romanian_ci"}, {228, "utf8mb4 COLLATE utf8mb4_slovenian_ci"}, {229, "utf8mb4 COLLATE utf8mb4_polish_ci"}, {230, "utf8mb4 COLLATE utf8mb4_estonian_ci"}, {231, "utf8mb4 COLLATE utf8mb4_spanish_ci"}, {232, "utf8mb4 COLLATE utf8mb4_swedish_ci"}, {233, "utf8mb4 COLLATE utf8mb4_turkish_ci"}, {234, "utf8mb4 COLLATE utf8mb4_czech_ci"}, {235, "utf8mb4 COLLATE utf8mb4_danish_ci"}, {236, "utf8mb4 COLLATE utf8mb4_lithuanian_ci"}, {237, "utf8mb4 COLLATE utf8mb4_slovak_ci"}, {238, "utf8mb4 COLLATE utf8mb4_spanish2_ci"}, {239, "utf8mb4 COLLATE utf8mb4_roman_ci"}, {240, "utf8mb4 COLLATE utf8mb4_persian_ci"}, {241, "utf8mb4 COLLATE utf8mb4_esperanto_ci"}, {242, "utf8mb4 COLLATE utf8mb4_hungarian_ci"}, {243, "utf8mb4 COLLATE utf8mb4_sinhala_ci"}, {244, "utf8mb4 COLLATE utf8mb4_german2_ci"}, {245, "utf8mb4 COLLATE utf8mb4_croatian_ci"}, {246, "utf8mb4 COLLATE utf8mb4_unicode_520_ci"}, {247, "utf8mb4 COLLATE utf8mb4_vietnamese_ci"}, {248,"gb18030 COLLATE gb18030_chinese_ci"}, {249,"gb18030 COLLATE gb18030_bin"}, {250,"gb18030 COLLATE gb18030_unicode_520_ci"}, {255,"utf8mb4 COLLATE utf8mb4_0900_ai_ci"}, {256,"utf8mb4 COLLATE utf8mb4_de_pb_0900_ai_ci"}, {257,"utf8mb4 COLLATE utf8mb4_is_0900_ai_ci"}, {258,"utf8mb4 COLLATE utf8mb4_lv_0900_ai_ci"}, {259,"utf8mb4 COLLATE utf8mb4_ro_0900_ai_ci"}, {260,"utf8mb4 COLLATE utf8mb4_sl_0900_ai_ci"}, {261,"utf8mb4 COLLATE utf8mb4_pl_0900_ai_ci"}, {262,"utf8mb4 COLLATE utf8mb4_et_0900_ai_ci"}, {263,"utf8mb4 COLLATE utf8mb4_es_0900_ai_ci"}, {264,"utf8mb4 COLLATE utf8mb4_sv_0900_ai_ci"}, {265,"utf8mb4 COLLATE utf8mb4_tr_0900_ai_ci"}, {266,"utf8mb4 COLLATE utf8mb4_cs_0900_ai_ci"}, {267,"utf8mb4 COLLATE utf8mb4_da_0900_ai_ci"}, {268,"utf8mb4 COLLATE utf8mb4_lt_0900_ai_ci"}, {269,"utf8mb4 COLLATE utf8mb4_sk_0900_ai_ci"}, {270,"utf8mb4 COLLATE utf8mb4_es_trad_0900_ai_ci"}, {271,"utf8mb4 COLLATE utf8mb4_la_0900_ai_ci"}, {273,"utf8mb4 COLLATE utf8mb4_eo_0900_ai_ci"}, {274,"utf8mb4 COLLATE utf8mb4_hu_0900_ai_ci"}, {275,"utf8mb4 COLLATE utf8mb4_hr_0900_ai_ci"}, {277,"utf8mb4 COLLATE utf8mb4_vi_0900_ai_ci"}, {278,"utf8mb4 COLLATE utf8mb4_0900_as_cs"}, {279,"utf8mb4 COLLATE utf8mb4_de_pb_0900_as_cs"}, {280,"utf8mb4 COLLATE utf8mb4_is_0900_as_cs"}, {281,"utf8mb4 COLLATE utf8mb4_lv_0900_as_cs"}, {282,"utf8mb4 COLLATE utf8mb4_ro_0900_as_cs"}, {283,"utf8mb4 COLLATE utf8mb4_sl_0900_as_cs"}, {284,"utf8mb4 COLLATE utf8mb4_pl_0900_as_cs"}, {285,"utf8mb4 COLLATE utf8mb4_et_0900_as_cs"}, {286,"utf8mb4 COLLATE utf8mb4_es_0900_as_cs"}, {287,"utf8mb4 COLLATE utf8mb4_sv_0900_as_cs"}, {288,"utf8mb4 COLLATE utf8mb4_tr_0900_as_cs"}, {289,"utf8mb4 COLLATE utf8mb4_cs_0900_as_cs"}, {290,"utf8mb4 COLLATE utf8mb4_da_0900_as_cs"}, {291,"utf8mb4 COLLATE utf8mb4_lt_0900_as_cs"}, {292,"utf8mb4 COLLATE utf8mb4_sk_0900_as_cs"}, {293,"utf8mb4 COLLATE utf8mb4_es_trad_0900_as_cs"}, {294,"utf8mb4 COLLATE utf8mb4_la_0900_as_cs"}, {296,"utf8mb4 COLLATE utf8mb4_eo_0900_as_cs"}, {297,"utf8mb4 COLLATE utf8mb4_hu_0900_as_cs"}, {298,"utf8mb4 COLLATE utf8mb4_hr_0900_as_cs"}, {300,"utf8mb4 COLLATE utf8mb4_vi_0900_as_cs"}, {303,"utf8mb4 COLLATE utf8mb4_ja_0900_as_cs"}, {304,"utf8mb4 COLLATE utf8mb4_ja_0900_as_cs_ks"}, {305,"utf8mb4 COLLATE utf8mb4_0900_as_ci"}, {306,"utf8mb4 COLLATE utf8mb4_ru_0900_ai_ci"}, {307,"utf8mb4 COLLATE utf8mb4_ru_0900_as_cs"}, {308,"utf8mb4 COLLATE utf8mb4_zh_0900_as_cs"}, {309,"utf8mb4 COLLATE utf8mb4_0900_bin"}, {0, NULL} }; static value_string_ext mysql_collation_vals_ext = VALUE_STRING_EXT_INIT(mysql_collation_vals); /* MariaDB specific character sets and collations Last Update: MariaDB 10.5.4 */ static const value_string mariadb_collation_vals[] = { {1,"big5 COLLATE big5_chinese_ci"}, {2,"latin2 COLLATE latin2_czech_cs"}, {3,"dec8 COLLATE dec8_swedish_ci"}, {4,"cp850 COLLATE cp850_general_ci"}, {5,"latin1 COLLATE latin1_german1_ci"}, {6,"hp8 COLLATE hp8_english_ci"}, {7,"koi8r COLLATE koi8r_general_ci"}, {8,"latin1 COLLATE latin1_swedish_ci"}, {9,"latin2 COLLATE latin2_general_ci"}, {10,"swe7 COLLATE swe7_swedish_ci"}, {11,"ascii COLLATE ascii_general_ci"}, {12,"ujis COLLATE ujis_japanese_ci"}, {13,"sjis COLLATE sjis_japanese_ci"}, {14,"cp1251 COLLATE cp1251_bulgarian_ci"}, {15,"latin1 COLLATE latin1_danish_ci"}, {16,"hebrew COLLATE hebrew_general_ci"}, {18,"tis620 COLLATE tis620_thai_ci"}, {19,"euckr COLLATE euckr_korean_ci"}, {20,"latin7 COLLATE latin7_estonian_cs"}, {21,"latin2 COLLATE latin2_hungarian_ci"}, {22,"koi8u COLLATE koi8u_general_ci"}, {23,"cp1251 COLLATE cp1251_ukrainian_ci"}, {24,"gb2312 COLLATE gb2312_chinese_ci"}, {25,"greek COLLATE greek_general_ci"}, {26,"cp1250 COLLATE cp1250_general_ci"}, {27,"latin2 COLLATE latin2_croatian_ci"}, {28,"gbk COLLATE gbk_chinese_ci"}, {29,"cp1257 COLLATE cp1257_lithuanian_ci"}, {30,"latin5 COLLATE latin5_turkish_ci"}, {31,"latin1 COLLATE latin1_german2_ci"}, {32,"armscii8 COLLATE armscii8_general_ci"}, {33,"utf8 COLLATE utf8_general_ci"}, {34,"cp1250 COLLATE cp1250_czech_cs"}, {35,"ucs2 COLLATE ucs2_general_ci"}, {36,"cp866 COLLATE cp866_general_ci"}, {37,"keybcs2 COLLATE keybcs2_general_ci"}, {38,"macce COLLATE macce_general_ci"}, {39,"macroman COLLATE macroman_general_ci"}, {40,"cp852 COLLATE cp852_general_ci"}, {41,"latin7 COLLATE latin7_general_ci"}, {42,"latin7 COLLATE latin7_general_cs"}, {43,"macce COLLATE macce_bin"}, {44,"cp1250 COLLATE cp1250_croatian_ci"}, {45,"utf8mb4 COLLATE utf8mb4_general_ci"}, {46,"utf8mb4 COLLATE utf8mb4_bin"}, {47,"latin1 COLLATE latin1_bin"}, {48,"latin1 COLLATE latin1_general_ci"}, {49,"latin1 COLLATE latin1_general_cs"}, {50,"cp1251 COLLATE cp1251_bin"}, {51,"cp1251 COLLATE cp1251_general_ci"}, {52,"cp1251 COLLATE cp1251_general_cs"}, {53,"macroman COLLATE macroman_bin"}, {54,"utf16 COLLATE utf16_general_ci"}, {55,"utf16 COLLATE utf16_bin"}, {56,"utf16le COLLATE utf16le_general_ci"}, {57,"cp1256 COLLATE cp1256_general_ci"}, {58,"cp1257 COLLATE cp1257_bin"}, {59,"cp1257 COLLATE cp1257_general_ci"}, {60,"utf32 COLLATE utf32_general_ci"}, {61,"utf32 COLLATE utf32_bin"}, {62,"utf16le COLLATE utf16le_bin"}, {63,"binary COLLATE binary"}, {64,"armscii8 COLLATE armscii8_bin"}, {65,"ascii COLLATE ascii_bin"}, {66,"cp1250 COLLATE cp1250_bin"}, {67,"cp1256 COLLATE cp1256_bin"}, {68,"cp866 COLLATE cp866_bin"}, {69,"dec8 COLLATE dec8_bin"}, {70,"greek COLLATE greek_bin"}, {71,"hebrew COLLATE hebrew_bin"}, {72,"hp8 COLLATE hp8_bin"}, {73,"keybcs2 COLLATE keybcs2_bin"}, {74,"koi8r COLLATE koi8r_bin"}, {75,"koi8u COLLATE koi8u_bin"}, {77,"latin2 COLLATE latin2_bin"}, {78,"latin5 COLLATE latin5_bin"}, {79,"latin7 COLLATE latin7_bin"}, {80,"cp850 COLLATE cp850_bin"}, {81,"cp852 COLLATE cp852_bin"}, {82,"swe7 COLLATE swe7_bin"}, {83,"utf8 COLLATE utf8_bin"}, {84,"big5 COLLATE big5_bin"}, {85,"euckr COLLATE euckr_bin"}, {86,"gb2312 COLLATE gb2312_bin"}, {87,"gbk COLLATE gbk_bin"}, {88,"sjis COLLATE sjis_bin"}, {89,"tis620 COLLATE tis620_bin"}, {90,"ucs2 COLLATE ucs2_bin"}, {91,"ujis COLLATE ujis_bin"}, {92,"geostd8 COLLATE geostd8_general_ci"}, {93,"geostd8 COLLATE geostd8_bin"}, {94,"latin1 COLLATE latin1_spanish_ci"}, {95,"cp932 COLLATE cp932_japanese_ci"}, {96,"cp932 COLLATE cp932_bin"}, {97,"eucjpms COLLATE eucjpms_japanese_ci"}, {98,"eucjpms COLLATE eucjpms_bin"}, {99,"cp1250 COLLATE cp1250_polish_ci"}, {101,"utf16 COLLATE utf16_unicode_ci"}, {102,"utf16 COLLATE utf16_icelandic_ci"}, {103,"utf16 COLLATE utf16_latvian_ci"}, {104,"utf16 COLLATE utf16_romanian_ci"}, {105,"utf16 COLLATE utf16_slovenian_ci"}, {106,"utf16 COLLATE utf16_polish_ci"}, {107,"utf16 COLLATE utf16_estonian_ci"}, {108,"utf16 COLLATE utf16_spanish_ci"}, {109,"utf16 COLLATE utf16_swedish_ci"}, {110,"utf16 COLLATE utf16_turkish_ci"}, {111,"utf16 COLLATE utf16_czech_ci"}, {112,"utf16 COLLATE utf16_danish_ci"}, {113,"utf16 COLLATE utf16_lithuanian_ci"}, {114,"utf16 COLLATE utf16_slovak_ci"}, {115,"utf16 COLLATE utf16_spanish2_ci"}, {116,"utf16 COLLATE utf16_roman_ci"}, {117,"utf16 COLLATE utf16_persian_ci"}, {118,"utf16 COLLATE utf16_esperanto_ci"}, {119,"utf16 COLLATE utf16_hungarian_ci"}, {120,"utf16 COLLATE utf16_sinhala_ci"}, {121,"utf16 COLLATE utf16_german2_ci"}, {122,"utf16 COLLATE utf16_croatian_mysql561_ci"}, {123,"utf16 COLLATE utf16_unicode_520_ci"}, {124,"utf16 COLLATE utf16_vietnamese_ci"}, {128,"ucs2 COLLATE ucs2_unicode_ci"}, {129,"ucs2 COLLATE ucs2_icelandic_ci"}, {130,"ucs2 COLLATE ucs2_latvian_ci"}, {131,"ucs2 COLLATE ucs2_romanian_ci"}, {132,"ucs2 COLLATE ucs2_slovenian_ci"}, {133,"ucs2 COLLATE ucs2_polish_ci"}, {134,"ucs2 COLLATE ucs2_estonian_ci"}, {135,"ucs2 COLLATE ucs2_spanish_ci"}, {136,"ucs2 COLLATE ucs2_swedish_ci"}, {137,"ucs2 COLLATE ucs2_turkish_ci"}, {138,"ucs2 COLLATE ucs2_czech_ci"}, {139,"ucs2 COLLATE ucs2_danish_ci"}, {140,"ucs2 COLLATE ucs2_lithuanian_ci"}, {141,"ucs2 COLLATE ucs2_slovak_ci"}, {142,"ucs2 COLLATE ucs2_spanish2_ci"}, {143,"ucs2 COLLATE ucs2_roman_ci"}, {144,"ucs2 COLLATE ucs2_persian_ci"}, {145,"ucs2 COLLATE ucs2_esperanto_ci"}, {146,"ucs2 COLLATE ucs2_hungarian_ci"}, {147,"ucs2 COLLATE ucs2_sinhala_ci"}, {148,"ucs2 COLLATE ucs2_german2_ci"}, {149,"ucs2 COLLATE ucs2_croatian_mysql561_ci"}, {150,"ucs2 COLLATE ucs2_unicode_520_ci"}, {151,"ucs2 COLLATE ucs2_vietnamese_ci"}, {159,"ucs2 COLLATE ucs2_general_mysql500_ci"}, {160,"utf32 COLLATE utf32_unicode_ci"}, {161,"utf32 COLLATE utf32_icelandic_ci"}, {162,"utf32 COLLATE utf32_latvian_ci"}, {163,"utf32 COLLATE utf32_romanian_ci"}, {164,"utf32 COLLATE utf32_slovenian_ci"}, {165,"utf32 COLLATE utf32_polish_ci"}, {166,"utf32 COLLATE utf32_estonian_ci"}, {167,"utf32 COLLATE utf32_spanish_ci"}, {168,"utf32 COLLATE utf32_swedish_ci"}, {169,"utf32 COLLATE utf32_turkish_ci"}, {170,"utf32 COLLATE utf32_czech_ci"}, {171,"utf32 COLLATE utf32_danish_ci"}, {172,"utf32 COLLATE utf32_lithuanian_ci"}, {173,"utf32 COLLATE utf32_slovak_ci"}, {174,"utf32 COLLATE utf32_spanish2_ci"}, {175,"utf32 COLLATE utf32_roman_ci"}, {176,"utf32 COLLATE utf32_persian_ci"}, {177,"utf32 COLLATE utf32_esperanto_ci"}, {178,"utf32 COLLATE utf32_hungarian_ci"}, {179,"utf32 COLLATE utf32_sinhala_ci"}, {180,"utf32 COLLATE utf32_german2_ci"}, {181,"utf32 COLLATE utf32_croatian_mysql561_ci"}, {182,"utf32 COLLATE utf32_unicode_520_ci"}, {183,"utf32 COLLATE utf32_vietnamese_ci"}, {192,"utf8 COLLATE utf8_unicode_ci"}, {193,"utf8 COLLATE utf8_icelandic_ci"}, {194,"utf8 COLLATE utf8_latvian_ci"}, {195,"utf8 COLLATE utf8_romanian_ci"}, {196,"utf8 COLLATE utf8_slovenian_ci"}, {197,"utf8 COLLATE utf8_polish_ci"}, {198,"utf8 COLLATE utf8_estonian_ci"}, {199,"utf8 COLLATE utf8_spanish_ci"}, {200,"utf8 COLLATE utf8_swedish_ci"}, {201,"utf8 COLLATE utf8_turkish_ci"}, {202,"utf8 COLLATE utf8_czech_ci"}, {203,"utf8 COLLATE utf8_danish_ci"}, {204,"utf8 COLLATE utf8_lithuanian_ci"}, {205,"utf8 COLLATE utf8_slovak_ci"}, {206,"utf8 COLLATE utf8_spanish2_ci"}, {207,"utf8 COLLATE utf8_roman_ci"}, {208,"utf8 COLLATE utf8_persian_ci"}, {209,"utf8 COLLATE utf8_esperanto_ci"}, {210,"utf8 COLLATE utf8_hungarian_ci"}, {211,"utf8 COLLATE utf8_sinhala_ci"}, {212,"utf8 COLLATE utf8_german2_ci"}, {213,"utf8 COLLATE utf8_croatian_mysql561_ci"}, {214,"utf8 COLLATE utf8_unicode_520_ci"}, {215,"utf8 COLLATE utf8_vietnamese_ci"}, {223,"utf8 COLLATE utf8_general_mysql500_ci"}, {224,"utf8mb4 COLLATE utf8mb4_unicode_ci"}, {225,"utf8mb4 COLLATE utf8mb4_icelandic_ci"}, {226,"utf8mb4 COLLATE utf8mb4_latvian_ci"}, {227,"utf8mb4 COLLATE utf8mb4_romanian_ci"}, {228,"utf8mb4 COLLATE utf8mb4_slovenian_ci"}, {229,"utf8mb4 COLLATE utf8mb4_polish_ci"}, {230,"utf8mb4 COLLATE utf8mb4_estonian_ci"}, {231,"utf8mb4 COLLATE utf8mb4_spanish_ci"}, {232,"utf8mb4 COLLATE utf8mb4_swedish_ci"}, {233,"utf8mb4 COLLATE utf8mb4_turkish_ci"}, {234,"utf8mb4 COLLATE utf8mb4_czech_ci"}, {235,"utf8mb4 COLLATE utf8mb4_danish_ci"}, {236,"utf8mb4 COLLATE utf8mb4_lithuanian_ci"}, {237,"utf8mb4 COLLATE utf8mb4_slovak_ci"}, {238,"utf8mb4 COLLATE utf8mb4_spanish2_ci"}, {239,"utf8mb4 COLLATE utf8mb4_roman_ci"}, {240,"utf8mb4 COLLATE utf8mb4_persian_ci"}, {241,"utf8mb4 COLLATE utf8mb4_esperanto_ci"}, {242,"utf8mb4 COLLATE utf8mb4_hungarian_ci"}, {243,"utf8mb4 COLLATE utf8mb4_sinhala_ci"}, {244,"utf8mb4 COLLATE utf8mb4_german2_ci"}, {245,"utf8mb4 COLLATE utf8mb4_croatian_mysql561_ci"}, {246,"utf8mb4 COLLATE utf8mb4_unicode_520_ci"}, {247,"utf8mb4 COLLATE utf8mb4_vietnamese_ci"}, {576,"utf8 COLLATE utf8_croatian_ci"}, {577,"utf8 COLLATE utf8_myanmar_ci"}, {578,"utf8 COLLATE utf8_thai_520_w2"}, {608,"utf8mb4 COLLATE utf8mb4_croatian_ci"}, {609,"utf8mb4 COLLATE utf8mb4_myanmar_ci"}, {610,"utf8mb4 COLLATE utf8mb4_thai_520_w2"}, {640,"ucs2 COLLATE ucs2_croatian_ci"}, {641,"ucs2 COLLATE ucs2_myanmar_ci"}, {642,"ucs2 COLLATE ucs2_thai_520_w2"}, {672,"utf16 COLLATE utf16_croatian_ci"}, {673,"utf16 COLLATE utf16_myanmar_ci"}, {674,"utf16 COLLATE utf16_thai_520_w2"}, {736,"utf32 COLLATE utf32_croatian_ci"}, {737,"utf32 COLLATE utf32_myanmar_ci"}, {738,"utf32 COLLATE utf32_thai_520_w2"}, {1025,"big5 COLLATE big5_chinese_nopad_ci"}, {1027,"dec8 COLLATE dec8_swedish_nopad_ci"}, {1028,"cp850 COLLATE cp850_general_nopad_ci"}, {1030,"hp8 COLLATE hp8_english_nopad_ci"}, {1031,"koi8r COLLATE koi8r_general_nopad_ci"}, {1032,"latin1 COLLATE latin1_swedish_nopad_ci"}, {1033,"latin2 COLLATE latin2_general_nopad_ci"}, {1034,"swe7 COLLATE swe7_swedish_nopad_ci"}, {1035,"ascii COLLATE ascii_general_nopad_ci"}, {1036,"ujis COLLATE ujis_japanese_nopad_ci"}, {1037,"sjis COLLATE sjis_japanese_nopad_ci"}, {1040,"hebrew COLLATE hebrew_general_nopad_ci"}, {1042,"tis620 COLLATE tis620_thai_nopad_ci"}, {1043,"euckr COLLATE euckr_korean_nopad_ci"}, {1046,"koi8u COLLATE koi8u_general_nopad_ci"}, {1048,"gb2312 COLLATE gb2312_chinese_nopad_ci"}, {1049,"greek COLLATE greek_general_nopad_ci"}, {1050,"cp1250 COLLATE cp1250_general_nopad_ci"}, {1052,"gbk COLLATE gbk_chinese_nopad_ci"}, {1054,"latin5 COLLATE latin5_turkish_nopad_ci"}, {1056,"armscii8 COLLATE armscii8_general_nopad_ci"}, {1057,"utf8 COLLATE utf8_general_nopad_ci"}, {1059,"ucs2 COLLATE ucs2_general_nopad_ci"}, {1060,"cp866 COLLATE cp866_general_nopad_ci"}, {1061,"keybcs2 COLLATE keybcs2_general_nopad_ci"}, {1062,"macce COLLATE macce_general_nopad_ci"}, {1063,"macroman COLLATE macroman_general_nopad_ci"}, {1064,"cp852 COLLATE cp852_general_nopad_ci"}, {1065,"latin7 COLLATE latin7_general_nopad_ci"}, {1067,"macce COLLATE macce_nopad_bin"}, {1069,"utf8mb4 COLLATE utf8mb4_general_nopad_ci"}, {1070,"utf8mb4 COLLATE utf8mb4_nopad_bin"}, {1071,"latin1 COLLATE latin1_nopad_bin"}, {1074,"cp1251 COLLATE cp1251_nopad_bin"}, {1075,"cp1251 COLLATE cp1251_general_nopad_ci"}, {1077,"macroman COLLATE macroman_nopad_bin"}, {1078,"utf16 COLLATE utf16_general_nopad_ci"}, {1079,"utf16 COLLATE utf16_nopad_bin"}, {1080,"utf16le COLLATE utf16le_general_nopad_ci"}, {1081,"cp1256 COLLATE cp1256_general_nopad_ci"}, {1082,"cp1257 COLLATE cp1257_nopad_bin"}, {1083,"cp1257 COLLATE cp1257_general_nopad_ci"}, {1084,"utf32 COLLATE utf32_general_nopad_ci"}, {1085,"utf32 COLLATE utf32_nopad_bin"}, {1086,"utf16le COLLATE utf16le_nopad_bin"}, {1088,"armscii8 COLLATE armscii8_nopad_bin"}, {1089,"ascii COLLATE ascii_nopad_bin"}, {1090,"cp1250 COLLATE cp1250_nopad_bin"}, {1091,"cp1256 COLLATE cp1256_nopad_bin"}, {1092,"cp866 COLLATE cp866_nopad_bin"}, {1093,"dec8 COLLATE dec8_nopad_bin"}, {1094,"greek COLLATE greek_nopad_bin"}, {1095,"hebrew COLLATE hebrew_nopad_bin"}, {1096,"hp8 COLLATE hp8_nopad_bin"}, {1097,"keybcs2 COLLATE keybcs2_nopad_bin"}, {1098,"koi8r COLLATE koi8r_nopad_bin"}, {1099,"koi8u COLLATE koi8u_nopad_bin"}, {1101,"latin2 COLLATE latin2_nopad_bin"}, {1102,"latin5 COLLATE latin5_nopad_bin"}, {1103,"latin7 COLLATE latin7_nopad_bin"}, {1104,"cp850 COLLATE cp850_nopad_bin"}, {1105,"cp852 COLLATE cp852_nopad_bin"}, {1106,"swe7 COLLATE swe7_nopad_bin"}, {1107,"utf8 COLLATE utf8_nopad_bin"}, {1108,"big5 COLLATE big5_nopad_bin"}, {1109,"euckr COLLATE euckr_nopad_bin"}, {1110,"gb2312 COLLATE gb2312_nopad_bin"}, {1111,"gbk COLLATE gbk_nopad_bin"}, {1112,"sjis COLLATE sjis_nopad_bin"}, {1113,"tis620 COLLATE tis620_nopad_bin"}, {1114,"ucs2 COLLATE ucs2_nopad_bin"}, {1115,"ujis COLLATE ujis_nopad_bin"}, {1116,"geostd8 COLLATE geostd8_general_nopad_ci"}, {1117,"geostd8 COLLATE geostd8_nopad_bin"}, {1119,"cp932 COLLATE cp932_japanese_nopad_ci"}, {1120,"cp932 COLLATE cp932_nopad_bin"}, {1121,"eucjpms COLLATE eucjpms_japanese_nopad_ci"}, {1122,"eucjpms COLLATE eucjpms_nopad_bin"}, {1125,"utf16 COLLATE utf16_unicode_nopad_ci"}, {1147,"utf16 COLLATE utf16_unicode_520_nopad_ci"}, {1152,"ucs2 COLLATE ucs2_unicode_nopad_ci"}, {1174,"ucs2 COLLATE ucs2_unicode_520_nopad_ci"}, {1184,"utf32 COLLATE utf32_unicode_nopad_ci"}, {1206,"utf32 COLLATE utf32_unicode_520_nopad_ci"}, {1216,"utf8 COLLATE utf8_unicode_nopad_ci"}, {1238,"utf8 COLLATE utf8_unicode_520_nopad_ci"}, {1248,"utf8mb4 COLLATE utf8mb4_unicode_nopad_ci"}, {1270,"utf8mb4 COLLATE utf8mb4_unicode_520_nopad_ci"}, {0, NULL} }; static value_string_ext mariadb_collation_vals_ext = VALUE_STRING_EXT_INIT(mariadb_collation_vals); /* allowed MYSQL_SHUTDOWN levels */ static const value_string mysql_shutdown_vals[] = { {0, "default"}, {1, "wait for connections to finish"}, {2, "wait for transactions to finish"}, {8, "wait for updates to finish"}, {16, "wait flush all buffers"}, {17, "wait flush critical buffers"}, {254, "kill running queries"}, {255, "kill connections"}, {0, NULL} }; /* allowed MYSQL_SET_OPTION values */ static const value_string mysql_option_vals[] = { {0, "multi statements on"}, {1, "multi statements off"}, {0, NULL} }; static const value_string mysql_session_track_type_vals[] = { {0, "SESSION_SYSVARS_TRACKER"}, {1, "CURRENT_SCHEMA_TRACKER"}, {2, "SESSION_STATE_CHANGE_TRACKER"}, {3, "SESSION_TRACK_GTIDS"}, {4, "SESSION_TRACK_TRANSACTION_CHARACTERISTICS"}, {5, "SESSION_TRACK_TRANSACTION_STATE"}, {0, NULL} }; static const value_string mysql_response_code_vals[] = { { MYSQL_RESPONSE_OK, "OK Packet" }, { MYSQL_RESPONSE_ERR, "ERR Packet" }, { MYSQL_RESPONSE_EOF, "EOF Packet" }, { MYSQL_RESPONSE_INFILE, "LOCAL INFILE Packet" }, { 0, NULL } }; /* protocol id */ static int proto_mysql = -1; /* dissector configuration */ static gboolean mysql_desegment = TRUE; static gboolean mysql_showquery = FALSE; /* expand-the-tree flags */ static gint ett_mysql = -1; static gint ett_server_greeting = -1; static gint ett_login_request = -1; static gint ett_caps = -1; static gint ett_extcaps = -1; static gint ett_stat = -1; static gint ett_row_value = -1; static gint ett_request = -1; static gint ett_query_attributes = -1; static gint ett_refresh = -1; static gint ett_field_flags = -1; static gint ett_exec_param = -1; static gint ett_bulk_param = -1; static gint ett_session_track = -1; static gint ett_session_track_data = -1; static gint ett_extmeta = -1; static gint ett_extmeta_data = -1; static gint ett_connattrs = -1; static gint ett_connattrs_attr = -1; static gint ett_mysql_field = -1; static gint ett_binlog_event = -1; static gint ett_binlog_event_hb_v2 = -1; /* protocol fields */ static int hf_mysql_caps_server = -1; static int hf_mysql_caps_client = -1; static int hf_mysql_cap_long_password = -1; static int hf_mysql_cap_found_rows = -1; static int hf_mysql_cap_long_flag = -1; static int hf_mysql_cap_connect_with_db = -1; static int hf_mysql_cap_no_schema = -1; static int hf_mysql_cap_compress = -1; static int hf_mysql_cap_odbc = -1; static int hf_mysql_cap_local_files = -1; static int hf_mysql_cap_ignore_space = -1; static int hf_mysql_cap_change_user = -1; static int hf_mysql_cap_interactive = -1; static int hf_mysql_cap_ssl = -1; static int hf_mysql_cap_ignore_sigpipe = -1; static int hf_mysql_cap_transactions = -1; static int hf_mysql_cap_reserved = -1; static int hf_mysql_cap_secure_connect = -1; static int hf_mysql_extcaps_server = -1; static int hf_mysql_extcaps_client = -1; static int hf_mysql_cap_multi_statements = -1; static int hf_mysql_cap_multi_results = -1; static int hf_mysql_cap_ps_multi_results = -1; static int hf_mysql_cap_plugin_auth = -1; static int hf_mysql_cap_connect_attrs = -1; static int hf_mysql_cap_plugin_auth_lenenc_client_data = -1; static int hf_mysql_cap_client_can_handle_expired_passwords = -1; static int hf_mysql_cap_session_track = -1; static int hf_mysql_cap_deprecate_eof = -1; static int hf_mysql_cap_optional_metadata = -1; static int hf_mysql_cap_compress_zstd = -1; static int hf_mysql_cap_query_attrs = -1; static int hf_mysql_cap_mf_auth = -1; static int hf_mysql_cap_cap_ext = -1; static int hf_mysql_cap_unused = -1; static int hf_mysql_server_language = -1; static int hf_mysql_server_status = -1; static int hf_mysql_stat_it = -1; static int hf_mysql_stat_ac = -1; static int hf_mysql_stat_mr = -1; static int hf_mysql_stat_mu = -1; static int hf_mysql_stat_bi = -1; static int hf_mysql_stat_ni = -1; static int hf_mysql_stat_cr = -1; static int hf_mysql_stat_lr = -1; static int hf_mysql_stat_dr = -1; static int hf_mysql_stat_bs = -1; static int hf_mysql_stat_mc = -1; static int hf_mysql_stat_session_state_changed = -1; static int hf_mysql_stat_query_was_slow = -1; static int hf_mysql_stat_ps_out_params = -1; static int hf_mysql_stat_trans_readonly = -1; static int hf_mysql_refresh = -1; static int hf_mysql_rfsh_grants = -1; static int hf_mysql_rfsh_log = -1; static int hf_mysql_rfsh_tables = -1; static int hf_mysql_rfsh_hosts = -1; static int hf_mysql_rfsh_status = -1; static int hf_mysql_rfsh_threads = -1; static int hf_mysql_rfsh_slave = -1; static int hf_mysql_rfsh_master = -1; static int hf_mysql_packet_length = -1; static int hf_mysql_packet_number = -1; static int hf_mysql_request = -1; static int hf_mysql_command = -1; static int hf_mysql_response_code = -1; static int hf_mysql_error_code = -1; static int hf_mysql_error_string = -1; static int hf_mysql_sqlstate = -1; static int hf_mysql_message = -1; static int hf_mysql_payload = -1; static int hf_mysql_server_greeting = -1; static int hf_mysql_session_track = -1; static int hf_mysql_session_track_type = -1; static int hf_mysql_session_track_length = -1; static int hf_mysql_session_track_data = -1; static int hf_mysql_session_track_data_length = -1; static int hf_mysql_session_track_sysvar_length = -1; static int hf_mysql_session_track_sysvar_name = -1; static int hf_mysql_session_track_sysvar_value = -1; static int hf_mysql_session_track_schema = -1; static int hf_mysql_session_track_schema_length = -1; static int hf_mysql_session_state_change = -1; static int hf_mysql_session_track_gtids = -1; static int hf_mysql_session_track_gtids_encoding = -1; static int hf_mysql_session_track_gtids_length = -1; static int hf_mysql_session_track_transaction_characteristics = -1; static int hf_mysql_session_track_transaction_characteristics_length = -1; static int hf_mysql_session_track_transaction_state = -1; static int hf_mysql_session_track_transaction_state_length = -1; static int hf_mysql_protocol = -1; static int hf_mysql_version = -1; static int hf_mysql_login_request = -1; static int hf_mysql_max_packet = -1; static int hf_mysql_user = -1; static int hf_mysql_table_name = -1; static int hf_mysql_schema = -1; static int hf_mysql_client_auth_plugin = -1; static int hf_mysql_connattrs = -1; static int hf_mysql_connattrs_length = -1; static int hf_mysql_connattrs_attr = -1; static int hf_mysql_connattrs_name_length = -1; static int hf_mysql_connattrs_name = -1; static int hf_mysql_connattrs_value_length = -1; static int hf_mysql_connattrs_value = -1; static int hf_mysql_zstd_compression_level = -1; static int hf_mysql_thread_id = -1; static int hf_mysql_salt = -1; static int hf_mysql_salt2 = -1; static int hf_mysql_auth_plugin_length = -1; static int hf_mysql_auth_plugin = -1; static int hf_mysql_charset = -1; static int hf_mysql_passwd = -1; static int hf_mysql_unused = -1; static int hf_mysql_affected_rows = -1; static int hf_mysql_insert_id = -1; static int hf_mysql_num_warn = -1; static int hf_mysql_stmt_id = -1; static int hf_mysql_query_attributes = -1; static int hf_mysql_query_attributes_count = -1; static int hf_mysql_query_attributes_send_types_to_server = -1; static int hf_mysql_query_attribute_name_type = -1; static int hf_mysql_query_attribute_name = -1; static int hf_mysql_query_attribute_value = -1; static int hf_mysql_query = -1; static int hf_mysql_shutdown = -1; static int hf_mysql_option = -1; static int hf_mysql_num_rows = -1; static int hf_mysql_param = -1; static int hf_mysql_num_params = -1; static int hf_mysql_exec_flags4 = -1; static int hf_mysql_exec_flags5 = -1; static int hf_mysql_exec_iter = -1; static int hf_mysql_binlog_position = -1; static int hf_mysql_binlog_position8 = -1; static int hf_mysql_binlog_flags = -1; static int hf_mysql_binlog_server_id = -1; static int hf_mysql_binlog_file_name = -1; static int hf_mysql_binlog_file_name_length = -1; static int hf_mysql_binlog_slave_hostname_length = -1; static int hf_mysql_binlog_slave_hostname = -1; static int hf_mysql_binlog_slave_user_length = -1; static int hf_mysql_binlog_slave_user = -1; static int hf_mysql_binlog_slave_password_length = -1; static int hf_mysql_binlog_slave_password = -1; static int hf_mysql_binlog_slave_mysql_port = -1; static int hf_mysql_binlog_replication_rank = -1; static int hf_mysql_binlog_master_id = -1; static int hf_mysql_binlog_event_header_timestamp = -1; static int hf_mysql_binlog_event_header_event_type = -1; static int hf_mysql_binlog_event_header_server_id = -1; static int hf_mysql_binlog_event_header_event_size = -1; static int hf_mysql_binlog_event_header_log_position = -1; static int hf_mysql_binlog_event_header_flags = -1; static int hf_mysql_binlog_event_checksum = -1; static int hf_mysql_binlog_event_heartbeat_v2 = -1; static int hf_mysql_binlog_event_heartbeat_v2_otw = -1; static int hf_mysql_binlog_event_heartbeat_v2_otw_type = -1; static int hf_mysql_binlog_gtid_data = -1; static int hf_mysql_binlog_gtid_data_length = -1; static int hf_mysql_binlog_hb_event_filename = -1; static int hf_mysql_binlog_hb_event_log_position = -1; static int hf_mysql_clone_command_code = -1; static int hf_mysql_clone_response_code = -1; static int hf_mysql_eof = -1; static int hf_mysql_num_fields = -1; static int hf_mysql_extra = -1; static int hf_mysql_fld_catalog = -1; static int hf_mysql_fld_db = -1; static int hf_mysql_fld_table = -1; static int hf_mysql_fld_org_table = -1; static int hf_mysql_fld_name = -1; static int hf_mysql_fld_org_name = -1; static int hf_mysql_fld_charsetnr = -1; static int hf_mysql_fld_length = -1; static int hf_mysql_fld_type = -1; static int hf_mysql_fld_flags = -1; static int hf_mysql_fld_not_null = -1; static int hf_mysql_fld_primary_key = -1; static int hf_mysql_fld_unique_key = -1; static int hf_mysql_fld_multiple_key = -1; static int hf_mysql_fld_blob = -1; static int hf_mysql_fld_unsigned = -1; static int hf_mysql_fld_zero_fill = -1; static int hf_mysql_exec_field_null = -1; static int hf_mysql_null_buffer = -1; static int hf_mysql_fld_enum = -1; 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_text = -1; static int hf_mysql_new_parameter_bound_flag = -1; static int hf_mysql_exec_param = -1; static int hf_mysql_exec_unsigned = -1; static int hf_mysql_exec_field_longlong = -1; static int hf_mysql_exec_field_unsigned_longlong = -1; static int hf_mysql_exec_field_string = -1; static int hf_mysql_exec_field_double = -1; static int hf_mysql_exec_field_datetime_length = -1; static int hf_mysql_exec_field_year = -1; static int hf_mysql_exec_field_month = -1; static int hf_mysql_exec_field_day = -1; static int hf_mysql_exec_field_hour = -1; static int hf_mysql_exec_field_minute = -1; static int hf_mysql_exec_field_second = -1; static int hf_mysql_exec_field_second_b = -1; static int hf_mysql_exec_field_long = -1; static int hf_mysql_exec_field_unsigned_long = -1; static int hf_mysql_exec_field_tiny = -1; static int hf_mysql_exec_field_unsigned_tiny = -1; static int hf_mysql_exec_field_short = -1; static int hf_mysql_exec_field_unsigned_short = -1; static int hf_mysql_exec_field_float = -1; static int hf_mysql_exec_field_time_length = -1; static int hf_mysql_exec_field_time_sign = -1; static int hf_mysql_exec_field_time_days = -1; 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_sha2_auth = -1; static int hf_mysql_sha2_response = -1; static int hf_mysql_pubkey = -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 int hf_mysql_loaddata_filename = -1; static int hf_mysql_loaddata_payload = -1; //static int hf_mariadb_fld_charsetnr = -1; static int hf_mariadb_server_language = -1; static int hf_mariadb_charset = -1; static int hf_mariadb_cap_progress = -1; static int hf_mariadb_cap_commulti = -1; static int hf_mariadb_cap_bulk = -1; static int hf_mariadb_cap_extmetadata = -1; static int hf_mariadb_cap_cache_metadata = -1; static int hf_mariadb_extcaps_server = -1; static int hf_mariadb_extcaps_client = -1; static int hf_mariadb_bulk_flag_autoid = -1; static int hf_mariadb_bulk_flag_sendtypes = -1; static int hf_mariadb_bulk_caps_flags = -1; static int hf_mariadb_bulk_paramtypes = -1; static int hf_mariadb_bulk_indicator = -1; static int hf_mariadb_bulk_row_nr = -1; static int hf_mariadb_send_meta = -1; static int hf_mariadb_extmeta = -1; static int hf_mariadb_extmeta_data = -1; static int hf_mariadb_extmeta_length = -1; static int hf_mariadb_extmeta_key = -1; static int hf_mariadb_extmeta_type = -1; static int hf_mariadb_extmeta_format = -1; static dissector_handle_t mysql_handle; static dissector_handle_t tls_handle; static expert_field ei_mysql_dissector_incomplete = EI_INIT; static expert_field ei_mysql_streamed_param = EI_INIT; static expert_field ei_mysql_prepare_response_needed = EI_INIT; static expert_field ei_mysql_unknown_response = EI_INIT; static expert_field ei_mysql_command = EI_INIT; static expert_field ei_mysql_invalid_length = EI_INIT; static expert_field ei_mysql_compression = EI_INIT; /* type constants */ static const value_string type_constants[] = { {0x00, "FIELD_TYPE_DECIMAL" }, {0x01, "FIELD_TYPE_TINY" }, {0x02, "FIELD_TYPE_SHORT" }, {0x03, "FIELD_TYPE_LONG" }, {0x04, "FIELD_TYPE_FLOAT" }, {0x05, "FIELD_TYPE_DOUBLE" }, {0x06, "FIELD_TYPE_NULL" }, {0x07, "FIELD_TYPE_TIMESTAMP" }, {0x08, "FIELD_TYPE_LONGLONG" }, {0x09, "FIELD_TYPE_INT24" }, {0x0a, "FIELD_TYPE_DATE" }, {0x0b, "FIELD_TYPE_TIME" }, {0x0c, "FIELD_TYPE_DATETIME" }, {0x0d, "FIELD_TYPE_YEAR" }, {0x0e, "FIELD_TYPE_NEWDATE" }, {0x0f, "FIELD_TYPE_VARCHAR" }, {0x10, "FIELD_TYPE_BIT" }, {0xf6, "FIELD_TYPE_NEWDECIMAL" }, {0xf7, "FIELD_TYPE_ENUM" }, {0xf8, "FIELD_TYPE_SET" }, {0xf9, "FIELD_TYPE_TINY_BLOB" }, {0xfa, "FIELD_TYPE_MEDIUM_BLOB"}, {0xfb, "FIELD_TYPE_LONG_BLOB" }, {0xfc, "FIELD_TYPE_BLOB" }, {0xfd, "FIELD_TYPE_VAR_STRING" }, {0xfe, "FIELD_TYPE_STRING" }, {0xff, "FIELD_TYPE_GEOMETRY" }, {0, NULL} }; typedef enum mysql_state { UNDEFINED, LOGIN, REQUEST, RESPONSE_OK, RESPONSE_ERROR, RESPONSE_EOF, INTERMEDIATE_EOF, RESPONSE_MESSAGE, RESPONSE_TABULAR, RESPONSE_SHOW_FIELDS, FIELD_PACKET, ROW_PACKET, COLUMN_COUNT, RESPONSE_PREPARE, PREPARED_PARAMETERS, PREPARED_FIELDS, AUTH_SWITCH_REQUEST, AUTH_SWITCH_RESPONSE, AUTH_SHA2, AUTH_PUBKEY, AUTH_SHA2_RESPONSE, BINLOG_DUMP, CLONE_INIT, CLONE_ACTIVE, CLONE_EXIT, RESPONSE_LOCALINFILE, INFILE_DATA } mysql_state_t; static const value_string state_vals[] = { {UNDEFINED, "undefined"}, {LOGIN, "login"}, {REQUEST, "request"}, {RESPONSE_OK, "response OK"}, {RESPONSE_ERROR, "response ERROR"}, {RESPONSE_EOF, "response EOF"}, {INTERMEDIATE_EOF, "intermediate EOF"}, {RESPONSE_MESSAGE, "response message"}, {RESPONSE_TABULAR, "tabular response"}, {RESPONSE_SHOW_FIELDS, "response to SHOW FIELDS"}, {FIELD_PACKET, "field packet"}, {ROW_PACKET, "row packet"}, {COLUMN_COUNT, "column count"}, {RESPONSE_PREPARE, "response to PREPARE"}, {PREPARED_PARAMETERS, "parameters in response to PREPARE"}, {PREPARED_FIELDS, "fields in response to PREPARE"}, {AUTH_SWITCH_REQUEST, "authentication switch request"}, {AUTH_SWITCH_RESPONSE, "authentication switch response"}, {AUTH_SHA2, "caching_sha2_password"}, {AUTH_PUBKEY, "public key request"}, {AUTH_SHA2_RESPONSE, "caching_sha2_password response"}, {BINLOG_DUMP, "binlog event"}, {CLONE_INIT, "cloning initializing"}, {CLONE_ACTIVE, "cloning active"}, {CLONE_EXIT, "cloning shutting down"}, {RESPONSE_LOCALINFILE, "local infile"}, {INFILE_DATA, "local infile data"}, {0, NULL} }; #define MAX_MY_METADATA_COUNT G_MAXINT16 // Arbitrary; is 32k enough? typedef struct { guint16 count; guint16* flags; guint8* types; } my_metadata_list_t; typedef struct mysql_conn_data { guint16 srv_caps; guint16 srv_caps_ext; guint16 clnt_caps; guint16 clnt_caps_ext; mysql_state_t state; guint32 stmt_id; guint16 stmt_num_params; guint16 stmt_num_fields; wmem_tree_t* stmts; #ifdef CTDEBUG guint32 generation; #endif guint8 major_version; guint32 frame_start_ssl; guint32 frame_start_compressed; guint8 compressed_state; gboolean is_mariadb_server; /* set to 1, if connected to a MariaDB server */ gboolean is_mariadb_client; /* set to 1, if connected from a MariaDB client */ guint32 mariadb_server_ext_caps; guint32 mariadb_client_ext_caps; guint64 remaining_field_packet_count; my_metadata_list_t field_metas; } mysql_conn_data_t; struct mysql_frame_data { mysql_state_t state; }; typedef struct my_stmt_data { my_metadata_list_t param_metas; my_metadata_list_t field_metas; guint16 bulk_flags; } my_stmt_data_t; typedef struct mysql_exec_dissector { guint8 type; guint8 unsigned_flag; void (*dissector)(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); } mysql_exec_dissector_t; /* function prototypes */ static int mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree); static int mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *server_status); static int mysql_dissect_caps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_caps, guint16 *caps); static int mysql_dissect_extcaps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_extcaps, guint16 *caps); static int mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_field_packet(tvbuff_t *tvb, proto_item *pi, int offset, proto_tree *tree, packet_info *pinfo, mysql_conn_data_t *conn_data, mysql_state_t current_state); static int mysql_dissect_text_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree); static int mysql_dissect_binary_row_packet(tvbuff_t *tvb, packet_info *pinfo, proto_item *pi, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_binlog_event_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree); static int mysql_dissect_response_prepare(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_auth_switch_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_eof(tvbuff_t *tvb, packet_info *pinfo, proto_item *pi, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_auth_switch_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_auth_sha2(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static int mysql_dissect_loaddata(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data); static void mysql_dissect_exec_string(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_datetime(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_tiny(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_unsigned_tiny(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_short(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_unsigned_short(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_long(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_unsigned_long(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_float(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_double(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_longlong(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_unsigned_longlong(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static void mysql_dissect_exec_null(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static char mysql_dissect_exec_param(proto_item *req_tree, tvbuff_t *tvb, int *offset, int *param_offset, guint8 param_flags, packet_info *pinfo); static char mysql_dissect_binary_row_value(tvbuff_t *tvb, packet_info *pinfo, proto_item *pi, int *offset, proto_item *tree, guint8 field_type, guint16 field_flag); static void mysql_dissect_exec_primitive(tvbuff_t *tvb, int *param_offset, proto_item *field_tree, const int hfindex, const int offset); static void mysql_dissect_exec_time(tvbuff_t *tvb, int *param_offset, proto_item *field_tree); static int mariadb_dissect_caps_or_flags(tvbuff_t *tvb, int offset, enum ftenum type, proto_tree *tree, int mariadb_caps, int * const *fields, void *value); static gint my_tvb_strsize(tvbuff_t *tvb, int offset); static int tvb_get_fle(tvbuff_t *tvb, proto_tree* tree, int offset, guint64 *res, guint8 *is_null); static int mysql_field_add_lestring(tvbuff_t *tvb, int offset, proto_tree *tree, int field); static int dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_); static guint get_mysql_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_); static const mysql_exec_dissector_t mysql_exec_dissectors[] = { { 0x01, 0, mysql_dissect_exec_tiny }, { 0x01, 1, mysql_dissect_exec_unsigned_tiny }, { 0x02, 0, mysql_dissect_exec_short }, { 0x02, 1, mysql_dissect_exec_unsigned_short }, { 0x03, 0, mysql_dissect_exec_long }, { 0x03, 1, mysql_dissect_exec_unsigned_long }, { 0x04, 0, mysql_dissect_exec_float }, { 0x05, 0, mysql_dissect_exec_double }, { 0x06, 0, mysql_dissect_exec_null }, { 0x07, 0, mysql_dissect_exec_datetime }, { 0x08, 0, mysql_dissect_exec_longlong }, { 0x08, 1, mysql_dissect_exec_unsigned_longlong }, { 0x0a, 0, mysql_dissect_exec_datetime }, { 0x0b, 0, mysql_dissect_exec_time }, { 0x0c, 0, mysql_dissect_exec_datetime }, { 0xf6, 0, mysql_dissect_exec_string }, { 0xfc, 0, mysql_dissect_exec_string }, { 0xfd, 0, mysql_dissect_exec_string }, { 0xfe, 0, mysql_dissect_exec_string }, { 0x00, 0, NULL }, }; static int * const mysql_rfsh_flags[] = { &hf_mysql_rfsh_grants, &hf_mysql_rfsh_log, &hf_mysql_rfsh_tables, &hf_mysql_rfsh_hosts, &hf_mysql_rfsh_status, &hf_mysql_rfsh_threads, &hf_mysql_rfsh_slave, &hf_mysql_rfsh_master, NULL }; static int * const mysql_stat_flags[] = { &hf_mysql_stat_it, &hf_mysql_stat_ac, &hf_mysql_stat_mu, &hf_mysql_stat_mr, &hf_mysql_stat_bi, &hf_mysql_stat_ni, &hf_mysql_stat_cr, &hf_mysql_stat_lr, &hf_mysql_stat_dr, &hf_mysql_stat_bs, &hf_mysql_stat_mc, &hf_mysql_stat_query_was_slow, &hf_mysql_stat_ps_out_params, &hf_mysql_stat_trans_readonly, &hf_mysql_stat_session_state_changed, NULL }; static int * const mysql_caps_flags[] = { &hf_mysql_cap_long_password, &hf_mysql_cap_found_rows, &hf_mysql_cap_long_flag, &hf_mysql_cap_connect_with_db, &hf_mysql_cap_no_schema, &hf_mysql_cap_compress, &hf_mysql_cap_odbc, &hf_mysql_cap_local_files, &hf_mysql_cap_ignore_space, &hf_mysql_cap_change_user, &hf_mysql_cap_interactive, &hf_mysql_cap_ssl, &hf_mysql_cap_ignore_sigpipe, &hf_mysql_cap_transactions, &hf_mysql_cap_reserved, &hf_mysql_cap_secure_connect, NULL }; static int * const mysql_extcaps_flags[] = { &hf_mysql_cap_multi_statements, &hf_mysql_cap_multi_results, &hf_mysql_cap_ps_multi_results, &hf_mysql_cap_plugin_auth, &hf_mysql_cap_connect_attrs, &hf_mysql_cap_plugin_auth_lenenc_client_data, &hf_mysql_cap_client_can_handle_expired_passwords, &hf_mysql_cap_session_track, &hf_mysql_cap_deprecate_eof, &hf_mysql_cap_optional_metadata, &hf_mysql_cap_compress_zstd, &hf_mysql_cap_query_attrs, &hf_mysql_cap_mf_auth, &hf_mysql_cap_cap_ext, &hf_mysql_cap_unused, NULL }; static int * const mariadb_extcaps_flags[] = { &hf_mariadb_cap_progress, &hf_mariadb_cap_commulti, &hf_mariadb_cap_bulk, &hf_mariadb_cap_extmetadata, &hf_mariadb_cap_cache_metadata, NULL }; static int * const mariadb_bulk_caps_flags[] = { &hf_mariadb_bulk_flag_autoid, &hf_mariadb_bulk_flag_sendtypes, NULL }; static int * const mysql_fld_flags[] = { &hf_mysql_fld_not_null, &hf_mysql_fld_primary_key, &hf_mysql_fld_unique_key, &hf_mysql_fld_multiple_key, &hf_mysql_fld_blob, &hf_mysql_fld_unsigned, &hf_mysql_fld_zero_fill, &hf_mysql_fld_enum, &hf_mysql_fld_auto_increment, &hf_mysql_fld_timestamp, &hf_mysql_fld_set, NULL }; /* Helper function to only set state on first pass */ static void mysql_set_conn_state(packet_info *pinfo, mysql_conn_data_t *conn_data, mysql_state_t state) { if (!pinfo->fd->visited) { conn_data->state = state; } } static guint64 mysql_get_remaining_field_packet_count(mysql_conn_data_t *conn_data) { return conn_data->remaining_field_packet_count; } static void mysql_dec_remaining_field_packet_count(mysql_conn_data_t *conn_data) { conn_data->remaining_field_packet_count--; } static void mysql_set_remaining_field_packet_count(mysql_conn_data_t *conn_data, guint64 num_fields) { conn_data->remaining_field_packet_count = num_fields; } static int mysql_dissect_greeting(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data) { gint protocol; gint lenstr; int ver_offset; proto_item *tf; proto_item *greeting_tree; char buffer[7]; protocol= tvb_get_guint8(tvb, offset); if (protocol == 0xff) { return mysql_dissect_error_packet(tvb, pinfo, offset+1, tree); } mysql_set_conn_state(pinfo, conn_data, LOGIN); tf = proto_tree_add_item(tree, hf_mysql_server_greeting, tvb, offset, -1, ENC_NA); greeting_tree = proto_item_add_subtree(tf, ett_server_greeting); col_append_fstr(pinfo->cinfo, COL_INFO, " proto=%d", protocol) ; proto_tree_add_item(greeting_tree, hf_mysql_protocol, tvb, offset, 1, ENC_NA); offset += 1; /* version string */ lenstr = tvb_strsize(tvb,offset); /* check if it is a MariaDB Server: MariaDB always sends 5.5.5- before real version number */ tvb_get_raw_bytes_as_string(tvb, offset, buffer, 7); if (lenstr > 6 && strncmp(buffer, MARIADB_RPL_VERSION_HACK, sizeof(MARIADB_RPL_VERSION_HACK) - 1) == 0) { conn_data->is_mariadb_server= 1; col_append_fstr(pinfo->cinfo, COL_INFO, " version=%s ", tvb_format_text(pinfo->pool, tvb, offset + 6, lenstr - 7)); } else { col_append_fstr(pinfo->cinfo, COL_INFO, " version=%s ", tvb_format_text(pinfo->pool, tvb, offset, lenstr-1)); } col_set_fence(pinfo->cinfo, COL_INFO); proto_tree_add_item(greeting_tree, hf_mysql_version, tvb, offset, lenstr, ENC_ASCII); conn_data->major_version = 0; for (ver_offset = 0; ver_offset < lenstr; ver_offset++) { guint8 ver_char = tvb_get_guint8(tvb, offset + ver_offset); if (ver_char == '.') break; conn_data->major_version = conn_data->major_version * 10 + ver_char - '0'; } offset += lenstr; /* 4 bytes little endian thread_id */ proto_tree_add_item(greeting_tree, hf_mysql_thread_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* salt string */ lenstr = tvb_strsize(tvb,offset); proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; /* rest is optional */ if (!tvb_reported_length_remaining(tvb, offset)) return offset; /* 2 bytes CAPS */ offset = mysql_dissect_caps(tvb, offset, greeting_tree, hf_mysql_caps_server, &conn_data->srv_caps); /* MariaDB server don't have the CLIENT_MYSQL/CLIENT_LONG_PASSWORD capability */ if (!(conn_data->srv_caps & MYSQL_CAPS_LP)) { conn_data->is_mariadb_server= 1; } /* rest is optional */ if (!tvb_reported_length_remaining(tvb, offset)) return offset; proto_tree_add_item(greeting_tree, conn_data->is_mariadb_server ? hf_mariadb_server_language : hf_mysql_server_language, tvb, offset, 1, ENC_NA); offset += 1; /* for charset */ offset = mysql_dissect_server_status(tvb, offset, greeting_tree, NULL); /* 2 bytes ExtCAPS */ offset = mysql_dissect_extcaps(tvb, offset, greeting_tree, hf_mysql_extcaps_server, &conn_data->srv_caps_ext); /* 1 byte Auth Plugin Length */ proto_tree_add_item(greeting_tree, hf_mysql_auth_plugin_length, tvb, offset, 1, ENC_NA); offset += 1; if (conn_data->is_mariadb_server) { /* 6 bytes unused */ proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb, offset, 6, ENC_NA); offset += 6; /* MariaDB specific extended capabilities */ offset= mariadb_dissect_caps_or_flags(tvb, offset, FT_UINT32, greeting_tree, hf_mariadb_extcaps_server, mariadb_extcaps_flags, &conn_data->mariadb_server_ext_caps); } else { /* 10 bytes unused */ proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb, offset, 10, ENC_NA); offset += 10; } /* 4.1+ server: rest of salt */ if (tvb_reported_length_remaining(tvb, offset)) { lenstr = tvb_strsize(tvb,offset); proto_tree_add_item(greeting_tree, hf_mysql_salt2, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; } /* 5.x server: auth plugin */ if (tvb_reported_length_remaining(tvb, offset)) { lenstr = tvb_strsize(tvb,offset); proto_tree_add_item(greeting_tree, hf_mysql_auth_plugin, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; } return offset; } /* Add a connect attributes entry to the connattrs subtree return bytes read */ static int add_connattrs_entry_to_tree(tvbuff_t *tvb, packet_info *pinfo _U_, proto_item *tree, int offset) { guint64 lenstr; int orig_offset = offset, lenfle; proto_item *ti; proto_tree *connattrs_tree; const guint8 *str; ti = proto_tree_add_item(tree, hf_mysql_connattrs_attr, tvb, offset, 1, ENC_NA); connattrs_tree = proto_item_add_subtree(ti, ett_connattrs_attr); lenfle = tvb_get_fle(tvb, connattrs_tree, offset, &lenstr, NULL); proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_name_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item_ret_string(connattrs_tree, hf_mysql_connattrs_name, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA, pinfo->pool, &str); proto_item_append_text(ti, " - %s", str); offset += (int)lenstr; lenfle = tvb_get_fle(tvb, connattrs_tree, offset, &lenstr, NULL); proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_value_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item_ret_string(connattrs_tree, hf_mysql_connattrs_value, tvb, offset, (gint)lenstr, ENC_ASCII|ENC_NA, pinfo->pool, &str); proto_item_append_text(ti, ": %s", str); offset += (int)lenstr; proto_item_set_len(ti, offset - orig_offset); return (offset - orig_offset); } static int mysql_dissect_login(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data) { gint lenstr; proto_item *tf; proto_item *login_tree; /* after login there can be OK or DENIED */ if (conn_data->clnt_caps & MYSQL_CAPS_SL) { mysql_set_conn_state(pinfo, conn_data, LOGIN); } else if (!(conn_data->clnt_caps == 0)) { mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); } tf = proto_tree_add_item(tree, hf_mysql_login_request, tvb, offset, -1, ENC_NA); login_tree = proto_item_add_subtree(tf, ett_login_request); offset = mysql_dissect_caps(tvb, offset, login_tree, hf_mysql_caps_client, &conn_data->clnt_caps); /* MariaDB clients don't have the CLIENT_MYSQL/CLIENT_LONG_PASSWORD capability */ if (!(conn_data->clnt_caps & MYSQL_CAPS_LP)) { conn_data->is_mariadb_client= 1; } if (!(conn_data->frame_start_ssl) && conn_data->clnt_caps & MYSQL_CAPS_SL) /* Next packet will be use SSL */ { col_set_str(pinfo->cinfo, COL_INFO, "Response: SSL Handshake"); conn_data->frame_start_ssl = pinfo->num; ssl_starttls_ack(tls_handle, pinfo, mysql_handle); } if (conn_data->clnt_caps & MYSQL_CAPS_CU) /* 4.1 protocol */{ offset = mysql_dissect_extcaps(tvb, offset, login_tree, hf_mysql_extcaps_client, &conn_data->clnt_caps_ext); proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(login_tree, conn_data->is_mariadb_server ? hf_mariadb_charset : hf_mysql_charset, tvb, offset, 1, ENC_NA); offset += 1; /* for charset */ if (conn_data->is_mariadb_client){ /* 19 bytes unused */ proto_tree_add_item(login_tree, hf_mysql_unused, tvb, offset, 19, ENC_NA); offset += 19; offset= mariadb_dissect_caps_or_flags(tvb, offset, FT_UINT32, login_tree, hf_mariadb_extcaps_client, mariadb_extcaps_flags, &conn_data->mariadb_client_ext_caps); } else { /* 23 bytes unused */ proto_tree_add_item(login_tree, hf_mysql_unused, tvb, offset, 23, ENC_NA); offset += 23; } } else { /* pre-4.1 */ proto_tree_add_item(login_tree, hf_mysql_max_packet, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; } /* User name */ lenstr = my_tvb_strsize(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, " user=%s ", tvb_format_text(pinfo->pool, tvb, offset, lenstr-1)); proto_tree_add_item(login_tree, hf_mysql_user, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; /* rest is optional */ if (!tvb_reported_length_remaining(tvb, offset)) { col_set_fence(pinfo->cinfo, COL_INFO); return offset; } /* password: asciiz or length+ascii */ if (conn_data->clnt_caps & MYSQL_CAPS_SC) { lenstr = tvb_get_guint8(tvb, offset); offset += 1; } else { lenstr = my_tvb_strsize(tvb, offset); } if (tree && lenstr > 1) { proto_tree_add_item(login_tree, hf_mysql_passwd, tvb, offset, lenstr, ENC_NA); } offset += lenstr; /* optional: initial schema */ if (conn_data->clnt_caps & MYSQL_CAPS_CD) { lenstr= my_tvb_strsize(tvb,offset); if(lenstr<0){ return offset; } col_append_fstr(pinfo->cinfo, COL_INFO, "db=%s ", tvb_format_text(pinfo->pool, tvb, offset, lenstr-1)); col_set_fence(pinfo->cinfo, COL_INFO); proto_tree_add_item(login_tree, hf_mysql_schema, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; } /* optional: authentication plugin */ if (conn_data->clnt_caps_ext & MYSQL_CAPS_PA) { mysql_set_conn_state(pinfo, conn_data, AUTH_SWITCH_REQUEST); lenstr= my_tvb_strsize(tvb,offset); proto_tree_add_item(login_tree, hf_mysql_client_auth_plugin, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; } /* optional: connection attributes */ if (conn_data->clnt_caps_ext & MYSQL_CAPS_CA && tvb_reported_length_remaining(tvb, offset)) { proto_tree *connattrs_tree; int lenfle; guint64 connattrs_length; int length; lenfle = tvb_get_fle(tvb, login_tree, offset, &connattrs_length, NULL); tf = proto_tree_add_item(login_tree, hf_mysql_connattrs, tvb, offset, (guint32)connattrs_length, ENC_NA); connattrs_tree = proto_item_add_subtree(tf, ett_connattrs); proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_length, tvb, offset, lenfle, connattrs_length); offset += lenfle; while (connattrs_length > 0) { length = add_connattrs_entry_to_tree(tvb, pinfo, connattrs_tree, offset); offset += length; connattrs_length -= length; } } if (conn_data->clnt_caps_ext & MYSQL_CAPS_ZS) { proto_tree_add_item(login_tree, hf_mysql_zstd_compression_level, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; } return offset; } static void mysql_dissect_exec_string(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { guint32 param_len32; guint8 param_len; param_len = tvb_get_guint8(tvb, *param_offset); switch (param_len) { case 0xfc: /* 252 - 64k chars */ *param_offset += 1; param_len32 = tvb_get_letohs(tvb, *param_offset); proto_tree_add_item(field_tree, hf_mysql_exec_field_string, tvb, *param_offset, 2, ENC_ASCII | ENC_LITTLE_ENDIAN); *param_offset += param_len32 + 2; break; case 0xfd: /* 64k - 16M chars */ *param_offset += 1; param_len32 = tvb_get_letoh24(tvb, *param_offset); proto_tree_add_item(field_tree, hf_mysql_exec_field_string, tvb, *param_offset, 3, ENC_ASCII | ENC_LITTLE_ENDIAN); *param_offset += param_len32 + 3; break; default: /* < 252 chars */ proto_tree_add_item(field_tree, hf_mysql_exec_field_string, tvb, *param_offset, 1, ENC_ASCII | ENC_NA); *param_offset += param_len + 1; break; } } static void mysql_dissect_exec_time(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { guint8 param_len; param_len = tvb_get_guint8(tvb, *param_offset); proto_tree_add_item(field_tree, hf_mysql_exec_field_time_length, tvb, *param_offset, 1, ENC_NA); *param_offset += 1; if (param_len >= 1) { proto_tree_add_item(field_tree, hf_mysql_exec_field_time_sign, tvb, *param_offset, 1, ENC_NA); } if (param_len >= 5) { proto_tree_add_item(field_tree, hf_mysql_exec_field_time_days, tvb, *param_offset + 1, 4, ENC_LITTLE_ENDIAN); } if (param_len >= 8) { proto_tree_add_item(field_tree, hf_mysql_exec_field_hour, tvb, *param_offset + 5, 1, ENC_NA); proto_tree_add_item(field_tree, hf_mysql_exec_field_minute, tvb, *param_offset + 6, 1, ENC_NA); proto_tree_add_item(field_tree, hf_mysql_exec_field_second, tvb, *param_offset + 7, 1, ENC_NA); } if (param_len >= 12) { proto_tree_add_item(field_tree, hf_mysql_exec_field_second_b, tvb, *param_offset + 8, 4, ENC_LITTLE_ENDIAN); } *param_offset += param_len; } static void mysql_dissect_exec_datetime(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { guint8 param_len; param_len = tvb_get_guint8(tvb, *param_offset); proto_tree_add_item(field_tree, hf_mysql_exec_field_datetime_length, tvb, *param_offset, 1, ENC_NA); *param_offset += 1; if (param_len >= 2) { proto_tree_add_item(field_tree, hf_mysql_exec_field_year, tvb, *param_offset, 2, ENC_LITTLE_ENDIAN); } if (param_len >= 4) { proto_tree_add_item(field_tree, hf_mysql_exec_field_month, tvb, *param_offset + 2, 1, ENC_NA); proto_tree_add_item(field_tree, hf_mysql_exec_field_day, tvb, *param_offset + 3, 1, ENC_NA); } if (param_len >= 7) { proto_tree_add_item(field_tree, hf_mysql_exec_field_hour, tvb, *param_offset + 4, 1, ENC_NA); proto_tree_add_item(field_tree, hf_mysql_exec_field_minute, tvb, *param_offset + 5, 1, ENC_NA); proto_tree_add_item(field_tree, hf_mysql_exec_field_second, tvb, *param_offset + 6, 1, ENC_NA); } if (param_len >= 11) { proto_tree_add_item(field_tree, hf_mysql_exec_field_second_b, tvb, *param_offset + 7, 4, ENC_LITTLE_ENDIAN); } *param_offset += param_len; } static void mysql_dissect_exec_primitive(tvbuff_t *tvb, int *param_offset, proto_item *field_tree, const int hfindex, const int offset) { proto_tree_add_item(field_tree, hfindex, tvb, *param_offset, offset, ENC_LITTLE_ENDIAN); *param_offset += offset; } static void mysql_dissect_exec_tiny(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_tiny, 1); } static void mysql_dissect_exec_unsigned_tiny(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_unsigned_tiny, 1); } static void mysql_dissect_exec_short(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_short, 2); } static void mysql_dissect_exec_unsigned_short(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_unsigned_short, 2); } static void mysql_dissect_exec_long(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_long, 4); } static void mysql_dissect_exec_unsigned_long(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_unsigned_long, 4); } static void mysql_dissect_exec_float(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_float, 4); } static void mysql_dissect_exec_double(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_double, 8); } static void mysql_dissect_exec_longlong(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_longlong, 8); } static void mysql_dissect_exec_unsigned_longlong(tvbuff_t *tvb, int *param_offset, proto_item *field_tree) { mysql_dissect_exec_primitive(tvb, param_offset, field_tree, hf_mysql_exec_field_unsigned_longlong, 8); } static void mysql_dissect_exec_null(tvbuff_t *tvb _U_, int *param_offset _U_, proto_item *field_tree _U_) {} static char mysql_dissect_exec_param(proto_item *req_tree, tvbuff_t *tvb, int *offset, int *param_offset, guint8 param_flags, packet_info *pinfo) { guint8 param_type, param_unsigned; proto_item *tf; proto_item *field_tree; int dissector_index = 0; tf = proto_tree_add_item(req_tree, hf_mysql_exec_param, tvb, *offset, 2, ENC_NA); field_tree = proto_item_add_subtree(tf, ett_stat); proto_tree_add_item(field_tree, hf_mysql_fld_type, tvb, *offset, 1, ENC_NA); param_type = tvb_get_guint8(tvb, *offset); *offset += 1; /* type */ proto_tree_add_item(field_tree, hf_mysql_exec_unsigned, tvb, *offset, 1, ENC_NA); if ((tvb_get_guint8(tvb, *offset) & 128) == 128) { param_unsigned = 1; } else { param_unsigned = 0; } *offset += 1; /* signedness */ if ((param_flags & MYSQL_PARAM_FLAG_STREAMED) == MYSQL_PARAM_FLAG_STREAMED) { expert_add_info(pinfo, field_tree, &ei_mysql_streamed_param); return 1; } while (mysql_exec_dissectors[dissector_index].dissector != NULL) { if (mysql_exec_dissectors[dissector_index].type == param_type && mysql_exec_dissectors[dissector_index].unsigned_flag == param_unsigned) { mysql_exec_dissectors[dissector_index].dissector(tvb, param_offset, field_tree); return 1; } dissector_index++; } return 0; } static int mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data, mysql_state_t current_state) { gint opcode; gint lenstr; proto_item *request_item, *tf = NULL, *ti; proto_item *req_tree; guint32 stmt_id; my_stmt_data_t *stmt_data; int stmt_pos, param_offset; /* LOCAL INFILE Request sends an empty packet after sending the file content * https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_local_infile_request.html */ if (tvb_reported_length_remaining(tvb, offset) == 0) return offset; switch(current_state) { case AUTH_SWITCH_RESPONSE: return mysql_dissect_auth_switch_response(tvb, pinfo, offset, tree, conn_data); case AUTH_SHA2: return mysql_dissect_auth_sha2(tvb, pinfo, offset, tree, conn_data); case INFILE_DATA: return mysql_dissect_loaddata(tvb, pinfo, offset, tree, conn_data); default:; } request_item = proto_tree_add_item(tree, hf_mysql_request, tvb, offset, -1, ENC_NA); req_tree = proto_item_add_subtree(request_item, ett_request); opcode = tvb_get_guint8(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str_ext(opcode, &mysql_command_vals_ext, "Unknown (%u) ")); proto_tree_add_item(req_tree, hf_mysql_command, tvb, offset, 1, ENC_NA); proto_item_append_text(request_item, " %s", val_to_str_ext(opcode, &mysql_command_vals_ext, "Unknown (%u)")); offset += 1; switch (opcode) { case MYSQL_QUIT: break; case MYSQL_PROCESS_INFO: mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR); break; case MYSQL_DEBUG: case MYSQL_PING: mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); break; case MYSQL_STATISTICS: mysql_set_conn_state(pinfo, conn_data, RESPONSE_MESSAGE); break; case MYSQL_INIT_DB: case MYSQL_CREATE_DB: case MYSQL_DROP_DB: lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); break; case MYSQL_QUERY: /* Check both the extended capabilities of the client and server. The flag is set by the client * even if the server didn't set it. This is only actively used if both set the flag. */ if ((conn_data->clnt_caps_ext & MYSQL_CAPS_QA) && (conn_data->srv_caps_ext & MYSQL_CAPS_QA)){ proto_item *query_attrs_item = proto_tree_add_item(req_tree, hf_mysql_query_attributes, tvb, offset, -1, ENC_NA); proto_item *query_attrs_tree = proto_item_add_subtree(query_attrs_item, ett_query_attributes); gint n_params = tvb_get_guint8(tvb, offset); proto_tree_add_item(query_attrs_tree, hf_mysql_query_attributes_count, tvb, offset, 1, ENC_ASCII); offset += 2; if (n_params > 0) { gint null_count = (n_params + 7) / 8; proto_tree_add_item(query_attrs_tree, hf_mysql_unused, tvb, offset, null_count, ENC_ASCII); offset += null_count; proto_tree_add_item(query_attrs_tree, hf_mysql_query_attributes_send_types_to_server, tvb, offset, 1, ENC_ASCII); offset += 1; for (int i = 0; i < n_params; ++i) { proto_tree_add_item(query_attrs_tree, hf_mysql_query_attribute_name_type, tvb, offset, 2, ENC_ASCII); offset += 2; offset = mysql_field_add_lestring(tvb, offset, query_attrs_tree, hf_mysql_query_attribute_name); } for (int i = 0; i < n_params; ++i) { offset = mysql_field_add_lestring(tvb, offset, query_attrs_tree, hf_mysql_query_attribute_value); } } } else if ((conn_data->clnt_caps_ext == 0) && (conn_data->srv_caps_ext == 0)){ // No server/client capabilities, probably in the middle of a conversation // As the query isn't likely to start with 0x00 this probably means these are // query attributes we need to skip if (tvb_get_guint8(tvb, offset) == 0) offset += 2; } lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, lenstr, ENC_ASCII); if (mysql_showquery) { col_append_fstr(pinfo->cinfo, COL_INFO, " { %s } ", tvb_format_text(pinfo->pool, tvb, offset, lenstr)); col_set_fence(pinfo->cinfo, COL_INFO); } offset += lenstr; mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR); break; case MYSQL_STMT_PREPARE: lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_query, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; mysql_set_conn_state(pinfo, conn_data, RESPONSE_PREPARE); break; case MYSQL_STMT_CLOSE: proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; mysql_set_conn_state(pinfo, conn_data, REQUEST); break; case MYSQL_STMT_RESET: proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); break; case MYSQL_FIELD_LIST: lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_table_name, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; mysql_set_conn_state(pinfo, conn_data, RESPONSE_SHOW_FIELDS); break; case MYSQL_PROCESS_KILL: proto_tree_add_item(req_tree, hf_mysql_thread_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); break; case MYSQL_CHANGE_USER: lenstr = tvb_strsize(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_user, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; if (conn_data->clnt_caps & MYSQL_CAPS_SC) { lenstr = tvb_get_guint8(tvb, offset); offset += 1; } else { lenstr = tvb_strsize(tvb, offset); } proto_tree_add_item(req_tree, hf_mysql_passwd, tvb, offset, lenstr, ENC_NA); offset += lenstr; lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_schema, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; if (tvb_reported_length_remaining(tvb, offset) > 0) { proto_tree_add_item(req_tree, conn_data->is_mariadb_server ? hf_mariadb_charset : hf_mysql_charset, tvb, offset, 1, ENC_NA); offset += 2; /* for charset */ } mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); /* optional: authentication plugin */ if (conn_data->clnt_caps_ext & MYSQL_CAPS_PA) { mysql_set_conn_state(pinfo, conn_data, AUTH_SWITCH_REQUEST); lenstr= my_tvb_strsize(tvb,offset); proto_tree_add_item(req_tree, hf_mysql_client_auth_plugin, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; } /* optional: connection attributes */ if (conn_data->clnt_caps_ext & MYSQL_CAPS_CA) { proto_tree *connattrs_tree; int lenfle; guint64 connattrs_length; int length; lenfle = tvb_get_fle(tvb, req_tree, offset, &connattrs_length, NULL); tf = proto_tree_add_item(req_tree, hf_mysql_connattrs, tvb, offset, (guint32)connattrs_length, ENC_NA); connattrs_tree = proto_item_add_subtree(tf, ett_connattrs); proto_tree_add_uint64(connattrs_tree, hf_mysql_connattrs_length, tvb, offset, lenfle, connattrs_length); offset += lenfle; while (connattrs_length > 0) { length = add_connattrs_entry_to_tree(tvb, pinfo, connattrs_tree, offset); offset += length; connattrs_length -= length; } } break; case MYSQL_REFRESH: proto_tree_add_bitmask_with_flags(req_tree, tvb, offset, hf_mysql_refresh, ett_refresh, mysql_rfsh_flags, ENC_BIG_ENDIAN, BMT_NO_APPEND); offset += 1; mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); break; case MYSQL_SHUTDOWN: proto_tree_add_item(req_tree, hf_mysql_shutdown, tvb, offset, 1, ENC_NA); offset += 1; mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); break; case MYSQL_SET_OPTION: proto_tree_add_item(req_tree, hf_mysql_option, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; mysql_set_conn_state(pinfo, conn_data, RESPONSE_OK); break; case MYSQL_STMT_FETCH: proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(req_tree, hf_mysql_num_rows, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR); break; case MYSQL_STMT_SEND_LONG_DATA: proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); stmt_id = tvb_get_letohl(tvb, offset); offset += 4; stmt_data = (my_stmt_data_t *)wmem_tree_lookup32(conn_data->stmts, stmt_id); if (stmt_data != NULL) { guint16 data_param = tvb_get_letohs(tvb, offset); if (stmt_data->param_metas.count > data_param) { stmt_data->param_metas.flags[data_param] |= MYSQL_PARAM_FLAG_STREAMED; } } proto_tree_add_item(req_tree, hf_mysql_param, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* rest is data */ lenstr = tvb_reported_length_remaining(tvb, offset); if (tree && lenstr > 0) { proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, lenstr, ENC_NA); } offset += lenstr; if (conn_data->state != RESPONSE_PREPARE) { // if pipelinning, keeping PREPARE state mysql_set_conn_state(pinfo, conn_data, REQUEST); } break; case MARIADB_STMT_BULK_EXECUTE: proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); stmt_id = tvb_get_letohl(tvb, offset); offset += 4; // use last prepared statement if (stmt_id == 0xffffffff) { stmt_id = conn_data->stmt_id; } stmt_data = (my_stmt_data_t *)wmem_tree_lookup32(conn_data->stmts, stmt_id); if (stmt_data != NULL) { guint32 row_nr = 1; proto_item *param_tree; mariadb_dissect_caps_or_flags(tvb, offset, FT_UINT16, req_tree, hf_mariadb_bulk_caps_flags, mariadb_bulk_caps_flags, &stmt_data->bulk_flags); offset += 2; if ((stmt_data->bulk_flags & MARIADB_BULK_SEND_TYPES) && stmt_data->param_metas.count) { tf = proto_tree_add_item(req_tree, hf_mariadb_bulk_paramtypes, tvb, offset, -1, ENC_NA); param_tree = proto_item_add_subtree(tf, ett_exec_param); for (stmt_pos = 0; stmt_pos < stmt_data->param_metas.count; stmt_pos++) { stmt_data->param_metas.types[stmt_pos] = tvb_get_guint8(tvb, offset); proto_tree_add_item(param_tree, hf_mysql_fld_type, tvb, offset, 1, ENC_NA); offset+= 1; stmt_data->param_metas.flags[stmt_pos] = tvb_get_guint8(tvb, offset); proto_tree_add_item(param_tree, hf_mysql_exec_unsigned, tvb, offset, 1, ENC_NA); offset+= 1; } } while (tvb_reported_length_remaining(tvb, offset) > 0){ tf = proto_tree_add_uint_format(req_tree, hf_mariadb_bulk_row_nr, tvb, offset, 0, row_nr, "%d. Dataset", row_nr); proto_item_set_generated(tf); param_tree = proto_item_add_subtree(tf, ett_bulk_param); for (stmt_pos = 0; stmt_pos < stmt_data->param_metas.count; stmt_pos++) { guint8 indicator= tvb_get_guint8(tvb, offset); proto_tree_add_item(param_tree, hf_mariadb_bulk_indicator, tvb, offset, 1, ENC_NA); offset++; /* If no indicator was specified, data will follow */ if (!indicator) { int dissector_index= 0; while (mysql_exec_dissectors[dissector_index].dissector != NULL) { if (mysql_exec_dissectors[dissector_index].type == stmt_data->param_metas.types[stmt_pos]) /* && mysql_exec_dissectors[dissector_index].unsigned_flag == stmt_data->param_flags[stmt_pos]) */ { mysql_exec_dissectors[dissector_index].dissector(tvb, &offset, param_tree); break; } dissector_index++; } } } row_nr++; } } if (conn_data->state != RESPONSE_PREPARE) { // if pipelinning, keeping PREPARE state mysql_set_conn_state(pinfo, conn_data, REQUEST); } break; case MYSQL_STMT_EXECUTE: proto_tree_add_item(req_tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); stmt_id = tvb_get_letohl(tvb, offset); offset += 4; if (conn_data->major_version >= 5) { proto_tree_add_item(req_tree, hf_mysql_exec_flags5, tvb, offset, 1, ENC_NA); } else { proto_tree_add_item(req_tree, hf_mysql_exec_flags4, tvb, offset, 1, ENC_NA); } offset += 1; proto_tree_add_item(req_tree, hf_mysql_exec_iter, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; // use last prepared statement if (stmt_id == 0xffffffff) { stmt_id = conn_data->stmt_id; } stmt_data = (my_stmt_data_t *)wmem_tree_lookup32(conn_data->stmts, stmt_id); if (stmt_data != NULL) { if (stmt_data->param_metas.count != 0) { guint8 stmt_bound; offset += (stmt_data->param_metas.count + 7) / 8; /* NULL bitmap */ proto_tree_add_item(req_tree, hf_mysql_new_parameter_bound_flag, tvb, offset, 1, ENC_NA); stmt_bound = tvb_get_guint8(tvb, offset); offset += 1; if (stmt_bound == 1) { param_offset = offset + stmt_data->param_metas.count * 2; guint8 flags; for (stmt_pos = 0; stmt_pos < stmt_data->param_metas.count; stmt_pos++) { flags = (guint8)stmt_data->param_metas.flags[stmt_pos]; if (!mysql_dissect_exec_param(req_tree, tvb, &offset, ¶m_offset, flags, pinfo)) break; } offset = param_offset; } } } else { lenstr = tvb_reported_length_remaining(tvb, offset); if (tree && lenstr > 0) { ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, lenstr, ENC_NA); expert_add_info(pinfo, ti, &ei_mysql_prepare_response_needed); } offset += lenstr; } if (conn_data->state != RESPONSE_PREPARE) { // if pipelinning, keeping PREPARE state mysql_set_conn_state(pinfo, conn_data, RESPONSE_TABULAR); } break; case MYSQL_BINLOG_DUMP_GTID: // See mysql_binlog_open() in "sql-common/client.cc" proto_tree_add_item(req_tree, hf_mysql_binlog_flags, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(req_tree, hf_mysql_binlog_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; lenstr = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN); proto_tree_add_item(req_tree, hf_mysql_binlog_file_name_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(req_tree, hf_mysql_binlog_position8, tvb, offset, 8, ENC_LITTLE_ENDIAN); offset += 8; if (tree && lenstr > 0) { proto_tree_add_item(req_tree, hf_mysql_binlog_file_name, tvb, offset, lenstr, ENC_ASCII); } offset += lenstr; lenstr = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN); proto_tree_add_item(req_tree, hf_mysql_binlog_gtid_data_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(req_tree, hf_mysql_binlog_gtid_data, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; mysql_set_conn_state(pinfo, conn_data, BINLOG_DUMP); break; case MYSQL_BINLOG_DUMP: proto_tree_add_item(req_tree, hf_mysql_binlog_position, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(req_tree, hf_mysql_binlog_flags, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(req_tree, hf_mysql_binlog_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* binlog file name ? */ lenstr = tvb_reported_length_remaining(tvb, offset); if (tree && lenstr > 0) { proto_tree_add_item(req_tree, hf_mysql_binlog_file_name, tvb, offset, lenstr, ENC_ASCII); } offset += lenstr; mysql_set_conn_state(pinfo, conn_data, BINLOG_DUMP); break; case MYSQL_REGISTER_SLAVE: proto_tree_add_item(req_tree, hf_mysql_binlog_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; lenstr = tvb_get_guint8(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_binlog_slave_hostname_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(req_tree, hf_mysql_binlog_slave_hostname, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; lenstr = tvb_get_guint8(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_binlog_slave_user_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(req_tree, hf_mysql_binlog_slave_user, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; lenstr = tvb_get_guint8(tvb, offset); proto_tree_add_item(req_tree, hf_mysql_binlog_slave_password_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(req_tree, hf_mysql_binlog_slave_password, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; proto_tree_add_item(req_tree, hf_mysql_binlog_slave_mysql_port, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(req_tree, hf_mysql_binlog_replication_rank, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(req_tree, hf_mysql_binlog_master_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; mysql_set_conn_state(pinfo, conn_data, REQUEST); break; /* FIXME: implement replication packets */ case MYSQL_TABLE_DUMP: case MYSQL_CONNECT_OUT: ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA); expert_add_info_format(pinfo, ti, &ei_mysql_dissector_incomplete, "FIXME: implement replication packets"); offset += tvb_reported_length_remaining(tvb, offset); mysql_set_conn_state(pinfo, conn_data, REQUEST); break; case MYSQL_CLONE: mysql_set_conn_state(pinfo, conn_data, CLONE_INIT); break; case MYSQL_RESET_CONNECTION: break; default: ti = proto_tree_add_item(req_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA); expert_add_info(pinfo, ti, &ei_mysql_command); offset += tvb_reported_length_remaining(tvb, offset); mysql_set_conn_state(pinfo, conn_data, UNDEFINED); } proto_item_set_end(request_item, tvb, offset); return offset; } /* * Decode a compressed packet * https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_compression.html */ static int mysql_dissect_compressed(tvbuff_t *tvb, int offset, proto_tree *mysql_tree, packet_info *pinfo, mysql_conn_data_t *conn_data) { tvbuff_t *next_tvb, *next_tvb2; guint clen, ulen; clen = tvb_get_letoh24(tvb, offset); 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; ulen = tvb_get_letoh24(tvb, offset); proto_tree_add_item(mysql_tree, hf_mysql_compressed_packet_length_uncompressed, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; if (ulen>0) { next_tvb = tvb_child_uncompress(tvb, tvb, offset, clen); if (next_tvb) { add_new_data_source(pinfo, next_tvb, "compressed data"); int next_offset = 0; while (tvb_reported_length_remaining(next_tvb, next_offset) > 0) { guint32 pdulen = tvb_get_letoh24(next_tvb, next_offset) + 4; next_tvb2 = tvb_new_subset_length(next_tvb, next_offset, pdulen); conn_data->compressed_state = MYSQL_COMPRESS_PAYLOAD; dissect_mysql_pdu(next_tvb2, pinfo, mysql_tree, NULL); conn_data->compressed_state = MYSQL_COMPRESS_ACTIVE; next_offset += pdulen; } offset += clen; } else { expert_add_info_format(pinfo, mysql_tree, &ei_mysql_compression, "Can't uncompress packet"); } } else { while (tvb_reported_length_remaining(tvb, offset) > 0) { guint32 pdulen = tvb_get_letoh24(tvb, offset) + 4; next_tvb = tvb_new_subset_length(tvb, offset, pdulen); conn_data->compressed_state = MYSQL_COMPRESS_PAYLOAD; dissect_mysql_pdu(next_tvb, pinfo, mysql_tree, NULL); conn_data->compressed_state = MYSQL_COMPRESS_ACTIVE; offset += pdulen; } } return offset; } static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data, proto_item *pi, mysql_state_t current_state) { gint response_code; gint lenstr; proto_item *ti; response_code = tvb_get_guint8(tvb, offset); switch (response_code) { case 0xff: proto_tree_add_item(tree, hf_mysql_response_code, tvb, offset, 1, ENC_NA); proto_item_append_text(pi, " - %s", val_to_str(RESPONSE_ERROR, state_vals, "Unknown (%u)")); offset = mysql_dissect_error_packet(tvb, pinfo, offset+1, tree); mysql_set_conn_state(pinfo, conn_data, REQUEST); break; case 0xfe: proto_tree_add_item(tree, hf_mysql_response_code, tvb, offset, 1, ENC_NA); proto_tree_add_item(tree, hf_mysql_eof, tvb, offset, 1, ENC_NA); offset += 1; if (tvb_reported_length_remaining(tvb, offset) <= 5) { // real EOF packet offset = mysql_dissect_eof(tvb, pinfo, pi, offset, tree, conn_data); if (current_state == PREPARED_PARAMETERS) { if (conn_data->stmt_num_fields > 0) { proto_item_append_text(pi, " - %s", val_to_str(INTERMEDIATE_EOF, state_vals, "Unknown (%u)")); mysql_set_remaining_field_packet_count(conn_data, conn_data->stmt_num_fields); mysql_set_conn_state(pinfo, conn_data, PREPARED_FIELDS); } else { proto_item_append_text(pi, " - %s", val_to_str(RESPONSE_EOF, state_vals, "Unknown (%u)")); mysql_set_conn_state(pinfo, conn_data, REQUEST); } } else if (current_state == FIELD_PACKET) { // intermediate EOF packet proto_item_append_text(pi, " - %s", val_to_str(INTERMEDIATE_EOF, state_vals, "Unknown (%u)")); mysql_set_conn_state(pinfo, conn_data, ROW_PACKET); } else { // ending EOF packet proto_item_append_text(pi, " - %s", val_to_str(RESPONSE_EOF, state_vals, "Unknown (%u)")); mysql_set_conn_state(pinfo, conn_data, REQUEST); } } else if (tvb_reported_length_remaining(tvb, offset) < 0xffffff) { // not an EOF if (current_state == AUTH_SWITCH_REQUEST) { proto_item_append_text(pi, " - %s", val_to_str(AUTH_SWITCH_REQUEST, state_vals, "Unknown (%u)")); offset = mysql_dissect_auth_switch_request(tvb, pinfo, offset, tree, conn_data); } else { proto_item_append_text(pi, " - %s", val_to_str(RESPONSE_OK, state_vals, "Unknown (%u)")); offset = mysql_dissect_ok_packet(tvb, pinfo, offset, tree, conn_data); mysql_set_conn_state(pinfo, conn_data, REQUEST); } } else { // text row packet proto_item_append_text(pi, " - %s", val_to_str(ROW_PACKET, state_vals, "Unknown (%u)")); mysql_set_conn_state(pinfo, conn_data, ROW_PACKET); offset = mysql_dissect_text_row_packet(tvb, offset, tree); } break; case 0xfb: /* https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_local_infile_request.html */ col_append_str(pinfo->cinfo, COL_INFO, " LOCAL INFILE"); proto_tree_add_item(tree, hf_mysql_response_code, tvb, offset, 1, ENC_NA); proto_item_append_text(pi, " - %s", val_to_str(RESPONSE_LOCALINFILE, state_vals, "Unknown (%u)")); lenstr = tvb_reported_length_remaining(tvb, ++offset); proto_tree_add_item(tree, hf_mysql_loaddata_filename, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; mysql_set_conn_state(pinfo, conn_data, INFILE_DATA); break; case 0x00: proto_tree_add_item(tree, hf_mysql_response_code, tvb, offset, 1, ENC_NA); offset+=1; switch (current_state) { case RESPONSE_PREPARE: proto_item_append_text(pi, " - %s", val_to_str(RESPONSE_PREPARE, state_vals, "Unknown (%u)")); offset = mysql_dissect_response_prepare(tvb, pinfo, offset, tree, conn_data); break; case ROW_PACKET: proto_item_append_text(pi, " - %s", val_to_str(ROW_PACKET, state_vals, "Unknown (%u)")); offset = mysql_dissect_binary_row_packet(tvb, pinfo, pi, offset, tree, conn_data); break; case BINLOG_DUMP: proto_item_append_text(pi, " - %s", val_to_str(BINLOG_DUMP, state_vals, "Unknown (%u)")); offset = mysql_dissect_binlog_event_packet(tvb, pinfo, offset, tree); break; default: proto_item_append_text(pi, " - %s", val_to_str(RESPONSE_OK, state_vals, "Unknown (%u)")); offset = mysql_dissect_ok_packet(tvb, pinfo, offset, 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; } if (current_state == CLONE_INIT) mysql_set_conn_state(pinfo, conn_data, CLONE_ACTIVE); break; } break; default: switch (current_state) { case RESPONSE_MESSAGE: if ((lenstr = tvb_reported_length_remaining(tvb, offset))) { proto_tree_add_item(tree, hf_mysql_message, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; } mysql_set_conn_state(pinfo, conn_data, REQUEST); break; case RESPONSE_TABULAR: case REQUEST: /* That shouldn't be the case; maybe two requests in a row (s. bug 15074) */ proto_item_append_text(pi, " - %s", val_to_str(COLUMN_COUNT, state_vals, "Unknown (%u)")); offset = mysql_dissect_result_header(tvb, pinfo, offset, tree, conn_data); break; case PREPARED_PARAMETERS: proto_item_append_text(pi, " - %s", val_to_str(current_state, state_vals, "Unknown (%u)")); offset = mysql_dissect_field_packet(tvb, pi, offset, tree, pinfo, conn_data, current_state); mysql_dec_remaining_field_packet_count(conn_data); if (mysql_get_remaining_field_packet_count(conn_data) == 0) { if (conn_data->clnt_caps_ext & MYSQL_CAPS_DE) { if (conn_data->stmt_num_fields > 0) { mysql_set_remaining_field_packet_count(conn_data, conn_data->stmt_num_fields); mysql_set_conn_state(pinfo, conn_data, PREPARED_FIELDS); } else { mysql_set_conn_state(pinfo, conn_data, REQUEST); } } } break; case FIELD_PACKET: case RESPONSE_SHOW_FIELDS: proto_item_append_text(pi, " - %s", val_to_str(current_state, state_vals, "Unknown (%u)")); offset = mysql_dissect_field_packet(tvb, pi, offset, tree, pinfo, conn_data, current_state); mysql_dec_remaining_field_packet_count(conn_data); if ((conn_data->clnt_caps_ext & MYSQL_CAPS_DE) && (mysql_get_remaining_field_packet_count(conn_data) == 0)) { mysql_set_conn_state(pinfo, conn_data, ROW_PACKET); } break; case ROW_PACKET: proto_item_append_text(pi, " - %s", val_to_str(current_state, state_vals, "Unknown (%u)")); offset = mysql_dissect_text_row_packet(tvb, offset, tree); break; case PREPARED_FIELDS: proto_item_append_text(pi, " - %s", val_to_str(current_state, state_vals, "Unknown (%u)")); offset = mysql_dissect_field_packet(tvb, pi, offset, tree, pinfo, conn_data, current_state); mysql_dec_remaining_field_packet_count(conn_data); if ((conn_data->clnt_caps_ext & MYSQL_CAPS_DE) && (mysql_get_remaining_field_packet_count(conn_data) == 0)) { mysql_set_conn_state(pinfo, conn_data, REQUEST); } break; case AUTH_SWITCH_REQUEST: if (tvb_reported_length_remaining(tvb,offset) == 2) { proto_item_append_text(pi, " - %s", val_to_str(AUTH_SHA2, state_vals, "Unknown (%u)")); offset = mysql_dissect_auth_sha2(tvb, pinfo, offset, tree, conn_data); } else { proto_item_append_text(pi, " - %s", val_to_str(AUTH_SWITCH_REQUEST, state_vals, "Unknown (%u)")); offset = mysql_dissect_auth_switch_request(tvb, pinfo, offset, tree, conn_data); } break; default: ti = proto_tree_add_item(tree, hf_mysql_payload, tvb, offset, -1, ENC_NA); expert_add_info(pinfo, ti, &ei_mysql_unknown_response); offset += tvb_reported_length_remaining(tvb, offset); mysql_set_conn_state(pinfo, conn_data, UNDEFINED); } } return offset; } static int mysql_dissect_error_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree) { col_append_fstr(pinfo->cinfo, COL_INFO, " Error %d ", tvb_get_letohs(tvb, offset)); col_set_fence(pinfo->cinfo, COL_INFO); proto_tree_add_item(tree, hf_mysql_error_code, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; if (tvb_get_guint8(tvb, offset) == '#') { offset += 1; proto_tree_add_item(tree, hf_mysql_sqlstate, tvb, offset, 5, ENC_ASCII); offset += 5; } proto_tree_add_item(tree, hf_mysql_error_string, tvb, offset, -1, ENC_ASCII); offset += tvb_reported_length_remaining(tvb, offset); return offset; } /* Add a session track entry to the session tracking subtree return bytes read */ static int add_session_tracker_entry_to_tree(tvbuff_t *tvb, packet_info *pinfo, proto_item *tree, int offset) { guint8 data_type; /* session tracker type */ guint64 length; /* complete length of session tracking entry */ guint64 lenstr; int orig_offset = offset, lenfle; proto_item *item, *ti; proto_tree *session_track_tree; ti = proto_tree_add_item(tree, hf_mysql_session_track, tvb, offset, 1, ENC_NA); session_track_tree = proto_item_add_subtree(ti, ett_session_track); proto_tree_add_item(session_track_tree, hf_mysql_session_track_type, tvb, offset, 1, ENC_BIG_ENDIAN); data_type = tvb_get_guint8(tvb, offset); offset += 1; lenfle = tvb_get_fle(tvb, session_track_tree, offset, &length, NULL); proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_length, tvb, offset, lenfle, length); offset += lenfle; switch (data_type) { case 0: /* SESSION_SYSVARS_TRACKER */ lenfle = tvb_get_fle(tvb, session_track_tree, offset, &lenstr, NULL); proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_sysvar_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item(session_track_tree, hf_mysql_session_track_sysvar_name, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; lenfle = tvb_get_fle(tvb, session_track_tree, offset, &lenstr, NULL); proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_sysvar_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item(session_track_tree, hf_mysql_session_track_sysvar_value, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; break; case 1: /* CURRENT_SCHEMA_TRACKER */ lenfle = tvb_get_fle(tvb, session_track_tree, offset, &lenstr, NULL); proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_schema_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item(session_track_tree, hf_mysql_session_track_schema, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; break; case 2: /* SESSION_STATE_CHANGE_TRACKER */ proto_tree_add_item(session_track_tree, hf_mysql_session_state_change, tvb, offset, 1, ENC_ASCII); offset++; break; case 3: /* SESSION_TRACK_GTIDS */ proto_tree_add_item(session_track_tree, hf_mysql_session_track_gtids_encoding, tvb, offset, 1, ENC_NA); offset++; lenfle = tvb_get_fle(tvb, session_track_tree, offset, &lenstr, NULL); proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_gtids_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item(session_track_tree, hf_mysql_session_track_gtids, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; break; case 4: /* SESSION_TRACK_TRANSACTION_CHARACTERISTICS */ lenfle = tvb_get_fle(tvb, session_track_tree, offset, &lenstr, NULL); proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_transaction_characteristics_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item(session_track_tree, hf_mysql_session_track_transaction_characteristics, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; break; case 5: /* SESSION_TRACK_TRANSACTION_STATE */ lenfle = tvb_get_fle(tvb, session_track_tree, offset, &lenstr, NULL); proto_tree_add_uint64(session_track_tree, hf_mysql_session_track_transaction_state_length, tvb, offset, lenfle, lenstr); offset += lenfle; proto_tree_add_item(session_track_tree, hf_mysql_session_track_transaction_state, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; break; default: /* unsupported types skipped */ item = proto_tree_add_item(session_track_tree, hf_mysql_payload, tvb, offset, (gint)length, ENC_NA); expert_add_info_format(pinfo, item, &ei_mysql_dissector_incomplete, "FIXME: unrecognized session tracker data"); offset += (int)length; } proto_item_set_len(ti, offset - orig_offset); return (offset - orig_offset); } /* Add a extended metadata entry to the extended meta subtree return bytes read */ static int add_extended_meta_entry_to_tree(tvbuff_t *tvb, packet_info *pinfo, proto_item *tree, int offset) { guint8 data_type; guint64 lenstr; int orig_offset = offset, lenfle; proto_item *item, *ti; proto_tree *extmeta_tree; ti = proto_tree_add_item(tree, hf_mariadb_extmeta, tvb, offset, 1, ENC_NA); extmeta_tree = proto_item_add_subtree(ti, ett_extmeta); proto_tree_add_item(extmeta_tree, hf_mariadb_extmeta_key, tvb, offset, 1, ENC_BIG_ENDIAN); data_type = tvb_get_guint8(tvb, offset); offset += 1; lenfle = tvb_get_fle(tvb, extmeta_tree, offset, &lenstr, NULL); proto_tree_add_uint64(extmeta_tree, hf_mariadb_extmeta_length, tvb, offset, lenfle, lenstr); offset += lenfle; switch (data_type) { case 0: /* TYPE */ proto_tree_add_item(extmeta_tree, hf_mariadb_extmeta_type, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; break; case 1: /* FORMAT */ proto_tree_add_item(extmeta_tree, hf_mariadb_extmeta_format, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; break; default: /* unsupported types skipped */ item = proto_tree_add_item(extmeta_tree, hf_mysql_payload, tvb, offset, (gint)lenstr, ENC_NA); expert_add_info_format(pinfo, item, &ei_mysql_dissector_incomplete, "FIXME: unrecognized extended metadata data"); offset += (int)lenstr; } proto_item_set_len(ti, offset - orig_offset); return (offset - orig_offset); } static int mysql_dissect_ok_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data) { guint64 lenstr = 0; guint64 affected_rows; guint64 insert_id; int fle; guint16 server_status = 0; col_append_str(pinfo->cinfo, COL_INFO, " OK " ); col_set_fence(pinfo->cinfo, COL_INFO); fle = tvb_get_fle(tvb, tree, offset, &affected_rows, NULL); proto_tree_add_uint64(tree, hf_mysql_affected_rows, tvb, offset, fle, affected_rows); offset += fle; fle= tvb_get_fle(tvb, tree, offset, &insert_id, NULL); if (tree && insert_id) { proto_tree_add_uint64(tree, hf_mysql_insert_id, tvb, offset, fle, insert_id); } offset += fle; if (tvb_reported_length_remaining(tvb, offset) > 0) { offset = mysql_dissect_server_status(tvb, offset, tree, &server_status); /* 4.1+ protocol only: 2 bytes number of warnings */ if ((conn_data->clnt_caps & conn_data->srv_caps & MYSQL_CAPS_CU) || ((conn_data->clnt_caps == 0) && (conn_data->srv_caps == 0))) { proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN); lenstr = tvb_get_ntohs(tvb, offset); offset += 2; } } if (conn_data->clnt_caps_ext & MYSQL_CAPS_ST) { if (tvb_reported_length_remaining(tvb, offset) > 0) { guint64 session_track_length; proto_item *tf; proto_item *session_track_tree = NULL; int length; offset += tvb_get_fle(tvb, tree, offset, &lenstr, NULL); /* first read the optional message */ if (lenstr) { proto_tree_add_item(tree, hf_mysql_message, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; } /* session state tracking */ if (server_status & MYSQL_STAT_SESSION_STATE_CHANGED) { fle = tvb_get_fle(tvb, tree, offset, &session_track_length, NULL); tf = proto_tree_add_item(tree, hf_mysql_session_track_data, tvb, offset, -1, ENC_NA); session_track_tree = proto_item_add_subtree(tf, ett_session_track_data); proto_tree_add_uint64(tf, hf_mysql_session_track_data_length, tvb, offset, fle, session_track_length); offset += fle; while (session_track_length > 0) { length = add_session_tracker_entry_to_tree(tvb, pinfo, session_track_tree, offset); offset += length; session_track_length -= length; } } } } else { if ((tvb_reported_length_remaining(tvb, offset) > 0) && ((conn_data->clnt_caps == 0) && (conn_data->srv_caps == 0))) { // No client or server capabilities to work with, Let's try to skip over session state offset += tvb_get_fle(tvb, tree, offset, &lenstr, NULL); } /* optional: message string */ if (tvb_reported_length_remaining(tvb, offset) > 0) { if(lenstr > (guint64)tvb_reported_length_remaining(tvb, offset)) lenstr = tvb_reported_length_remaining(tvb, offset); proto_tree_add_item(tree, hf_mysql_message, tvb, offset, (gint)lenstr, ENC_ASCII); offset += (int)lenstr; } } mysql_set_conn_state(pinfo, conn_data, REQUEST); return offset; } static int mysql_dissect_server_status(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *server_status) { if (server_status) { *server_status = tvb_get_letohs(tvb, offset); } proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_mysql_server_status, ett_stat, mysql_stat_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); offset += 2; return offset; } static int mysql_dissect_caps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_caps, guint16 *caps) { *caps= tvb_get_letohs(tvb, offset); proto_tree_add_bitmask_with_flags(tree, tvb, offset, mysql_caps, ett_caps, mysql_caps_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); offset += 2; return offset; } static int mysql_dissect_extcaps(tvbuff_t *tvb, int offset, proto_tree *tree, int mysql_extcaps, guint16 *ext_caps) { *ext_caps= tvb_get_letohs(tvb, offset); proto_tree_add_bitmask_with_flags(tree, tvb, offset, mysql_extcaps, ett_extcaps, mysql_extcaps_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); offset += 2; return offset; } static int mariadb_dissect_caps_or_flags(tvbuff_t *tvb, int offset, enum ftenum type, proto_tree *tree, int mariadb_caps, int * const *fields, void *value) { guint8 diff= 0; switch (type) { case FT_UINT8: *((guint8 *)value)= tvb_get_guint8(tvb, offset); diff= 1; break; case FT_UINT16: *((guint16 *)value)= tvb_get_letohs(tvb, offset); diff= 2; break; case FT_UINT32: *((guint32 *)value)= tvb_get_letohl(tvb, offset); diff= 4; break; default: return 0; } proto_tree_add_bitmask_with_flags(tree, tvb, offset, mariadb_caps, ett_extcaps, fields, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); offset+= diff; return offset; } static int mysql_dissect_result_header(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data) { gint fle; guint64 num_fields, extra; guint8 send_meta= 0; my_metadata_list_t *field_metas; my_stmt_data_t *stmt_data; col_append_str(pinfo->cinfo, COL_INFO, "TABULAR " ); col_set_fence(pinfo->cinfo, COL_INFO); fle = tvb_get_fle(tvb, tree, offset, &num_fields, NULL); proto_tree_add_uint64(tree, hf_mysql_num_fields, tvb, offset, fle, num_fields); offset += fle; /** skip info flag **/ send_meta = 1; if (conn_data->mariadb_client_ext_caps & MARIADB_CAPS_ME && conn_data->mariadb_server_ext_caps & MARIADB_CAPS_ME && tvb_reported_length_remaining(tvb, offset)) { send_meta = tvb_get_guint8(tvb, offset); proto_tree_add_item(tree, hf_mariadb_send_meta, tvb, offset, 1, ENC_NA); offset += 1; } if (num_fields > MAX_MY_METADATA_COUNT) { expert_add_info_format(pinfo, tree, &ei_mysql_invalid_length, "Invalid length: %" G_GUINT64_FORMAT, num_fields); return tvb_reported_length_remaining(tvb, 0); } else if (send_meta) { field_metas = wmem_new(wmem_file_scope(), my_metadata_list_t); field_metas->count = (guint16)num_fields; field_metas->flags = (guint16 *)wmem_alloc0_array(wmem_file_scope(), guint16, (size_t)num_fields); field_metas->types = (guint8 *)wmem_alloc0_array(wmem_file_scope(), guint8, (size_t)num_fields); conn_data->field_metas = *field_metas; } else { if (conn_data->stmt_id) { stmt_data = (my_stmt_data_t *)wmem_tree_lookup32(conn_data->stmts, conn_data->stmt_id); if (stmt_data != NULL) { field_metas = &stmt_data->field_metas; conn_data->field_metas = *field_metas; } } } if (tvb_reported_length_remaining(tvb, offset)) { fle = tvb_get_fle(tvb, tree, offset, &extra, NULL); proto_tree_add_uint64(tree, hf_mysql_extra, tvb, offset, fle, extra); offset += fle; } if (num_fields) { if (send_meta) { mysql_set_conn_state(pinfo, conn_data, FIELD_PACKET); mysql_set_remaining_field_packet_count(conn_data, num_fields); } else { mysql_set_remaining_field_packet_count(conn_data, 0); if (conn_data->clnt_caps_ext & MYSQL_CAPS_DE) { mysql_set_conn_state(pinfo, conn_data, ROW_PACKET); } else { /** Intermediate EOF follow **/ mysql_set_conn_state(pinfo, conn_data, FIELD_PACKET); } } } else { mysql_set_conn_state(pinfo, conn_data, ROW_PACKET); } return offset; } /* * Add length encoded string to tree */ static int mysql_field_add_lestring(tvbuff_t *tvb, int offset, proto_tree *tree, int field) { guint64 lelen; guint8 is_null; header_field_info* hfi; proto_item* ti; proto_tree* sub_tree; int start_offset = offset; hfi = proto_registrar_get_nth(field); DISSECTOR_ASSERT(hfi != NULL); sub_tree = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_mysql_field, &ti, "%s", hfi->name); offset += tvb_get_fle(tvb, sub_tree, offset, &lelen, &is_null); if(is_null) proto_tree_add_string(sub_tree, field, tvb, offset, 0, "NULL"); else { proto_tree_add_item(sub_tree, field, tvb, offset, (int)lelen, ENC_NA); /* Prevent infinite loop due to overflow */ if (offset + (int)lelen < offset) { offset = tvb_reported_length(tvb); } else { offset += (int)lelen; } } proto_item_set_len(ti, offset -start_offset); return offset; } static int mysql_dissect_field_packet(tvbuff_t *tvb, proto_item *pi _U_, int offset, proto_tree *tree, packet_info *pinfo _U_, mysql_conn_data_t *conn_data, mysql_state_t current_state) { guint8 fld_type; guint16 fld_flag; int length = tvb_reported_length(tvb); /* Are these fields optional? a trace suggests they are...*/ offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_catalog); if (offset >= length) { return offset; } offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_db); offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_table); offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_table); offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_name); offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_org_name); // mariadb extended metadata infos if (conn_data->mariadb_client_ext_caps & MARIADB_CAPS_EM && conn_data->mariadb_server_ext_caps & MARIADB_CAPS_EM) { guint64 extended_length; proto_item *extended_tree = NULL; proto_item *tf; int fle; fle = tvb_get_fle(tvb, tree, offset, &extended_length, NULL); tf = proto_tree_add_item(tree, hf_mariadb_extmeta_data, tvb, offset, fle + (guint32) extended_length, ENC_NA); extended_tree = proto_item_add_subtree(tf, ett_extmeta_data); proto_tree_add_uint64(tf, hf_mariadb_extmeta_length, tvb, offset, fle, extended_length); offset += fle; while (extended_length > 0) { length = add_extended_meta_entry_to_tree(tvb, pinfo, extended_tree, offset); offset += length; extended_length -= length; } } offset +=1; /* filler */ proto_tree_add_item(tree, hf_mysql_fld_charsetnr, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* charset */ proto_tree_add_item(tree, hf_mysql_fld_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* length */ proto_tree_add_item(tree, hf_mysql_fld_type, tvb, offset, 1, ENC_NA); fld_type = tvb_get_guint8(tvb, offset); offset += 1; /* type */ proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_mysql_fld_flags, ett_field_flags, mysql_fld_flags, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); fld_flag = tvb_get_letohs(tvb, offset); offset += 2; /* flags */ proto_tree_add_item(tree, hf_mysql_fld_decimals, tvb, offset, 1, ENC_NA); offset += 1; /* decimals */ offset += 2; /* filler */ if (current_state == FIELD_PACKET || current_state == PREPARED_FIELDS) { if (conn_data->field_metas.count) { guint64 fieldpos = conn_data->field_metas.count - mysql_get_remaining_field_packet_count(conn_data); if (fieldpos >= conn_data->field_metas.count) { expert_add_info_format(pinfo, tree, &ei_mysql_invalid_length, "Invalid length: %" G_GUINT64_FORMAT, fieldpos); return tvb_reported_length_remaining(tvb, 0); } conn_data->field_metas.types[fieldpos] = fld_type; conn_data->field_metas.flags[fieldpos] = fld_flag; } } /* default (Only use for show fields) */ if (tvb_reported_length_remaining(tvb, offset) > 0) { offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_fld_default); } return offset; } static int mysql_dissect_text_row_packet(tvbuff_t *tvb, int offset, proto_tree *tree) { while (tvb_reported_length_remaining(tvb, offset) > 0) { offset = mysql_field_add_lestring(tvb, offset, tree, hf_mysql_row_text); } return offset; } static int mysql_dissect_binary_row_packet(tvbuff_t *tvb, packet_info *pinfo, proto_item *pi, int offset, proto_tree *tree, mysql_conn_data_t *conn_data) { int fieldpos; if (conn_data->field_metas.count) { /* null bitmap */ int nfields = conn_data->field_metas.count; int null_len = (nfields + 9) / 8; char *null_buffer; null_buffer = (guint8 *)wmem_alloc(wmem_packet_scope(), (size_t)null_len + 1); tvb_get_raw_bytes_as_string(tvb, offset, null_buffer, (size_t)null_len + 1); proto_tree_add_bytes_with_length(tree, hf_mysql_null_buffer, tvb, offset, null_len, null_buffer, null_len); offset += null_len; for (fieldpos = 0; fieldpos < nfields; fieldpos++) { if ((null_buffer[(fieldpos + 2) / 8] & (1 << ((fieldpos + 2) % 8))) == 0) { // data is not null if (tvb_reported_length_remaining(tvb, offset) > 0) { if (!mysql_dissect_binary_row_value(tvb, pinfo, pi, &offset, tree, conn_data->field_metas.types[fieldpos], conn_data->field_metas.flags[fieldpos])) break; } } else { proto_tree_add_item(tree, hf_mysql_exec_field_null, tvb, offset, 0, ENC_NA); } } } return offset; } static char mysql_dissect_binary_row_value(tvbuff_t *tvb, packet_info *pinfo _U_, proto_item *pi _U_, int *offset, proto_item *tree, guint8 field_type, guint16 field_flag) { int dissector_index = 0; guint8 param_unsigned = 0; if (field_flag & MYSQL_FLD_UNSIGNED_FLAG) { param_unsigned = 1; } while (mysql_exec_dissectors[dissector_index].dissector != NULL) { if (mysql_exec_dissectors[dissector_index].type == field_type && mysql_exec_dissectors[dissector_index].unsigned_flag == param_unsigned) { mysql_exec_dissectors[dissector_index].dissector(tvb, offset, tree); return 1; } dissector_index++; } return 0; } static int mysql_dissect_response_prepare(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data) { my_stmt_data_t *stmt_data; my_metadata_list_t *field_metas; my_metadata_list_t *param_metas; guint32 stmt_id; proto_tree_add_item(tree, hf_mysql_stmt_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); stmt_id = tvb_get_letohl(tvb, offset); conn_data->stmt_id=stmt_id; offset += 4; proto_tree_add_item(tree, hf_mysql_num_fields, tvb, offset, 2, ENC_LITTLE_ENDIAN); conn_data->stmt_num_fields = tvb_get_letohs(tvb, offset); offset += 2; proto_tree_add_item(tree, hf_mysql_num_params, tvb, offset, 2, ENC_LITTLE_ENDIAN); conn_data->stmt_num_params = tvb_get_letohs(tvb, offset); stmt_data = wmem_new(wmem_file_scope(), struct my_stmt_data); param_metas = wmem_new(wmem_file_scope(), my_metadata_list_t); param_metas->count = conn_data->stmt_num_params; param_metas->flags = (guint16 *)wmem_alloc0_array(wmem_file_scope(), guint16, param_metas->count); param_metas->types = (guint8 *)wmem_alloc0_array(wmem_file_scope(), guint8, param_metas->count); stmt_data->param_metas = *param_metas; field_metas = wmem_new(wmem_file_scope(), my_metadata_list_t); field_metas->count = conn_data->stmt_num_fields; field_metas->flags = (guint16 *)wmem_alloc0_array(wmem_file_scope(), guint16, field_metas->count); field_metas->types = (guint8 *)wmem_alloc0_array(wmem_file_scope(), guint8, field_metas->count); stmt_data->field_metas = *field_metas; conn_data->field_metas = *field_metas; wmem_tree_insert32(conn_data->stmts, stmt_id, stmt_data); offset += 2; /* Filler */ offset += 1; proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN); if (conn_data->stmt_num_params > 0) { mysql_set_remaining_field_packet_count(conn_data, conn_data->stmt_num_params); mysql_set_conn_state(pinfo, conn_data, PREPARED_PARAMETERS); } else if (conn_data->stmt_num_fields > 0) { mysql_set_remaining_field_packet_count(conn_data, conn_data->stmt_num_fields); mysql_set_conn_state(pinfo, conn_data, PREPARED_FIELDS); } else { mysql_set_remaining_field_packet_count(conn_data, 0); mysql_set_conn_state(pinfo, conn_data, REQUEST); } return offset + tvb_reported_length_remaining(tvb, offset); } /** Enumeration type for the different types of log events. */ enum Log_event_type { /** Every time you add a type, you have to - Assign it a number explicitly. Otherwise it will cause trouble if a event type before is deprecated and removed directly from the enum. - Fix Format_description_event::Format_description_event(). */ UNKNOWN_EVENT = 0, /* Deprecated since mysql 8.0.2. It is just a placeholder, should not be used anywhere else. */ START_EVENT_V3 = 1, QUERY_EVENT = 2, STOP_EVENT = 3, ROTATE_EVENT = 4, INTVAR_EVENT = 5, SLAVE_EVENT = 7, APPEND_BLOCK_EVENT = 9, DELETE_FILE_EVENT = 11, RAND_EVENT = 13, USER_VAR_EVENT = 14, FORMAT_DESCRIPTION_EVENT = 15, XID_EVENT = 16, BEGIN_LOAD_QUERY_EVENT = 17, EXECUTE_LOAD_QUERY_EVENT = 18, TABLE_MAP_EVENT = 19, /** The V1 event numbers are used from 5.1.16 until mysql-5.6. */ WRITE_ROWS_EVENT_V1 = 23, UPDATE_ROWS_EVENT_V1 = 24, DELETE_ROWS_EVENT_V1 = 25, /** Something out of the ordinary happened on the master */ INCIDENT_EVENT = 26, /** Heartbeat event to be send by master at its idle time to ensure master's online status to slave */ HEARTBEAT_LOG_EVENT = 27, /** In some situations, it is necessary to send over ignorable data to the slave: data that a slave can handle in case there is code for handling it, but which can be ignored if it is not recognized. */ IGNORABLE_LOG_EVENT = 28, ROWS_QUERY_LOG_EVENT = 29, /** Version 2 of the Row events */ WRITE_ROWS_EVENT = 30, UPDATE_ROWS_EVENT = 31, DELETE_ROWS_EVENT = 32, GTID_LOG_EVENT = 33, ANONYMOUS_GTID_LOG_EVENT = 34, PREVIOUS_GTIDS_LOG_EVENT = 35, TRANSACTION_CONTEXT_EVENT = 36, VIEW_CHANGE_EVENT = 37, /* Prepared XA transaction terminal event similar to Xid */ XA_PREPARE_LOG_EVENT = 38, /** Extension of UPDATE_ROWS_EVENT, allowing partial values according to binlog_row_value_options. */ PARTIAL_UPDATE_ROWS_EVENT = 39, TRANSACTION_PAYLOAD_EVENT = 40, HEARTBEAT_LOG_EVENT_V2 = 41, /** Add new events here - right above this comment! Existing events (except ENUM_END_EVENT) should never change their numbers */ ENUM_END_EVENT /* end marker */ }; static const value_string mysql_binlog_event_type_vals[] = { {0, "Unknown"}, {1, "START_EVENT_V3"}, {2, "Query"}, {3, "Stop"}, {4, "Rotate"}, {5, "Intvar"}, {7, "SLAVE_EVENT"}, {9, "Append_block"}, {11, "Delete_file"}, {13, "RAND"}, {14, "User_var"}, {15, "Format_desc"}, {16, "Xid"}, {17, "Begin_load_query"}, {18, "Execute_load_query"}, {19, "Table_map"}, {23, "Write_rows_v1"}, {24, "Update_rows_v1"}, {25, "Delete_rows_v1"}, {26, "Incident"}, {27, "Heartbeat"}, {28, "Ignorable"}, {29, "Rows_query"}, {30, "Write_rows"}, {31, "Update_rows"}, {32, "Delete_rows"}, {33, "Gtid"}, {34, "Anonymous_Gtid"}, {35, "Previous_gtids"}, {36, "Transaction_context"}, {37, "View_change"}, {38, "XA_prepare"}, {39, "Update_rows_partial"}, {40, "Transaction_payload"}, {41, "Heartbeat_v2"}, {0, NULL}, }; static int mysql_dissect_binlog_event_heartbeat_v2(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree) { int fle; guint64 num; proto_item *item, *parent_item; proto_item *hb_v2_tree, *hb_v2_subtree; col_append_str(pinfo->cinfo, COL_INFO, "Heartbeat_v2 "); col_set_fence(pinfo->cinfo, COL_INFO); item = proto_tree_add_item(tree, hf_mysql_binlog_event_heartbeat_v2, tvb, offset, -1, ENC_NA); hb_v2_tree = proto_item_add_subtree(item, ett_binlog_event); // OTW_HB_LOG_FILENAME_FIELD parent_item = proto_tree_add_item(hb_v2_tree, hf_mysql_binlog_event_heartbeat_v2_otw, tvb, offset, -1, ENC_NA); hb_v2_subtree = proto_item_add_subtree(parent_item, ett_binlog_event_hb_v2); item = proto_tree_add_item(hb_v2_subtree, hf_mysql_binlog_event_heartbeat_v2_otw_type, tvb, offset, 1, ENC_NA); proto_item_append_text(item, " (OTW_HB_LOG_FILENAME_FIELD)"); proto_item_append_text(parent_item, " OTW_HB_LOG_FILENAME_FIELD"); offset += 1; fle = tvb_get_fle(tvb, hb_v2_subtree, offset, &num, ENC_NA); offset += fle; proto_tree_add_item(hb_v2_subtree, hf_mysql_binlog_hb_event_filename, tvb, offset, (gint) num, ENC_ASCII); offset += (gint)num; // OTW_HB_LOG_POSITION_FIELD parent_item = proto_tree_add_item(hb_v2_tree, hf_mysql_binlog_event_heartbeat_v2_otw, tvb, offset, -1, ENC_NA); hb_v2_subtree = proto_item_add_subtree(parent_item, ett_binlog_event_hb_v2); item = proto_tree_add_item(hb_v2_subtree, hf_mysql_binlog_event_heartbeat_v2_otw_type, tvb, offset, 1, ENC_NA); proto_item_append_text(item, " (OTW_HB_LOG_POSITION_FIELD)"); proto_item_append_text(parent_item, " OTW_HB_LOG_POSITION_FIELD"); offset += 1; fle = tvb_get_fle(tvb, hb_v2_subtree, offset, &num, NULL); offset += fle; fle = tvb_get_fle(tvb, hb_v2_subtree, offset, &num, NULL); proto_tree_add_uint64(hb_v2_subtree, hf_mysql_binlog_hb_event_log_position, tvb, offset, fle, num); offset += fle; // OTW_HB_LOG_FILENAME_FIELD parent_item = proto_tree_add_item(hb_v2_tree, hf_mysql_binlog_event_heartbeat_v2_otw, tvb, offset, -1, ENC_NA); hb_v2_subtree = proto_item_add_subtree(parent_item, ett_binlog_event_hb_v2); item = proto_tree_add_item(hb_v2_subtree, hf_mysql_binlog_event_heartbeat_v2_otw_type, tvb, offset, 1, ENC_NA); proto_item_append_text(item, " (OTW_HB_HEADER_END_MARK)"); proto_item_append_text(parent_item, " OTW_HB_HEADER_END_MARK"); offset += 1; return offset; } static int mysql_dissect_binlog_event_header(tvbuff_t *tvb, int offset, proto_tree *tree) { proto_tree_add_item(tree, hf_mysql_binlog_event_header_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(tree, hf_mysql_binlog_event_header_event_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(tree, hf_mysql_binlog_event_header_server_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(tree, hf_mysql_binlog_event_header_event_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(tree, hf_mysql_binlog_event_header_log_position, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(tree, hf_mysql_binlog_event_header_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; return offset; } static int mysql_dissect_binlog_event_packet(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree) { guint8 event_type; int fle; col_append_str(pinfo->cinfo, COL_INFO, "Binlog Event " ); col_set_fence(pinfo->cinfo, COL_INFO); event_type = tvb_get_guint8(tvb, offset + 4); offset = mysql_dissect_binlog_event_header(tvb, offset, tree); switch (event_type) { case HEARTBEAT_LOG_EVENT_V2: offset = mysql_dissect_binlog_event_heartbeat_v2(tvb, pinfo, offset, tree); break; default: fle = tvb_reported_length_remaining(tvb, offset); offset += fle - 4; break; } // checksum proto_tree_add_item(tree, hf_mysql_binlog_event_checksum, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; return offset; } static int mysql_dissect_eof(tvbuff_t *tvb, packet_info *pinfo _U_, proto_item *pi _U_, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_) { guint16 server_status = 0; proto_tree_add_item(tree, hf_mysql_num_warn, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; offset = mysql_dissect_server_status(tvb, offset, tree, &server_status); return offset + tvb_reported_length_remaining(tvb, offset); } static int mysql_dissect_auth_switch_request(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_) { gint lenstr; col_set_str(pinfo->cinfo, COL_INFO, "Auth Switch Request " ); col_set_fence(pinfo->cinfo, COL_INFO); mysql_set_conn_state(pinfo, conn_data, AUTH_SWITCH_RESPONSE); if (conn_data->clnt_caps_ext & MYSQL_CAPS_PA) { /* https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_auth_switch_request.html */ /* name */ lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(tree, hf_mysql_auth_switch_request_name, tvb, offset, lenstr, ENC_ASCII); offset += lenstr; /* Data */ lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(tree, hf_mysql_auth_switch_request_data, tvb, offset, lenstr, ENC_NA); offset += lenstr; } else { /* https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_old_auth_switch_request.html */ /* Status (Always 0xfe) */ proto_tree_add_item(tree, hf_mysql_auth_switch_request_status, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; } return offset + tvb_reported_length_remaining(tvb, offset); } static int mysql_dissect_auth_switch_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_) { gint lenstr; col_set_str(pinfo->cinfo, COL_INFO, "Auth Switch Response " ); col_set_fence(pinfo->cinfo, COL_INFO); /* Data */ lenstr = my_tvb_strsize(tvb, offset); proto_tree_add_item(tree, hf_mysql_auth_switch_response_data, tvb, offset, lenstr, ENC_NA); offset += lenstr; return offset + tvb_reported_length_remaining(tvb, offset); } /* caching_sha2_password authentication state Doc: https://dev.mysql.com/doc/dev/mysql-server/latest/page_caching_sha2_authentication_exchanges.html */ static int mysql_dissect_auth_sha2(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_) { col_set_str(pinfo->cinfo, COL_INFO, "Caching_sha2_password " ); col_set_fence(pinfo->cinfo, COL_INFO); if (tvb_reported_length_remaining(tvb,offset) == 2) offset++; char *auth2_state; guint8 c = tvb_get_guint8(tvb, offset); switch (c) { case 2: auth2_state = "request_public_key"; mysql_set_conn_state(pinfo, conn_data, AUTH_PUBKEY); break; case 3: auth2_state = "fast_auth_success"; break; case 4: auth2_state = "perform_full_authentication"; mysql_set_conn_state(pinfo, conn_data, AUTH_SHA2); break; default: auth2_state = "unknown"; } col_append_str(pinfo->cinfo, COL_INFO, auth2_state); proto_tree_add_string(tree, hf_mysql_sha2_auth, tvb, offset, 1, auth2_state); offset++; return offset + tvb_reported_length_remaining(tvb, offset); } /* Public key as requested during caching_sha2_password authentication */ static int mysql_dissect_pubkey(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_, proto_item *pi _U_, mysql_state_t current_state _U_) { tvbuff_t *next_tvb; col_set_str(pinfo->cinfo, COL_INFO, "Public key " ); col_set_fence(pinfo->cinfo, COL_INFO); mysql_set_conn_state(pinfo, conn_data, AUTH_SHA2_RESPONSE); offset++; gint len = tvb_reported_length_remaining(tvb, offset) - 1; next_tvb = tvb_new_subset_length(tvb, offset, len); add_new_data_source(pinfo, next_tvb, "public key"); proto_tree_add_item(tree, hf_mysql_pubkey, tvb, offset, len, ENC_ASCII); offset += len; return offset + tvb_reported_length_remaining(tvb,offset); } /* If caching_sha2_password authentication is used over a non-secure channel then the authentication response (password) is encrypted with a RSA public key. This means that we can't dissect this response without access to the RSA private key. */ static int mysql_dissect_sha2_response(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree _U_, mysql_conn_data_t *conn_data _U_, proto_item *pi _U_, mysql_state_t current_state _U_) { gint len = tvb_reported_length_remaining(tvb, offset); proto_tree_add_item(tree, hf_mysql_sha2_response, tvb, offset, len, ENC_NA); return offset + tvb_reported_length_remaining(tvb, offset); } static int mysql_dissect_clone_request(tvbuff_t *tvb _U_, packet_info *pinfo _U_, int offset _U_, proto_tree *tree _U_, mysql_conn_data_t *conn_data _U_, proto_item *pi _U_, mysql_state_t current_state _U_) { guint8 req_code = tvb_get_guint8(tvb, offset); switch (req_code) { case MYSQL_CLONE_COM_INIT: case MYSQL_CLONE_COM_ATTACH: case MYSQL_CLONE_COM_REINIT: case MYSQL_CLONE_COM_EXECUTE: case MYSQL_CLONE_COM_ACK: col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(req_code, mysql_clone_command_vals, "%s")); proto_tree_add_item(tree, hf_mysql_clone_command_code, tvb, offset, 1, ENC_NA); break; case MYSQL_CLONE_COM_EXIT: col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(req_code, mysql_clone_command_vals, "%s")); proto_tree_add_item(tree, hf_mysql_clone_command_code, tvb, offset, 1, ENC_NA); mysql_set_conn_state(pinfo, conn_data, CLONE_EXIT); break; default: col_append_str(pinfo->cinfo, COL_INFO, " Unknown Clone Command Code") ; /* TODO, Set error etc */ } offset++; return offset; } static int mysql_dissect_clone_response(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, mysql_conn_data_t *conn_data, proto_item *pi _U_, mysql_state_t current_state) { guint8 resp_code = tvb_get_guint8(tvb, offset); switch (resp_code) { case MYSQL_CLONE_COM_RES_LOCS: case MYSQL_CLONE_COM_RES_DATA_DESC: case MYSQL_CLONE_COM_RES_DATA: case MYSQL_CLONE_COM_RES_PLUGIN: case MYSQL_CLONE_COM_RES_CONFIG: case MYSQL_CLONE_COM_RES_COLLATION: case MYSQL_CLONE_COM_RES_PLUGIN_V2: case MYSQL_CLONE_COM_RES_CONFIG_V3: case MYSQL_CLONE_COM_RES_COMPLETE: if (current_state == CLONE_EXIT) mysql_set_conn_state(pinfo, conn_data, REQUEST); /* fall through */ case MYSQL_CLONE_COM_RES_ERROR: col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str(resp_code, mysql_clone_response_vals, "%s")); proto_tree_add_item(tree, hf_mysql_clone_response_code, tvb, offset, 1, ENC_NA); break; default: col_append_str(pinfo->cinfo, COL_INFO, " Unknown Clone Response Code") ; /* TODO, Set error etc */ } offset++; return offset; } /* This is the payload (file content) of the LOAD DATA LOCAL INFILE https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_local_infile_data.html */ static int mysql_dissect_loaddata(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, proto_tree *tree, mysql_conn_data_t *conn_data _U_) { col_append_str(pinfo->cinfo, COL_INFO, " LOCAL INFILE Payload"); col_set_fence(pinfo->cinfo, COL_INFO); gint lenstr = tvb_reported_length_remaining(tvb, offset); tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, lenstr); add_new_data_source(pinfo, next_tvb, "local infile"); proto_tree_add_item(tree, hf_mysql_loaddata_payload, tvb, offset, lenstr, ENC_NA); offset += lenstr; mysql_set_conn_state(pinfo, conn_data, REQUEST); return offset; } /* get length of string in packet buffer SYNOPSIS my_tvb_strsize() tvb packet buffer offset current offset DESCRIPTION deliver length of string, delimited by either \0 or end of buffer RETURN VALUE length of string found, including \0 (if present) */ static gint my_tvb_strsize(tvbuff_t *tvb, int offset) { gint len = tvb_strnlen(tvb, offset, -1); if (len == -1) { len = tvb_reported_length_remaining(tvb, offset); } else { len++; /* the trailing \0 */ } return len; } /* read "field length encoded" value from packet buffer SYNOPSIS tvb_get_fle() tvb in packet buffer tree in....protocol tree offset in offset in buffer res out where to store FLE value, may be NULL is_null out where to store ISNULL flag, may be NULL DESCRIPTION read FLE from packet buffer and store its value and ISNULL flag in caller provided variables Docs: https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_dt_integers.html RETURN VALUE length of FLE */ static int tvb_get_fle(tvbuff_t *tvb, proto_tree *tree _U_, int offset, guint64 *res, guint8 *is_null) { guint8 prefix; int num_bytes; guint64 length; prefix = tvb_get_guint8(tvb, offset); if (is_null) { *is_null = 0; } switch (prefix) { case 251: if (res) *res = 0; if (is_null) *is_null = 1; return 1; case 252: // 0xFC num_bytes = 3; offset++; length = (guint64)tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); break; case 253: // 0xFD num_bytes = 4; offset++; length = (guint64)tvb_get_guint24(tvb, offset, ENC_LITTLE_ENDIAN); break; case 254: // 0xFE num_bytes = 9; offset++; length = tvb_get_guint64(tvb, offset, ENC_LITTLE_ENDIAN); break; default: num_bytes = 1; length = tvb_get_guint8(tvb, offset); } if (res) { *res = length; } return num_bytes; } /* dissector helper: length of PDU */ static guint get_mysql_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_) { /* Regular packet header: length (3) + sequence number (1) */ conversation_t *conversation; mysql_conn_data_t *conn_data; guint len = 4 + tvb_get_letoh24(tvb, offset); conversation = find_conversation_pinfo(pinfo, 0); if (conversation) { conn_data = (mysql_conn_data_t *)conversation_get_proto_data(conversation, proto_mysql); if (conn_data && conn_data->compressed_state == MYSQL_COMPRESS_ACTIVE && pinfo->num > conn_data->frame_start_compressed) { /* Compressed packet header includes uncompressed packet length (3) */ len += 3; } } return len; } /* dissector main function: handle one PDU */ static int dissect_mysql_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { proto_tree *mysql_tree= NULL; proto_item *ti; conversation_t *conversation; int offset = 0; guint packet_number; gboolean is_response, is_tls = FALSE; mysql_conn_data_t *conn_data; #ifdef CTDEBUG mysql_state_t conn_state_in, conn_state_out, frame_state; guint64 generation; proto_item *pi; #endif struct mysql_frame_data *mysql_frame_data_p; /* get conversation, create if necessary*/ conversation= find_or_create_conversation(pinfo); /* get associated state information, create if necessary */ conn_data= (mysql_conn_data_t *)conversation_get_proto_data(conversation, proto_mysql); if (!conn_data) { conn_data = wmem_new0(wmem_file_scope(), mysql_conn_data_t); conn_data->stmts = wmem_tree_new(wmem_file_scope()); conversation_add_proto_data(conversation, proto_mysql, conn_data); } /* Using tvb_raw_offset(tvb) allows storage of multiple "proto data" in a single frame * (when there are multiple MySQL pdus in a single frame) */ mysql_frame_data_p = (struct mysql_frame_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_mysql, tvb_raw_offset(tvb)); if (!mysql_frame_data_p) { /* We haven't seen this frame before. Store the state of the * conversation now so if/when we dissect the frame again * we'll start with the same state. */ mysql_frame_data_p = wmem_new(wmem_file_scope(), struct mysql_frame_data); mysql_frame_data_p->state = conn_data->state; p_add_proto_data(wmem_file_scope(), pinfo, proto_mysql, tvb_raw_offset(tvb), mysql_frame_data_p); } if ((conn_data->frame_start_compressed) && (pinfo->num > conn_data->frame_start_compressed)) { if (conn_data->compressed_state == MYSQL_COMPRESS_ACTIVE) { mysql_dissect_compressed(tvb, offset, tree, pinfo, conn_data); return tvb_reported_length(tvb); } } ti = proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, ENC_NA); mysql_tree = proto_item_add_subtree(ti, ett_mysql); proto_tree_add_item(mysql_tree, hf_mysql_packet_length, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset+= 3; col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL"); if (pinfo->destport == pinfo->match_uint) { is_response= FALSE; } else { is_response= TRUE; } packet_number = tvb_get_guint8(tvb, offset); proto_tree_add_item(mysql_tree, hf_mysql_packet_number, tvb, offset, 1, ENC_NA); offset += 1; #ifdef CTDEBUG conn_state_in= conn_data->state; frame_state = mysql_frame_data_p->state; generation= conn_data->generation; if (tree) { pi = proto_tree_add_debug_text(mysql_tree, "conversation: %p", conversation); proto_item_set_generated(pi); pi = proto_tree_add_debug_text(mysql_tree, "generation: %" PRId64, generation); proto_item_set_generated(pi); pi = proto_tree_add_debug_text(mysql_tree, "conn state: %s (%u)", val_to_str(conn_state_in, state_vals, "Unknown (%u)"), conn_state_in); proto_item_set_generated(pi); pi = proto_tree_add_debug_text(mysql_tree, "frame state: %s (%u)", val_to_str(frame_state, state_vals, "Unknown (%u)"), frame_state); proto_item_set_generated(pi); } #endif is_tls = proto_is_frame_protocol(pinfo->layers, "tls"); if (is_response) { if (packet_number == 0 && mysql_frame_data_p->state == UNDEFINED) { col_set_str(pinfo->cinfo, COL_INFO, "Server Greeting "); offset = mysql_dissect_greeting(tvb, pinfo, offset, mysql_tree, conn_data); } else if ((mysql_frame_data_p->state == CLONE_ACTIVE) || (mysql_frame_data_p->state == CLONE_EXIT)) { col_set_str(pinfo->cinfo, COL_INFO, "Clone Response"); offset = mysql_dissect_clone_response(tvb, pinfo, offset, mysql_tree, conn_data, ti, mysql_frame_data_p->state); } else if (mysql_frame_data_p->state == AUTH_PUBKEY) { col_set_str(pinfo->cinfo, COL_INFO, "Public key "); offset = mysql_dissect_pubkey(tvb, pinfo, offset, mysql_tree, conn_data, ti, mysql_frame_data_p->state); } else { col_set_str(pinfo->cinfo, COL_INFO, "Response "); offset = mysql_dissect_response(tvb, pinfo, offset, mysql_tree, conn_data, ti, mysql_frame_data_p->state); } } else { if (mysql_frame_data_p->state == LOGIN && (packet_number == 1 || (packet_number == 2 && is_tls))) { 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 if ((mysql_frame_data_p->state == CLONE_ACTIVE) || (mysql_frame_data_p->state == CLONE_EXIT)) { col_set_str(pinfo->cinfo, COL_INFO, "Clone Request"); offset = mysql_dissect_clone_request(tvb, pinfo, offset, mysql_tree, conn_data, ti, mysql_frame_data_p->state); } else if (mysql_frame_data_p->state == AUTH_SHA2_RESPONSE) { col_set_str(pinfo->cinfo, COL_INFO, "Caching_sha2_password response"); offset = mysql_dissect_sha2_response(tvb, pinfo, offset, mysql_tree, conn_data, ti, mysql_frame_data_p->state); } else { col_set_str(pinfo->cinfo, COL_INFO, "Request"); offset = mysql_dissect_request(tvb, pinfo, offset, mysql_tree, conn_data, mysql_frame_data_p->state); } } #ifdef CTDEBUG conn_state_out= conn_data->state; ++(conn_data->generation); pi = proto_tree_add_debug_text(mysql_tree, "next proto state: %s (%u)", val_to_str(conn_state_out, state_vals, "Unknown (%u)"), conn_state_out); proto_item_set_generated(pi); #endif /* remaining payload indicates an error */ if (tvb_reported_length_remaining(tvb, offset) > 0) { ti = proto_tree_add_item(mysql_tree, hf_mysql_payload, tvb, offset, -1, ENC_NA); expert_add_info(pinfo, ti, &ei_mysql_dissector_incomplete); } return tvb_reported_length(tvb); } /* dissector entrypoint, handles TCP-desegmentation */ static int dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { tcp_dissect_pdus(tvb, pinfo, tree, mysql_desegment, 3, get_mysql_pdu_len, dissect_mysql_pdu, data); return tvb_reported_length(tvb); } /* protocol registration */ void proto_register_mysql(void) { static hf_register_info hf[]= { { &hf_mysql_packet_length, { "Packet Length", "mysql.packet_length", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_packet_number, { "Packet Number", "mysql.packet_number", FT_UINT8, BASE_DEC, NULL, 0x0, "Packet Number (now called: Sequence ID)", HFILL }}, { &hf_mysql_request, { "Request Command", "mysql.request", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_command, { "Command", "mysql.command", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mysql_command_vals_ext, 0x0, NULL, HFILL }}, { &hf_mysql_response_code, { "Response Code", "mysql.response_code", FT_UINT8, BASE_HEX, VALS(mysql_response_code_vals), 0x0, NULL, HFILL }}, { &hf_mysql_error_code, { "Error Code", "mysql.error_code", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_error_string, { "Error message", "mysql.error.message", FT_STRING, BASE_NONE, NULL, 0x0, "Error string in case of MySQL error message", HFILL }}, { &hf_mysql_sqlstate, { "SQL state", "mysql.sqlstate", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_message, { "Message", "mysql.message", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_server_greeting, { "Server Greeting", "mysql.server_greeting", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_protocol, { "Protocol", "mysql.protocol", FT_UINT8, BASE_DEC, NULL, 0x0, "Protocol Version", HFILL }}, { &hf_mysql_version, { "Version", "mysql.version", FT_STRINGZ, BASE_NONE, NULL, 0x0, "MySQL Version", HFILL }}, { &hf_mysql_session_track, { "Session Track", "mysql.session_track", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_type, { "Session tracking type", "mysql.session_track.type", FT_UINT8, BASE_DEC, VALS(mysql_session_track_type_vals), 0x0, NULL, HFILL }}, { &hf_mysql_session_track_length, { "Session tracking length", "mysql.session_track.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_data, { "Session tracking data", "mysql.session_track.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_data_length, { "Session tracking data length", "mysql.session_track.data.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_sysvar_length, { "System variable change Length", "mysql.session_track.sysvar.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_sysvar_name, { "System variable change Name", "mysql.session_track.sysvar.name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_sysvar_value, { "System variable change Value", "mysql.session_track.sysvar.value", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_schema_length, { "Schema change length", "mysql.session_track.schema.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_schema, { "Schema change", "mysql.session_track.schema", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_state_change, { "State change", "mysql.session_track.state_change", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_gtids_encoding, { "GTIDs encoding", "mysql.session_track.gtids.encoding", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_gtids_length, { "GTIDs length", "mysql.session_track.gtids.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_gtids, { "GTIDs", "mysql.session_track.gtids", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_transaction_characteristics_length, { "Transaction characteristics length", "mysql.session_track.transaction_characteristics.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_transaction_characteristics, { "Transaction characteristics", "mysql.session_track.transaction_characteristics", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_transaction_state_length, { "Transaction state length", "mysql.session_track.transaction_state.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_session_track_transaction_state, { "Transaction state", "mysql.session_track.transaction_state", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_caps_server, { "Server Capabilities", "mysql.caps.server", FT_UINT16, BASE_HEX, NULL, 0x0, "MySQL Capabilities", HFILL }}, { &hf_mysql_caps_client, { "Client Capabilities", "mysql.caps.client", FT_UINT16, BASE_HEX, NULL, 0x0, "MySQL Capabilities", HFILL }}, { &hf_mysql_cap_long_password, { "Long Password","mysql.caps.lp", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LP, NULL, HFILL }}, { &hf_mysql_cap_found_rows, { "Found Rows","mysql.caps.fr", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_FR, NULL, HFILL }}, { &hf_mysql_cap_long_flag, { "Long Column Flags","mysql.caps.lf", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LF, NULL, HFILL }}, { &hf_mysql_cap_connect_with_db, { "Connect With Database","mysql.caps.cd", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CD, NULL, HFILL }}, { &hf_mysql_cap_no_schema, { "Don't Allow database.table.column","mysql.caps.ns", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_NS, NULL, HFILL }}, { &hf_mysql_cap_compress, { "Can use compression protocol","mysql.caps.cp", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CP, NULL, HFILL }}, { &hf_mysql_cap_odbc, { "ODBC Client","mysql.caps.ob", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_OB, NULL, HFILL }}, { &hf_mysql_cap_local_files, { "Can Use LOAD DATA LOCAL","mysql.caps.li", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_LI, NULL, HFILL }}, { &hf_mysql_cap_ignore_space, { "Ignore Spaces before '('","mysql.caps.is", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IS, NULL, HFILL }}, { &hf_mysql_cap_change_user, { "Speaks 4.1 protocol (new flag)","mysql.caps.cu", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CU, NULL, HFILL }}, { &hf_mysql_cap_interactive, { "Interactive Client","mysql.caps.ia", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_IA, NULL, HFILL }}, { &hf_mysql_cap_ssl, { "Switch to SSL after handshake","mysql.caps.sl", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SL, NULL, HFILL }}, { &hf_mysql_cap_ignore_sigpipe, { "Ignore sigpipes","mysql.caps.ii", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_II, NULL, HFILL }}, { &hf_mysql_cap_transactions, { "Knows about transactions","mysql.caps.ta", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_TA, NULL, HFILL }}, { &hf_mysql_cap_reserved, { "Speaks 4.1 protocol (old flag)","mysql.caps.rs", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_RS, NULL, HFILL }}, { &hf_mysql_cap_secure_connect, { "Can do 4.1 authentication","mysql.caps.sc", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_SC, NULL, HFILL }}, { &hf_mysql_extcaps_server, { "Extended Server Capabilities", "mysql.extcaps.server", FT_UINT16, BASE_HEX, NULL, 0x0, "MySQL Extended Capabilities", HFILL }}, { &hf_mysql_extcaps_client, { "Extended Client Capabilities", "mysql.extcaps.client", FT_UINT16, BASE_HEX, NULL, 0x0, "MySQL Extended Capabilities", HFILL }}, { &hf_mysql_cap_multi_statements, { "Multiple statements","mysql.caps.ms", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MS, NULL, HFILL }}, { &hf_mysql_cap_multi_results, { "Multiple results","mysql.caps.mr", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MR, NULL, HFILL }}, { &hf_mysql_cap_ps_multi_results, { "PS Multiple results","mysql.caps.pm", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_PM, NULL, HFILL }}, { &hf_mysql_cap_plugin_auth, { "Plugin Auth","mysql.caps.pa", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_PA, NULL, HFILL }}, { &hf_mysql_cap_connect_attrs, { "Connect attrs","mysql.caps.ca", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CA, NULL, HFILL }}, { &hf_mysql_cap_plugin_auth_lenenc_client_data, { "Plugin Auth LENENC Client Data","mysql.caps.pm", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_AL, NULL, HFILL }}, { &hf_mysql_cap_client_can_handle_expired_passwords, { "Client can handle expired passwords","mysql.caps.ep", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_EP, NULL, HFILL }}, { &hf_mysql_cap_session_track, { "Session variable tracking","mysql.caps.session_track", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_ST, NULL, HFILL }}, { &hf_mysql_cap_deprecate_eof, { "Deprecate EOF","mysql.caps.deprecate_eof", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_DE, NULL, HFILL }}, { &hf_mysql_cap_optional_metadata, { "Client can handle optional resultset metadata","mysql.caps.optional_metadata", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_RM, NULL, HFILL }}, { &hf_mysql_cap_compress_zstd, { "ZSTD Compression Algorithm","mysql.caps.compress_zsd", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_ZS, NULL, HFILL }}, { &hf_mysql_cap_query_attrs, { "Query Attributes","mysql.caps.query_attrs", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_QA, NULL, HFILL }}, { &hf_mysql_cap_mf_auth, { "Multifactor Authentication","mysql.caps.mf_auth", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_MF, NULL, HFILL }}, { &hf_mysql_cap_cap_ext, { "Capability Extension","mysql.caps.cap_ext", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_CAPS_CE, NULL, HFILL }}, { &hf_mysql_cap_unused, { "Unused","mysql.caps.unused", FT_UINT16, BASE_HEX, NULL, MYSQL_CAPS_UNUSED, NULL, HFILL }}, { &hf_mysql_login_request, { "Login Request", "mysql.login_request", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_max_packet, { "MAX Packet", "mysql.max_packet", FT_UINT32, BASE_DEC, NULL, 0x0, "MySQL Max packet", HFILL }}, { &hf_mysql_charset, { "Charset", "mysql.charset", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mysql_collation_vals_ext, 0x0, "MySQL Charset", HFILL }}, { &hf_mariadb_charset, { "Charset", "mariadb.charset", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mariadb_collation_vals_ext, 0x0, "MySQL Charset", HFILL }}, { &hf_mysql_table_name, { "Table Name", "mysql.table_name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_user, { "Username", "mysql.user", FT_STRINGZ, BASE_NONE, NULL, 0x0, "Login Username", HFILL }}, { &hf_mysql_schema, { "Schema", "mysql.schema", FT_STRING, BASE_NONE, NULL, 0x0, "Login Schema", HFILL }}, { &hf_mysql_client_auth_plugin, { "Client Auth Plugin", "mysql.client_auth_plugin", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_connattrs, { "Connection Attributes", "mysql.connattrs", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_connattrs_length, { "Connection Attributes length", "mysql.connattrs.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_connattrs_attr, { "Connection Attribute", "mysql.connattrs.attr", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_connattrs_name_length, { "Connection Attribute Name Length", "mysql.connattrs.name.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_connattrs_name, { "Connection Attribute Name", "mysql.connattrs.name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_connattrs_value_length, { "Connection Attribute Value Length", "mysql.connattrs.value.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_connattrs_value, { "Connection Attribute Value", "mysql.connattrs.value", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_zstd_compression_level, { "ZSTD Compression Level", "mysql.compression.zstd_level", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_extmeta_data, { "Extended metadata data", "mysql.extmeta_data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_extmeta, { "Extended metadata", "mysql.extmeta", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_extmeta_length, { "Extended metadata length", "mysql.extmeta.length", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_extmeta_key, { "Extended metadata key", "mysql.extmeta.key", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_extmeta_type, { "Extended metadata type", "mysql.extmeta.type", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_extmeta_format, { "Extended metadata format", "mysql.extmeta.format", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_salt, { "Salt", "mysql.salt", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_salt2, { "Salt", "mysql.salt2", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_auth_plugin_length, { "Authentication Plugin Length", "mysql.auth_plugin.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_auth_plugin, { "Authentication Plugin", "mysql.auth_plugin", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_thread_id, { "Thread ID", "mysql.thread_id", FT_UINT32, BASE_DEC, NULL, 0x0, "MySQL Thread ID", HFILL }}, { &hf_mysql_server_language, { "Server Language", "mysql.server_language", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mysql_collation_vals_ext, 0x0, "MySQL Charset", HFILL }}, { &hf_mariadb_server_language, { "Server Language", "mariadb.server_language", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &mariadb_collation_vals_ext, 0x0, "MySQL Charset", HFILL }}, { &hf_mysql_server_status, { "Server Status", "mysql.server_status", FT_UINT16, BASE_HEX, NULL, 0x0, "MySQL Status", HFILL }}, { &hf_mysql_stat_it, { "In transaction", "mysql.stat.it", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_IT, NULL, HFILL }}, { &hf_mysql_stat_ac, { "AUTO_COMMIT", "mysql.stat.ac", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_AC, NULL, HFILL }}, { &hf_mysql_stat_mr, { "More results", "mysql.stat.mr", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MR, NULL, HFILL }}, { &hf_mysql_stat_mu, { "Multi query / Unused", "mysql.stat.mu", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MU, "Multi query / Unused with MySQL >= 5.6", HFILL }}, { &hf_mysql_stat_bi, { "Bad index used", "mysql.stat.bi", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BI, NULL, HFILL }}, { &hf_mysql_stat_ni, { "No index used", "mysql.stat.ni", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_NI, NULL, HFILL }}, { &hf_mysql_stat_cr, { "Cursor exists", "mysql.stat.cr", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_CR, NULL, HFILL }}, { &hf_mysql_stat_lr, { "Last row sent", "mysql.stat.lr", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_LR, NULL, HFILL }}, { &hf_mysql_stat_dr, { "Database dropped", "mysql.stat.dr", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_DR, NULL, HFILL }}, { &hf_mysql_stat_bs, { "No backslash escapes", "mysql.stat.bs", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_BS, NULL, HFILL }}, { &hf_mysql_stat_mc, { "Metadata changed", "mysql.stat.mc", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_MC, NULL, HFILL }}, { &hf_mysql_stat_session_state_changed, { "Session state changed", "mysql.stat.session_state_changed", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_SESSION_STATE_CHANGED, NULL, HFILL }}, { &hf_mysql_stat_query_was_slow, { "Query was slow", "mysql.stat.query_was_slow", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_QUERY_WAS_SLOW, NULL, HFILL }}, { &hf_mysql_stat_ps_out_params, { "PS Out Params", "mysql.stat.ps_out_params", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_PS_OUT_PARAMS, NULL, HFILL }}, { &hf_mysql_stat_trans_readonly, { "In Trans Readonly", "mysql.stat.trans_readonly", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_STAT_TRANS_READONLY, NULL, HFILL }}, { &hf_mysql_refresh, { "Refresh Option", "mysql.refresh", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_rfsh_grants, { "reload permissions", "mysql.rfsh.grants", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_GRANT, NULL, HFILL }}, { &hf_mysql_rfsh_log, { "flush logfiles", "mysql.rfsh.log", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_LOG, NULL, HFILL }}, { &hf_mysql_rfsh_tables, { "flush tables", "mysql.rfsh.tables", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_TABLES, NULL, HFILL }}, { &hf_mysql_rfsh_hosts, { "flush hosts", "mysql.rfsh.hosts", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_HOSTS, NULL, HFILL }}, { &hf_mysql_rfsh_status, { "reset statistics", "mysql.rfsh.status", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_STATUS, NULL, HFILL }}, { &hf_mysql_rfsh_threads, { "empty thread cache", "mysql.rfsh.threads", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_THREADS, NULL, HFILL }}, { &hf_mysql_rfsh_slave, { "flush slave status", "mysql.rfsh.slave", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_SLAVE, NULL, HFILL }}, { &hf_mysql_rfsh_master, { "flush master status", "mysql.rfsh.master", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MYSQL_RFSH_MASTER, NULL, HFILL }}, { &hf_mysql_unused, { "Unused", "mysql.unused", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_passwd, { "Password", "mysql.passwd", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_payload, { "Payload", "mysql.payload", FT_BYTES, BASE_NONE, NULL, 0x0, "Additional Payload", HFILL }}, { &hf_mysql_affected_rows, { "Affected Rows", "mysql.affected_rows", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_insert_id, { "Last INSERT ID", "mysql.insert_id", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_num_warn, { "Warnings", "mysql.warnings", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_stmt_id, { "Statement ID", "mysql.stmt_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_query_attributes, { "Query Attributes", "mysql.query_attrs", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_query_attributes_count, { "Count", "mysql.query_attrs_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_query_attributes_send_types_to_server, { "Send types to server", "mysql.query_attrs_send_types_to_server", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_query_attribute_name_type, { "Attribute Name Type", "mysql.query_attr_name_type", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_query_attribute_name, { "Attribute Name", "mysql.query_attr_name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_query_attribute_value, { "Attribute Value", "mysql.query_attr_value", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_query, { "Statement", "mysql.query", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_shutdown, { "Shutdown Level", "mysql.shutdown", FT_UINT8, BASE_DEC, VALS(mysql_shutdown_vals), 0x0, NULL, HFILL }}, { &hf_mysql_option, { "Option", "mysql.option", FT_UINT16, BASE_DEC, VALS(mysql_option_vals), 0x0, NULL, HFILL }}, { &hf_mysql_param, { "Parameter", "mysql.param", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_num_params, { "Number of parameter", "mysql.num_params", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_num_rows, { "Rows to fetch", "mysql.num_rows", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_flags4, { "Flags (unused)", "mysql.exec_flags", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_flags5, { "Flags", "mysql.exec_flags", FT_UINT8, BASE_DEC, VALS(mysql_exec_flags_vals), 0x0, NULL, HFILL }}, { &hf_mysql_new_parameter_bound_flag, { "New parameter bound flag", "mysql.new_parameter_bound_flag", FT_UINT8, BASE_DEC, VALS(mysql_new_parameter_bound_flag_vals), 0x0, NULL, HFILL }}, { &hf_mysql_exec_iter, { "Iterations (unused)", "mysql.exec_iter", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_position, { "Binlog Position", "mysql.binlog.position", FT_UINT32, BASE_DEC, NULL, 0x0, "Position to start at", HFILL }}, { &hf_mysql_binlog_position8, { "Binlog Position", "mysql.binlog.position8", FT_UINT64, BASE_DEC, NULL, 0x0, "Position to start at", HFILL }}, { &hf_mysql_binlog_flags, { "Binlog Flags", "mysql.binlog.flags", FT_UINT16, BASE_HEX, NULL, 0x0, "(currently not used; always 0)", HFILL }}, { &hf_mysql_binlog_server_id, { "Binlog server id", "mysql.binlog.server_id", FT_UINT32, BASE_DEC, NULL, 0x0, "server_id of the slave", HFILL }}, { &hf_mysql_binlog_slave_hostname_length, { "Slave hostname length", "mysql.binlog.slave_hostname_length", FT_UINT8, BASE_DEC, NULL, 0x0, "slave_hostname field length", HFILL }}, { &hf_mysql_binlog_slave_hostname, { "Slave hostname", "mysql.binlog.slave_hostname", FT_STRING, BASE_NONE, NULL, 0x0, "slave_hostname", HFILL }}, { &hf_mysql_binlog_slave_user_length, { "Slave user length", "mysql.binlog.slave_user_length", FT_UINT8, BASE_DEC, NULL, 0x0, "slave_hostname field length", HFILL }}, { &hf_mysql_binlog_slave_user, { "Slave user", "mysql.binlog.slave_user", FT_STRING, BASE_NONE, NULL, 0x0, "slave_user", HFILL }}, { &hf_mysql_binlog_slave_password_length, { "Slave password length", "mysql.binlog.slave_password_length", FT_UINT8, BASE_DEC, NULL, 0x0, "slave_password field length", HFILL }}, { &hf_mysql_binlog_slave_password, { "Slave password", "mysql.binlog.slave_password", FT_STRING, BASE_NONE, NULL, 0x0, "slave_password", HFILL }}, { &hf_mysql_binlog_slave_mysql_port, { "Slave MySQL port", "mysql.binlog.slave_mysql_port", FT_UINT16, BASE_DEC, NULL, 0x0, "slave's mysql port", HFILL }}, { &hf_mysql_binlog_replication_rank, { "Replication rank", "mysql.binlog.replication_rank", FT_UINT32, BASE_DEC, NULL, 0x0, "ignored", HFILL }}, { &hf_mysql_binlog_master_id, { "Master id", "mysql.binlog.master_id", FT_UINT32, BASE_HEX, NULL, 0x0, "master_id of the slave", HFILL }}, { &hf_mysql_binlog_file_name, { "Binlog file name", "mysql.binlog.file_name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_file_name_length, { "Binlog file name length", "mysql.binlog.file_name_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_gtid_data, { "Binlog GTID Data", "mysql.binlog.gtid_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_gtid_data_length, { "Binlog file GTID data length", "mysql.binlog.gtid_data_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_event_header_timestamp, { "Timestamp", "mysql.binlog.event_header.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_event_header_event_type, { "Binlog Event Type", "mysql.binlog.event_header.event_type", FT_UINT8, BASE_DEC, VALS(mysql_binlog_event_type_vals), 0x0, "event type", HFILL }}, { &hf_mysql_binlog_event_header_server_id, { "Server ID", "mysql.binlog.event_header.server_id", FT_UINT32, BASE_DEC, NULL, 0x0, "server-id of the originating mysql-server", HFILL }}, { &hf_mysql_binlog_event_header_event_size, { "Event Size", "mysql.binlog.event_header.event_size", FT_UINT32, BASE_DEC, NULL, 0x0, "size of the event (header, post-header, body)", HFILL }}, { &hf_mysql_binlog_event_header_log_position, { "Binlog Position", "mysql.binlog.event_header.log_position", FT_UINT32, BASE_DEC, NULL, 0x0, "position of the next event", HFILL }}, { &hf_mysql_binlog_event_header_flags, { "Binlog Event Flags", "mysql.binlog.event_header.flags", FT_UINT16, BASE_HEX, NULL, 0x0, "flag", HFILL }}, { &hf_mysql_binlog_event_checksum, { "Checksum", "mysql.binlog.event_checksum", FT_UINT32, BASE_HEX, NULL, 0x0, "binlog event checksum", HFILL }}, { &hf_mysql_binlog_event_heartbeat_v2, { "Binlog Event: HEARTBEAT_LOG_EVENT_V2", "mysql.binlog.event_heartbeat_v2", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_event_heartbeat_v2_otw, { "Entry", "mysql.binlog.event_heartbeat_v2_otw", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_event_heartbeat_v2_otw_type, { "Type", "mysql.binlog.event_heartbeat_v2_otw_type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_binlog_hb_event_filename, { "Binlog Filename", "mysql.binlog.hb_event.filename", FT_STRING, BASE_NONE, NULL, 0x0, "filename", HFILL }}, { &hf_mysql_binlog_hb_event_log_position, { "Binlog Position", "mysql.binlog.hb_event.log_position", FT_UINT64, BASE_DEC, NULL, 0x0, "position of the next event", HFILL }}, { &hf_mysql_clone_command_code, { "Clone Command Code", "mysql.clone.command_code", FT_UINT8, BASE_HEX, VALS(mysql_clone_command_vals), 0x0, NULL, HFILL }}, { &hf_mysql_clone_response_code, { "Clone Response Code", "mysql.clone.response_code", FT_UINT8, BASE_HEX, VALS(mysql_clone_response_vals), 0x0, NULL, HFILL }}, { &hf_mysql_eof, { "EOF marker", "mysql.eof", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_num_fields, { "Number of fields", "mysql.num_fields", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_send_meta, { "send metadata", "mysql.metadata_follows", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_extra, { "Extra data", "mysql.extra", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_fld_catalog, { "Catalog", "mysql.field.catalog", FT_STRING, BASE_NONE, NULL, 0x0, "Field: catalog", HFILL }}, { &hf_mysql_fld_db, { "Database", "mysql.field.db", FT_STRING, BASE_NONE, NULL, 0x0, "Field: database", HFILL }}, { &hf_mysql_fld_table, { "Table", "mysql.field.table", FT_STRING, BASE_NONE, NULL, 0x0, "Field: table", HFILL }}, { &hf_mysql_fld_org_table, { "Original table", "mysql.field.org_table", FT_STRING, BASE_NONE, NULL, 0x0, "Field: original table", HFILL }}, { &hf_mysql_fld_name, { "Name", "mysql.field.name", FT_STRING, BASE_NONE, NULL, 0x0, "Field: name", HFILL }}, { &hf_mysql_fld_org_name, { "Original name", "mysql.field.org_name", FT_STRING, BASE_NONE, NULL, 0x0, "Field: original name", HFILL }}, { &hf_mysql_fld_charsetnr, { "Charset number", "mysql.field.charsetnr", FT_UINT16, BASE_DEC|BASE_EXT_STRING, &mysql_collation_vals_ext, 0x0, "Field: charset number", HFILL }}, //{ &hf_mariadb_fld_charsetnr, //{ "Charset number", "mariadb.field.charsetnr", //FT_UINT16, BASE_DEC|BASE_EXT_STRING, &mariadb_collation_vals_ext, 0x0, //"Field: charset number", HFILL }}, { &hf_mysql_fld_length, { "Length", "mysql.field.length", FT_UINT32, BASE_DEC, NULL, 0x0, "Field: length", HFILL }}, { &hf_mysql_fld_type, { "Type", "mysql.field.type", FT_UINT8, BASE_DEC, VALS(type_constants), 0x0, "Field: type", HFILL }}, { &hf_mysql_fld_flags, { "Flags", "mysql.field.flags", FT_UINT16, BASE_HEX, NULL, 0x0, "Field: flags", HFILL }}, { &hf_mysql_fld_not_null, { "Not null", "mysql.field.flags.not_null", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_NOT_NULL_FLAG, "Field: flag not null", HFILL }}, { &hf_mysql_fld_primary_key, { "Primary key", "mysql.field.flags.primary_key", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_PRI_KEY_FLAG, "Field: flag primary key", HFILL }}, { &hf_mysql_fld_unique_key, { "Unique key", "mysql.field.flags.unique_key", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNIQUE_KEY_FLAG, "Field: flag unique key", HFILL }}, { &hf_mysql_fld_multiple_key, { "Multiple key", "mysql.field.flags.multiple_key", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_MULTIPLE_KEY_FLAG, "Field: flag multiple key", HFILL }}, { &hf_mysql_fld_blob, { "Blob", "mysql.field.flags.blob", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_BLOB_FLAG, "Field: flag blob", HFILL }}, { &hf_mysql_fld_unsigned, { "Unsigned", "mysql.field.flags.unsigned", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_UNSIGNED_FLAG, "Field: flag unsigned", HFILL }}, { &hf_mysql_fld_zero_fill, { "Zero fill", "mysql.field.flags.zero_fill", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ZEROFILL_FLAG, "Field: flag zero fill", HFILL }}, { &hf_mysql_null_buffer, { "Row null buffer", "mysql.row.nullbuffer", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_fld_enum, { "Enum", "mysql.field.flags.enum", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_ENUM_FLAG, "Field: flag enum", HFILL }}, { &hf_mysql_fld_auto_increment, { "Auto increment", "mysql.field.flags.auto_increment", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_AUTO_INCREMENT_FLAG, "Field: flag auto increment", HFILL }}, { &hf_mysql_fld_timestamp, { "Timestamp", "mysql.field.flags.timestamp", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_TIMESTAMP_FLAG, "Field: flag timestamp", HFILL }}, { &hf_mysql_fld_set, { "Set", "mysql.field.flags.set", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MYSQL_FLD_SET_FLAG, "Field: flag set", HFILL }}, { &hf_mysql_fld_decimals, { "Decimals", "mysql.field.decimals", 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_text, { "text", "mysql.row.text", FT_STRING, BASE_NONE, NULL, 0x0, "Field: row packet text", HFILL }}, { &hf_mysql_exec_param, { "Parameter", "mysql.exec_param", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_unsigned, { "Unsigned", "mysql.exec.unsigned", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_longlong, { "Value (INT64)", "mysql.exec.field.longlong", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_unsigned_longlong, { "Value (UINT64)", "mysql.exec.field.unsigned_longlong", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_string, { "Value (String)", "mysql.exec.field.string", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_double, { "Value (Double)", "mysql.exec.field.double", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_datetime_length, { "Length", "mysql.exec.field.datetime.length", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_year, { "Year", "mysql.exec.field.year", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_month, { "Month", "mysql.exec.field.month", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_day, { "Day", "mysql.exec.field.day", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_hour, { "Hour", "mysql.exec.field.hour", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_minute, { "Minute", "mysql.exec.field.minute", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_second, { "Second", "mysql.exec.field.second", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_second_b, { "Billionth of a second", "mysql.exec.field.secondb", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_long, { "Value (INT32)", "mysql.exec.field.long", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_unsigned_long, { "Value (UINT32)", "mysql.exec.field.unsigned_long", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_tiny, { "Value (INT8)", "mysql.exec.field.tiny", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_unsigned_tiny, { "Value (UINT8)", "mysql.exec.field.unsigned_tiny", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_short, { "Value (INT16)", "mysql.exec.field.short", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_unsigned_short, { "Value (UINT16)", "mysql.exec.field.unsigned_short", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_float, { "Value (Float)", "mysql.exec.field.float", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_null, { "Value: -NULL-", "mysql.exec.field.null", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_time_length, { "Length", "mysql.exec.field.time.length", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_time_sign, { "Flags", "mysql.exec.field.time.sign", FT_UINT8, BASE_DEC, VALS(mysql_exec_time_sign_vals), 0x0, NULL, HFILL }}, { &hf_mysql_exec_field_time_days, { "Days", "mysql.exec.field.time.days", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_auth_switch_request_status, { "Status", "mysql.auth_switch_request.status", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_auth_switch_request_name, { "Auth Method Name", "mysql.auth_switch_request.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_auth_switch_request_data, { "Auth Method Data", "mysql.auth_switch_request.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_auth_switch_response_data, { "Auth Method Data", "mysql.auth_switch_response.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_sha2_auth, { "SHA2 Auth State", "mysql.hf_mysql_sha2_auth.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_pubkey, { "Public Key", "mysql.hf_mysql_pubkey", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_sha2_response, { "SHA2 Auth Response", "mysql.hf_mysql_sha2_response", 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 }}, { &hf_mysql_loaddata_filename, { "LOCAL INFILE Filename", "mysql.load_data.filename", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mysql_loaddata_payload, { "LOCAL INFILE Payload", "mysql.load_data.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_cap_progress, { "Progress indication", "mariadb.caps.pr", FT_BOOLEAN, 32, TFS(&tfs_set_notset), MARIADB_CAPS_PR, NULL, HFILL }}, { &hf_mariadb_cap_commulti, { "Multi commands", "mariadb.caps.cm", FT_BOOLEAN, 32, TFS(&tfs_set_notset), MARIADB_CAPS_CM, NULL, HFILL }}, { &hf_mariadb_cap_bulk, { "Bulk Operations", "mariadb.caps.bo", FT_BOOLEAN, 32, TFS(&tfs_set_notset), MARIADB_CAPS_BO, NULL, HFILL }}, { &hf_mariadb_cap_extmetadata, { "Extended metadata", "mariadb.caps.em", FT_BOOLEAN, 32, TFS(&tfs_set_notset), MARIADB_CAPS_EM, NULL, HFILL }}, { &hf_mariadb_cap_cache_metadata, { "Cache metadata", "mariadb.caps.me", FT_BOOLEAN, 32, TFS(&tfs_set_notset), MARIADB_CAPS_ME, NULL, HFILL }}, { &hf_mariadb_extcaps_server, { "MariaDB Extended Server Capabilities", "mariadb.extcaps.server", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_extcaps_client, { "MariaDB Extended Client Capabilities", "mariadb.extcaps.client", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_bulk_flag_autoid, { "Return Generated Autoincrement IDs", "mariadb.bulk.flag.autoid", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MARIADB_BULK_AUTOID, NULL, HFILL }}, { &hf_mariadb_bulk_flag_sendtypes, { "Send Parameter Types", "mariadb.bulk.flag.sendtypes", FT_BOOLEAN, 16, TFS(&tfs_set_notset), MARIADB_BULK_SEND_TYPES, NULL, HFILL }}, { &hf_mariadb_bulk_caps_flags, { "MariaDB Bulk Capabilities", "mariadb.bulk.flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_bulk_paramtypes, { "Bulk Parameter Types", "mariadb.bulk.paramtypesg", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_mariadb_bulk_indicator, { "Indicator", "mariadb.bulk.indicators", FT_UINT8, BASE_HEX, VALS(mariadb_bulk_indicator_vals), 0x00, NULL, HFILL }}, { &hf_mariadb_bulk_row_nr, { "Row nr", "mariadb.bulk.row_nr", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, }; static gint *ett[]= { &ett_mysql, &ett_server_greeting, &ett_login_request, &ett_caps, &ett_extcaps, &ett_stat, &ett_row_value, &ett_request, &ett_refresh, &ett_field_flags, &ett_exec_param, &ett_bulk_param, &ett_session_track, &ett_session_track_data, &ett_extmeta, &ett_extmeta_data, &ett_connattrs, &ett_connattrs_attr, &ett_mysql_field, &ett_query_attributes, &ett_binlog_event, &ett_binlog_event_hb_v2 }; static ei_register_info ei[] = { { &ei_mysql_dissector_incomplete, { "mysql.dissector_incomplete", PI_UNDECODED, PI_WARN, "FIXME - dissector is incomplete", EXPFILL }}, { &ei_mysql_streamed_param, { "mysql.streamed_param", PI_SEQUENCE, PI_CHAT, "This parameter was streamed, its value can be found in Send BLOB packets", EXPFILL }}, { &ei_mysql_prepare_response_needed, { "mysql.prepare_response_needed", PI_UNDECODED, PI_WARN, "PREPARE Response packet is needed to dissect the payload", EXPFILL }}, { &ei_mysql_command, { "mysql.command.invalid", PI_PROTOCOL, PI_WARN, "Unknown/invalid command code", EXPFILL }}, { &ei_mysql_unknown_response, { "mysql.unknown_response", PI_UNDECODED, PI_WARN, "unknown/invalid response", EXPFILL }}, { &ei_mysql_invalid_length, { "mysql.invalid_length", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }}, { &ei_mysql_compression, { "mysql.uncompress_failure", PI_MALFORMED, PI_WARN, "Uncompression failed", EXPFILL }}, }; module_t *mysql_module; expert_module_t* expert_mysql; proto_mysql = proto_register_protocol("MySQL Protocol", "MySQL", "mysql"); proto_register_field_array(proto_mysql, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_mysql = expert_register_protocol(proto_mysql); expert_register_field_array(expert_mysql, ei, array_length(ei)); mysql_module = prefs_register_protocol(proto_mysql, NULL); prefs_register_bool_preference(mysql_module, "desegment_buffers", "Reassemble MySQL buffers spanning multiple TCP segments", "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); mysql_handle = register_dissector("mysql", dissect_mysql, proto_mysql); } /* dissector registration */ void proto_reg_handoff_mysql(void) { tls_handle = find_dissector("tls"); dissector_add_uint_with_preference("tcp.port", TCP_PORT_MySQL, mysql_handle); } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */