TCP Proxyを書いてPostgreSQLの通信を覗いてみる

覗いてみました。

ただ見るだけなら tcpdump などを活用すれば良さそうなのですが、せっかくならプロトコルを解析した結果を出力してみたかったので、取得結果をイジれるようにTCP Proxyを書くところからはじめてみました。

TCP Proxyってどうやって書けば?というのは基本的にインターネットの情報を参考にしました。特に以下のツールのコードを参考にしました。

github.com

で、書いたのが tcprxy です。

github.com

$ tcprxy -l localhost:12345 -r localhost:1234

という、よくありそうな感じでTCP Proxyなプロセスを起動するだけのツールです。

準備

まず、localhost:5432PostgreSQLを起動しておきます。 tcprxyPostgreSQLをリモートアドレス -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章 フロントエンド/バックエンドプロトコル

とりあえず今回は、簡易クエリ ( 52.2.2. ) だけを解析して出力できるようにしてみました。

52.7. メッセージの書式

クエリは先頭バイトが '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を書いたので他の通信も覗いてみようと思います。