Por que os consoles às vezes ficam suspensos para sempre quando a conexão SSH é interrompida?

89

Eu já vi isso com muitos consoles (no Linux, Mac, ...) e com muitas máquinas diferentes em muitas redes diferentes. Nunca consigo identificar exatamente o motivo, porque isso acontece: tudo o que você precisa fazer é fazer login em uma máquina via SSH. Se a conexão for interrompida por algum motivo (por uma questão de simplicidade, digamos que o cabo de rede foi puxado), às vezes o console trava para sempre - outras vezes, ele sai corretamente para o shell pai.

É tão irritante quando isso acontece (por exemplo, você perde o histórico de comandos.) Existe talvez um atalho de teclado secreto que possa forçar uma saída (Ctrl-C ou Ctrl-D não funcionam)? E qual é a razão para esse "bug" aleatório em todas as implementações, afinal?

Chris Lercher
fonte
Esse tópico parece apropriado para mencionar o Mosh (Mobile Shell), que lida bem com falhas de conexão, incluindo roaming (alteração de IP) e outras coisas.
Ciprian Tomoiagă 22/03

Respostas:

137

Há um atalho de teclado "secreto" para forçar uma saída: ~) Na sessão congelada, pressione estas teclas na ordem: Enter~.O til (somente após uma nova linha) é reconhecido como uma sequência de escape pelo cliente ssh, e o período informa o cliente para encerrar seus negócios sem mais delongas.

O comportamento de longo prazo em questões de comunicação não é um bug, a sessão SSH está esperando que o outro lado volte. Se a rede quebrar, às vezes até dias depois, você poderá recuperar uma sessão SSH. Claro que você pode dizer especificamente para desistir e morrer com a sequência acima. Também existem várias coisas que você pode fazer, como definir intervalos de manutenção em seu cliente para que, se ele não tiver um link ativo por um certo período de tempo, ele desligue por conta própria, mas o comportamento padrão seja permanecer conectado quanto possível!

Edit: Outra aplicação útil dessa chave de interrupção é chamar a atenção do cliente ssh local e colocá-lo em segundo plano para retornar ao shell local por um minuto - diga para obter algo do seu histórico - e force-o para continuar trabalhando remotamente. Enter~ Ctrl+ Zpara enviar o cliente ssh para a fila de trabalhos em segundo plano do shell local e fg, normalmente, para recuperá-lo.

Editar: ao lidar com sessões SSH aninhadas, você pode adicionar vários caracteres til para interromper apenas uma das sessões SSH da cadeia, mas manter as outras. Por exemplo, se você estiver aninhado em 3 níveis (por exemplo, você ssh de local-> Máquina1-> Máquina2-> Máquina3), Enter~.retornará à sua sessão local, Enter~~.o deixará na Máquina1 e Enter~~~.o deixará na Máquina2 . Isso também funciona para outras seqüências de escape, como mover temporariamente a sessão ssh para o segundo plano. O acima funciona para qualquer nível de aninhamento, adicionando apenas mais til.

Por fim, você pode usar Enter~?para imprimir um menu de ajuda dos comandos de escape disponíveis.

TL; DR - os comandos de escape suportados são Sequências de escape suportadas:

 ~.   - 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
fonte
11
+1 por saber a senha de detecção de casal com segredo secreto para fotografar sshd na cabeça. Você descobriu da mesma maneira que eu ( ~/.somethingorotherdigitando errado depois de pressionar Enter)?
voretaq7
2
@ voretaq7: Não, eu não era tão esperto, mas quando alguém me deu uma pista, eu disse "Sério? Então é isso que estava acontecendo todas aquelas vezes em que meu shell era BANG! sem nenhuma razão quando eu estava digitando?" . Não é uma sequência comum, exceto nos erros de digitação da que você mencionou, mas pode acontecer.
Caleb
14
Em que "segredo" ele quer dizer "na página de manual".
Larsks
4
Enquanto muitas pessoas não sabem disso, é realmente um segredo à vista. man sshaborda isso na ESCAPE CHARACTERSseção ~.(Desconectar) e ~^Z(background ssh) são muito úteis.
Stefan Lasiewski
9
É claro que está na página de manual :) Eu só usei a palavra segredo porque o OP o usou e estava usando a língua na bochecha. O problema com esse recurso é que as pessoas não sabem onde procurar, esperam que os caracteres de controle e esses sinais façam parte do shell ou algo assim. Depois que você souber onde procurar ou até o que perguntar, é claro que está lá.
Caleb
12

O SSH oferece uma instalação de manutenção contínua. Adicione o seguinte ao seu local ~/.ssh/config(crie se não existir):

ServerAliveInterval 15
ServerAliveCount 3

Essa configuração estabelecerá um sinal de manutenção de funcionamento enviado a cada 15 segundos através do túnel seguro. Após três falhas consecutivas, o cliente SSH será encerrado.

Observe que em alguns sistemas (incluindo o macOS 10.14), ele precisa ser:

ServerAliveInterval 15
ServerAliveCountMax 3

Retirado desta resposta em ask.ubuntu: https://askubuntu.com/a/29967/30266

krlmlr
fonte
9

O fato de travar é uma função do TCP, não do SSH. O aplicativo não tem como saber que a sessão / conexão TCP foi cortada, a menos que o TCP informe ao aplicativo usando a conexão que a conexão não existe mais. Da perspectiva de cada host, a sessão TCP ainda está no estado Estabelecido e não há nada a dizer que uma sessão inativa longa (sem fluxo de dados) não é válida senão um RST ou uma falta de resposta a um pacote TCP keepalive (que não é universalmente implementado). Isso não parece ser um bug no SSH para mim, eu esperaria esse comportamento.

joeqwerty
fonte
5

Se a conexão estiver travada corretamente, nenhuma combinação mágica de teclas será executada, pois a conexão já está travada antes de você pressionar a tecla. Você pode dizer ao cliente para terminar, mas isso não afetará o histórico mantido (ou não) no final do servidor.

Embora isso não responda à pergunta, ele pode ajudar a reduzir os efeitos de uma conexão travada: quando estou trabalhando remotamente (e mesmo quando não estou), eu passo screen(com ou sem o byobuinvólucro, dependendo da disponibilidade) para que, se houver algum tipo de conexão, minha sessão, com todo o seu histórico, seja preservada e esteja disponível no estado em que a deixei ao reconectar.

David Spillett
fonte
6
Sua sugestão sobre a tela é boa, mas o primeiro bit não é aplicável ao problema. Você não precisa passar as chaves para o lado remoto; você só precisa transferi-las para o cliente local ssh! O OP quer sua concha local de volta, incluindo a história. O SSH assume o controle e não responde a seqüências normais de interrupção, como CTRL-C, porque as transmite. Existe uma maneira de passar e encerrar o cliente local, veja minha resposta. O histórico local normalmente é mantido de qualquer maneira, se você efetuar login novamente, dependendo da configuração do shell.
Caleb
2
@ Caleb: a pergunta mencionada especificamente perdendo histórico, e o histórico de comandos é armazenado no lado do servidor. Para solicitar ao servidor que faça algo diferente com o histórico, você precisa enviar uma mensagem ao servidor para que ele faça algo diferente com o histórico. É claro que existem maneiras de fazer o bash (e algumas outras conchas) registrar as linhas do histórico imediatamente, em vez de coletá-las na RAM até que o usuário exista corretamente o shell com exit/ logoutque resolveria o problema do histórico sem o uso screen.
David Spillett