handshake.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package binlog
  2. import (
  3. "bytes"
  4. )
  5. type Capabilities struct {
  6. LongPassword bool
  7. FoundRows bool
  8. LongFlag bool
  9. ConnectWithDB bool
  10. NoSchema bool
  11. Compress bool
  12. ODBC bool
  13. LocalFiles bool
  14. IgnoreSpace bool
  15. Protocol41 bool
  16. Interactive bool
  17. SSL bool
  18. IgnoreSigpipe bool
  19. Transactions bool
  20. LegacyProtocol41 bool
  21. SecureConnection bool
  22. MultiStatements bool
  23. MultiResults bool
  24. PSMultiResults bool
  25. PluginAuth bool
  26. ConnectAttrs bool
  27. PluginAuthLenEncClientData bool
  28. CanHandleExpiredPasswords bool
  29. SessionTrack bool
  30. DeprecateEOF bool
  31. SSLVerifyServerCert bool
  32. OptionalResultSetMetadata bool
  33. RememberOptions bool
  34. }
  35. type Status struct {
  36. InTrans bool
  37. Autocommit bool
  38. MoreResultsExists bool
  39. QueryNoGoodIndexUsed bool
  40. QueryNoIndexUsed bool
  41. CursorExists bool
  42. LastRowSent bool
  43. DBDropped bool
  44. NoBackslashEscapes bool
  45. MetadataChanged bool
  46. QueryWasSlow bool
  47. PSOutParams bool
  48. InTransReadonly bool
  49. SessionStateChanged bool
  50. }
  51. type Handshake struct {
  52. PacketLength uint64
  53. SequenceID uint64
  54. ProtocolVersion uint64
  55. ServerVersion string
  56. ThreadID uint64
  57. AuthPluginDataPart1 *bytes.Buffer
  58. CapabilityFlags1 *bytes.Buffer
  59. Charset uint64
  60. StatusFlags *bytes.Buffer
  61. CapabilityFlags2 *bytes.Buffer
  62. AuthPluginDataLength uint64
  63. AuthPluginDataPart2 *bytes.Buffer
  64. AuthPluginName string
  65. Capabilities *Capabilities
  66. Status *Status
  67. }
  68. type HandshakeResponse struct {
  69. ClientFlag *Capabilities
  70. MaxPacketSize uint64
  71. CharacterSet uint64
  72. Username string
  73. AuthResponseLength uint64
  74. AuthResponse string
  75. Database string
  76. ClientPluginName string
  77. KeyValues map[string]string
  78. }
  79. func (c *Conn) decodeCapabilityFlags(hs *Handshake) {
  80. var cfb = append(hs.CapabilityFlags1.Bytes(), hs.CapabilityFlags2.Bytes()...)
  81. capabilities := c.bitmaskToStruct(cfb, hs.Capabilities).(Capabilities)
  82. hs.Capabilities = &capabilities
  83. }
  84. func (c *Conn) decodeStatusFlags(hs *Handshake) {
  85. status := c.bitmaskToStruct(hs.StatusFlags.Bytes(), hs.Status).(Status)
  86. hs.Status = &status
  87. }
  88. func (c *Conn) decodeHandshakePacket() error {
  89. packet := Handshake{}
  90. packet.PacketLength = c.getInt(TypeFixedInt, 3)
  91. packet.SequenceID = c.getInt(TypeFixedInt, 1)
  92. packet.ProtocolVersion = c.getInt(TypeFixedInt, 1)
  93. packet.ServerVersion = c.getString(TypeNullTerminatedString, 0)
  94. packet.ThreadID = c.getInt(TypeFixedInt, 4)
  95. packet.AuthPluginDataPart1 = c.readBytes(8)
  96. c.discardBytes(1)
  97. packet.CapabilityFlags1 = c.readBytes(2)
  98. packet.Charset = c.getInt(TypeFixedInt, 1)
  99. packet.StatusFlags = c.readBytes(2)
  100. c.decodeStatusFlags(&packet)
  101. packet.CapabilityFlags2 = c.readBytes(2)
  102. c.decodeCapabilityFlags(&packet)
  103. packet.AuthPluginDataLength = c.getInt(TypeFixedInt, 1)
  104. c.discardBytes(10)
  105. packet.AuthPluginDataPart2 = c.readBytes(packet.AuthPluginDataLength - 8)
  106. packet.AuthPluginName = c.getString(TypeNullTerminatedString, 0)
  107. err := c.scanner.Err()
  108. if err != nil {
  109. return err
  110. }
  111. c.Handshake = &packet
  112. return nil
  113. }
  114. func (c *Conn) writeHandshakeResponse() error {
  115. hr := c.NewHandshakeResponse()
  116. cf := c.structToBitmask(hr.ClientFlag)
  117. c.putBytes(cf)
  118. c.putInt(TypeFixedInt, MaxPacketSize, 4)
  119. c.putInt(TypeFixedInt, hr.CharacterSet, 1)
  120. c.putNullBytes(23)
  121. c.putString(TypeNullTerminatedString, hr.Username)
  122. salt := append(c.Handshake.AuthPluginDataPart1.Bytes(), c.Handshake.AuthPluginDataPart2.Bytes()...)
  123. ar := c.cachingSha2Auth(salt, []byte(hr.AuthResponse))
  124. if hr.ClientFlag.PluginAuthLenEncClientData {
  125. c.putInt(TypeLenEncInt, uint64(len(ar)), 0)
  126. c.putBytes(ar)
  127. } else if hr.ClientFlag.SecureConnection {
  128. c.putInt(TypeFixedInt, uint64(len(ar)), 1)
  129. c.putBytes(ar)
  130. } else {
  131. c.putString(TypeNullTerminatedString, c.Config.Pass)
  132. }
  133. // Write database name
  134. if hr.ClientFlag.ConnectWithDB {
  135. c.putString(TypeNullTerminatedString, hr.Database)
  136. }
  137. // Write auth plugin
  138. if hr.ClientFlag.PluginAuth {
  139. c.putString(TypeNullTerminatedString, hr.ClientPluginName)
  140. }
  141. if c.Flush() != nil {
  142. return c.Flush()
  143. }
  144. return nil
  145. }
  146. func (c *Conn) NewHandshakeResponse() *HandshakeResponse {
  147. return &HandshakeResponse{
  148. ClientFlag: &Capabilities{
  149. LongPassword: true,
  150. FoundRows: true,
  151. LongFlag: false,
  152. ConnectWithDB: true,
  153. NoSchema: false,
  154. Compress: false,
  155. ODBC: false,
  156. LocalFiles: false,
  157. IgnoreSpace: true,
  158. Protocol41: true,
  159. Interactive: true,
  160. SSL: false,
  161. IgnoreSigpipe: false,
  162. Transactions: true,
  163. LegacyProtocol41: false,
  164. SecureConnection: false,
  165. MultiStatements: false,
  166. MultiResults: false,
  167. PSMultiResults: true,
  168. PluginAuth: false,
  169. ConnectAttrs: false,
  170. PluginAuthLenEncClientData: true,
  171. CanHandleExpiredPasswords: false,
  172. SessionTrack: false,
  173. DeprecateEOF: false,
  174. SSLVerifyServerCert: false,
  175. OptionalResultSetMetadata: false,
  176. RememberOptions: false,
  177. },
  178. MaxPacketSize: MaxPacketSize,
  179. CharacterSet: 45,
  180. Username: c.Config.User,
  181. AuthResponseLength: uint64(len(c.Config.Pass)),
  182. AuthResponse: c.Config.Pass,
  183. Database: c.Config.Database,
  184. ClientPluginName: c.Handshake.AuthPluginName,
  185. KeyValues: nil,
  186. }
  187. }