Pourquoi les consoles sont-elles parfois suspendues pour toujours lorsque la connexion SSH est interrompue?

89

Je l'ai vu avec tant de consoles (sous Linux, Mac, ...) et avec beaucoup de machines différentes sur de nombreux réseaux. Je ne peux jamais identifier avec précision la raison, pourquoi cela se produit: tout ce que vous avez à faire est de vous connecter à une machine via SSH. Si la connexion est interrompue pour une raison quelconque (pour simplifier, supposons que le câble réseau ait été tiré), la console se bloque parfois pour toujours - à d'autres moments, elle se débrouille correctement jusqu'au shell parent.

C’est tellement agaçant que cela se produise (par exemple, vous perdez l’historique des commandes). Existe-t-il un raccourci clavier secret qui peut forcer une sortie (Ctrl-C ou Ctrl-D ne fonctionnent pas)? Et quelle est la raison de ce "bogue" aléatoire dans toutes les implémentations?

Chris Lercher
la source
Ce fil de discussion semble approprié de mentionner Mosh (Mobile Shell), qui gère bien les échecs de connexion, y compris l'itinérance (changement d'adresse IP) et d'autres éléments.
Ciprian Tomoiagă

Réponses:

138

Il existe un raccourci clavier "secret" pour forcer une sortie: ~) Dans la session gelée, appuyez sur les touches suivantes: Enter~.Le tilde (uniquement après une nouvelle ligne) est reconnu comme une séquence d'échappement par le client ssh, et le point indique au client de mettre fin à ses activités sans plus tarder.

Le comportement à long blocage sur les problèmes de communication n’est pas un bug, la session SSH traîne en espérant que l’autre côté reviendra. Si le réseau tombe en panne, vous pouvez parfois récupérer une session SSH parfois plusieurs jours plus tard. Bien sûr, vous pouvez spécifiquement lui dire d'abandonner et de mourir avec la séquence ci-dessus. Vous pouvez également effectuer diverses opérations, telles que la définition de délais de maintien de la vie dans votre client, de sorte que, s'il n'a pas de lien actif pendant un certain temps, il s'éteint tout seul, mais le comportement par défaut est le suivant: connecté que possible!

Edit: une autre application utile de cette clé d’interruption consiste à attirer l’attention du client ssh local et à l’arrière-plan pour revenir à votre shell local pendant une minute, afin d’obtenir un élément de votre historique, puis de le relier à un travail à distance. Enter~ Ctrl+ Zpour envoyer le client ssh à la file d'attente des travaux en arrière-plan de votre shell local, puis, fgcomme d'habitude, pour le récupérer.

Edit: lorsqu’il s’agit de sessions SSH imbriquées, vous pouvez ajouter plusieurs caractères tilde pour ne sortir que d’une des sessions SSH de la chaîne, tout en conservant les autres. Par exemple, si vous êtes imbriqué dans 3 niveaux (c.-à-d. Que ssh de local-> Machine1-> Machine2-> Machine3), Enter~.vous retournerez à votre session locale, Enter~~.vous laissera dans Machine1 et Enter~~~.vous laissera dans Machine2. . Cela fonctionne également pour d'autres séquences d'échappement, telles que le déplacement temporaire de la session ssh en arrière-plan. Ce qui précède fonctionne pour n'importe quel niveau d'imbrication, en ajoutant simplement plus de tilde.

Enfin, vous pouvez utiliser Enter~?pour imprimer un menu d'aide contenant les commandes d'échappement disponibles.

TL; DR - les commandes d'échappement prises en charge sont les séquences d'échappement prises en charge:

 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)
Caleb
la source
11
+1 pour connaître le mot de passe dodecatouple-secret-probation pour tirer sshd dans la tête. L'avez-vous découvert de la même manière que moi (erreur ~/.somethingorotherde frappe après avoir frappé entrer)?
voretaq7
2
@ voretaq7: Non, je n'étais pas si malin que ça, mais quand quelqu'un me l'a dit, je suis allé "Vraiment? Alors c'est ce qui se passait toutes les fois où ma coquille est tombée BANG! sans raison quand je tapais?" . Ce n'est pas une séquence courante, sauf dans les types erronés de celui que vous mentionnez, mais cela peut arriver.
Caleb
14
C'est pourquoi "secret" signifie "dans la page de manuel".
larsks
4
Bien que beaucoup de gens ne le sachent pas, c'est un secret à la vue. man sshcouvre cela sous la ESCAPE CHARACTERSsection. ~.(Disconnect) et ~^Z(background ssh) sont très pratiques.
Stefan Lasiewski
9
Bien sûr, il est dans la page de manuel :) J'ai utilisé le mot secret uniquement parce que l'OP l'a fait, et j'utilisais la langue dans les joues. Le problème avec cette fonctionnalité est que les gens ne savent pas où chercher, ils s'attendent à ce que des caractères de contrôle et de tels signaux fassent partie du shell ou autres. Une fois que vous savez où chercher ou même quoi demander, c'est bien sûr là.
Caleb
12

SSH offre une facilité de maintien en vie. Ajoutez ce qui suit à votre section locale ~/.ssh/config(créez-la si elle n’existe pas):

ServerAliveInterval 15
ServerAliveCount 3

Ce paramètre établit un signal persistant envoyé toutes les 15 secondes via le tunnel sécurisé. Après trois échecs consécutifs, le client SSH se ferme.

Notez que sur certains systèmes (y compris macOS 10.14), il doit être remplacé par:

ServerAliveInterval 15
ServerAliveCountMax 3

Tiré de cette réponse sur ask.ubuntu: https://askubuntu.com/a/29967/30266

krlmlr
la source
9

Le fait qu'il se bloque est une fonction de TCP, pas de SSH. L’application n’a aucun moyen de savoir que la session / connexion TCP a été interrompue, à moins que TCP n’indique à l’application qui utilise la connexion que la connexion n’existe plus. Du point de vue de chaque hôte, la session TCP est toujours à l'état Etabli et rien ne permet de dire qu'une session inactive longue (sans flux de données) n'est pas valide, à l'exception d'un RST ou d'un manque de réponse à un paquet keepalive TCP (qui n'est pas universellement implémenté). Cela ne semble pas être un bug dans SSH pour moi, je m'attendrais à ce comportement.

joeqwerty
la source
5

Si la connexion est correctement interrompue, aucune frappe magique ne sera transmise, car la connexion est déjà suspendue avant que vous ne lanciez les touches. Vous pouvez dire au client de se terminer mais cela n'affectera pas l'historique conservé (ou non) du côté du serveur.

Bien que cela ne réponde pas réellement à la question, cela peut aider à réduire les effets d'un blocage de connexion: lorsque je travaille à distance (et même généralement lorsque je ne le suis pas), je parcours screen(avec ou sans le byobuwrapper en fonction de sa disponibilité). de sorte que, s’il existe une sorte de connexion, ma session, avec tout son historique, est conservée et disponible dans l’état que j’ai laissé lors de la reconnexion.

David Spillett
la source
6
Votre suggestion concernant l’écran convient, mais le premier élément ne s’applique pas à la question. Vous n'avez pas besoin de passer les clés du côté distant, il vous suffit de les faire parvenir au client ssh LOCAL! L'OP veut retrouver son shell local, y compris son histoire. SSH le prend en charge et ne répond pas aux séquences d'interruption normales telles que CTRL-C car il les transmet. Il existe un moyen de passer et de mettre fin au client local, voir ma réponse. De toute façon, l’historique local est généralement conservé si vous vous reconnectez, en fonction de la configuration du shell.
Caleb
2
@Caleb: la question mentionnait spécifiquement la perte de l'historique et l'historique des commandes est stocké côté serveur. Pour demander au serveur de faire quelque chose de différent avec l'historique, vous devez lui envoyer un message lui indiquant de faire quelque chose de différent avec l'historique. Bien sûr, il y a moyen de faire en sorte que bash (et quelques autres coquilles) enregistre immédiatement les lignes de l'historique plutôt que de les collecter dans la RAM jusqu'à ce que l'utilisateur existe correctement dans le shell avec exit/ logoutqui résoudrait le problème de l'historique sans utiliser screen.
David Spillett