mysql协议分析_mysql协议分析

完整代码git: https://git.oschina.net/kfeicat/protocolAnalyse.git

参考资料:

mysql起始握手,先由server发起,client分析并回应自已同意的特性,然后双方依照这些特性处理数据包。

通信时是否采用压缩会改变数据包的字节变化。

客户端的特性在首个回应(既握手包)服务器中体现,如:是否开启压缩、字符集、用户登录信息等。

1.未采用压缩时,客户端向服务器发送的包格式:

格式:3*byte,1*byte,1*byte,n*byte

表示:消息长度,包序号,请求类型,请求内容

2.采用压缩后,客户端向服务器发送的包格式:

格式:3*byte,1*byte,3*byte,n*byte

表示:消息长度,包序号,压缩包大小,压缩包内容

当压缩包大小为0x00时,表示当前包未采用压缩,则n*byte内容为1*byte,n*byte,既请求类型,请求内容

当压缩包大小大于0x00时,表示当前包已采用zlib压缩,则n*byte内容,先解压缩,解压后内容为1*byte,n*byte,既请求类型,请求内容。

package mysql;

import java.io.IOException;

import java.io.OutputStream;

import java.io.UnsupportedEncodingException;

import java.util.HashMap;

import java.util.Map;

/**

* 支持mysql 4.1+,不支持ssl

* @author shanl

*

*/

public class MysqlAnalyse {

/**传输包默认最大长度16M*/

public static final int PACKET_MAXIMUM_LENGTH = 1024*1024*16;

Map properties = new HashMap();

//StringBuilder sql = new StringBuilder();

long requestType = -1;

boolean endPacket = true;

//int packetLen = PACKET_MAXIMUM_LENGTH;

byte[] _packet = null;

int _off = 0;

int _len = 0;

/**

* 默认开启压缩、utf-8编码

*/

public MysqlAnalyse(){

this.setProperty("compress", true);

this.setProperty("encoding", "utf-8");

}

/**

通过客户端向服务端回应的握手包,获得一个MysqlAnlayse实例。 

* 建立连接时,server先向client发送握手包,此包包括server支持的特性和编码等信息,

* client回应包中需要说明本地支持什么特性,比如是否支持(zlib)压缩。

* @param buff

* @param off

* @param len

* @return

* @see 

* http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse

*/

public static MysqlAnalyse handshake(byte[] buff,int off,int len){

MysqlAnalyse anly = new MysqlAnalyse();

//2 byte,capability_flags

long capability_flags = Util.littleBys2Uint32(new byte[]{

buff[off],buff[off+1]

}, 0, 2);

//4byte,前2byte表示mysql特性(如下:是否开启压缩),后2byte客户端扩展特性

boolean compress = CapabilityFlag.CLIENT_COMPRESS==(CapabilityFlag.CLIENT_COMPRESS & capability_flags);

anly.setProperty("compress", compress);

//4byte,最大发送包字节数

long max_packet_size = Util.littleBys2Uint32(new byte[]{

buff[off+4],buff[off+5],

buff[off+6],buff[off+7]

}, 0, 4);

anly.setProperty("max.packet.size", max_packet_size);

//1byte,字符编码

short character_set_id = buff[8];

String character_set = "utf-8"; //需要分析

//SET NAMES utf8; 显示客户端发送的SQL语句中使用什么字符集

anly.setProperty("encoding", character_set);

return anly;

}

/**

 解析数据包   

未压缩:指客户端已开启压缩功能,但数据包本身不值得压缩,所以未进行压缩。

未开启压缩:指客户端未开启压缩功能,比如:./mysql 没有加-C, --compress参数。

客户端开启压缩功能后,向服务器发送数据包时,将会在包头(3+1字节)后,额外多3个字节,

表示压缩包大小,如果此值为0x000000(小端字节顺),则表示数据未压缩。

* @param buff

* @param off

* @param len

* @return 如果是最后一个包返回true

*/

public boolean parse(byte[] packet,int off,int len){

//sql = endPacket? new StringBuilder():sql;

//_buff = (null==_buff? new byte[packetLen]: _buff);

//_buff = packet;

//_off = off;

//_len = len;

if((Boolean)properties.get("compress")){

endPacket=compress(packet,off,len);

}else{

endPacket=noncompress(packet,off,len);

}

return endPacket;

}

/**

* (客户端)支持压缩

* @param packet

* @param off

* @param len

*/

boolean compress(byte[] packet,int off,int len){

long tranPackLen = Util.littleBys2Uint32(packet,off+0,3); //3 byte,传输包长度,此长度已经-7

short tranPackNo = packet[off+3];//1 byte,传输包序号

long compressPackLen = Util.littleBys2Uint32(packet,off+4,3);//3 byte,压缩后包长度

//未压缩

if(0x000000==compressPackLen){

long srcLen = Util.littleBys2Uint32(packet,off+3+1+3,4)-1;//4byte,(包含类型信息的)源数据长度

this.requestType = packet[off+3+1+3+4];//1byte,类型信息

_packet = packet;

_off = off+3+1+3;

_len = (int)srcLen;

//sql.append(toSql(packet, off+3+1+3, (int)srcLen));

}else{ //已压缩

byte[] src = Util.decompress(packet,off+3+1+3,

(int)tranPackLen,(int)compressPackLen);//n byte,src为zlib解压后的源数据

long srcLen = Util.littleBys2Uint32(src,0,4)-1;//4byte,(包含类型信息的)源数据长度

this.requestType = src[4];//1byte,类型信息

_packet = src;

_off = 0;

_len = (int) srcLen;

//sql.append(toSql(src,0,(int)srcLen));

}

return 0x00==tranPackNo;

}

/**

* (客户端)不支持压缩

* @param packet

* @param off

* @param len

*/

boolean noncompress(byte[] packet,int off,int len){

long tranPackLen = Util.littleBys2Uint32(packet,off+0,3); //3 byte

short tranPackNo = packet[off+3];//1 byte

this.requestType = packet[off+4];//1 byte

//sql.append(toSql(packet,off,(int)tranPackLen));

_packet = packet;

_off = off;

_len = (int)tranPackLen;

return 0x00==tranPackNo;

}

/**

* 当前包中的sql语句

* 注:这不一定是一个完整的sql语句

* @param packet

* @param off

* @param len

* @return 当requestType!=ClientRequestType.COM_QUERY时,返回""

*/

String toSql(byte[] packet,int off,int len){

try {

return new String(packet,off+5,len, (String)getProperty("encoding"));

} catch (UnsupportedEncodingException e) {

throw new RuntimeException(e);

}

}

/**

* 返回sql语句 

* 只有当requestType==ClientRequestType.COM_QUERY时可用

* @return 类型不符合时,返回""

*/

public String getSql(){

if(ClientRequestType.COM_QUERY!=this.requestType){

return "";

}

//return sql.toString();

return toSql(_packet,_off,_len);

}

/**

* 返回sql语句 

* 只有当requestType==ClientRequestType.COM_QUERY时可用

* @param data

* @param off

* @return

*/

public int getSql(byte[] data, int off){

System.arraycopy(_packet, _off, data, off, _len);

return _len;

}

public void writeSql(OutputStream out) throws IOException{

out.write(_packet, _off, _len);

out.flush();

}

/**

* 返回当前sql请求类型,参见ClientRequestType

* @return 未知请求返回-1

*/

public long getRequestType(){

return requestType;

}

/**

* 设置特性

* @param name

* @param value

*/

public void setProperty(String name,Object value){

this.properties.put(name, value);

}

/**

* 设置特性

* @param properties

*/

public void putProperty(Map properties){

this.properties.putAll(properties);;

}

/**

* 取特性

* @param name

* @return

*/

public Object getProperty(String name){

return this.properties.get(name);

}

/**

* 返回所有特性

* @return

*/

public Map getProperties(){

return this.properties;

}

///**

// * 设置传输包大小

// * 默认值   PACKET_MAXIMUM_LENGTH

// * @param len

// * @see #PACKET_MAXIMUM_LENGTH

// */

//public void setTranPacketLength(int len){

//this.packetLen = len;

//}

}

package mysql;

/**

* 特性

* @author shanl

* @see http://dev.mysql.com/doc/internals/en/capability-flags.html#flag-CLIENT_PROTOCOL_41

*/

public interface CapabilityFlag {

long CLIENT_LONG_PASSWORD = 0x00000001;

long CLIENT_FOUND_ROWS= 0x00000002;

long CLIENT_LONG_FLAG= 0x00000004;

long CLIENT_CONNECT_WITH_DB = 0x00000008;

long CLIENT_NO_SCHEMA= 0x00000010;

long CLIENT_COMPRESS =0x00000020;

long CLIENT_ODBC = 0x00000040;

long CLIENT_LOCAL_FILES = 0x00000080;

long CLIENT_IGNORE_SPACE= 0x00000100;

long CLIENT_PROTOCOL_41= 0x00000200;

long CLIENT_INTERACTIVE = 0x00000400;

long CLIENT_SSL= 0x00000800;

long CLIENT_IGNORE_SIGPIPE= 0x00001000;

long CLIENT_TRANSACTIONS= 0x00002000;

long CLIENT_RESERVED = 0x00004000;

long CLIENT_SECURE_CONNECTION=0x00008000;

long CLIENT_MULTI_STATEMENTS= 0x00010000;

long CLIENT_MULTI_RESULTS= 0x00020000;

long CLIENT_PS_MULTI_RESULTS= 0x00040000;

long CLIENT_PLUGIN_AUTH= 0x00080000;

long CLIENT_CONNECT_ATTRS= 0x00100000;

long CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA=0x00200000;

long CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS= 0x00400000;

long CLIENT_SESSION_TRACK= 0x00800000;

long CLIENT_DEPRECATE_EOF=0x01000000;

}

package mysql;

/**

* 客户端请求类型

* @author shanl

* @see http://dev.mysql.com/doc/internals/en/text-protocol.html

*/

public interface ClientRequestType {

/**(内部线程状态)*/

int COM_SLEEP= 0x00;

/**关闭连接*/

int COM_QUIT = 0x01;

/**切换数据库*/

int COM_INIT_DB = 0x02;

/**SQL查询请求*/

int COM_QUERY = 0x03;

/**获取数据表字段信息*/

int COM_FIELD_LIST = 0x04;

/**创建数据库*/

int COM_CREATE_DB = 0x05;

/**删除数据库*/

int COM_DROP_DB = 0x06;

/**清除缓存*/

int COM_REFRESH = 0x07;

/**停止服务器*/

int COM_SHUTDOWN = 0x08;

/**获取服务器统计信息*/

int COM_STATISTICS = 0x09;

/**获取当前连接的列表*/

int COM_PROCESS_INFO = 0x0A;

/**(内部线程状态)*/

int COM_CONNECT = 0x0B;

/**中断某个连接*/

int COM_PROCESS_KILL = 0x0C;

/**保存服务器调试信息*/

int COM_DEBUG = 0x0D;

/**测试连通性*/

int COM_PING = 0x0E;

/**(内部线程状态)*/

int COM_TIME= 0x0F;

/**(内部线程状态)*/

int COM_DELAYED_INSERT = 0x10;

/**重新登陆(不断连接*/

int COM_CHANGE_USER =   0x11;

/**获取二进制日志信息*/

int COM_BINLOG_DUMP= 0x12;

/**获取数据表结构信息*/

int COM_TABLE_DUMP= 0x13;

/**(内部线程状态)*/

int COM_CONNECT_OUT = 0x14;

/**从服务器向主服务器进行注册*/

int COM_REGISTER_SLAVE= 0x15;

/**预处理SQL语句*/

int COM_STMT_PREPARE = 0x16;

/**执行预处理语句*/

int COM_STMT_EXECUTE = 0x17;

/**发送BLOB类型的数据*/

int COM_STMT_SEND_LONG_DATA=0x18;

/**销毁预处理语句*/

int COM_STMT_CLOSE= 0x19;

/**清除预处理语句参数缓存*/

int COM_STMT_RESET = 0x1A;

/**设置语句选项*/

int COM_SET_OPTION = 0x1B;

/**获取预处理语句的执行结果*/

int COM_STMT_FETCH= 0x1C;

}

package mysql;

import java.io.ByteArrayOutputStream;

import java.io.OutputStream;

import java.util.zip.Inflater;

/**

* 为mysql分析专用工具

* @author shanl

*

*/

public class Util {

/**

* Big-Endian字节数组转uint32

* @param bys

* @param off

* @param len

* @return

*/

public static long bigBys2Uint32(byte[] bys,int off,int len){

long uint32 = 0;

for(int i=0,end=len-1,c=end; i<=end; i++,c--){

uint32 |= (0xff&bys[off+i])<

}

return uint32;

}

/**

* Little-Endian字节数组转uint32

* @param bys

* @param off

* @param len

* @return

*/

public static long littleBys2Uint32(byte[] bys,int off,int len){

long uint32 = 0;

for(int i=len-1; i>=0; i--){

uint32 |= (0xff&bys[off+i])<

}

return uint32;

}

/**

* 适用于mysql与客户端交互时zlib解压

* @param data

* @param off

* @param len

* @param out

* @throws Exception

*/

public static void decompress(byte[] data, int off, int len,OutputStream out){

Inflater decompresser = new Inflater();

decompresser.reset();

decompresser.setInput(data, off, len);

byte[] buf = new byte[1024];

try{

while(!decompresser.finished()){

int i = decompresser.inflate(buf);

out.write(buf, 0, i);

out.flush();

}

}catch(Exception ex){

throw new RuntimeException(ex);

}

}

/**

* 适用于mysql与客户端交互时zlib解压

* @param data 数据

* @param off 偏移量

* @param len 长度

* @return

*/

public static byte[] decompress(byte[] data, int off, int len) {

byte[] output = null;

Inflater decompresser = new Inflater();

decompresser.reset();

//decompresser.setInput(data);

decompresser.setInput(data, off, len);

ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);

try {

byte[] buf = new byte[1024];

while (!decompresser.finished()) {

int i = decompresser.inflate(buf);

o.write(buf, 0, i);

}

output = o.toByteArray();

} catch (Exception e) {

throw new RuntimeException(e);

} finally {

try {

o.close();

} catch (Exception e) {

}

}

decompresser.end();

return output;

}

/**

* 适用于mysql与客户端交互时zlib解压

* @param data 数据

* @param off 偏移量

* @param len 长度

* @param srcLen 源数据长度

* @return

*/

public static byte[] decompress(byte[] data, int off, int len, int srcLen) {

byte[] output = null;

Inflater decompresser = new Inflater();

decompresser.reset();

//decompresser.setInput(data);

decompresser.setInput(data, off, len);

ByteArrayOutputStream o = new ByteArrayOutputStream(srcLen);

try {

o.reset();

byte[] buf = new byte[1024];

while (!decompresser.finished()) {

int i = decompresser.inflate(buf);

o.write(buf, 0, i);

}

output = o.toByteArray();

} catch (Exception e) {

throw new RuntimeException(e);

} finally {

try {

o.close();

} catch (Exception e) {

}

}

decompresser.end();

return output;

}

}

package mysql;

/**

* 支持的字符编码

* @author shanl

* @see 

* http://dev.mysql.com/doc/internals/en/character-set.html#packet-Protocol::CharacterSet

*/

public class CharacterSet {

/***

int big5_chinese_ci              =1;

int latin2_czech_cs              =2;

int dec8_swedish_ci              =3;

int cp850_general_ci             =4;

int latin1_german1_ci            =5;

int hp8_english_ci               =6;

int koi8r_general_ci             =7;

int latin1_swedish_ci            =8;

int latin2_general_ci            =9;

int swe7_swedish_ci             =10;

int ascii_general_ci            =11;

int ujis_japanese_ci            =12;

int sjis_japanese_ci            =13;

int cp1251_bulgarian_ci         =14;

int latin1_danish_ci            =15;

int hebrew_general_ci           =16;

int tis620_thai_ci              =18;

int euckr_korean_ci             =19;

int latin7_estonian_cs          =20;

int latin2_hungarian_ci         =21;

int koi8u_general_ci            =22;

int cp1251_ukrainian_ci         =23;

int gb2312_chinese_ci           =24;

int greek_general_ci            =25;

int cp1250_general_ci           =26;

int latin2_croatian_ci          =27;

int gbk_chinese_ci              =28;

int cp1257_lithuanian_ci        =29;

int latin5_turkish_ci           =30;

int latin1_german2_ci           =31;

int armscii8_general_ci         =32;

int utf8_general_ci             =33;

int cp1250_czech_cs             =34;

int ucs2_general_ci             =35;

int cp866_general_ci            =36;

int keybcs2_general_ci          =37;

int macce_general_ci            =38;

int macroman_general_ci         =39;

int cp852_general_ci            =40;

int latin7_general_ci           =41;

int latin7_general_cs           =42;

int macce_bin                   =43;

int cp1250_croatian_ci          =44;

int utf8mb4_general_ci          =45;

int utf8mb4_bin                 =46;

int latin1_bin                  =47;

int latin1_general_ci           =48;

int latin1_general_cs           =49;

int cp1251_bin                  =50;

int cp1251_general_ci           =51;

int cp1251_general_cs           =52;

int macroman_bin                53

int utf16_general_ci            54

int utf16_bin                   55

int cp1256_general_ci           57

int cp1257_bin                  58

int cp1257_general_ci           59

int utf32_general_ci            60

int utf32_bin                   61

int binary                      63

int armscii8_bin                64

int ascii_bin                   65

int cp1250_bin                  66

int cp1256_bin                  67

int cp866_bin                   68

int dec8_bin                    69

int greek_bin                   70

int hebrew_bin                  71

int  hp8_bin                     72

int keybcs2_bin                 73

int koi8r_bin                   74

int koi8u_bin                   75

int latin2_bin                  77

int latin5_bin                  78

int latin7_bin                  79

int cp850_bin                   80

int cp852_bin                   81

int swe7_bin                    82

int utf8_bin                    83

int big5_bin                    84

int euckr_bin                   85

int gb2312_bin                  86

int gbk_bin                     87

int sjis_bin                    88

int tis620_bin                  89

int ucs2_bin                    90

int ujis_bin                    91

int geostd8_general_ci          92

int geostd8_bin                 93

latin1_spanish_ci           94

cp932_japanese_ci           95

cp932_bin                   96

eucjpms_japanese_ci         97

eucjpms_bin                 98

cp1250_polish_ci            99

utf16_unicode_ci           101

utf16_icelandic_ci         102

utf16_latvian_ci           103

utf16_romanian_ci          104

utf16_slovenian_ci         105

utf16_polish_ci            106

utf16_estonian_ci          107

utf16_spanish_ci           108

utf16_swedish_ci           109

utf16_turkish_ci           110

utf16_czech_ci             111

utf16_danish_ci            112

utf16_lithuanian_ci        113

utf16_slovak_ci            114

utf16_spanish2_ci          115

utf16_roman_ci             116

utf16_persian_ci           117

utf16_esperanto_ci         118

utf16_hungarian_ci         119

utf16_sinhala_ci           120

ucs2_unicode_ci            128

ucs2_icelandic_ci          129

ucs2_latvian_ci            130

ucs2_romanian_ci           131

ucs2_slovenian_ci          132

ucs2_polish_ci             133

ucs2_estonian_ci           134

ucs2_spanish_ci            135

ucs2_swedish_ci            136

ucs2_turkish_ci            137

ucs2_czech_ci              138

ucs2_danish_ci             139

ucs2_lithuanian_ci         140

ucs2_slovak_ci             141

ucs2_spanish2_ci           142

ucs2_roman_ci              143

ucs2_persian_ci            144

ucs2_esperanto_ci          145

ucs2_hungarian_ci          146

ucs2_sinhala_ci            147

ucs2_general_mysql500_ci   159

utf32_unicode_ci           160

utf32_icelandic_ci         161

utf32_latvian_ci           162

utf32_romanian_ci          163

utf32_slovenian_ci         164

utf32_polish_ci            165

utf32_estonian_ci          166

utf32_spanish_ci           167

utf32_swedish_ci           168

utf32_turkish_ci           169

utf32_czech_ci             170

utf32_danish_ci            171

utf32_lithuanian_ci        172

utf32_slovak_ci            173

utf32_spanish2_ci          174

utf32_roman_ci             175

utf32_persian_ci           176

utf32_esperanto_ci         177

utf32_hungarian_ci         178

utf32_sinhala_ci           179

utf8_unicode_ci            192

utf8_icelandic_ci          193

utf8_latvian_ci            194

utf8_romanian_ci           195

utf8_slovenian_ci          196

utf8_polish_ci             197

utf8_estonian_ci           198

utf8_spanish_ci            199

utf8_swedish_ci            200

utf8_turkish_ci            201

utf8_czech_ci              202

utf8_danish_ci             203

utf8_lithuanian_ci         204

utf8_slovak_ci             205

utf8_spanish2_ci           206

utf8_roman_ci              207

utf8_persian_ci            208

utf8_esperanto_ci          209

utf8_hungarian_ci          210

utf8_sinhala_ci            211

utf8_general_mysql500_ci   223

utf8mb4_unicode_ci         224

utf8mb4_icelandic_ci       225

utf8mb4_latvian_ci         226

utf8mb4_romanian_ci        227

utf8mb4_slovenian_ci       228

utf8mb4_polish_ci          229

utf8mb4_estonian_ci        230

utf8mb4_spanish_ci         231

utf8mb4_swedish_ci         232

utf8mb4_turkish_ci         233

utf8mb4_czech_ci           234

utf8mb4_danish_ci          235

utf8mb4_lithuanian_ci      236

utf8mb4_slovak_ci          237

utf8mb4_spanish2_ci        238

utf8mb4_roman_ci           239

utf8mb4_persian_ci         240

utf8mb4_esperanto_ci       241

utf8mb4_hungarian_ci       242

utf8mb4_sinhala_ci         243

***/

}

package test2;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.InetAddress;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.net.Socket;

import java.net.SocketTimeoutException;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.zip.DataFormatException;

import java.util.zip.Inflater;

import mysql.ClientRequestType;

import mysql.MysqlAnalyse;

import mysql.MysqlSimpleProxy;

import mysql.Util;

/**

* 这是测试类

* @author shanl

*

*/

public class Test4 {

public static void main(String[] args){

//t1();

//t2();

//t3();

//t4();

//t5();

//t6();

//t7();

//t8();

t9();

}

static void t9(){

//InetSocketAddress address = new InetSocketAddress(1024);

//System.out.println(address.getHostName());

MysqlSimpleProxy proxy = new MysqlSimpleProxy("192.168.2.182:3306");

proxy.setListenPort(3306);

proxy.setRecordDir("e:/a/2");

//proxy.start();

proxy.service(null);

}

/**

* 调用MysqlAnlyse进行分析

*/

static void t8(){

long packLen = 0; //3byte

long number = 0;//1byte

long compress = 0;//3byte

File srcDir = new File("e://a//2");

File compressFile = new File(srcDir,"fc_103533_0.out.compress.3"); //uncompress

//File compressFile = new File(srcDir,"fc_103533_0.out.compress.2"); //uncompress

//File compressFile = new File(srcDir,"fc_103533_0.out.compress.1"); //compress

//File compressFile = new File(srcDir,"fc_103533_0.out.decompress"); //non-compress

int readLen = 0;

byte[] buff = new byte[1024*4];

try {

FileInputStream fin = new FileInputStream(compressFile);

readLen = fin.read(buff);

fin.close();

} catch (Exception e) {

e.printStackTrace();

}

try{

MysqlAnalyse anly = new MysqlAnalyse();

anly.setProperty("compress", true);

anly.setProperty("encoding", "utf-8");

anly.parse(buff, 0, readLen);

System.out.println(anly.getRequestType());

System.out.println(anly.getSql());

}catch(Exception e){

e.printStackTrace();

}

}

static void t7(){

byte[] capability_flags_lower = {

(byte) 0xff,(byte) 0xf7

};

byte[] capability_flags_upper = {

(byte) 7f,(byte) 0x80

};

//byte[] bys = {

//capability_flags_upper[1],capability_flags_upper[0],

//capability_flags_lower[1],capability_flags_lower[0]

//};

//byte[] bys = {

//capability_flags_lower[0],capability_flags_lower[1],

//capability_flags_upper[0],capability_flags_upper[1],

//};

byte[] bys = {

capability_flags_upper[0],capability_flags_upper[1],

capability_flags_lower[0],capability_flags_lower[1],

};

//byte[] bys = {

(byte) 0x85,(byte) 0xa6

//(byte) 0xa5,(byte) 0xa6

//};

long capability_flags = bigBys2Uint32(bys,0,bys.length);

//System.out.println(capability_flags);

long compress_flag = 0x00000020;

long odbc_flag = 0x00000040;

long l = capability_flags & compress_flag;

System.out.println(l);

System.out.println(compress_flag==l);

}

static void t6(){

byte[] bys = "中".getBytes();

long i32 = bigBys2Uint32(bys,0,bys.length);

System.out.println(i32);

}

static void t5(){

long packLen = 0; //3byte

long number = 0;//1byte

long compress = 0;//3byte

File srcDir = new File("e://a//2");

File compressFile = new File(srcDir,"fc_103533_0.out.compress.1"); //uncompress

//File compressFile = new File(srcDir,"fc_103533_0.out.compress.2"); //compress

int readLen = 0;

byte[] buff = new byte[1024*4];

try {

FileInputStream fin = new FileInputStream(compressFile);

readLen = fin.read(buff);

fin.close();

} catch (Exception e) {

e.printStackTrace();

}

try{

packLen = littleBys2Uint32(buff,0,3);

number = littleBys2Uint32(buff,3,1);

compress = littleBys2Uint32(buff,4,3);

System.out.println("readLen: "+readLen);

System.out.println("packLen: "+packLen);

System.out.println("number: " +number);

System.out.println("compress: "+compress);

}catch(Exception e){

e.printStackTrace();

}

//decompress

long srcLen = 0;

long srcReqType = 0;

byte[] srcData = null;

try{

if(compress>0){

byte[] decompressData = Util.decompress(buff,3+1+3,readLen-7);

srcLen = Util.littleBys2Uint32(decompressData,0,4)-1;//-1去掉clientRequestType

srcReqType = Util.littleBys2Uint32(decompressData, 4, 1);

srcData = new byte[(int) srcLen];

System.arraycopy(decompressData, 5, srcData, 0, (int)srcLen);//

}else{

srcLen = Util.littleBys2Uint32(buff,3+1+3,4)-1; //-1去掉clientRequestType

srcReqType = Util.littleBys2Uint32(buff, 3+1+3+4, 1);

srcData = new byte[(int) srcLen];

System.arraycopy(buff, 3+1+3+4+1, srcData, 0, (int)srcLen);

}

System.out.println("srcLen: "+srcLen);

System.out.println("srcReqType: "+srcReqType);

if((int)srcReqType==ClientRequestType.COM_QUERY){

System.out.println("sql: "+new String(srcData));

}else{

System.out.println("non-sql request.");

}

}catch(Exception e){

e.printStackTrace();

}

}

static void t4(){

byte[] bys = {

(byte) 0xda,0x00,0x00,

};

byte[] bys1 = {

0x00,0x00,(byte) 0xda,

};

System.out.println(littleBys2Uint32(bys,0,bys.length));

System.out.println(bigBys2Uint32(bys1,0,bys1.length));

}

/**

* Big-Endian字节数组转uint32

* @param bys

* @param off

* @param len

* @return

*/

static long bigBys2Uint32(byte[] bys,int off,int len){

long uint32 = 0;

for(int i=0,end=len-1,c=end; i<=end; i++,c--){

uint32 |= (0xff&bys[off+i])<

}

return uint32;

}

/**

* Little-Endian字节数组转uint32

* @param bys

* @param off

* @param len

* @return

*/

static long littleBys2Uint32(byte[] bys,int off,int len){

long uint32 = 0;

for(int i=len-1; i>=0; i--){

uint32 |= (0xff&bys[off+i])<

}

return uint32;

}

static void t3(){

short[] bys = {

0xda,0x00,0x00,0x00

};

long uint32 = 0;

for(int i=bys.length-1; i>=0; i--){

uint32 |= (0xff&bys[i])<

}

System.out.println(uint32);

//System.out.println(0xff&0xda);

}

public static byte[] decompress(byte[] data, int off, int len) {

byte[] output = new byte[0];

Inflater decompresser = new Inflater();

decompresser.reset();

//decompresser.setInput(data);

decompresser.setInput(data, off, len);

ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);

try {

byte[] buf = new byte[1024];

while (!decompresser.finished()) {

int i = decompresser.inflate(buf);

o.write(buf, 0, i);

}

output = o.toByteArray();

} catch (Exception e) {

output = data;

e.printStackTrace();

} finally {

try {

o.close();

} catch (IOException e) {

e.printStackTrace();

}

}

decompresser.end();

return output;

}

public static void decompress(byte[] data, int off, int len,OutputStream out) throws Exception{

Inflater decompresser = new Inflater();

decompresser.reset();

decompresser.setInput(data, off, len);

byte[] buf = new byte[1024];

while(!decompresser.finished()){

int i = decompresser.inflate(buf);

out.write(buf, 0, i);

out.flush();

}

}

static void t2(){

File recordDir = new File("e://a//2");

String srcFile = "fc_103533_0.out";

File cf = new File(recordDir,srcFile+".compress");

//File cf1 = new File(recordDir,"fc_103533_0.out.compress.1");

File df = new File(recordDir,srcFile+".decompress");

int readLen = 0;

byte[] buff = new byte[1024*4];

try {

FileInputStream fin = new FileInputStream(cf);

readLen = fin.read(buff);

fin.close();

} catch (Exception e) {

e.printStackTrace();

}

//try{

//FileOutputStream fout = new FileOutputStream(cf1);

//fout.write(buff,7,readLen-7);

//fout.close();

//}catch(Exception ex){

//ex.printStackTrace();

//}

try{

FileOutputStream fout = new FileOutputStream(df);

decompress(buff,7,readLen-7,fout);

fout.close();

}catch(Exception ex){

ex.printStackTrace();

}

}

static final SimpleDateFormat sdf = new SimpleDateFormat("[HH:mm:ss]");

static final SimpleDateFormat fsdf = new SimpleDateFormat("HHmmss");

/**

* 简单的代理,主要用于本地存储通信字节

*/

static void t1(){

File recordDir = new File("e://a//2");

String tsip = "192.168.2.182";

int tsport = 3306;

int listenPort = 3306;

ServerSocket ss = null;

Socket fcsocket = null;

Socket tssocket = null;

int readTimeout = 1000*60*5;

try{

System.out.println("listen port:"+listenPort);

ss = new ServerSocket(listenPort);

for(int i=0;;i++){

fcsocket = ss.accept();

fcsocket.setSoTimeout(readTimeout);

System.out.println("new connected "+i);

tssocket = new Socket(tsip,tsport);

tssocket.setSoTimeout(readTimeout);

String fname_padding = fsdf.format(new Date())+"_"+i+".out";

new Recording(fcsocket,tssocket,new File(recordDir,"fc_"+fname_padding)).start();

new Recording(tssocket,fcsocket,new File(recordDir,"ts_"+fname_padding)).start();

}

}catch(Exception ex){

}

}

static class Recording extends Thread{

Socket fcsocket = null;

Socket tssocket = null;

File recordFile = null;

public Recording(Socket from,Socket to,File file){

this.fcsocket = from;

this.tssocket = to;

this.recordFile = file;

}

public void run(){

InputStream fcin = null;

OutputStream tsout = null;

int readLen = 0;

byte[] buff = new byte[1024*4];

FileOutputStream fileOut = null;

try{

recordFile.createNewFile();

fcin = fcsocket.getInputStream();

tsout = tssocket.getOutputStream();

fileOut = new FileOutputStream(recordFile);

}catch(Exception ex){

try { fileOut.close(); } catch (IOException e) { }

try { fcsocket.close(); } catch (IOException e) { }

try { tssocket.close(); } catch (IOException e) { }

return;

}

for(;;){

try{

readLen = fcin.read(buff);

tsout.write(buff,0,readLen);

tsout.flush();

fileOut.write(sdf.format(new Date()).getBytes());

fileOut.write(buff,0,readLen);

fileOut.flush();

}catch(SocketTimeoutException ste){

continue;

}catch(Exception ex){

break;

}

}

try{fileOut.close();}catch(Exception ex){}

}

}

}

package mysql;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.InetAddress;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.net.Socket;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.concurrent.ExecutorService;

import org.apache.log4j.Logger;

/**

* 一个简单的mysql代理 

* 主要用于分析和截获sql语句

* @author shanl

*

*/

public class MysqlSimpleProxy {

ExecutorService threadPool = null;

InetSocketAddress targetAddress = null;

int listenPort = 3306;

static final Logger logger = Logger.getLogger(MysqlSimpleProxy.class);

String recordDir = ".";

/**

*

* @param targetAddress 目标服务器地址,格式 [:port] port默认3306

*/

public MysqlSimpleProxy(String targetAddress){

String[] ss = targetAddress.split(":");

this.targetAddress = new InetSocketAddress(ss[0],

1==ss.length? 3306: Integer.parseInt(ss[1]));

}

public void start(){

ServerSocket ss = null;

try {

ss = new ServerSocket(listenPort);

} catch (IOException e) {

logger.error(e.getMessage(), e);

return;

}

logger.info("MysqlPort listen port:" + listenPort);

System.err.println("MysqlPort listen port:" + listenPort);

Socket fromClient = null;

for(int i=0;;i++){

try{

fromClient = ss.accept();

connectHandler(fromClient);

logger.info("MysqlPort new connect:"+i);

}catch(Exception e){

logger.error(e.getMessage(), e);

break;

}

}

try{ss.close();}catch(Exception ex){}

}

/**

* 以服务方式启动

* @param threadPool 可以为null

*/

public void service(ExecutorService threadPool){

Thread t = new Thread(

new Runnable(){

@Override

public void run() {

start();

}},

"MysqlProxy");

if(null==threadPool) t.start();

else threadPool.execute(t);

}

static final SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");

static final SimpleDateFormat head = new SimpleDateFormat("[dd HH:mm:ss]");

void connectHandler(Socket fromClient){

Socket toServer = null;

try{

toServer = new Socket();

toServer.connect(targetAddress, 1000*10);

FileOutputStream out = new FileOutputStream(new File(recordDir,

"c_"+sdf.format(new Date())+"_"+fromClient.getInetAddress().getHostAddress()

+".record"));

InetAddress fcAddress = fromClient.getInetAddress();

out.write(head.format(new Date()).getBytes());

out.write(("client:"+fcAddress.getHostAddress()).getBytes());

out.write((",server:"+targetAddress.getHostString()+":"+targetAddress.getPort()).getBytes());

out.flush();

Thread c2s = new Thread(new Worker(fromClient, toServer, out));

Thread s2c = new Thread(new Worker(toServer, fromClient, null));

if(null==threadPool){

c2s.start();

s2c.start();

}else{

threadPool.execute(c2s);

threadPool.execute(s2c);

}

}catch(Exception e){

logger.error(e.getMessage(), e);

try{if(null!=toServer)toServer.close();}catch(Exception ex){}

}

}

/**

* 设置本地监听地址,默认3306

* @param port

*/

public void setListenPort(int port){

this.listenPort = port;

}

public void setThreadPool(ExecutorService threadPool){

this.threadPool = threadPool;

}

/**

* 设置截获数据的存储目录

* @param dir 默认'./'

*/

public void setRecordDir(String dir){

this.recordDir = dir;

}

static class Worker extends Thread{

Socket from = null;

Socket to = null;

OutputStream record = null;

public Worker(Socket from,Socket to,OutputStream record){

this.from = from;

this.to = to;

this.record = record;

}

public void run(){

int readLen = 0;

byte[] buff = new byte[1024*1024*16];

MysqlAnalyse analy = null;

StringBuilder sb = new StringBuilder();

try{

InputStream in = from.getInputStream();

OutputStream out = to.getOutputStream();

readLen = in.read(buff);

out.write(buff,0,readLen);

out.flush();

if(null!=record)analy = MysqlAnalyse.handshake(buff, 0, readLen);

while(-1!=(readLen=in.read(buff)) ){

if(null!=record){

boolean endPack = analy.parse(buff, 0, readLen);

if(ClientRequestType.COM_QUERY==analy.getRequestType()){

sb.append(analy.getSql());

if(endPack){

record.write((MysqlSimpleProxy.head.format(new Date())).getBytes());

record.write(sb.toString().getBytes());

record.flush();

sb = new StringBuilder();

}

}

//logger.info("requestType:"+analy.getRequestType()+",sql:"+analy.getSql());

}

out.write(buff,0,readLen);

out.flush();

}

}catch(Exception e){

logger.error(e.getMessage(), e);

}finally{

try{if(null!=from)from.close();}catch(Exception e){}

try{if(null!=to)to.close();}catch(Exception e){}

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值