SSH: Berikan tambahan "pipa" selain stdin, stdout, stderr

12

Saat menghubungkan ke host dengan SSH, biasanya tiga "pipa" yang disediakan antara tuan rumah dan tamu, untuk stdin, stdout, dan stderr.

Apakah ada opsi baris perintah untuk membuat maju untuk deskriptor file tambahan ( 3dan seterusnya)?

Sebagai contoh, saya ingin melakukannya

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

yang akan mencetak 'test' ke deskriptor file yang dibuka secara lokal 10.

mic_e
sumber
2
Mungkin bukan tanpa suntingan sumber yang rumit, mengingat berbagai closefrom(STDERR_FILENO + 1)panggilan di bawah kode sumber OpenSSH. Apa yang Anda coba lakukan yang menuntut ini?
thrig
Protokol mendukung tunneling stream tambahan selain stdin/ out/ err, tetapi AFAIK, tidak ada server / klien yang menyediakan dukungan dengan cara apa pun fitur itu.
salva
@ thrig Bukan OP, dan ini sudah lama, tetapi jika Anda masih penasaran apa ini bisa berguna untuk, apa yang saya harapkan untuk menemukan di sini adalah petunjuk tentang cara pipa melalui ssh, skrip untuk bash dan stdin untuk skrip itu. Sesuatu yang mirip dengan:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL
@ thrig Tampak pada saya bahwa sesuatu seperti --forwardfdseharusnya bahkan tidak diperlukan. sshdapat memeriksa apa deskriptor file terbuka sebelum membuka hal lain, dan meneruskannya secara otomatis ke deskriptor file yang sama di sisi jarak jauh. Ini bisa sangat transparan seperti contoh saya. Saya bertanya-tanya betapa sulitnya untuk memperbaiki sshitu. Seperti yang Anda katakan, itu bisa rumit tergantung pada alasan di balik itu closefrom(STDERR_FILENO + 1).
JoL

Jawaban:

6

Anda dapat melakukan ini menggunakan penerusan soket, yang tersedia sejak openssh-6.7. Ini semacam pipa. Teknik ini dijelaskan misalnya di sini: http://www.25thandclement.com/~william/projects/streamlocal.html

Anda akan mendapatkan rute dua arah untuk data Anda. Ada contoh dengan mysql:

Koneksi klien MySQL proxy pada server jarak jauh ke instance lokal Anda:

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

Saya yakin itu harus mungkin. Saya hanya dapat menyarankan retas di mana Anda menggunakan koneksi ssh ekstra untuk masing-masing membawa sepasang deskriptor file lainnya. Misalnya bukti skrip konsep berikut melakukan ssh pertama untuk menjalankan perintah dummy (sleep) untuk menghubungkan fds lokal 5 dan 6 ke stdin dan stdout jarak jauh, dengan anggapan fds ini adalah yang ingin Anda tambahkan ke 0,1 biasa, 2.

Kemudian ssh asli dilakukan, dan pada remote itu menghubungkan remote fds 5 dan 6 ke stdin dan stdout dari ssh lainnya.

Sama seperti contoh, skrip ini meneruskan halaman manual yang di-gzip ke remote, yang membuka ritsleting dan menjalankannya melalui man. Stdin dan stdout dari ssh asli masih tersedia untuk hal-hal lain.

#!/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
meuh
sumber
1

Masalah dengan jawaban dari @jakuje adalah: ini hanya berfungsi dengan soket , tetapi Anda tidak dapat menggunakan alat UNIX standar yang mengharapkan file dengannya:

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

bash: /tmp/sock.remote: Tidak ada perangkat atau alamat tersebut

Juga ada masalah bahwa file soket lokal tidak dihapus pada host jarak jauh; ketika berikutnya Anda menjalankan perintah yang sama, Anda mendapatkan peringatan dan soket tidak dibuat ulang dengan benar. Anda dapat memberikan opsi -o StreamLocalBindUnlink=yesuntuk sshmemutuskan tautan soket lama itu, tetapi dalam pengujian saya itu tidak cukup; Anda juga harus mengedit sshd_configagar memuat StreamLocalBindUnlink=yesagar opsi itu berfungsi.

Tetapi Anda dapat menggunakan socatatau netcatatau alat serupa lainnya yang mendukung UNIX soket lokal ( netcat-traditionalyang tidak cukup!) Untuk menggunakan forwarding soket lokal untuk transfer file:

# 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'

Anda juga dapat menjalankan perintah interaktif, dalam hal ini Anda harus menggunakan ssh -tuntuk mengalokasikan TTYs.

Masalah dengan solusi ini adalah Anda harus membuat hard-path path dari UNIX local sockets: Secara lokal ini tidak terlalu menjadi masalah karena Anda dapat memasukkannya $$di path untuk membuatnya unik per proses atau pengguna direktori sementara, tetapi pada remote-end Anda lebih baik tidak menggunakan direktori yang bisa ditulis dunia /tmp/seperti yang saya lakukan dalam contoh saya. Direktori juga harus sudah ada saat sshsesi dimulai. Dan inode soket akan tetap ada bahkan setelah sesi ditutup, jadi menggunakan sesuatu seperti "$ HOME / .ssh. $$" akan mengacaukan direktori Anda dengan inode yang mati seiring waktu.

Anda juga dapat menggunakan soket TCP terikat localhost, yang akan menyelamatkan Anda dari mengacaukan sistem file Anda dengan inode mati, tetapi bahkan dengan mereka Anda masih harus masalah untuk memilih nomor port (unik) yang tidak digunakan. Jadi masih belum ideal. ( sshmemiliki kode untuk mengalokasikan port secara dinamis, tetapi saya tidak menemukan cara untuk mengambil informasi itu pada host jarak jauh.)

Mungkin solusi termudah untuk menyalin file adalah menggunakan fungsi berbagi koneksi built-in ssh dan melakukan scpatau sfrpperintah saat sesi interaktif Anda masih berjalan secara paralel. Lihat Menyalin file kembali ke sistem lokal dengan ssh .

pmhahn
sumber