handshake.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. package binlog
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. )
  6. type capabilityFlag uint32
  7. const (
  8. longPassword capabilityFlag = 1 << iota
  9. foundRows
  10. longFlag
  11. connectWithDb
  12. noSchema
  13. compress
  14. odbc
  15. localFiles
  16. ignoreSpace
  17. protocol41
  18. interactive
  19. ssl
  20. ignoreSigpipe
  21. transactions
  22. legacyProtocol41
  23. secureConnection
  24. multiStatements
  25. multiResults
  26. psMultiResults
  27. pluginAuth
  28. connectAttrs
  29. pluginAuthLenEncClientData
  30. canHandleExpiredPasswords
  31. sessionTrack
  32. deprecateEOF
  33. sslVerifyServerCert
  34. optionalResultSetMetadata
  35. rememberOptions
  36. )
  37. type statusFlag uint16
  38. const (
  39. inTrans statusFlag = 1 << iota
  40. autocommit
  41. moreResultsExists
  42. queryNoGoodIndexUsed
  43. queryNoIndexUsed
  44. cursorExists
  45. lastRowSent
  46. dBDropped
  47. noBackslashEscapes
  48. metadataChanged
  49. queryWasSlow
  50. psOutParams
  51. inTransReadonly
  52. sessionStateChanged
  53. )
  54. type CapabilityFlags struct {
  55. LongPassword bool
  56. FoundRows bool
  57. LongFlag bool
  58. ConnectWithDb bool
  59. NoSchema bool
  60. Compress bool
  61. ODBC bool
  62. LocalFiles bool
  63. IgnoreSpace bool
  64. Protocol41 bool
  65. Interactive bool
  66. SSL bool
  67. IgnoreSigpipe bool
  68. Transactions bool
  69. LegacyProtocol41 bool
  70. SecureConnection bool
  71. MultiStatements bool
  72. MultiResults bool
  73. PSMultiResults bool
  74. PluginAuth bool
  75. ConnectAttrs bool
  76. PluginAuthLenEncClientData bool
  77. CanHandleExpiredPasswords bool
  78. SessionTrack bool
  79. DeprecateEOF bool
  80. SSLVerifyServerCert bool
  81. OptionalResultSetMetadata bool
  82. RememberOptions bool
  83. }
  84. type StatusFlags struct {
  85. InTrans bool
  86. Autocommit bool
  87. MoreResultsExists bool
  88. QueryNoGoodIndexUsed bool
  89. QueryNoIndexUsed bool
  90. CursorExists bool
  91. LastRowSent bool
  92. DBDropped bool
  93. NoBackslashEscapes bool
  94. MetadataChanged bool
  95. QueryWasSlow bool
  96. PSOutParams bool
  97. InTransReadonly bool
  98. SessionStateChanged bool
  99. }
  100. type HandshakePacket struct {
  101. PacketLength uint64
  102. SequenceID uint64
  103. ProtocolVersion uint64
  104. ServerVersion string
  105. ThreadID uint64
  106. AuthPluginDataPart1 []byte
  107. CapabilityFlags1 []byte
  108. Charset uint64
  109. Status []byte
  110. CapabilityFlags2 []byte
  111. AuthPluginDataLength uint64
  112. AuthPluginDataPart2 []byte
  113. AuthPluginName string
  114. CapabilityFlags *CapabilityFlags
  115. StatusFlags *StatusFlags
  116. }
  117. type HandshakeResponse struct {
  118. ClientFlag *CapabilityFlags
  119. MaxPacketSize uint64
  120. CharacterSet uint64
  121. Username string
  122. AuthResponseLength uint64
  123. AuthResponse string
  124. Database string
  125. ClientPluginName string
  126. KeyValues map[string]string
  127. }
  128. func (c *Conn) decodeCapabilityFlags(hs *HandshakePacket) {
  129. var cfb = append(hs.CapabilityFlags1, hs.CapabilityFlags2...)
  130. var cf = capabilityFlag(binary.LittleEndian.Uint32(cfb))
  131. hs.CapabilityFlags = &CapabilityFlags{
  132. LongPassword: cf&longPassword == 0,
  133. FoundRows: cf&foundRows == 0,
  134. LongFlag: cf&longFlag == 0,
  135. ConnectWithDb: cf&connectWithDb == 0,
  136. NoSchema: cf&noSchema == 0,
  137. Compress: cf&compress == 0,
  138. ODBC: cf&odbc == 0,
  139. LocalFiles: cf&localFiles == 0,
  140. IgnoreSpace: cf&ignoreSpace == 0,
  141. Protocol41: cf&protocol41 == 0,
  142. Interactive: cf&interactive == 0,
  143. SSL: cf&ssl == 0,
  144. IgnoreSigpipe: cf&ignoreSigpipe == 0,
  145. Transactions: cf&transactions == 0,
  146. LegacyProtocol41: cf&legacyProtocol41 == 0,
  147. SecureConnection: cf&secureConnection == 0,
  148. MultiStatements: cf&multiStatements == 0,
  149. MultiResults: cf&multiResults == 0,
  150. PSMultiResults: cf&psMultiResults == 0,
  151. PluginAuth: cf&pluginAuth == 0,
  152. ConnectAttrs: cf&connectAttrs == 0,
  153. PluginAuthLenEncClientData: cf&pluginAuthLenEncClientData == 0,
  154. CanHandleExpiredPasswords: cf&canHandleExpiredPasswords == 0,
  155. SessionTrack: cf&sessionTrack == 0,
  156. DeprecateEOF: cf&deprecateEOF == 0,
  157. SSLVerifyServerCert: cf&sslVerifyServerCert == 0,
  158. OptionalResultSetMetadata: cf&optionalResultSetMetadata == 0,
  159. RememberOptions: cf&rememberOptions == 0,
  160. }
  161. }
  162. func (c *Conn) decodeStatusFlags(hs *HandshakePacket) {
  163. var sf = statusFlag(binary.LittleEndian.Uint32(hs.Status))
  164. hs.StatusFlags = &StatusFlags{
  165. InTrans: sf&inTrans == 0,
  166. Autocommit: sf&autocommit == 0,
  167. MoreResultsExists: sf&moreResultsExists == 0,
  168. QueryNoGoodIndexUsed: sf&queryNoGoodIndexUsed == 0,
  169. QueryNoIndexUsed: sf&queryNoIndexUsed == 0,
  170. CursorExists: sf&cursorExists == 0,
  171. LastRowSent: sf&lastRowSent == 0,
  172. DBDropped: sf&dBDropped == 0,
  173. NoBackslashEscapes: sf&noBackslashEscapes == 0,
  174. MetadataChanged: sf&metadataChanged == 0,
  175. QueryWasSlow: sf&queryWasSlow == 0,
  176. PSOutParams: sf&psOutParams == 0,
  177. InTransReadonly: sf&inTransReadonly == 0,
  178. SessionStateChanged: sf&sessionStateChanged == 0,
  179. }
  180. }
  181. func (c *Conn) decodeHandshakePacket() error {
  182. packet := HandshakePacket{}
  183. var err error
  184. packet.PacketLength, err = c.getInt(TypeFixedInt, 3)
  185. if err != nil {
  186. return err
  187. }
  188. packet.SequenceID, err = c.getInt(TypeFixedInt, 1)
  189. if err != nil {
  190. return err
  191. }
  192. packet.ProtocolVersion, err = c.getInt(TypeFixedInt, 1)
  193. if err != nil {
  194. return err
  195. }
  196. packet.ServerVersion, err = c.getString(TypeNullTerminatedString, 0)
  197. if err != nil {
  198. return err
  199. }
  200. packet.ThreadID, err = c.getInt(TypeFixedInt, 4)
  201. if err != nil {
  202. return err
  203. }
  204. packet.AuthPluginDataPart1, err = c.getBytes(8)
  205. if err != nil {
  206. return err
  207. }
  208. err = c.consumeBytes(1)
  209. if err != nil {
  210. return err
  211. }
  212. packet.CapabilityFlags1, err = c.getBytes(2)
  213. if err != nil {
  214. return err
  215. }
  216. packet.Charset, err = c.getInt(TypeFixedInt, 1)
  217. if err != nil {
  218. return err
  219. }
  220. packet.Status, err = c.getBytes(2)
  221. if err != nil {
  222. return err
  223. }
  224. c.decodeStatusFlags(&packet)
  225. packet.CapabilityFlags2, err = c.getBytes(2)
  226. if err != nil {
  227. return err
  228. }
  229. c.decodeCapabilityFlags(&packet)
  230. packet.AuthPluginDataLength, err = c.getInt(TypeFixedInt, 1)
  231. if err != nil {
  232. return err
  233. }
  234. err = c.consumeBytes(10)
  235. if err != nil {
  236. return err
  237. }
  238. packet.AuthPluginDataPart2, err = c.getBytes(packet.AuthPluginDataLength - 8)
  239. if err != nil {
  240. return err
  241. }
  242. packet.AuthPluginName, err = c.getString(TypeNullTerminatedString, 0)
  243. if err != nil {
  244. return err
  245. }
  246. c.Handshake = &packet
  247. return nil
  248. }
  249. func (c *Conn) encodeHandshakeResponse() []byte {
  250. hr := NewHandshakeResponse()
  251. buf := bytes.NewBuffer(make([]byte, 0))
  252. // Capabilities flag.
  253. flags := make([]byte, 4)
  254. if hr.ClientFlag.LongPassword {
  255. flags[0] |= 0x1
  256. }
  257. if hr.ClientFlag.FoundRows {
  258. flags[0] |= 0x2
  259. }
  260. if hr.ClientFlag.LongFlag {
  261. flags[0] |= 0x4
  262. }
  263. if hr.ClientFlag.ConnectWithDb {
  264. flags[0] |= 0x8
  265. }
  266. if hr.ClientFlag.NoSchema {
  267. flags[0] |= 0x10
  268. }
  269. if hr.ClientFlag.Compress {
  270. flags[0] |= 0x20
  271. }
  272. if hr.ClientFlag.ODBC {
  273. flags[0] |= 0x40
  274. }
  275. if hr.ClientFlag.LocalFiles {
  276. flags[0] |= 0x80
  277. }
  278. if hr.ClientFlag.IgnoreSpace {
  279. flags[1] |= 0x1
  280. }
  281. if hr.ClientFlag.Protocol41 {
  282. flags[1] |= 0x2
  283. }
  284. if hr.ClientFlag.Interactive {
  285. flags[1] |= 0x4
  286. }
  287. if hr.ClientFlag.SSL {
  288. flags[1] |= 0x8
  289. }
  290. if hr.ClientFlag.IgnoreSigpipe {
  291. flags[1] |= 0x10
  292. }
  293. if hr.ClientFlag.Transactions {
  294. flags[1] |= 0x20
  295. }
  296. if hr.ClientFlag.LegacyProtocol41 {
  297. flags[1] |= 0x40
  298. }
  299. if hr.ClientFlag.SecureConnection {
  300. flags[1] |= 0x80
  301. }
  302. if hr.ClientFlag.MultiStatements {
  303. flags[2] |= 0x1
  304. }
  305. if hr.ClientFlag.MultiResults {
  306. flags[2] |= 0x2
  307. }
  308. if hr.ClientFlag.PSMultiResults {
  309. flags[2] |= 0x4
  310. }
  311. if hr.ClientFlag.PluginAuth {
  312. flags[2] |= 0x8
  313. }
  314. if hr.ClientFlag.ConnectAttrs {
  315. flags[2] |= 0x10
  316. }
  317. if hr.ClientFlag.PluginAuthLenEncClientData {
  318. flags[2] |= 0x20
  319. }
  320. if hr.ClientFlag.CanHandleExpiredPasswords {
  321. flags[2] |= 0x40
  322. }
  323. if hr.ClientFlag.SessionTrack {
  324. flags[2] |= 0x80
  325. }
  326. if hr.ClientFlag.DeprecateEOF {
  327. flags[3] |= 0x1
  328. }
  329. if hr.ClientFlag.SSLVerifyServerCert {
  330. flags[3] |= 0x2
  331. }
  332. if hr.ClientFlag.OptionalResultSetMetadata {
  333. flags[3] |= 0x4
  334. }
  335. if hr.ClientFlag.RememberOptions {
  336. flags[3] |= 0x8
  337. }
  338. // Write Capability Flags.
  339. buf.Write(flags)
  340. // Write MaxPacketSize
  341. //buf.Write()
  342. // Write CharacterSet
  343. cs := make([]byte, 2)
  344. binary.LittleEndian.PutUint16(cs, uint16(hr.CharacterSet))
  345. buf.Write(cs[:1])
  346. // Write Filler
  347. buf.Write(make([]byte, 23))
  348. // Write username
  349. u := append([]byte(hr.Username), NullByte)
  350. buf.Write(u)
  351. salt := append(c.Handshake.AuthPluginDataPart1, c.Handshake.AuthPluginDataPart2...)
  352. ar := c.cachingSha2Auth(salt, []byte(hr.AuthResponse))
  353. if hr.ClientFlag.PluginAuthLenEncClientData {
  354. buf.Write(c.encLenEncInt(uint64(len(ar))))
  355. buf.Write(ar)
  356. } else if hr.ClientFlag.SecureConnection {
  357. l := make([]byte, 2)
  358. binary.LittleEndian.PutUint16(l, uint16(len(ar)))
  359. buf.Write(l[:1])
  360. buf.Write(ar)
  361. } else {
  362. buf.Write(append(ar, NullByte))
  363. }
  364. // Write database name
  365. if hr.ClientFlag.ConnectWithDb {
  366. buf.Write(append([]byte(hr.Database), NullByte))
  367. }
  368. // Write auth plugin
  369. if hr.ClientFlag.PluginAuth {
  370. buf.Write([]byte(hr.ClientPluginName))
  371. }
  372. pl := make([]byte, 4)
  373. binary.LittleEndian.PutUint32(pl, uint32(buf.Len()))
  374. p := append(pl[:3], 1)
  375. p = append(p, buf.Bytes()...)
  376. buf = bytes.NewBuffer(p)
  377. return buf.Bytes()
  378. }
  379. func NewHandshakeResponse() *HandshakeResponse {
  380. return &HandshakeResponse{
  381. ClientFlag: &CapabilityFlags{
  382. LongPassword: true,
  383. FoundRows: true,
  384. LongFlag: true,
  385. ConnectWithDb: true,
  386. NoSchema: false,
  387. Compress: false,
  388. ODBC: false,
  389. LocalFiles: false,
  390. IgnoreSpace: true,
  391. Protocol41: true,
  392. Interactive: true,
  393. SSL: false,
  394. IgnoreSigpipe: false,
  395. Transactions: true,
  396. LegacyProtocol41: false,
  397. SecureConnection: true,
  398. MultiStatements: false,
  399. MultiResults: false,
  400. PSMultiResults: true,
  401. PluginAuth: false,
  402. ConnectAttrs: false,
  403. PluginAuthLenEncClientData: false,
  404. CanHandleExpiredPasswords: false,
  405. SessionTrack: true,
  406. DeprecateEOF: true,
  407. SSLVerifyServerCert: false,
  408. OptionalResultSetMetadata: true,
  409. RememberOptions: true,
  410. },
  411. MaxPacketSize: MaxPacketSize,
  412. CharacterSet: 45,
  413. Username: "",
  414. AuthResponseLength: 0,
  415. AuthResponse: "",
  416. Database: "",
  417. ClientPluginName: "",
  418. KeyValues: nil,
  419. }
  420. }