func (c *Conn) writeAuthHandshake() error { // Adjust client capability flags based on server support capability := mysql.CLIENT_PROTOCOL_41 | mysql.CLIENT_SECURE_CONNECTION | mysql.CLIENT_LONG_PASSWORD | mysql.CLIENT_TRANSACTIONS | mysql.CLIENT_LONG_FLAG capability &= c.capability //packet length //capbility 4 //max-packet size 4 //charset 1 //reserved all[0] 23 length := 4 + 4 + 1 + 23 //username length += len(c.user) + 1 //we only support secure connection auth := mysql.CalcPassword(c.salt, []byte(c.password)) length += 1 + len(auth) if len(c.db) > 0 { capability |= mysql.CLIENT_CONNECT_WITH_DB length += len(c.db) + 1 } c.capability = capability data := make([]byte, length+4) //capability [32 bit] data[4] = byte(capability) data[5] = byte(capability >> 8) data[6] = byte(capability >> 16) data[7] = byte(capability >> 24) //MaxPacketSize [32 bit] (none) //data[8] = 0x00 //data[9] = 0x00 //data[10] = 0x00 //data[11] = 0x00 //Charset [1 byte] data[12] = byte(c.collation) //Filler [23 bytes] (all 0x00) pos := 13 + 23 //User [null terminated string] if len(c.user) > 0 { pos += copy(data[pos:], c.user) } //data[pos] = 0x00 pos++ // auth [length encoded integer] data[pos] = byte(len(auth)) pos += 1 + copy(data[pos+1:], auth) // db [null terminated string] if len(c.db) > 0 { pos += copy(data[pos:], c.db) //data[pos] = 0x00 } return c.writePacket(data) }
func (c *ClientConn) readHandshakeResponse() error { data, err := c.readPacket() if err != nil { return err } pos := 0 //capability c.capability = binary.LittleEndian.Uint32(data[:4]) pos += 4 //skip max packet size pos += 4 //charset, skip, if you want to use another charset, use set names //c.collation = CollationId(data[pos]) pos++ //skip reserved 23[00] pos += 23 //user name c.user = string(data[pos : pos+bytes.IndexByte(data[pos:], 0)]) pos += len(c.user) + 1 //auth length and auth authLen := int(data[pos]) pos++ auth := data[pos : pos+authLen] checkAuth := mysql.CalcPassword(c.salt, []byte(c.proxy.cfg.Password)) if c.user != c.proxy.cfg.User || !bytes.Equal(auth, checkAuth) { golog.Error("ClientConn", "readHandshakeResponse", "error", 0, "auth", auth, "checkAuth", checkAuth, "client_user", c.user, "config_set_user", c.proxy.cfg.User, "passworld", c.proxy.cfg.Password) return mysql.NewDefaultError(mysql.ER_ACCESS_DENIED_ERROR, c.user, c.c.RemoteAddr().String(), "Yes") } pos += authLen var db string if c.capability&mysql.CLIENT_CONNECT_WITH_DB > 0 { if len(data[pos:]) == 0 { return nil } db = string(data[pos : pos+bytes.IndexByte(data[pos:], 0)]) pos += len(c.db) + 1 } golog.Error("handshake ", "response", "db ", 0, db) if err := c.useDB(db); err != nil { return err } return nil }