SSH: Fournir des fds «pipe» supplémentaires en plus de stdin, stdout, stderr

12

Lors de la connexion à un hôte avec SSH, généralement trois « tubes » sont prévus entre l' hôte et l' invité, pour stdin, stdoutet stderr.

Existe-t-il une option de ligne de commande pour créer des transferts pour des descripteurs de fichiers supplémentaires ( 3et suivants)?

Par exemple, j'aimerais faire

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

qui imprimerait 'test' dans le descripteur de fichier ouvert localement 10.

mic_e
la source
2
Probablement pas sans modifications source difficiles, étant donné les différents closefrom(STDERR_FILENO + 1)appels sous le code source OpenSSH. Qu'essayez-vous de faire qui exige cela?
thrig
Le protocole prend en charge la tunnellisation de flux supplémentaires en plus de stdin/ out/ err, mais AFAIK, aucun serveur / client ne prend en charge de quelque manière que ce soit cette fonctionnalité.
salva
@thrig Not OP, et cela fait longtemps, mais au cas où vous seriez toujours curieux de savoir à quoi cela pourrait être utile, ce que j'espérais trouver ici était un indice sur la façon de diriger via ssh, un script pour bash et le stdin pour ce script. Quelque chose qui ressemble à:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL
@thrig Il me semble que quelque chose comme ça --forwardfdne devrait même pas être nécessaire. sshpourrait vérifier quels sont les descripteurs de fichiers ouverts avant d'ouvrir toute autre chose, et les transmettre automatiquement aux mêmes descripteurs de fichiers sur le côté distant. Cela pourrait être totalement transparent comme mon exemple. Je me demande combien il serait difficile de corriger sshcela. Comme vous l'avez dit, cela pourrait être délicat en fonction des raisons derrière cela closefrom(STDERR_FILENO + 1).
JoL

Réponses:

6

Vous pouvez le faire en utilisant le transfert de socket, disponible depuis openssh-6.7. C'est une sorte de pipe. Cette technique est décrite par exemple ici: http://www.25thandclement.com/~william/projects/streamlocal.html

Vous obtiendrez un itinéraire bidirectionnel pour vos données. Il y a un exemple avec mysql:

Connexions du client MySQL proxy sur un serveur distant à votre instance locale:

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

Je suis sûr que cela devrait être possible. Je ne peux que suggérer un hack où vous utilisez des connexions ssh supplémentaires pour chacune transporter une autre paire de descripteurs de fichiers. Par exemple, le script de preuve de concept suivant effectue un premier ssh pour exécuter une commande fictive (veille) pour connecter les fds locaux 5 et 6 aux stdin et stdout distants, en supposant que ces fds sont ceux que vous souhaitez ajouter au 0,1 habituel, 2.

Ensuite, le vrai ssh est terminé, et sur la télécommande, il connecte les fds distants 5 et 6 à la stdin et à la sortie standard de l'autre ssh.

À titre d'exemple, ce script transmet une page de manuel compressée à la télécommande, qui la décompresse et la fait passer par man. Le stdin et le stdout du vrai ssh sont toujours disponibles pour d'autres choses.

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

Le problème avec la réponse de @jakuje est: cela ne fonctionne qu'avec les sockets , mais vous ne pouvez pas utiliser d'outils UNIX standard qui attendent des fichiers avec eux:

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

bash: /tmp/sock.remote: aucun périphérique ou adresse de ce type

Il y a aussi le problème que le fichier de socket local n'est pas supprimé sur l'hôte distant; la prochaine fois que vous exécutez la même commande, vous obtenez un avertissement et le socket n'est pas recréé correctement. Vous pouvez donner la possibilité -o StreamLocalBindUnlink=yesde sshdissocier cette ancienne socket, mais dans mes tests, ce n'était pas suffisant; vous devez également vous modifier sshd_configpour contenir StreamLocalBindUnlink=yespour que cette option fonctionne.

Mais vous pouvez utiliser socatou netcatou tout autre outil similaire prenant en charge les sockets locaux UNIX (ce netcat-traditionaln'est PAS suffisant!) Pour utiliser le transfert de socket local pour le transfert de fichiers:

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

Vous pouvez également exécuter des commandes interactives, auquel cas vous devez utiliser ssh -tpour allouer des ATS.

Le problème avec cette solution est que vous devez coder en dur les chemins des sockets locaux UNIX: localement, ce n'est pas vraiment un problème que vous pouvez inclure $$dans le chemin pour le rendre unique par processus ou utilisateur un répertoire temporaire, mais sur le à distance, il vaut mieux ne pas utiliser le répertoire accessible en écriture /tmp/comme je le fais dans mon exemple. Le répertoire doit également déjà exister au démarrage de la sshsession. Et l'inode de socket restera même après la fermeture de la session, donc utiliser quelque chose comme "$ HOME / .ssh. $$" encombrera votre répertoire avec des inodes morts au fil du temps.

Vous pouvez également utiliser des sockets TCP liés à localhost, ce qui vous évitera d'encombrer vos systèmes de fichiers avec des inodes morts, mais même avec eux, vous avez toujours du mal à choisir un numéro de port inutilisé (unique). Donc toujours pas idéal. ( ssha du code pour allouer dynamiquement les ports, mais je n'ai trouvé aucun moyen de récupérer ces informations sur l'hôte distant.)

La solution la plus simple pour copier des fichiers consiste probablement à utiliser la fonctionnalité de partage de connexion intégrée de ssh et à exécuter une commande scpor sfrppendant que votre session interactive s'exécute toujours en parallèle. Voir Copier un fichier sur le système local avec ssh .

pmhahn
la source