Dieses Praktikum beschäftigt sich wieder mit der Netzwerkschicht. Diesmal aber nicht mit Routing und Longest Prefix Matching, sondern mit Network Address Translation (NAT). NAT ist im heutigen Internet allgegenwärtig und daher ist es wichtig zu verstehen wie NAT funktioniert und was NAT einem bietet, bzw. was NAT erschwert. Dabei ist dies nicht nur für Netzwerk-Admins wichtig, sondern insbesondere für Anwendungsentwickler, bei denen im Zweifel eine Anwendung nicht mehr funktioniert, wenn NAT im Spiel ist.
Um NAT zu verstehen, bemühen wir wieder einmal Mininet
und führen auch wieder Werkzeuge ein, die uns helfen, Experimente mit einer richtige NAT-Implementierung durchzuführen.
Wir werden eine echte NAT-Implementierung untersuchen, um zu verstehen, wie eine solche intern arbeitet. Dazu müseen wir kontrolliert Zustand in der NAT-Tabelle erzeugen und dazu brauchen wir ein Werkzeug, das es uns erlaubt TCP-Verbindungen und UDP Pakete zu erzeugen, bei denen wir die genutzten Ports einstellen können, denn NAT nutzt diese zum Multiplexen/Demultiplexen. Darüber hinaus brauchen wir natürlich auch einen Server, der diese Pakete und Verbindungsversuche annimmt. Für diese Aufgabe eignet sich Netcat hervorragend. Die man page von Netcat hat folgendes zu seinem Anwednungsbereich zu sagen:
The nc (or netcat) utility is used for just about anything under the sun involving TCP, UDP, or UNIX-domain sockets. It can open TCP connections, send UDP packets, listen on arbitrary TCP and UDP ports, do port scanning, and deal with both IPv4 and IPv6. Unlike telnet(1), nc scripts nicely, and separates error messages onto standard error instead of sending them to standard output, as telnet(1) does with some.
Für unsere Zwecke also das ideale Werkzeug. Schauen wir uns die für dieses Praktikum wichtigsten Kommandozeilenschalter an.
Das Netcat-Tool heißt auf der Kommandozeile nc
. Als Client werden wir nur einige der verfügbaren Schalten benutzen. Der generelle Aufruf als TCP-Client sieht so aus:
nc [-p source_port] [-q seconds] [destination] [port]
Dabei ist:
[-p source_port]
- Der Quellport, der genutzt werden soll[-q seconds]
- Anzahl an Sekunden, die gewartet werden soll, bevor nc
sich beendet (negativer Wert bedeutet nicht beenden!)[destination]
- Die IP-Adresse oder der Hostname, zum dem der Client sich verbinden soll[port]
- Die ZielportnummerBeispiel:
echo "hello" | nc -p 3456 -q -1 10.0.0.1 1234
Im Beispiel wird der String "hello" über eine TCP-Verbinding an 10.0.0.1 Port 1234, Quell-Port 3456 gesendet. Die TCP-Verbindung bleibt danach offen (-q -1
).
Einen Server mit Natcat aufzusetzen ist ebenso einfach. Der generelle Aufruf sieht dabei wie folgt aus:
nc -l -k [port]
Dabei ist:
-l
- Das l
steht für listen
. Dieses Flag sagt Netcat, dass ein Server und kein Client erzeugt werden soll-k
- Diese Option instruiert nc
, dass der Server sich nicht nach der ersten Verbindung beendigen soll[port]
- Der lokale Port, auf dem der Server Verbindungen annehmen sollBeispiel:
nc -k -l 1234
Hier wir ein TCP-Server gestartet, der beliebige Verbindungsanfragen auf Port 1234 annimmt.
Bei UDP ist das Ganze noch ein wenig simpler. Ein Client wird einfach wie folgt gestartet:
nc [-u] [destination] [port]
-u
- UDP anstelle von TCP benutzen[destination]
- Die IP-Adresse oder der Hostname, zum dem UDP Pakete geschickt werden sollen[port]
- Die ZielportnummerBeispiel:
echo "hello" | nc -u 10.0.0.1 1234
Hier wird ein UDP Datagram mit dem String "hello" als Inhalt an einen UDP-Server auf dem Host 10.0.0.1, Port 1234 geschickt.
Der UDP-Server unterscheidet sich nur duch den -u
Schalter, um UDP anstelle von TCP zu nutzen. D.h. ein UDP-Server sieht wie folgt aus:
nc -l -u -k [port]
Dabei ist:
-u
- UDP anstelle von TCP benutzen-l
- Das l
steht für listen
. Dieses Flag sagt Netcat, dass ein Server und kein Client erzeugt werden soll-k
- Diese Option instruiert nc
, dass der Server sich nicht nach dem ersten Paket beendigen soll[port]
- Der lokale Port, auf dem der Server Pakete annehmen sollBeispiel:
nc -k -u -l 1234
Hier wird ein UDP-Server gestartet, der Pakete auf Port 1234 annimmt und beliebige Pakete annimmt ohne sich zu beenden.
Zu guter Letzt brauchen wir noch ein Werkzeug, dass die NAT-Tabelle anzeigen kann und dieses Werzeug heisst conntrack
. Hier brauchen wir nur einen Schalter, und zwar -L
, mit dem die Tabelle angezeigt wird. conntrack
kann wesentlich mehr, aber für unsere Zwecke reicht das einfache Anzeigen der Tabelleneinträge.
Damit sind Sie für das Praktikum gerüstet.
Viel Erfolg!
Zunächst benötigen Sie die Datei nat_topo.py, die die Mininet-Topologie beinhaltet mit der wir arbeiten werden. Die Topologie besteht aus vier Hosts (h0 - h3
), wovon h1
, h2
und h3
sich jeweils hinter einem NAT-Router (nat1
und nat2
) befinden. Starten Sie die Topologie in Mininet wie gewohnt mit:
sudo python nat_topo.py
Sie sollten nun die ihnen schon bekannte Mininet CLI vor sich haben. Das Netz was hier erzeugt wurde sieht wie folgt aus:
h0
ist für heute sowas wie ein Server im Internet und h1
ist in einem privaten Subnetz hinter dem NAT-Router nat1
. h2
und h3
sind ebenfalls hinter einem NAT-Router (nat2
). Fangen wir an, das Verhalten dieser Router zu untersuchen.
ping
von Host h1
aus die beiden Hosts h0
und h2
zu erreichen. Erklären Sie warum es klappt/bzw. nicht klappt (ein Blick auf die Topologie hilft sicherlich).h0
mit:h0 python3 -m http.server 80 &
Verbinden Sie sich nun auf nat1
und h1
(xterm h1 nat1
). Starten sie Wireshark auf nat1
(wireshark &
) und wählen Sie als Netzwerkschnittstelle zum Aufzeichnen die Schnittstelle mit dem Namen any
, also alle verfügbaren Schnittstellen. Starten Sie die Aufzeichnung und kontaktieren Sie den eben gestarteten Webserver von h1
aus via:
`curl 10.0.0.1`
Schauen Sie sich in Wireshark an, wie der NAT-Router die Pakete verändert. Versuchen Sie anhand der Netzwerk-Topologie die Veränderungen nachzuvollziehen.
nc
). Wie schon gesehen, kann man mit Netcat einfach TCP-Verbindungen aufbauen und über diese Daten transportieren. Daten braucht es aber gar nicht, um das Verhalten der NAT zu beobachten. Zunächst aber, starten wir einen Server, der TCP-Verbindungen auf dem Host im "Internet" (h0
) annimmt.nc -k -l 1234
Als nächstes verbinden wir uns von Host h1
aus mit diesem Server:
nc -q -1 10.0.0.1 1234
Wichtig ist dabei, dass -q -1
gesetzt ist, so dass die Verbindung bestehen bleibt! Jetzt schauen Sie sich den NAT-Tabelleneintrag zu dieser TCP-Verbindung auf nat1
an via:
conntrack -L
Sie sollten einen Eintrag wie diesen hier sehen:
tcp 6 431970 ESTABLISHED src=192.168.1.100 dst=10.0.0.1 sport=34016 dport=1234 src=10.0.0.1 dst=10.0.0.5 sport=1234 dport=34016 [ASSURED] mark=0 use=1
Dabei handelt es sich um das Protokoll (tcp
), die Protokollnummer wie sie im dazugehörigen IP-Feld steht (6
), der Timeout für den Eintrag in Sekunden (431970
), den Zustand der TCP-Verbindung (ESTABLISHED
), das Viertupel von Paketen Richtung Internet, wie Sie LAN-seitig ankommen und das Viertupel von Paketen aus dem Internet, wie sie WAN-seitig ankommen. Die Viertupel werden für das Muliplexen/Demultiplexen benötigt und für das Umschreiben der Pakete. Den Rest brauchen wir hier nicht. Fällt Ihnen etwas am Viertupel auf? Wurde der Quellport verändert?
Beenden Sie den nc
-Client (und nur den Client, denn den Server benötigen wir noch) und schauen Sie danach gleich wieder in die NAT-Tabelle. Was fällt Ihnen auf? Welcher Eintrag hat sich verändert und warum?
nat2
und den Hosts h2
und h3
. Wir nutzen wieder Netcat und verbinden uns von h2
und h3
mit jeweils den gleichen Quell-Ports, damit die NAT nicht einfach die Ports wiederverwenden kann. Dazu verbinden sie sich jeweils von h2
und h3
mit dem eben gestarteten Server wie folgt:nc -p 3456 -q -1 10.0.0.1 1234
Verbinden Sie sich mit nat2
und schauen Sie sich die NAT-Tabelle mit conntrack
an. Erklären Sie sich die Ausgabe (insbesondere die Viertupel).
Sie haben gesehen, dass die NAT das TCP-Protokoll versteht! Warum? Nun offensichtlich hat der NAT-Router seinen Timeout angepasst nachdem er die FIN-Segmente der Endpunkte gesehen hat. D.h. der NAT-Router hat gesehen, dass die Verbindung abgebaut wurde. Und, der NAT-Router hat den Eintrag noch eine Zeit lang gehalten. Es scheint so, als würde der NAT-Router auch den TIME-WAIT-Zustand kennen. Wiederholen Sie das Experiment mit nc
mit UDP und untersuchen Sie das Verhalten der NAT bezüglich der Dauer der Einträge.
Einen UDP Server können Sie mit
nc -k -u -l 1234
starten. Und um dem Server etwas zu schicken (dieses mal müssen wir etwas schicken, da es keinen Verbindungsaufbau gibt!), können Sie z.B. dies hier benutzen.
echo "hello" | nc -u 10.0.0.1 1234
Was passiert, wenn ein Paket erneut verschickt wird, bevor der Eintrag gelöscht wird (setzen Sie dazu auch den Quellport mit dem -p
-Schalter auf einen bestimmten Port).
Wir haben gesehen was passiert, wenn wir TCP und UDP nutzen, aber was ist, wenn wir ein Protokoll einsetzen, das gar keine Port-Nummern hat, wie z.B. ICMP? Probieren Sie es doch einfach aus!
ping
, um h0
(10.0.0.1
) zu erreichen. Schauen Sie wieder in die NAT-Tabelle von nat2
. ping
nutzt ICMP und ICMP benutzt kein Transportprotokoll und damit keine Port-Nummern. Welche Informationen nutzt der NAT-Router, um die ICMP-Antworten korrekt zu identifizieren? Schauen Sie sich die Informationen auf dem Hin- und Rückweg genau an.h2
Richtung h0
indem sie ein paarmal hintereinander:ping -c 1 10.0.0.1
ausführen. Schauen Sie nun in die NAT-Tabelle von nat2
. Versuchen Sie zu erklären, warum Sie so viele Einträge sehen.
In der Vorlesung haben wir den Dijkstra-Algorithmus kennengelernt. Berechnen Sie die kürzesten Wege, einmal ausgehend von A und einmal ausgehend von G im hier dargestellten Netz mithilfe von Dijkstra.
In der Vergangenheit wurde neue Transportprotokolle entwickelt. Unter anderem SCTP und DCCP. Glauben Sie nach dem heutigen Praktikum, dass NAT evtl. ein Grund ist, dass diese Transportprotokolle nie eine weite Verbreitung erfahren haben? Welchen weiteren Nachteil hat NAT, den wir in der Vorlesung noch nicht besprochen hatten?
Ich würde mich über Ihre Kritik und Verbesserungsvorschläge freuen. Auch Lob, klar. Eine kurze Umfrage finden Sie hier.