再現する手順:

再現する手順:

ProxyCommand が使用されている場合、OpenSSH_8.4p1 は同じ接続を共有する他のセッションを終了するのはなぜですか? これを防ぐ方法はありますか?

注: ProxyCommand 引数が省略されている場合、この動作は発生しないようです。

再現する手順:

  1. ローカルホストへの既存の共有接続をすべて切断します。
ssh -o ControlPath=/tmp/%C -O exit 127.0.0.1 2>/dev/null
ssh -o ControlPath=/tmp/%C -O exit localhost 2>/dev/null
  1. 次のコマンドをそれぞれ異なるターミナルで 2 回並行して実行します。
ssh -F none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
  -o ControlMaster=auto -o ControlPath=/tmp/%C -o ControlPersist=1d \
  -o ProxyCommand='ssh -W %h:%p 127.0.0.1' \
  localhost 'sleep 3600'
  1. Ctrl + C と入力して、SIGINT で最初の ssh プロセスを中断します。

予想される行動

  • SIGINT されたプロセスのみが終了します。
  • 他のプロセスは影響を受けずに実行され続けます。

実際の行動

  • 両方のプロセスが終了します。

答え1

SIGINT されたプロセスのみが終了します。

「プロセス」は誤った前提です。Ctrl+C SIGINTフォアグラウンドプロセスに送信するグループターミナルのプロセス グループには複数のプロセスが含まれる場合があります。

次に、これが関連します。

ProxyCommand
サーバーに接続するために使用するコマンドを指定します。コマンド文字列は行末まで拡張され、execシェル プロセスが長引かないようにユーザーのシェル ディレクティブを使用して実行されます。
[…]

ソース

コマンドは、 main と同じプロセス グループ内でローカルに実行されますssh。この例ではコマンドは ですssh …が、一般的には何でもかまいません。いずれにしても、コマンドは を認識せずControlMasterControlPersistmain に使用しますssh

Ctrl+を押すとC、フォアグラウンドプロセスグループの各プロセスが を取得します。以外の場合、このソケットは最初から によって処理されるため、 SIGINT"main"sshは のソケットに影響を与えずに終了します。ControlPathControlPersistnoさらにもう一つ ssh意図的に独自のプロセス グループ内に生成されたプロセスは存続できます。このコンテキストでは、これを真のメインと呼ぶことができますssh

予期しない動作は、 で指定されたコマンドがProxyCommandフォアグラウンド プロセス グループで生成され、中断する とSIGINT連携して動作するためです。 コマンドは、通常どおりにシグナルに反応します。 この場合、コマンドは で終了します。 また、 コマンドはすべてのデータを中継することになっていたため、マスター接続 (実際にメインとなる) は役に立たなくなりました。 依存するすべてのプロセスとともに終了します。sshSIGINTsshssh

したがって、オリジナルでは、マスター接続 (およびソケット) の処理がssh確実に維持されるように追加の作業が行われますが、同様に重要な で指定されたコマンドに対してはこれが実行されません。これはバグと呼べると思います。sshCtrlCProxyCommand

で指定されたコマンドが、でProxyCommand免疫によって生成されたほうが良いでしょう。sshそのCtrlプロセス グループ。私はこれを十分に分析していません。とにかく、今のところはそうではありません。コマンドは、 +を押した時点でフォアグラウンド プロセス グループであるプロセス グループで生成さCれるため、 になりますSIGINT

回避策としては、コマンドを の影響を受けないようにすることですSIGINT。 内部ではが自動的にを使用するため、 を直接ProxyCommand使用することはできません。これは意味をなさず、動作しません。さらに別のシェルが必要です。trapProxyCommandexecexec trap …

ssh -F none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
  -o ControlMaster=auto -o ControlPath=/tmp/%C -o ControlPersist=1d \
  -o ProxyCommand='sh -c "trap \"\" INT; exec ssh -W %h:%p 127.0.0.1"' \
  localhost 'sleep 3600'

私のテストでは、免疫があっても、時間が来たときにSIGINTこの内部sshが終了するのを防ぐことはできず、有限設定のためマスター接続が終了するはずであることが示されていますControlPersist

関連情報