From Huagang Xie: dissector for MySQL protocol.
svn path=/trunk/; revision=6939
This commit is contained in:
parent
3e393a11f0
commit
96b2d60763
4
AUTHORS
4
AUTHORS
|
@ -1572,6 +1572,10 @@ Christian Falckenberg <christian.falckenberg [AT] nortelnetworks.com> {
|
|||
Initial MEGACO support
|
||||
}
|
||||
|
||||
Huagang Xie <xie [AT] lids.org> {
|
||||
MySQL support
|
||||
}
|
||||
|
||||
Alain Magloire <alainm[AT]rcsm.ece.mcgill.ca> was kind enough to
|
||||
give his permission to use his version of snprintf.c.
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Makefile.am
|
||||
# Automake file for Ethereal
|
||||
#
|
||||
# $Id: Makefile.am,v 1.539 2003/01/16 07:10:24 guy Exp $
|
||||
# $Id: Makefile.am,v 1.540 2003/01/19 21:29:08 guy Exp $
|
||||
#
|
||||
# Ethereal - Network traffic analyzer
|
||||
# By Gerald Combs <gerald@ethereal.com>
|
||||
|
@ -267,6 +267,7 @@ DISSECTOR_SRC = \
|
|||
packet-mtp2.c \
|
||||
packet-mtp3.c \
|
||||
packet-mtp3mg.c \
|
||||
packet-mysql.c \
|
||||
packet-nbipx.c \
|
||||
packet-nbns.c \
|
||||
packet-ncp.c \
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## Makefile for building ethereal.exe with Microsoft C and nmake
|
||||
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
|
||||
#
|
||||
# $Id: Makefile.nmake,v 1.270 2003/01/14 01:17:44 guy Exp $
|
||||
# $Id: Makefile.nmake,v 1.271 2003/01/19 21:29:08 guy Exp $
|
||||
|
||||
include config.nmake
|
||||
include <win32.mak>
|
||||
|
@ -210,6 +210,7 @@ DISSECTOR_SRC = \
|
|||
packet-mtp2.c \
|
||||
packet-mtp3.c \
|
||||
packet-mtp3mg.c \
|
||||
packet-mysql.c \
|
||||
packet-nbipx.c \
|
||||
packet-nbns.c \
|
||||
packet-ncp.c \
|
||||
|
|
|
@ -1685,6 +1685,7 @@ B<http://www.ethereal.com>.
|
|||
rmkml <rmkml [AT] wanadoo.fr>
|
||||
Anders Broman <a.broman [AT] telia.com>
|
||||
Christian Falckenberg <christian.falckenberg [AT] nortelnetworks.com>
|
||||
Huagang Xie <xie [AT] lids.org>
|
||||
|
||||
Alain Magloire <alainm[AT]rcsm.ece.mcgill.ca> was kind enough to give his
|
||||
permission to use his version of snprintf.c.
|
||||
|
|
|
@ -0,0 +1,837 @@
|
|||
/* packet-mysql.c
|
||||
* Routines for mysql packet dissection
|
||||
*
|
||||
* Huagang XIE <huagang@intruvert.com>
|
||||
*
|
||||
* $Id: packet-mysql.c,v 1.1 2003/01/19 21:29:08 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@ethereal.com>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* Copied from packet-tftp.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*
|
||||
* the protocol spec at
|
||||
* http://public.logicacmg.com/~redferni/mysql/MySQL-Protocol.html
|
||||
* and MySQL source code
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <epan/packet.h>
|
||||
#include <epan/conversation.h>
|
||||
|
||||
#include "packet-smb-common.h"
|
||||
#include "packet-frame.h"
|
||||
#include "reassemble.h"
|
||||
#include "prefs.h"
|
||||
|
||||
/* Capabilities */
|
||||
#define MYSQL_CAPS_LP 0x0001
|
||||
#define MYSQL_CAPS_FR 0x0002
|
||||
#define MYSQL_CAPS_LF 0x0004
|
||||
#define MYSQL_CAPS_CD 0x0008
|
||||
#define MYSQL_CAPS_NS 0x0010
|
||||
#define MYSQL_CAPS_CP 0x0020
|
||||
#define MYSQL_CAPS_OB 0x0040
|
||||
#define MYSQL_CAPS_LI 0x0080
|
||||
#define MYSQL_CAPS_IS 0x0100
|
||||
#define MYSQL_CAPS_CU 0x0200
|
||||
#define MYSQL_CAPS_IA 0x0400
|
||||
#define MYSQL_CAPS_SL 0x0800
|
||||
#define MYSQL_CAPS_II 0x1000
|
||||
#define MYSQL_CAPS_TA 0x2000
|
||||
|
||||
static int proto_mysql = -1;
|
||||
static int hf_mysql_packet_length= -1;
|
||||
static int hf_mysql_packet_number= -1;
|
||||
static int hf_mysql_opcode= -1;
|
||||
static int hf_mysql_response_code= -1;
|
||||
static int hf_mysql_error_code= -1;
|
||||
static int hf_mysql_payload= -1;
|
||||
static int hf_mysql_protocol= -1;
|
||||
static int hf_mysql_caps= -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_version = -1;
|
||||
static int hf_mysql_max_packet= -1;
|
||||
static int hf_mysql_user= -1;
|
||||
static int hf_mysql_password= -1;
|
||||
static int hf_mysql_thread_id = -1;
|
||||
static int hf_mysql_salt= -1;
|
||||
static int hf_mysql_charset= -1;
|
||||
static int hf_mysql_status= -1;
|
||||
static int hf_mysql_unused= -1;
|
||||
static int hf_mysql_parameter= -1;
|
||||
|
||||
static gint ett_mysql = -1;
|
||||
static gint ett_server_greeting = -1;
|
||||
static gint ett_caps = -1;
|
||||
static gint ett_request = -1;
|
||||
|
||||
|
||||
static dissector_handle_t mysql_handle;
|
||||
|
||||
static gboolean mysql_desegment = TRUE;
|
||||
|
||||
#define TCP_PORT_MySQL 3306
|
||||
|
||||
#define MySQL_SLEEP 0
|
||||
#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
|
||||
#define MySQL_PROCESS_KILL 12
|
||||
#define MySQL_DEBUG 13
|
||||
#define MySQL_PING 14
|
||||
#define MySQL_TIME 15
|
||||
#define MySQL_DELAY_INSERT 16
|
||||
#define MySQL_CHANGE_USER 17
|
||||
#define MySQL_BINLOG_DUMP 18
|
||||
#define MySQL_TABLE_DUMP 19
|
||||
#define MySQL_CONNECT_OUT 20
|
||||
|
||||
|
||||
static const value_string mysql_opcode_vals[] = {
|
||||
{ MySQL_SLEEP, "SLEEP" },
|
||||
{ MySQL_QUIT, "Quit" },
|
||||
{ MySQL_INIT_DB, "Init Database" },
|
||||
{ MySQL_QUERY, "Query" },
|
||||
{ MySQL_FIELD_LIST, "Field List" },
|
||||
{ MySQL_CREATE_DB, "Create Database" },
|
||||
{ MySQL_DROP_DB , "Drop Database" },
|
||||
{ MySQL_REFRESH , "Refresh" },
|
||||
{ MySQL_SHUTDOWN , "Shutdown" },
|
||||
{ MySQL_STATISTICS , "Statistics" },
|
||||
{ MySQL_PROCESS_INFO , "Process Info" },
|
||||
{ MySQL_CONNECT , "Connect" },
|
||||
{ MySQL_PROCESS_KILL , "Process Kill" },
|
||||
{ MySQL_DEBUG , "Debug" },
|
||||
{ MySQL_PING , "Ping" },
|
||||
{ MySQL_TIME , "Time" },
|
||||
{ MySQL_DELAY_INSERT , "Delay Insert" },
|
||||
{ MySQL_CHANGE_USER , "Change User" },
|
||||
{ MySQL_BINLOG_DUMP , "Binlog Dump" },
|
||||
{ MySQL_TABLE_DUMP, "Table Dump" },
|
||||
{ MySQL_CONNECT_OUT, "Table Connect Out" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const value_string mysql_status_vals[] = {
|
||||
{1, "IN_TRANS" },
|
||||
{2, "AUTOCOMMIT"},
|
||||
{ 0, NULL }
|
||||
};
|
||||
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}
|
||||
};
|
||||
#if 0
|
||||
static const value_string mysql_error_code_vals[] = {
|
||||
{ 0, "Not defined" },
|
||||
{ 1, "File not found" },
|
||||
{ 2, "Access violation" },
|
||||
{ 3, "Disk full or allocation exceeded" },
|
||||
{ 4, "Illegal MySQL Operation" },
|
||||
{ 5, "Unknown transfer ID" },
|
||||
{ 6, "File already exists" },
|
||||
{ 7, "No such user" },
|
||||
{ 8, "Option negotiation failed" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
static int mysql_dissect_server_greeting(tvbuff_t *tvb, packet_info *pinfo,
|
||||
int offset, proto_tree *tree);
|
||||
static int mysql_dissect_authentication(tvbuff_t *tvb, packet_info *pinfo,
|
||||
int offset, proto_tree *tree);
|
||||
static int mysql_dissect_request(tvbuff_t *tvb, packet_info *pinfo,
|
||||
int offset, proto_tree *tree);
|
||||
static int mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo,
|
||||
int offset, proto_tree *tree);
|
||||
|
||||
static void
|
||||
dissect_mysql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
||||
{
|
||||
proto_tree *mysql_tree = NULL;
|
||||
proto_item *ti;
|
||||
conversation_t *conversation;
|
||||
|
||||
gint offset = 0;
|
||||
gint this_offset = 0;
|
||||
guint32 packet_length;
|
||||
guint packet_number;
|
||||
|
||||
guint i1=0;
|
||||
|
||||
guint is_response=0;
|
||||
guint32 length;
|
||||
|
||||
conversation = find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype,
|
||||
pinfo->srcport, pinfo->destport, 0);
|
||||
|
||||
if (!conversation) {
|
||||
/* create a new conversation */
|
||||
conversation = conversation_new(&pinfo->src, &pinfo->dst, pinfo->ptype,
|
||||
pinfo->srcport, pinfo->destport, 0);
|
||||
/* reset some counter */
|
||||
offset = this_offset = 0;
|
||||
}
|
||||
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_PROTOCOL))
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, "MySQL");
|
||||
|
||||
if (pinfo->destport == TCP_PORT_MySQL) {
|
||||
is_response=0;
|
||||
}else {
|
||||
is_response=1;
|
||||
}
|
||||
|
||||
while (tvb_reported_length_remaining(tvb, offset) != 0) {
|
||||
/*
|
||||
* We use "tvb_ensure_length_remaining()" to make sure
|
||||
* there actually *is* data remaining.
|
||||
*/
|
||||
length = tvb_ensure_length_remaining(tvb, offset);
|
||||
|
||||
this_offset = offset;
|
||||
|
||||
packet_length = tvb_get_letoh24(tvb, offset);
|
||||
/* check if reassembly is needed */
|
||||
if (mysql_desegment && pinfo->can_desegment) {
|
||||
if(packet_length+4 > length) {
|
||||
pinfo->desegment_offset = offset;
|
||||
pinfo->desegment_len = packet_length + 4 - length;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (tree) {
|
||||
ti = proto_tree_add_item(tree, proto_mysql, tvb, offset, -1, FALSE);
|
||||
mysql_tree = proto_item_add_subtree(ti, ett_mysql);
|
||||
|
||||
proto_tree_add_uint(mysql_tree, hf_mysql_packet_length, tvb,
|
||||
offset, 3, packet_length);
|
||||
}
|
||||
offset += 3;
|
||||
/* packet number */
|
||||
packet_number= tvb_get_guint8(tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_uint(mysql_tree, hf_mysql_packet_number, tvb,
|
||||
offset, 1, packet_number);
|
||||
}
|
||||
offset += 1;
|
||||
|
||||
/*
|
||||
* packet == 0 && response --> server greeting
|
||||
* packet == 1 && request --> login request
|
||||
*/
|
||||
if(is_response ) {
|
||||
if( packet_number == 0 ) {
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "Server Greeting" ) ;
|
||||
}
|
||||
offset = mysql_dissect_server_greeting(tvb,pinfo,offset,mysql_tree);
|
||||
}else {
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "Response" ) ;
|
||||
}
|
||||
offset = mysql_dissect_response(tvb,pinfo,offset,mysql_tree);
|
||||
}
|
||||
} else {
|
||||
if( packet_number == 1 ) {
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "Login Request") ;
|
||||
}
|
||||
offset = mysql_dissect_authentication(tvb,pinfo,offset,mysql_tree);
|
||||
}else {
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "Request") ;
|
||||
}
|
||||
offset = mysql_dissect_request(tvb,pinfo,offset,mysql_tree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* paylod */
|
||||
if(packet_length+4 > length) {
|
||||
if (mysql_desegment && pinfo->can_desegment) {
|
||||
i1 = packet_length-offset+this_offset+4;
|
||||
} else {
|
||||
/* increase by 1 to make the display or unassembly packet */
|
||||
i1 = length-offset+this_offset+4;
|
||||
}
|
||||
} else {
|
||||
i1 = packet_length-offset+this_offset+4;
|
||||
}
|
||||
if (tree && i1 > 0) {
|
||||
proto_tree_add_item(mysql_tree, hf_mysql_payload,
|
||||
tvb, offset, i1, FALSE);
|
||||
}
|
||||
offset += i1;
|
||||
}
|
||||
pinfo->desegment_offset = 0;
|
||||
pinfo->desegment_len = 0;
|
||||
}
|
||||
static int
|
||||
mysql_dissect_response(tvbuff_t *tvb, packet_info *pinfo,
|
||||
int offset, proto_tree *tree)
|
||||
{
|
||||
gint response_code;
|
||||
gint error_code;
|
||||
|
||||
/* response code */
|
||||
response_code= tvb_get_guint8(tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_uint(tree, hf_mysql_response_code, tvb,
|
||||
offset, 1, response_code);
|
||||
}
|
||||
offset +=1;
|
||||
|
||||
if(response_code== 0xff ) {
|
||||
/* error code */
|
||||
error_code = tvb_get_letohs(tvb, offset);
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " Error Code: %x", error_code );
|
||||
}
|
||||
if (tree) {
|
||||
proto_tree_add_uint(tree, hf_mysql_error_code, tvb,
|
||||
offset, 2, error_code);
|
||||
}
|
||||
offset +=2;
|
||||
|
||||
} else {
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_str(pinfo->cinfo, COL_INFO, " OK" );
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int
|
||||
mysql_dissect_request(tvbuff_t *tvb,packet_info *pinfo,
|
||||
int offset, proto_tree *tree)
|
||||
{
|
||||
gint opcode;
|
||||
gint strlen;
|
||||
proto_item *tf;
|
||||
proto_item *req_tree=NULL;
|
||||
|
||||
if(tree) {
|
||||
tf=proto_tree_add_text(tree,tvb,offset,-1,"Command");
|
||||
req_tree = proto_item_add_subtree(tf ,ett_request);
|
||||
}
|
||||
|
||||
opcode = tvb_get_guint8(tvb, offset);
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " Command: %s",
|
||||
val_to_str(opcode, mysql_opcode_vals, "Unknown (%u)"));
|
||||
}
|
||||
|
||||
if (req_tree) {
|
||||
proto_tree_add_uint_format(req_tree, hf_mysql_opcode, tvb,
|
||||
offset , 1, opcode, "Command: %s (%u)",
|
||||
val_to_str(opcode, mysql_opcode_vals, "Unknown (%u)"),opcode);
|
||||
}
|
||||
/* command parameter */
|
||||
|
||||
offset += 1;
|
||||
if ( (strlen = tvb_length_remaining(tvb,offset)) > 0 ) {
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " : %s",
|
||||
tvb_memdup(tvb,offset,strlen));
|
||||
}
|
||||
|
||||
if (tree) {
|
||||
proto_tree_add_item(req_tree, hf_mysql_parameter, tvb,
|
||||
offset, strlen, FALSE );
|
||||
}
|
||||
offset +=strlen;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mysql_dissect_authentication(tvbuff_t *tvb, packet_info *pinfo,
|
||||
int offset, proto_tree *tree)
|
||||
{
|
||||
gint16 client_caps;
|
||||
gint32 max_packet;
|
||||
gint strlen;
|
||||
|
||||
proto_item *tf;
|
||||
proto_item *cap_tree;
|
||||
proto_item *login_tree=NULL;
|
||||
|
||||
if(tree) {
|
||||
tf=proto_tree_add_text(tree,tvb,offset,-1,"Login Packet");
|
||||
login_tree = proto_item_add_subtree(tf ,ett_server_greeting);
|
||||
}
|
||||
|
||||
client_caps= tvb_get_letohs(tvb, offset);
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " Caps: 0x%x",client_caps) ;
|
||||
}
|
||||
if(tree) {
|
||||
tf = proto_tree_add_uint_format(login_tree, hf_mysql_caps, tvb, offset , 1, client_caps, "Caps: 0x%04x ", client_caps );
|
||||
cap_tree = proto_item_add_subtree(tf, ett_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, client_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, client_caps);
|
||||
}
|
||||
|
||||
/* proto_tree_add_uint(tree, hf_mysql_client_caps, tvb,
|
||||
offset, 2, client_caps);
|
||||
*/
|
||||
offset +=2;
|
||||
/* 3 bytes max packet, 16777216 - x */
|
||||
max_packet = 0xffffff - tvb_get_letoh24(tvb, offset);
|
||||
if(tree) {
|
||||
proto_tree_add_uint(login_tree, hf_mysql_max_packet, tvb,
|
||||
offset, 3, max_packet);
|
||||
}
|
||||
offset +=3;
|
||||
/* User name */
|
||||
strlen = tvb_strsize(tvb,offset);
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " ,user: %s",
|
||||
tvb_get_ptr(tvb,offset,strlen));
|
||||
}
|
||||
if (tree) {
|
||||
proto_tree_add_item(login_tree, hf_mysql_user, tvb,
|
||||
offset, strlen, FALSE );
|
||||
}
|
||||
offset +=strlen;
|
||||
|
||||
/* Password */
|
||||
strlen = tvb_length_remaining(tvb,offset);
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " ,password: %s",
|
||||
tvb_get_ptr(tvb,offset,strlen));
|
||||
}
|
||||
if (tree) {
|
||||
proto_tree_add_item(login_tree, hf_mysql_password, tvb,
|
||||
offset, strlen, FALSE );
|
||||
}
|
||||
offset +=strlen;
|
||||
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mysql_dissect_server_greeting(tvbuff_t *tvb, packet_info *pinfo,
|
||||
int offset, proto_tree *tree)
|
||||
{
|
||||
gint protocol;
|
||||
gint strlen;
|
||||
gint32 thread_id;
|
||||
gint16 server_caps;
|
||||
gint charset;
|
||||
gint16 status;
|
||||
|
||||
proto_item *tf;
|
||||
proto_item *greeting_tree=NULL;
|
||||
proto_item *cap_tree;
|
||||
|
||||
protocol= tvb_get_guint8(tvb, offset);
|
||||
|
||||
if(tree) {
|
||||
tf = proto_tree_add_text(tree,tvb,offset,-1,"Server Greeting");
|
||||
greeting_tree = proto_item_add_subtree(tf ,ett_server_greeting);
|
||||
}
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " Protocol : %d",protocol) ;
|
||||
}
|
||||
if (tree) {
|
||||
proto_tree_add_uint(greeting_tree, hf_mysql_protocol, tvb,
|
||||
offset, 1, protocol);
|
||||
}
|
||||
offset +=1;
|
||||
/* version string */
|
||||
|
||||
strlen = tvb_strsize(tvb,offset);
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " ,version: %s",
|
||||
tvb_get_ptr(tvb,offset,strlen));
|
||||
}
|
||||
if (tree) {
|
||||
proto_tree_add_item(greeting_tree, hf_mysql_version, tvb,
|
||||
offset, strlen, FALSE );
|
||||
}
|
||||
offset +=strlen;
|
||||
|
||||
/* 4 bytes little endian thread_id */
|
||||
thread_id = tvb_get_letohl(tvb, offset);
|
||||
if(tree) {
|
||||
proto_tree_add_uint(greeting_tree, hf_mysql_thread_id, tvb,
|
||||
offset, 4, thread_id);
|
||||
}
|
||||
offset +=4;
|
||||
/* salt string */
|
||||
strlen = tvb_strsize(tvb,offset);
|
||||
if (tree) {
|
||||
proto_tree_add_item(greeting_tree, hf_mysql_salt, tvb,
|
||||
offset, strlen, FALSE );
|
||||
}
|
||||
offset +=strlen;
|
||||
/* 2 bytes CAPS */
|
||||
server_caps= tvb_get_letohs(tvb, offset);
|
||||
|
||||
if (check_col(pinfo->cinfo, COL_INFO)) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " Caps: 0x%x",server_caps) ;
|
||||
}
|
||||
if(tree) {
|
||||
tf = proto_tree_add_uint_format(greeting_tree, hf_mysql_caps, tvb, offset , 1, server_caps, "Caps: 0x%04x ", server_caps );
|
||||
cap_tree = proto_item_add_subtree(tf, ett_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_password, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_found_rows, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_long_flag, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_connect_with_db, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_no_schema, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_compress, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_odbc, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_local_files, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_space, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_change_user, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_interactive, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_ssl, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_ignore_sigpipe, tvb, offset, 2, server_caps);
|
||||
proto_tree_add_boolean(cap_tree, hf_mysql_cap_transactions, tvb, offset, 2, server_caps);
|
||||
}
|
||||
offset+=2;
|
||||
/* 1 byte charset */
|
||||
charset = tvb_get_guint8(tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_uint_format(greeting_tree, hf_mysql_charset, tvb,
|
||||
offset, 1, charset, "Charset: %s (%u)",
|
||||
val_to_str(charset, mysql_charset_vals, "Unknown (%u)"), charset);
|
||||
}
|
||||
offset +=1;
|
||||
/* 2 byte status */
|
||||
status = tvb_get_letohs(tvb, offset);
|
||||
if (tree) {
|
||||
proto_tree_add_uint_format(greeting_tree, hf_mysql_status, tvb,
|
||||
offset, 2, status, "Status: %s (%u)",
|
||||
val_to_str(status, mysql_status_vals, "Unknown (%u)"), status);
|
||||
}
|
||||
offset +=2;
|
||||
/* other unused */
|
||||
strlen = tvb_length_remaining(tvb,offset);
|
||||
|
||||
if (tree) {
|
||||
proto_tree_add_item(greeting_tree, hf_mysql_unused, tvb,
|
||||
offset, strlen, FALSE );
|
||||
}
|
||||
offset +=strlen;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
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,
|
||||
"MySQL packet length", HFILL }},
|
||||
|
||||
{ &hf_mysql_packet_number,
|
||||
{ "Packet Number", "mysql.packet_number",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Packet Number", HFILL }},
|
||||
|
||||
{ &hf_mysql_opcode,
|
||||
{ "Command", "mysql.opcode",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
"MySQL OPCODE", HFILL }},
|
||||
|
||||
{ &hf_mysql_response_code,
|
||||
{ "Response Code", "mysql.response_code",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Respone Code", HFILL }},
|
||||
|
||||
{ &hf_mysql_error_code,
|
||||
{ "Error Code", "mysql.error_code",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Error CODE", HFILL }},
|
||||
|
||||
{ &hf_mysql_protocol,
|
||||
{ "Protocol", "mysql.protocol",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Protocol", HFILL }},
|
||||
|
||||
{ &hf_mysql_version,
|
||||
{ "Version", "mysql.version",
|
||||
FT_STRINGZ, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Version", HFILL }},
|
||||
|
||||
{ &hf_mysql_caps,
|
||||
{ "Caps", "mysql.caps",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Capabilities", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_long_password,
|
||||
{ "Long Password","tcp.caps.lp",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_LP,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_found_rows,
|
||||
{ "Found Rows","tcp.caps.fr",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_FR,
|
||||
"", HFILL }},
|
||||
|
||||
|
||||
{ &hf_mysql_cap_long_flag,
|
||||
{ "Long Flag","tcp.caps.lf",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_LF,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_connect_with_db,
|
||||
{ "Connect With Database","tcp.caps.cd",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_CD,
|
||||
"", HFILL }},
|
||||
|
||||
|
||||
{ &hf_mysql_cap_no_schema,
|
||||
{ "Dont Allow database.table.column","tcp.caps.ns",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_NS,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_compress,
|
||||
{ "Can use compression protocol","tcp.caps.CP",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_CP,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_odbc,
|
||||
{ "ODBC Client","tcp.caps.ob",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_OB,
|
||||
"", HFILL }},
|
||||
|
||||
|
||||
{ &hf_mysql_cap_local_files,
|
||||
{ "Can Use LOAD DATA LOCAL","tcp.caps.li",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_LI,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_ignore_space,
|
||||
{ "Ignore Spaces before (","tcp.caps.is",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_IS,
|
||||
"", HFILL }},
|
||||
|
||||
|
||||
{ &hf_mysql_cap_change_user,
|
||||
{ "Support the mysql_change_user()","tcp.caps.cu",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_CU,
|
||||
"", HFILL }},
|
||||
|
||||
|
||||
{ &hf_mysql_cap_interactive,
|
||||
{ "an Interactive Client","tcp.caps.ia",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_IA,
|
||||
"", HFILL }},
|
||||
|
||||
|
||||
{ &hf_mysql_cap_ssl,
|
||||
{ "Switch to SSL after handshake","tcp.caps.sl",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_SL,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_ignore_sigpipe,
|
||||
{ "Ignore sigpipes","tcp.caps.ii",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_II,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_cap_transactions,
|
||||
{ "Client knows about transactions","tcp.caps.ta",
|
||||
FT_BOOLEAN, 16, TFS(&flags_set_truth), MYSQL_CAPS_TA,
|
||||
"", HFILL }},
|
||||
|
||||
{ &hf_mysql_max_packet,
|
||||
{ "MAX Packet", "mysql.max_packet",
|
||||
FT_UINT24, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Max packet", HFILL }},
|
||||
|
||||
{ &hf_mysql_user,
|
||||
{ "Username", "mysql.user",
|
||||
FT_STRINGZ, BASE_DEC, NULL, 0x0,
|
||||
"Login Username", HFILL }},
|
||||
|
||||
{ &hf_mysql_password,
|
||||
{ "Password", "mysql.password",
|
||||
FT_STRING, BASE_DEC, NULL, 0x0,
|
||||
"Login Password", HFILL }},
|
||||
|
||||
{ &hf_mysql_salt,
|
||||
{ "Salt", "mysql.salt",
|
||||
FT_STRINGZ, BASE_DEC, NULL, 0x0,
|
||||
"Salt", HFILL }},
|
||||
|
||||
{ &hf_mysql_thread_id,
|
||||
{ "Thread ID", "mysql.thread_id",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Thread ID", HFILL }},
|
||||
|
||||
{ &hf_mysql_charset,
|
||||
{ "Charset", "mysql.charset",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Charset", HFILL }},
|
||||
|
||||
{ &hf_mysql_status,
|
||||
{ "Status", "mysql.status",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Status", HFILL }},
|
||||
|
||||
{ &hf_mysql_unused,
|
||||
{ "Unused", "mysql.unused",
|
||||
FT_STRING, BASE_DEC, NULL, 0x0,
|
||||
"Unused", HFILL }},
|
||||
|
||||
{ &hf_mysql_parameter,
|
||||
{ "Parameter", "mysql.parameter",
|
||||
FT_STRING, BASE_DEC, NULL, 0x0,
|
||||
"Parameter", HFILL }},
|
||||
{ &hf_mysql_payload,
|
||||
{ "Payload", "mysql.payload",
|
||||
FT_STRING, BASE_DEC, NULL, 0x0,
|
||||
"MySQL Payload", HFILL }},
|
||||
|
||||
|
||||
};
|
||||
#if 0
|
||||
{ &hf_mysql_destination_file,
|
||||
{ "DESTINATION File", "mysql.destination_file",
|
||||
FT_STRINGZ, BASE_DEC, NULL, 0x0,
|
||||
"MySQL source file name", HFILL }},
|
||||
|
||||
{ &hf_mysql_blocknum,
|
||||
{ "Block", "mysql.block",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
"Block number", HFILL }},
|
||||
|
||||
{ &hf_mysql_error_code,
|
||||
{ "Error code", "mysql.error.code",
|
||||
FT_UINT16, BASE_DEC, VALS(mysql_error_code_vals), 0x0,
|
||||
"Error code in case of MySQL error message", HFILL }},
|
||||
|
||||
{ &hf_mysql_error_string,
|
||||
{ "Error message", "mysql.error.message",
|
||||
FT_STRINGZ, BASE_DEC, NULL, 0x0,
|
||||
"Error string in case of MySQL error message", HFILL }}
|
||||
#endif
|
||||
static gint *ett[] = {
|
||||
&ett_mysql,
|
||||
&ett_server_greeting,
|
||||
&ett_caps,
|
||||
&ett_request,
|
||||
};
|
||||
module_t *mysql_module;
|
||||
|
||||
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));
|
||||
|
||||
mysql_handle = create_dissector_handle(dissect_mysql, proto_mysql);
|
||||
|
||||
mysql_module = prefs_register_protocol(proto_mysql, NULL);
|
||||
prefs_register_bool_preference(mysql_module, "desegment_buffers",
|
||||
"Desegment all MySQL buffers spanning multiple TCP segments",
|
||||
"Whether the MySQL dissector should desegment all MySQL buffers spanning multiple TCP segments",
|
||||
&mysql_desegment);
|
||||
}
|
||||
|
||||
void
|
||||
proto_reg_handoff_mysql(void)
|
||||
{
|
||||
dissector_add("tcp.port", TCP_PORT_MySQL, mysql_handle);
|
||||
}
|
Loading…
Reference in New Issue