rcmdnk's blog
Last update

TP-Link WiFi ルーター WiFi6 PS5 対応 無線LAN 11ax AX4800 4324Mbps (5 GHz) + 574 Mbps (2.4 GHz) OneMesh対応 メーカー保証3年 Archer AX4800/A

以前、Macに対して 外部からアクセス出来るようにする方法 みたいなのを書きましたが、 ダイナミックDNSとかを使っても外から接続できない様な状況になったので、 そういった場合に無理やり接続できる様にしてみたという話。

状況

無線LANでも有線でも良いのですが、ルータ越しにネットにつながってる状態を考えます。

この場合、ルータにはグローバルIPが割り当てられていて、 ルータ内の端末にはプライベートIPのみが割り当てられます。

この時に、ルータの設定をいじることが出来れば、 ルータにグローバルIPで1022番ポートにアクセスしたら それをルータに192.168.1.2というプライベートIPで繋がってる端末の22番に転送、 みたいな事が出来ます。

No-IP 1 のクライアントをルータ内の端末で動かしてみると、 繋げたドメインはルータのグローバルIPに結び付けられていました。

したがって、普通に端末がグローバルIPを持ってるものだと思って そのドメインにssh接続すると、ルータの22番ポートに繋がるわけで、 ポート設定してない限り端末にはつながりません。

こういった場合に、ルータの設定が自分では変えられないものだったり、 外まで多段接続になっていてとてもポートを直接開放することが出来ない様な場合、 前の方法 ではssh(やvnc)では接続出来ません。 (TeamViewerなら可能)

こういった場合にも無理やり接続出来るようにしてみました。

必要なもの

必要な物は、 接続先の端末からも接続元の端末からも見える、 外部に公開されていて、ポートを転送したりしても良いサーバです。

ここを中継してつなげるようにします。

以下、最終的に接続したい端末をdest、 中継サーバーをserver、 接続元の手元の端末をclientとします。

接続される側での設定

やることは、destにおいて定期的にserverからのポートフォワードを 行うだけです。

こんなスクリプトを作って

portFoward
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env bash
if [ $# -lt 2 ];then
  echo "usage: port_forward <host> <port>"
  exit 1
fi
host=$1
port=$2

## Main loop
while [ 1 ];do
  # Try to extract server information
  ret=$(ssh -x $host netstat -a 2>/dev/null)
  if [ $? -ne 0 ];then
    # Could be offline (this machine or server), try later.
    #echo "Cound not resolve hostname $host"
    exit
  fi
  # Check if the port is active or not
  if echo "$ret"|grep $port|grep -q "LISTEN";then
    # Port is active, ok, nothing to be done.
    exit 0
  fi
  # If the network was disconnected, previous ssh process could remained
  # w/o the connection. These processes should be cleaned up.
  pids=$(ps -u$USER|grep "ssh -x -N -R ${port}:localhost:22 ${host}"|grep -v grep|awk '{print $2}')
  if [ "$pids" != "" ];then
    kill -kill $pids >& /dev/null
  fi
  # Then do port forwarding from $host:$port to localhost:22
  # You can ssh to this machine by accessing localhost:$port at server
  # If server's sshd_config has ""GatewayPorts yes",
  # Then you can access to this machine directly by `ssh $host:$port`.
  ssh -x -N -R $port:localhost:22 $host >& /dev/null &
done

下みたいな感じのcronジョブを作ります。

crontab
1
2
## Port Forward
0 * * * * $HOME/usr/bin/portFoward server 10022

上の設定では、1時間おきにserverの10022番ポートをdestの22番ポートに転送する 設定をしています。

server及びclientでの設定

serverに於いて、.ssh/configなんかに、

.ssh/config
1
2
3
4
5
Host dest
  HostName localhost
  Port 10022
  IdentityFile ~/.ssh/id_rsa
  User user

書いておけばserverにおいて、ssh destとするだけで destssh出来る様になります。 (IdentityFileに関しては対応する公開鍵がdestにある場合。)

これで、普段使いとしては、

client server:22 server:10022 (= dest:22)

という接続を行えばdestsshで入れる事になります。

2回目のsshがポートが特殊なだけで前にやった 多段ssh設定 と同じことなので、 適当に多段ssh設定 にしたがってclientから直接destまで届くような設定を してあげれば簡単にdestにいつでもssh出来るようになります。

追記: 2014/09/04

具体的には

~/.ssh/config
1
2
3
4
5
6
7
8
9
Host server
  User         user_at_server
  HostName     server

Host dest
  User user
  HostName localhost
  Port 10022
  ProxyCommand ssh server -W %h:%p

こんな感じで、destの設定でHostNameをlocalhostに変更し、 Portを10022等設定したものにすればOK。

追記ここまで

これで

$ ssh dest

で直接繋がる様になります。

ネットワークが一時切れたりIPが変わってしまっても大丈夫。 (1時間のタイムラグがありますが、ラグがクリティカルなら間隔を狭める等。

crontab
1
2
## Port Forward
*/5 * * * * $HOME/usr/bin/portFoward server 10022

とすれば5分置きにチェックする設定になります。

まとめ

安全で自由に使える公開サーバーがあることが前提になりますが、 ご利用は自己責任で、ということで。

Sponsored Links
  1. 全く関係ないですが、ついこの前、 No-IPのいくつかのドメインが マルウェアの温床となってるとかでMicrosoftが訴訟を起こして 差止めましたね。

    No-IP側は「Microsoft有り得ん」的な態度で怒りを露わにしてる感じでしたが。

    No-IP’s Formal Statement on Microsoft Takedown No-IP Blog - Managed DNS Services

    と思ってたらどうも大体の所は元に戻せた模様。

    Update: Details on Microsoft Takeover | No-IP Blog - Managed DNS Services

Sponsored Links

« GtHub Pagesについて GNU screenのUTF8パッチ付きのHomebrew用Formula »

}