A situação é assim:
http client ----> corporate firewall ----> http server
Devido a uma manutenção de atividade, o servidor e o cliente manteriam as conexões TCP abertas e o cliente usaria um conjunto de conexões para solicitações HTTP.
O firewall tem uma regra para "matar" conexões TCP de longa data após 1 hora. O problema é que nosso cliente HTTP não detectou que a conexão TCP foi destruída e tentou reutilizar conexões essencialmente mortas que, do nosso lado, pareciam o cliente "travado" após um período de tempo. Uma solicitação seria interrompida e a próxima funcionaria, provavelmente porque uma nova conexão foi estabelecida.
A questão aqui é qual é o mecanismo com o qual o firewall está matando as conexões TCP de uma maneira que nosso cliente HTTP não conseguiu detectá-las. Tentei reproduzir esse comportamento localmente de algumas maneiras:
- Mate as conexões TCP em nosso roteador vyos, o Wireshark no lado do cliente capturou o TCP FIN-ACK. Está bem
- Mate o lado do cliente da conexão TCP no TCPView no Windows, o Wireshark detectou o TCP RST no lado do cliente. Está bem
- A porta de bloqueio após a conexão estabelecida com o firewall do lado do cliente resultou na exceção de redefinição de soquete. Está bem
Eu tenho um dump do Wireshark no lado do servidor e tentei descobrir se o firewall envia um FIN ou RST com ip.dst==serverip && (tcp.flags.reset==1 || tcp.flags.fin==1)
mas nada apareceu.
Além disso, a captura do Wireshark no lado do cliente mostra o problema quando a solicitação HTTP é encerrada, seguida por uma dúzia de retransmissões de TCP, não sendo levada a lugar algum.
O cliente HTTP é um cliente Java nativo e / ou Jetty HTTP (tentou ambos), ambos falharam ao detectar uma conexão TCP morta. Gostaria de reproduzir o comportamento localmente, mas não consigo descobrir de que maneira astuciosa o firewall está matando as conexões, procurando, portanto, possíveis respostas.
Respostas:
Você não menciona o tipo de firewall, mas eu suspeito que simplesmente elimine os pacotes.
O que tenderia a confirmar isso.
fonte
Provavelmente, o firewall acabou de descartar o pacote sem enviar um pacote RST, provavelmente após atingir algum tipo de tempo limite da sessão. Esse é geralmente um comportamento configurável.
Pessoalmente, prefiro que o pacote RST seja enviado precisamente porque ajuda os clientes a se comportarem normalmente, mas ouvi argumentos no sentido de que isso não deve ser feito em firewalls externos para evitar fornecer qualquer tipo de feedback aos possíveis invasores.
Eu já vi essa causa alguns problemas, porque os clientes normalmente não lidam com esse tipo de cenário com muita elegância. Essencialmente, eles continuam tentando novamente a sessão TCP original (que agora está morta) e nunca tentam restabelecer uma nova. Eventualmente, um tempo limite do lado do cliente é acionado e o usuário recebe uma mensagem de erro desagradável. Configurar o keepalive HTTP adequadamente para o aplicativo pode ajudar a corrigir isso.
fonte
O @Ron Trunk está exatamente correto, quase certamente a conexão aberta está sendo descartada ativamente (negar regra inserida) ou passivamente (removida de conexões conhecidas e não pode ser recriada sem uma sincronização). Um dos comentários sugeriu tentar você mesmo. Aqui está uma receita para fazer isso usando namespaces de rede linux. Ele assume que o encaminhamento de IP está ativado no kernel do seu host, você é root e provavelmente outras coisas.
Você precisa de três janelas / conchas / telas / terminais. Execute cada comando abaixo em um terminal distinto:
ip netns exec three socat TCP-LISTEN:5001 STDIO
ip netns exec one socat STDIO TCP:3.3.3.3:5001
Observe que, depois de executar esses comandos, tudo o que você digita em uma janela será refletido na outra e vice-versa (após pressionar Return). Se isso não for verdade, pode ser necessário ativar o encaminhamento de IP.
ip netns exec two iptables -I FORWARD -j DROP
Então, nada que você digitar será permitido.
Você pode simular um método de descarte menos ativo com regras de encaminhamento (não testadas) como:
Consulte /unix/127081/conntrack-tcp-timeout-for-state-stablished-not-working e https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl .txt para obter informações sobre como ajustar os tempos limite - embora não esteja claro para mim que o iptables suporta nativamente uma vida útil máxima da conexão; Acredito que todos os tempos limite sejam inativos.
Limpe com
ip netns del one; ip netns del two; ip netns del three
fonte
O firewall pode enviar um pacote ICMP indicando que o destino estava inacessível. Para qualquer coisa, exceto TCP, essa é a única indicação de erro possível, por exemplo, enviar um pacote para uma porta UDP fechada gerará uma mensagem "destino inacessível" com o código de razão definido como "porta inacessível".
Também é possível enviar mensagens de "porta inacessível" como resposta aos pacotes TCP, isso também encerra a conexão, mas qualquer pessoa que analise despejos de pacotes notará que isso é incomum, pois a convenção TCP indica portas fechadas com um RST.
Espera-se que o remetente mapeie todos os pacotes de erros ICMP recebidos de volta para a conexão de origem e os manipule adequadamente, para que um pacote de erros gerado por firewall também possa ser usado para terminar uma conexão TCP. O pacote ICMP contém uma cópia dos cabeçalhos do pacote incorreto para permitir esse mapeamento.
fonte