Linuxコマンド

SSHポートフォワーディングの使い方(図で説明)

投稿日:

SSHのポートフォワーディング(SSHポート転送)機能を利用すると、ローカルホストの任意のポートに送信したデータを、リモートホストの特定のポートへ転送することができます。

POPのようなプレーンテキストのプロトコルに使用して、SSHの通信経路は使った安全な通信を行うことに利用できます。

SSHポートフォワーディングは、主に次のようなケースで利用します。

  • SSHの暗号化された通信経路を使った安全な通信を行う
  • ファイアーウォールを超えてサーバーと通信する
  • 複数ホストを経由する必要がある場合、最終ホストと直接通信しているようにアクセスする

この記事ではSSHポートフォワーディング(SSHポート転送)について、使い方や動作を図を使ってわかりやすく説明していきます。

コマンドの構文と説明に使用するケース

最初にポートフォワーディングの構文とこの記事で説明するケースを見てみましょう。

SSHポートフォワーディングの構文

SSHポートフォワーディングを行うためのsshコマンドの構文は次の通りです。

ssh -f -N -L ローカルポート番号:転送先ホスト名:転送先ポート番号 ユーザ名@SSH接続ホスト名

-fオプションはSSHの認証が完了し、リモートコマンドを実行した後にSSHをバックグランドへ移行するためのオプションです。

-Nオプションはリモートコマンドを実行しないよう指示するオプションです。上記の構文ではリモートで実行するコマンドの指定がないので、-fオプションを指定するときは-Nオプションが必要です(指定しないとエラーになる)。

-Lオプションはポートフォワーディングを指示するオプションです。「ローカルポート番号」には、ローカルマシンで使用していない任意のポート番号を指定します。

システムポート(ウェルノウンポート)の「0番〜1023番」はrootユーザーでしか使用できません。一般にシステムポートの使用は避けた方が良いでしょう。

「転送先ホスト名:転送先ポート番号」には、通信を転送する先のホスト名とそのポート番号を指定します。

残りの「ユーザ名@SSH接続ホスト名」には、SSHサーバーのホスト名とそのユーザ名を指定します。

なお、ホスト名の部分はIPアドレスでも構いません。

記事で説明するケース

この記事ではリモートのWebサーバー(80番ポート)にアクセスする次の2つのケースを例として、ポートフォワーディングの使い方とその動作を説明します。

この記事で説明するケース

ケース1:SSHサーバー経由でWebサーバーへアクセスする

ケース1はローカルマシンからWebサーバへ直接アクセスできません。しかし、SSHサーバー(ポート22番)にログインはでき、そのSSHサーバーからWebサーバー(ポート80番)にはアクセスできます。

例えば、SSHサーバーとWebサーバーが社内LANのネットワーク上にあり、外部からはSSHサーバー(踏み台サーバー)を経由しなければならない場合がこれに該当します。

このケースでポートフォワーディングを使うと、ローカルマシンがWebサーバーに直接アクセスしているかのように通信できます。

ケース2:ファイアーウォールを超えてアクセスする

ケース2はファイアーウォールでポート80番が遮断されているため、Webサーバー(ポート80番)に直接アクセスできません。しかし、SSHサーバー(ポート22番)にログインはできるケースです。

このときポートフォワーディングを使うと、ローカルマシンからサーバーで稼働するWebサーバー(ポート80番)に直接アクセスしているかのように通信ができます。

なお、ここではSSH接続にパスワード認証を使っているものと想定しています。

それではそれぞれのケースについてポートフォワーディングの使い方を見ていきましょう。

ケース1:
SSHサーバー経由でWebサーバーへアクセスする

ケース1はローカルマシンから直接Webサーバーへアクセスできないが、SSHサーバーにログインすることができ、かつSSHサーバーからはWebサーバーへアクセスできる場合です。

言い換えれば、Webサーバーへアクセスするには必ずSSHサーバーを経由する必要があるということです。

SSHサーバー経由でWebサーバーへアクセスする

上図のような構成のとき、SSHポートフォワーディングを使ってローカルマシンからWebサーバーへアクセスできるようにするには次のコマンドを実行します。

ssh -L 50080:www.example.com:80 taro@ssh.example.com

コマンドを実行するとパスワードを尋ねられますので、通常のSSH接続と同じようにパスワードを入力してSSHサーバーにログインします。

このコマンドのそれぞれの意味は次の通りです。

  • 「50080」はローカルマシンで使用するポート番号です。ローカルマシンで使用していない任意のポート番号を指定します。
  • 「www.example.com:80」の部分には、SSHの通信を転送する先のリモートホスト名とポート番号を指定します。ここではWebサーバーの80番ポートを指定しています。
  • コマンドの残りの部分は、SSHサーバーにログインするために必要なものを指定します。ここではユーザーtaroがパスワード認証でログインできることを想定しています。

これでローカルマシンの50080番ポートへの通信がWebサーバー(ポート80番)へ送られるようになります。このとき、SSH接続の経路の通信は暗号化されます。

Webブラウザでアクセスする

Webブラウザを使って実際にWebサーバーにアクセスしてみましょう。例えば、通常は以下のURLでWebページにアクセスできるとします。

http://a.example.com/page-a.html

ポートフォワーディングを使ったときはコマンドで指定したローカルマシンのポートにアクセスしますので、URLは次のようになります。

http://localhost:50080/page-a.html

URLのホスト名はローカルマシンを表すlocalhost(ループバックアドレス)、ポート番号はコマンドで指定した50080番です。

ブラウザを起動して上記のURLにアクセスするとWebサーバーからpage-aを取得してブラウザに表示されます。

ケース1の通信の詳細

このときの通信の流れを詳しく見てみましょう。

まずSSHコマンドを実行すると、ローカルマシンの任意のポート(any)とSSHサーバーの22番ポートでSSH接続が確立されます。

次にブラウザでローカルマシンの50080番ポートにアクセスすると、その通信はSSH接続の通信路を通ってSSHサーバーの22番ポートへ送られます。さらにSSHサーバの任意のポート(any)とWebサーバーの80番ポートの接続が確立され、確立された経路を通ってWebサーバーの80番ポートへ送られます。

この動作を図で表すと次のようになります。

SSHポートフォワーディングのケース1の説明図

SSH接続のパイプ(トンネル)は、ここを通る通信が暗号化されていることを表しています。

SSHコマンドをバックグラウンドで実行する

先程はWebブラウザを使いましたが、curlコマンドなどでWebサーバーにアクセスしたい場合もあるでしょう。

前述のコマンドを実行するとターミナルはSSHサーバーにログインした状態なのでローカルマシンのコマンドを実行できません。新しくターミナルを立ち上げて、そこでコマンドを実行しても良いのですが、SSHコマンドをバックグラウンドで実行すれば同じターミナルがそのまま使用できます。

それには先ほどのコマンドに-fと-Nオプションを追加します。

ssh -f -N -L 50080:www.example.com:80 taro@ssh.example.com

-fオプションは認証が完了してリモートでコマンド実行した後にSSHをバックグランドへ移行するためのオプションです。ここではリモートで実行するコマンドを指定していないので、リモートコマンドを実行しないよう指示する-Nオプションも指定します。

このようにするとSSHコマンドはバックグラウンドで実行されますので、そのままターミナルからローカルマシンのコマンドを実行できます。

例えば先ほどと同じWebページをcurlコマンドで取得するには、ターミナルで次のコマンドを実行します。URLはブラウザでアクセスする場合と同じです。

curl http://localhost:50080/page-a.html

ただしSSHコマンドはバックグラウンドで実行され続けますので、ポートフォワーディングが不要になったらプロセスをキルするといいでしょう。

それには次のようにpsコマンドでバックグラウンドで実行されているSSHコマンドのプロセスID(PID)を確認し、killコマンドでプロセスを終了します。

# ps -ef | grep ssh
...
root  3200  ...  ssh -f -N -L 50080:www.example.com:80 taro@ssh.example.com
...
# kill 3200

ケース2:
ファイアーウォールを超えて接続する

ケース2はサーバーにSSH(ポート22番)接続はできるが、そのサーバーで稼働するWebサーバー(ポート80番)には直接アクセスできないケースです。

SSHポートフォワーディングのケース2の概要図

このケースでもSSHポートフォワーディングを使うと、ローカルマシンからWebサーバーに直接アクセスしているかのように通信できます。

このときはターミナルから次のコマンドをいずれかを実行します。

ssh -L 50080:localhost:80 taro@a.example.com
ssh -L 50080:server.example.com:80 taro@a.example.com

どちらのコマンドでもやりたいことができますが、サーバー内部での動作が少し異なります。1つ目のコマンドをおすすめします。

コマンドを実行したら、通常のSSH接続と同じようにサーバーにログインします。

ケース1との違いは転送先のホスト名の指定だけです。ケース1はSSHサーバーとは異なるサーバー(Webサーバー)のホスト名を指定していましたが、今回は自分自身のホスト名(localhostあるいはserver.example.com)を指定しています。

つまり、SSH接続の経路を通ってきた通信を自身のポート80番に転送しています。

Webブラウザでアクセスする

WebブラウザでアクセスするURLもケース1と同じで、ローカルホスト自身(localhost)のポート50080番を指定します。

http://localhost:50080/page-a.html

WebブラウザでこのURLにアクセスするとpage-a.htmlを取得して表示します。

ケース2の通信の詳細

この動作を図で表すと次のようになります。

SSHポートフォワーディングのケース2の説明図

SSHコマンドを実行するとローカルマシンの任意のポート(any)とサーバーの22番ポートの間でSSH接続が確立されます。

ブラウザからローカルマシンの50080番ポートにアクセスすると、通信はSSHの通信路を通りサーバーに送られ、その通信はさらにサーバー自身のポート80番に転送されます。

ローカルマシンとサーバーAの間はSSHのトンネルを通りますので、その通信が暗号化されているのもケース1と同じです。

SSHコマンドをバックグラウンドで実行する

SSHコマンドをバックグランドで実行する方法もケース1と同様で、先ほどのコマンドに-fと-Nオプションを追加します。

ssh -f -N -L 50080:localhost:80 taro@a.example.com

curlコマンドでWebページを取得する方法もケース1と同じです。

curl http://localhost:50080/page-a.html

バックグラウンドで実行されているコマンドは不要になったらkillするようにしましょう。

localhostと実際のホスト名を指定したときの違い

先ほど次の2つのコマンドを紹介しましたが、この違いについて簡単に説明します。

ssh -L 50080:localhost:80 taro@a.example.com
ssh -L 50080:server.example.com:80 taro@a.example.com

「localhost」と「server.example.com」の指定はどちらもSSHサーバー自身を表すことになりますが、それぞれ名前解決されるとlocalhostは「127.0.0.1(ループバックアドレス)」に、server.example.comはサーバーの実際のIPアドレスに解決されます。

ループバックアドレスは論理インタフェースに紐づけられ、実際のIPアドレスは物理インタフェースに紐づけられますので、ポートフォワーディングの際、SSHサーバーのポート20番に届いた通信が論理インタフェースに紐づけられたループバックアドレスに転送されるか、物理インタフェースに紐づけらた実際のIPアドレスに転送されるかが異なることになります。

つまりSSHサーバーのポート20番に届いた通信が自身のポート80番へ転送される経路が多少異なるということです。

この経路の違いがどのように影響するかはOSの詳細に立ち入ることになり、またポートフォワーディングの使い方という本質からだいぶ外れてしまうのでこのへんにしておきますが、localhostとの通信は完全な内部通信となりますので、こちらを使った方が何かと問題が出ないと思います。

なお、私の持っている本で3冊にポートフォワードの記載がありましたが、いずれも実際のホスト名を使っていました。しかしmanコマンドで参照できるSSHコマンドのマニュアルではlocalhostを使用していました。

まとめ

SSHポートフォワーディングは、目的のサーバーにアクセスするためにSSHサーバーを経由しなければならないときに非常に便利です。

この記事ではWebサーバー(ポート80番)を例にしましたが、もちろん任意のリモートホストの任意のポートにポートフォワーディングすることが可能です。

私はファイル転送にもよくポートフォワーディングを使っていますので、最後にこの事例を簡単に説明して終わりにしたいと思います。

ポートフォワーディングを使ってファイルを転送する

このケースは次のような構成であるとします。

クライアント --- リモートホスト1 --- リモートホスト2

クライアントからリモートホスト1にSSH接続ができ、リモートホスト1からリモートホスト2にもSSH接続ができるが、クライアントからリモートホスト2には直接SSH接続できないケースです。このときクライアントでリモートホスト2からファイルを取得したいとします。

ポートフォワーディングを使わないで手順は大体次のようになるでしょう。

  1. クライアントからリモートホスト1にSSHログインする
  2. リモートホスト1からリモートホスト2のファイルをSCPで取得する
  3. クライアントからリモートホスト1のファイルをSCPやWinSCPなどのアプリケーションで取得する
  4. リモートホスト1に残っているファイルを削除する

これをポートフォワーディングを使って行うと次のようになります。

  1. クライアントでポートフォワーディング(転送先ホストはリモートホスト2のポート22番)を実行する
  2. クライアントからSCPやWinSCPなどを使って自身のポートにアクセスし、リモートホスト2のファイルを取得する
  3. ポートフォワーディングのプロセスを終了する

この説明だとあまり楽になってないように思えるかもしれませんが、実際はかなり楽できると思います。特にリモートホスト1に一時ファイルができないのが良いところです。

このほかにも便利な使い方がありますので、皆さんもSSHポートフォワーディングを是非使ってみてください。

ここから先は主に検証した内容の覚え書きです。SSHポートフォワードを使うにはここまでの記事で十分ですので、この先は読まなくても良いでしょう。興味のある方のみ先に進んでいただければと思います。

【参考】動作検証

この記事を書くにあたり仮想環境でサーバーを建てて検証を実施しました。

Webサーバへのアクセスは一瞬で終わってしまうので、この検証ではPOPサーバーにTelnetで接続して確認を行います。

ケース1の検証

仮想環境に3台のLinuxマシンを用意します。

ローカルマシン用のLinuxマシン
  • ホスト名:client
  • IPアドレス:192.168.60.10
  • 用途:SSHクライアント用
SSHサーバー用のLinuxマシン
  • ホスト名:Server1
  • IPアドレス:192.168.60.20
  • 用途:SSHサーバーが稼働。Server2のPOPサーバへもアクセス可能
POPサーバー用のLinuxマシン
  • ホスト名:Server2
  • IPアドレス:192.168.60.30
  • 用途:POPサーバ(dovecot)が稼働

clientでSSHポートフォワーディングのコマンドを実行します。Server1にSSH接続し、その通信はServer2のPOPサーバーへ転送します。

[root@client ~]# ssh -f -N -L 50110:192.168.60.30:110 taro@192.168.60.20

この状態でのclientのTCPソケットを確認します。

[root@client ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
...
LISTEN   0        128            127.0.0.1:50110            0.0.0.0:*
ESTAB    0        0          192.168.60.10:56474      192.168.60.20:22
...

SSHの接続が確立され、ループバックアドレス(127.0.0.1)のポート50110番がLISTENです。

clientのループバックアドレス(127.0.0.1)のポート50110番にTelnetで接続します。これでServer2のPOPサーバーに接続されました。

[root@client ~]# telnet 127.0.0.1 50110
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
+OK Dovecot ready.

このときのclientのTCPソケットを別のターミナルを立ち上げて見てみます。

[root@client ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
...
LISTEN   0        128            127.0.0.1:50110            0.0.0.0:*
ESTAB    0        0              127.0.0.1:50110          127.0.0.1:39152
ESTAB    0        0              127.0.0.1:39152          127.0.0.1:50110
ESTAB    0        0          192.168.60.10:56474      192.168.60.20:22
...

「127.0.0.1:50110」と「127.0.0.1:39152」との間で接続が確立されています。

Telnet接続したときの通信をclentでキャプチャした結果は次の通りです。複数のインタフェース(loとeth1)をキャプチャしたかったので、tcpdumpではなくtsharkを使いました。

[root@client ~]# tshark -i lo -i eth1 -n
...
...
1 0.000000000    127.0.0.1 → 127.0.0.1    TCP 74 39152 → 50110 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=1165547724 TSecr=0 WS=128
2 0.000007518    127.0.0.1 → 127.0.0.1    TCP 74 50110 → 39152 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=1165547724 TSecr=1165547724 WS=128
3 0.000014242    127.0.0.1 → 127.0.0.1    TCP 66 39152 → 50110 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=1165547724 TSecr=1165547724
4 0.010067703    127.0.0.1 → 127.0.0.1    TCP 86 50110 → 39152 [PSH, ACK] Seq=1 Ack=1 Win=43776 Len=20 TSval=1165547734 TSecr=1165547724
5 0.010095015    127.0.0.1 → 127.0.0.1    TCP 66 39152 → 50110 [ACK] Seq=1 Ack=21 Win=43776 Len=0 TSval=1165547734 TSecr=1165547734
6 0.000115681 192.168.60.10 → 192.168.60.20 SSH 166 Client: Encrypted packet (len=100)
7 0.001023164 192.168.60.20 → 192.168.60.10 SSH 118 Server: Encrypted packet (len=52)
8 0.001038095 192.168.60.10 → 192.168.60.20 TCP 66 56474 → 22 [ACK] Seq=101 Ack=53 Win=278 Len=0 TSval=1792724337 TSecr=3104266180
9 0.009896408 192.168.60.20 → 192.168.60.10 SSH 134 Server: Encrypted packet (len=68)
10 0.009914526 192.168.60.10 → 192.168.60.20 TCP 66 56474 → 22 [ACK] Seq=101 Ack=121 Win=278 Len=0 TSval=1792724346 TSecr=3104266188
^C14 packets captured

「127.0.0.1:39152」と「127.0.0.1:50110」で接続が確立され、client(192.168.60.10)とServer1(192.168.60.20)間の通信はSSH接続が使われていることがわかります。

Server1のTCPソケットの状態は次の通りです。

[root@Serve1 ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
...
ESTAB    0        0          192.168.60.20:37244      192.168.60.30:110
ESTAB    0        0          192.168.60.20:22         192.168.60.10:56474
...

SSH接続とServer2のPOPサーバー(192.168.60.30:110)との接続が確立されていることがわかります。

Server1でTelnet接続したときのキャプチャは次の通りです。

[root@Serve1 ~]# tshark -i lo -i eth1 -n
...
    1 0.000000000 192.168.60.10 → 192.168.60.20 SSH 166 Client: Encrypted packet (len=100)
    2 0.000146179 192.168.60.20 → 192.168.60.30 TCP 74 37244 → 110 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=33210704 TSecr=0 WS=128
    3 0.000428286 192.168.60.30 → 192.168.60.20 TCP 74 110 → 37244 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=1011476475 TSecr=33210704 WS=128
    4 0.000444294 192.168.60.20 → 192.168.60.30 TCP 66 37244 → 110 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=33210705 TSecr=1011476475
    5 0.000540260 192.168.60.20 → 192.168.60.10 SSH 118 Server: Encrypted packet (len=52)
    6 0.000791571 192.168.60.10 → 192.168.60.20 TCP 66 56474 → 22 [ACK] Seq=101 Ack=53 Win=278 Len=0 TSval=1792724337 TSecr=3104266180
    7 0.009096094 192.168.60.30 → 192.168.60.20 POP 86 S: +OK Dovecot ready.
    8 0.009122311 192.168.60.20 → 192.168.60.30 TCP 66 37244 → 110 [ACK] Seq=1 Ack=21 Win=29312 Len=0 TSval=33210713 TSecr=1011476484
    9 0.009349972 192.168.60.20 → 192.168.60.10 SSH 134 Server: Encrypted packet (len=68)
   10 0.009725835 192.168.60.10 → 192.168.60.20 TCP 66 56474 → 22 [ACK] Seq=101 Ack=121 Win=278 Len=0 TSval=1792724346 TSecr=3104266188
^C10 packets captured

Server1(192.168.60.20のポート37224番)とServer2(192.168.60.30のポート110番)の接続が確立され、この接続を使って通信が行われていること、およびclientとServer1の間ではSSH接続を使って通信していることがわかります。

Server2でも同じようにみてみます。TCPソケットの状態は次の通りです。

[root@Server2 ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
LISTEN   0        100              0.0.0.0:110              0.0.0.0:*
LISTEN   0        128              0.0.0.0:22               0.0.0.0:*
...
ESTAB    0        0          192.168.60.30:110        192.168.60.20:37244
...

Server2でキャプチャした内容は次の通りです。

[root@Server2 ~]# tshark -i lo -i eth1 -n
...
    1 0.000000000 192.168.60.20 → 192.168.60.30 TCP 74 37244 → 110 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=33210704 TSecr=0 WS=128
    2 0.000029528 192.168.60.30 → 192.168.60.20 TCP 74 110 → 37244 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=1011476475 TSecr=33210704 WS=128
    3 0.000227995 192.168.60.20 → 192.168.60.30 TCP 66 37244 → 110 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=33210705 TSecr=1011476475
    4 0.008548826 192.168.60.30 → 192.168.60.20 POP 86 S: +OK Dovecot ready.
    5 0.009014309 192.168.60.20 → 192.168.60.30 TCP 66 37244 → 110 [ACK] Seq=1 Ack=21 Win=29312 Len=0 TSval=33210713 TSecr=1011476484
^C5 packets captured

Server1(192.168.60.20のポート37224番)とServer2(192.168.60.30のポート110番)の接続が確立され、この接続を使ってServer1と通信していることがわかります。

ケース2の検証

ケース2では仮想環境に2台のLinuxマシンを用意します。

ローカルマシン用のLinuxマシン
  • ホスト名:client
  • IPアドレス:192.168.60.10
  • 用途:SSHクライアント用
SSHサーバー用のLinuxマシン
  • ホスト名:Server1
  • IPアドレス:192.168.60.20
  • 用途:SSHサーバーとPOPサーバが稼働するサーバー

SSHポートフォワーディングのため以下のコマンドを実行します。

# ssh -f -N -L 50110:localhost:110 taro@192.168.60.20

このときのclientのTCPソケットの状態を確認します。

[root@client ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
...
LISTEN   0        128            127.0.0.1:50110            0.0.0.0:*
ESTAB    0        0          192.168.60.10:56424      192.168.60.20:22
...

「127.0.0.1:50110」がLISTENで、Server1(192.168.60.20)とSSH接続が確立されています。

clientのポート50110番にTelnetで接続します。Server1のPOPサーバーと接続されました。

[root@client ~]# telnet 127.0.0.1 50110
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
+OK Dovecot ready.

POPサーバーと接続された状態のclientのソケットを確認します。

[root@client ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
...
LISTEN   0        128            127.0.0.1:50110            0.0.0.0:*
ESTAB    0        0              127.0.0.1:39118          127.0.0.1:50110
ESTAB    0        0          192.168.60.10:56424      192.168.60.20:22
ESTAB    0        0              127.0.0.1:50110          127.0.0.1:39118
...

「127.0.0.1:39118」と「127.0.0.1:50110」の間の接続と、SSH接続が確立されています。

Telnet接続したときの通信をclientでキャプチャした結果は次の通りです。

[root@client ~]# tshark -i lo -i eth1 -n
...
    1 0.000000000 192.168.60.10 → 192.168.60.20 SSH 166 Client: Encrypted packet (len=100)
    2 0.000614701 192.168.60.20 → 192.168.60.10 SSH 118 Server: Encrypted packet (len=52)
    3 0.000624958 192.168.60.10 → 192.168.60.20 TCP 66 56424 → 22 [ACK] Seq=101 Ack=53 Win=278 Len=0 TSval=1789555944 TSecr=3101097788
    4 -0.000129537    127.0.0.1 → 127.0.0.1    TCP 74 39118 → 50110 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=1162379331 TSecr=0 WS=128
    5 -0.000122340    127.0.0.1 → 127.0.0.1    TCP 74 50110 → 39118 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=1162379331 TSecr=1162379331 WS=128
    6 -0.000114875    127.0.0.1 → 127.0.0.1    TCP 66 39118 → 50110 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=1162379331 TSecr=1162379331
    7 0.009258142    127.0.0.1 → 127.0.0.1    TCP 86 50110 → 39118 [PSH, ACK] Seq=1 Ack=1 Win=43776 Len=20 TSval=1162379341 TSecr=1162379331
    8 0.009267739    127.0.0.1 → 127.0.0.1    TCP 66 39118 → 50110 [ACK] Seq=1 Ack=21 Win=43776 Len=0 TSval=1162379341 TSecr=1162379341
    9 0.009147352 192.168.60.20 → 192.168.60.10 SSH 134 Server: Encrypted packet (len=68)
   10 0.009165047 192.168.60.10 → 192.168.60.20 TCP 66 56424 → 22 [ACK] Seq=101 Ack=121 Win=278 Len=0 TSval=1789555952 TSecr=3101097796
^C10 packets captured

「127.0.0.1:39118」と「127.0.0.1:50110」で接続が確立され、client(192.168.60.10)とServer1(192.168.60.20)の間ではSSH接続でパケットがやり取りされていることが見てとれます。

このときServer1のTCPソケットは次の通りです。

[root@Serve1 ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
LISTEN   0        100              0.0.0.0:110              0.0.0.0:*
LISTEN   0        128              0.0.0.0:22               0.0.0.0:*
...
ESTAB    0        0              127.0.0.1:110            127.0.0.1:32800
ESTAB    0        0          192.168.60.20:22         192.168.60.10:56424
ESTAB    0        0              127.0.0.1:32800          127.0.0.1:110
...

Server1の内部(127.0.0.1)でポート32800番とポート110番ポートの接続が確立されたことがわかります。

Server1でキャプチャした結果は次の通り。

[root@Serve1 ~]# tshark -i lo -i eth1 -n
...
    1 0.000000000    127.0.0.1 → 127.0.0.1    TCP 74 32800 → 110 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=1648130125 TSecr=0 WS=128
    2 0.000034110    127.0.0.1 → 127.0.0.1    TCP 74 110 → 32800 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=1648130125 TSecr=1648130125 WS=128
    3 0.000047073    127.0.0.1 → 127.0.0.1    TCP 66 32800 → 110 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=1648130125 TSecr=1648130125
    4 -0.000166854 192.168.60.10 → 192.168.60.20 SSH 166 Client: Encrypted packet (len=100)
    5 0.000081507 192.168.60.20 → 192.168.60.10 SSH 118 Server: Encrypted packet (len=52)
    6 0.000445111 192.168.60.10 → 192.168.60.20 TCP 66 56424 → 22 [ACK] Seq=101 Ack=53 Win=278 Len=0 TSval=1789555944 TSecr=3101097788
    7 0.008540671    127.0.0.1 → 127.0.0.1    POP 86 S: +OK Dovecot ready.
    8 0.008632949 192.168.60.20 → 192.168.60.10 SSH 134 Server: Encrypted packet (len=68)
    9 0.008855826 192.168.60.10 → 192.168.60.20 TCP 66 56424 → 22 [ACK] Seq=101 Ack=121 Win=278 Len=0 TSval=1789555952 TSecr=3101097796
   10 0.008555632    127.0.0.1 → 127.0.0.1    TCP 66 32800 → 110 [ACK] Seq=1 Ack=21 Win=43776 Len=0 TSval=1648130133 TSecr=1648130133
^C10 packets captured

「127.0.0.1:32800」と「127.0.0.1:110」で接続が確立され、SSH接続でもパケットがやり取りされていることが見てとれます。

ループバックアドレスを指定と自身のIPアドレスを指定の違い

先程は転送先とホスト名としてlocalhostを指定しました。次のように転送先に実際のIPアドレス(192.168.60.20)を使ったときとの違いも見てみましょう。

[root@client ~]# ssh -f -N -L 50110:192.168.60.20:110 taro@192.168.60.20

結論としてはServer1内部のPOPサーバーとの接続に使用されるIPが異なります。

Telnetで接続したときのServer1のTCPソケットを見てみましょう。

[root@Serve1 ~]# ss -atn
State    Recv-Q   Send-Q     Local Address:Port        Peer Address:Port    Process
...
ESTAB    0        0          192.168.60.20:22         192.168.60.10:56470
ESTAB    0        0          192.168.60.20:110        192.168.60.20:43804
ESTAB    0        0          192.168.60.20:43804      192.168.60.20:110
...

localhost(127.0.0.1)を指定した場合、「127.0.0.1:32800」と「127.0.0.1:110」のようにループバックアドレス間で接続が確立されましたが、実IPアドレスを指定した場合は「192.168.60.20:43804」と「192.168.60.20:110のように実IPアドレス間で接続が確立されています。

このように接続に使われるIPアドレスが異なるのでServer1内部での経路が全く同じになるというわけではありません。

以上、検証はここまでとなります。ここが本当の最後になります。最後まで読んでいただきありがとうございます。

-Linuxコマンド

Copyright© アナグマのモノローグ , 2022 All Rights Reserved Powered by STINGER.