Como manter um túnel SSH confiável de forma confiável?

207

Eu uso um túnel SSH do trabalho para contornar vários firewalls idóticos (tudo bem com meu chefe :)). O problema é que depois de um tempo a conexão ssh normalmente trava e o túnel está quebrado.

Se eu pudesse pelo menos monitorar o túnel automaticamente, eu poderia reiniciar o túnel quando ele trava, mas eu nem imaginei uma maneira de fazer isso.

Pontos de bônus para quem pode me dizer como evitar que minha conexão ssh seja interrompida, é claro!

    
por Peltier 08.09.2009 / 15:04

15 respostas

247

Parece que você precisa do autossh . Isto irá monitorar um túnel ssh e reiniciá-lo conforme necessário. Nós usamos isso há alguns anos e parece funcionar bem.

autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C

Mais detalhes sobre o parâmetro -M aqui

    
por 08.09.2009 / 15:43
35

Todos os firewalls com informações de estado esquecem-se de uma conexão depois de não ver um pacote para essa conexão por algum tempo (para impedir que as tabelas de estado fiquem cheias de conexões onde ambas as extremidades morreram sem fechar a conexão). A maioria das implementações TCP enviará um pacote keepalive após um longo período de tempo sem ouvir do outro lado (2 horas é um valor comum). Se, no entanto, houver um firewall com estado que se esquece da conexão antes que os pacotes keepalive possam ser enviados, uma conexão de longa duração, mas ociosa, morrerá.

Se for esse o caso, a solução é evitar que a conexão fique ociosa. O OpenSSH tem uma opção chamada ServerAliveInterval que pode ser usada para impedir a conexão de ficar ocioso por muito tempo (como bônus, ele detectará quando o par morreu antes, mesmo se a conexão estiver inativa).

    
por 28.09.2009 / 15:47
23

No seu próprio computador Mac ou Linux, configure seu ssh para manter o servidor ssh ativo a cada 3 minutos. Abra um terminal e use o seu seu invisível .ssh em sua casa:

cd ~/.ssh/ 

crie um arquivo de configuração de 1 linha com:

echo "ServerAliveInterval 180" >> config

você também deve adicionar:

ServerAliveCountMax xxxx (high number)

o padrão é 3, portanto, o ServerAliveInterval 180 irá parar de enviar após 9 minutos (3 dos intervalos de 3 minutos especificados por ServerAliveInterval).

    
por 29.05.2010 / 15:45
20

Eu usei o seguinte script Bash para continuar gerando novos túneis ssh quando o anterior morre. Usar um script é útil quando você não quer ou não pode instalar pacotes adicionais ou usar o compilador.

while true
do
  ssh <ssh_options> [user@]hostname
  sleep 15
done

Observe que isso requer um arquivo de chaves para estabelecer a conexão automaticamente, mas esse também é o caso do autossh.

    
por 22.09.2009 / 16:58
11

O Systemd é ideal para isso.

Crie um arquivo de serviço /etc/systemd/system/sshtunnel.service contendo:

[Unit]
Description=SSH Tunnel
After=network.target

[Service]
Restart=always
RestartSec=20
User=sshtunnel
ExecStart=/bin/ssh -NT -o ServerAliveInterval=60 -L 5900:localhost:5900 user@otherserver

[Install]
WantedBy=multi-user.target

(Modifique o comando ssh para se adequar)

  • isso será executado como usuário sshtunnel , para garantir que o usuário exista primeiro
  • edite systemctl enable sshtunnel para configurá-lo para iniciar no momento da inicialização
  • edite systemctl start sshtunnel para iniciar imediatamente

Atualização de janeiro de 2018 : algumas distros (por exemplo, Fedora 27) podem usar a política do SELinux para impedir o uso de SSH do init do systemd, caso em que uma política personalizada precisará a ser criado para fornecer as isenções necessárias.

    
por 28.07.2016 / 08:10
9

Com certeza, parece-me que você está interpretando mal o ServerAliveCountMax. Pelo que entendi os documentos, é o número de mensagens vivas do servidor que podem ficar sem resposta sem que a conexão seja terminada. Portanto, em casos como os que estamos discutindo aqui, configurá-lo com um valor alto apenas garantirá que uma conexão interrompida não seja detectada e terminada!

A simples configuração de ServerAliveInterval deve ser suficiente para resolver o problema com um firewall, esquecendo-se da conexão e deixando o ServerAliveCountMax low permitir que o terminal de origem perceba a falha e termine se a conexão falhar de qualquer maneira.

O que você deseja é, 1) que a conexão permaneça aberta permanentemente em circunstâncias normais, 2) que a falha de conexão seja detectada e que o lado de origem saia com falha e 3) que o comando ssh seja reeditado toda vez que ele sai (como você faz isso é muito dependente da plataforma, o script "while true" sugerido por Jawa é unidirecional, no OS XI realmente configurar um item launchd).

    
por 28.11.2013 / 02:04
9

Sempre use a opção ServerAliveInterval SSH caso os problemas de túnel sejam gerados por sessões NAT expiradas.

Sempre use um método de respawn caso a conectividade seja desativada por completo, você tem pelo menos três opções aqui:

  • programa autossh
  • script bash ( while true do ssh ...; sleep 5; done ) não remove o comando sleep, ssh pode falhar rapidamente e você reaparecerá muitos processos
  • /etc/inittab , para ter acesso a uma caixa enviada e instalada em outro país, por trás de NAT, sem encaminhamento de porta para a caixa, você pode configurá-la para criar um túnel ssh de volta para você:

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • script upstart no Ubuntu, onde /etc/inittab não está disponível:

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /path/to/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip
    post-stop script
        sleep 5
    end script
    

ou use sempre os dois métodos.

    
por 08.03.2014 / 22:30
6

Eu resolvi esse problema com isso:

Editar

~/.ssh/config

E adicione

ServerAliveInterval 15
ServerAliveCountMax 4

De acordo com a página de manual ssh_config:

ServerAliveCountMax
         Sets the number of server alive messages (see below) which may be
         sent without ssh(1) receiving any messages back from the server.
         If this threshold is reached while server alive messages are
         being sent, ssh will disconnect from the server, terminating the
         session.  It is important to note that the use of server alive
         messages is very different from TCPKeepAlive (below).  The server
         alive messages are sent through the encrypted channel and there‐
         fore will not be spoofable.  The TCP keepalive option enabled by
         TCPKeepAlive is spoofable.  The server alive mechanism is valu‐
         able when the client or server depend on knowing when a connec‐
         tion has become inactive.

         The default value is 3.  If, for example, ServerAliveInterval
         (see below) is set to 15 and ServerAliveCountMax is left at the
         default, if the server becomes unresponsive, ssh will disconnect
         after approximately 45 seconds.  This option applies to protocol
         version 2 only.

 ServerAliveInterval
         Sets a timeout interval in seconds after which if no data has
         been received from the server, ssh(1) will send a message through
         the encrypted channel to request a response from the server.  The
         default is 0, indicating that these messages will not be sent to
         the server.  This option applies to protocol version 2 only.
    
por 30.05.2013 / 15:32
3

ExitOnForwardFailure yes é um bom complemento para as outras sugestões. Se ele se conecta, mas não consegue estabelecer o encaminhamento de porta, é tão inútil para você como se não tivesse sido conectado.

    
por 07.06.2015 / 01:41
1

Eu tive a necessidade de manter um túnel SSH a longo prazo. Minha solução estava sendo executada em um servidor Linux e é apenas um pequeno programa em C que reaparece o ssh usando autenticação baseada em chave.

Eu não tenho certeza sobre o enforcamento, mas eu tive túneis morrem devido a timeouts.

Eu adoraria fornecer o código para o respawner, mas não consigo encontrá-lo agora.

    
por 08.09.2009 / 15:17
1

enquanto existem ferramentas como autossh que ajuda a reiniciar a sessão ssh ... o que eu acho realmente útil é rodar o comando 'screen'. Ele permite que você reinicie suas sessões ssh mesmo depois de desconectar. Especialmente útil se a sua conexão não for tão confiável quanto deveria ser.

... não se esqueça de marcar esta é a resposta 'correta' se te ajuda k! ; -)

    
por 08.09.2009 / 16:09
1

Um pouco de hack, mas eu gosto de usar a tela para manter isso. Atualmente tenho um controle remoto que está em execução há semanas.

Exemplo, iniciando localmente:

screen
ssh -R ......

Quando o encaminhamento remoto é aplicado e você tem um shell no computador remoto:

screen
Ctrl + a + d

Agora você tem um redirecionamento remoto ininterrupto. O truque é executar a tela em ambas as extremidades

    
por 13.03.2012 / 13:11
1

Recentemente tive esse problema, porque essas soluções exigem que você insira novamente a senha sempre que usar um login de senha. Usei o sshpass em um loop junto com um prompt de texto para evitar a senha no arquivo de lote. / p>

Pensei em compartilhar minha solução neste caso, caso alguém mais tenha o mesmo problema:

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done
    
por 30.07.2015 / 16:02
0

Eu tive problemas semelhantes com o meu provedor anterior. Para mim, foi o mesmo com qualquer conexão tcp, visitando sites ou enviando e-mails.

A solução foi configurar uma conexão VPN via UDP (eu estava usando o OpenVPN). Essa conexão foi mais tolerante com o que causou as desconexões. Então você pode executar qualquer serviço através desta conexão.

Ainda pode haver problemas com a conexão, mas como o túnel será mais tolerante, qualquer sessão ssh sentirá um curto espaço de espera, em vez de ser desconectada.

Para fazer isso, você precisará de um serviço de VPN on-line, que pode ser configurado em seu próprio servidor.

    
por 28.09.2009 / 12:27
0

Como autossh não atende às nossas necessidades (existe erro se não puder se conectar ao servidor na primeira tentativa), escrevemos um aplicativo bash puro: link

Cria um túnel reverso para a porta sshd do NODE (22) no servidor por padrão. Se você precisar executar outras ações (como encaminhar portas adicionais, enviar e-mails durante a conexão, etc ...), poderá colocar as pastas on-connect e on-disconnect dos seus scripts.

    
por 15.07.2017 / 02:04