SSH: Stdin, stdout, stderr'e ek olarak ek "boru" diskleri sağlayın


12

SSH ile bir ana bilgisayara bağlarken, genellikle üç "boru" için, ev sahibi ve konuk arasında sağlanır stdin, stdoutve stderr.

Ek dosya tanımlayıcıları ( 3ve daha sonraki) için ileriye doğru oluşturmak için bir komut satırı seçeneği var mı ?

Örneğin, yapmak istiyorum

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

yerel olarak açılan dosya tanımlayıcısına (10) 'test' yazdıracaktır.


2
Muhtemelen zor kaynak düzenlemeleri olmadan değil closefrom(STDERR_FILENO + 1), OpenSSH kaynak kodu altındaki çeşitli çağrılar göz önüne alındığında . Bunu talep eden ne yapmaya çalışıyorsunuz?
59

Protokol, stdin/ out/ dışında ek akışların tünellenmesini destekler err, ancak AFAIK, hiçbir sunucu / istemci bu özellikte hiçbir şekilde destek sağlamaz.
salva

@thrig OP değil ve uzun zaman oldu, ama bunun ne için yararlı olabileceğini hala merak ediyorsanız, burada bulmayı umduğum şey ssh ile nasıl boru yapılacağı hakkında bir ipucu, bash için bir senaryo ve bu senaryo için stdin. infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
Benzer bir

@thrig Benim gibi bir şeye --forwardfdbile ihtiyaç duyulmaması gerekiyor. sshbaşka bir şeyi açmadan önce açık dosya tanımlayıcılarının ne olduğunu kontrol edebilir ve bunları uzak taraftaki aynı dosya tanımlayıcılarına otomatik olarak iletebilir. Örneğim gibi tamamen şeffaf olabilir. Bunun için yama yapmanın ne kadar zor olacağını merak ediyorum ssh. Söylediğiniz gibi, bunların arkasındaki nedenlere bağlı olarak zor olabilir closefrom(STDERR_FILENO + 1).
JoL

Yanıtlar:


6

Bunu, openssh-6.7'den beri kullanılabilen soket yönlendirmeyi kullanarak yapabilirsiniz. Bu bir çeşit boru. Bu teknik örneğin burada açıklanmıştır: http://www.25thandclement.com/~william/projects/streamlocal.html

Verileriniz için iki yönlü rota kazanacaksınız. Mysql ile bir örnek var:

Uzak sunucudaki yerel örneğinizle Proxy MySQL istemci bağlantıları:

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

1

Eminim mümkün olmalı. Ben sadece başka bir çift dosya tanımlayıcı taşımak için ekstra ssh bağlantıları kullandığınız bir kesmek önerebilir. Örneğin, aşağıdaki kavram betiği kanıtı, yerel fds 5 ve 6'yı uzak stdin ve stdout'a bağlamak için bir kukla komut (uyku) çalıştırmak için bir ilk ssh yapar, bu fds'nin her zamanki 0,1'e eklemek istediğiniz varsayımlardır, 2.

Daha sonra gerçek ssh yapılır ve uzaktan kumandada uzak fds 5 ve 6'yı diğer ssh'ın stdin ve stdout'una bağlar.

Örnek olarak, bu komut dosyası gzip ile sıkıştırılmış bir adam sayfasını uzaktan kumandaya geçirir, bu sayfa onu açar ve insanın içinden geçirir. Gerçek ssh'ın stdin ve stdout hala diğer şeyler için kullanılabilir.

#!/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'nin cevabı ile ilgili sorun: sadece soketlerle çalışıyor , ancak onlarla dosya bekleyen standart UNIX araçlarını kullanamazsınız :

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

bash: /tmp/sock.remote: Böyle bir cihaz veya adres yok

Ayrıca, yerel yuva dosyasının uzak ana bilgisayarda silinmemesi sorunu da vardır; bir sonraki aynı komutu çalıştırdığınızda bir uyarı alırsınız ve soket doğru şekilde yeniden oluşturulmaz. Sen seçeneği verebilir -o StreamLocalBindUnlink=yesüzere ssho eski soket bağlantısını kaldırmak için, ama benim testlerde yeterli değildi; bu seçeneğin çalışması için sizi sshd_configiçerecek şekilde düzenlemeniz gerekir StreamLocalBindUnlink=yes.

Ama kullanabilir socatveya netcatveya destekleyici diğer benzer alet UNIX yerel soket ( netcat-traditionalolduğunu DEĞİL yeterince!) Dosyası transferi için yerel soket yönlendirmesini kullanmak:

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

Etkileşimli komutlar da çalıştırabilirsiniz, bu durumda ssh -tTTY'leri ayırmak için kullanmalısınız.

Bu çözümdeki sorun, UNIX yerel soketlerinin yollarını sabit olarak kodlamanız gerektiğidir: Yerel olarak $$, işlem veya kullanıcı başına geçici bir dizin yapmak için yola dahil edebileceğiniz kadar çok sorun değil, remote-end daha iyi /tmp/benim örnekte yaptığım gibi dünya tarafından yazılabilir dizin kullanmayın . Dizin, sshoturum başlatıldığında zaten var olmalıdır . Ve soket inode, oturum kapatıldıktan sonra bile kalır, bu nedenle "$ HOME / .ssh. $$" gibi bir şey kullanıldığında, dizininiz zaman içinde ölü inode ile karışır.

Ayrıca, bağlanmış TCP soketlerini de kullanabilirsiniz localhost, bu da dosya sistemlerinizi ölü inotlarla karıştırmanızı önler, ancak onlarla birlikte bile (benzersiz) kullanılmayan bir bağlantı noktası numarası seçmeniz gerekir. Yani hala ideal değil. ( sshbağlantı noktalarını dinamik olarak ayırmak için kodu var, ancak uzak ana bilgisayarda bu bilgileri almanın bir yolunu bulamadım.)

Muhtemelen dosyaları kopyalamanın en kolay çözümü, ssh'ın yerleşik bağlantı paylaşım işlevini kullanmak ve etkileşimli oturumunuz paralel olarak çalışırken bir scpveya sfrpkomut yapmaktır . Bkz. Bir dosyayı ssh ile yerel sisteme geri kopyalama .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.