Help us understand the problem. What is going on with this article?

異なるprivateネットワーク内の端末をsshで繋ぐ

More than 5 years have passed since last update.

ある朝,「出先のノートPCから家の母艦PCを操作したい(=sshで潜りたい)」とふと思いたった.

固定グローバルIPを持ちかつsshで潜れる機器が家のネットワークにあれば,以下のようにローカルポートをフォワードしてやれば良いが,あいにく家にはそんな高いものは存在しない.(DDNS?知らんな)

with_global_ip
# (pc1):ノートPC/(pc2):母艦PC/(pc3):固定グローバルIPを持つPC
(pc1)$ ssh -L (ローカルポート):(pc2):22 (username)@(pc3)
# ex.  ssh -L 22222:192.168.0.2:22 hogehoge@110.110.110.220

そこでなんとなく契約していたVPSを中継サーバにして,ノートPC/母艦PCのsshトンネルを結ぶことにした.

abstract_image
# (pc1):ノートPC/(pc2):母艦PC/(pc3):中継サーバ
                               (pc3:port20022)--<ssh tunnel>--(pc2:port22) (母艦-中継サーバのsshトンネル)
(pc1:port20022)--<ssh tunnel>--(pc3:port20022)                             (ノート-中継サーバのsshトンネル)

# トンネルを作った上で...
(pc1) $ ssh -p 20022 (username)@localhost

前提

ネットワーク前提を整理すると以下のようになる.pc[123]は前述の構成図参照.

  • pc1(ノートPC)/pc2(母艦PC)はprivateアドレスのみ持ち,かつ所属するネットワーク内のグローバルIP持ちの機器にsshで潜れない.
  • pc3(中継サーバ)はpc1/pc2にsshで潜れない. (潜れるならばローカルポートフォワードでOKなので)
  • pc1/pc2はpc3にsshで潜れる.

母艦-中継サーバのsshトンネル

このトンネルでは,中継サーバの20022番ポートを母艦の22番ポート(sshのデフォルトポート)にフォワードする.
方向が(sshサーバ)->(sshクライアント)のため,リモートポートフォワードを使用する.

remoteforward
(pc2) $ ssh -R 20022:localhost:22 (username)@(pc3)

ノート-中継サーバのsshトンネル

このトンネルでは,ノートの20022番ポートを中継サーバの20022番ポートにフォワードする.
方向が(sshクライアント)->(sshサーバ)のため,ローカルポートフォワードを使用する.

localforward
(pc1) $ ssh -L 20022:(pc3):20022 (username)@(pc3)

ノートからのssh接続 with GatewayPortsの変更

準備完了.で,ノートPCの20022番ポートにアクセスで一件落着…と思いきや...

(pc1) $ ssh -p 20022 (username)@localhost
ssh_exchange_identification: Connection closed by remote host 

この原因は中継サーバ上でlistenしているポートを確認することで判明する.
中継サーバ上で,20022番(母艦の22番ポートにフォワードされている)はループバックアドレス(localhost)にバインドされているため,
(中継サーバ):20022にフォワードしても上手く接続できない.

(pc3) $ netstat -lt | grep 20022
tcp        0      0 localhost:20022             *:*                         LISTEN
tcp        0      0 localhost:20022             *:*                         LISTEN

これを解決するためには,sshdのGatewayPortsの設定を変える必要がある.
GatewayPorts=no(デフォルト値)では,リモートポートフォワード時のポートが常にループバックアドレスにバインドされるため,
GatewayPorts=yesと設定して,任意のアドレスにバインドするように変更する.

GatewayPorts_yes
(pc3) $ sudo vi /etc/ssh/sshd_config
…
GatewayPorts yes(pc3) $ sudo /etc/init.d/sshd restart 
sshd を停止中:                                             [  OK  ]
sshd を起動中:                                             [  OK  ]

(pc2) $ ssh -R 20022:localhost:22 (username)@(pc3)

# *(任意のアドレス)にバインドされていることを確認
(pc3) $ netstat -lt | grep 20022
tcp  0  0  *:20022  *:*  LISTEN

これでようやくノートから母艦へsshで潜ることができる.

(pc1) $ ssh -p 20022 (username)@localhost
Password:

あるいはGatewayPorts=clientspecified として接続時にバインドするアドレスを指定してもよい.

GatewayPorts_clientspecified
(pc3) $ sudo vi /etc/ssh/sshd_config
…
GatewayPorts clientspecified
…
(pc3) $ sudo /etc/init.d/sshd restart 
sshd を停止中:                                             [  OK  ]
sshd を起動中:                                             [  OK  ]

# 20022番ポートの指定の前に,バインドするIP or FQDNを指定する.
(pc2) $ ssh -R (pc3):20022:localhost:22 (username)@(pc3)

# リモートポートフォワード時に指定したアドレスにバインドされていることを確認
(pc3) $ netstat -lt | grep 20022
tcp  0  0  (pc3):20022  *:*  LISTEN

これでもさきほどと同様,sshで潜れるようになる.

(pc1) $ ssh -p 20022 (username)@localhost
Password:

ノートからのssh接続 with GatewayPortsデフォルトのまま

ここまでで要求を満たせたため,ほっとしてコーヒーを飲んでいたところ,「GatewayPortsのデフォルト設定(no)でできるのに,わざわざ設定変更する男の人って…」という恒例の声が横から聞こえてきた.
どうも「うわ…私の○○…」よろしく,口元に手をあてての発言らしい.(注: この記事を書いている時点で,我が家に人間は一人のみ)

今後の力関係のためにも,デフォルト設定のまま要求を満たす方法を模索していたところ,何とか見つけた.
GatewayPorts=noだと,リモートポートフォワード時にループバックアドレスにバインドされてしまうならば,ループバックアドレスを指定してローカルポートをフォワードしてやればよいだけだった.

localforward_localhost
(pc2) $ ssh -R 20022:localhost:22 (username)@(pc3) # pc3(中継サーバ)上ではlocalhost:20022がlistenになる
(pc1) $ ssh -L 20022:localhost:20022 (username)@(pc3) # 20022:(pc3):20022ではなく20022:localhost:20022
(pc1) $ ssh -p 20022 (username)@localhost
Password:

ポイントはlocalhostがsshコマンドを実行している端末を表しているわけではないということ.
これを押さえないと混乱する.

# 下記のlocalhostはpc1(ssh実行端末)を表すわけではない.
# pc1上の20022番ポートを,pc3(中継サーバ)上でlistenしている""localhost"":20022にフォワードする.
(pc1) $ ssh -L 20022:localhost:20022 (username)@(pc3) 

参考

(ref1). http://www.slideshare.net/tohakushi/ssh-13118950
(ref2). $ man sshd_config

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした