Upgrade to Pro — share decks privately, control downloads, hide ads and more …

第一回データベースについて語る会

 第一回データベースについて語る会

データベースのクライアント作成に関する話

MySQLのクライアント作成の時の話ですが、他のデータベースでも同じようなことが言えるかもしれません。

自分が初めて作成した時の知見を元に発表を行いますので、資料に間違った情報があるかもしれませんがご了承ください。

間違っている箇所や、もっとこうした方が良いなどありましたら教えてください!

Takahiko Tominaga

July 25, 2024
Tweet

Other Decks in Programming

Transcript

  1. 自己紹介 名前: 富永 孝彦 (とみなが たかひこ) 所属: 株式会社 Nextbeat SNS

    X: @takapi327 Github: https://github.com/takapi327 趣味 プログラミング大好き
  2. ngrepの使用方法 `-x`: キャプチャしたパケットのデータ部分を16進数形式で表示します。各バイトが2桁の16進数で表示され、可読なASCII文字が表示されます。 `-q`: 出力の際にパケットのデータ部分のみを表示し、その他の情報を抑制します。これは「クワイエットモード」 (quiet mode)として知られています。 `-d`: デバイスを指定します。ここでは`lo0`を指定しています。`lo0`はループバックインターフェースを指しています。ループバックインターフェースは、ローカル ホスト(`127.0.0.1`)との通信を行うために使用されます。

    `''`: フィルタ条件として空の文字列を指定しています。これは、特定の内容に関するフィルタリングを行わないことを意味します。すべてのパケットをキャプチャ 対象とする場合に使用されます。 `'port 3306'`: キャプチャ対象のパケットをTCPまたはUDPのポート番号`3306`に限定します。この場合、MySQLデータベースが通常使用するポート番号3306に対 するパケットがキャプチャ対象となります。 1 sudo ngrep -x -q -d lo0 '' 'port 3306'
  3. ngrepの使用方法 `-x`: キャプチャしたパケットのデータ部分を16進数形式で表示します。各バイトが2桁の16進数で表示され、可読なASCII文字が表示されます。 `-q`: 出力の際にパケットのデータ部分のみを表示し、その他の情報を抑制します。これは「クワイエットモード」 (quiet mode)として知られています。 `-d`: デバイスを指定します。ここでは`lo0`を指定しています。`lo0`はループバックインターフェースを指しています。ループバックインターフェースは、ローカル ホスト(`127.0.0.1`)との通信を行うために使用されます。

    `''`: フィルタ条件として空の文字列を指定しています。これは、特定の内容に関するフィルタリングを行わないことを意味します。すべてのパケットをキャプチャ 対象とする場合に使用されます。 `'port 3306'`: キャプチャ対象のパケットをTCPまたはUDPのポート番号`3306`に限定します。この場合、MySQLデータベースが通常使用するポート番号3306に対 するパケットがキャプチャ対象となります。 このコマンドは、MySQLサーバーへのすべてのトラフィック(ループバックインターフェース経由で送受信さ れるもの)を16進数形式で出力します。 1 sudo ngrep -x -q -d lo0 '' 'port 3306'
  4. ngrepの使用方法 // step 3 sudo ngrep -x -q -d lo0

    '' 'port 3306' Password: interface: lo0 (127.0.0.0/255.0.0.0) filter: ( port 3306 ) and (ip || ip6) 1 2 3 4 5
  5. ngrepの使用方法 interface: lo0 (127.0.0.0/255.0.0.0) filter: ( port 3306 ) and

    (ip || ip6) 1 // step 3 2 sudo ngrep -x -q -d lo0 '' 'port 3306' 3 Password: 4 5
  6. ngrepの使用方法 // step 3 sudo ngrep -x -q -d lo0

    '' 'port 3306' Password: interface: lo0 (127.0.0.0/255.0.0.0) filter: ( port 3306 ) and (ip || ip6) 1 2 3 4 5
  7. ngrepの使用方法 // step 5 sudo ngrep -x -q -d lo0

    '' 'port 3306' Password: interface: lo0 (127.0.0.0/255.0.0.0) filter: ( port 3306 ) and (ip || ip6) T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password. 1 2 3 4 5 6 7 8 9 10 11 12
  8. ngrepの使用方法 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 4a 00 00

    00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password. 1 // step 5 2 sudo ngrep -x -q -d lo0 '' 'port 3306' 3 Password: 4 interface: lo0 (127.0.0.0/255.0.0.0) 5 filter: ( port 3306 ) and (ip || ip6) 6 7 8 9 10 11 12
  9. ngrepの使用方法 // step 5 sudo ngrep -x -q -d lo0

    '' 'port 3306' Password: interface: lo0 (127.0.0.0/255.0.0.0) filter: ( port 3306 ) and (ip || ip6) T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password. 1 2 3 4 5 6 7 8 9 10 11 12
  10. パケットの見方 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a

    00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  11. パケットの見方 この部分はパケットがどこからどこへ送信されたかを示しています。ここでは、MySQLサーバーからMySQLク ライアントへの通信を示しています。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  12. パケットの見方 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a

    00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  13. パケットの見方 この部分はパケットのデータ部分を示しています。ここでは、MySQLサーバーからMySQLクライアントへの通 信データを示しています。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  14. パケットの見方 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a

    00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  15. パケットの見方 パケットは各2桁の16進数が1バイトを表しています。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2

    4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  16. パケットの見方 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a

    00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  17. パケットの見方 MySQLでは最初の4バイトはヘッダー部分を示しており、それ以外の部分はボディのデータ部分を示していま す。 ペイロードの長さ (最初の3バイト) Sequence ID (最後の1バイト) 1 T

    127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  18. パケットの見方 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a

    00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  19. パケットの見方 この右に表示されているデータは、パケットのデータ部分をASCII文字列で表現したものです。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2

    4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  20. 固定長整数の例 例えば、3バイトの固定長整数(int<3>)の場合。3バイトのデータで一つの整数を表現します。 バイト順序 16進数 10進数 バイト1 0x01 1 バイト2 0x02

    2 バイト3 0x03 3 この場合、値は0x010203となり、これを10進数に変換すると291になります。 つまり、int<3>というデータ型の場合はバイト配列の内、3つのバイトで表現を行っているということです。
  21. ペイロードの長さ: int<3> つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  22. ペイロードの長さ: int<3> つまり この3桁がペイロードの長さを示しています。この場合、0x4a000000を10進数に変換すると74になります。 ※ つまり、このパケットのペイロード部分は74個のバイトで構成されているということ 1 T 127.0.0.1:3306 ->

    127.0.0.1:56281 [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  23. シークエンスID: int<1> つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  24. シークエンスID: int<1> つまり この1桁がシークエンスIDを示しています。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP]

    #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  25. 例えば、文字列 "Hello" を string<NULL> としてエンコードすると以下のようになります: 文字列 16進数 H 0x48 e

    0x65 l 0x6c l 0x6c o 0x6f NULL 0x00 この場合、文字列 "Hello" は16進数で "48 65 6C 6C 6F 00" と表現されます。最後の00バイトが、文字列の終わ りを示すNULL終端文字です。
  26. 例えば、長さが5の文字列 "Hello" の場合: データ バイト例 長さ (5) 05 文字列 "Hello"

    48 65 6C 6C 6F つまり、"Hello" の長さエンコードされた文字列は "05 48 65 6C 6C 6F" となります。
  27. プロトコルバージョン: int<1> つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  28. プロトコルバージョン: int<1> つまり この1桁がプロトコルバージョン(`int<1>`)を示しています。常に10進数の10になります。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP]

    #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  29. サーバーバージョン: string<NULL> つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  30. サーバーバージョン: string<NULL> つまり ここで0がきているので、NULL終端文字列の終わりを示しているとわかる。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP]

    #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  31. サーバーバージョン: string<NULL> つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  32. サーバーバージョン: string<NULL> つまり なので、ここまでのデータはサーバーバージョンを示しているとわかる。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP]

    #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  33. スレッドID: int<4> つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  34. スレッドID: int<4> つまり この4桁がスレッドID(`int<4>`)を示しています。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP]

    #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  35. 認証プラグインのランダムデータ1: string<8> つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  36. 認証プラグインのランダムデータ1: string<8> つまり この8桁が認証プラグインのランダムデータ1を示しています。 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP]

    #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  37. 認証プラグインのランダムデータ2の長さ: int<1> つまり (※ 先ほどからの間にあるパケットは省略しています) 1 T 127.0.0.1:3306 -> 127.0.0.1:56281

    [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  38. 認証プラグインのランダムデータ2の長さ: int<1> つまり (※ 先ほどからの間にあるパケットは省略しています) この1桁が長さを示しています。15は10進数で17になります。 今回取得したいデータは、`$len=MAX(13, length of auth-plugin-data

    - 8)`という条件があるので、取得した長 さを使い計算すると 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  39. 認証プラグインのランダムデータ2の長さ: int<1> つまり (※ 先ほどからの間にあるパケットは省略しています) この1桁が長さを示しています。15は10進数で17になります。 今回取得したいデータは、`$len=MAX(13, length of auth-plugin-data

    - 8)`という条件があるので、取得した長 さを使い計算すると `$len=MAX(13, 17 - 8)` 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  40. 認証プラグインのランダムデータ2の長さ: int<1> つまり (※ 先ほどからの間にあるパケットは省略しています) この1桁が長さを示しています。15は10進数で17になります。 今回取得したいデータは、`$len=MAX(13, length of auth-plugin-data

    - 8)`という条件があるので、取得した長 さを使い計算すると `$len=MAX(13, 17 - 8)` `$len=MAX(13, 9)` 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  41. 認証プラグインのランダムデータ2の長さ: int<1> つまり (※ 先ほどからの間にあるパケットは省略しています) この1桁が長さを示しています。15は10進数で17になります。 今回取得したいデータは、`$len=MAX(13, length of auth-plugin-data

    - 8)`という条件があるので、取得した長 さを使い計算すると `$len=MAX(13, 17 - 8)` `$len=MAX(13, 9)` `$len=13` 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  42. 認証プラグインのランダムデータ: $length つまり 1 T 127.0.0.1:3306 -> 127.0.0.1:56281 [AP] #5

    2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  43. 認証プラグインのランダムデータ: $length つまり この範囲(13)のデータが認証プラグインのランダムデータを示しています。 ※ 間にreserved: `string[10]`があるので、その値は飛ばしています。(全て0の値) 1 T 127.0.0.1:3306

    -> 127.0.0.1:56281 [AP] #5 2 4a 00 00 00 0a 38 2e 30 2e 33 33 00 9b 19 00 00 J....8.0.33..... 3 69 26 73 2a 75 08 1c 2c 00 ff ff ff 02 00 ff df i&s*u..,.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 63 01 02 01 2e ...........c.... 5 3e 45 23 57 31 7f 5b 00 63 61 63 68 69 6e 67 5f >E#W1.[.caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  44. 雑に送ってみる ``` 4a 00 00 00 ``` 上記はMySQLサーバーから送られてくるパケットの一部です。それぞれ以下要件に従ってデコードするコードをScalaで作成してください。 - Scodecライブラリを使用

    - 最初の3つはペイロードの長さとしてデコード - 最後の1つはシークエンスIDとしてデコード ※ ライブラリの指定はしなくても良い (使いたいものがあれば指定)
  45. 生成されたコード ※ プロンプトや使用言語、その時の調子によって精度は変わります。 1 import scodec._ 2 import scodec.bits._ 3

    import scodec.codecs._ 4 import scodec.Attempt._ 5 6 case class MySQLPacket( 7 payloadLength: Int, 8 sequenceId: Int 9 )
  46. object MySQLPacketDecoder: // ペイロード長とシーケンスIDのコーデック定義 val payloadLengthCodec: Codec[Int] = ("payloadLength" |

    uint24L) val sequenceIdCodec: Codec[Int] = ("sequenceId" | uint8L) // MySQLPacket用にコーデックを1つにまとめる val mySQLPacketCodec: Codec[MySQLPacket] = ( payloadLengthCodec :: sequenceIdCodec ).as[MySQLPacket] def main(args: Array[String]): Unit = // 16進文字列をバイト列に変換 val hexString = "4a000000" val bytesOpt = ByteVector.fromHex(hexString) // ByteVectorが正常に作成されたことを確認する。 bytesOpt match case Some(bytes) => // パケットをデコードする mySQLPacketCodec.decode(bytes.bits) match case Successful(DecodeResult(packet, _)) => println(s"Payload Length: ${packet.payloadLength}") println(s"Sequence ID: ${packet.sequenceId}") case Failure(err) => println(s"Failed to decode: $err") case None => println(s"Invalid hex string: $hexString") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
  47. // ペイロード長とシーケンスIDのコーデック定義 val payloadLengthCodec: Codec[Int] = ("payloadLength" | uint24L) val

    sequenceIdCodec: Codec[Int] = ("sequenceId" | uint8L) 1 object MySQLPacketDecoder: 2 3 4 5 // MySQLPacket用にコーデックを1つにまとめる 6 val mySQLPacketCodec: Codec[MySQLPacket] = ( 7 payloadLengthCodec :: sequenceIdCodec 8 ).as[MySQLPacket] 9 def main(args: Array[String]): Unit = 10 // 16進文字列をバイト列に変換 11 val hexString = "4a000000" 12 val bytesOpt = ByteVector.fromHex(hexString) 13 // ByteVectorが正常に作成されたことを確認する。 14 bytesOpt match 15 case Some(bytes) => 16 // パケットをデコードする 17 mySQLPacketCodec.decode(bytes.bits) match 18 case Successful(DecodeResult(packet, _)) => 19 println(s"Payload Length: ${packet.payloadLength}") 20 println(s"Sequence ID: ${packet.sequenceId}") 21 case Failure(err) => 22 println(s"Failed to decode: $err") 23 case None => 24 println(s"Invalid hex string: $hexString")
  48. // MySQLPacket用にコーデックを1つにまとめる val mySQLPacketCodec: Codec[MySQLPacket] = ( payloadLengthCodec :: sequenceIdCodec

    ).as[MySQLPacket] 1 object MySQLPacketDecoder: 2 // ペイロード長とシーケンスIDのコーデック定義 3 val payloadLengthCodec: Codec[Int] = ("payloadLength" | uint24L) 4 val sequenceIdCodec: Codec[Int] = ("sequenceId" | uint8L) 5 6 7 8 9 def main(args: Array[String]): Unit = 10 // 16進文字列をバイト列に変換 11 val hexString = "4a000000" 12 val bytesOpt = ByteVector.fromHex(hexString) 13 // ByteVectorが正常に作成されたことを確認する。 14 bytesOpt match 15 case Some(bytes) => 16 // パケットをデコードする 17 mySQLPacketCodec.decode(bytes.bits) match 18 case Successful(DecodeResult(packet, _)) => 19 println(s"Payload Length: ${packet.payloadLength}") 20 println(s"Sequence ID: ${packet.sequenceId}") 21 case Failure(err) => 22 println(s"Failed to decode: $err") 23 case None => 24 println(s"Invalid hex string: $hexString")
  49. // 16進文字列をバイト列に変換 val hexString = "4a000000" val bytesOpt = ByteVector.fromHex(hexString)

    1 object MySQLPacketDecoder: 2 // ペイロード長とシーケンスIDのコーデック定義 3 val payloadLengthCodec: Codec[Int] = ("payloadLength" | uint24L) 4 val sequenceIdCodec: Codec[Int] = ("sequenceId" | uint8L) 5 // MySQLPacket用にコーデックを1つにまとめる 6 val mySQLPacketCodec: Codec[MySQLPacket] = ( 7 payloadLengthCodec :: sequenceIdCodec 8 ).as[MySQLPacket] 9 def main(args: Array[String]): Unit = 10 11 12 13 // ByteVectorが正常に作成されたことを確認する。 14 bytesOpt match 15 case Some(bytes) => 16 // パケットをデコードする 17 mySQLPacketCodec.decode(bytes.bits) match 18 case Successful(DecodeResult(packet, _)) => 19 println(s"Payload Length: ${packet.payloadLength}") 20 println(s"Sequence ID: ${packet.sequenceId}") 21 case Failure(err) => 22 println(s"Failed to decode: $err") 23 case None => 24 println(s"Invalid hex string: $hexString")
  50. // パケットをデコードする mySQLPacketCodec.decode(bytes.bits) match case Successful(DecodeResult(packet, _)) => println(s"Payload Length:

    ${packet.payloadLength}") println(s"Sequence ID: ${packet.sequenceId}") case Failure(err) => println(s"Failed to decode: $err") 1 object MySQLPacketDecoder: 2 // ペイロード長とシーケンスIDのコーデック定義 3 val payloadLengthCodec: Codec[Int] = ("payloadLength" | uint24L) 4 val sequenceIdCodec: Codec[Int] = ("sequenceId" | uint8L) 5 // MySQLPacket用にコーデックを1つにまとめる 6 val mySQLPacketCodec: Codec[MySQLPacket] = ( 7 payloadLengthCodec :: sequenceIdCodec 8 ).as[MySQLPacket] 9 def main(args: Array[String]): Unit = 10 // 16進文字列をバイト列に変換 11 val hexString = "4a000000" 12 val bytesOpt = ByteVector.fromHex(hexString) 13 // ByteVectorが正常に作成されたことを確認する。 14 bytesOpt match 15 case Some(bytes) => 16 17 18 19 20 21 22 23 case None => 24 println(s"Invalid hex string: $hexString")
  51. object MySQLPacketDecoder: // ペイロード長とシーケンスIDのコーデック定義 val payloadLengthCodec: Codec[Int] = ("payloadLength" |

    uint24L) val sequenceIdCodec: Codec[Int] = ("sequenceId" | uint8L) // MySQLPacket用にコーデックを1つにまとめる val mySQLPacketCodec: Codec[MySQLPacket] = ( payloadLengthCodec :: sequenceIdCodec ).as[MySQLPacket] def main(args: Array[String]): Unit = // 16進文字列をバイト列に変換 val hexString = "4a000000" val bytesOpt = ByteVector.fromHex(hexString) // ByteVectorが正常に作成されたことを確認する。 bytesOpt match case Some(bytes) => // パケットをデコードする mySQLPacketCodec.decode(bytes.bits) match case Successful(DecodeResult(packet, _)) => println(s"Payload Length: ${packet.payloadLength}") println(s"Sequence ID: ${packet.sequenceId}") case Failure(err) => println(s"Failed to decode: $err") case None => println(s"Invalid hex string: $hexString") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
  52. まずは ScalaはJDBCを使ってMySQLサーバーと通信するので、mysql-connector-javaを使って通信しているデータを見 てみる。 まずはここから! ※ Scala CLIを使用 1 //> using

    scala "3.3.3" 2 //> using dep mysql:mysql-connector-java:8.0.33 3 4 val dataSource = new MysqlDataSource() 5 dataSource.setServerName("127.0.0.1") 6 dataSource.setPortNumber(3306) 7 dataSource.setUser("username") 8 dataSource.setPassword("password") 9 dataSource.setUseSSL(false) // v8 (caching_sha2_password) 使用の場合 10 dataSource.setAllowPublicKeyRetrieval(true) // v8 (caching_sha2_password) 使用の場合 11 12 // 接続 13 val connection = dataSource.getConnection 1 scala-cli mysql-connector.sc
  53. 先ほどと同じようにngrepでパケットを監視してみると… 先ほどと同じ形式でデータが送られてきていることがわかる 1 T 127.0.0.1:13306 -> 127.0.0.1:59433 [AP] #5 2

    4a 00 00 00 0a 38 2e 30 2e 33 33 00 79 0a 00 00 J....8.0.33.y... 3 4b 3d 5f 7f 66 71 40 68 00 ff ff ff 02 00 ff df K=_.fq@h.���..�� 4 15 00 00 00 00 00 00 00 00 00 00 54 45 45 19 59 ...........TEE.Y 5 63 0f 63 18 27 76 07 00 63 61 63 68 69 6e 67 5f c.c.'v..caching_ 6 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 sha2_password.
  54. 送られたデータに対して、MySQLドライバーはこのようなデータを送信していることがわかる つまり… 1 T 127.0.0.1:59433 -> 127.0.0.1:13306 [AP] #7 2

    e0 00 00 01 07 a2 3e 19 ff ff ff 00 ff 00 00 00 �....�>.���.�... 3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4 00 00 00 00 6c 64 62 63 00 20 1c ea ae b9 6a bd ....ldbc. .ꮹj� 5 3c cd 06 dc 21 7a 98 53 6c 6b 6e 82 49 bc d7 44 <�.�!z.Slkn.I��D 6 d1 2d 42 7c f7 28 f5 f5 61 5a 63 61 63 68 69 6e �-B|�(��aZcachin 7 67 5f 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 g_sha2_password. 8 83 10 5f 72 75 6e 74 69 6d 65 5f 76 65 72 73 69 .._runtime_versi 9 6f 6e 07 31 31 2e 30 2e 31 37 0f 5f 63 6c 69 65 on.11.0.17._clie 10 6e 74 5f 76 65 72 73 69 6f 6e 06 38 2e 30 2e 33 nt_version.8.0.3 11 33 0f 5f 63 6c 69 65 6e 74 5f 6c 69 63 65 6e 73 3._client_licens 12 65 03 47 50 4c 0f 5f 72 75 6e 74 69 6d 65 5f 76 e.GPL._runtime_v 13 65 6e 64 6f 72 0f 41 6d 61 7a 6f 6e 2e 63 6f 6d endor.Amazon.com 14 20 49 6e 63 2e 0c 5f 63 6c 69 65 6e 74 5f 6e 61 Inc.._client_na 15 6d 65 11 4d 79 53 51 4c 20 43 6f 6e 6e 65 63 74 me.MySQL Connect 16 6f 72 2f 4a or/J
  55. 送られたデータに対して、MySQLドライバーはこのようなデータを送信していることがわかる つまり… これが答え! 1 T 127.0.0.1:59433 -> 127.0.0.1:13306 [AP] #7

    2 e0 00 00 01 07 a2 3e 19 ff ff ff 00 ff 00 00 00 �....�>.���.�... 3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4 00 00 00 00 6c 64 62 63 00 20 1c ea ae b9 6a bd ....ldbc. .ꮹj� 5 3c cd 06 dc 21 7a 98 53 6c 6b 6e 82 49 bc d7 44 <�.�!z.Slkn.I��D 6 d1 2d 42 7c f7 28 f5 f5 61 5a 63 61 63 68 69 6e �-B|�(��aZcachin 7 67 5f 73 68 61 32 5f 70 61 73 73 77 6f 72 64 00 g_sha2_password. 8 83 10 5f 72 75 6e 74 69 6d 65 5f 76 65 72 73 69 .._runtime_versi 9 6f 6e 07 31 31 2e 30 2e 31 37 0f 5f 63 6c 69 65 on.11.0.17._clie 10 6e 74 5f 76 65 72 73 69 6f 6e 06 38 2e 30 2e 33 nt_version.8.0.3 11 33 0f 5f 63 6c 69 65 6e 74 5f 6c 69 63 65 6e 73 3._client_licens 12 65 03 47 50 4c 0f 5f 72 75 6e 74 69 6d 65 5f 76 e.GPL._runtime_v 13 65 6e 64 6f 72 0f 41 6d 61 7a 6f 6e 2e 63 6f 6d endor.Amazon.com 14 20 49 6e 63 2e 0c 5f 63 6c 69 65 6e 74 5f 6e 61 Inc.._client_na 15 6d 65 11 4d 79 53 51 4c 20 43 6f 6e 6e 65 63 74 me.MySQL Connect 16 6f 72 2f 4a or/J
  56. MySQLドライバーの返答に対して、MySQLサーバーはこのようなデータを返している つまり… 1 T 127.0.0.1:13306 -> 127.0.0.1:59433 [AP] #9 2

    02 00 00 02 01 03 ...... 3 4 T 127.0.0.1:13306 -> 127.0.0.1:59433 [AP] #11 5 07 00 00 03 00 00 00 02 00 00 00 ........... 6 7 ...
  57. まとめ データベースクライアントを作る時は… 1. データベースとの通信を見ましょう 2. AIを使ってコードを生成しましょう 3. 既存ライブラリの通信をカンニングしましょう 4. 1

    ~ 3を繰り返しましょう どんなことでもコツコツ積み上げて行けば大きなものができていく! 興味が湧いた人は挑戦してみてね!