LISTENできるポートをサーバ側で完全に制限できるsshリバースフォワーディングをnetcatで実現する(できませんでした!!!)


グローバルIPアドレスを持っていないRaspberryPiに外部からsshしたいときなどに大活躍のssh -Rですが、サーバ側の一存でLISTENするポートを鍵ごとに制限する方法がopensshの本家には存在せず、SSH Reverse Port Forwarding で鍵ごとにlistenできるポートを制限するで紹介したパッチをあてて、permitremoteopenを使うと鍵ごとにbindできるポートを制限することは可能なのですが、これの話をしているのは世界中で作者と自分くらいなのでは?本家にマージされる可能性は限りなくゼロに近いので、他の方法を考えてみようと思います。

最初に思いついたのは1クライアントごとにコンテナでsshdを起動することなのですが、sshd + 1セッションで12MBくらいメモリを消費していたのでやめました。

次に、nc(netcat)をssh -Rのかわりにする方法を考えてみました。

サーバ上でncを実行し2222番でLISTENして、sshの標準入出力を通信路に使って、クライアント側で起動したncでクライアント側で起動しているsshd(22番)にアクセスします。
パイプだけだとデータの流れが一方通行なので、fifoを使ってクライアント側のncの標準出力をsshクライアントの標準入力に渡してやります。

クライアント側のコマンド
client$ cat fifo | (ssh user@ssh-server nc -l 2222) | nc localhost 22 > fifo

まるで自らの尾を喰らい続けるウロボロスのようですね。

念の為, ncがちゃんとLISTENしているかどうか確認してみます。

サーバ側でncがLISTENしているかどうか確かめる
server$ sudo sockstat |grep 2222
user nc        32658 3  tcp4   *:2222                *:*

クライアントへのsshは, 普通にssh -Rしたときと一緒です。

サーバ側からクライアント側にsshする
server$ ssh user@localhost -p 2222

ここまでうまくいっていれば、あとは.ssh/authorized_keyscommand=nc -l 2222を設定しておけば、リバースフォワーディングのクライアントがどのポートでLISTENするのかをサーバ側の一存で決められるようになります。(なるはず。まだ試してない)

で、重要なことに気づいたんですが、ncを使っていると1セッションしかsshできない・・・
これではちょっと使い物にならない(シェルログインしながらscpとかしたいやん!)ので、別の方法を考えることにします・・・