handshake.go 10 KB

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