Die Situation ist wie folgt:
http client ----> corporate firewall ----> http server
Aufgrund eines Keepalive würden Server und Client TCP-Verbindungen offen halten und der Client würde einen Verbindungspool für HTTP-Anforderungen verwenden.
Die Firewall hat die Regel, langjährige TCP-Verbindungen nach 1 Stunde zu "beenden". Das Problem ist, dass unser HTTP-Client nicht erkennt, dass die TCP-Verbindung zerstört wurde, und versucht hat, im Wesentlichen tote Verbindungen wiederzuverwenden, die auf unserer Seite so aussahen, als ob der Client nach einer gewissen Zeit "hängen geblieben" wäre. Eine Anfrage würde hängen bleiben, dann würde die nächste funktionieren, vermutlich weil eine neue Verbindung hergestellt wurde.
Hier stellt sich die Frage, mit welchem Mechanismus die Firewall TCP-Verbindungen so beendet, dass unser HTTP-Client sie nicht erkennen konnte. Ich habe versucht, dieses Verhalten auf verschiedene Arten lokal zu reproduzieren:
- Beenden Sie TCP-Verbindungen auf unserem Vyos-Router. Wireshark auf der Clientseite hat TCP FIN-ACK erfasst. OK
- Wenn Sie die TCP-Verbindungsclientseite in TCPView unter Windows beenden, hat Wireshark TCP-RST auf der Clientseite erkannt. OK
- Das Blockieren des Ports nach dem Herstellen der Verbindung zur clientseitigen Firewall führte zu einer Ausnahme beim Zurücksetzen des Sockets. OK
Ich habe einen Wireshark-Dump auf der Serverseite und habe versucht herauszufinden, ob die Firewall eine FIN oder RST mit sendet, ip.dst==serverip && (tcp.flags.reset==1 || tcp.flags.fin==1)
aber es wurde nichts angezeigt.
Darüber hinaus zeigt die Wireshark-Erfassung auf der Clientseite das Problem, wenn die HTTP-Anforderung ausgeht, gefolgt von einem Dutzend TCP-Neuübertragungen, die letztendlich nirgendwo hingehen.
Der HTTP-Client ist ein nativer Java- und / oder Jetty-HTTP-Client (beide ausprobiert). Beide konnten keine tote TCP-Verbindung erkennen. Ich möchte das Verhalten lokal reproduzieren, kann jedoch nicht herausfinden, auf welche zweifelhafte Weise die Firewall die Verbindungen beendet, und suche daher nach möglichen Antworten.
Antworten:
Sie erwähnen die Art der Firewall nicht, aber ich vermute, dass die Pakete am einfachsten verworfen werden.
Welches würde dazu neigen, dies zu bestätigen.
quelle
Höchstwahrscheinlich hat die Firewall das Paket nur verworfen, ohne ein RST-Paket zu senden, wahrscheinlich nachdem ein Sitzungszeitlimitwert erreicht wurde. Dies ist normalerweise ein konfigurierbares Verhalten.
Ich persönlich bevorzuge es, dieses RST-Paket genau deshalb senden zu lassen, weil es Clients dabei hilft, sich normal zu verhalten, aber ich habe Argumente dafür gehört, dass dies nicht auf nach außen gerichteten Firewalls erfolgen sollte, um potenziellen Angreifern keinerlei Feedback zu geben.
Ich habe gesehen, dass dies einige Probleme verursacht, weil Kunden mit solchen Szenarien normalerweise nicht sehr elegant umgehen. Im Wesentlichen wiederholen sie die ursprüngliche TCP-Sitzung (die jetzt tot ist) und versuchen niemals, eine neue wiederherzustellen. Schließlich wird ein clientseitiges Timeout ausgelöst und der Benutzer erhält eine böse Fehlermeldung. Wenn Sie HTTP Keepalive entsprechend für die App einrichten, kann dies behoben werden.
quelle
@ Ron Trunk ist genau richtig, mit ziemlicher Sicherheit wird die offene Verbindung entweder aktiv (Verweigerungsregel eingefügt) oder passiv (aus bekannten Verbindungen entfernt und darf ohne Synchronisierung nicht neu erstellt werden) getrennt. In einem der Kommentare wurde vorgeschlagen, es selbst auszuprobieren. Hier ist ein Rezept für die Verwendung von Linux-Netzwerk-Namespaces. Es wird davon ausgegangen, dass die IP-Weiterleitung im Kernel Ihres Hosts aktiviert ist, Sie Root sind und wahrscheinlich auch andere Dinge.
Sie benötigen dann drei Fenster / Schalen / Bildschirme / Terminals. Führen Sie jeden der folgenden Befehle in einem eigenen Terminal aus:
ip netns exec three socat TCP-LISTEN:5001 STDIO
ip netns exec one socat STDIO TCP:3.3.3.3:5001
Beachten Sie, dass nach dem Ausführen dieser Befehle alles, was Sie in ein Fenster eingeben, im anderen Fenster angezeigt wird und umgekehrt (nachdem Sie die Eingabetaste gedrückt haben). Wenn dies nicht der Fall ist, müssen Sie möglicherweise die IP-Weiterleitung aktivieren.
ip netns exec two iptables -I FORWARD -j DROP
Dann wird nichts, was Sie eingeben, durchgelassen.
Sie können eine weniger aktive Drop-Methode mit (nicht getesteten) Weiterleitungsregeln wie den folgenden simulieren:
Siehe /unix/127081/conntrack-tcp-timeout-for-state-stablished-not-working und https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl .txt für Informationen zum Anpassen der Zeitüberschreitungen - obwohl mir nicht klar ist, dass iptables nativ eine maximale Verbindungslebensdauer unterstützt; Ich glaube, alle Timeouts sind Leerlauf-Timeouts.
Aufräumen mit
ip netns del one; ip netns del two; ip netns del three
quelle
Die Firewall kann ein ICMP-Paket senden, das angibt, dass das Ziel nicht erreichbar war. Für alles andere als TCP ist dies die einzig mögliche Fehleranzeige. Wenn Sie beispielsweise ein Paket an einen geschlossenen UDP-Port senden, wird die Meldung "Ziel nicht erreichbar" mit dem Ursachencode "Port nicht erreichbar" generiert.
Es ist auch möglich, "Port nicht erreichbare" Nachrichten als Antwort auf TCP-Pakete zu senden. Dadurch wird auch die Verbindung beendet. Jeder, der Paket-Dumps analysiert, wird jedoch feststellen, dass dies ungewöhnlich ist, da die TCP-Konvention darin besteht, geschlossene Ports mit einem RST anzuzeigen.
Es wird erwartet, dass der Absender alle empfangenen ICMP-Fehlerpakete der ursprünglichen Verbindung zuordnet und entsprechend behandelt, sodass ein von der Firewall generiertes Fehlerpaket auch zum Beenden einer TCP-Verbindung verwendet werden kann. Das ICMP-Paket enthält eine Kopie der Header des fehlerhaften Pakets, um diese Zuordnung zu ermöglichen.
quelle