Mysql 協議嗅探

需求

監聽經過網卡的全部mysql流量,進行解析,可在不影響現有業務狀況下,進行入侵檢測(IDS)或數據集成python

協議要點

起初發現 用mysql-front訪問數據庫和mysql 的客戶端訪問時數據包格式不一樣,糾結好久,不明白,mysql-front源碼看了眼,delphi,不懂,棄mysql

壓縮解析

當連接mysql時,若啓用-C參數表示,對於鏈接數據啓用壓縮,壓縮格式爲zlibsql

mysql的壓縮函數爲:數據庫

 1 // mysql-source/mysys/my_compress.c
 2 
 3 my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
 4 {
 5   DBUG_ENTER("my_compress");
 6   if (*len < MIN_COMPRESS_LENGTH)
 7   {
 8     *complen=0;
 9     DBUG_PRINT("note",("Packet too short: Not compressed"));
10   }
11   else
12   {
13     uchar *compbuf=my_compress_alloc(packet,len,complen);
14     if (!compbuf)
15       DBUG_RETURN(*complen ? 0 : 1);
16     memcpy(packet,compbuf,*len);
17     my_free(compbuf);
18   }
19   DBUG_RETURN(0);
20 }
21 
22 
23 uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
24 {
25   uchar *compbuf;
26   uLongf tmp_complen;
27   int res;
28   *complen=  *len * 120 / 100 + 12;
29 
30   if (!(compbuf= (uchar *) my_malloc(key_memory_my_compress_alloc,
31                                      *complen, MYF(MY_WME))))
32     return 0;                    /* Not enough memory */
33 
34   tmp_complen= (uint) *complen;
35   res= compress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet, (uLong) *len);
36   *complen=    tmp_complen;
37 
38   if (res != Z_OK)
39   {
40     my_free(compbuf);
41     return 0;
42   }
43 
44   if (*complen >= *len)
45   {
46     *complen= 0;
47     my_free(compbuf);
48     DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
49     return 0;
50   }
51   /* Store length of compressed packet in *len */
52   swap_variables(size_t, *len, *complen);
53   return compbuf;
54 }

 其中第35行調用了zlib中的compress()函數,可是該處僅對compress()進行了封裝,並無協議解析部分,咱們繼續往下看。函數

 

整個項目尋找目標代碼比較費勁,能夠先在頭文件中尋找關鍵信息,因而找到了下面的代碼ui

// mysql-source/include/sql_state.h
{ ER_NET_UNCOMPRESS_ERROR                 ,"08S01", "" }

 

這是在mysql在解析壓縮的數據時若是出錯的提示信息和錯誤碼,依次能夠查找其引用,發現了真正的數據包壓縮代碼this

 1 // mysql-source/sql/net_serv.cc
 2 
 3 static uchar *
 4 compress_packet(NET *net, const uchar *packet, size_t *length)
 5 {
 6   uchar *compr_packet;
 7   size_t compr_length;
 8   const uint header_length= NET_HEADER_SIZE + COMP_HEADER_SIZE;
 9 
10   compr_packet= (uchar *) my_malloc(key_memory_NET_compress_packet,
11                                     *length + header_length, MYF(MY_WME));
12 
13   if (compr_packet == NULL)
14     return NULL;
15 
16   memcpy(compr_packet + header_length, packet, *length);
17 
18   /* Compress the encapsulated packet. */
19   if (my_compress(compr_packet + header_length, length, &compr_length))
20   {
21     /*
22       If the length of the compressed packet is larger than the
23       original packet, the original packet is sent uncompressed.
24     */
25     compr_length= 0;
26   }
27 
28   /* Length of the compressed (original) packet. */
29   int3store(&compr_packet[NET_HEADER_SIZE], static_cast<uint>(compr_length));
30   /* Length of this packet. */
31   int3store(compr_packet, static_cast<uint>(*length));
32   /* Packet number. */
33   compr_packet[3]= (uchar) (net->compress_pkt_nr++);
34 
35   *length+= header_length;
36 
37   return compr_packet;
38 }

 從8-19行能夠看到,壓縮數據的組包過程,前面分別加了NET_HEADER_SIZE + COMP_HEADER_SIZE 長的控制字段spa

 

查找該宏,發現其定義以下code

1 // mysql-source/include/mysql_com.h
2 
3   /* Constants when using compression */
4 #define NET_HEADER_SIZE 4        /* standard header size */
5 #define COMP_HEADER_SIZE 3        /* compression header extra size */

NET_HEADER_SIZE 字段中 長度字段存儲 數據部分 未解壓時的長度blog

COMP_HEADER_SIZE 字段是用來存儲  解壓後的 數據的長度,咱們能夠依次申請內存,而後調用zlib對壓縮內容進行解析便可。

 

 若是不分析直接進行對wireshark抓到的數據進行zlib解析的話,因爲控制字段的存在會解壓縮失敗,在python中的報錯以下

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
zlib.error: Error -3 while decompressing data: incorrect data check

 起初看到這個錯誤很頭痛也不想看zlib解析細節,纔有了從mysql找緣由的本文,如今能夠記錄zlib 壓縮字符串的開頭經常是\x78\x9c,出現一樣錯誤的能夠看看是否正確

相關文章
相關標籤/搜索