handshake.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. package binlog
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. )
  6. type CapabilityFlags 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 StatusFlags struct {
  37. StatusInTrans bool
  38. StatusAutocommit bool
  39. MoreResultsExists bool
  40. QueryNoGoodIndexUsed bool
  41. QueryNoIndexUsed bool
  42. StatusCursorExists bool
  43. StatusLastRowSent bool
  44. StatusDBDropped bool
  45. StatusNoBackslashEscapes bool
  46. StatusMetadataChanged bool
  47. QueryWasSlow bool
  48. PSOutParams bool
  49. StatusInTransReadonly bool
  50. SessionStateChanged bool
  51. }
  52. type HandshakePacket struct {
  53. PacketLength uint64
  54. SequenceID uint64
  55. ProtocolVersion uint64
  56. ServerVersion string
  57. ThreadID uint64
  58. AuthPluginDataPart1 []byte
  59. CapabilityFlags1 []byte
  60. Charset uint64
  61. Status []byte
  62. CapabilityFlags2 []byte
  63. AuthPluginDataLength uint64
  64. AuthPluginDataPart2 []byte
  65. AuthPluginName string
  66. CapabilityFlags *CapabilityFlags
  67. StatusFlags *StatusFlags
  68. }
  69. type HandshakeResponse struct {
  70. ClientFlag *CapabilityFlags
  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 *HandshakePacket) {
  81. hs.CapabilityFlags = &CapabilityFlags{
  82. LongPassword: (hs.CapabilityFlags1[0] & 1) > 0,
  83. FoundRows: (hs.CapabilityFlags1[0] & 2) > 0,
  84. LongFlag: (hs.CapabilityFlags1[0] & 4) > 0,
  85. ConnectWithDb: (hs.CapabilityFlags1[0] & 8) > 0,
  86. NoSchema: (hs.CapabilityFlags1[0] & 16) > 0,
  87. Compress: (hs.CapabilityFlags1[0] & 32) > 0,
  88. ODBC: (hs.CapabilityFlags1[0] & 64) > 0,
  89. LocalFiles: (hs.CapabilityFlags1[0] & 128) > 0,
  90. IgnoreSpace: (hs.CapabilityFlags1[1] & 1) > 0,
  91. Protocol41: (hs.CapabilityFlags1[1] & 2) > 0,
  92. Interactive: (hs.CapabilityFlags1[1] & 4) > 0,
  93. SSL: (hs.CapabilityFlags1[1] & 8) > 0,
  94. IgnoreSigpipe: (hs.CapabilityFlags1[1] & 16) > 0,
  95. Transactions: (hs.CapabilityFlags1[1] & 32) > 0,
  96. LegacyProtocol41: (hs.CapabilityFlags1[1] & 64) > 0,
  97. SecureConnection: (hs.CapabilityFlags1[1] & 128) > 0,
  98. MultiStatements: (hs.CapabilityFlags2[0] & 1) > 0,
  99. MultiResults: (hs.CapabilityFlags2[0] & 2) > 0,
  100. PSMultiResults: (hs.CapabilityFlags2[0] & 4) > 0,
  101. PluginAuth: (hs.CapabilityFlags2[0] & 8) > 0,
  102. ConnectAttrs: (hs.CapabilityFlags2[0] & 16) > 0,
  103. PluginAuthLenEncClientData: (hs.CapabilityFlags2[0] & 32) > 0,
  104. CanHandleExpiredPasswords: (hs.CapabilityFlags2[0] & 64) > 0,
  105. SessionTrack: (hs.CapabilityFlags2[0] & 128) > 0,
  106. DeprecateEOF: (hs.CapabilityFlags2[1] & 1) > 0,
  107. SSLVerifyServerCert: (hs.CapabilityFlags2[1] & 2) > 0,
  108. OptionalResultSetMetadata: (hs.CapabilityFlags2[1] & 4) > 0,
  109. RememberOptions: (hs.CapabilityFlags2[1] & 8) > 0,
  110. }
  111. }
  112. func (c *Conn) decodeStatusFlags(hs *HandshakePacket) {
  113. hs.StatusFlags = &StatusFlags{
  114. StatusInTrans: (hs.Status[0] & 1) > 0,
  115. StatusAutocommit: (hs.Status[0] & 2) > 0,
  116. MoreResultsExists: (hs.Status[0] & 4) > 0,
  117. QueryNoGoodIndexUsed: (hs.Status[0] & 8) > 0,
  118. QueryNoIndexUsed: (hs.Status[0] & 16) > 0,
  119. StatusCursorExists: (hs.Status[0] & 32) > 0,
  120. StatusLastRowSent: (hs.Status[0] & 64) > 0,
  121. StatusDBDropped: (hs.Status[0] & 128) > 0,
  122. StatusNoBackslashEscapes: (hs.Status[1] & 1) > 0,
  123. StatusMetadataChanged: (hs.Status[1] & 2) > 0,
  124. QueryWasSlow: (hs.Status[1] & 4) > 0,
  125. PSOutParams: (hs.Status[1] & 8) > 0,
  126. StatusInTransReadonly: (hs.Status[1] & 16) > 0,
  127. SessionStateChanged: (hs.Status[1] & 32) > 0,
  128. }
  129. }
  130. func (c *Conn) decodeHandshakePacket() error {
  131. packet := HandshakePacket{}
  132. var err error
  133. packet.PacketLength, err = c.getInt(TypeFixedInt, 3)
  134. if err != nil {
  135. return err
  136. }
  137. packet.SequenceID, err = c.getInt(TypeFixedInt, 1)
  138. if err != nil {
  139. return err
  140. }
  141. packet.ProtocolVersion, err = c.getInt(TypeFixedInt, 1)
  142. if err != nil {
  143. return err
  144. }
  145. packet.ServerVersion, err = c.getString(TypeNullTerminatedString, 0)
  146. if err != nil {
  147. return err
  148. }
  149. packet.ThreadID, err = c.getInt(TypeFixedInt, 4)
  150. if err != nil {
  151. return err
  152. }
  153. packet.AuthPluginDataPart1, err = c.getBytes(8)
  154. if err != nil {
  155. return err
  156. }
  157. err = c.consumeBytes(1)
  158. if err != nil {
  159. return err
  160. }
  161. packet.CapabilityFlags1, err = c.getBytes(2)
  162. if err != nil {
  163. return err
  164. }
  165. packet.Charset, err = c.getInt(TypeFixedInt, 1)
  166. if err != nil {
  167. return err
  168. }
  169. packet.Status, err = c.getBytes(2)
  170. if err != nil {
  171. return err
  172. }
  173. c.decodeStatusFlags(&packet)
  174. packet.CapabilityFlags2, err = c.getBytes(2)
  175. if err != nil {
  176. return err
  177. }
  178. c.decodeCapabilityFlags(&packet)
  179. packet.AuthPluginDataLength, err = c.getInt(TypeFixedInt, 1)
  180. if err != nil {
  181. return err
  182. }
  183. err = c.consumeBytes(10)
  184. if err != nil {
  185. return err
  186. }
  187. packet.AuthPluginDataPart2, err = c.getBytes(packet.AuthPluginDataLength - 8)
  188. if err != nil {
  189. return err
  190. }
  191. packet.AuthPluginName, err = c.getString(TypeNullTerminatedString, 0)
  192. if err != nil {
  193. return err
  194. }
  195. c.Handshake = &packet
  196. return nil
  197. }
  198. func (c *Conn) encodeHandshakeResponse() []byte {
  199. hr := NewHandshakeResponse()
  200. buf := bytes.NewBuffer(make([]byte, 0))
  201. // Capabilities flag.
  202. flags := make([]byte, 4)
  203. if hr.ClientFlag.LongPassword {
  204. flags[0] |= 0x1
  205. }
  206. if hr.ClientFlag.FoundRows {
  207. flags[0] |= 0x2
  208. }
  209. if hr.ClientFlag.LongFlag {
  210. flags[0] |= 0x4
  211. }
  212. if hr.ClientFlag.ConnectWithDb {
  213. flags[0] |= 0x8
  214. }
  215. if hr.ClientFlag.NoSchema {
  216. flags[0] |= 0x10
  217. }
  218. if hr.ClientFlag.Compress {
  219. flags[0] |= 0x20
  220. }
  221. if hr.ClientFlag.ODBC {
  222. flags[0] |= 0x40
  223. }
  224. if hr.ClientFlag.LocalFiles {
  225. flags[0] |= 0x80
  226. }
  227. if hr.ClientFlag.IgnoreSpace {
  228. flags[1] |= 0x1
  229. }
  230. if hr.ClientFlag.Protocol41 {
  231. flags[1] |= 0x2
  232. }
  233. if hr.ClientFlag.Interactive {
  234. flags[1] |= 0x4
  235. }
  236. if hr.ClientFlag.SSL {
  237. flags[1] |= 0x8
  238. }
  239. if hr.ClientFlag.IgnoreSigpipe {
  240. flags[1] |= 0x10
  241. }
  242. if hr.ClientFlag.Transactions {
  243. flags[1] |= 0x20
  244. }
  245. if hr.ClientFlag.LegacyProtocol41 {
  246. flags[1] |= 0x40
  247. }
  248. if hr.ClientFlag.SecureConnection {
  249. flags[1] |= 0x80
  250. }
  251. if hr.ClientFlag.MultiStatements {
  252. flags[2] |= 0x1
  253. }
  254. if hr.ClientFlag.MultiResults {
  255. flags[2] |= 0x2
  256. }
  257. if hr.ClientFlag.PSMultiResults {
  258. flags[2] |= 0x4
  259. }
  260. if hr.ClientFlag.PluginAuth {
  261. flags[2] |= 0x8
  262. }
  263. if hr.ClientFlag.ConnectAttrs {
  264. flags[2] |= 0x10
  265. }
  266. if hr.ClientFlag.PluginAuthLenEncClientData {
  267. flags[2] |= 0x20
  268. }
  269. if hr.ClientFlag.CanHandleExpiredPasswords {
  270. flags[2] |= 0x40
  271. }
  272. if hr.ClientFlag.SessionTrack {
  273. flags[2] |= 0x80
  274. }
  275. if hr.ClientFlag.DeprecateEOF {
  276. flags[3] |= 0x1
  277. }
  278. if hr.ClientFlag.SSLVerifyServerCert {
  279. flags[3] |= 0x2
  280. }
  281. if hr.ClientFlag.OptionalResultSetMetadata {
  282. flags[3] |= 0x4
  283. }
  284. if hr.ClientFlag.RememberOptions {
  285. flags[3] |= 0x8
  286. }
  287. // Write Capability Flags.
  288. buf.Write(flags)
  289. // Write MaxPacketSize
  290. //buf.Write()
  291. // Write CharacterSet
  292. cs := make([]byte, 2)
  293. binary.LittleEndian.PutUint16(cs, uint16(hr.CharacterSet))
  294. buf.Write(cs[:1])
  295. // Write Filler
  296. buf.Write(make([]byte, 23))
  297. // Write username
  298. u := append([]byte(hr.Username), NullByte)
  299. buf.Write(u)
  300. salt := append(c.Handshake.AuthPluginDataPart1, c.Handshake.AuthPluginDataPart2...)
  301. ar := c.cachingSha2Auth(salt, []byte(hr.AuthResponse))
  302. if hr.ClientFlag.PluginAuthLenEncClientData {
  303. buf.Write(c.encLenEncInt(uint64(len(ar))))
  304. buf.Write(ar)
  305. } else if hr.ClientFlag.SecureConnection {
  306. l := make([]byte, 2)
  307. binary.LittleEndian.PutUint16(l, uint16(len(ar)))
  308. buf.Write(l[:1])
  309. buf.Write(ar)
  310. } else {
  311. buf.Write(append(ar, NullByte))
  312. }
  313. // Write database name
  314. if hr.ClientFlag.ConnectWithDb {
  315. buf.Write(append([]byte(hr.Database), NullByte))
  316. }
  317. // Write auth plugin
  318. if hr.ClientFlag.PluginAuth {
  319. buf.Write([]byte(hr.ClientPluginName))
  320. }
  321. pl := make([]byte, 4)
  322. binary.LittleEndian.PutUint32(pl, uint32(buf.Len()))
  323. p := append(pl[:3], 1)
  324. p = append(p, buf.Bytes()...)
  325. buf = bytes.NewBuffer(p)
  326. return buf.Bytes()
  327. }
  328. func NewHandshakeResponse() *HandshakeResponse {
  329. return &HandshakeResponse{
  330. ClientFlag: &CapabilityFlags{
  331. LongPassword: true,
  332. FoundRows: true,
  333. LongFlag: true,
  334. ConnectWithDb: true,
  335. NoSchema: false,
  336. Compress: false,
  337. ODBC: false,
  338. LocalFiles: false,
  339. IgnoreSpace: true,
  340. Protocol41: true,
  341. Interactive: true,
  342. SSL: false,
  343. IgnoreSigpipe: false,
  344. Transactions: true,
  345. LegacyProtocol41: false,
  346. SecureConnection: true,
  347. MultiStatements: false,
  348. MultiResults: false,
  349. PSMultiResults: true,
  350. PluginAuth: false,
  351. ConnectAttrs: false,
  352. PluginAuthLenEncClientData: false,
  353. CanHandleExpiredPasswords: false,
  354. SessionTrack: true,
  355. DeprecateEOF: true,
  356. SSLVerifyServerCert: false,
  357. OptionalResultSetMetadata: true,
  358. RememberOptions: true,
  359. },
  360. MaxPacketSize: MaxPacketSize,
  361. CharacterSet: 45,
  362. Username: "",
  363. AuthResponseLength: 0,
  364. AuthResponse: "",
  365. Database: "",
  366. ClientPluginName: "",
  367. KeyValues: nil,
  368. }
  369. }