Falha no encaminhamento de porta remota SSH

26

Acompanhamento: Parece que a série rápida de desconexões que coincide com alguns meses de execução de cada servidor provavelmente é coincidência e serviu apenas para revelar o problema real. A razão pela qual ele não conseguiu se reconectar é quase certamente devido aos valores AliveInterval (resposta de kasperd). O uso da opção ExitOnForwardFailure deve permitir que o tempo limite ocorra corretamente antes de se reconectar, o que deve resolver o problema na maioria dos casos. A sugestão do MadHatter (o script de interrupção) é provavelmente a melhor maneira de garantir que o túnel possa se reconectar, mesmo se tudo falhar.

Eu tenho um servidor (A) atrás de um firewall que inicia um túnel reverso em várias portas para um pequeno DigitalOcean VPS (B), para que eu possa conectar-me a A via endereço IP de B. O túnel trabalha de forma consistente há cerca de três meses, mas falhou repentinamente quatro vezes nas últimas 24 horas. A mesma coisa aconteceu há algum tempo em outro provedor de VPS - meses de operação perfeita e, de repente, várias falhas rápidas.

Eu tenho um script na máquina A que executa automaticamente o comando tunnel ( ssh -R *:X:localhost:X address_of_Bpara cada porta X), mas quando é executado, ele diz Warning: remote port forwarding failed for listen port X.

Entrar no sshd /var/log/secureno servidor mostra estes erros:

bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X

A solução requer a reinicialização do VPS. Até então, todas as tentativas de se reconectar transmitem a mensagem "falha no encaminhamento de porta remota" e não funcionam. Agora é o ponto em que o túnel dura apenas cerca de 4 horas antes de parar.

Nada mudou no VPS e é uma máquina de usuário único e uso único que serve apenas como ponto final do túnel reverso. Está executando o OpenSSH_5.3p1 no CentOS 6.5. Parece que o sshd não fecha as portas quando a conexão é perdida. Não sei explicar por que, ou por que isso aconteceria repentinamente agora, depois de meses de operação quase perfeita.

Para esclarecer, primeiro preciso descobrir por que o sshd se recusa a ouvir as portas após a falha do túnel, o que parece ser causado pelo sshd deixar as portas abertas e nunca fechá-las. Esse parece ser o principal problema. Só não tenho certeza do que faria com que ele se comportasse dessa maneira depois de meses se comportando como eu esperava (por exemplo, fechando as portas imediatamente e permitindo que o script se reconecte).

Justin Mrkva
fonte
Qual a sua pergunta? Como resolver o erro de ligação da porta, ou como descobrir por que o ssh está morrendo ou algo mais novamente?
MadHatter apoia Monica
Eu preciso descobrir por que o sshd se recusa a abrir as portas no VPS (o erro de ligação). O erro de ligação da porta parece ser a raiz do problema, e tudo deve funcionar se eu conseguir resolver isso.
23714 Justin Bittencourt
2
Para qualquer lurker tardio, em vez de criar manualmente um script para manter a conexão aberta, basta usar o autossh, que faz isso por você. serverfault.com/questions/598210/…
oligofren

Respostas:

27

Concordo com o MadHatter, que é provável que sejam encaminhamentos de portas de conexões ssh desativadas. Mesmo que o seu problema atual acabe sendo algo diferente, você pode esperar encontrar essas conexões ssh desativadas mais cedo ou mais tarde.

Existem três maneiras pelas quais essas conexões desativadas podem ocorrer:

  • Um dos dois pontos de extremidade foi reinicializado enquanto a outra extremidade da conexão estava completamente inativa.
  • Um dos dois pontos de extremidade fechou a conexão, mas no momento em que a conexão foi fechada, houve uma interrupção temporária na conexão. A interrupção durou alguns minutos após o fechamento da conexão e, portanto, a outra extremidade nunca soube da conexão fechada.
  • A conexão ainda está completamente funcional nos dois pontos finais da conexão ssh, mas alguém colocou um dispositivo com estado em algum lugar entre eles, o que excedeu o tempo limite da conexão devido à ociosidade. Esse dispositivo estável seria um NAT ou um firewall, o firewall que você já mencionou é o principal suspeito.

Descobrir qual dos três acima está acontecendo não é muito importante, porque existe um método que abordará os três. Esse é o uso de mensagens keepalive.

Você deve procurar a ClientAliveIntervalpalavra - chave sshd_confige o ServerAliveIntervalintervalo para ssh_configou ~/.ssh/config.

A execução do sshcomando em um loop pode funcionar bem. É uma boa idéia inserir uma suspensão no loop, para que você não acabe inundando o servidor quando a conexão, por algum motivo, falhar.

Se o cliente se reconectar antes que a conexão seja encerrada no servidor, você poderá acabar em uma situação em que a nova conexão ssh esteja ativa, mas sem encaminhamento de porta. Para evitar isso, você precisa usar a ExitOnForwardFailurepalavra-chave no lado do cliente.

Kasperd
fonte
Eu estou pensando que este pode ser o problema. Em particular, meu script em A tentará se reconectar a B se o processo ssh morrer (é claro que a mensagem de aviso não mata o processo ssh, ele fica paralisado quando isso acontece, mas isso é um problema para outro dia). Mas se A tentar se reconectar a B muito rapidamente, B poderá estar aguardando que A se reconecte. Eu provavelmente preciso garantir que B sempre atinja o tempo limite antes que A se reconecte. Combinando isso com a sugestão do MadHatter de matar os processos sshd antes de se reconectar, provavelmente cobrirá 95% dos casos possíveis.
23614 Justin Bittencourt
1
E falando da mensagem de aviso que não matava o SSH, isso me fez pensar ... e olhar para as páginas de manual. Acontece que -o ExitOnForwardFailure yesé exatamente o que eu precisava. Então isso é uma coisa a menos que preciso descobrir. Para pensar, eu ia escrever um script Python para analisar essas mensagens de aviso. Isso é muito mais simples. : D
Justin Mrkva
Desculpe por esquecer ExitOnForwardFailureao escrever minha resposta. Eu o adicionei à resposta agora.
Kasperd
4
Não tem problema, e foi realmente -o ExitOnForwardFailure=yes(observe o sinal de igual). Portanto, se alguém se deparar com isso, não copie e cole do meu comentário anterior, ele não funcionará. : P
Justin Mrkva
Então, eu monitoro o servidor há cerca de 10 horas e parece que ele está funcionando bem; Neste momento, estou assumindo que esta resposta está correta (tenho cerca de 99% de certeza com base no que vi) e que a série de desconexões rápidas foi coincidência relacionada a problemas de rede que apareceram alguns meses depois iniciando cada serviço. Obrigado a todos por sua ajuda. ;)
Justin Mrkva
4

Você pode encontrar o processo que está vinculando a porta nesse servidor com

sudo netstat -apn|grep -w X

Parece muito provável que seja o meio defunto sshd, mas por que fazer suposições quando você pode ter dados? Também é uma boa maneira de um script encontrar um PID para enviar o sinal 9 antes de tentar abrir o túnel novamente.

MadHatter apoia Monica
fonte
Lembro-me de verificar isso no provedor VPS anterior e confirmei que sshd era o processo de ouvir essas portas. Da próxima vez que isso acontecer, vou checá-lo aqui, mas como o comportamento e a configuração são exatamente os mesmos, não espero que seja diferente.
23414 Justin Bittencourt
Ótimo, o seu script que reabre o túnel mata o antigo tunneller antes de tentar fazê-lo.
MadHatter apoia Monica
Nunca há mais de um script de encapsulamento (em A) em execução ao mesmo tempo, se é isso que você está dizendo. Por outro lado, se você deseja que o script execute remotamente um comando em B para eliminar os processos dispersos ... isso não é uma má idéia. Mas uma preocupação é matar repetidamente todas as conexões SSH se eu estiver tentando depurar. Se o script em A está sempre matando B devido a uma falha, não posso ser constantemente expulso de B pelo script A desonesto. : P Vou ter que testar para garantir que não faça isso. Mas, como eu disse, não é uma má idéia. ;)
Justin Mrkva
Eu não tinha pensado que havia. Você diz que há um script em execução no servidor remoto que tenta abrir um encapsulamento e falha, devido ao erro de ligação, e presumo que ele seja executado apenas quando você precisar (por exemplo, quando o encapsulamento existente não for bom) porque você não disse o contrário. Tudo o que estou sugerindo é que elimine o processo específico que mantém a porta aberta antes de tentar abrir o novo túnel.
MadHatter apoia Monica
O script executando ssh está apenas no servidor A, o servidor B é um servidor vanilla comum, sem scripts extras. O que provavelmente farei é escrever um script kill para colocar no servidor B e chamá-lo remotamente de A se ele não conseguir conectar um certo número de vezes seguidas. Dessa forma, é menos provável que interfira com outras conexões SSH. E provavelmente terei o log do script kill sempre que for executado e sair sem fazer nada se for chamado muitas vezes com muita rapidez. Pessoalmente, parece que limitar a taxa de script que mata o sshd é provavelmente prudente. : P
Justin Mrkva
3

Para mim, quando um sshtúnel é desconectado, leva algum tempo para que a conexão seja redefinida, para que o sshprocesso continue bloqueado, deixando-me sem túneis ativos e não sei por quê. Uma solução alternativa é colocar sshem segundo plano -fe gerar novas conexões sem esperar que as conexões antigas sejam redefinidas. O -o ExitOnForwardFailure=yespode ser usado para LIMT o número de novos processos. A -o ServerAliveInterval=60melhora a confiabilidade de sua conexão atual.

Você pode repetir o sshcomando com frequência, digamos, em um cronou em um loop no seu script, por exemplo, a seguir, executamos o sshcomando a cada 3 minutos:

while (1)
do
    ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
    sleep 180
done
Stephen Quan
fonte
uma forma mais robusta solução estaria usando autossh
Marco Lavagnino
-o ExitOnForwardFailure=yesera o que eu estava procurando, muito obrigado!
Vadipp
1

Na minha experiência, o ssh tem o hábito um pouco cansativo de não sair corretamente, se 'algo' ainda estiver sendo executado no sistema remoto. Por exemplo, iniciado em segundo plano. Você pode reproduzir isso:

ssh <server>
while true; do  sleep 60; done&
exit

Seu ssh será desconectado, mas na verdade não fechará a sessão - até que o processo remoto termine (o que não acontecerá, porque é um loop 'while true'). Pode estar acontecendo algo semelhante - sua sessão tem um processo 'travado' que está sendo gerado pelo ssh. A porta permanece em uso e, portanto, não pode ser reutilizada pelo seu processo local.

Sobrique
fonte
O comando SSH completo que é executado na máquina A é ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 &para que não haja nada sendo executado pelo SSH, exceto o próprio túnel, especificamente devido à opção -N. Tudo o que está sendo mantido aberto está sendo feito no servidor remoto B usando o próprio sshd.
Justin Mrkva