nwa_gesamt_tcp.pdf
Document Details
Uploaded by Deleted User
Tags
Full Transcript
27 3 Transportschicht TCP 3.1 Einleitung Die Transportschicht hat die Aufgabe, eine zuverlässige Übertragung von Daten zu gewährleisten, unabhängig von den physikalischen Netzen. Sie soll d...
27 3 Transportschicht TCP 3.1 Einleitung Die Transportschicht hat die Aufgabe, eine zuverlässige Übertragung von Daten zu gewährleisten, unabhängig von den physikalischen Netzen. Sie soll der Anwendungsschicht ein effizientes, zuverlässiges Dienstangebot zur Verfügung stellen, sodass die Netzwerk-Anwendungen sich nur um die Verarbeitung der Nutzdaten zu kümmern brauchen aber nicht um deren Aufbereitung oder um Fehlerkorrekturen. Es stehen in der Praxis mit dem Transmission Control Protocol (TCP) und dem User Datagram Protocol (UDP) zwei verschiedene Transportdienste zur Verfügung. UDP ist das wesentlich einfachere dadurch aber auch schnellere Protokoll, das verbindungslos und ohne aufwändige Fehlererkennungsmechanismen arbeitet; es kommt insbesondere bei solchen Anwendungen zum Einsatz, für die Schnelligkeit wichtiger als Zuverlässigkeit ist. TCP ist das wesentlich aufwändigere Protokoll, das den Anwendungen einen fehlerfreien Datenstrom zur Verfügung stellt. Dem TCP- Protokoll kommt im Internet eine besonders wichtige Rolle zu: Einerseits wird die Entwicklung einer Anwendung wesentlich vereinfacht, da sie sich nicht um Funktionen im Netzwerk zu kümmern braucht, sondern nur ihre Daten an der Schnittstelle zur TCP-Instanz abliefern muss, andererseits müssen sich die unteren Schichten nur mit dem technischen Datentransport beschäftigen, z.B. Wegefindung oder technische Signalübertragung. Zusammengefasst ist die Aufgabe der Transportschicht: Bereitstellung eines zuverlässigen Dienstes oberhalb eines unzuverlässigen Netzwerks. A B Anwendung Anwendung TCP TCP IP IP IP IP IP LLC/MAC 2 2 2 2 2 2 LLC/MAC Hardware 1 1 1 1 1 1 Hardware Router 1 Router 2 Router N Abbildung 19 Aus ihrer Sicht kommunizieren die TCP-Prozesse der Rechner A und B direkt miteinander; die tatsächliche technische Kommunikation erfolgt dabei aber immer über Datagramme/Pakete, die den Weg über alle Router nehmen. Die beiden TCP-Prozesse haben jedoch keine Kenntnis von diesem Weg: Sie kennen nicht die einzelnen Router, nicht die Topologie des Netzwerkes, nicht die Entfernungen und auch nicht die verwendete Technik auf den Einzelstrecken. Einerseits ist dies von Vorteil, da die Kommunikation der Rechner A und B vollkommen unabhängig von der eingesetzten Technik funktioniert, andererseits wird die Erfüllung der Hauptaufgabe „Qualitätssicherung“ schwieriger, da oft nur das bloße Vorhandensein von Fehlersituationen festgestellt werden kann, aber nicht deren Ursache. Eine Transportinstanz muss permanent aktiv sein, da jederzeit Daten von einer Anwendung verschickt werden oder über das Netzwerk eintreffen könnten. Das TCP-Protokoll setzt (im Gegensatz zu UDP) einen Verbindungsaufbau voraus bevor Nutzdaten verschickt oder angenommen werden können. Die Adressierung mittels des IP-Protokolls ermöglicht nur die Zuordnung eines Datenpakets zu einem bestimmten Netzwerk-Interface, kann jedoch keine Unterscheidung zwischen den Anwendungen machen. Daher ist eine zusätzliche Adressierung auf der Transport- schicht erforderlich, über die die Daten den einzelnen Anwendungen zugeordnet werden können. Aufgrund der im Internet eingesetzten Datagramm-Technik können Pakete nicht nur beschädigt werden oder verloren gehen, es kann auch die Paketreihenfolge bei der Übertragung durcheinander geraten. TCP muss daher Pakete zwischenspeichern, sortieren und ggf. wiederholt übertragen können. Zudem muss gewährleistet sein, dass ein sendender Rechner die Pakete nicht schneller abschickt als sie der empfangende Rechner aufnehmen und verarbeiten kann. 28 3.2 TCP-Header Um diese Funktionen umzusetzen, müssen zusätzlich zu den Nutzdaten einige Informationen in einem TCP-Paket mitgeliefert werden, die im TCP-Header in jedem Paketes übertragen werden. Quellport (16) Zielport (16) Sequenz-Nummer SEQ (32) Bestätigungs-Nummer ACK (32) RST res. (3) ECE Window-Size (16) NS URG PSH Header-Länge (4) CWR SYN FIN ACK Checksum (16) Urgent-Pointer (16) Optionen... Quellport und Zielport: Adressierung eines TCP-Paketes, um das Paket dem gewünschten Anwendungsprozess zuzuordnen Sequenz-Nummer: eindeutiger Bezeichner für jedes Byte innerhalb eines gesendeten Paketes Bestätigungs-Nummer: Bestätigung/Quittierung des korrekten Empfangs von Bytes Header-Länge: Länge in 32-Bit-Worten, mindestens 5 (20 Byte Standard-Header), max. 15 (mit Options- Headern) nicht genutzter Bereich (3 Bit) Flags NS/CWR/ECE: 3 Bits für Explicit Congestion Notification ECN (Stauvermeidung) Flags: 6 Bits für das Verbindungsmanagement Window-Size: maximale Größe des Pufferspeichers für den Empfang von Daten Checksum: Prüfsumme zur Erkennung von Übertragungsfehlern Urgent-Pointer: Verweis auf eine Byte-Position mit vorrangig zu verarbeitenden Daten 3.3 Verbindungsmanagement 3.3.1 Verbindungsaufbau Der Aufbau einer Verbindung vor der eigentlichen Datenübertragung findet nur beim TCP-Protokoll statt; das UDP- Protokoll arbeitet verbindungslos. Der Verbindungsaufbau erfolgt nach dem Prinzip des 3-Wege-Handschlags, was die Wahrscheinlichkeit des Aufbaus fehlerhafter Verbindungen reduziert. Derjenige Rechner, der die Verbindung zu einer bestimmten Anwendung auf dem Zielrechner aufbauen möchte, schickt zunächst ein TCP-Paket mit gesetztem SYN-Flag an den gewünschten Zielport. Die Adressen der Zielports sind für viele Standard-Anwendungen fest definiert, z.B. Port-Nr. 25 für Mail, Port-Nr. 80 für HTTP, Port-Nr. 22 für SSH, Port-Nr. 23 für Telnet oder Port-Nr. 20 und 21 für FTP. Diese festen Port-Adressen liegen im Bereich bis 1023. Es kann jedoch auch eine Transport-Instanz mit einer beliebigen (freien) Port-Nummer aus dem zur Verfügung stehenden 16-Bit-Adressbereich (max. 65535) gestartet werden, deren Port-Nummer dem aufbauenden Rechner dann jedoch bekannt sein muss. Der Quell-Port wird vom aufbauenden Rechner zufällig gewählt (eine freie Port-Nummer meistens aus dem Bereich größer 32768). Damit das Paket eindeutig identifiziert werden kann, wird außerdem eine zufällige initiale Sequenznummer gesetzt. Ist der Zielport beim empfangenden Rechner offen (d.h. dort läuft ein Anwendungsprozess, der die Daten annehmen und verarbeiten kann), so wird die Anfrage nach einem Verbindungsaufbau positiv bestätigt. Dieser Rechner antwortet hierbei mit einem Paket, in dessen TCP-Header ebenfalls das SYN-Flag gesetzt ist und außerdem das ACK-Flag. In diesem Paket wird die zuvor empfangene Sequenznummer SEQ im ACK-Feld bestätigt, so dass der anfragende Rechner diese Bestätigung seiner Verbindungsanfrage auch zuordnen kann; beim Verbindungsaufbau gilt: ACK = SEQ + 1. Der genau Ablauf des Bestätigungsmechanismus wird in Kapitel 1.3.4 erläutert. In diesem Paket wird als Zielport natürlich der im ersten Paket genannte Quellport verwendet. Sollte der Zielport nicht offen sein, so wird die Verbindungsanfrage mit einem Reset-Paket (RST-Flag im Header ist gesetzt) beantwortet. 29 Mit dem dritten Handschlag wird die positive Bestätigung der Verbindungsanfrage nochmals bestätigt, indem ein Paket mit (nur noch) gesetztem ACK-Flag zurückgeschickt wird; auch hier gilt: ACK = SEQ + 1. Die Verbindung ist nun über die vier Parameter Quell- und Ziel-IP-Adresse sowie Quell- und Ziel-Port eindeutig identifiziert und sie ist im Status „established“. Rechner A Three-Way-Handshake Rechner B 1 Verbindungsanfrage von A an B Es werden hier nur die für diese Darstellung relevanten Header-Felder angegeben Flags=SYN SEQ=500 Length=0 2 Bestätigung von B an A Synchronisations-Flag Paket enthält keine Nutzdaten Von A selbst gewählte zufällige Sequenz-Nummer Flags=SYN | ACK SEQ=99 ACK=501 Length=0 WinSize=240 Bestätigung der Anfrage mit SYN und ACK-Flag Paket enthält keine Nutzdaten Von B selbst gewählte zufällige Sequenz-Nummer Aktuell verfügbarer Platz (in Byte) im Empfangsfenster von B, d.h. diese Bestätigung mit ACK: diese Nummer bezieht sich auf das von A Datenmenge darf A abschicken, ohne gesendete SEQ (hier beim Verbindungsaufbau ausnahmsweise 3 Bestätigung der Bestätigung von A an B ACK=SEQ+1 sonst immer ACK=SEQ+Length mit der Länge des dass ein ACK für zuvor gesendete Pakete eingetroffen ist empfangenen Paketes Flags=ACK SEQ=501 ACK=100 Length=0 WinSize=200 Aktuell verfügbarer Platz (in Byte) im Nächste SEQ-Nummer von A: bezieht sich auf das von A zuvor Empfangsfenster von A, d.h. diese gesendete SEQ (hier beim Verbindungsaufbau ausnahmsweise Datenmenge darf B abschicken, ohne SEQ_neu=SEQ_alt+1 sonst immer SEQ_neu=SEQ_alt+Length dass ein ACK für zuvor gesendete mit der Länge des zuvor gesendeten Paketes) Pakete eingetroffen ist Beim Verbindungsaufbau werden zudem einige weitere Informationen ausgetauscht. Eines der wichtigsten Elemente ist hierbei die so genannte „Window Size“. Diese Fenstergröße bezieht sich auf die Größe des jeweils auf beiden Seiten zur Verfügung stehenden Pufferspeichers. Damit ein sendender Rechner den empfangenden Rechner nicht mit Daten überfluten kann, teilt der empfangende Rechner die Größe seines aktuell für diese Verbindung verfügbaren Pufferspeichers mit. Der sendende Rechner kann nun diese Datenmenge abschicken, ohne dass er befürchten muss, dass Datenpakete deswegen verloren gehen, weil der empfangende Rechner diese Daten nicht schnell genug aufnehmen kann. Dieser Pufferspeicher kann im Laufe einer Verbindung dynamisch verändert werden („Sliding Window“ siehe Kapitel 3.3.4). Video in Moodle: TCP_3-way_audio2020.mp4 3.3.2 Verbindungsabbau Für den Verbindungsabbau wird ebenfalls das Prinzip des 3-Wege-Handschlags angewendet. Statt des SYN-Flags wird hierbei mittels des FIN-Flags die Bereitschaft zum Verbindungsabbau angezeigt. Sind im Laufe einer Verbindung alle Daten zwischen den beiden Rechnern ausgetauscht worden und es soll nun die Verbindung beendet werden, so ist der Ablauf des Abbaus einfach: FIN → FIN/ACK → ACK. Der Verbindungsstatus wechselt dann in den Status „Time Wait“: Die Verbindung ist zwar korrekt beendet, aber die Pufferspeicher bleiben trotzdem noch für einige Zeit aktiv, denn es ist möglich, dass noch duplizierte oder verspätete Pakete aus dieser Verbindung „unterwegs sind“. Würden alle Puffer und Parameter einer Verbindung sofort nach deren Beendigung freigegeben werden, so könnten in ungünstigen Fällen verspätete Pakete aus alten Verbindungen in neue Verbindungen (mit den gleichen Parametern) einfließen und dort erhebliche Störungen verursachen. Es ist jedoch zu berücksichtigen, dass der Datenaustausch in beide Richtungen läuft, da eine TCP-Verbindung immer voll-duplex ist. Hat einer der beiden beteiligten Rechner alle Daten abgeschickt, so kann er nicht einfach die Verbindung beenden, da davon auszugehen ist, dass der andere Rechner seinerseits noch Daten zurückschicken möchte. Derjenige Rechner, der die Verbindung beenden möchte, teilt diesen Wunsch der Gegenseite lediglich mit, die diesen Abbauwunsch aber nur mit einem ACK bestätigt. Erst dann wenn auch die Gegenseite die Verbindung abbauen kann, antwortet sie mit einem FIN/ACK. 30 3.3.3 Datenübertragungsphase Während der Datenübertragungsphase werden die eintreffenden Pakete im Empfangspuffer gespeichert, auf Korrektheit überprüft und dann – in der richtigen Reihenfolge – an die Anwendung weitergegeben. In diesem Abschnitt wird nur die Grundfunktion des Bestätigungsmechanismus behandelt. Weitere Funktionen, insbesondere das Verhalten im Fehlerfall, werden in späteren Kapiteln erläutert. Nach dem erfolgreichen Aufbau einer Verbindung können beide Seiten Datenpakete abschicken. Die maximale Größe eines Datenpakets ist durch die maximale Nutzdatenmenge eines IP-Paketes auf 64 kB begrenzt. I.d.R. wird eine Nutzdatenmenge von 1500 Byte (einschließlich IP- und TCP-Header) nicht überschritten, da dies die so genannte MTU (Max. Transmission Unit) im Ethernet ist. Man vermeidet damit aufwändige Fragmentierungs- prozesse. Jedes abgeschickte Datenpaket bleibt zunächst in einem Sendepuffer gespeichert; denn im Fehlerfall (beschädigtes oder verloren gegangenes Paket) müssen diese Daten ggf. erneut übertragen werden. Erst wenn ein Paket, bzw. genauer ausgedrückt, eine bestimmte Datenmenge vom Empfänger positiv bestätigt wurde, können die Daten aus dem Sendepuffer entfernt werden. S R t i a uc e o i t h n : n T r eP C -e VA i b r d n n u g t s i u a g f b e u a , t k a e u t e l S Q E A ( = ) 0 5 , 0 E S Q ( B ) = 1 0 N. r u R c e R n h r e c eA n h h c s c i r e t k B e k a P e t m N t i u d z t t a n e , R D ( c e e i h n e s r e D B r a e b e t s ä t s u l g i tg n d t b e i s e e s h c u n ä r. r k n W s t i h c i d n a w of u z i S d i v e e hn o e i B r : e lW S a v t n= 0 8 n e T C P-H e d a r e -F e d l r e ) S Q E 5 = 0 D C A e i K L n ä 1 = e g0 L a k n W u aS g f 2 =u r 4 0d n d r e WL n i8 = d0o w z i S e W S 8 = 0 m a x. 8 0 y B t e e b a r t g e n E S = Q 0 1 0 A C K = 8 5 0 W = S 8 0 L 0 = b B e s ä t g i t d t s a o v n A m e f p n a e g e n P k a t e S Q E 5 = 0 8 C A K 1 = 0 W S 2 = 0 4 L 6 = 5 i m A t K C = E S A ( Q ) + ä L g n : e C A K = 5 0 8 + 0 D g i s e e n e u d E S n e t Q P w k a t e d r i s u h r e m ö e i d : t h L n ä e g d s e u z o v r S Q E n _ u e =SE Q _ l a + t n ä L g e : E S Q n _ u e = 0 5 + 0 8 0 B e h r h öE S t s = Qn i e 0 1e 0 E S Q c i n A t h C d , = K d a 4 6 e i ä L 5 g n e W = S 0 8 L = 0 E S Q 6 = 5 4 C A = K 0 1 0 W S 2 = 0 4 = L 7 5 z v u r o L = 0 w r a m B A t i e b C ä t s = K g i t S t E Q ( a d A ) v s L + n o ä n A e g m : p A a f K C g n 5 = n e 0 8 P e +k a 5 6 t e i D e g E S n e s _ Q d n u e t e u = n e E S S a P QQ E i w e k _ d r e t t l a m u e sL + d h r n ä e i h ö e g : ä L : tE S g n_ Q ee n e du 5 = z s 0 8 v u + r o 5 6 Abbildung 20 In diesem Beispiel wurde Rechner A von Rechner B zuvor z.B. beim Verbindungsaufbau eine Window Size von 80 Byte mitgeteilt, sodass der Sendepuffer von A und der Empfangspuffer von B genau diese Größe besitzen. Umgekehrt setzt Rechner A die Größe seines Empfangspuffers auf 240 Byte, entsprechend hat das Sendefenster von Rechner B genau diese Größe (dies ist hier nicht relevant). Die Größen der beiden Sende- bzw. Empfangs- fenster sind also unabhängig voneinander. Rechner A lädt in diesem Beispiel eine Datenmenge von 80 Byte in seinen Sendepuffer und schickt ein entsprechendes Paket hier mit der Sequenznummer SEQ=500 ab; die Daten bleiben zunächst im Sendepuffer gespeichert. Nach dem Eintreffen des Paketes bei Rechner B wird die Korrektheit mittels der Checksum im TCP-Header überprüft und dann eine Bestätigung (gesetztes ACK-Flag) zurückgeschickt. Der ACK-Wert berechnet sich aus der Sequenznummer und der Länge der Nutzdaten im empfangenen Paket, also ACK=SEQ+L, hier ACK=500+80=580. Der Sender A weiß nun, dass alle Daten (Bytes) bis einschließlich der Sequenznummer 579 korrekt beim Empfänger B eingetroffen sind und somit auch aus dem Sendepuffer gelöscht werden können; die Sequenznummer des nächsten Paketes ist SEQ=580. Der Vorteil der Nummerierung einzelner Bytes statt ganzer Pakete ist, dass der Bestätigungsmechanismus nicht an willkürliche Paketgrenzen gebunden ist und es somit möglich ist, beliebige Byte-Mengen zu bestätigen (auch Teilbereiche oder zusammengefasste Bereiche). Video in Moodle: TCP_SEQ_ACK_audio2020.mp4 31 3.3.4 Flussteuerung: Sliding Window Nach der positiven Bestätigung einer bestimmten Datenmenge kann diese aus dem Sendepuffer gelöscht werden. Würde jedoch ein sendender Rechner nach dem Absenden eines Datenpaketes erst auf die Bestätigung warten (Stop-and-Wait-Verfahren, siehe Abb. 21) bevor neue Daten versendet werden, so würde kein kontinuierlicher Datenfluss entstehen und die verfügbare Bandbreite würde nicht ausgenutzt werden. Sender Empfänger 3 Byte in das Sendefenster Sendefenster laden und abschicken, SEQ 5, L=3 dann warten Empfangsfenster Daten prüfen, an die Anwendung weitergeben, SEQ 5, L=3 Bestätigung senden ACK=5+3=8 (SEQ+L) ACK 8 und Empfangspuffer löschen Nach positiver Bestätigung: Daten aus dem Sendepuffer löschen Neue Daten in das SEQ 8, L=3 Sendefenster laden und abschicken Daten prüfen, an die Anwendung weitergeben, Bestätigung senden SEQ 8, L=3 ACK=8+3=11 (SEQ+L) und Empfangspuffer löschen ACK 11 SEQ 11, L=3 Zeit Abbildung 21: Stop-and-Wait Andererseits kann der sendende Rechner auch nicht beliebig schnell Daten absenden, da er damit einen langsamen Empfänger mit Daten überfluten würde. Daher setzt der sendende Rechner die Größe seines Sendepuffers auf die Größe des Wertes der Window Size, mit dem der Empfänger mitteilt, wie viele Daten er in seinem Empfangspuffer garantiert abspeichern kann. Der Sender kann nun alle Daten aus seinem Sendepuffer abschicken, da sichergestellt ist, dass der Empfänger diese Datenmenge auf jeden Fall in seinem Empfangspuffer aufnehmen kann. Sender Empfänger Sendefenster SEQ 5, L=3 Empfangsfenster SEQ 5, L=3 SEQ 5, L=3 SEQ 8, L=4 SEQ 8, L=4 SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=2 SEQ 12, L=2 SEQ 8, L=4 SEQ 12, L=2 SEQ 14, L=3 SEQ 12, L=2 SEQ 14, L=3 SEQ 17, L=2 Zeit Abbildung 22: Sliding-Window 32 In Abbildung 22 ist dargestellt, wie der Sender Daten in sein Sendefenster lädt und abschickt, dann weitere Daten lädt usw. obwohl noch keine Bestätigung des Empfängers eingetroffen ist. Erst wenn der Sendepuffer vollständig gefüllt ist, muss der Sender anhalten. In diesem Beispiel trifft jedoch zu diesem Zeitpunkt die Bestätigung (ACK 8) des ersten Paktes (SEQ 5) ein, sodass dieses Paket aus dem Sendepuffer entfernt werden kann und neue Daten (SEQ 14) geladen und abgeschickt werden können. Wieder ist der Sendepuffer voll, aber da nun die nächste Bestätigung (ACK 12) eintrifft, kann Paket SEQ 8 gelöscht werden usw. In diesem Beispiel wird davon ausgegangen, dass der Empfänger die Daten prüft und sofort an die Anwendung weiterleitet. Das Empfangsfenster ist also bereits wieder leer, wenn die Bestätigung abgeschickt wird. Die Größe des Fensters (Window Size) bleibt daher immer gleich. Kann der Empfänger die Daten jedoch nicht sofort weitergeben, weil die Anwendung zurzeit keine Daten annehmen kann oder die CPU anderweitig beschäftigt ist, so müssen die Daten zunächst im Empfangspuffer gespeichert bleiben (siehe Abb. 23). Dadurch verkleinert sich aber die aktuell zur Verfügung stehende Window Size: Der hardware-seitig reservierte Speicher ist durch das im Puffer befindliche Paket teilweise belegt. Der Sender darf nun natürlich nicht mehr so viele Daten wie zuvor unbestätigt verschicken, denn dann würde der jetzt noch verfügbare Speicherplatz nicht mehr ausreichen. Der Empfänger muss also diese verkleinerte Window Size dem Sender mitteilen. Sender Empfänger Sendefenster SEQ 5, L=3 Empfangsfenster SEQ 5, L=3 SEQ 5, L=3 SEQ 8, L=4 SEQ 5, L=3 SEQ 8, L=4 SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=2 SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=2 SEQ 8, L=4 SEQ 12, L=2 SEQ 12, L=2 Zeit Abbildung 23: Sliding Window Ursprünglich hatte die Window Size in diesem Beispiel eine Größe von 9 Byte. Mit der Bestätigung des ersten Pakets (ACK 8) muss die Window Size um 3 Byte verkleinert werden, da die Daten zunächst im Speicher verbleiben müssen. Dies muss dem Sender mitgeteilt werden, indem der Empfänger seinen Wert der WinSize im TCP-Header auf 6 Byte verkleinert. Dies hat zur Folge, dass der Sender zwar das Paket SEQ 5 aus seinem Puffer löscht, aber gleichzeitig die Größe seines Sendepuffers um diese 3 Byte verkleinert und somit keine weiteren Daten senden kann. Letztlich kann die Window Size auf null gesetzt werden, sodass der Datenfluss zum Stillstand kommt. Erst wenn der Empfänger einige Daten aus dem Empfangspuffer verarbeitet hat, wird in einem weiteren Bestätigungs- paket (wobei die vorherige ACK-Nummer erneut verwendet wird) eine neue, vergrößerte Window Size übermittelt und der Sender kann neue Daten laden und abschicken. Video in Moodle: TCP_Sliding_Window_audio2020.mp4 und sliding_window.mp4 3.3.5 ACK-Delay, Silly-Window und Nagle-Algorithmus Das zuvor beschriebene Verhalten kann zwei unerwünschte Effekte erzeugen: zum einen werden durch das ständige Ändern der Window Size viele rein administrative Pakete (also ohne Nutzdaten) verschickt, zum anderen führt eine sehr kleine Window Size dazu, dass sehr kleine Pakete mit wenig Nutzdateninhalt erzeugt werden. Betrachtet man folgende einfache Situation (siehe Abb. 24): das empfangene Paket wird geprüft und (sofern das Paket in Ordnung ist) eine Bestätigung abgeschickt. Das Paket verbleibt jedoch zunächst im Puffer, sodass in dieser Bestätigung die Window Size um die Größe des Paketes verringert wird. Kurze Zeit später nimmt die Anwendung die Daten ab und das Paket kann aus dem Puffer gelöscht werden. Nun ist der Puffer wieder frei (hat also wieder 33 die ursprüngliche Größe), sodass dieses dem Sender mitgeteilt werden muss. Es wird daher ein erneutes Bestätigungspaket mit der wieder vergrößerten Window Size gesendet, wobei der vorherige ACK-Wert nochmals Empfänger Empfangsfenster SEQ 5, L=3 Ursprüngliche WinSize=9 Nach dem Empfang des Paketes: WinSize=6 ACK=8, WinSize=6, L=0 Das Paket wird an die Anwendung abgegeben: neue WinSize=9 Erneutes ACK mit dieser wieder ACK=8, WinSize=9, L=0 vergrößerten WinSize Abbildung 24: ohne ACK-Delay verwendet wird. Da mit jedem Paket ein IP- und ein TCP-Header verbunden ist, die jeweils eine Mindestgröße (ohne Optionen) von jeweils 20 Byte haben, so würden in diesem Beispiel 3 Byte Nutzdaten gesendet mit insgesamt 120 Byte Protokoll-Overhead (das gesendete Paket und zwei Bestätigungen mit je 40 Byte Protokoll- Header). Diesen ständigen Wechsel der Window Size kann man in vielen Situationen verhindern, indem das Senden der ersten Bestätigung kurz verzögert wird (ACK-Delay). Denn oftmals ist der Anwendungsprozess gar nicht langfristig blockiert, sondern kann die Daten kurze Zeit nach dem Absenden des ersten ACK bereits abnehmen. Allerdings ist zu beachten, dass dieser ACK-Delay die Round Trip Time RTT (also die Zeit zwischen Absenden eines Paketes und Empfang der Bestätigung) erhöht und damit die Gesamt-Übertragungsrate (insbesondere in schnellen Netzen) verringert. ACK-Delay wird daher nicht verwendet (abhängig von der TCP-Implementation im Betriebs- system), wenn das sich der Füllgrad des Empfangsfensters schnell verändert (d.h. bei „gut gefülltem“ Empfangs- fenster wird sofort ein ACK gesendet). Eine weitere Schwierigkeit mit der Fenstergröße wird in Abb. 23 deutlich: Durch die Überlastsituation beim Empfänger wird die Window Size auf null gesetzt und der Sender kann keine Daten mehr abschicken. Geht man davon aus, dass dann der Empfänger langsam wieder Daten an die Anwendung weitergibt, wird Platz im Empfangspuffer frei, was dem Sender mit einer Erhöhung der Window Size mitgeteilt wird. Dieser lädt daraufhin sofort neue Daten in den Sendepuffer und schickt ein Paket ab. Nun wird der Empfangspuffer wieder auf null gesetzt. In einer solchen Situation würde die Fenstergröße also ständig von null auf einen kleinen Wert springen und sofort wieder auf null gesetzt werden (sog. Silly-Window-Syndrom), mit der Folge, dass viele sehr kleine Pakete verschickt werden würden (großer Protokoll-Overhead). Dies kann man verhindern, indem das Empfangs- fenster erst dann von null aus auf einen größeren Wert gesetzt wird, wenn mindestens wieder eine MSS (Maximum Segment Size) im Pufferspeicher zur Verfügung steht (Silly-Window-Avoidence). Einen ähnlichen Ansatz verfolgt der Nagle-Algorithmus: Übergibt eine Anwendung sehr langsam Daten an den Sendepuffer, würden viele sehr kleine Pakete (also mit wenig Nutzdateninhalt und somit hohem Protokoll- Overhead) erzeugt werden. Mit aktiviertem Nagle-Algorithmus sammelt der Sender daher zunächst eine gewisse Datenmenge (meist 1 MSS) bevor ein Paket verschickt wird. Trifft während des Wartens jedoch ein ACK vom Empfänger ein, wird sofort das nächste Paket verschickt, um den Kommunikationsablauf nicht zu behindern. Bei Anwendungen, die prinzipbedingt mit sehr kleinen Datenmengen arbeiten, wird dieses Verhalten abgeschaltet, ebenso (selbstverständlich) bei gesetztem Push-Flag. 34 4 TCP-Funktionen 4.1 MTU und MSS Die Maximum Transmission Unit MTU bezeichnet die größte von der Netzwerk-Hardware am Stück transportier- bare Datenmenge; sie beträgt im normalen Ethernet 1500 Byte. Hinzu kommt der Frame-Header mit 18 Byte bzw. bei VLAN-Tagging 22 Byte. Daraus bestimmt ein sendender Rechner die Maximum Segment Size MSS, z.B. beim TCP-Protokoll: MSS = MTU – IP_Header – TCP_Header z.B. MSS = 1500 – 20 – 20 = 1460 Byte Nutzdaten im TCP-Paket bei IPv4. Enthält der TCP-Header Options-Felder, so müssen diese zusätzlich berücksichtigt werden (z.B. die häufig verwendete Timestamp-Option mit 10 Byte zzgl. 2 Byte NoOperational-Feld). Bei DSL-Verbindungen fallen weitere 8 Byte für das PPPoE-Protokoll an, die bei der Berechnung der MSS zusätzlich abzuziehen sind. Da die MTU hardware-abhängig ist, kann ein Rechner direkt nur die MTU des eigenen LANs ermitteln. Bauen zwei Rechner eine Verbindung auf, so wird die lokal bestimmte MSS beim 3-Wege-Handshake (also nur im SYN- bzw. SYN/ACK-Paket) dem Kommunikationspartner bekanntgegeben, sodass sich beide darauf einstellen können. Liegen jedoch auf einem Pfad noch weitere Netzwerke zwischen Sender und Empfänger, so sind die MTUs dieser Netzwerke „auf dem Pfad“ nicht ersichtlich. Wird bspw. ein TCP-Paket mit 1460 Byte Nutzdateninhalt abgeschickt, da es die MSS beim Sender selbst und auch beim Empfänger zulässt, und trifft dieses Paket auf seinem Weg zum Ziel auf ein Netzwerk mit geringerer MTU, so kann es nur dann weitergeleitet werden, wenn es automatisch in kleinere Einheiten zerlegt wird. Diese Fragmentierung muss durch die Router auf dem Pfad erfolgen, was bei IPv4- Paketen möglich ist, bei IPv6 jedoch nicht. 4.2 MTU Path Discovery Bei IPv4 ist die Fragmentierung im Pfad problemlos möglich. Nachteil ist jedoch der aufwändige Fragmentierungs- und Reassemblierungs-Prozess. Bei IPv6 gibt es die Funktion der Fragmentierung nur auf dem Quellrechner, d.h. ein Router auf dem Pfad darf ein zu großes IPv6-Paket nicht fragmentieren und müsste folglich eine Destination- unreachable-Nachricht an den Quellrechner schicken. Daher ist bei IPv4 die Funktion des MTU Path Discovery lediglich wünschenswert, während sie bei IPv6 zwingend notwendig ist. MTU Path Discovery bestimmt die kleinste MTU auf dem gesamten Pfad vom Quell- zum Zielrechner. MTU Path Discovery bei IPv4 Trifft ein IPv4-Paket auf ein Netzwerk mit zu kleiner MTU, so wird der für dieses Netzwerk zuständige Router das Paket automatisch fragmentieren, also in kleineren, passenden Einheiten weiterschicken. Der Zielrechner wird die so zerlegten Pakete wieder zusammensetzen. Ist jedoch das „Don't Fragment Bit“ im IP-Header gesetzt, so darf der Router nicht fragmentieren und schickt eine ICMP-Meldung zurück an den Quellrechner: ICMP Typ 3, Code 4 „Destination unreachable – Fragmentation needed“, die auch den MTU-Wert desjenigen Netzwerkes enthält, bei dem das Problem aufgetreten ist. Der Quellrechner kann nun entscheiden, ob das Ziel unerreichbar bleibt, ob er auf das „Don't Fragment Bit“ verzichtet oder ob er die Pakete selbst fragmentieren möchte. Damit dieses Problem nicht für jedes gesendete Paket immer wieder auftritt, speichert der Quellrechner den MTU- Wert temporär in seinem Kernel-Routing-Cache für den spezifischen Zielrechner, abzurufen mit ip route get MTU Path Discovery bei IPv6 Bei IPv6 ist die Funktion einer Fragmentierung im Pfad nicht vorgesehen, weshalb ein Paket bei zu kleiner MTU nicht weitergeleitet werden kann. Derjenige Router bei dem das Problem auftritt, schickt eine ICMPv6-Meldung an den Quellrechner: ICMPv6 Typ2 „Packet-too-big“ Nun fragmentiert der Quellrechner selbst alle folgenden Pakete mit derjenigen maximalen MTU, die in dem ICMPv6-Paket übermittelt wurde. Dieser Wert wird für ca. 10 Minuten im lokalen Kernel-Routing-Cache gespeichert (abzurufen mit ip -6 route get ). Die minimale erlaubte MTU bei IPv6 beträgt 1280 Byte, bei kleinerer MTU ist ein Netzwerk nicht IPv6-fähig. Ein Routingprotokoll wie bspw. RIPng würde in diesem Fall eine Ungültig-Meldung (Metrik 16) verschicken. Video in Moodle: mtu_mss_fragmentierung.mp4 35 4.3 Window Size Scaling Der TCP-Header definiert ein 16-Bit-Feld für die Fenstergröße, sodass maximal 2 16 Byte = 65535 B = 64 kB im Sende- bzw. Empfangsfenster gespeichert werden können; dies entspricht 524288 Bit. Die minimale Window Size, um optimalerweise einen ununterbrochenen Datenfluss mittels Sliding Window zu erreichen, berechnet sich zu minWinSize = RTT * Linkspeed Bei einer Übertragungsrate von 1 Gbps könnte selbst die maximal mögliche Fenstergröße nach nur 0,5 ms gefüllt sein. Trifft innerhalb dieser Zeit kein ACK ein, so muss die Übertragung angehalten werden. Das TCP-Basis-Protokoll wäre damit nicht mehr in der Lage, mit aktueller Netzwerktechnik einen kontinuierlichen Datenfluss zu gewähr- leisten, denn eine Round Trip Time RTT von weniger als 1 ms ist nur in lokalen Netzen mit geringer Latenzzeit erreichbar. Weitverkehrsnetze können allein aufgrund der physikalischen Signallaufzeit bereits Latenzzeiten von weit mehr als 100 ms haben (mit dieser Umlaufverzögerung könnte das Basis-TCP eine Übertragungsrate von max. 5 Mbps bedienen). Mit der TCP-Option „Window Scaling“ kann diese Fenstergröße theoretisch auf 2 32 Byte erhöht werden (das ist der Wert, der über die SEQs maximal adressierbar wäre), praktisch ist eine Fenstergröße von 1 GB (2 30 Byte) möglich. Dieser Options-Header enthält einen Wert n „Shift Count“, mit dem die originale Window Size „bitweise links geshiftet“ wird. Der TCP-Header-Wert Window Size wird also nur indirekt verwendet, die tatsächliche Window Size ergibt sich aus tatsächliche_WinSize = Header_WinSize * 2n Der kleinste zulässige Wert ist 0, was bedeutet, dass der sendende Rechner das Window-Scaling zwar grundsätzlich unterstützt, aber bei der aktuellen TCP-Verbindung nicht nutzen möchte; der größte Wert ist 14, was zu der maximalen Fenstergröße von 216 * 214 = 230 Byte führt. Die Option kann nur in Verbindung mit SYN-Flags verwendet werden, kann also nur einmal beim Verbindungsaufbau (einzeln für jede Seite der Verbindung) festgelegt werden. Für die initiale Fenstergröße beim Verbindungsaufbau wird dieser Faktor aber noch nicht genutzt. Für die ersten nach dem 3-Wege-Handshake gesendeten Pakete gilt daher die maximale Fenstergröße von 64 kB, erst die erste Bestätigung des Empfängers enthält eine Window Size, die mit dem Scaling-Faktor multipliziert wird. 4.4 RTT, RTO und Timestamps Für TCP-Verbindungen ist die Bestimmung des Retransmission TimeOut (RTO) von großer Wichtigkeit. Der RTO gibt diejenige Zeit an, nach der ein Paket erneut gesendet wird, falls keine Bestätigung des Empfängers eintrifft. Ist dieser Wert zu groß, so würde ein Sender unnötig lange warten, bevor ein Paket erneut gesendet wird. Im Falle von Paketverlusten würde damit der Durchsatz erheblich reduziert werden. Ist dieser Wert dagegen zu klein, so würde eine erneute Absendung eines Paketes ausgelöst, obwohl aufgrund einer großen Umlaufverzögerung (Round Trip Time RTT) eine Bestätigung noch gar nicht angekommen sein konnte. Es würden also unnötige Paket- Duplikate gesendet werden. Ohne die Timestamp-Option (s.u.) muss eine TCP-Implementation beim Senden eines Paketes einen Timer starten und diesen nach dem Empfang des dazugehörigen ACK wieder stoppen. Aus dieser aktuell gemessenen Umlaufzeit TRTT kann dann nach folgender Formel ein gemittelter RTT-Wert für das aktuelle Paket (Index i) bestimmt werden: TS,i = α · TS,i-1 + (1 - α) · TRTT wobei die zuvor berechnete, gemittelte Umlaufverzögerung TS,i-1 mit 90% gewichtet wird (implementierungs- abhängiger Faktor α = 0,9) und die aktuell gemessene RTT mit 10%. Daraus wird der aktuell gültige RTO-Wert berechnet: TRTO = min(TO , max(TU , β · TS,i)) mit implementierungs-abhängigen Werten für den Faktor β (oft β=2), eine Obergrenze T O und eine Untergrenze TU (heute oft 200 ms, sodass auch bei sehr kleinen RTTs in schnellen LANs i.d.R. mindestens 200 ms gewartet wird, bis ein Paket bei ausbleibender Bestätigung erneut gesendet wird). In der Praxis wäre es aus Effizienzgründen jedoch kaum möglich, bei jedem einzelnen versendeten Paket eine RTT- Messung zu starten. Daher wird bei den meisten TCP-Implementierungen nur eine Messung pro Fenster (Window) durchgeführt. Bei kleinen Fenstern (ohne Window-Scaling) erhält man damit noch gute RTT-Abschätzungen, bei sehr großen Fenstern (zwingend notwendig bei schnellen Netzen mit hoher Latenz) ist dies oft nicht der Fall. Zudem kann es vorkommen, dass die RTT-Abschätzung völlig versagt, mit entsprechend negativen Auswirkungen auf den RTO und damit auf den Durchsatz bei Paketverlusten und bzgl. der Stauvermeidungs-Strategien. Beispielsweise kann bei Paketverlusten und den daraufhin zurückgeschickten doppelten oder mehrfachen ACKs ein Sender gar nicht feststellen, welches der ACKs sich auf welches gesendete Paket bezieht: Im folgenden Beispiel 36 geht Paket SEQ 8 verloren; wurde für dieses oder eines der darauf folgenden Pakete eine RTT-Messung gestartet, so ist für den Sender nicht feststellbar, welches der ACK 8 sich auf welches Paket bezieht. Sender Empfänger SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 ACK 8 ACK 8 ACK 8 Um solche Schwierigkeiten zu vermeiden, wurde der TCP-Options-Header „Timestamp“ (10 Byte, zusätzlich zum 20-Byte-Standard-Header) eingeführt. Für diese Zeitangabe wird beim Booten des Rechners ein Timer gestartet und (heute bei den meisten Betriebssystemen) in Millisekunden hochgezählt; sie basiert also nicht auf der aktuellen System-Uhrzeit. Der Timestamp-Header besteht aus zwei 4-Byte-Zeitstempeln: TS Value (TSval, aktueller TS des Absenders eines Paketes) und TS Echo Reply (TSecr, Übernahme des TSval aus einem zuvor empfangenen Paket). Hinzu kommt je ein Byte, das diesen Optionstyp (Nr. 8) anzeigt, und die Länge dieses Headers. Da TCP die Teil- barkeit des Headers durch 32 Bit bzw. 4 Byte verlangt, muss (sofern der Timestamp der einzige Options-Header ist) ein Padding durch zwei 1-Byte große NOP-Header (No Operational) erfolgen. Timestamps dienen zur effizienteren und sichereren Messung der Round Trip Time (RTT). Mit dieser Option braucht eine TCP-Implementation zur Messung der RTT keinen aufwändigen Timer zu starten, sondern lediglich eine Differenzbildung zweier Zahlen durchzuführen. Einem gesendeten Paket wird mit dieser Option der aktuelle Timestamp-Wert des Betriebssystems im Headerfeld TSval beigefügt. Der empfangende Rechner fügt diesen Wert in das ACK-Paket im Headerfeld TSecr ein, sodass nach Empfang dieses ACK aus dem TSecr-Wert und dem in diesem Moment gültigen Timestamp-Wert einfach nur die Differenz gebildet werden muss, um die aktuelle Umlaufverzögerung zu bestimmen. Diese RTT-Messung wird allerdings nur dann durchgeführt, wenn ein Paket sich auf neue Daten bezieht; ein „reines“ ACK-Paket, das selbst keine Nutzdaten enthält, wird gar nicht mehr beantwortet, sodass ein TSecr-Wert, der sich auf dieses Paket bezieht, zu einem eher zufälligen Zeitpunkt gesendet wird und damit keine Basis für eine RTT-Messung bietet. Aus einem einzelnen TSecr kann die RTT nur mit einer bestimmten Genauigkeit gemessen werden (das Zeitintervall (heute üblich: 1 ms), in dem der Timestamp-Wert im Betriebssystem hochgezählt wird), also entweder 0 ms, falls der TSecr-Wert genau dem aktuellen Timestamp-Wert entspricht, oder 1 ms falls der aktuelle TS um 1 hochgezählt wurde. Aus einer Mittelung mehrerer Messungen können aber auch kleinere Werte berechnet werden (z.B. 3 Pakete mit TSecr – akt_TS = 0 und 1 Paket mit TSecr – akt_TS = 1 ergibt eine RTT von 0,25 ms). Das oben skizzierte Problem tritt bei Verwendung von Timestamps nicht auf, da sich trotz des doppelten ACK der Timestamp-Wert auf das richtige Paket bezieht. Hätte beispielsweise das Paket SEQ 12 den TSval=37 so würde trotz des doppelten ACK 8 für dieses Paket der richtige Wert TSecr=37 in das ACK-Paket eingefügt werden. Außerdem wären ohne Timestamps keine effizienteren ACK-Mechanismen möglich. Beispielsweise verhindert ACK-Delay nicht nur den dauernden Wechsel der WinSize sondern ermöglicht durch die kurze Wartezeit vor dem Senden des ACK auch das zusammengefasste Bestätigen mehrerer kurz hintereinander eintreffender Pakete. Bei Funktionen wie Generic Receive Offload stehen zudem die Paket-Einheiten im Sendefenster in keinem direkten Zusammenhang mehr zu den Paket-Einheiten im Empfangsfenster. Dieses Verhalten muss der Sender bei der RTO-Berechnung aber berücksichtigen. Folgendes Beispiel (Abb. 25) soll diese Problematik verdeutlichen. Sendefenster SEQ 5, L=3, SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 TSval=1 TSval=3 TSval=6 TSval=8 Empfangsfenster SEQ 5, L=3 SEQ 8, L=7 SEQ 15, L=2 ACK 8, ACK 15, ACK 17, TSecr=1 TSecr=6 TSecr=8 Abbildung 25: Timestamps bei Generic Receive Offload 37 Der Sender berechnet aus den zurückgelieferten TSecr-Werten und seinem aktuellen Timestamp-Wert die RTT: aktueller TS beim 6 11 13 Eintreffen des ACK, z.B. – TSecr 1 6 8 = RTT 5 5 5 Die Pakete SEQ 8 und SEQ 12 werden zusammen im ACK 15 bestätigt. Der TSecr-Wert 6 im ACK 15 ist hier allerdings nicht geeignet gesetzt, es ergibt sich daher ein zu kleiner RTO. Grund: Der RTO-Timer für Paket SEQ 8 wird zum Zeitpunkt TS=3 gestartet, er soll hier im Beispiel der Einfachheit halber gleich der RTT sein, also RTO=5. Zum Zeitpunkt TS=8 würde der RTO bereits ablaufen. Da SEQ 8 aber erst zusammen mit SEQ 12 bestätigt wird, kommt das entsprechende ACK erst zum Zeitpunkt TS=11 an und Paket SEQ 8 wäre bereits erneut gesendet worden. Bei diesem ACK-Verhalten muss daher der Empfänger immer den TSval- Wert des frühesten Paketes als TSecr verwenden. Hinweis: In diesem Beispiel würde dies natürlich nichts mehr bewirken, dieses Verhalten wäre im gesamten Kommunikationsverlauf erforderlich, um bereits zu einem früheren Zeitpunkt auf geeignete RTO-Werte zu kommen. Timestamps in Stausituationen Wie im vorangegangenen Beispiel gesehen, ist es nicht immer die beste Wahl, denjenigen TSval zum Sender zurückzuschicken, der sich auf das aktuellste Paket bezieht, da hiermit unrealistisch kleine RTTs bestimmt werden könnten. Ähnliches gilt in Stausituationen. Im folgenden Beispiel soll die Funktion „Fast Retransmit“ dafür sorgen, dass bei einzelnen Paketverlusten nicht erst der RTO-Ablauf abgewartet werden muss, sondern schneller eine erneute Sendung eines verlorenen Paketes ausgelöst wird (zudem soll vermieden werden, dass der RTO überhaupt abläuft, da dies bei vielen Stauvermeidungsfunktionen zu einem sehr starken Rückgang der Übertragungsrate führt). Angenommen, es geht ein Paket verloren, die drei folgenden kommen aber an (siehe Abb. 26). Es würde nun dreimal das gleiche ACK an den Sender geschickt werden. Fast Retransmit (siehe Kapitel 4.5.3) sorgt nun in dieser Situation dafür, dass der Sender zunächst nur ein einziges (nämlich das vermutlich verlorene) Paket erneut abschickt und dann auf das nächste ACK wartet. Ist dies ein zusammengefasstes ACK für alle Pakete (das verlorene und die danach korrekt eingetroffenen), kann der Sender an genau dieser Stelle fortfahren und braucht zum einen nicht alle Pakete erneut zu übertragen, zum anderen läuft kein RTO ab. Sendefenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 Empfangsfenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 ACK 8 ACK 8 ACK 8 ACK 8 Sendefenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 erneutes Absenden (nur) von SEQ 8 Empfangsfenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 ACK 19 Abbildung 26: Timestamps in Stausituationen 38 Bei diesem Fast Retransmit ist es bzgl. des Timestamps nun aber nicht sinnvoll, den TSval aus Paket SEQ 17 als TSecr zu übernehmen, sondern besser den Wert aus Paket SEQ 8, denn diese Differenz zum aktuellen TS des Senders ist der in dieser Situation der realistischere RTT-Wert, außerdem sollte hier der RTT besser über- als unterabgeschätzt werden, denn Fast Retransmit soll ja gerade den RTO-Ablauf verhindern. Timestamps und das Problem der „Wrapped SEQ-No.“ Bei schnellen Netzen mit großen Latenzzeiten (das betrifft alle aktuellen Hochgeschwindigkeits-LANs) kann das Problem entstehen, dass sich innerhalb eines realistischen zeitlichen Rahmens Sequenznummern wiederholen, d.h. es können realistisch ein älteres (sich aber noch aktiv in der Pipeline befindliches) und ein aktuelles Paket dieselbe Sequenznummer tragen, was bzgl. der ACKs zu erheblichen Problemen führen kann. Das PAWS-Mechanismus (Protect Against Wrapped Seq) verhindert solche Probleme mithilfe von Timestamps. Vereinfacht ausgedrückt: Trifft ein Paket mit einer aktuellen SEQ ein, hat aber einen deutlich älteren (also kleineren) Timestamp als alle kürzlich empfangenen Pakete, so liegt „der Verdacht nahe“, dass es sich um ein veraltetes Duplikat handelt, mit einer Sequenznummer aus dem früheren 32-Bit-SEQ-Bereich. Timestamps als Sicherheitsproblem Da der Timestamp-Zähler beim Booten des Rechners bei Null beginnt, ist es anhand eines TCP-Paketes von diesem Rechner leicht zu erkennen, wie lange dieser Rechner bereits aktiv ist. Ein sehr großer Timestamp kann u.U. darauf hindeuten, dass das Betriebssystem kaum gepflegt wird, da insbesondere Sicherheits-Updates im Kernel i.d.R. einen Neustart erfordern. Mit der Systemvariablen (unter Unix) net.ipv4.tcp_timestamps kann die Funktion deaktiviert werden, was bei langsamen Netzen (DSL, 100-Mbps-Ethernet) problemlos möglich ist, bei schnellen Netzen mit hoher Latenz jedoch nicht empfehlenswert ist (Stichwort „Congestion Collapse“). Eine Alternative zu Boot-Zeit-abhängigen Timestamps sind Timestamps mit „random offset“, deren Wert beim Verbindungsaufbau zufällig initialisiert wird. 4.5 Retransmission 4.5.1 go-back-n (GBN) Wird ein Paket abgeschickt, geht aber auf dem Weg zum Ziel verloren, so kann der Empfänger dafür keine Bestätigung verschicken. Auf der Senderseite wird daher der RTO-Timer (siehe Kapitel 4.4) für jedes Paket beim Versenden gestartet. Kommt nach Ablauf des RTO keine Bestätigung an, so wird nicht nur dieses Paket erneut versendet sondern auch alle folgenden noch im Sendefenster befindlichen Pakete. Kommen nach dem Paketverlust die folgenden Pakete beim Empfänger an, so werden sie zwar bestätigt, aber mit derselben ACK-Nummer wie beim zuletzt korrekt empfangenen Paket, sog. „doppeltes ACK“. Dies liegt an der Logik der Bestätigungen: Es werden nicht einzelne Pakete mit einer bestimmten Nummer bestätigt, sondern es wird bestätigt, dass bis zu einer bestimmten Byte-Position im Empfangsfenster alles korrekt eingetroffen ist (denn dies ist mit den Sequenznummern schließlich gemeint: es werden Bytes nummeriert und nicht Pakete, die lediglich willkürliche Begrenzungen im Datenfluss darstellen). In Abbildung 27 geht Paket SEQ 8 verloren. Es wird mit dem ACK 8 die letzte vollständige, korrekte Byte-Position bestätigt, sodass nach Ablauf des RTO für Paket SEQ 8 beim Sender der gesamte Inhalt des Sendefensters erneut übertragen wird. Die dem verlorenen Paket folgenden Pakete werden doppelt mit ACK 8 bestätigt. In dem Fall, dass eine Bestätigung verloren geht (Abbildung 28), läuft ebenfalls der RTO ab und es werden alle Pakete ab der zuletzt korrekt bestätigten Byte-Position erneut übertragen 39 Sender Empfänger Sendefenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 Verlust Empfangsfenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 ACK 8 ACK 8 ACK 8 ACK 8 Sendefenster nach Eintreffen von ACK 8 weitergeschoben SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 Abbildung 27: Paketverlust bei GBN Sender Empfänger Sendefenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 Empfangsfenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 ACK 8 ACK 12 ACK 15 ACK 17 ACK 19 Verlust Sendefenster nach Eintreffen von ACK 8 weitergeschoben SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 SEQ 17, L=2 Abbildung 28: ACK-Verlust Video in der Mediathek (Channel NWA): TCP (Retransmission, doppeltes ACK) Video in Moodle (alt): TCP_Retransmission_GBN_audio2020.mp4 4.5.2 Selective Retransmission Moderne TCP-Implementierungen versuchen möglichst GBN zu vermeiden, da dies zu einer oft unnötigen mehrfachen Übertragung derselben Daten führt. Im obigen Fall des ACK-Verlustes (Abbildung 28) braucht der Sender eigentlich gar nichts zu wiederholen, da er durch die folgenden korrekten ACKs bereits erkennen kann, dass offenbar alles korrekt übertragen wurde. Er benötigt lediglich einen ausreichend großen RTO, damit die Sendewiederholung von SEQ 8 nicht vor dem Eintreffen von ACK 15 ausgelöst wird. Denn das ACK 15 bestätigt bereits den korrekten und vollständigen Eingang aller Bytes bis zur Position 15. 40 Im ersten Fall (Verlust des gesendeten Paketes, Abbildung 27) kann der Sender anhand des doppelten ACK erkennen, dass grundsätzlich ein Paketverlust geschehen sein könnte, kann aber nicht wissen, wie viele Pakete betroffen sind (auch wenn nicht nur SEQ 8 sondern auch SEQ 12 verloren gegangen wäre, so würde trotzdem ein ACK 8 geschickt). Der Sender könnte daher zunächst nur SEQ 8 erneut schicken, worauf der Empfänger erkennt, dass „die Lücke gefüllt“ ist und sofort mit ACK 19 die gesamte Datenmenge mit einen einzigen ACK bestätigen kann. Sofern das Fenster ausreichend groß ist, kann die Datenübertragung während dieses „Korrekturprozesses“ normal weiterlaufen. Ein Problem bei diesem Vorgehen wäre allerdings, dass ein einziges doppeltes ACK nicht zwangsläufig auf einen Paketverlust schließen lässt: Es könnte auch eine Umordnung stattgefunden haben (Pakete kommen in der falschen Reihenfolge beim Empfänger an). In diesem Fall (z.B. Reihenfolge SEQ 5, dann 12, erst danach 8) würde der Empfänger zwar zunächst ein doppeltes ACK 8 abschicken, die Pakete dann aber richtig sortieren und mit ACK 15 die vollständige Bytefolge bis 15 bestätigen. Der Sender hätte aber bereits eine erneute, aber eigentlich unnötige, Sendung von SEQ 8 veranlasst. 4.5.3 Fast Retransmit Die Funktion Fast Retransmit (eingeführt mit TCP-Tahoe s.u.) vermeidet das zuletzt geschilderte Problem. Geht ein Paket verloren, aber alle späteren kommen korrekt an, so schickt der Empfänger mehrere doppelte ACK (Abbildung 27). Treffen beim Sender mindestens drei doppelte ACK ein (insgesamt also vier gleiche ACKs), schickt der Sender zunächst nur das erste Paket ausgehend von der zuletzt bestätigten Position im Sendefenster ab, bevor der RTO des verlorenen Paketes abläuft (daher „fast retransmit“). Nun wartet der Sender das entsprechende ACK ab: Ist „die Lücke geschlossen“ so würde der Empfänger ein zusammenfassendes ACK für alle bereits empfangenen Pakete schicken (im Fall von Abbildung 27 das ACK 19). 4.5.4 Selective Acknowledgement (SACK) Gehen mehrere Pakete verloren, so kann der Sender anhand der doppelten ACKs nur erkennen, dass es Paketverluste gegeben hat, er weiß aber nicht welche und wie viele. Beim Selective oder Fast Retransmit kann der Sender nur schrittweise alle Pakete ab der zuletzt bestätigten Position erneut abschicken, solange bis der Empfänger in einem zusammenfassenden ACK den korrekten Empfang aller Daten bestätigt. Problematisch sind auch Funktionen wie TCP Segmentation Offload (TSO), bei denen der Sender größere Segmente sendet als es die MTU es zulassen würde. Im folgenden Beispiel (Abbildung 29) werden die Pakete des Senders von einer TSO- Funktion (siehe Kapitel 4.6) in kleinere Segmente zerlegt, weshalb der Empfänger auch nur diese Pakete bestätigen kann. Geht im Beispiel das Teil-Paket SEQ 11 verloren, so würde der Empfänger mehrere doppelte ACK 11 zurückschicken. Der Sender müsste nun (abhängig von seinen „Retransmission-Fähigkeiten“) entweder beide Pakete SEQ 8 und SEQ 12 (also die Daten von Byte-Position 8 bis einschließlich 14) erneut übertragen oder mindestens alle Daten von Byte-Position 11 (bis dahin wurde bereits bestätigt) bis einschließlich 14, obwohl nur die Bytes 11 und 12 verloren gegangen sind. Sender Empfänger TCP-Sendefenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 TCP-Empfangsfenster SEQ 5, L=2 SEQ 7, L=2 SEQ 9, L=2 SEQ 11, L=2 SEQ 13, L=2 SEQ 15, L=2 Abbildung 29: Paketverlust bei TSO Mit der TCP-Option Selective ACK (SACK) wird dem Empfänger die Möglichkeit gegeben, exakt für diejenigen Byte- Bereiche eine Bestätigung zu geben, die bei ihm korrekt eingetroffen sind. Der Sender braucht dann nur genau die Byte-Bereiche erneut zu übertragen, die in der SACK-Option nicht genannt wurden. Anstatt bei mehrfachen Paketverlusten alle Pakete einzeln erneut zu verschicken, könnte der Sender ein einziges Paket mit allen fehlenden Daten bilden. Im Fall obiger Abbildung, könnte tatsächlich ausschließlich der Byte-Bereich 11 bis 12 in einem Paket gesendet werden (unabhängig von den ursprünglichen Paketgrenzen). 41 Der Standard-TCP-Header enthält die dafür erforderlichen Informationen nicht, daher müssen zwei zusätzliche Options-Header definiert werden. Ein Header zeigt lediglich beim Verbindungsaufbau (SYN-Flag) an, ob SACK überhaupt unterstützt wird (2-Byte-Option: ein Byte Typ (Nr. 4) ein Byte Länge (immer 2)). Die eigentliche SACK- Option kommt immer dann zum Einsatz, wenn tatsächlich Paketverluste bemerkt werden. Der Empfänger bestätigt mittels eines Beginn- und eines Ende-Wertes genau diejenigen Byte-Bereiche, die korrekt empfangen wurden. Der normale ACK-Mechanismus bleibt davon unberührt. 32 Bit - Typ Nr. 5 Length Beginn 1. Block Ende 1. Block Beginn 2. Block Ende 2. Block Abbildung 30: TCP-Option Selective ACK Es können maximal drei Blöcke in einem Header bestätigt werden (26 Byte: drei Blöcke à 2*4 Byte und 2 Byte Typ/Length), da zum einen der TCP-Options-Header höchstens 40 Byte umfassen darf und zum anderen fast immer die Timestamp-Option (10 Byte) verwendet wird. Video in Moodle: TCP_Retransmission_wireshark.mp4 4.6 TCP Segmentation Offload Bei der Paketanalyse wird man manchmal feststellen, dass offensichtlich viel größere IP-Pakete verschickt werden, als es die beim TCP-Verbindungsaufbau übermittelte Maximum Segment Size MSS bzw. die lokale MTU erlaubt, ohne dass eine Fragmentierung stattfindet. Ursache dafür ist, dass die Netzwerkkarte (Network Interface Card NIC) intern eine Aufteilung größerer IP-Pakete in die höchstens zulässige MTU vornehmen kann. Da das Capturing z.B. in wireshark aber vorher stattfindet, also bevor die NIC die Pakete zerlegt, sind oftmals größere Pakete in der Analyse sichtbar. Nimmt man das Capturing auf einem der Router auf dem Pfad zwischen Sender und Empfänger vor, so sind die realen Frames mit der wahren MSS zu sehen. Auf dem empfangenden Rechner sind aber nochmals andere Paket-Größen zu sehen, da das Zusammensetzen der Pakete in der Empfänger-NIC nicht unbedingt in der gleichen Unterteilung stattfindet wie beim Sender die Zerlegung. Diese Funktion wird als „Large Segment Offload“ oder als „TCP Segmentation Offload“ (TSO) bezeichnet. Hiermit wird es TCP erlaubt, auch größere Pakete zu verarbeiten (bis zu 64 kB) als es die MSS zulässt, was erheblich ressourcen-schonender ist, als die Verarbeitung kleiner Pakete. Die Aufteilung bzw. Segmentierung der eigentlich Sender TCP-Sendefenster SEQ 5, L=3 SEQ 8, L=4 SEQ 12, L=3 SEQ 15, L=2 Z