Test-TCPTimeout

Wie kann ich "Timeouts" einer Verbindung erkennen? Wie ich auf TCP Session Timeout / TCP Idle Timeout beschrieben habe, kann eine Verbindung bis zu 2 Stunden ohne übertragene Pakete als aktiv gelten. Erst nach spätestens 2 Stunden muss ein Endpunkte ein "Keep-Alive"-Paket senden. Darauf können natürlich Systeme nicht vertrauen, die Sessions speichern. Das sind Firewalls, NAT-Router und andere Systeme können TCP-Verbindungen, die längere Zeit "untätig" sind, unterbrechen ohne dass die Endpunkte dies sofort bemerken.

Überlegungen

Ich habe mir daher überlegt, wie ich in so einem Fall messen kann, ob es zu kurze Timeout-Werte gibt. Microsoft selbst empfiehlt, dass eine Verbindung mindestens 120 Sekunden bestehen bestehen bleiben darf.

A minimum of 120 seconds would be a good idle timeout on egress equipment used for Office 365 as MAPI/HTTP has application level keep alives set which will ensure the connection is not prematurely terminated with this timeout value or above.
Quelle: Network Perimeters & TCP Idle session settings for Outlook on Office 365 https://blogs.technet.microsoft.com/onthewire/2014/03/04/network-perimeters-tcp-idle-session-settings-for-outlook-on-office-365/

Es stellt sich aber schon die Frage, wie das zu messen ist. Auf der Seite HTTP Chunked habe ich mit einen PHP-Script zum Test der Funktion von lange laufenden HTTP-Verbindungen bereit gestellt. Allerdings funktioniert das natürlich nur mit HTTP-Verbindungen aber nicht mit POP3, IMAP4, SMTP und anderen Ports. Zudem gibt es hier auch immer die Gegenseite, meist in Form eines Apache WebServers, der lang laufende PHP-Skripte beendet.

Das wird dann auch bei den meisten anderen Web-Hosting-Anbietern auch nicht anders sein.

Eine reine TCP-Connection kann aber auch von beiden Seiten abgebaut werden. Wenn Sie z.B. eine Verbindung mit "TELNET outlook.office365.com 110" wird nicht 2 Stunden bestehen bleiben, denn der SMTP-Server überwacht seinerseits die Aktivität und wenn nichts mehr passiert, dann beendet der Server die Verbindung. Hier ist es dann aber meist ein aktives Abbrechen und die Gegenseite beendet auch die TCP-Verbindung. Ein Wireshark-Trace zeigt das recht einfach:

Nach dem 3-Wege Handshake (Paket 1-3) kommt das "Willkommen" und ich sende aber keine Daten. Der Exchange Server reagiert nach ca. 67 Sekunden mit der Meldung zum Abbruch (Paket 7) und baut danach auch die TCP-Verbindung aktiv ab.

TCP eingehend

Am interessantesten ist erst einmal der Rückkanal, d.h. mein Outlook verbindet sich mit Office 365 und fordert Daten an. Nachdem alle Daten erhalten wurden, sendet Outlook eine Anforderung, auf die der Exchange Online Server aber nicht sofort antwortet. Es ist ein "Outstanding Request", auf den Exchange eigenständig antwortet, sobald es etwas neues gibt. Das vorletzte Paket ist hier dann der HTTP-Request an den Server, der von dort sehr schnell per TCP ACK quittiert wird. Und dann ist erst mal "Ruhe". Eine Lösung wäre nun eine EWS-Abfrage an ein Postfach zu stellen, welches dann in entsprechenden Abständen eine Mail bekommt und so eine Antwort provoziert. Damit wäre aber nur Exchange Online zu testen.

Ich habe zuerst einmal ein Skript gebaut, welche generell eine TCP annimmt und in immer länger werdenden Abständen eine Rückmeldung in Form eines Zeitstempel liefert. Mein Client baut eine Verbindung einfach per TELNET.EXE zur Gegenseite auf dem konfigurierten Port auf und wartet. Der Client muss gar nichts tun. Die Gegenseite sendet eigenständig die Pakete:

Auf der Sendeseite läuft natürlich das PowerShell-Script und wartet erst auf die eingehende Verbindung um dann in den konfigurierten Abständen einen Zeitstempel zu senden:

Sobald hier also eine Firewall o.ä. die Verbindung des Rückwegs unterbricht, wird der Client keine Info mehr bekommen. Meist wird dann aber auch der Sender abbrechen, da er auf das ausgehende TCP-Paket ja eine Quittung erwartet.

Auf meinen PC über "localhost" sind natürlich auch 14400 Sekunden ( =4 Stunden) kein Problem. Wobei hier der TCP-Stack im Unterbau dann mit "Keep-Alive" die Verbindung nach 2h aufrecht erhält.

Der Sender härt aufgrund der Parametrisierung nach 14400 Sekunden auf:

Diese Zeit können Sie natürlich auch hochdrehen. Im Wireshark sieht das dann so aus, wenn ich über "Localhost" arbeite.

Gut zu sehen, wie die Abstände immer größer werden aber hier selbst bei 14400 Sekunden (4h) ein TCP-Timeout oder Keep-Alive auftritt.

Download

Wenn Sie selbst ihre Tests damit machen wollen, können sie hier das PowerShell-Script herunter laden:

test-tcptimeout.ps1

Bedenken Sie, dass das Skript einen TC-Port (Default 25) öffnet und eine lokale Firewall ggfls. konfiguriert werden muss.

Test mit HTTP

Ich habe auch überlegt diese Funktion als HTTP-Service zu bauen. So könnte eine PHP-Seite ja relativ einfach auf einem beliebigen Webserver laufen und auf eine Anforderung durch einen Browser entsprechende Daten liefern. Auf der Seite HTTP Chunked habe ich ein entsprechende Skript bereit gestellt, mit dem ich die Funktion von "Chunked Transfers" per HTTP demonstrieren kann.

Das Problem dabei ist, dass die meisten Webserver der Provider die Laufzeit von PHP-Skripten auf z.B. 60 Sekunden beschränken. Längere Messungen sind daher damit nicht möglich.

Test mit produktiven Services

Wen einfache PHP-Server auf der anderen Seite aufgrund von Beschränkungen beim beim Webserver nicht lange genug Daten senden können, dann kann ein anderer Ansatz eine Lösung sein. Sie baut etwas darauf auf, das ein NAT-Device, ein Proxy oder eine Firewall nicht nur eine Richtung abbaut, sondern beide Richtungen beendet.

Also könnte auch ein Client Pakete in immer größeren Abständen senden und solange die Gegenseite darauf noch mit einem  TCP ACK antwortet, besteht die Verbindung noch. Das Problem hierbei ist aber, dass die meisten Gegenstellen einen Client ohne sinnvolle Aktivität sehr schnell rauswerfen. Eine TCP-Connection kostet ja Ressourcen und wenn der Client sich nicht zumindest anmeldet, wird der Server die Verbindung schneller beenden als ein Timeout aus dem Verbindungsweg. Sie müssten also schon eine sinnvolle Verbindung starten, z.B.

  • Exchange Polling
    Sie könnten per EWS eine Anfrage auf ein Postfach machen, in dem Sie per SMTP die Aktivität gezielt steuern können. EWS kenne einen "Streaming"-Abruf, bei dem ein ausstehender HTTP-Request erst dann beantwortet wird, wenn eine Aktivität anliegt.
  • IMAP4-Push
    Die gleiche Technik gibt es für das IMAP4-Protokoll, bei dem eine Verbindung sehr lange aufrecht erhalten werden kann. Der Client stellt eine Anfrage und der IMAP4-Server antwortet erst bei einer Veränderung.
  • SSH-Shell
    Es gibt speziell Linux-Server, zu denen Sie sich per SSH auf die Konsole verbinden können. Wenn Sie hier einen Root-Server haben oder der Provider es zulässt, dann kann der Timeout durchaus höher als 2 Minuten sein. Allerdings gibt es hier beim Protokoll die Besonderheit, dass SSH auch "0-Bytes-Pakete" als Keepalive senden kann. Der Test ist also nicht immer zuverlässig

Die Protokolle EWS und IMAP4 scheinen mir hier als ehesten für einen weiteren Test geeignet zu sein. Allerdings muss das Skript dann sich natürlich anmelden und sie müssen die Kontrolle über das Postfach haben, um zu verschiedenen Zeiten eine Aktivität für den Server zu erzeugen.

Entsprechende Skripte habe ich dazu noch nicht erstellt. 

Weitere Links