144 lines
2.6 KiB
Go
144 lines
2.6 KiB
Go
|
package mysql
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
cnsm "git.loafle.net/commons_go/network_service_matcher"
|
||
|
)
|
||
|
|
||
|
type PacketSize struct {
|
||
|
PacketLength [3]byte
|
||
|
PacketNumber byte
|
||
|
}
|
||
|
|
||
|
type mySql struct {
|
||
|
Payload PacketSize
|
||
|
Protocol byte
|
||
|
Version [256]byte
|
||
|
|
||
|
TreadId uint32
|
||
|
Salt1 [9]byte
|
||
|
ServerCapa uint16
|
||
|
ServerLang uint8
|
||
|
ServerStat uint16
|
||
|
ExtServerCapa uint16
|
||
|
AuthPlugLen uint8
|
||
|
_ [10]uint8
|
||
|
Salt2 [13]uint8
|
||
|
AuthPlugName [64]uint8
|
||
|
}
|
||
|
|
||
|
type MySqlMatcher struct {
|
||
|
cnsm.Matchers
|
||
|
version string
|
||
|
isErrResp bool
|
||
|
errCode int
|
||
|
errMsg string
|
||
|
isSSL bool
|
||
|
}
|
||
|
|
||
|
func (t *MySqlMatcher) ServiceName() string {
|
||
|
if t.isErrResp {
|
||
|
return "MySQL" + "(Err-" + strconv.Itoa(t.errCode) + " : " + t.errMsg + ")"
|
||
|
}
|
||
|
if t.isSSL {
|
||
|
return "MySQL" + "-" + t.version + "(SSL)"
|
||
|
}
|
||
|
return "MySQL" + "(" + t.version + ")"
|
||
|
}
|
||
|
|
||
|
func (t *MySqlMatcher) IsPrePacket() bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (t *MySqlMatcher) HasResponse(index int) bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (t *MySqlMatcher) IsError(info cnsm.MatchInfo, index int, packet *cnsm.Packet) bool {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (t *MySqlMatcher) Match(info cnsm.MatchInfo, index int, packet *cnsm.Packet) bool {
|
||
|
|
||
|
if packet == nil || len(packet.Buffer) <= 0 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
r := new(bytes.Buffer)
|
||
|
r.Write(packet.Buffer)
|
||
|
|
||
|
m := mySql{}
|
||
|
if err := binary.Read(r, binary.LittleEndian, &m); err != nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
buf := bytes.NewBuffer(m.Payload.PacketLength[:])
|
||
|
packetLen, _ := binary.ReadUvarint(buf)
|
||
|
|
||
|
if packetLen != uint64(packet.Len-4) {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if m.Protocol == 0xff {
|
||
|
//MySQL error response
|
||
|
var code [2]uint8
|
||
|
copy(code[:], m.Version[:2])
|
||
|
|
||
|
var msg [256]uint8
|
||
|
copy(msg[:], m.Version[2:])
|
||
|
|
||
|
errCode := binary.LittleEndian.Uint16(code[:])
|
||
|
if errCode < 1000 || errCode > 1727 {
|
||
|
return false
|
||
|
}
|
||
|
errMsg := bytes.Trim(msg[:], "\x00")
|
||
|
|
||
|
t.isErrResp = true
|
||
|
t.errCode = int(errCode)
|
||
|
t.errMsg = string(errMsg)
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
if m.Protocol != 10 && m.Protocol != 9 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
t.checkSSL(packet)
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (t *MySqlMatcher) checkSSL(packet *cnsm.Packet) {
|
||
|
|
||
|
temp := make([]byte, packet.Len)
|
||
|
r := new(bytes.Buffer)
|
||
|
r.Write(packet.Buffer)
|
||
|
|
||
|
if err := binary.Read(r, binary.LittleEndian, &temp); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
t.version = strings.Split(string(packet.Buffer)[5:packet.Len], "\x00")[0]
|
||
|
versionLen := len(t.version) + 1
|
||
|
data := binary.LittleEndian.Uint16(temp[18+versionLen : 20+versionLen])
|
||
|
s := fmt.Sprintf("%b", data)
|
||
|
|
||
|
for i, b := range s {
|
||
|
if i == 4 {
|
||
|
if b == 49 {
|
||
|
t.isSSL = true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func NewMatcher() cnsm.Matcher {
|
||
|
return &MySqlMatcher{}
|
||
|
}
|