SSH: Geben Sie zusätzlich zu stdin, stdout, stderr zusätzliche "Pipe" -Fds an

12

Bei Anschluss an einen Host mit SSH verbinden, in der Regel drei „Rohre“ sind zwischen Wirt und Gast zur Verfügung gestellt, für stdin, stdout, und stderr.

Gibt es eine Befehlszeilenoption, um 3Weiterleitungen für zusätzliche Dateideskriptoren ( und höher) zu erstellen ?

Zum Beispiel würde ich gerne tun

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

Dies würde "test" auf den lokal geöffneten Dateideskriptor 10 ausgeben.

Mäuse
quelle
2
Wahrscheinlich nicht ohne schwierige Änderungen an der Quelle, angesichts der verschiedenen closefrom(STDERR_FILENO + 1)Aufrufe unter dem OpenSSH-Quellcode. Was versuchst du zu tun, das dies verlangt?
Am
Das Protokoll unterstützt das Tunneln zusätzlicher Streams neben stdin/ out/ err, aber AFAIK, kein Server / Client bietet in irgendeiner Weise Unterstützung für diese Funktion.
Salva
@thrig Nicht OP, und es ist lange her, aber für den Fall, dass Sie immer noch neugierig sind, wozu dies nützlich sein könnte, hatte ich gehofft, hier einen Hinweis darauf zu finden, wie man durch ssh pfeift, ein Skript für bash und das Standard für dieses Skript. Etwas Ähnliches wie:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL
@thrig Mir fällt ein, dass sowas --forwardfdgar nicht gebraucht werden sollte. sshÜberprüfen Sie die geöffneten Dateideskriptoren, bevor Sie eine andere Funktion öffnen, und leiten Sie sie automatisch an dieselben Dateideskriptoren auf der Remote-Seite weiter. Es könnte völlig transparent sein wie in meinem Beispiel. Ich frage mich, wie schwierig es wäre, dafür zu flicken ssh. Wie Sie sagten, könnte es schwierig sein, abhängig von den Gründen, die dahinter stecken closefrom(STDERR_FILENO + 1).
JoL

Antworten:

6

Dazu können Sie die Socket-Weiterleitung verwenden, die seit openssh-6.7 verfügbar ist. Das ist eine Art Pfeife. Diese Technik wird zum Beispiel hier beschrieben: http://www.25thandclement.com/~william/projects/streamlocal.html

Sie erhalten eine Route in zwei Richtungen für Ihre Daten. Es gibt ein Beispiel mit MySQL:

Proxy MySQL-Client-Verbindungen auf einem Remote-Server zu Ihrer lokalen Instanz:

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

Ich bin mir sicher, dass es möglich sein sollte. Ich kann nur einen Hack vorschlagen, bei dem Sie zusätzliche ssh-Verbindungen verwenden, um jeweils ein weiteres Paar von Dateideskriptoren zu übertragen. Beispiel: Das folgende Proof-of-Concept-Skript führt zunächst einen Dummy-Befehl (sleep) aus, um die lokalen fds 5 und 6 mit dem fernen stdin und stdout zu verbinden. Vorausgesetzt, Sie möchten diese fds zu den üblichen 0,1-fds hinzufügen. 2.

Dann ist der eigentliche SSH fertig, und auf der Fernbedienung werden die fds 5 und 6 mit dem Standard und dem Standard des anderen SSH verbunden.

Nur als Beispiel übergibt dieses Skript eine gzippte Manpage an die Fernbedienung, die die Manpage entpackt und durchläuft. Der Standard und der Standard des echten SSH sind noch für andere Dinge verfügbar.

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

Das Problem mit der Antwort von @jakuje ist: Es funktioniert nur mit Sockets , aber Sie können keine Standard-UNIX-Tools verwenden, die Dateien mit ihnen erwarten :

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

bash: /tmp/sock.remote: Kein solches Gerät oder keine solche Adresse

Außerdem besteht das Problem, dass die lokale Socket-Datei auf dem Remote-Host nicht gelöscht wird. Wenn Sie das nächste Mal denselben Befehl ausführen, wird eine Warnung angezeigt und der Socket wird nicht ordnungsgemäß neu erstellt. Sie können die Option -o StreamLocalBindUnlink=yeszum sshTrennen dieser alten Socket geben, aber in meinen Tests war es nicht genug; Sie müssen Sie auch bearbeiten, um sshd_configzu enthalten, StreamLocalBindUnlink=yesdamit diese Option funktioniert.

Aber können Sie verwenden , socatoder netcatoder ein anderes ähnliches Werkzeug unterstützt UNIX lokale Steckdosen ( netcat-traditionalist nicht genug!) , Um die lokale Socket - Weiterleitung für die Dateiübertragung zu verwenden:

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

Sie können auch interaktive Befehle ausführen. In diesem Fall sollten Sie ssh -tTTYs zuweisen.

Das Problem bei dieser Lösung ist, dass Sie die Pfade der lokalen UNIX-Sockets fest codieren müssen: Lokal ist dies kein so großes Problem, wie Sie es $$in den Pfad aufnehmen können, um ihn pro Prozess oder Benutzer als temporäres Verzeichnis eindeutig zu machen, sondern auf der Remote-End verwenden Sie besser nicht das von der Welt beschreibbare Verzeichnis /tmp/wie in meinem Beispiel. Das Verzeichnis muss auch bereits beim sshStart der Sitzung vorhanden sein. Und die Socket-Inode bleibt auch nach dem Schließen der Sitzung erhalten. Wenn Sie also so etwas wie "$ HOME / .ssh. $$" verwenden, wird Ihr Verzeichnis im Lauf der Zeit mit toten Inodes überfüllt.

Sie können auch TCP-Sockets verwenden, an localhostdie Sie gebunden sind, um zu verhindern , dass Ihre Dateisysteme mit toten Inodes überfrachtet werden. Trotzdem müssen Sie immer noch Probleme haben, eine (eindeutige) nicht verwendete Portnummer zu wählen. Also immer noch nicht ideal. ( sshHat Code zum dynamischen Zuweisen von Ports, aber ich habe keine Möglichkeit gefunden, diese Informationen auf dem Remote-Host abzurufen.)

Die wahrscheinlich einfachste Lösung zum Kopieren von Dateien besteht darin, die integrierte Verbindungsfreigabefunktion von ssh zu verwenden und einen scpoder sfrp-Befehl auszuführen, während Ihre interaktive Sitzung noch parallel ausgeführt wird. Siehe Eine Datei mit ssh zurück auf das lokale System kopieren .

pmhahn
quelle