Question (TL; DR)
Lors de l'attribution dynamique de ports pour le transfert à distance ( -R
option aka ), comment un script sur la machine distante (provenant par exemple de .bashrc
) peut-il déterminer quels ports ont été choisis par OpenSSH?
Contexte
J'utilise OpenSSH (aux deux extrémités) pour me connecter à notre serveur central, que je partage avec plusieurs autres utilisateurs. Pour ma session à distance (pour l'instant), je voudrais transmettre X, cups et pulseaudio.
Le plus trivial est le transfert de X, en utilisant l' -X
option. L'adresse X allouée est stockée dans la variable d'environnement DISPLAY
et à partir de là, je peux déterminer le port TCP correspondant, dans la plupart des cas de toute façon. Mais je n'en ai presque jamais besoin, car Xlib fait honneur DISPLAY
.
J'ai besoin d'un mécanisme similaire pour les tasses et pulseaudio. Les bases pour les deux services existent, sous la forme des variables environnementales CUPS_SERVER
et PULSE_SERVER
, respectivement. Voici des exemples d'utilisation:
ssh -X -R12345:localhost:631 -R54321:localhost:4713 datserver
export CUPS_SERVER=localhost:12345
lowriter #and I can print using my local printer
lpr -P default -o Duplex=DuplexNoTumble minutes.pdf #printing through the tunnel
lpr -H localhost:631 -P default -o Duplex=DuplexNoTumble minutes.pdf #printing remotely
mpg123 mp3s/van_halen/jump.mp3 #annoy co-workers
PULSE_SERVER=localhost:54321 mpg123 mp3s/van_halen/jump.mp3 #listen to music through the tunnel
Le problème est réglé CUPS_SERVER
et PULSE_SERVER
correctement.
Nous utilisons beaucoup les transferts de ports et j'ai donc besoin d'allocations de ports dynamiques. Les allocations de ports statiques ne sont pas une option.
OpenSSH dispose d'un mécanisme d'allocation dynamique des ports sur le serveur distant, en spécifiant 0
comme port de liaison pour le transfert à distance (l' -R
option). En utilisant la commande suivante, OpenSSH allouera dynamiquement des ports pour les coupes et le transfert d'impulsions.
ssh -X -R0:localhost:631 -R0:localhost:4713 datserver
Lorsque j'utilise cette commande, ssh
imprimera ce qui suit pour STDERR
:
Allocated port 55710 for remote forward to 127.0.0.1:4713
Allocated port 41273 for remote forward to 127.0.0.1:631
Voilà les informations que je veux! Finalement, je veux générer:
export CUPS_SERVER=localhost:41273
export PULSE_SERVER=localhost:55710
Cependant, les messages "Port alloué ..." sont créés sur ma machine locale et envoyés à STDERR
, auxquels je ne peux pas accéder sur la machine distante. Curieusement, OpenSSH ne semble pas avoir les moyens de récupérer des informations sur les transferts de port.
Comment puis-je récupérer ces informations pour les mettre dans un script shell pour définir correctement CUPS_SERVER
et PULSE_SERVER
sur l'hôte distant?
Impasses
La seule chose facile que j'ai pu trouver était d'augmenter la verbosité du sshd
jusqu'à ce que ces informations puissent être lues dans les journaux. Ce n'est pas viable car ces informations révèlent beaucoup plus d'informations qu'il n'est raisonnable de rendre accessibles aux utilisateurs non root.
Je pensais à patcher OpenSSH pour prendre en charge une séquence d'échappement supplémentaire qui affiche une belle représentation de la structure interne permitted_opens
, mais même si c'est ce que je veux, je ne peux toujours pas accéder aux séquences d'échappement client depuis le côté serveur.
Il doit y avoir une meilleure façon
L'approche suivante semble très instable et se limite à une session SSH par utilisateur. Cependant, j'ai besoin d'au moins deux sessions simultanées et d'autres utilisateurs encore plus. Mais j'ai essayé ...
Lorsque les étoiles sont alignées correctement, après avoir sacrifié un poulet ou deux, je peux abuser du fait que ce sshd
n'est pas démarré en tant qu'utilisateur, mais abandonne les privilèges après une connexion réussie, pour ce faire:
obtenir une liste des numéros de port pour toutes les sockets d'écoute qui appartiennent à mon utilisateur
netstat -tlpen | grep ${UID} | sed -e 's/^.*:\([0-9]\+\) .*$/\1/'
obtenir une liste des numéros de port pour toutes les sockets d'écoute qui appartiennent aux processus démarrés par mon utilisateur
lsof -u ${UID} 2>/dev/null | grep LISTEN | sed -e 's/.*:\([0-9]\+\) (LISTEN).*$/\1/'
Tous les ports qui se trouvent dans le premier ensemble, mais pas dans le deuxième ensemble ont une forte probabilité d'être mes ports de transfert, et en effet de soustraire les rendements des ensembles
41273
,55710
et6010
; tasses, pouls et X, respectivement.6010
est identifié comme le port X utilisantDISPLAY
.41273
est le port des tasses, carlpstat -h localhost:41273 -a
retourne0
.55710
est le port d'impulsion, carpactl -s localhost:55710 stat
retourne0
. (Il imprime même le nom d'hôte de mon client!)
(Pour effectuer la soustraction définie sort -u
, enregistrer la sortie des lignes de commande ci-dessus et utiliser comm
pour effectuer la soustraction.)
Pulseaudio me permet d'identifier le client et, à toutes fins utiles, cela peut servir d'ancrage pour séparer les sessions SSH qui doivent être séparées. Cependant, je ne l' ai pas trouvé un moyen de lier 41273
, 55710
et 6010
au même sshd
processus. netstat
ne divulguera pas ces informations aux utilisateurs non root. Je reçois seulement un -
dans la PID/Program name
colonne où je voudrais lire 2339/54
(dans ce cas particulier). Si proche ...
netstat
vous ne verrez pas le PID pour les processus que vous ne possédez pas ou qui sont de l'espace noyau. Par exemple