SSH: Zapewnij dodatkowe „rury” FDS oprócz stdin, stdout, stderr

12

W przypadku podłączenia do komputera o SSH, zwykle trzy „rury” są między gościem a gospodarzem, dla stdin, stdouti stderr.

Czy jest dostępna opcja wiersza polecenia do tworzenia dalej dla dodatkowych deskryptorów plików ( 3i kolejnych )?

Na przykład chciałbym to zrobić

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

który wypisuje „test” na lokalnie otwieranym deskryptorze pliku 10.

mic_e
źródło
2
Prawdopodobnie nie bez skomplikowanych edycji kodu źródłowego, biorąc pod uwagę różne closefrom(STDERR_FILENO + 1)wywołania w kodzie źródłowym OpenSSH. Czego chcesz to zrobić?
thrig
Protokół obsługuje tunelowanie dodatkowych strumieni oprócz stdin/ out/ err, ale AFAIK, żaden serwer / klient nie zapewnia wsparcia w żaden sposób tej funkcji.
salva
@thrig Not OP, a minęło sporo czasu, ale jeśli nadal jesteś ciekawy, do czego to może być przydatne, miałem nadzieję znaleźć tutaj wskazówkę, jak przepuścić ssh, skrypt do bash i standardowe dla tego skryptu. Coś podobnego do:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL
@ thrig Przyszło mi do głowy, że coś takiego --forwardfdnie powinno być nawet potrzebne. sshmoże sprawdzić, jakie są otwarte deskryptory plików przed otwarciem jakiejkolwiek innej rzeczy, i przesłać je automatycznie do tych samych deskryptorów plików po stronie zdalnej. Może być całkowicie przejrzysty, jak mój przykład. Zastanawiam się, jak trudno byłoby to załatać ssh. Jak powiedziałeś, może to być trudne w zależności od przyczyn closefrom(STDERR_FILENO + 1).
JoL

Odpowiedzi:

6

Możesz to zrobić za pomocą funkcji przekazywania gniazd, która jest dostępna od openssh-6.7. To jest jakaś fajka. Technikę tę opisano na przykład tutaj: http://www.25thandclement.com/~william/projects/streamlocal.html

Otrzymasz dwukierunkową trasę dla swoich danych. Jest przykład z mysql:

Połączenia klienta proxy MySQL na zdalnym serwerze z lokalną instancją:

ssh -R/var/run/mysql.sock:/var/run/mysql.sock \
    -R127.0.0.1:3306:/var/run/mysql.sock somehost 
Jakuje
źródło
1

Jestem pewien, że to powinno być możliwe. Mogę tylko zasugerować włamanie, w którym używasz dodatkowych połączeń ssh, aby każde zawierało kolejną parę deskryptorów plików. Np. Następujący skrypt sprawdzający koncepcję wykonuje pierwsze ssh, aby uruchomić fałszywe polecenie (uśpienie) w celu podłączenia lokalnych FDS 5 i 6 do zdalnych stdin i stdout, zakładając, że te fds są tymi, które chcesz dodać do zwykłego 0,1, 2)

Następnie wykonywany jest prawdziwy ssh, a na pilocie łączy zdalne fds 5 i 6 ze stdin i stdout drugiego ssh.

Przykładowo, ten skrypt przekazuje stronę podręcznika gzip do pilota, który rozpakowuje go i uruchamia przez człowieka. Stdin i stdout prawdziwego ssh są nadal dostępne dla innych rzeczy.

#!/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
źródło
1

Problem z odpowiedzią @jakuje jest taki: działa tylko z gniazdami , ale nie można używać standardowych narzędzi UNIX oczekujących plików :

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

bash: /tmp/sock.remote: Brak takiego urządzenia lub adresu

Istnieje również problem polegający na tym, że plik lokalnego gniazda nie jest usuwany na zdalnym hoście; po następnym uruchomieniu tego samego polecenia pojawi się ostrzeżenie, a gniazdo nie zostanie poprawnie utworzone ponownie. Można dać opcję -o StreamLocalBindUnlink=yes, aby sshsię rozłączyć to stare gniazdo, ale w moich testów nie było na tyle; musisz również edytować cię, sshd_configaby zawierał StreamLocalBindUnlink=yestę opcję, aby zadziałała.

Ale możesz użyć socatlub netcatdowolnego innego podobnego narzędzia obsługującego lokalne gniazda UNIX ( netcat-traditionalto NIE wystarczy!), Aby użyć lokalnego przekazywania gniazd do przesyłania plików:

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

Możesz także uruchamiać interaktywne polecenia, w takim przypadku należy użyć ssh -tdo przydzielenia TTY.

Problem z tym rozwiązaniem polega na tym, że musisz na stałe zakodować ścieżki lokalnych gniazd systemu UNIX: lokalnie nie jest to tak duży problem, jak można uwzględnić $$w ścieżce, aby był unikalny dla procesu lub użytkownika jako katalog tymczasowy, ale w katalogu Zdalnie, lepiej nie używaj katalogu do zapisu na świecie, /tmp/jak w moim przykładzie. Katalog musi już istnieć podczas sshuruchamiania sesji. A i-węzeł gniazda pozostanie nawet po zamknięciu sesji, więc użycie czegoś takiego jak „$ HOME / .ssh. $$” zaśmieci twój katalog martwymi i-węzłami z czasem.

Możesz także użyć połączonych gniazd TCP localhost, co pozwoli ci uniknąć bałagania systemów plików martwymi i-węzłami, ale nawet przy nich nadal będziesz miał problem z wyborem (unikalnego) nieużywanego numeru portu. Więc nadal nie jest idealny. ( sshma kod do dynamicznego przydzielania portów, ale nie znalazłem sposobu na odzyskanie tych informacji na zdalnym hoście).

Prawdopodobnie najłatwiejszym rozwiązaniem do skopiowania plików jest skorzystanie z wbudowanej funkcji udostępniania połączenia ssh i wykonanie polecenia scplub sfrppodczas, gdy sesja interaktywna jest nadal uruchomiona równolegle. Zobacz Skopiuj plik z powrotem do systemu lokalnego za pomocą ssh .

pmhahn
źródło