ポートフォワーディング
ssh hostname] -l [usrname] -N -f [-L
オプション
- -N
- ログイン時にシェルを立ち上げない
- -f
- sshをバックグラウンドで実行する
- -L
- ローカルからリモートにフォワーディングする
- -R
- リモートからローカルにフォワーディングする
- -l
- ユーザIDを指定する
例
ローカルの8080番をホスト名server.sample.jpのHTTP(80番)にフォワードする.
接続の確立.
$ ssh -f -N -L 8080:localhost:80 server.sample.jp -l username
上記コマンドのlocalhostは,server.sample.jpが解釈するホスト名であることに注意する.つまり,server.sample.jpから見たlocalhostなので,localhost = server.sample.jpとなる.従って,上記コマンドは,以下のコマンドと同等である.
$ ssh -f -N -L 8080:server.sample.jp:80 server.sample.jp -l username
フォワーディングされていることを確認.
$ firefox localhost:8080
ローカルの2222番をゲートウェイgw.sample.jp経由でserver.sample.jpに接続する.
$ ssh -f -N -L 2222:server:22 gw.sample.jp -l username
$ ssh -p 2222 localhost
良くわかる解説
sshの特徴の一つとして,ポートフォワーディングがある.たとえば,次のようにsshを実行する.
% ssh -L X:Remote:Y Remote -l username
このあと,別のウィンドウからローカルマシン(Local)のX番ポートに接続すると,sshによって,その通信はすべてRemoteのY番ポートへ転送される.これをポートフォワーディングという.
sshでポートフォワーディングができる一番の意義は,ローカルとリモートマシン間の通信がsshが提供するレベルのセキュアなものになるということである.従って,この機能を使ってSMTP(25番)やPOP(110番)と通信すれば,メールの内容を盗み見られるといった心配がなくなる.
ただし,FTPに関しては注意が必要である.別紙参照
以下,sshポートフォワーディングに関するいくつかの接続例である.各入力例のうち,ユーザ名が同じ場合は -l username は要らない.また,フォワード元のポート番号(矢印が出ているところ)には,root以外のユーザは1024番以下の特権ポートを指定できない.
なお,以下の接続例のうち私が実際に試したのは例1と例2くらいである.その他のうち,例2ダッシュと例4と例5は,ネットで調べて見掛けたものである.それ以外の例には根本的な間違いがあるかも知れない.
例その1
上で解説されている状態を絵で書くと、下図のようになる.
% ssh -L X:Remote:Y Remote -l username
図中,Sはsshdと接続するためにsshクライアントが適当に使っている番号.==== の部分は暗号化されているので,盗聴されても大丈夫.矢印の向きは,ポートにconnectするか,bindしてlistenするかの違い.
+--Local--+ +--Remote---+
| | | |
| +--> S ======> 22 --+ |
| | | | | |
| +--- X Y <--+ |
| | | |
+---------+ +-----------+
例その2
ポートフォワードのターゲットポートはRemote以外のマシンのものでもよい.
たとえば,
% ssh -L X:Remote_2:Y Remote -l username
とする.
すると,Remote(ここではsshdが動いている)を経由して,Remote_2への通信が可能になる.
図中,SとTは適当にあてがわれる番号である.この方式の場合、暗号化されるのは ==== の部分のみで,Remote:T ---> Y:Remote_2間の通信は暗号化されない.RemoteとRemote_2がファイアーウォールの中にあるなど,通信を盗聴されない環境であることが必要になる.
+--Local--+ +--Remote---+ +-Remote_2-+
| | | | | |
| +--> S ======> 22 -------> T --------> Y |
| | | | | | |
| +--- X | | | |
| | | | | |
+---------+ +-----------+ +----------+
例その2ダッシュ
フォワードするポート番号(Y)に22を指定すると,Remoteを介して,Remote_2への直接のsshログインが可能になる.
たとえば,
% ssh -L X:Remote_2:22 Remote -l username
として,ssh通信を一つ確立した後で,
% ssh -p X localhost -l username
とする.
この場合は,Remote:T ---> Y:Remote_2 間の通信も暗号化される.というか,XからYまでの通信はsshプロトコルによってすべて暗号化される.図中,Local:SとRemote:22間は2重に暗号化されていることになる.
+--Local--+ +--Remote---+ +-Remote_2-+
| |---------| | | |
| +==> S ======> 22 =======> T ========> 22 |
| U |---------| | | |
| U | | | | |
| +=== X | | | |
| | | | | |
+---------+ +-----------+ +----------+
例その3
例2で,さらにRemoteとRemote_2間の通信も暗号化するためには,remote_2上でもsshdを動かし,2段階のポートフォワードをおこなう.
たとえば,
% ssh -L X:Remote:Z Remote -l username
でログインした後,
% ssh -L Z:Remote_2:Y Remote_2 -l username
でさらにログインをする.
すると,以下のように,Z番ポートを経由した通信経路が出来上がる.Zの辺りが絵的に少し苦しいけど、それでも通信は暗号化される.
+--Local--+ +--Remote---+ +-Remote_2-+
| | | | | |
| +--> S ======> 22 -+ +-> T ========> 22 --+ |
| | | | | | | | | |
| +--- X | | | | Y <--+ |
| | | +->-+ | | |
+---------+ +-----Z-----+ +----------+
あるいは,例2ダッシュの方法を応用してもよい.
たとえば,
% ssh -L Z:Remote_2:22 Remote -l username
としてssh通信を一つ確立した後で,
% ssh -p Z -L X:Remote_2:Y localhost -l username
とする.
+--Local--+ +--Remote--+ +-Remote_2-+
| |---------| | | |
Z ======> S ======> 22 ======> T ========> 22 --+ |
|<---+ |---------| | | | |
| | | | | | | |
| +--- X | | Y <--+ |
| | | | | |
+---------+ +----------+ +----------+
例その4
逆に,Remoteのポートをフォワードすることも可能である.これには,-Lオプションの代わりに-Rオプションを用いる.
たとえば,
% ssh -R X:Local:Y Remote -l username
としてログインする.
すると,RemoteのX番ポートがLocalマシンのY番へフォワードされる.
+--Local--+ +--Remote--+
| | | |
| +--- S ======> 22 <-+ |
| | | | | |
| +--> Y X ---+ |
| | | |
+---------+ +----------+
例その5
例4において,-Lオプションの時と同様,フォワードする相手先は,必ずしもLocalマシンのポートでなくてもよい.
たとえば,
% ssh -R X:Remote_2:Y Remote -l username
とすると,次のようになる.
この場合,LocalとRemote_2間の通信は暗号化されない.
+--Local--+ +--Remote--+ +-Remote_2-+
| | | | | |
| +--- S ======> 22 <-+ | | |
| | | | | | | |
| +--> T --+ X ---+ | +--> Y |
| | | | | | | |
+---------+ | +----------+ | +----------+
| |
+-----------------------+
例その6
例5において,さらにLocalとRemote_2間の通信を暗号化する方法.
たとえば,あるターミナルで,
% ssh -R X:Local:Z Remote -l username
としてログインし,別のターミナルで
% ssh -L Z:Remote_2:Y Remote_2 -l username
とする.
これで,RemoteのX番ポートからRemote_2のY番ポートまで,ローカルホストのZ番ポートを介したセキュアな通信経路を確保できる.
+--Local--+ +--Remote--+ +-Remote_2-+
| | | | | |
|+---<--- S ======> 22 <-+ | +==> 22 --+ |
Z| | | | | U | | |
|+--->--- T ==+ X ---+ | U Y <--+ |
| | U | | U | |
+---------+ U +----------+ U +----------+
U U
+=======================+
あるいは,例3で例2ダッシュを応用した時と同じようなロジックでも可能.
たとえば,
% ssh -R Z:Remote_2:22 Remote -l username
としてログインし,そこからさらに,
% ssh -p Z -L X:Remote_2:Y Remote_2 -l username
とする.
+--Local--+ +--Remote--+ +-Remote_2-+
| |---------| | | |
| +=== S ======> 22 <====== Z +==> 22 --+ |
| U |---------| +--->| U | | |
| U | | | | U | | |
| +==> T ==+ X ----+ | U Y <--+ |
| | U | | U | |
+---------+ U +----------+ U +----------+
U U
+=======================+
この場合,RemoteからRemote_2へsshが出来ることが必要である.ので,本当なら次のようにする方が簡単ではある.
% ssh Remote -l username
としてログインし,そこからさらに,
% ssh -L X:Remote_2:Y Remote_2 -l username
とする.
+--Local--+ +--Remote--+ +-Remote_2-+
| | | | | |
| S ======> 22 +--> T ========> 22 --+ |
| | | | | | | |
| | X ----+ | Y <--+ |
| | | | | |
+---------+ +----------+ +----------+