handshake.go 5.9 KB

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