TCP SYN ACK RES

Es war ein mal ein Loadbalancer, der wollte nicht glauben, dass meine Lync Services "online" sind. Und so habe ich wieder mal einen unerwarteten Sonderfall im Windows IP-Stack analysieren dürfen. Doch eins nach dem Anderen.

TCP-Port Check

Zu einer der wichtigen Aufgaben eines Load-Balancer gehört ist, die Erreichbarkeit der nachfolgenden Server zu überprüfen. Idealerweise erfolgt dies natürlich mit den gleichen Protokollen, die verteilt werden. Einen Mailserver kann man per SMTP erreichen und z.B. ein "220 *" als Willkommensstring erwarten und auf ein "EHLO" noch ein 220 OK. Wer einen Webserver überprüfen möchte, kann neben dem TCP-Connect auf Port 80 auch noch ein GET absetzen und so sicherstellen, dass der Webserver wirklich reagiert. Ob dabei ein 200 OK oder ein 404 kommt, ist für die meisten Systeme irrelevant, solange das HTTP-Protokoll erfüllt ist.

Aber ein Loadbalancer oder ein Monitor-System wird nie alle Protokolle verstehen und emulieren können. Meist scheitert das schon z.B. an SIP und erst Recht bei SIP/TLS. Auf der anderen Seite machen sich viele Loadbalancer Administratoren das Leben auch mal gerne leicht und sehen einen TCP-Connect schon als ausreichend an. Es soll sogar Konfigurationen geben, die es beim ICMP-Ping bewenden lassen.

Wer sich die Mühe einer Lastverteilung macht, sollte möglichst zuverlässig die Server überprüfen, die die Funktion bereitstellen. Ein einfacher TCP-Connect oder gar ICMP-Ping sind aus meiner Sicht nur ein Notnagel, wenn höherwertige Tests nicht möglich sind. Wenn aber ein einfacher HTTP-GET nicht möglich ist, dann sollten Sie vielleicht ein anderen Produkt suchen.

TCP-Handshake

Ehe Daten per TCP übertragen werden können, müssen die Partner erst mal eine Verbindung aufbauen. Das Ziel hält dazu unter einer IP-Adresse einen Port offen, auf den sich ein Client verbinden kann. Damit Sie später erkennen können, ob Pakete verloren gegangen sind oder nicht, wird über einen Drei-Wege-Handshake erst mal die Kommunikation gestartet. Dabei werden über einen "SYN" (Synchronize) "Sequenznummern" ausgetauscht, die mit einem "ACK" quittiert und dann je Richtung einfach weiter erhöht werden. Die Verbindung wird dann am Ende wieder geordnet durch einen FIN (Finish)

Es ist dabei gar nicht vorgeschrieben, dass auch Datenübertragen werden müssen. Ein Loadbalancer, der also nur die Erreichbarkeit eines Port prüfen möchte, kann den Drei-Wege-Handshake durchlaufen und am Ende die Verbindung wieder abbauen. Sofern das alles "fehlerfrei" erfolgt, kann der Loadbalancer zumindest davon ausgehen, dass hinter dem TCP-Port auch ein Prozess steckt, der Daten verarbeiten könnte.

Wenn Sie genau hinsehen, dann finden Sie am Ende zwei ACK/FIN - ACK-Sequenzen. Jede Seite kann von sich aus die Verbindung beenden und sollte dies auch tun. Nur weil der Client z.B. nicht mehr senden will und das mit der ersten ACK/FIN-Meldung kund tut, kann der Server ja durchaus noch einige Zeit etwas an den Client zurück senden.

Verkürzter Verbindungsabbau

Durch eine Fehleranalyse bei einem Kunden ist aber der Fall aufgetreten, dass der Loadbalancer immer wieder Fehlermeldungen geworfen hat, dass der "SYN ACK Handshake" nicht zustande gekommen ist. Um diesen Fehler einzukreisen, habe wir wieder den bekannten NetMon 3 zu Hilfe genommen und geschaut, was am Server ankommt und zurück gesendet wird.

Die ersten drei Pakete stellen den bekannten Handshake dar, aber auf den Verbindungsabbau durch den Client 192.168.182.1 auf den Server 192.168.182.2 antwortet der Server direkt mit einem RESET. Scheinbar hat das den Loadbalancer dazu verleitet von einem Fehler auszugehen. Als Ablaufdiagramm sieht dies wie folgt aus:

Das ist ein sehr verkürzter Verbindungsabbau. Normalerweise können wir ein TCP-RESET nur, wenn ein Client einen nicht erreichbaren Port anspricht und der Server dies damit kundtut. Aber anscheinend ist es gar nicht mal so unüblich eine Verbindung so zu beenden und die Ressourcen schnell frei zu geben. Diverse Quellen im Internet kann man dazu zitieren:

RST in response to FIN is an old hack that's still common in http. The concept is basically that http sessions are short-lived, with a single Req/Resp pair (http 1.0). This special case therefore doesn't require TCP's ability to receive data after a FIN is sent, so after the server is done sending the requested content, the browser will send a RST. This bypasses the CLOSE-WAIT and LAST-ACK states on the browser, and triggers the server to bypass the FIN-WAIT-1/FIN-WAIT-2/CLOSING states.
Quelle: https://ask.wireshark.org/questions/13986/why-tcp-reset-sent-after-receive-finack-packet

A TCP probe makes a connection, and if the connection through a 3-way handshake (SYN, SYN-ACK, and ACK) is successful, when the ACE receives FIN-ACK from the server, the server is marked as passed. By default, the ACE terminates a TCP connection gracefully by sending a FIN to the server. … To configure the ACE to terminate a TCP connection by sending an RST, use the connection term command. This command is available für TCP-based connection-oriented probes (ECHO TCP, Finger, FTP, HTTP, HTTPS, IMAP, POP, RTSP, SIP TCP, SMTP, TCP, and Telnet probe configuration modes). The syntax of this command is as follows: “connection term forced”
Quelle_ http://www.cisco.com/c/en/us/td/docs/interfaces_modules/services_modules/ace/vA4_2_0/configuration/
slb/guide/slbcfggd/probe.html#wp1075645

Das letzte Zitat beschreibt z.B. die Einstellung, wie ein Cisco ACE seinerseits beim TCP-Check die Verbindung mit einem RESET beendet. 

WebServer Check

Das Problem habe ich so bei einem höherwertigen Check noch nicht gesehen. Wenn ein Loadbalancer also z.B. einen HTTP-GET nutzt dann findet der 3-Wege Handshake und Datenübertragung statt und am Ende wird die Verbindung abgebaut.

Hier sieht man gut einen HTTP-Get, den ich per PowerShell mit "Invoke-WebRequest" gestartet habe. Man sieht auch, dass der Client die Verbindung danach noch ca. 100 Sekunden "hält", eher diese dann "sauber" abbaut.

Wenn ich aber das PowerShell-Fenster nach dem Ausführen von "Invoke-Webrequest" mit einem Quit schliesse, dann ist das Ende auch hier deutlich abrupter

Der Client sendet gerade noch ein letztes "RESET" zurück, welches aber vom WebServer gar nicht mehr quittiert wird.

Kniffliger kann so ein Check natürlich sein, wenn statt HTTP die SSL-Verschlüsselung genutzt wird. Der Loadbalancer muss dann erst einen TLS-Kanal aushandeln, was natürlich etwas mehr Ressourcen kostet. Im Gegenzug kann er aber auch gleich die Gültigkeit der Zertifikats prüfen.

Zusammenfassung

Der TCP-Handshake, wie er in vielen Quellen als "Referenz" gerne erklärt wird, kommt beim Verbindungsaufbau immer zum Einsatz. Aber das Ende einer TCP-Verbindung ist nicht immer so, wie es in den RFCs und anderen Quellen aufgeführt wird. Ein "schnelles RESET" ist in vielen Fällen sogar die Tagesordnung. Meist ist dies der Client, wenn er schnell beendet wird und letztlich der TCP-Stack dann die Aufräumarbeiten übernimmt. Da der Client schon nicht mehr da ist und daher niemand mehr Daten senden oder gar noch empfangene Daten weiter verarbeiten wird, kann er sich den geordneten Abbau auch sparen.

Interessant war für mich dass ein Webserver (hier der IIS) ebenfalls mit einem RESET die Verbindung abbaut. Das passiert scheinbar immer dann, wenn eine TCP-Connection zwar aufgebaut aber ohne Übertragung von Daten wieder abgebaut werden soll. Darauf gilt es zu achten, wenn ein Load-Balancer mal wieder "nur" einen TCP-Check macht und erst nach dem aus seiner Sicht geordneten Abbau den Server auch als Verfügbar ansieht.

Weitere Links