La situation est comme ceci:
http client ----> corporate firewall ----> http server
En raison d'une keepalive, le serveur et le client garderaient les connexions TCP ouvertes et le client utiliserait un pool de connexions pour les requêtes HTTP.
Le pare-feu a une règle pour "tuer" les connexions TCP de longue date après 1 heure. Le problème est que notre client HTTP ne détecterait pas que la connexion TCP a été détruite et il a essayé de réutiliser des connexions essentiellement mortes qui de notre côté ressemblaient au client "pendu" après un certain temps. Une demande se bloquerait, puis la suivante fonctionnerait, probablement parce qu'une nouvelle connexion a été établie.
La question ici est quel est le mécanisme avec lequel le pare-feu tue les connexions TCP d'une manière que notre client HTTP n'a pas pu les détecter. J'ai essayé de reproduire ce comportement localement de plusieurs manières:
- Tuez les connexions TCP sur notre routeur vyos, Wireshark du côté client a capturé TCP FIN-ACK. D'accord
- Tuez la connexion TCP côté client dans TCPView sous Windows, Wireshark a détecté TCP RST côté client. D'accord
- Bloquer le port après une connexion établie au pare-feu côté client, a entraîné une exception de réinitialisation de socket. D'accord
J'ai un vidage Wireshark côté serveur et j'ai essayé de trouver si le pare-feu envoie un FIN ou RST avec ip.dst==serverip && (tcp.flags.reset==1 || tcp.flags.fin==1)
mais rien ne s'est affiché.
De plus, la capture Wireshark côté client montre le problème lors de la sortie de la requête HTTP, suivie par une douzaine de retransmissions TCP, ne conduisant finalement nulle part.
Le client HTTP est un client HTTP natif Java et / ou Jetty (essayé les deux), les deux n'ont pas réussi à détecter une connexion TCP morte. Je voudrais reproduire le comportement localement, mais je ne peux pas comprendre de quelle manière douteuse le pare-feu tue les connexions, donc je cherche des réponses possibles.
Réponses:
Vous ne mentionnez pas le type de pare-feu, mais je soupçonne le plus simplement de laisser tomber les paquets.
Ce qui tendrait à le confirmer.
la source
Très probablement, le pare-feu vient de supprimer le paquet sans envoyer de paquet RST, probablement après avoir atteint une valeur d'expiration de session quelconque. Il s'agit généralement d'un comportement configurable.
Personnellement, je préfère que ce paquet RST soit envoyé précisément parce qu'il aide les clients à se comporter normalement, mais j'ai entendu des arguments selon lesquels cela ne devrait pas être fait sur des pare-feu orientés vers l'extérieur pour éviter de fournir tout type de rétroaction à des attaquants potentiels.
J'ai vu cette cause causer plusieurs problèmes car les clients ne gèrent généralement pas ce type de scénario de manière très élégante. Essentiellement, ils continuent à réessayer via la session TCP d'origine (qui est maintenant morte) et n'essaient jamais d'en rétablir une nouvelle. Finalement, un délai d'attente côté client se déclenche et l'utilisateur reçoit un message d'erreur désagréable. La configuration appropriée de Keepalive HTTP pour l'application peut aider à résoudre ce problème.
la source
@Ron Trunk est exactement correct, presque certainement la connexion ouverte est abandonnée soit activement (règle de refus insérée) ou passivement (supprimée des connexions connues et non autorisée à être recréée sans syn). Un des commentaires a suggéré de l'essayer vous-même. Voici une recette pour le faire en utilisant des espaces de noms de réseau Linux. Il suppose que le transfert IP est activé dans le noyau de votre hôte, que vous êtes root et probablement d'autres choses.
Vous avez alors besoin de trois fenêtres / coques / écrans / terminaux. Exécutez chaque commande ci-dessous dans un terminal distinct:
ip netns exec three socat TCP-LISTEN:5001 STDIO
ip netns exec one socat STDIO TCP:3.3.3.3:5001
Notez qu'après avoir exécuté ces commandes, tout ce que vous tapez dans une fenêtre sera reflété dans l'autre, et vice-versa (après avoir appuyé sur retour). Si ce n'est pas vrai, vous devrez peut-être activer le transfert IP.
ip netns exec two iptables -I FORWARD -j DROP
Ensuite, rien de ce que vous tapez ne sera autorisé.
Vous pouvez simuler une méthode de suppression moins active avec des règles de transfert (non testées) comme:
Voir /unix/127081/conntrack-tcp-timeout-for-state-stablished-not-working et https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl .txt pour des informations sur la façon d'ajuster les délais d'attente - bien qu'il ne soit pas clair pour moi que iptables supporte nativement une durée de vie de connexion maximale; Je crois que tous les délais d'attente sont des délais d'attente inactifs.
Nettoyez avec
ip netns del one; ip netns del two; ip netns del three
la source
Le pare-feu peut envoyer un paquet ICMP indiquant que la cible était inaccessible. Pour tout sauf TCP, c'est la seule indication d'erreur possible, par exemple l'envoi d'un paquet à un port UDP fermé générera un message "destination inaccessible" avec le code anomalie réglé sur "port inaccessible".
Il est également possible d'envoyer des messages "port inaccessible" en réponse aux paquets TCP, cela met également fin à la connexion, mais quiconque analyse les vidages de paquets remarquera que cela est inhabituel, car la convention TCP est d'indiquer les ports fermés avec un RST.
L'expéditeur doit mapper tous les paquets d'erreur ICMP reçus vers la connexion d'origine et les traiter de manière appropriée, de sorte qu'un paquet d'erreur généré par le pare-feu peut également être utilisé pour mettre fin à une connexion TCP. Le paquet ICMP contient une copie des en-têtes du paquet incriminé pour permettre ce mappage.
la source