handshake.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. package binlog
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "reflect"
  6. )
  7. type Capabilities struct {
  8. LongPassword bool
  9. FoundRows bool
  10. LongFlag bool
  11. ConnectWithDB bool
  12. NoSchema bool
  13. Compress bool
  14. ODBC bool
  15. LocalFiles bool
  16. IgnoreSpace bool
  17. Protocol41 bool
  18. Interactive bool
  19. SSL bool
  20. IgnoreSigpipe bool
  21. Transactions bool
  22. LegacyProtocol41 bool
  23. SecureConnection bool
  24. MultiStatements bool
  25. MultiResults bool
  26. PSMultiResults bool
  27. PluginAuth bool
  28. ConnectAttrs bool
  29. PluginAuthLenEncClientData bool
  30. CanHandleExpiredPasswords bool
  31. SessionTrack bool
  32. DeprecateEOF bool
  33. SSLVerifyServerCert bool
  34. OptionalResultSetMetadata bool
  35. RememberOptions bool
  36. }
  37. type Status struct {
  38. InTrans bool
  39. Autocommit bool
  40. MoreResultsExists bool
  41. QueryNoGoodIndexUsed bool
  42. QueryNoIndexUsed bool
  43. CursorExists bool
  44. LastRowSent bool
  45. DBDropped bool
  46. NoBackslashEscapes bool
  47. MetadataChanged bool
  48. QueryWasSlow bool
  49. PSOutParams bool
  50. InTransReadonly bool
  51. SessionStateChanged bool
  52. }
  53. type Handshake struct {
  54. PacketLength uint64
  55. SequenceID uint64
  56. ProtocolVersion uint64
  57. ServerVersion string
  58. ThreadID uint64
  59. AuthPluginDataPart1 []byte
  60. CapabilityFlags1 []byte
  61. Charset uint64
  62. StatusFlags []byte
  63. CapabilityFlags2 []byte
  64. AuthPluginDataLength uint64
  65. AuthPluginDataPart2 []byte
  66. AuthPluginName string
  67. Capabilities *Capabilities
  68. Status *Status
  69. }
  70. type HandshakeResponse struct {
  71. ClientFlag *Capabilities
  72. MaxPacketSize uint64
  73. CharacterSet uint64
  74. Username string
  75. AuthResponseLength uint64
  76. AuthResponse string
  77. Database string
  78. ClientPluginName string
  79. KeyValues map[string]string
  80. }
  81. func bitmaskToStruct(b []byte, t reflect.Type) interface{} {
  82. l := len(b)
  83. var x uint64
  84. switch {
  85. case l > 32:
  86. x = uint64(binary.LittleEndian.Uint64(b))
  87. case l > 16:
  88. x = uint64(binary.LittleEndian.Uint32(b))
  89. case l > 8:
  90. x = uint64(binary.LittleEndian.Uint16(b))
  91. default:
  92. x = uint64(uint(b[0]))
  93. }
  94. v := reflect.New(t.Elem()).Elem()
  95. for i := 0; i < v.NumField(); i++ {
  96. f := v.Field(i)
  97. flag := uint64(1 << uint(i))
  98. v := x&flag > 0
  99. f.SetBool(v)
  100. }
  101. return v.Interface()
  102. }
  103. func (c *Conn) decodeCapabilityFlags(hs *Handshake) {
  104. var cfb = append(hs.CapabilityFlags1, hs.CapabilityFlags2...)
  105. capabilities := bitmaskToStruct(cfb, reflect.TypeOf(hs.Capabilities)).(Capabilities)
  106. hs.Capabilities = &capabilities
  107. }
  108. func (c *Conn) decodeStatusFlags(hs *Handshake) {
  109. status := bitmaskToStruct(hs.StatusFlags, reflect.TypeOf(hs.Status)).(Status)
  110. hs.Status = &status
  111. }
  112. func (c *Conn) decodeHandshakePacket() error {
  113. packet := Handshake{}
  114. var err error
  115. packet.PacketLength, err = c.getInt(TypeFixedInt, 3)
  116. if err != nil {
  117. return err
  118. }
  119. packet.SequenceID, err = c.getInt(TypeFixedInt, 1)
  120. if err != nil {
  121. return err
  122. }
  123. packet.ProtocolVersion, err = c.getInt(TypeFixedInt, 1)
  124. if err != nil {
  125. return err
  126. }
  127. packet.ServerVersion, err = c.getString(TypeNullTerminatedString, 0)
  128. if err != nil {
  129. return err
  130. }
  131. packet.ThreadID, err = c.getInt(TypeFixedInt, 4)
  132. if err != nil {
  133. return err
  134. }
  135. packet.AuthPluginDataPart1, err = c.getBytes(8)
  136. if err != nil {
  137. return err
  138. }
  139. err = c.consumeBytes(1)
  140. if err != nil {
  141. return err
  142. }
  143. packet.CapabilityFlags1, err = c.getBytes(2)
  144. if err != nil {
  145. return err
  146. }
  147. packet.Charset, err = c.getInt(TypeFixedInt, 1)
  148. if err != nil {
  149. return err
  150. }
  151. packet.StatusFlags, err = c.getBytes(2)
  152. if err != nil {
  153. return err
  154. }
  155. c.decodeStatusFlags(&packet)
  156. packet.CapabilityFlags2, err = c.getBytes(2)
  157. if err != nil {
  158. return err
  159. }
  160. c.decodeCapabilityFlags(&packet)
  161. packet.AuthPluginDataLength, err = c.getInt(TypeFixedInt, 1)
  162. if err != nil {
  163. return err
  164. }
  165. err = c.consumeBytes(10)
  166. if err != nil {
  167. return err
  168. }
  169. packet.AuthPluginDataPart2, err = c.getBytes(packet.AuthPluginDataLength - 8)
  170. if err != nil {
  171. return err
  172. }
  173. packet.AuthPluginName, err = c.getString(TypeNullTerminatedString, 0)
  174. if err != nil {
  175. return err
  176. }
  177. c.Handshake = &packet
  178. return nil
  179. }
  180. func (c *Conn) encodeHandshakeResponse() []byte {
  181. hr := NewHandshakeResponse()
  182. buf := bytes.NewBuffer(make([]byte, 0))
  183. // Capabilities flag.
  184. //var cf capability = 0
  185. // Write Capability Flags.
  186. //buf.Write([]byte(cf))
  187. // Write MaxPacketSize
  188. //buf.Write()
  189. // Write CharacterSet
  190. cs := make([]byte, 2)
  191. binary.LittleEndian.PutUint16(cs, uint16(hr.CharacterSet))
  192. buf.Write(cs[:1])
  193. // Write Filler
  194. buf.Write(make([]byte, 23))
  195. // Write username
  196. u := append([]byte(hr.Username), NullByte)
  197. buf.Write(u)
  198. salt := append(c.Handshake.AuthPluginDataPart1, c.Handshake.AuthPluginDataPart2...)
  199. ar := c.cachingSha2Auth(salt, []byte(hr.AuthResponse))
  200. if hr.ClientFlag.PluginAuthLenEncClientData {
  201. buf.Write(c.encLenEncInt(uint64(len(ar))))
  202. buf.Write(ar)
  203. } else if hr.ClientFlag.SecureConnection {
  204. l := make([]byte, 2)
  205. binary.LittleEndian.PutUint16(l, uint16(len(ar)))
  206. buf.Write(l[:1])
  207. buf.Write(ar)
  208. } else {
  209. buf.Write(append(ar, NullByte))
  210. }
  211. // Write database name
  212. if hr.ClientFlag.ConnectWithDB {
  213. buf.Write(append([]byte(hr.Database), NullByte))
  214. }
  215. // Write auth plugin
  216. if hr.ClientFlag.PluginAuth {
  217. buf.Write([]byte(hr.ClientPluginName))
  218. }
  219. pl := make([]byte, 4)
  220. binary.LittleEndian.PutUint32(pl, uint32(buf.Len()))
  221. p := append(pl[:3], 1)
  222. p = append(p, buf.Bytes()...)
  223. buf = bytes.NewBuffer(p)
  224. return buf.Bytes()
  225. }
  226. func NewHandshakeResponse() *HandshakeResponse {
  227. return &HandshakeResponse{
  228. ClientFlag: &Capabilities{
  229. LongPassword: true,
  230. FoundRows: true,
  231. LongFlag: true,
  232. ConnectWithDB: true,
  233. NoSchema: false,
  234. Compress: false,
  235. ODBC: false,
  236. LocalFiles: false,
  237. IgnoreSpace: true,
  238. Protocol41: true,
  239. Interactive: true,
  240. SSL: false,
  241. IgnoreSigpipe: false,
  242. Transactions: true,
  243. LegacyProtocol41: false,
  244. SecureConnection: true,
  245. MultiStatements: false,
  246. MultiResults: false,
  247. PSMultiResults: true,
  248. PluginAuth: false,
  249. ConnectAttrs: false,
  250. PluginAuthLenEncClientData: false,
  251. CanHandleExpiredPasswords: false,
  252. SessionTrack: true,
  253. DeprecateEOF: true,
  254. SSLVerifyServerCert: false,
  255. OptionalResultSetMetadata: true,
  256. RememberOptions: true,
  257. },
  258. MaxPacketSize: MaxPacketSize,
  259. CharacterSet: 45,
  260. Username: "",
  261. AuthResponseLength: 0,
  262. AuthResponse: "",
  263. Database: "",
  264. ClientPluginName: "",
  265. KeyValues: nil,
  266. }
  267. }