Se eu executar algo assim:
ssh -4 -f -N -T -R "/home/dude/lol.socket:192.168.4.44:4444" dude@someserver -p 22 -i privatekey -o "ExitOnForwardFailure yes" -o ConnectTimeout=5 -o ConnectionAttempts=3 -o ServerAliveInterval=15 -o
E então digamos que a conexão seja encerrada ou seja interrompida por qualquer motivo. O arquivo de soquete criado /home/dude/lol.socket
no someserver
não é excluído pelo sshd. Portanto, como o iniciador do túnel reverso está se recuperando e tenta recriar o túnel, ele não pode porque:
Error: remote port forwarding failed for listen path /home/dude/lol.socket
No lado do servidor, você obtém algo como:
error: bind: Address already in use
error: unix_listener: cannot bind to path: /home/dude/lol.socket
Qual seria a maneira suportada / melhor hack para limpar o soquete após a desconexão? Isso é um bug no sshd, não deveria fazer isso automaticamente se/quando as desconexões forem notadas?
história de fundo:
A ideia por trás do uso dos soquetes é simplesmente que o servidor lidará com n "caras", criando túneis reversos para m serviços "lol" em quaisquer portas e o uso de soquetes torna muito mais fácil garantir que um "cara" só possa acessar e vincular para suas próprias tomadas, mas não para as tomadas de outros caras. Também me livra de ter que manter um registro de qual cara está usando qual porta para expor qual serviço. E quando o cara quiser se conectar ao serviço em algum outro servidor, tudo o que ele precisa saber é o nome do serviço e vinculá-lo a alguma porta local aleatória (ou soquete, se ele quiser), ou seja
ssh -v -i -4 -N -T -L "127.0.0.1:3334:/home/dude/lol.sock" -p 22 dude@someserver -o "ExitOnForwardFailure yes" -o ConnectTimeout=5 -o ConnectionAttempts= 3 -o ServerAliveInterval=15 -o ServerAliveCountMax=3
Não há necessidade de saber algum número de porta mágica na qual o túnel reverso no servidor deve estar sendo executado. Portanto, se você tiver ideias melhores sobre como resolver esse problema, sou todo ouvidos.
Testado com cliente/servidor em execução Debian 9
(cliente realmente no mac dentro do contêiner docker) usando a versão openssh-client/server7.4p1-10+deb9u2
TL;DR;
A solução é definir o valor de StreamLocalBindUnlink como yes na configuração sshd no servidor:
sudo sh -c 'echo "StreamLocalBindUnlink yes" >> /etc/ssh/sshd_config'
.Longa história
A razão pela qual isso acontece é porque os arquivos de soquete unix não são removidos automaticamente quando o soquete é fechado. Eles precisam ser limpos manualmente ao fechar, se desejado, chamando
remove
/unlink
com o caminho do arquivo, mas o openssh não faz isso. No entanto, ao pesquisar mais sobre o assunto, percebi que a "melhor prática" com soquetes unix éunlink
corrigir antes de vinculá-lo ( verifique esta resposta SO para obter mais detalhes ). E é exatamente isso que oStreamLocalBindUnlink yes
sshd diz para fazer.A página man diz:
A desvantagem dessa abordagem é que a religação ao soquete agora é permitida, mesmo que a conexão antiga ainda esteja lá. Fazer isso parece deixar o antigo túnel pendurado lá, de modo que todas as conexões tcp existentes que passam permaneçam intactas, mas todas as novas conexões vão para o novo túnel. Além disso, o túnel antigo parece estar permanentemente e irreversivelmente separado do endereço do soquete do sistema de arquivos e não poderá receber mais novas conexões, mesmo que o novo túnel seja fechado.
Referências