¿Por qué las consolas a veces se cuelgan para siempre cuando se corta la conexión SSH?

89

He visto esto con tantas consolas (en Linux, Mac, ...) y con muchas máquinas diferentes en muchas redes diferentes. Nunca puedo precisar la razón exacta, por qué sucede esto: todo lo que tiene que hacer es iniciar sesión en una máquina a través de SSH. Si la conexión se interrumpe por alguna razón (por simplicidad, digamos que el cable de red fue desconectado), a veces la consola simplemente se cuelga para siempre; en otras ocasiones, simplemente sale bien al shell principal.

Es muy molesto cuando esto sucede (por ejemplo, pierde el historial de comandos). ¿Existe quizás un atajo de teclado secreto que pueda forzar una salida (Ctrl-C o Ctrl-D no funcionan)? ¿Y cuál es la razón de este "error" aleatorio en todas las implementaciones de todos modos?

Chris Lercher
fuente
Este hilo parece apropiado para mencionar Mosh (Mobile Shell) que trata bien con fallas de conexión, incluyendo roaming (cambio de IP) y otras cosas.
Ciprian Tomoiagă

Respuestas:

138

Hay un atajo de teclado "secreto" para forzar una salida: ~) Desde la sesión congelada, presione estas teclas en orden: Enter~.el cliente ssh reconoce la tilde (solo después de una nueva línea) como una secuencia de escape, y el período indica cliente para terminar su negocio sin más preámbulos.

El comportamiento de suspensión prolongada en los problemas de comunicación no es un error, la sesión SSH se cuelga esperando que el otro lado regrese. Si la red se rompe, a veces, incluso días después, puede recuperar una sesión SSH. Por supuesto, puedes decirle específicamente que se rinda y muera con la secuencia anterior. También hay varias cosas que puede hacer, como establecer tiempos de espera para mantener vivo en su cliente, de modo que si no tiene un enlace activo durante un cierto período de tiempo, se apaga solo, pero el comportamiento predeterminado es permanecer como conectado como sea posible!

Editar: Otra aplicación útil de esta tecla de interrupción es llamar la atención del cliente ssh local y ponerlo en segundo plano para que vuelva a su shell local por un minuto —diga obtener algo de su historial— y luego póngalo a tierra para seguir trabajando de forma remota. Enter~ Ctrl+ Zpara enviar el cliente ssh a la cola de trabajos en segundo plano de su shell local, y luego, fgcomo es normal, recuperarlo.

Editar: cuando se trata de sesiones SSH anidadas, puede agregar varios caracteres tilde para salir solo de una de las sesiones SSH en la cadena, pero conservar las demás. Por ejemplo, si está anidado en 3 niveles (es decir, ssh desde local-> Machine1-> Machine2-> Machine3), lo Enter~.llevará de regreso a su sesión local, Enter~~.lo dejará en Machine1 y Enter~~~.lo dejará en Machine2 . Esto también funciona para otras secuencias de escape, como mover la sesión ssh a segundo plano temporalmente. Lo anterior funciona para cualquier nivel de anidamiento, simplemente agregando más tilde.

Finalmente, puede usar Enter~?para imprimir un menú de ayuda de los comandos de escape disponibles.

TL; DR: los comandos de escape admitidos son secuencias de escape admitidas:

 ~.   - 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
fuente
11
+1 por conocer la contraseña de prueba de secreto de dodecatouple para disparar sshd en la cabeza. ¿Lo descubriste de la misma manera que yo (escribiendo mal ~/.somethingorotherdespués de presionar enter)?
voretaq7
2
@ voretaq7: No, yo no era tan inteligente, pero cuando alguien me dio una pista me dije "¿En serio? ¿Entonces eso es lo que estaba sucediendo todas esas veces que mi caparazón se BANG! ¿Sin ninguna razón cuando estaba escribiendo?" . No es una secuencia común, excepto en los tipos incorrectos de la que mencionas, pero puede suceder.
Caleb
14
Por "secreto" quiere decir "en la página del manual".
larsks
44
Si bien muchas personas no saben sobre esto, es realmente un secreto a la vista. man sshcubre esto en la ESCAPE CHARACTERSsección. ~.(Desconectar) y ~^Z(ssh de fondo) son muy útiles.
Stefan Lasiewski
99
Por supuesto, está en la página de manual :) Solo usé la palabra secreto porque lo hizo el OP, y estaba usando la lengua en la mejilla. El problema con esta característica es que las personas no saben dónde buscarla, esperan que los caracteres de control y tales señales sean parte del shell o tal. Una vez que sepa dónde buscar o incluso qué preguntar, por supuesto, está allí.
Caleb
12

SSH ofrece una instalación para mantenerse con vida. Agregue lo siguiente a su local ~/.ssh/config(cree si no existe):

ServerAliveInterval 15
ServerAliveCount 3

Esta configuración establecerá una señal de mantenimiento de vida enviada cada 15 segundos a través del túnel seguro. Después de tres fallas consecutivas, el cliente SSH saldrá.

Tenga en cuenta que, en algunos sistemas (incluido macOS 10.14), debe ser:

ServerAliveInterval 15
ServerAliveCountMax 3

Tomado de esta respuesta en ask.ubuntu: https://askubuntu.com/a/29967/30266

krlmlr
fuente
9

El hecho de que se cuelgue es una función de TCP, no de SSH. La aplicación no tiene forma de saber que la sesión / conexión TCP se ha cortado a menos que TCP informe a la aplicación utilizando la conexión que la conexión ya no existe. Desde la perspectiva de cada host, la sesión TCP todavía está en el estado establecido y no hay nada que decir que una sesión inactiva larga (sin flujo de datos) no es válida más que un RST o la falta de respuesta a un paquete TCP keepalive (que no está implementado universalmente). Eso no parece ser un error en SSH para mí, esperaría ese comportamiento.

joeqwerty
fuente
5

Si la conexión se cuelga correctamente, no se podrá presionar ninguna tecla mágica ya que la conexión ya está colgada antes de presionar las teclas. Puede decirle al cliente que termine, pero esto no afectará el historial mantenido (o no) en el extremo del servidor.

Si bien esto en realidad no responde la pregunta, puede ayudar a reducir los efectos de un bloqueo de conexión: cuando estoy trabajando de forma remota (e incluso cuando no lo estoy) me encuentro con screen(con o sin el byobucontenedor dependiendo de su disponibilidad) de modo que si hay algún tipo de conexión, mi sesión, con todo su historial, se conserva y está disponible en el estado en que la dejé cuando me reconecte.

David Spillett
fuente
66
Su sugerencia sobre la pantalla está bien, pero el primer bit en realidad no es aplicable al problema. No necesita pasar las llaves al lado remoto, ¡solo tiene que pasarlas al cliente ssh LOCAL! El OP quiere recuperar su caparazón local, incluida la historia. SSH lo toma y no responde a las secuencias de interrupción normales como CTRL-C porque las transmite. Hay una manera de llegar y terminar el cliente local, vea mi respuesta. El historial en el extremo local generalmente se mantiene de todos modos si inicia sesión nuevamente, dependiendo de la configuración del shell.
Caleb
2
@Caleb: la pregunta menciona específicamente la pérdida de historial, y el historial de comandos se almacena en el lado del servidor. Para decirle al servidor que haga algo diferente con el historial, debe enviar un mensaje al servidor para indicarle que haga algo diferente con el historial. Por supuesto, hay formas de hacer que bash (y algunos otros shells) graben las líneas del historial inmediatamente en lugar de recopilarlas en la RAM hasta que el usuario exista correctamente el shell con exit/ logoutque resolvería el problema del historial sin usarlo screen.
David Spillett