Chienomi

SSHのリバースポートフォワーディングの強化

unit

  • TOP
  • Old Archives
  • SSHのリバースポートフォワーディングの強化

以前かなり入念に設定して外出中もSSHでログインできるようにしたはずだったのだが、実際に試してみるとうまくいかないケースがあった。

もちろん、前回の設定で、SSHが死ねば再度コネクションを貼り直すようにしたし、サーバーから一定時間応答がなければ死んだとみなすようになっていた。 これで万全のはずだった。

ところが、サーバーからPONGは届いているにもかかわらず、ポートフォワーディングは死んでいる…という事態に遭遇したのだ。

これでは困る。 なぜそんなことになるというのか。

しかし発生するものは仕方ない。 実際にログインできない場合には無理やり貼り直すことにしよう。

方法としては割と単純で、自分自身に対するものではあるが、一旦サーバーにSSHで接続し、そこからSSHで手元のコンピュータに対してログインしコマンドを実行する。 これに失敗すればコネクションが切れているとみなす。

ProxyCommandを使う必要はなく、単純にsshのコマンドとしてsshを含めればいい。

ssh serverhost ssh mycomputer true

新しく鍵を作ってサーバーに登録する。

サーバーで実行するコマンドはsshである。

また、逆にサーバーでも新しい鍵を作って手元コンピュータに登録する。つまり、互いにコマンド実行用の鍵を登録することになる。

サーバー側で結びつけるコマンドはsshである。 このSSHで~/.ssh/configによってターゲットコンピュータに対してログインするホストを指定する。

Host target-pc-connection-check
    User jrh
    Port 2222
    Hostname localhost
    IdentityFile ~/.ssh/target-pc-connection-check_rsa

サーバー側で鍵に結びつけるコマンドはssh target-pc-connection-checkである。

ターゲット側では次のように登録する。

Host target-pc-connection-check-via-server
    User jrh
    Port 22
    Hostname serverhost.example.com
    IdentityFile ~/.ssh/target-pc-connection-check-via-server_rsa

これでターゲットコンピュータがこの鍵でサーバーにログインすると自動的にサーバーはSSHを実行しターゲットコンピュータにSSHポートフォワーディングを介して接続しようとする。 自動化のためそれぞれの鍵にはパスワードはかけない。

ターゲット側で鍵に結びつけるコマンドはtrueでも良いと思うが、echo OKあたりでも良いだろう。

これでターゲット側から

ssh target-pc-connection-check-via-server | grep -qF OK

とすれば、コネクションが到達するかどうかをチェックできる。

Systemdユニットに組み込むと面倒なことになるので、システムトレイアプリに組み込む。

#!/usr/bin/zsh

unitname="sshreverse.service"

systemctl start --user $unitname

while systemctl status --user $unitname | grep -F "active (running)"
do
  (
    while sleep 300
    do
      if ssh target-pc-connection-check-via-server | grep -qF OK
      then
        :
      else
        systemctl restart --user $unitname
      fi
    done
  ) > /dev/null &
  typeset -i checkpid=$!
  yad --notification --image="network-vpn" --title="Reverse Forwarding is Now Active"
  if yad --title="Stop Reverse Forwarding" --image dialog-question --button=gtk-yes:0 --button=gtk-no:1 --text="Really stop reverse for
warding?"
  then
    kill $checkpid
    systemctl stop --user $unitname
  fi
done