Eu tenho vários túneis ssh reversos configurados a partir de raspberry pis remotos, executando o debian jessie. Os RPIs usam um dongle 3G para obter conectividade intrnet, e é por isso que estou usando ssh reverso para fazer login remotamente. Cada RPI configura um túnel ssh reverso para um servidor em nuvem, que eu uso para fazer login em cada sistema.
Os túneis ssh são configurados da seguinte forma:
ssh -N -o ExitOnForwardFailure=yes -R 23xx:localhost:22 [email protected]
onde 23xx é a porta usada para encaminhar conexões da porta 22 e 178.xxxxx é o endereço IP do servidor.
Meu problema é que, às vezes, quando tento fazer o ssh em um sistema, ele trava para sempre, sem nenhum erro da seguinte forma:
ssh pi_username@localhost -p 23xx
O terminal simplesmente não emite nada depois disso e trava para sempre. Quando tento depurar usando -vvv, é isso que recebo:
ssh pi_username@localhost -p 23xx -vvv
OpenSSH_6.7p1 Debian-5+deb8u4, OpenSSL 1.0.1t 3 May 2016
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: ssh_connect: needpriv 0
debug1: Connecting to localhost [::1] port 23xx.
debug1: Connection established.
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_rsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/master/.ssh/id_ed25519-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.7p1 Debian-5+deb8u4
Parece que a conexão foi estabelecida, mas o login não é solicitado. Alguma ideia? Alguma recomendação sobre como depurar ainda mais?
Isso é apenas uma teoria, mas o que eu suspeito que esteja acontecendo é que as conexões TCP para suas sessões ssh estão morrendo, mas o "servidor em nuvem" não está detectando. Então, quando você vai fazer uma conexão com
localhost -p 23xx
, o processo ssh ainda está lá e ouvindo, mas quando ele tenta enviar dados de volta para o Pi, ele trava até que o número máximo de retransmissões TCP seja encontrado e finalmente decide que a conexão está morta e sai (você diz que trava para sempre, mas aposto que, se você esperasse o suficiente, conseguiria redefinir a conexão).Agora, supondo que você tenha o Pi configurado para se reconectar se o túnel ssh morrer, você pode pensar que isso deve resolver o problema. Há alguns problemas potenciais com essa ideia. A primeira é que o Pi também pode não estar detectando a conexão morta. Portanto, até que ele tente enviar dados e atinja o limite de retransmissão do TCP, ele não verá a conexão inativa e fará a reconexão. O segundo problema em potencial é que, mesmo que detecte a conexão inoperante e tente reconectar, não será capaz de estabelecer o ouvinte no servidor de nuvem porque o ssh anterior ainda está lá e segurando a porta.
A solução aqui é configurar o ssh para que ele possa detectar as conexões mortas. Existem algumas maneiras de fazer isso, TCP KeepAlive e SSH KeepAlive. (ref: https://unix.stackexchange.com/a/34201/4358 )
TCP KeepAlive (
TCPKeepAlive
configuração na configuração ssh) usa a funcionalidade nativa de manutenção de atividade do TCP. Basicamente, o kernel envia um TCP ACK vazio a cada X segundos e, quando não recebe um ACK da outra ponta (ou é reiniciado), fecha a conexão que notifica o aplicativo (SSH).SSH KeepAlive (as configurações
ServerAlive*
&ClientAlive*
) é semelhante, mas opera em uma camada superior. Aqui, o processo SSH envia dados reais por meio da conexão e procura uma resposta. Isso deve detectar uma conexão morta tão bem quanto um TCP KeepAlive normal, no entanto, é mais provável que mantenha a conexão ativa, pois os saltos no meio podem reconhecer pacotes TCP KeepAlive e ignorá-los e expirar a conexão ociosa. Mas um SSH KeepAlive não pode ser reconhecido, pois parece tráfego real para qualquer salto no meio.TL;DR:
No raspberry Pis, adicione as seguintes configurações à configuração do cliente ssh (
~/.ssh/config
ou/etc/ssh/ssh_config
):( documentação )
No servidor, adicione as seguintes configurações ao seu ssh daemon config (
/etc/ssh/sshd_config
):( documentação )
Observe que fiz o valor do intervalo um pouco mais alto. A razão para isso é apenas para que ambos os lados não enviem suas mensagens KeepAlive exatamente ao mesmo tempo e se cruzem no fio. Não há nenhum dano real nisso, apenas uma pequena ineficiência. Também não importa qual lado é mais alto, desde que sejam diferentes.
Eu tenho o mesmo problema.
Altere o valor de mtu para 1200. ( MTU )
SSH conectado como esperado depois disso. Espero que esta resposta encurte sua busca por soluções alternativas. :)