web-dev-qa-db-ja.com

SSH:stdin、stdout、stderrに加えて、追加の「パイプ」fdsを提供します

SSHを使用してホストに接続する場合、通常、stdinstdout、およびstderrの3つの「パイプ」がホストとゲストの間に提供されます。

追加のファイル記述子(3以降)の転送を作成するコマンドラインオプションはありますか?

例えば、私はしたいです

ssh --forwardfd=10:3 remotehost 'echo test >&3'

ローカルで開いたファイル記述子に「テスト」を出力します10。

12
mic_e

これは、openssh-6.7以降で使用可能なソケット転送を使用して行うことができます。これはある種のパイプです。このテクニックの例を次に示します: http://www.25thandclement.com/~william/projects/streamlocal.html

データの双方向ルートを取得します。 mysqlの例があります。

リモートサーバー上のMySQLクライアント接続をローカルインスタンスにプロキシします。

ssh -R/var/run/mysql.sock:/var/run/mysql.sock \
    -R127.0.0.1:3306:/var/run/mysql.sock somehost 
6
Jakuje

@jakujeからの回答の問題は、ソケットでのみ機能するが、ファイルと一緒に:

ssh -R/tmp/sock.remote:/tmp/sock.local "$Host" 'LANG=C cat >/tmp/sock.remote'

bash:/tmp/sock.remote:そのようなデバイスやアドレスはありません

また、ローカルソケットファイルがリモートホストで削除されないという問題もあります。次に同じコマンドを実行すると、警告が表示され、ソケットが正しく再作成されません。オプション-o StreamLocalBindUnlink=yesからsshを指定して古いソケットのリンクを解除できますが、私のテストではそれでは不十分でした。また、そのオプションを機能させるには、sshd_configを編集してStreamLocalBindUnlink=yesを含める必要があります。

ただし、socatまたはnetcatまたはUNIXローカルソケットをサポートする他の同様のツールを使用できますnetcat-traditional is[〜#〜]ない[〜#〜]十分!)ファイル転送にローカルソケット転送を使用するには:

# start local process listening on local socket, which receives the data when ssh opens the connections and saves it to a local file
nc -l -N -U /tmp/sock.local >/tmp/file.local &
# connect to remote $Host and pipe the remote file into the remote socket end
ssh \
 -o ExitOnForwardFailure=yes \
 -o StreamLocalBindUnlink=yes \
 -R /tmp/sock.remote:/tmp/sock.local \
 "$Host" \
 'nc -N -U /tmp/sock.remote </tmp/file.remote'

インタラクティブコマンドを実行することもできます。その場合、ssh -tを使用してTTYを割り当てる必要があります。

このソリューションの問題は、UNIXローカルソケットのパスをハードコードする必要があることです。ローカルでこれを問題にすることはありません。パスに$$を含めて、プロセスまたはユーザーごとに一意にすることができます。ディレクトリですが、リモートエンドでは、私の例のように、誰でも書き込み可能なディレクトリ/tmp/を使用しない方がよいでしょう。 sshセッションが開始されるとき、ディレクトリはすでに存在している必要があります。また、ソケットのiノードはセッションが閉じられた後も残るため、「$ HOME/.ssh。$$」のようなものを使用すると、時間の経過とともに、使用されていないiノードでディレクトリが乱雑になります。

TCPソケットlocalhostにバインドされたソケットを使用することもできます。これにより、デッドiノードでファイルシステムが乱雑になるのを防ぐことができますが、それでも、(一意)未使用のポート番号。したがって、まだ理想的ではありません。(sshには動的にポートを割り当てるコードがありますが、リモートホストでその情報を取得する方法が見つかりませんでした。)

おそらく、ファイルをコピーする最も簡単な解決策は、sshの組み込み接続共有機能を使用し、インタラクティブにscpまたはsfrpコマンドを実行することです。セッションはまだ並行して実行されています。 sshを使用してファイルをローカルシステムにコピーする を参照してください。

1
pmhahn

きっと可能だと思います。私はあなたが追加のssh接続を使用してそれぞれが別のペアのファイル記述子を運ぶハックを提案することができるだけです。例えば。次の概念実証スクリプトは、最初のsshを実行してダミーコマンド(スリープ)を実行し、ローカルのfds 5および6をリモートのstdinおよびstdoutに接続します。これらのfdsが通常の0、1、2に追加するものであると想定します。 。

次に、実際のsshが実行され、リモートでリモートfds 5および6が他のsshのstdinおよびstdoutに接続されます。

例として、このスクリプトはgzip圧縮されたmanページをリモートに渡し、リモートで解凍してmanで実行します。実際のsshのstdinとstdoutは、他のものでも引き続き使用できます。

#!/bin/bash
exec 5</usr/share/man/man1/ssh.1.gz 6>/tmp/out6 # pretend need 5 and 6

ssh remote 'echo $$ >/tmp/pid; exec sleep 99999' <&5 >&6 &
sleep 1 # hack. need /tmp/pid to be set

ssh remote '
  pid=$(</tmp/pid) 
  exec 5</proc/$pid/fd/0 6>/proc/$pid/fd/1
  echo start
  gzip -d <&5 | man /dev/stdin >&6
  echo stop
  kill -hup $pid
'
wait
less /tmp/out6
1
meuh