Verschiedene Werkzeuge eignen sich zur Fehlersuche im Netz. Einige verwende ich immer wieder bei den unterschiedlichsten Problemen, andere sind spezialisiert auf bestimmte Fragestellungen.
Hier stelle ich diejenigen, die ich am häufigsten einsetze, in alphabetischer Reihenfolge vor.
Das Programm arp
dient der Anzeige und Manipulation des ARP-Caches des
Kernels.
Ich setze es bei Problemen in direkt angeschlossenen Netzsegmenten ein und
verwende es
Der prinzipielle Aufruf ist:
# arp [Optionen] [$rechnername]
Bei Aufruf ohne Optionen zeigt arp
die MAC-Adressen an, die $rechnername
zugeordnet sind. Fehlt $rechnername, zeigt es alle bekannten
Adresszuordnungen an.
$rechnername kann ein Hostname sein, ein FQDN oder eine IP-Adresse.
Die für die Fehlersuche wichtigsten Optionen sind:
Für weitergehende Informationen verweise ich auf die Handbuchseite. Nähere Informationen zum ARP-Protokoll stehen im Grundlagenkapitel für Netze.
Wenn ich arp
verwende, um mich von der Anwesenheit eines Rechners mit einer
bestimmten IP-Adresse im Netz zu überzeugen, sieht das wie folgt aus:
Ich habe von keiner der beiden Adressen eine
Antwort auf die PING-Anfrage bekommen.
Bei 192.168.1.6
kam jedoch nach kurzer Verzögerung die Meldung
Destination Host Unreachable, die bei 192.168.1.5
fehlte.
Bei der Kontrolle des ARP-Caches zeigt sich, dass für die eine IP-Adresse
eine MAC-Zuordnung gegeben ist, für die andere nicht.
$ arp -an
? (192.168.1.5) auf 00:01:6c:6f:c5:d6 [ether] auf eth0
? (192.168.1.6) auf <unvollständig> auf eth0
...
Das lässt vermuten, dass auf dem Rechner mit IP-Adresse 192.168.1.5
PING
durch Paketfilterregeln blockiert wird, während in diesem Netzsegment zu
diesem Zeitpunkt kein Gerät die IP-Adresse 192.168.1.6 für sich beanspruchte.
Es gibt mehrere Szenarien, in denen ich mich bei der Fehlersuche mit Layer2-Bridges beschäftige. Zum einen, wenn ich einen verdächtigen Rechner habe und zur Kontrolle jeglichen Netzverkehrs eine Bridge vor seinen Netzanschluß schalten will. Oder, wenn ich den Verkehr auf einer Punkt-zu-Punkt-Verbindung kontrollieren will. In diesen Fällen möchte ich das restliche Netzwerk möglichst unverändert lassen und keinen anderen Rechner umkonfigurieren, um das Problem beobachten zu können. Mit einer Bridge bekomme ich allen Datenverkehr an der betreffenden Stelle frei Haus geliefert. Bis 100 MBit/s eignen sich beispielsweise Einplatinenrechner, wie in [Weidner2012] beschrieben, sehr gut dafür. Ein weiteres Szenario ist eine regulär betriebene Bridge, die scheinbar nicht funktioniert und die ich mit den bridge-utils untersuchen kann.
Prinzipiell kann ich mit einer Linux-Bridge den Verkehr filtern und
begrenzen. Dafür verwende ich auf Layer2-Ebene ebtables
und auf
Layer3-Ebene iptables
, bei letzteren benötige ich für eine Bridge
einen Kernel ab Version 2.4.
Linux-Bridges können das Spanning Tree Protocol (STP) verwenden und ich kann sie auch zur Diagnose von STP-Problemen heranziehen, obwohl mir hier tcpdump oder wireshark genausogut weiterhelfen.
Generell konfiguriere ich eine Bridge mit brctl
.
Mit ipconfig
, ip
oder einem DHCP-Client kann ich ihr dann eine IP-Adresse
zuweisen.
Das Bridge-Forwarding-Delay von circa 30 Sekunden kann bei DHCP-Clients
Probleme bereiten.
Wenn gar nichts geht, muss ich das Bridge-Interface mit statischen Adressen
konfigurieren.
Lässt eine Bridge keinen Traffic durch, suche ich im Verzeichnis
/proc/sys/net/bridge/ nach Dateien mit Namen die mit bridge-nf-*
beginnen.
Diese legen fest, ob die betreffende Bridge Verkehr filtert.
Das kann ich abschalten, indem ich eine ‘0’ in die betreffende Datei schreibe:
# echo 0 \
> /proc/sys/net/bridge/bridge-nf-call-arptables
# echo 0 \
> /proc/sys/net/bridge/bridge-nf-call-ip6tables
# echo 0 \
> /proc/sys/net/bridge/bridge-nf-call-iptables
Mit dem Program brctl
inspiziere und bearbeite ich
die Bridge-Konfiguration im Linux-Kernel.
Dabei verwende ich die folgenden Befehle um eine oder mehrere Bridge-Instanzen zu bearbeiten:
Jede Bridge benötigt Ports, zwischen denen sie Ethernet-Pakete vermittelt. Diese bearbeite ich mit den folgenden Befehlen:
ifconfig
oder ip
aktivieren.Um herauszufinden, an welcher Schnittstelle
die betreffende MAC-Adresse zuletzt gesichtet wurde, bestimme ich die
Adresse und den Port in den Zeilen, in denen bei Spalte
is local?
der Wert ‘yes’ steht und ermittle mit ifconfig
oder
ip
die betreffende Ethernet-Schnittstelle.
$ /usr/sbin/arp -an
192.168.1.253 auf 00:16:3e:ca:72:4c ether auf br0
192.168.1.223 auf b8:27:eb:74:74:d5 ether auf br0
...
$ brctl showmacs br0
port no mac addr is local? ageing timer
1 00:00:e8:df:92:b0 yes 0.00
1 00:16:3e:ca:72:4c no 20.54
2 00:1f:d0:97:c4:55 yes 0.00
2 b8:27:eb:74:74:d5 no 7.98
...
$ ip l sh
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
master br0 state UP qlen 1000
link/ether 00:1f:d0:97:c4:55 ...
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
master br0 state UNKNOWN qlen 1000
link/ether 00:00:e8:df:92:b0 ...
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
link/ether 00:00:e8:df:92:b0 ...
In diesem Beispiel ist der Rechner mit IP 192.168.1.223
an eth0 und der
Rechner mit IP 192.168.1.253
an eth1 angeschlossen, die über die Bridge
br0 miteinander verbunden sind.
Die Timer der Bridge kann ich mit den folgenden Befehlen ändern:
Mit ethtool
, mii-diag
oder mii-tool
kann ich die Konfiguration
von modernen Ethernetschnittstellen anzeigen und manipulieren.
Die Programme verwenden dazu das Media Independend Interface (MII),
von dem sich auch der Name ableitet.
Welches Programm installiert ist, hängt von der Linux-Distribution ab. Ob ich es überhaupt verwenden kann, hängt von der Ethernetkarte ab. Moderne Ethernetkarten und die Onboardschnittstellen neuerer Rechner funktionieren meist gut mit diesen Programmen.
Ich kann mit diesen Programmen unter anderem:
Gerade die Möglichkeit, Fehlanpassungen in der Geschwindigkeit oder beim Duplexverhalten zu erkennen, kann sich als wertvoll bei der Diagnose von Performanceproblemen erweisen.
Bei einer LWL-Verbindung hatten wir ernste Performanceprobleme, bei denen die Transferrate in einer Richtung auf wenige KB/s beim beidseitigen Lasttest herunter ging. Unser erster Gedanke war eine schlechte Faser, da das Problem nur in einer Richtung auftrat. Mit den mii-tools konnte ich eine Fehlanpassung der Ethernetkarte mit dem Medienwandler diagnostizieren. Nachdem ich die Schnittstelle auf Full-Duplex eingestellt hatte, blieb die verfügbare Datenübertragungsrate auch bei Volllast in beiden Richtungen im erwarteten Rahmen.
Mit dem Programm ifconfig kann ich die Netzwerkschnittstellen konfigurieren. Außerdem liefert es Informationen über den aktuellen Zustand und die Konfiguration der Netzwerkschnittstelle.
Es gibt drei Möglichkeiten ifconfig aufzurufen.
# ifconfig [-a]
zeigt den Status der aktiven Schnittstellen.
Gebe ich zusätzlich die Option -a
, zeigt es den Status aller Schnittstellen,
also auch der inaktiven.
# ifconfig $schnittstellenname
zeigt den Zustand der angegebenen Schnittstelle an.
In der dritten Form,
# ifconfig $schnittstellenname $optionen
wird die Schnittstelle konfiguriert.
Die wichtigsten Optionen bei der Fehlersuche sind
Weitere Informationen liefert die Handbuchseite.
Es ist möglich, an eine Netzwerkschnittstelle mehrere IP-Adressen zu binden. Das Programm ifconfig arbeitet jedoch mit einer Adresse pro Schnittstelle. Um weitere Adressen an diese Schnittstelle zu binden, füge ich an den Schnittstellennamen einen Doppelpunkt und eine Zahl an.
In letzter Zeit werden die Netzwerkschnittstellen oft mit dem Programm ip
vom Paket iproute2 konfiguriert, welches in der Sektion über
iproute beschrieben ist.
Für den schnellen Überblick über die aktuelle Konfiguration der Schnittstellen
gefällt mir die Ausgabe von ip addr show
besser, da sie kompakter
ist, was sich insbesondere dann auszahlt, wenn ein Rechner mehrere
Netzwerkschnittstellen hat, oder mehrere Adressen an einer Schnittstelle.
In diesem Abschnitt stelle ich drei Werkzeuge vor, mit denen ich auf einfache Weise den Netzwerkdurchsatz für TCP und UDP messen kann. Welches der drei ich einsetze, hängt meist von der Verfügbarkeit auf den beteiligten Rechnern ab.
Bei allen drei Werkzeugen benötige ich Zugang zu den Rechnern zwischen denen
ich messen will, zwei Programme kann ich mittels inetd
automatisch starten
lassen, so dass ich mich zum Zeitpunkt der Messung nicht anmelden muss.
Rootrechte brauche ich für die Messung nicht.
Für genauere Informationen zu den einzelnen Programmen sind, wie immer, die Handbuchseiten da.
Bei diesem Programm, dass ich als Client und Server einsetzen kann, erzeugt der Client den Traffic aus dem Hauptspeicher heraus, während der Server die angekommenen Daten verwirft, so dass nur der Durchsatz im Netz und das Handling der Daten im Hauptspeicher gemessen wird.
Ich kann einseitige Messungen machen und anschließend die Client- und Serverrolle tauschen oder zwei Verbindungen in den verschiedenen Richtungen gleichzeitig messen.
Normalerweise dauert eine Messung 10 Sekunden, während derer das Programm versucht, so viele Daten wie möglich zu versenden und an deren Ende es das Ergebnis ausgibt. Alternativ kann ich die Datenmenge vorgeben, so dass die Dauer vom Durchsatz abhängt. Außerdem ist es möglich, die Zeitdauer zu verändern und periodische Berichte ausgeben zu lassen, anstelle eines Berichts am Ende der Übertragung.
Bei UDP kann ich die Datenrate vorgeben und damit das Verhalten des Netzes bei unterschiedlich starker Auslastung untersuchen. Dazu kann ich mir beispielsweise mit Ping die RTT anzeigen lassen und dann das Netz verschieden stark auslasten. Mit TCP kann ich die Datenrate nicht vorgeben, da diese durch die Flusssteuerung automatisch angepasst wird.
Das Programm nttcp, das auf dem älteren Programm ttcp basiert, kann die Transferrate für TCP, UDP und UDP-Multicast messen.
Da es die Daten ebenfalls aus Puffern im Hauptspeicher über das Netzwerk sendet, fällt am Rechner nur die Zeit zum Messen und die Zeit im Netzwerkcode des Kernels in’s Gewicht.
Zusätzlich zu den Transferdaten gibt das Programm auch die benötigte CPU-Zeit aus.
Ich kann das Programm via inetd
auf einem Rechner starten lassen, so
dass ich mich dort zur Messung nicht anmelden muss.
Dieses Programm, dass auf nttcp
basiert, misst ebenfalls den Durchsatz für
TCP, UDP und UDP-Multicast.
Es kann etwa die gleichen Daten wie nttcp
anzeigen und außerdem die Verluste
bei UDP.
Wie bei nttcp
gibt es einen Sender- und einen Empfängermodus.
Zusätzlich gibt es einen Servermodus, in dem es sowohl senden als auch
empfangen kann.
Dieser ist insbesondere beim Aufruf via inetd
nützlich.
Die Ergebnisse werden beim Client angezeigt.
Eine Besonderheit von nuttcp
ist, dass es außer
memory-to-memory-Transfer auch disk-to-memory, memory-to-disk und
disk-to-disk messen kann.
Damit ist es möglich Szenarien zu messen, die realistischen Einsatzgebieten
näher kommen.
Die Programme der iproute-Suite sind moderne Werkzeuge zur Anzeige und Konfiguration von Netzwerkschnittstellen, -routen und der Verkehrskontrolle. Sie bieten gegenüber den Programmen der net-tools-Suite mehr Möglichkeiten.
Die iproute-Suite umfasst unter anderem die folgenden Programme:
Weitere und genauere Informationen stehen in den betreffenden Handbuchseiten und der zugehörigen Dokumentation.
Das Program ip dient zum Anzeigen und Manipulieren von Routen, Schnittstellen, Policy-Routing und Tunneln. Es ist das Programm aus der Suite, das ich am häufigsten aufrufe.
Allgemein sieht der Aufruf des Programms wie folgt aus:
ip [ Optionen ] Objekt [ Befehl [ Argumente ] ]
Die Optionen sind allgemeine Modifikatoren, die das Verhalten des Programms
ändern, wie -4
oder -6
, welche die Adressfamilie auf
IPv4 oder IPv6 einschränken.
Das Objekt gibt an, worüber ich Informationen wünsche, beziehungsweise, was ich manipulieren will. Mögliche Objekte sind unter anderem:
Der darauf folgende Befehl gibt die Aktion an, die ich ausführen will. Ihm folgen gegebenenfalls die passenden Argumente. Befehl und Argumente sind spezifisch für die entsprechenden Objekte.
Das Programm ss (socket statistics) liefert Informationen und Statistiken zu Sockets. Ähnliche Informationen kann ich zum Beispiel auch mit netstat bekommen, jedoch habe ich bei ss mehr Möglichkeiten zur Filterung, was mir bei Servern mit vielen Verbindungen zugute kommt.
Der Aufruf ist wie folgt:
ss [ Optionen ] [ Filter ]
Ohne Optionen zeigt ss die verbundenen TCP-Sockets an.
Die wichtigsten Optionen sind unter anderen:
Der Filter beim Aufruf von ss hat die allgemeine Form:
[ TCP-Status ] [ Ausdruck ]
Um nach TCP-Status zu filtern, gebe ich das Schlüsselwort state
oder
exclude
gefolgt von einem der Standard-TCP-Zustandsnamen oder einem
der folgenden an:
Falls weder ein state
noch ein exclude
Statement vorhanden
ist, gilt die Voreinstellung all
bei Option -a
und ansonsten
alle außer listening
, syn-recv
, time-wait
und closed
.
Mit dem Ausdruck kann ich nach Adressen und Ports filtern.
Weitere Optionen und Informationen zur Filterung gibt es in der Handbuchseite und im Artikel ``SS Utility: Quick Intro’’, den ich bei der Dokumentation des iproute-Pakets finde.
Mit dem Programm tc (traffic control) kann ich die Einstellungen zur Verkehrssteuerung des Kernels ansehen und manipulieren.
Dabei gilt es drei Arten von Objekten zu unterscheiden:
Die folgenden Klassenlosen QDISC stehen zur Verfügung:
Die folgenden klassenbasierten QDISC stehen zur Verfügung:
Die Klassen formen einen Baum, bei dem jede Klasse genau einen Vorfahren hat und mehrere Kinder haben kann.
Manche QDISC erlauben zur Laufzeit Klassen hinzuzufügen (CBQ, HTB), andere nicht (PRIO). Erstere können beliebig viele oder auch keine Subklassen haben, in denen die Datenpakete einsortiert werden.
Jede Klasse enthält genau ein Blatt-QDISC (per Default pfifo), welcher durch ein anderes ersetzt werden kann. Diese QDISC kann wiederum andere Klassen enthalten, die zunächst auch nur ein QDISC haben.
Wenn ein Datenpaket in einer klassenbasierten QDISC ankommt, wird es genau einer der enthaltenen Klassen zugeordnet. Sind Filter für eine Klasse definiert, werden diese zuerst für die Klassifizierung herangezogen. Einige QDISC werten auch das TOS-Feld des IP-Headers aus.
Jeder Knoten im Klassenbaum kann seine eigenen Filter haben. Filter in höheren Ebenen können direkt auf niedrigere Klassen verweisen.
Wenn ein Paket nicht klassifiziert werden konnte, geht es in die Blatt-QDISC der Klasse.
Alle QDISC, Klassen und Filter haben Ids, die automatisch bestimmt oder explizit spezifiziert werden. Diese Ids bestehen aus einer Haupt- und einer Nebennummer, getrennt durch Doppelpunkt.
Eine QDISC, welche Kinder haben kann, bekommt eine Hauptnummer, die ‘Handle’ genannt wird und lässt die Nebennummer als Namensraum für die Klassen. Üblicherweise benennt man QDISC, die Kinder haben, explizit.
Alle Klassen, die zur selben QDISC gehören, teilen sich die gleiche Hauptnummer. Jede hat eine separate Nebennummer, die Class-Id genannt wird und sich auf die QDISC (nicht die Elternklasse) bezieht.
Filter haben eine dreiteilige Filter-Id, die nur bei einer Filter-Hierarchie benötigt wird.
handle
Parameter benannt werden, Klassen mit classid
.remove
/ add
, der neue Knoten
wird gegebenenfalls neu erzeugtremove
/ add
, der neue Knoten muss bereits existieren.Weitere Informationen finden sich in der Handbuchseite.
Mit dem Programm rtmon kann ich Änderungen an der Routingtabelle des Kernels
über den netlink
Socket beobachten. Das Programm kann vor der ersten
Netzwerkkonfiguration, zum Beispiel in einem Init-Script, gestartet werden.
Rtmon schreibt in eine Datei und stellt der Historie der Routingtabelle einen Schnappschuss des Zustandes beim Start des Programms voran. Die Datei kann ich mit dem bereits besprochenen Programm ip auswerten.
Der typische Aufruf sieht in etwa so aus:
# rtmon file /var/log/rtmon.log
Anschließend kann ich die protokollierten Änderungen wie folgt ausgeben lassen:
# ip monitor file /var/log/rtmon.log
Sowohl beim Aufruf von rtmon, als auch bei dem von ip kann ich angeben, an welchen Objekten ich interessiert bin:
Weitere Informationen finden sich auch hier in der Handbuchseite.
Mit libtrace kann ich ähnlich wie mit libpcap eigene Analysewerkzeuge programmieren. Hier will ich aber auf die mitgelieferten libtrace-tools eingehen, mit denen ich Mitschnitte anfertigen und weiter bearbeiten kann.
Ein Vorteil von libtrace ist, dass diese Bibliothek und die damit geschriebenen Werkzeuge mit Paketmitschnitten aus unterschiedlichen Quellen umgehen und die verschiedenen Formate ineinander umwandeln können. Dazu verwendet libtrace sogenannte URI um das Format und die Quelle beziehungsweise das Ziel anzugeben.
Die folgende Tabelle listet einige der unterstützten Formate auf und gibt an, ob libtrace diese schreiben kann.
Unterstützte Formate für Paketmitschnitte
Format | URI | Read | Write |
---|---|---|---|
Live PCAP Schnittstelle | pcapint:$int | Ja | Ja |
PCAP Trace Datei | pcapfile:$fn | Ja | Ja |
ERF Trace Datei | erf:$fn | Ja | Ja |
DAG Gerät | dag:$devloc | Ja | Ja |
Native Linux interface | int:$int | Ja | Ja |
Native Linux interface | ring:$int | Ja | Ja |
(ring buffers) | |||
Native BSD interface | bpf:$int | Ja | Nein |
TSH trace file | tsh:$fn | Ja | Nein |
FR+ trace file | fr+:$fn | Ja | Nein |
Legacy DAG ATM Trace Datei | legacyatm:$fn | Ja | Nein |
Legacy DAG POS Trace Date | legacypos:$fn | Ja | Nein |
Legacy DAG Ethernet Trace | legacyeth:$fn | Ja | Nein |
Datei | |||
Legacy DAG NZIX Trace Datei | legacynzix:$fn | Ja | Nein |
ATM Cell Header Trace Datei | atmhdr:$fn | Ja | Nein |
RT Network Protocol | rt:$host:$port | Ja | Nein |
Genug der Vorrede, kommen wir zu den Werkzeugen.
Mit traceanon
kann ich die IP-Adressen von Paketmitschnitten anonymisieren.
Das ist wichtig, wenn ich einen Paketmitschnitt zu einem Problem weiterreichen,
aber möglichst wenig Informationen zur Netzwerkstruktur preisgeben will.
Das Programm traceanon
ändert die IP-Header der Datenpakete sowie die in ICMP
eingebetteten IP-Header und repariert die Prüfsummen innerhalb von TCP- und
UDP-Headern.
Es gibt zwei Schemata: bei dem einen ersetzt traceanon
einen kompletten
Adressblock durch einen anderen und beim anderen ersetzt es die Adressen mit dem
Cryptopan-Verfahren einzeln.
Wichtig beim Einsatz von traceanon
ist, immer im Hinterkopf zu behalten,
dass IP-Adressen auch auf anderem Weg preisgegeben werden können.
So werden IP-Adressen innerhalb von ARP-Paketen nicht anonymisiert und einige
Anwendungsprotokolle wie zum Beispiel HTTP, SMTP, OSPF und andere
Routingprotokolle können in den Anwendungsdaten Informationen über die
beteiligten Netze verraten.
Der Aufruf sieht so aus:
$ traceanon [options] $sourceuri $desturi
Die Beschreibung der Optionen steht in der Handbuchseite.
Dieses Werkzeug findet Differenzen zwischen zwei Mitschnitten und gibt diese aus. Dabei wertet es den Inhalt der Framingheader (PCAP oder ERF) nicht aus.
Mit der Option -m $max
kann ich die Ausgabe nach $max
Unterschieden abbrechen lassen.
Der Aufruf sieht so aus:
$ tracediff [ -m $maxdiff ] $firsturi $seconduri
Tracediff ist nützlich, wenn ich mehrere Mitschnitte einer Verbindungssitzung an verschiedenen Stellen aufgenommen habe und diese vergleichen will.
Mit diesem Werkzeug kann ich zwei oder mehrere Paketmitschnitte zu einem kombinieren, wobei die Reihenfolge der Pakete beibehalten wird.
Der Aufruf sieht so aus:
$ tracemerge [ options ] $outputuri $inputuri ...
Die Optionen sind in der Handbuchseite beschrieben.
Mit diesem Programm kann ich Datenpakete in lesbarer Form ausgeben.
Dabei kann ich mit der Option -f $filter
die Ausgabe auf bestimmte
Pakete einschränken und mit -c $count
die Anzahl der angezeigten
Pakete begrenzen.
Die Ausgabe ist abhängig davon, inwieweit die Protokolle in libtrace bekannt sind und ändert sich folglich von Version zu Version.
Folgender Beispielaufruf mit tracepktdump aus den libtrace-tools Version 3.0.10 soll das verdeutlichen:
In dieser Version ist das OSPF-Protokoll in der Bibliothek noch nicht bekannt und wird als Hexdump präsentiert. Die IP- und Ethernet-Header hingegen werden dekodiert und erscheinen nicht im Hexdump.
Dieses Werkzeug spielt einen Paketmitschnitt mit den gleichen Zeitabständen aus einer URI zu einer anderen. Ich kann damit einen Mitschnitt wieder auf das Netz schicken, wenn die zweite URI ein Netzwerkinterface bestimmt, Prüfsummen werden während des Abspielens neu berechnet.
Mit der Option -f $filter
kann ich die zurückgespielten Datenpakete
einschränken.
Beim Zurückspielen verwendet tracereplay
die Ethernet-Adressen aus
dem Mitschnitt, mit -b
kann ich als Ziel-Ethernet-Adresse jedoch die
Broadcast-Adresse angeben.
Der Aufruf sieht so aus:
$ tracereplay [ options ] $inputuri $outputuri
Die Optionen sind in der Handbuchseite beschrieben.
Dieses Programm kann eine Reihe von Berichten über die Eigenschaften von
Paketmitschnitten produzieren.
Die Berichte landen in Dateien, deren Name
gleich der langen Option gefolgt vom Suffix .rpt
ist.
Folgende Optionen und Reports sind für mich bei der Fehlersuche interessant:
Mehr Optionen und Berichte beschreibt die Handbuchseite.
Mit diesem Programm bekomme ich eine einfache filter- und zeitbasierte Analyse eines Paketmitschnitts. Dabei teilt es den Mitschnitt in Intervalle und gibt für jedes Intervall an, wie viele Datenpakete passend zu den angegebenen Filtern vorkommen.
Die möglichen Optionen sind unter anderen:
txt
, csv
, html
)Weitere Optionen stehen in der Handbuchseite.
Dieses Programm gibt ähnliche Analysen wie tracertstats aus, aber jeweils
für den gesamten Paketmitschnitt und nicht für einzelne Zeitintervalle
daraus. Mit der Option -f $filter
kann ich auch hier die Pakete
angeben, an denen ich interessiert bin.
Das Programm tracesummary
gibt eine einfache Zusammenfassung für einen Paketmitschnitt an
und ist ein Shellwrapper um tracestats
.
Dieses Programm teilt einen Paketmitschnitt in mehrere Dateien auf.
Das kann ich unter anderen mit diesen Optionen beeinflussen:
$count
Pakete pro Ausgabedatei.
Die Ausgabedateien werden nach dem in der Output-URI angegebenen Basisnamen
benannt, an den die Nummer des ersten Paketes in der Datei angehängt
wird.$bytes
Bytes in eine Datei$seconds
Sekunden$unixtime
$unixtime
$max
Ausgabedateien$snaplen
ab. Ohne
diese Angabe wird das komplette Datenpaket geschrieben.gzip
, bzip2
, lzo
oder none
)Weitere Optionen stehen in der Handbuchseite.
Zwei weitere Werkzeuge sind lediglich Shellwrapper um das Programm
tracesplit
:
Das Programm zeigt die aktivsten n Datenflüsse in einem Intervall an, ähnlich
wie top
für Prozesse oder mytop
für MySQL-Verbindungen.
Ich kann die Ausgabe mit folgenden Optionen an meine Bedürfnisse anpassen:
Ein weiteres Werkzeug, um schnell eine Netzwerkverbindung herzustellen,
ähnlich wie telnet
doch weitaus flexibler, ist netcat
.
Damit kann ich nicht nur TCP-, UDP- oder UNIX-Socket-Verbindungen aufbauen,
sondern auch einen einfachen Server für die genannten Protokolle einrichten.
Netcat ist sehr gut in Skripten einsetzbar und kann ein rudimentäres
Port-Scanning für TCP-Ports.
Außerdem, was in manchen Umgebungen wichtig sein kann: netcat
kann mit
Proxy-Servern umgehen und darüber Verbindungen herstellen.
Der grundlegende Aufruf ist
$ netcat [ optionen ] $host $port
wenn ich eine Verbindung via TCP oder UDP aufbauen will,
$ netcat [ optionen ] $port
wenn ich auf TCP- oder UDP-Verbindungen warten will, und
$ netcat [ optionen ] $socketpath
wenn ich mit UNIX-Domain-Sockets arbeiten will.
Will ich einen Portscan mit Option -z
starten, kann ich statt
eines Ports auch einen Bereich ($port1-$port2
) angeben.
Einige der wichtigsten Optionen sind:
-l
wartet netcat
auf weitere
Verbindungen, nachdem die erste endet.
Ohne diese Option beendet sich netcat
nach der ersten Verbindung.netcat
auf eine ankommende Verbindung anstatt selbst eine
Verbindung zu öffnen.$addr
.
Das ist nützlich, wenn mein Rechner mehrere Adressen hat.$proto
. Mögliche Werte sind
4
für SOCKS Version 4, 5
für SOCKS Version 5 und
connect
für die CONNECT-Methode bei HTTP-Proxies.netcat
an, keine Verbindung aufzubauen, sondern nur
nachzuschauen, ob der Port oder Portbereich offen ist.
Diese Option kombiniere ich sinnvollerweise mit -v
damit die Ports auch
angezeigt werden.Weitere Optionen finden sich in den Handbuchseiten.
Die folgenden Beispiele sind der Handbuchseite von netcat
entnommen.
Für eine einfache Client-Server-Verbindung gebe ich folgendes auf der Serverseite ein:
$ netcat -l 1234
und auf der Clientseite das folgende:
$ netcat host.example.net 1234
um mich mit dem Server zu verbinden.
Mit Option -u
verwende ich UDP statt TCP zur Übertragung.
Mit Option -U
geht es über UNIX-Domain-Sockets.
Dann verwende ich statt der Portnummer den Pfadnamen zur Socketdatei und
lasse auf Clientseite den Rechnernamen weg.
Die Socketdatei darf beim Start des Serverprozesses noch nicht existieren.
Um schnell mal eine Datei zu übertragen, erweitere ich das Client/Server Beispiel auf Serverseite wie folgt:
$ netcat -l 1234 > file.out
und auf Clientseite:
$ netcat host.example.net 1234 < file.in
Die Verbindung wird nach erfolgter Datenübertragung automatisch geschlossen. Vertausche ich die spitzen Klammern, wird die Datei vom Server zum Client übertragen.
Wenn ich das Plaintext-Protokoll des Servers kenne, kann ich mit netcat
auch
komplexe Protokolle bedienen oder testen:
$ netcat -C mail.example.net 25 <<EOT
HELO host.example.net
MAIL FROM:<user@host.example.net>
RCPT TO:<user2@host.example.net>
DATA
Subject: Testmail
Body of email.
.
QUIT
EOT
Mit diesem kurzen Skript kann ich eine E-Mail einspeisen, um einen
Mailserver zu testen.
Das gleiche kann ich auch interaktiv von Hand eingeben.
Die Option -C
sorgt dafür, dass netcat
im Netz die Kombination CRLF als
Zeilenende sendet, wie es im RFC spezifiziert ist.
Um festzustellen, welche TCP-Ports an einem Rechner erreichbar sind, kann ich
netcat
mit den Optionen -z
und -v
aufrufen:
Dieses Programm setze ich auch bei lokalen Problemen auf Linux-Rechnern ein. Daher habe ich es bereits im Kapitel Werkzeuge in Teil 2 dieses Buches beschrieben. Hier gehe ich auf Aspekte ein, die beim Untersuchen von Netzproblemen von Belang sind.
Rufe ich netstat
ohne Argumente auf, liefert es mir eine Liste der
offenen und aktiven Sockets aller konfigurierten Adressfamilien, das
heisst, der bestehenden Verbindungen.
Meist interessieren mich nicht alle Adressfamilien, sondern nur ganz
bestimmte. Dann kann ich diese zum Beispiel mit der Option
--protocol=$familie
einschränken. Für $familie
kann ich in
einer durch Komma separierten Liste die folgenden angeben: unix
,
inet
, ipx
, ax25
, netrom
, ddp
. Alternativ
kann ich jeden gewünschten Familiennamen einzeln als Option übergeben:
--unix
, --inet
, und so weiter.
In diesem Teil der Buches interessiert mich vor allem die Familie
--inet
. Diese kann ich weiter eingrenzen. Mit der Option -4
beziehungsweise -6
beschränke ich die Ausgabe auf die entsprechende
Version des Internet Protokolls.
Außerdem verwende ich
Bin ich nur daran interessiert, ob überhaupt ein Prozess an einem
Socket wartet, verwende ich die Option --listening
beziehungsweise
-l
. Diese läßt netstat
bei der normalen Ausgabe weg.
Will ich sowohl die aktiven als auch die lauschenden Sockets erfassen,
verwende ich die Option --all
beziehungsweise -a
.
Wenn ich eher an den Routen als an den Sockets interessiert bin, verwende
ich die Option --route
beziehungsweise -r
. Damit bekomme ich
die gleiche Ausgabe, wie mit dem Befehl route -e
. Auch hier kann ich
mit -4
oder -6
die Protokollversion einschränken.
Füge ich die Option -C
hinzu, bekomme ich Informationen aus dem
Routencache, mit der Option -F
stattdessen aus der Forwarding
Information Base (der Routentabelle), aber das ist sowieso die
Voreinstellung.
Mit der Option --interfaces
oder -i
kann ich Informationen
über die Netzgeräte bekommen.
Ein einfaches netstat -i
liefert mir in einer übersichtlichen Tabelle
zu jedem aktiven Interface unter anderem die MTU, die Anzahl der gesendeten
und empfangenen Datenpakete sowie die Anzahl der Sende- beziehungsweise
Empfangsfehler.
Kombiniere ich das mit -e
, bekomme ich die gleiche Ausgabe wie vom
Programm ifconfig
. Kombiniert mit -a
zeigt netstat
auch Interfaces
an, die nicht aktiviert sind.
Die Option --groups
beziehungsweise -g
liefert mir
Informationen zur Mitgliedschaft des Rechners in Multicast-Gruppen.
Mit der Option --statistics
beziehungsweise -s
zeigt netstat
zusammengefasste Statistiken für alle Protokolle.
Abschließen möchte ich diese kleine Vorstellung von netstat mit ein paar allgemeinen Optionen, mit denen ich die Ausgabe modifizieren kann.
Am häufigsten setze ich die Option --numeric
, kurz -n
ein.
Mit dieser Option zeigt netstat numerische statt symbolischer
Informationen an,
und das beschleunigt insbesondere bei Netzadressen die Anzeige immens,
weil sonst etliche DNS-Anfragen gestellt werden,
bevor die Ausgabe angezeigt werden kann.
Das kann ich auch selektiv mit
--numeric-hosts
, --numeric-ports
und --numeric-users
einstellen.
Mit der Option --verbose
oder -v
bekomme ich mehr Informationen,
insbesondere zu nicht konfigurierten Adressfamilien.
Ähnliches bietet die Option --extend
oder -e
, die zusätzliche
Informationen zum Beispiel bei Interfaces liefert.
Gebe ich die Option --continuos
oder -c
an, bekomme ich die
Informationen aller Sekunde neu ausgegeben.
OpenSSLs s_client
ist das dritte Werkzeug, welches ich zu Verbindungstests
verwende.
Dabei handelt es sich um einen generischen SSL/TLS Client, mit dem ich
verschlüsselte Protokolle wie HTTPS oder SSMTP und die
entsprechenden Server testen kann.
Der grundlegende Aufruf sieht wie folgt aus:
$ openssl s_client -connect $host:$port [ options ]
Die folgenden Optionen verwende ich häufiger, weitere sind, wie fast immer, in den Handbuchseiten zu finden.
smtp
, pop3
, imap
, ftp
.Bei Problemen mit der Aushandlung des SSL-Protokolls kann ich mit den
Optionen -bugs
, -ssl2
, -ssl3
, -tls
, -no_ssl2
, … experimentieren.
Details finden sich in der Handbuchseite.
Das folgende Beispiel zeigt eine HTTPS-Anfrage mit openssl:
Nachdem die verschlüsselte Verbindung
steht, gebe ich meine Anfrage an den Webserver genau so ein, wie ich es mit
netcat
bei einem unverschlüsselten Server tun würde und bekomme die Antwort
des Servers angezeigt.
Um die Authentisierung bei SMTP mit SASL zu testen, muss ich mir zunächst den String für die Credentials berechnen. Das PLAIN-SASL-Verfahren ist in RFC4616 beschrieben. Bei diesem sendet der Client einen String mit folgendem Aufbau an den Server.
authzid \0 authcid \0 passwd
Dabei ist
Der Server überprüft die Gültigkeit von authcid und passwd und dann, ob der Client damit die Rechte der authzid ausüben darf.
Da SMTP ein Plaintext-Protokoll ist, wird der String vor dem Senden mit Base64 codiert. Mit Hilfe von Perl kann ich mir diesen String berechnen lassen:
$ perl -MMIME::Base64 \
-e 'print encode_base64("john\0john\0passwd")';
am9obgBqb2huAHBhc3N3ZA==
Dann baue ich eine verschlüsselte Verbindung mit STARTTLS zum Mailserver auf und melde mich an:
$ openssl s_client -connect smtp.example.net:25\
-starttls smtp -quiet
depth=0 CN = smtp.example.net
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = smtp.example.net
verify return:1
250 DSN
EHLO client.example.net
250-smtp.example.net
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN am9obgBqb2huAHBhc3N3ZA==
235 2.7.0 Authentication successful
QUIT
221 2.0.0 Bye
Die Meldung 235 2.7.0 Authentication successful
zeigt mir, dass die
Anmeldung erfolgreich war.
Für knifflige Probleme, die ich mit den spezialisierten Werkzeugen nicht zu fassen kriege und denen mit einfacher Shell-Programmierung auch nicht beizukommen ist, benötige ich ein Werkzeug, das mächtiger ist als die Shell und universeller als die verschiedenen vorhandenen Spezialprogramme. Für mich ist das die Programmiersprache Perl. Insbesondere durch die vielen verfügbaren Module auf CPAN kann ich damit sehr schnell Speziallösungen für vertrackte Probleme zusammenbauen.
Ich hatte Perl als Werkzeug bereits im Abschnitt zur lokalen Fehlersuche beschrieben. Durch die vielen einfach verfügbaren und meist sehr gut getesteten und dokumentierten Module auf CPAN ist Perl für mich auch bei Netzwerkproblemen ein unentbehrliches Werkzeug für die Fehlersuche.
Das Perl Kochbuch [CT2000] hatte ich bereits erwähnt. Mit dessen Hilfe und den darin beschriebenen Modulen von CPAN war es mir möglich, in sehr kurzer Zeit ein spezielles Testprogramm für ein Timing-Problem bei einem Webservice zu schreiben.
Vor einiger Zeit hatte ich ein Problem, bei dem 502-Fehler eines Webservice von der Zeit, in der die Anfrage gesendet wurde, abhängig waren. Der Betreiber des Webservices war nicht kooperativ und um das Problem zu verifizieren benötigte ich die Möglichkeit HTTP-Anfragen gezielt zu verzögern.
Mit Hilfe des Kochbuches kam ich zu folgendem kurzen Programm:
http-injector.pl
1
#!/usr/bin/perl
2
use
Getopt
::
Long
;
3
use
IO
::
Socket
;
4
use
Time
::
HiRes
qw
(
sleep
);
5
6
my
%opt = ( delay => 0 );
7
8
GetOptions
(
\
%opt, 'delay=i');
9
10
my
$
serv
=
shift
;
11
my
$
port
=
shift
||
80
;
12
13
my
$
sock
=
IO
::
Socket
::
INET
->
new
(
PeerAddr
=>
$
serv
,
14
PeerPort
=>
$
port
,
15
Proto
=>
'tcp'
);
16
17
my
@in
=
<>
;
18
my
$
del
=
$
opt
{
delay
}
/
(
1.0
+
scalar
@in
);
19
foreach
(
@in
)
{
20
s
/
[
\r\n
]
+
$
//
;
21
sleep
$
del
;
22
print
$
sock
$
_
,
"\r\n"
;
23
}
24
sleep
$
del
;
25
print
$
sock
"\r\n"
;
26
27
while
(
my
$
line
=
<
$
sock>
)
{
28
print
$
line
;
29
}
In den Zeilen 2-4 lädt das Skript die benötigten Module. Die hier verwendeten sind Core-Module, das heißt bei der Installation von Perl automatisch mit installiert.
Getopt::Long
--delay
einen Integerwert angebe.IO::Socket
Time::HiRes
sleep()
Funktion bereit, die mit
Gleitkommazahlen zurechtkommt und Sekundenbruchteile schlafen kann.In Zeile 6 stellt es die Option --delay
auf den Wert 0 ein, falls
diese nicht explizit in der Kommandozeile angegeben wird.
In Zeile 8 werden die Optionen eingelesen.
Zeile 10 und 11 entnehmen den Server und gegebenenfalls den Port der Kommandozeile und in Zeile 13 öffnet es mit diesen Angaben den Socket.
In Zeile 17 liest das Skript die gesamte Eingabe in ein Array ein. Die benötigt es, weil es die Anzahl der Zeilen wissen muss, um die einzelnen Zeilen jeweils nach einem Bruchteil der Gesamtverzögerung senden zu können.
In den Zeilen 19-24 schließlich bereitet es die Zeilenenden auf und sendet die modifizierten Zeilen verzögert über den Socket.
In Zeile 25 schickt es die abschließende Leerzeile, nach der der Server antwortet.
In den Zeilen 27-29 liest das Skript die Antwort des Servers vom Socket und schreibt sie zur Standardausgabe.
Dieses Skript kann ich nun wie folgt aufrufen:
$
time
./http-injector.pl --delay 5 localhost 80 \
< request \
> reply
real 0m5.072s
user 0m0.056s
sys 0m0.012s
Dabei steht in der Datei request die HTTP-Anfrage, die ich an den Server sende. Nach fünf Sekunden ist die Anfrage beim Server, und die Antwort landet in der Datei reply.
Mit diesem Skript konnte ich nachweisen, dass dieselbe Anfrage einen Fehler lieferte, wenn sie mehr als drei Sekunden zur Übertragung brauchte und fehlerfrei beantwortet wurde, wenn sie weniger als drei Sekunden brauchte. Danach fand der Betreiber des Webservice die Stelle, an der der Timeout zu kurz eingestellt war und das Problem konnte aus der Welt geschafft werden.
Eines der grundlegenden und vielseitigsten Werkzeuge für das Netzwerk-Troubleshooting ist Ping. Mit diesem Programm kann ich:
Natürlich sind alle mit Ping gewonnenen Erkenntnisse mit einer Prise Salz zu nehmen.
In [Sloan2001] beschreibt der Autor die Anwendung von Ping beim Netzwerk-Troubleshooting sehr gut und ausführlich.
Die wichtigsten Kommandozeilenoptionen von ping
sind:
-i
mit Zeiten unter 0,2 Sekunden benötigen
Superuserrechte.
Um die Daten mit maximaler Geschwindigkeit zu senden, kombiniere ich diese
Option mit -l
.ping
sendet, ohne auf Antwort zu
warten.
Für mehr als drei Pakete benötige ich Superuserrechte.Daneben gibt es sehr viele weitere Optionen, die ich seltener verwende und deren genaue Auswirkungen ich nötigenfalls aus den Handbuchseiten erschließe.
Das ist der einfachste Test, den ich mit Ping ausführen kann. Ich gebe
$ ping $rechnername
ein und bekomme heraus, ob die betreffende Maschine erreichbar ist, ob also Antwortpakete von dort zurück kommen. Manche Versionen des Programms begnügen sich hier mit der einmaligen Ausgabe:
$rechnername is alive
Moderne Versionen zeigen nach Beendigung des Programms (nötigenfalls durch
Abbruch mit <CTRL>-C
) die Paketlaufzeiten und einige Statistiken an.
Restriktive Firewalleinstellungen können das Testen der Verbindung mit Ping verhindern. Bei etlichen Rechnern habe ich erlebt, dass diese nach der Installation zwar am Netzverkehr teilnehmen konnten, aber selbst nicht auf ICMP-Hello-Pakete antworteten. Das ist, aus meiner Sicht, eine Überreaktion auf die Tatsache, das einige DoS-Angriffe das ICMP-Protokoll und insbesondere ICMP-Hello verwendet haben.
Man kann nicht jedem vorschreiben, was er in seinem Netzwerk erlaubt und was nicht. Auf jeden Fall empfehle ich, sachlich einen möglichen oder eingebildeten Gewinn an Sicherheit gegenüber der Erschwernis bei der Netzwerkdiagnose abzuwägen.
Ein weiteres Anwendungsgebiet sind Performancemessungen im Netzwerk. Am einfachsten geht die Bestimmung der Paketlaufzeit zu einem entfernten Rechner und zurück, denn diese gibt Ping selbst aus. Aber auch die Datenübertragungsrate kann ich mit Ping bestimmen, sowie Netzwerklast für Lastmessungen erzeugen. Dazu suche ich mir einen Zeitpunkt aus, zu dem das Netz wenig belastet ist.
Einige Dinge gilt es zu beachten, wenn ich Ping beim Troubleshooting einsetze.
Zunächst arbeitet Ping nicht im luftleeren Raum, sondern hängt vom Funktionieren anderer Netzwerkelemente ab. Arbeite ich mit Hostnamen statt IP-Adressen, dann muss DNS funktionieren, oder die Namen müssen via /etc/hosts auflösbar sein.
Dann muss die Ethernet-Adresse des Zielrechners oder Routers aufgelöst werden können. Dazu muss ich sicherstellen, dass das ARP-Protokoll funktioniert oder statische ARP-Einträge verwenden, und zwar auf beiden Seiten. Oft wird die erste RTT bei einer Messung mit Ping durch das ARP-Protokoll verfälscht. Diesem Problem kann ich begegnen, indem ich grundsätzlich mehrere Ping-Pakete sende und die erste Zeit ignoriere.
Bei der Bestimmung der Datenübertragungsrate eines Links verwende ich ohnehin die niedrigste Zeit, da ist dieses Problem bereits berücksichtigt. Ich muss nur daran denken, immer mehrere gleichartige Ping-Pakete zu senden.
Ein weiteres mögliches Problem ist, dass das korrekte Funktionieren des Netzwerkes von Faktoren abhängen kann, die Ping nicht beeinflussen. So kann zum Beispiel ein kleines Ping-Paket problemlos hindurch gelangen, während größere Datenpakete der Anwendungsprotokolle verworfen werden.
Andererseits kann ICMP administrativ blockiert sein, während Anwendungsprotokolle von der Firewall durchgelassen werden, was zu einem False Negative führen kann. Gerade diese Konstellation trifft man häufig in Netzen, die von paranoiden Administratoren konfiguriert werden oder deren Administratoren die Auswirkungen der betreffenden Sperren nicht in vollem Maße abschätzen können. Ich halte es für sinnvoll, die Argumente für und wieder diese Sperren im Einzelfall zu klären und zu dokumentieren, damit es an dieser Stelle nicht immer wieder zu Diskussionen kommt, weil die Sicherheitseinstellungen das Troubleshooting erschweren. Für eine entsprechende Argumentation ist es notwendig, die möglichen Sicherheitsprobleme und gegebenenfalls alternative Gegenmaßnahmen zu kennen.
Einige mögliche Argumente für ein Sperren von ICMP sind:
Wenn Ping nicht komplett blockiert wird, ist es möglich, dass das Protokoll eine sehr niedrige Priorität am Router bekommt und allein dadurch, insbesondere bei gut ausgelasteten Routern unter den Tisch fällt oder zumindest die RTT stark verfälscht wird.
Bei manchen Routern kann es vorkommen, dass im Fall von NAT die ICMP-Echo-Antwort oder eine ICMP-Unreachable-Nachricht nicht an den anfragenden Host zurück geht.
Interessanterweise kann ich trotz unterdrücktem ICMP zumindest im lokalen Netzsegment herausbekommen, ob eine bestimmte IP-Adresse verwendet wird. Dazu lösche ich den ARP-Cache und schicke dann ein Ping-Paket zur entsprechenden Adresse. Ist danach ein korrekter ARP-Eintrag vorhanden, ist der Host angeschlossen und unterdrückt das ICMP-Echo.
Eines muss ich bei Ping-Tests immer im Hinterkopf behalten: Ping testet nur die Erreichbarkeit einer bestimmten IP-Adresse. Ob die angebotenen Dienste funktionieren und ob überhaupt der richtige Rechner diese Adresse verwendet, muss ich auf anderem Wege herausbekommen.
Sammle Argumente für und wider das Filtern von ICMP in den von dir betreuten Netzen. Dokumentiere die Argumente und mache die dokumentierten Argumente deinen Kollegen zugänglich. |
Einige Probleme im Netzwerk lassen sich auf fehlerhafte Routen zurückführen.
Die Routingtabelle des Kernels kann ich mit den Befehlen netstat -rn
,
route -n
oder ip route show
schnell kontrollieren.
Stelle ich dabei eine fehlerhafte Route fest, frage ich mich als nächstes:
woher kommt diese Route?
Bei der Beantwortung dieser Frage kann mir das Programm quagga helfen.
Quagga ist eine Programmsuite, die Protokolldämonen für die Routingprotokolle RIP, OSPF, BGP und ISIS enthält. Die Konfigurationssprache ist derjenigen von Cisco-Routern ähnlich, so dass jemand, der diese Geräte kennt, sich schnell hineinfindet. Beispielsweise lassen sich fast alle Code-Beispiele aus [Malhotra2002] mit Quagga nachvollziehen, obwohl diese für Cisco IOS geschrieben sind.
Ich kann die Protokolldämonen auf drei Arten konfigurieren: via telnet
,
über ein
Programm namens vtysh
oder durch Editieren der Konfigurationsdateien im
Verzeichnis /etc/quagga/ und anschließenden Neustart der Protokolldämonen.
Bei der Konfiguration via telnet
und vtysh
habe ich die
Möglichkeit, die interne Hilfefunktion als Gedächtnisstütze heranzuziehen.
Ausserdem werden Syntaxfehler sofort abgewiesen.
Der Befehl list
listet alle momentan möglichen Befehle nebst Argument
auf.
Ein ?
an beliebiger Stelle zeigt die möglichen Fortsetzungen. Das
heißt, ein Fragezeichen am Zeilenanfang listet alle momentan möglichen
Befehle, ein Fragezeichen nach einem Befehl listet die möglichen nächsten
Argumente.
Befehle muss ich nur soweit ausschreiben, dass sie eindeutig sind.
Das gleiche gilt für die Argumente.
Mit <Ctrl-P>
erhalte ich die letzte Zeile, mit <Ctrl-N>
die
nächste. An den Anfang der Zeile der Zeile komme ich mit <Ctrl-A>
, an
das Ende mit <Ctrl-E>
. Ausserdem funktionieren auf neueren Systemen
die Cursortasten und alle anderen Funktionen der libreadline.
Bei der interaktiven Arbeit mit den Protokolldaemonen habe ich drei Modi. Im
ersten, dem Operatormodus, kann ich im wesentlichen nur Informationen über
den aktuellen Zustand und die Routen abfragen. Mit dem Befehl enable
gelange ich in den Administratormodus und mit disable
komme ich
wieder zurück.
Im Administratormodus sehe ich mehr Informationen, vor allem kann ich die
Konfiguration ansehen, sichern oder wiederherstellen.
Aus dem Administratormodus komme ich mit dem Befehl configure terminal
in den Konfigurationsmodus und aus diesem mit end
oder exit
zurück in den Administratormodus.
Der Befehl exit
im Administrator- oder Operatormodus beendet die
Sitzung.
Im Konfigurationsmodus kann ich jeden einzelnen Aspekt der Konfiguration
ändern.
Dabei lassen sich einzelne Befehle zurücknehmen, indem ich sie mit
vorangestelltem no
noch einmal eingebe.
Finde ich zum Beispiel eine statische Route in der Konfiguration:
zebra# show running-config
...
ip route $destination $gateway
...
dann kann ich diese wie folgt entfernen:
zebra# config t
zebra(config)# no ip route $destination $gateway
zebra# end
Auf die gleiche Weise bearbeite ich auch ACL. Diese werden oft mit einer
Auffangregel am Ende abgeschlossen.
Füge ich eine neue spezifische Regel an, ist diese nicht aktiv, weil die
Auffangregel nun davor steht.
In diesem Fall entferne ich die Auffangregel mit vorangestelltem no
und
füge sie am Ende wieder an.
Mit den show ...
Befehlen kann ich mir den aktuellen Zustand des
Routingprotokolldämons ansehen. Das hilft mir oft schon, den Fehler
einzugrenzen. Suche ich aber nach der Ursache für den Fehler, dann benötige
ich Informationen darüber, wann etwas passiert ist. Dabei helfen mir die
log
und debug
Befehle. Mit dem log
Befehl lege ich
fest, wohin die Routingdämonen protokollieren und mit den debug
Befehlen, was protokolliert wird. Je nach Routingprotokoll und eingestellter
Protokollierung können die Logdateien sehr schnell sehr unübersichtlich
werden. Dann helfen mir ein paar Zeilen Perl-Skript, die relevanten
Informationen herauszusuchen und zusammenzusetzen.
Das Programm route
ist für die Anzeige und Manipulation von
Routingeinträgen zuständig.
Da ich die gleiche Funktionialität mit dem Befehl ip route
und
entsprechenden Optionen erreichen kann, gehe ich hier nicht näher auf
route
ein.
Falls das Paket iproute2 auf einen Rechner nicht installiert ist,
verweise ich auf die Handbuchseite von route
, die neben der ausführlichen
Erläuterung der Optionen Beispiele für die Verwendung enthält.
Die Programme der Samba-Suite, insbesondere die zum Paket smbclient zusammengefassten, können bei der Fehlersuche in Zusammenhang mit MS Windows Rechnern helfen.
Davon sind vor allem die folgenden bei der Fehlersuche für mich interessant:
wget
für HTTP, Dateien mit dem SMB-Protokoll herunterladen,Das Programm listet die IP Adresse, den NetBIOS-Namen, den Namen der
Arbeitsgruppe, des Betriebssystem und der SMB-Server-Version. Bei einem
lokalen Masterbrowser fügt es ein +
hinzu, bei einem Domain
Masterbrowser ein *
.
Das Programm wurde ursprünglich entwickelt, um die MS-RPC-Funktionalität in Samba zu testen. Damit kann man auch Windows NT Clients von UNIX-Arbeitsstationen aus administrieren. Es läßt sich gut in Skripten verwenden.
Für nähere Informationen schaue ich in die Handbuchseiten.
Mit diesem Client-Programm kann ich auf SMB- oder CIFS-Ressourcen auf
Servern zugreifen.
Das Interface ist ähnlich dem Programm ftp
für den Zugriff auf FTP-Server.
Damit kann ich Dateien vom Server holen, auf dem Server ablegen und Informationen über Verzeichnisse bekommen.
Mit dem Aufruf
$ smbclient -L $hostname -N
kann ich anonym alle Dienste des Servers $hostname
abfragen.
Mit diesem Programm kann ich Dateien von Servern mit dem SMB-Protokoll abholen, ähnlich wie mit dem Programm wget für das HTTP-Protokoll. Die Dateien werden als smb-URL angegeben. Eine smb-URL sieht wie folgt aus:
smb://[[[dom;]usr[:pas]@]host[/share[/path[/file]]]]
Für Informationen zu den möglichen Optionen schaue ich in die Handbuchseite.
Dieses Programm gibt eine Baumstruktur als Text aus, die alle bekannten Domains, die Server in diesen Domains und die Freigaben auf diesen Servern auflistet. Das kann in etwa so aussehen:
$ smbtree -N
WORKGROUP
\\HOST1 host1 server (Samba, Ubuntu)
\\HOST1\bilder
\\HOST1\psc HEWLETT-PACKARD OFFICEJET
\\HOST1\IPC$ IPC Service (host1 server (Samba))
\\HOST1\print$ Printer Drivers
\\HOST2 Samba 3.5.6
\\HOST2\public
\\HOST2\share
\\HOST2\IPC$ IPC Service (Samba 3.5.6)
Bei schwierigen Netzwerkproblemen verwende ich - quasi als große Kanone - tcpdump zum Mitschreiben des Datenverkehrs. Dabei setze ich tcpdump vorzugsweise auf Servern, die keine grafische Benutzeroberfläche haben, oder auf Routern/Bridges mit Linux oder BSD als Betriebssystem, ein. Auf Arbeitsstationen mit grafischer Oberfläche bevorzuge ich Wireshark.
Ich verwende tcpdump
Am häufigsten verwende ich tcpdump zum Mitschneiden von Datenverkehr. Dazu benötige ich Superuserrechte. Je nachdem, wie viele Schnittstellen mein Rechner hat, muss ich diese manchmal explizit angeben. Prinzipiell schalte ich die Namensauflösung ab, wenn ich mir die Datenpakete anzeigen lasse, um Verzögerungen durch DNS-Anfragen zu vermeiden.
Will ich die Daten nicht sofort auswerten, kann ich diese auch in eine Datei schreiben lassen, die ich dann später mit tcpdump, libtrace oder wireshark auswerte. Für die Auswertung der Datei benötige ich keine Superuserrechte sondern nur Leserechte auf die Datei.
Will ich über einen längeren Zeitraum Datenpakete mitschneiden und in Dateien archivieren, kann ich tcpdump anweisen, bei Erreichen einer bestimmten Dateigröße oder alternativ periodisch nach einer bestimmten Zeit mit einer neuen Datei zu beginnen.
Manche IPSEC-Verbindungen kann tcpdump dekodieren, wenn ich den Schlüssel angebe.
Bin ich nur an den Kopfdaten und nicht an den Anwendungsdaten interessiert, kann ich die maximale pro Datenpaket mitgeschnittene Länge vorgeben. Damit erhöht sich gleichzeitig die Verarbeitungsgeschwindigkeit, wenn ich die Daten in eine Datei schreibe. Andererseits können wichtige Informationen verloren gehen, wenn ich die Länge zu kurz wähle.
Die Optionen, die ich am häufigsten verwende, sind:
-l
.
Die Optionen -U und -l führen allerdings zu einer höheren I/O-Belastung, was
ich insbesondere bei Rechnern, die nahe ihrer Leistungsgrenze betrieben
werden, beachten muss.any
an.$filesize
ist.
An den Dateinamen wird eine fortlaufende Nummer angehängt.-w
angegebene Datei nach der in Sekunden
angegebenen Zeit zu rotieren.
Der Name der Datei sollte eine Zeitformatangabe für strftime(3) enthalten,
damit sie nicht überschrieben wird.
Zum Beispiel bekomme ich mit dump-%H%M.pcap die Stunde und Minute in den
Dateinamen, zu der der betreffende Mitschnitt beginnt.-v
angeben, um noch mehr Informationen zu bekommen.-C
oder -G
automatisch erzeugt
werden, zu begrenzen.
Je nach Kombination von -C
, -G
und -W
werden Dateien überschrieben
oder das Programm beendet sich bei Erreichen der Anzahl von Dateien.
Details finden sich in der Handbuchseite.Ein wesentlicher Punkt ist die Möglichkeit, zu bestimmen,
welche Datenpakete tcpdump mitschreibt und welche nicht.
Dazu verwende ich Filterausdrücke, die ich am Ende der Kommandozeile anfüge
oder in einer Datei sammele und mit der Option -F $dateiname
übergebe.
Detaillierte Informationen zu
den Filtermöglichkeiten von tcpdump oder libpcap im Allgemeinen finden sich
in der Handbuchseite pcap-filter.
In den meisten Fällen hänge ich den Filterausdruck an das Ende der Kommandozeile, weil das schneller geht. Nur bei komplizierten Filtern schreibe ich den Filter vor Benutzung in eine Datei.
Ein Filterausdruck besteht aus einem oder mehreren Primitiven, die über die
Begriffe and
, or
oder not
miteinander kombiniert werden können.
Ein Primitiv besteht aus einer ID, das ist ein Name oder eine Zahl,
der ein oder mehrere Qualifizierer vorangestellt werden. Die Qualifizierer
bestimmen, welche Bedeutung die ID hat.
So kann zum Beispiel die ID smtp
zusammen mit dem Qualifizierer zum einen auf eine Ethernetadresse verweisen
(ether host smtp
), auf eine IP-Adresse (host smtp
), auf den
TCP-Port 25 (port smtp
) oder auf etwas anderes.
Es gibt drei Arten von Qualifizierern, die miteinander kombiniert werden können:
host
(ein einzelner Rechner), net
(ein
ganzes Netz, Netznamen können zum Beispiel in /etc/networks definiert
werden), port
(ein TCP- oder UDP-Port, Portnamen werden in
/etc/services definiert) oder portrange
(ein Portbereich, zwei
Ports verbunden mit Bindestrich).src
,
dst
, src or dst
, src and dst
, inbound
,
outbound
. Fehlt der Richtungsqualifizierer, wird
src or dst
angenommen.ether
für Ethernet, ip
für IPv4, ip6
für IPv6, arp
, tcp
, udp
sein.
Protokollqualifizierer können noch weiter unterteilt sein, die Details
entnehme ich im Zweifel der Handbuchseite.Daneben gibt es noch einige spezielle Primitive, wie gateway
,
broadcast
, less
, greater
und arithmetische Ausdrücke,
die ich in Filterausdrücken verwenden kann.
Nachfolgend erläutere ich einige Primitive, die ich häufig einsetze:
$h
.$e
. Dabei kann ich
$e
als sechs durch Doppelpunkt getrennte Hexbytes oder als Name,
welcher in /etc/ethers definiert ist, angeben.$gw
, aber die IP-Adresse nicht.
So kann ich Datenpakete filtern, die über ein bestimmtes Gateway ankommen
oder abgehen.
Das funktioniert nur, wenn $gw
sowohl als IP-Adresse als auch als
Ethernet-Adresse aufgelöst werden kann.$n
mit einer
Bitmaskenlänge von $l
.
Es gibt noch andere Primitive, um das
auszudrücken, diese Notation funktioniert für IPv4 und IPv6.$p
.
Das ist nur gültig für TCP oder UDP.
Falls ich $p
als Name angebe, muss er in /etc/services definiert sein.$l
oder kleiner/gleich $l
.
Achtung, $l
ist nicht die Größe des angezeigten IP-Pakets sondern
inklusive weiterer Protokollheader.
Brauche ich das, teste ich die genauen Werte erst an einem einfacheren
Filterausdruck.$p
ist eines der in /etc/protocols definierten
Protokolle oder die betreffende Nummer, zum Beispiel 1 für icmp
,
6 für tcp
, 17 für udp
oder 89 für ospf
. Da
icmp
, tcp
und udp
Schlüsselwörter sind, muss ich sie
hier mit Backslash (\
) schützen: \icmp
, \tcp
, \udp
.ip proto \p or ip6 proto \p
, wobei p
für eines der drei Protokolle steht. Das heisst, ich bekomme die
entsprechenden Protokolle, unabhängig davon, ob sie via IPv4 oder IPv6
transportiert werden.So filtert zum Beispiel ip[0] & 0xf != 5
alle IPv4 Pakete mit
gesetzten Optionen.
Damit lassen sich sehr spezielle Filter erzeugen. Es setzt allerdings auch sehr genaue Kenntnis der untersuchten Protokolle voraus.
Weitere Informationen zu Optionen, Filterausdrücken und deren Bedeutungen gibt es in der Handbuchseite.
Neben ssh
ist telnet
für mich ein wichtiges Programm für die Fehlersuche im
Netz. Zum einen verwende ich es für den Zugriff auf ältere Router und
Switches, die das SSH-Protokoll nicht anbieten oder für den Zugriff auf die
interaktive Shell der Quagga-Protokolldämonen. Zum anderen setze ich es für
Tests von Anwendungsprotokollen wie SMTP, POP, IMAP, FTP oder HTTP
ein, die mit Plaintext via TCP arbeiten.
Zwar ist beim Testen der Plaintextprotokolle netcat
praktischer, aber
gerade auf älteren Rechnern finde ich häufiger telnet
als netcat
.
Der Vorteil von telnet
liegt eindeutig bei den interaktiven Shells, weil
es die Kennworte nicht auf der Konsole ausgibt, so dass sie nicht
durch einfaches Schultersurfen abgeschaut werden können. Außerdem
funktionieren die Cursortasten mit telnet
besser.
Ein Nachteil von telnet
gegenüber netcat
beim Testen der Plaintextprotokolle
ist, dass das Abbrechen einer Verbindung insbesondere mit einer deutschen
Tastatur eher unbequem ist.
Die Escape-Sequenz, mit der ich in den Kommandomodus umschalte, ist hier
ungünstig belegt, so dass ich meist darauf setze, dass die Gegenstelle die
Verbindung abbaut.
Alternativ kann ich beim Aufruf von
telnet
mit der Option -e <irgendwas>
ein anderes Zeichen für das
Umschalten in den Kommandomodus mitgeben, muss dann aber ein Zeichen
auswählen, dass im Protokoll nicht vorkommt und trotzdem leicht zu erreichen
ist.
Mit traceroute
untersuche ich Netzwerkpfade.
Außerdem kann ich damit die maximale Datenübertragungsrate der Netzsegmente
bestimmen, wie in Kapitel 12 beschrieben.
Bei Problemen mit der Erreichbarkeit eines Rechners oder Netzwerkes kann ich es dazu verwenden, das letzte erreichbare Netzsegment zu bestimmen um meine nächsten Schritte auf dieses zu fokussieren. Manchmal kann es bereits einen Hinweis auf die Art des Problems geben. Zum Beispiel deuten in der Ausgabe mehrfach auftretende IP-Adressen auf eine Schleife im Routing hin.
Wenn aufgerufen, sendet traceroute
Datenpakete zum Zielrechner, deren
IP-time-to-live-Feld (TTL) es zunächst auf 0 setzt und
dann sukzessive erhöht, bis sie den Zielhost erreichen.
Erhält ein Host oder Router ein Datenpaket mit einer TTL von 0,
verwirft er das Datenpaket und schickt an den Absender eine ICMP-Nachricht,
dass die TTL abgelaufen war.
Diese ICMP-Nachricht enthält die ersten Bytes des verworfenen Datenpaketes,
um dem Empfänger die Zuordnung zu erleichtern.
In der ursprünglichen Variante sendet traceroute
UDP-Pakete ab einer
bestimmten Portnummer und erhöht beim Senden nicht nur die TTL, sondern
gleichzeitig auch die Portnummer.
Das erleichtert, die zurückkehrenden ICMP-Nachrichten über den Port den
richtigen TTL zuzuordnen.
Damit ist es möglich mehrere Datenpakete mit verschiedenen TTL und Ports
quasi-parallel zu versenden und die Messzeit zu verkürzen.
Wenn eine UDP-Nachricht am Zielhost angekommen ist, sendet dieser keine
ICMP-ttl-exceeded-Nachricht, sondern stattdessen ICMP-port-unreachable, wenn
an dem betreffenden Port kein Prozess lauscht.
Darum ist es wichtig, für traceroute
via UDP einen Bereich zu verwenden,
in dem auf dem Zielhost kein UDP-Port in Verwendung ist.
Zwar kann der Zielhost auch an der IP-Adresse erkannt werden, aber gerade bei
multihomed Hosts oder Routern kann das Datenpaket an einem anderen Interface
ankommen und damit die ICMP-Antwort eine andere Absenderadresse haben.
Da Firewalleinstellungen in Netzwerken immer restriktiver werden, gibt es
einige Varianten von traceroute
, die auch andere Protokolle verwenden und
mit einem Port auf dem Zielrechner auskommen. So ist es möglich, traceroute
mit ICMP-echo-Paketen (Ping), TCP-Paketen (zum Beispiel Port 25 oder 80)
oder mit nur einem UDP-Port (zum Beispiel 53 oder 123) zu verwenden, wenn
die Firewall für eines dieser Protokolle freigegeben ist.
Zusätzlich zur IP-Adresse der Hops auf dem Weg zum Zielrechner zeigt
traceroute
oft noch die RTT zwischen gesendetem Datenpaket und ICMP-Antwort
an, aus der ich Rückschlüsse auf Art und Zustand des betreffenden
Netzsegmentes ziehen kann.
Auch bei traceroute
, wie bei allen Werkzeugen, muss ich bei der
Interpretation der Ergebnisse einige Sachen berücksichtigen.
So zeigt zum Beispiel die Reihenfolge der Hops nur, wie die Daten in einer Richtung zum Zeitpunkt der Messung gelaufen sind. Bei Änderungen im Routing kann sich der Weg bereits während der Messung ändern. Und der Rückweg kann ganz anders aussehen, wenn das Routing asymmetrisch ist.
Einige IP-Stacks senden ICMP-unreachable-Nachrichten mit einer TTL, die
gleich der ist, mit der das Datenpaket ankam.
Diese erscheinen dann als Zielhost bei symmetrischem Routing erst bei der
doppelten TTL, also viel weiter weg als sie in Wirklichkeit sind.
Die Hops davor sind dann alle mit *
markiert.
Wenn auf dem Weg der Daten zum Zielhost Adressen umgesetzt werden (NAT),
dann gehen die ICMP-Nachrichten nach der NAT an die umgesetzte Adresse und
erreichen vielleicht nicht den Rechner, auf dem ich traceroute
gestartet habe.
Schließlich ist es möglich, dass eine sehr restriktive Firewall die
Traceroute-Pakete einfach stillschweigend verwirft. In diesem Fall kann es
sinnvoll sein, traceroute
mit anderen Protokollen zu wiederholen und die
Ergebnisse zu vergleichen.
Abgesehen davon ist es möglich, mit traceroute
eine
relativ genaue Karte der erreichbaren Netze zu erstellen.
Da es unterschiedliche Implementierungen von traceroute
gibt, deren
Kommandozeilenoptionen zum Teil erheblich voneinander abweichen, verweise
ich auf die Dokumentation des installierten Programmes.
Neben tcpdump
und den libtrace-tools
arbeite ich oft mit wireshark
zur
Auswertung von Paketmitschnitten.
Da dieses Werkzeug mit einer grafischen Benutzeroberfläche daherkommt, habe
ich es auf kaum einem Server installiert, wegen der bequemen
Handhabung verwende ich es aber gern zur Auswertung von Paketmitschnitten auf
meiner Arbeitsstation.
Im Internet finden sich etliche Tutorials zum Einsatz von Wireshark, darum gehe ich hier nur kurz auf die Menüpunkte ein, die ich am häufigsten einsetze.
Einen ersten Überblick über einen geladenen oder mit Wireshark erzeugten Paketmitschnitt bekomme ich über den Menüeintrag Analyze > Expert Info Composite. In dem daraufhin geöffneten Fenster sind fünf Panels über die Reiter Errors, Warnings, Notes, Chats und Details zu erreichen. Die ersten vier Panels enthalten Bemerkungen von Wiresharks zu Ereignissen mit der Priorisierung entsprechend dem zugehörigen Reiter. Im Panel Details finde ich noch einmal alle Bemerkungen in der Reihenfolge, in der sie im Paketmitschnitt vorkommen. Praktisch ist, das beim Anklicken einer Notiz das zugehörige Datenpaket im Hauptfenster gleich ausgewählt wird.
Über den Menüeintrag Statistics > Conversations bekomme ich ebenfalls ein Fenster mit mehreren Panels, die ich über Reiter wie Ethernet, IPv4, IPv6, TCP, UDP, …, jeweils gefolgt von einer Zahl, auswählen kann. Dabei sind nur die Reiter aktiv, für die Wireshark Konversationen, das heisst Datenpakete mit dem entsprechenden Protokoll, identifizieren konnte. Die Zahl gibt die Anzahl der verschiedenen Konversationen an.
Im Panel ist dann eine Liste mit einer Zeile pro Konversation und den zugehörigen Parametern zu sehen. Über das Kontextmenü kann ich die entsprechende Konversation als Displayfilter für das Hauptfenster hinzufügen oder einfärben.
Bei TCP und UDP kann ich auch Follow Stream anwählen, um in einem weiteren Fenster die Nutzdaten der Verbindung zu sehen und zu speichern. Damit komme ich sehr bequem an die Nutzdaten heran.
Über diesen Menüeintrag bekomme ich einen grafischen Überblick über den zeitlichen Ablauf des Datenverkehrs. Hier kann ich mit Filtern einzelne Aspekte farblich hervorheben.
Bleibt schließlich die Paketliste im Hauptfenster.
Mit Displayfiltern kann ich die angezeigten Datenpakete einschränken. Außerdem kann ich Zeitreferenzpunkte setzen, für eine Analyse des Zeitverhaltens.
Auch hier habe ich die Möglichkeit, über das Kontextmenü und Follow Stream an die Nutzdaten heranzukommen.
Und vor allem kann ich für jedes Datenpaket die verschiedenen Protokollschichten auf- und zuklappen und brauche die entsprechenden Protokollparameter nicht selbst aus dem Hexdump zu ermitteln.