No meu caso, a causa acabou sendo uma interação entre uma VPN e um modem DSL desonesto com uma porta SSH externa para frente.
Cenário
Configuração:
- 192.168.0.0/24 é a rede LAN
- 192.168.1.0/24 é a rede do cliente VPN
- server1 (192.168.0.3) é o servidor VPN
- O modem DSL (192.168.0.10) é o roteador padrão para todos os hosts
- O modem DSL tem uma rota estática que envia o tráfego da VPN (ou seja, destinado a 192.168.1.0/24) para o servidor1
- Na configuração do modem DSL, a porta TCP 22 é encaminhada para o servidor1
- Na configuração do modem DSL, a porta VPN é encaminhada para o servidor1
- server2 (192.168.0.223) é o servidor para o qual estou tentando executar SSH
O sintoma era que, durante o estabelecimento da conexão, o lado do cliente sempre dizia "Falha na gravação: cano quebrado" depois que a senha ou a verificação da chave acontecia. Isso ocorreu logo após a etapa debug1: Sending command: ...
. Eu habilitei o log detalhado no servidor e ele disse que o cliente enviou uma redefinição de TCP.
Análise
Eu testei com o Wireshark e descobri que esta sequência ocorreu:
23.002349 192.168.1.6 -> 192.168.0.223 TCP 56677 > ssh [SYN] Seq=0 Win=5840 Len=0 MSS=1460 TSV=643508643 TSER=0 WS=8
23.080714 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1369 TSV=1628354 TSER=643508643 WS=7
23.080743 192.168.1.6 -> 192.168.0.223 TCP 56677 > ssh [ACK] Seq=1 Ack=1 Win=5888 Len=0 TSV=643508663 TSER=1628354
23.399242 192.168.0.223 -> 192.168.1.6 SSH Server Protocol: SSH-2.0-OpenSSH_6.7p1 Debian-5+deb8u1\r
23.399267 192.168.1.6 -> 192.168.0.223 TCP 56677 > ssh [ACK] Seq=1 Ack=40 Win=5888 Len=0 TSV=643508742 TSER=1628434
23.399606 192.168.1.6 -> 192.168.0.223 SSH Client Protocol: SSH-2.0-OpenSSH_5.5p1 Debian-6+squeeze8\r
23.479613 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [ACK] Seq=40 Ack=42 Win=29056 Len=0 TSV=1628454 TSER=643508742
23.479638 192.168.1.6 -> 192.168.0.223 SSHv2 Client: Key Exchange Init
23.488855 192.168.0.223 -> 192.168.1.6 SSHv2 Server: Key Exchange Init
23.528382 192.168.1.6 -> 192.168.0.223 TCP 56677 > ssh [ACK] Seq=890 Ack=960 Win=8960 Len=0 TSV=643508775 TSER=1628455
23.607196 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [ACK] Seq=960 Ack=890 Win=31872 Len=0 TSV=1628486 TSER=643508762
23.607218 192.168.1.6 -> 192.168.0.223 SSHv2 Client: Diffie-Hellman GEX Request
23.714323 192.168.0.223 -> 192.168.1.6 SSHv2 Server: Diffie-Hellman Key Exchange Reply
23.714367 192.168.1.6 -> 192.168.0.223 TCP 56677 > ssh [ACK] Seq=914 Ack=1240 Win=10752 Len=0 TSV=643508821 TSER=1628512
23.732326 192.168.1.6 -> 192.168.0.223 SSHv2 Client: Diffie-Hellman GEX Init
23.837671 192.168.0.223 -> 192.168.1.6 SSHv2 Server: Diffie-Hellman GEX Reply
23.876369 192.168.1.6 -> 192.168.0.223 TCP 56677 > ssh [ACK] Seq=1186 Ack=2088 Win=13568 L
23.934571 192.168.1.6 -> 192.168.0.223 SSHv2 Client: New Keys
24.052445 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [ACK] Seq=2088 Ack=1202 Win=33664 Len=0 TSV=1628598 TSER=643508876
24.052465 192.168.1.6 -> 192.168.0.223 SSHv2 Encrypted request packet len=52
24.130296 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [ACK] Seq=2088 Ack=1254 Win=33664 Len=0 TSV=1628617 TSER=643508906
24.131032 192.168.0.223 -> 192.168.1.6 SSHv2 Encrypted response packet len=52
[...]
29.775083 192.168.1.6 -> 192.168.0.223 SSHv2 Encrypted request packet len=136
29.897679 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [ACK] Seq=2728 Ack=2586 Win=39936 Len=0 TSV=1630059 TSER=643510336
30.986259 192.168.0.223 -> 192.168.1.6 SSHv2 Encrypted response packet len=52
30.986704 192.168.1.6 -> 192.168.0.223 SSHv2 Encrypted request packet len=136
31.066976 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [ACK] Seq=2780 Ack=2722 Win=41600 Len=0 TSV=1630351 TSER=643510639
31.068851 192.168.0.10 -> 192.168.1.6 SSH Encrypted response packet len=88
31.068874 192.168.1.6 -> 192.168.0.10 TCP 56677 > ssh [RST] Seq=1 Win=0 Len=0
61.015948 192.168.1.6 -> 192.168.0.223 SSHv2 Encrypted request packet len=68
61.094573 192.168.0.223 -> 192.168.1.6 TCP ssh > 56677 [RST] Seq=2780 Win=0 Len=0
O que está acontecendo aqui é que tudo (alguns detalhes ignorados) está bom até a segunda marca de 31,066976 (onde o server2 está enviando um ACK para uma solicitação). Mas então, o próximo pacote (em 31.068851) vem do DSL MODEM, que obviamente faz com que meu laptop envie um TCP RST (reset de conexão) dizendo que está usando uma conexão antiga ou algo assim. (Eu sei que isso estava relacionado, porque o RST é enviado da porta 56677).
MAS, o modem DSL parece estar redirecionando essa redefinição para o servidor1, o que obviamente elimina a conexão SSH real. Portanto, após um tempo limite de 30 segundos (em 61.015948), meu laptop tenta enviar outra solicitação sem resposta sobre a conexão TCP real à solicitação em 30.986704. Naturalmente, server1, em seguida, envia um TCP RST porque ele já havia desistido dessa conexão. Daí o erro Write failed: Broken pipe
no meu laptop.
Conclusão
O modem DSL está vendo metade da conexão, ou seja, responde aos pacotes do servidor2 e os encaminha para o servidor1 como tráfego da VPN. Mas pelo menos alguns desses pacotes estão sendo interpretados pelo modem DSL de alguma forma, porque está enviando respostas aleatórias (usando SSHv1 btw). Observe que o modem DSL não pode ver o pacote em 30.986704, porque ele sai do túnel no servidor1 e é enviado pela LAN para o servidor2. Então não tenho certeza do que está acontecendo.
Solução alternativa
Eu adicionei uma rota estática no servidor2 para 192.168.1.0/24 com o gateway 192.168.0.3 (server1), que evita o tráfego de resposta para clientes VPN usando o modem DSL. Problema resolvido.
PS - Para aqueles que são novos no TCP, lembre-se de que mensagens ACK separadas são enviadas somente se não houver dados de resposta disponíveis para envio dentro de um intervalo definido; se houver, o sinalizador ACK será definido nessa mensagem de dados.