TCP Proxyを書いてPostgreSQLの通信を覗いてみる
なんとなく興味がでてきたのでインターネット情報を参考にTCP Proxyを書いてPostgreSQLの通信覗いてみた。クエリの取得まではできた。
— k1LoW (@k1LoW) 2018年7月15日
HTTP/1.1の世界で生きていたので、プログラムでバイナリ?を触ったの久しぶり過ぎるし(TokyoTyrantのPHPクライアント書いたときぶり?)やっぱり全然慣れない
覗いてみました。
ただ見るだけなら tcpdump
などを活用すれば良さそうなのですが、せっかくならプロトコルを解析した結果を出力してみたかったので、取得結果をイジれるようにTCP Proxyを書くところからはじめてみました。
TCP Proxyってどうやって書けば?というのは基本的にインターネットの情報を参考にしました。特に以下のツールのコードを参考にしました。
で、書いたのが tcprxy
です。
$ tcprxy -l localhost:12345 -r localhost:1234
という、よくありそうな感じでTCP Proxyなプロセスを起動するだけのツールです。
準備
まず、localhost:5432
でPostgreSQLを起動しておきます。 tcprxy
をPostgreSQLをリモートアドレス -r
に指定して起動します。
$ tcprxy -l localhost:55432 -r localhost:5432
tcprxy
はデフォルトで双方向の通信を hex.Dump() を使って標準出力に出力します。
あとは psql
コマンドなどを使って localhost:55432
に接続して通信結果を覗いてみます。
PostgreSQLの通信を覗いてみる
まずはPostgreSQLへの接続まで
$ psql -U postgres -h localhost -p 55432 -d testdb Password for user postgres: psql (10.2, server 10.4 (Debian 10.4-1.pgdg90+1)) Type "help" for help. testdb=#
ダンプ結果が以下
00000000 00 00 00 08 04 d2 16 2f |......./| 00000000 4e |N| 00000000 00 00 00 52 00 03 00 00 75 73 65 72 00 70 6f 73 |...R....user.pos| 00000010 74 67 72 65 73 00 64 61 74 61 62 61 73 65 00 74 |tgres.database.t| 00000020 65 73 74 64 62 00 61 70 70 6c 69 63 61 74 69 6f |estdb.applicatio| 00000030 6e 5f 6e 61 6d 65 00 70 73 71 6c 00 63 6c 69 65 |n_name.psql.clie| 00000040 6e 74 5f 65 6e 63 6f 64 69 6e 67 00 55 54 46 38 |nt_encoding.UTF8| 00000050 00 00 |..| 00000000 52 00 00 00 0c 00 00 00 05 75 d4 cb 36 |R........u..6| 00000000 00 00 00 08 04 d2 16 2f |......./| 00000000 4e |N| 00000000 00 00 00 52 00 03 00 00 75 73 65 72 00 70 6f 73 |...R....user.pos| 00000010 74 67 72 65 73 00 64 61 74 61 62 61 73 65 00 74 |tgres.database.t| 00000020 65 73 74 64 62 00 61 70 70 6c 69 63 61 74 69 6f |estdb.applicatio| 00000030 6e 5f 6e 61 6d 65 00 70 73 71 6c 00 63 6c 69 65 |n_name.psql.clie| 00000040 6e 74 5f 65 6e 63 6f 64 69 6e 67 00 55 54 46 38 |nt_encoding.UTF8| 00000050 00 00 |..| 00000000 52 00 00 00 0c 00 00 00 05 d2 92 d0 67 |R...........g| 00000000 70 00 00 00 28 6d 64 35 63 66 35 39 35 66 36 63 |p...(md5cf595f6c| 00000010 34 39 34 66 64 35 66 32 66 34 37 62 62 31 31 32 |494fd5f2f47bb112| 00000020 35 30 62 35 65 65 31 31 00 |50b5ee11.| 00000000 52 00 00 00 08 00 00 00 00 53 00 00 00 1a 61 70 |R........S....ap| 00000010 70 6c 69 63 61 74 69 6f 6e 5f 6e 61 6d 65 00 70 |plication_name.p| 00000020 73 71 6c 00 53 00 00 00 19 63 6c 69 65 6e 74 5f |sql.S....client_| 00000030 65 6e 63 6f 64 69 6e 67 00 55 54 46 38 00 53 00 |encoding.UTF8.S.| 00000040 00 00 17 44 61 74 65 53 74 79 6c 65 00 49 53 4f |...DateStyle.ISO| 00000050 2c 20 4d 44 59 00 53 00 00 00 19 69 6e 74 65 67 |, MDY.S....integ| 00000060 65 72 5f 64 61 74 65 74 69 6d 65 73 00 6f 6e 00 |er_datetimes.on.| 00000070 53 00 00 00 1b 49 6e 74 65 72 76 61 6c 53 74 79 |S....IntervalSty| 00000080 6c 65 00 70 6f 73 74 67 72 65 73 00 53 00 00 00 |le.postgres.S...| 00000090 14 69 73 5f 73 75 70 65 72 75 73 65 72 00 6f 6e |.is_superuser.on| 000000a0 00 53 00 00 00 19 73 65 72 76 65 72 5f 65 6e 63 |.S....server_enc| 000000b0 6f 64 69 6e 67 00 55 54 46 38 00 53 00 00 00 31 |oding.UTF8.S...1| 000000c0 73 65 72 76 65 72 5f 76 65 72 73 69 6f 6e 00 31 |server_version.1| 000000d0 30 2e 34 20 28 44 65 62 69 61 6e 20 31 30 2e 34 |0.4 (Debian 10.4| 000000e0 2d 31 2e 70 67 64 67 39 30 2b 31 29 00 53 00 00 |-1.pgdg90+1).S..| 000000f0 00 23 73 65 73 73 69 6f 6e 5f 61 75 74 68 6f 72 |.#session_author| 00000100 69 7a 61 74 69 6f 6e 00 70 6f 73 74 67 72 65 73 |ization.postgres| 00000110 00 53 00 00 00 23 73 74 61 6e 64 61 72 64 5f 63 |.S...#standard_c| 00000120 6f 6e 66 6f 72 6d 69 6e 67 5f 73 74 72 69 6e 67 |onforming_string| 00000130 73 00 6f 6e 00 53 00 00 00 11 54 69 6d 65 5a 6f |s.on.S....TimeZo| 00000140 6e 65 00 55 54 43 00 4b 00 00 00 0c 00 00 0d a7 |ne.UTC.K........| 00000150 05 14 5d 33 5a 00 00 00 05 49 |..]3Z....I|
全くわからない。
簡単なクエリを実行してみます。
testdb=# SELECT COUNT(*) FROM information_schema.tables; count ------- 196 (1 row)
00000000 51 00 00 00 34 53 45 4c 45 43 54 20 43 4f 55 4e |Q...4SELECT COUN| 00000010 54 28 2a 29 20 46 52 4f 4d 20 69 6e 66 6f 72 6d |T(*) FROM inform| 00000020 61 74 69 6f 6e 5f 73 63 68 65 6d 61 2e 74 61 62 |ation_schema.tab| 00000030 6c 65 73 3b 00 |les;.| 00000000 54 00 00 00 1e 00 01 63 6f 75 6e 74 00 00 00 00 |T......count....| 00000010 00 00 00 00 00 00 14 00 08 ff ff ff ff 00 00 44 |...............D| 00000020 00 00 00 0d 00 01 00 00 00 03 31 39 36 43 00 00 |..........196C..| 00000030 00 0d 53 45 4c 45 43 54 20 31 00 5a 00 00 00 05 |..SELECT 1.Z....| 00000040 49 |I|
クエリが見えます。これなら解析結果を出力できそうです。
PostgreSQLのプロトコルを解析してみる
PostgreSQLは通信プロトコルも含め、しっかりとドキュメント化されています(日本語化も)。
とりあえず今回は、簡易クエリ ( 52.2.2. ) だけを解析して出力できるようにしてみました。
クエリは先頭バイトが 'Q' になるのでそのメッセージだけ取得して、クエリ文字列の部分だけ取得してみます。
実際の解析結果は tcprxy に -d pg
オプションを渡して確認できます
$ tcprxy -l localhost:55432 -r localhost:5432 -d pg
先ほどと同じようにクエリを実行してみます。
testdb=# SELECT COUNT(*) FROM information_schema.tables; count ------- 196 (1 row) testdb=# SELECT COUNT(*) FROM information_schema.columns; count ------- 1775 (1 row)
$ tcprxy -l localhost:55432 -r localhost:5432 -d pg SELECT COUNT(*) FROM information_schema.tables; SELECT COUNT(*) FROM information_schema.columns;
クエリを取得できました。
まとめ
簡単ですが普段使っているPostgreSQLの通信を覗くことができました。
せっかくTCP Proxyを書いたので他の通信も覗いてみようと思います。