handshake.go 6.1 KB

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