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 { return "MYSQL" } func (t *MySqlMatcher) String() 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{} }