SEEDS Creator's Blog

読者です 読者をやめる 読者になる 読者になる

stoneを使ってIRCのSSL暗号化を行う

IRC インフラ

stone は、アプリケーションレベルの TCP & UDP リピーターです。 stone - http://www.gcd.org/sengoku/stone/Welcome.ja.html

IRCサーバーはSSL暗号化に対応しているものが少なく、データがすべて平文でやりとりされてしまう。 stoneは任意のポートからポートへトンネルをつくる事が出来るアプリケーションなんですが、 stoneがSSLに対応している為、こちらを使ってIRCSSL対応を行います。

これはポートを待ち受けるアプリケーションであればどのアプリケーションでも暗号化可能かと思います。

イメージしにくいかもしれないので以下がイメージ図。

IRCサーバーは6667で待ち受けているアプリケーション。 stoneを使う事で6668ポートと6667ポートを中継し、クライアントは6668ポートに繋ぐ事でIRCへ接続できる。 またstoneはSSLに対応している為、6668ポートはSSL暗号化を利用する事ができる。

stoneのインストール

すこしハマったので詳細を記述します。

[code] cd /usr/local/src wget http://www.gcd.org/sengoku/stone/stone-2.3e.tar.gz tar zxvf stone-2.3e.tar.gz make linux-ssl [/code]

こんなエラーが出てしまった

[code] # make linux-ssl make TARGET=linux ssl_stone LIBS="-ldl" make[1]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7' make FLAGS="-DUSE_POP -DUSE_SSL " LIBS="-ldl -lssl -lcrypto" linux make[2]: Entering directory/usr/local/src/stone-2.3d-2.3.2.7' make FLAGS="-O -Wall -DCPP='\"/usr/bin/cpp -traditional\"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -DUSE_POP -DUSE_SSL " LIBS="-lpthread -ldl -lssl -lcrypto" stone make[3]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7' cc -O -Wall -DCPP='"/usr/bin/cpp -traditional"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -DUSE_POP -DUSE_SSL -o stone stone.c -lpthread -ldl -lssl -lcrypto stone.c: In function ‘saDup’: stone.c:1558: warning: cast from pointer to integer of different size stone.c: In function ‘sendPairUDPbuf’: stone.c:3023: warning: cast from pointer to integer of different size stone.c: In function ‘freePair’: stone.c:3644: warning: cast from pointer to integer of different size stone.c: In function ‘doconnect’: stone.c:3883: warning: cast from pointer to integer of different size stone.c: In function ‘acceptPair’: stone.c:4072: warning: cast from pointer to integer of different size stone.c: In function ‘strnUser’: stone.c:4509: error: dereferencing pointer to incomplete type stone.c:4524: error: dereferencing pointer to incomplete type stone.c:4536: error: dereferencing pointer to incomplete type stone.c:4551: error: dereferencing pointer to incomplete type stone.c:4557: error: dereferencing pointer to incomplete type stone.c: In function ‘proto2fdset’: stone.c:6239: warning: cast from pointer to integer of different size stone.c:6300: warning: cast from pointer to integer of different size stone.c: In function ‘dispatch’: stone.c:6916: warning: cast from pointer to integer of different size stone.c: In function ‘newMatch’: stone.c:7070: warning: cast from pointer to integer of different size stone.c: In function ‘freeMatch’: stone.c:7084: warning: cast from pointer to integer of different size stone.c: In function ‘initialize’: stone.c:10178: warning: cast from pointer to integer of different size make[3]: *** [stone] Error 1 make[3]: Leaving directory/usr/local/src/stone-2.3d-2.3.2.7' make[2]: [linux] Error 2 make[2]: Leaving directory /usr/local/src/stone-2.3d-2.3.2.7' make[1]: *** [ssl_stone] Error 2 make[1]: Leaving directory/usr/local/src/stone-2.3d-2.3.2.7' make: [linux-ssl] Error 2 [/code]

Debian Squeezeで発生。Lennyでは出ませんでした。 どうやらglibc 2.8 以降では、この構造体の定義を得るためには機能検査マクロ _GNU_SOURCE を定義しなければならないようです。 解決方法としては、Makefileの以下の記述部分に、-D_GNU_SOURCEを追加することで正常にコンパイルできるようになりました。 (参考) http://typex2.wordpress.com/2009/10/25/stone%E3%82%92linux%E3%81%A7%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%99%E3%82%8B/

[code] linux: $(MAKE) FLAGS="-O -Wall -DCPP='\"/usr/bin/cpp -traditional\"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL $(FLAGS)" LIBS="-lpthread $(LIBS)" stone

linux: $(MAKE) FLAGS="-O -Wall -DCPP='\"/usr/bin/cpp -traditional\"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -D_GNU_SOURCE $(FLAGS)" LIBS="-lpthread $(LIBS)" stone [/code]

再度実行。

[code] # make linux-ssl make TARGET=linux ssl_stone LIBS="-ldl" make[1]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7' make FLAGS="-DUSE_POP -DUSE_SSL " LIBS="-ldl -lssl -lcrypto" linux make[2]: Entering directory/usr/local/src/stone-2.3d-2.3.2.7' make FLAGS="-O -Wall -DCPP='\"/usr/bin/cpp -traditional\"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -D_GNU_SOURCE -DUSE_POP -DUSE_SSL " LIBS="-lpthread -ldl -lssl -lcrypto" stone make[3]: Entering directory /usr/local/src/stone-2.3d-2.3.2.7' cc -O -Wall -DCPP='"/usr/bin/cpp -traditional"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL -D_GNU_SOURCE -DUSE_POP -DUSE_SSL -o stone stone.c -lpthread -ldl -lssl -lcrypto stone.c: In function ‘saDup’: stone.c:1558: warning: cast from pointer to integer of different size stone.c: In function ‘sendPairUDPbuf’: stone.c:3023: warning: cast from pointer to integer of different size stone.c: In function ‘freePair’: stone.c:3644: warning: cast from pointer to integer of different size stone.c: In function ‘doconnect’: stone.c:3883: warning: cast from pointer to integer of different size stone.c: In function ‘acceptPair’: stone.c:4072: warning: cast from pointer to integer of different size stone.c: In function ‘proto2fdset’: stone.c:6239: warning: cast from pointer to integer of different size stone.c:6300: warning: cast from pointer to integer of different size stone.c: In function ‘dispatch’: stone.c:6916: warning: cast from pointer to integer of different size stone.c: In function ‘newMatch’: stone.c:7070: warning: cast from pointer to integer of different size stone.c: In function ‘freeMatch’: stone.c:7084: warning: cast from pointer to integer of different size stone.c: In function ‘initialize’: stone.c:10178: warning: cast from pointer to integer of different size make[3]: Leaving directory/usr/local/src/stone-2.3d-2.3.2.7' make[2]: Leaving directory /usr/local/src/stone-2.3d-2.3.2.7' make[1]: Leaving directory/usr/local/src/stone-2.3d-2.3.2.7' [/code]

なんか警告は出てますが無事コンパイル完了しました。

パスが通る位置にコンパイル済のstoneを移動 [code] cp -rfpa stone /usr/local/bin/ [/code]

動作テスト

動いてるポートへ別ポートから接続できるかテスト。(6668から6667へ接続例) [code] stone localhost:6667 6668 Mar 27 12:00:18.903642 139940579038976 start (2.3e) [21488] Mar 27 12:00:18.904514 139940579038976 stone 3: 127.0.0.1:ircd <- 0.0.0.0:6668 stone localhost:6667 6668 [/code]

これでircサーバーに6667でも6668でも接続が可能になる。 次は暗号化して待ち受けテスト

[code] stone localhost:6667 6668/ssl Mar 27 12:19:26.297086 140086834108160 start (2.3e) [23145] Mar 27 12:19:26.297835 140086834108160 SSL_CTX_use_PrivateKey_file(/usr/lib/ssl/certs/stone.pem) error:02001002:system library:fopen:No such file or directory [/code]

証明書がないというエラーが出て立ち上がらない。 どうやらデフォルトで/usr/lib/ssl/certs/stone.pemにある証明書&keyを利用するようなのでここに証明書を作成する。(要openssl)

[code] openssl req -new -outform pem -out stone.cert -newkey rsa:2048 -keyout stone.key -nodes -rand ./rand.pat -x509 -batch -days 3560 cat stone.cert stone.key > stone.pem cp stone.pem /usr/lib/ssl/certs/ [/code]

2048bitで3560(10年)使用できる鍵を作成。 普段使用している証明書と鍵でも 証明書ファイル 鍵ファイル の順番のファイルを作ればOKです。 改めてSSL接続テスト。

[code] stone localhost:6667 6668/ssl Mar 27 12:34:04.695961 140533134583552 start (2.3e) [24813] Mar 27 12:34:04.697198 140533134583552 stone 3: 127.0.0.1:ircd <- 0.0.0.0:6668/ssl [/code]

6668ポートにSSL接続できる事が確認できます。 これでSSLでの待ち受けもOKです。

起動

こんな感じで起動 [code] stone localhost:6667 6668/ssl >& /dev/null & [/code] Linuxファイアウォール設定でircの6667ポートを閉じて6668をOPENにする。 あとはIRCクライアント側(LimeChatとか)の設定で 6668ポートにSSLで接続できるようになります。

備考

今のところ僕の環境では問題ないですが、クリティカルな環境ではstoneが落ちたりするのを防ぐ為に プロセス監視を行うかdaemontoolsで監視するなどの設定が必要だと思います。