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


12

SSHでホストに接続する場合、通常3「パイプ」は、ホストとゲストとの間に設けられているstdinstdoutstderr

追加のファイル記述子のフォワード(3およびフォワード)を作成するコマンドラインオプションはありますか?

たとえば、私はやりたい

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

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


2
closefrom(STDERR_FILENO + 1)OpenSSHソースコードの下でのさまざまな呼び出しを考えると、おそらくトリッキーなソース編集なしではありません。これを要求していることは何ですか?
-thrig

プロトコルはstdin/ out/ 以外の追加ストリームのトンネリングerrをサポートしますが、サーバー/クライアントはその機能をサポートしません。
サルバ

@thrig OPではありませんが、それは長い間ですが、これが何に役立つのかまだ知りたい場合は、ここで見つけたいと思っていたのは、ssh、bashのスクリプト、そのスクリプトの標準入力。次のようなもの:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL

@thrigこのようなものは--forwardfd必要ないはずだと思います。ssh他のものを開く前に、開いているファイル記述子が何であるかをチェックし、リモート側の同じファイル記述子に自動的に転送できます。これは私の例のように完全に透過的です。sshそのためにパッチを当てるのはどれほど難しいでしょうか。あなたが言ったように、それらの背後にある理由によっては難しいかもしれませんclosefrom(STDERR_FILENO + 1)
-JoL

回答:


6

これは、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 

1

私はそれが可能になるはずだと確信しています。追加の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

@jakujeからの答えの問題は、socketsでのみ機能するが、それらを含むファイルを期待する標準のUNIXツールを使用できないことです

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、編集する必要があります。

しかし、あなたは使用することができますsocatnetcatまたはサポートする任意の他の同様のツールUNIXローカルソケットがnetcat-traditionalあるはありません、ファイル転送のためのローカルソケット転送を使用するのに十分な!):

# 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 -tTTYの割り当てに使用する必要があります。

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.