Content
Das Hangup-Problem
Eine der am häufigsten in der Newsgroup gestellten Fragen ist folgende:
Ich habe meinen Fli4l Router so konfiguriert, daß er nach x Sekunden/Minuten ohne Traffic auf der Leitung auflegt. Nun sind alle Rechner in meinem Netz aus, es gibt also keinen Datenverkehr mehr auf der Leitung und trotzdem legt der Router nicht auf. Kann mir das jemand erklären?
Der ppp-Daemon, das Programm, das die Daten über die isdn-, dsl- oder Modem-Leitung schickt, überwacht den Zustand der Leitung und merkt sich den Zeitpunkt, an dem das letzte Paket geschickt wurde. Liegt der Zeitpunkt mehr als die in HANGUP_TIMEOUT gesetzte Zeit zurück, legt der pppd auf. Solange man im Web browsed, chatted, News liest o.ä. ist es klar, daß die Leitung relativ aktiv ist, und der pppd daher nicht auflegt. Aber warum tut er das nicht, wenn kein Rechner mehr an ist und daher eigentlich keine Daten mehr über den Router transferiert werden können? Die Antwort ist eigentlich ganz einfach. Da man bei der Einwahl beim Provider eine IP-Adresse zugewiesen bekommt, die von jedem anderen Rechner im Netz aus erreichbar ist, kommen immer wieder Anfragen beim Router an, sei es, weil
- man die IP-Adresse eine p2p-Filesharing-Nutzers geerbt hat und nun ständig andere p2p-Clients versuchen, vom Router Files zu saugen, aber keinen p2p-Client finden, der sich mit ihnen unterhält,
- irgendwelche Scriptkiddies nach Rechnern mit Sicherheitslücken suchen, aber von der Firewall abgewiesen werden,
- Würmer die Fühler nach bekannten Lücken ausstrecken und gleichfalls an der Firewall scheitern u.a.m.
All diese reinkommenden Pakete werden als Aktivität auf der Leitung interpretiert und da die Leitung aktiv ist, legt der ppp-Daemon nicht auf. Da liegt natürlich die Frage nahe, ob man dem ppp-Daemon nicht einfach beibringen könnte, diesen Datenverkehr von außen zu ignorieren. Das geht leider bisher nicht, da nicht der Daemon selbst Buch über Aktivitäten auf der Leitung führt, sondern der Linux-Kern dies tut. Der Daemon erkundigt sich nur regelmäßig beim Kern, wie es mit der Leitung aussieht und reagiert entsprechend.
Die Lösung
Mit dem 2.4er Kern ändert sich das. Dieser Kern gestattet es zu bestimmen, welche Pakete als Aktivität auf dem Netz gewertet werden sollen. Dazu spezifiziert man einen einen Filter-Ausdruck (über die pppd-Option active-filter), den der pppd an den Kern weiterreicht. Dieser Filter wird auf jedes ppp-Paket angewendet und nur wenn der Filterausdruck wahr ist, wird das Paket als Netzwerkaktivität gewertet. Damit können wir nun also sagen, daß nur rausgehender Datenverkehr den ppp-Daemon am Auflegen hindern soll, einfach indem wir den Filter 'outbound' mitgeben. Leider werden wir dann feststellen, daß das nicht hilft. Wir machen alle Rechner im eigenen Netz aus, und trotzdem legt der Router nicht auf. Unser Router reagiert leider auf Anfragen von außen und sendet selbstständig Pakete als Reaktion auf Anfragen anderer Rechner. Um zu erklären, warum er das tut und wie wir dieses Problem lösen, müssen wir einen kurzen Abstecher in die Untiefen der Netzwerk-Protokolle machen. Im wesentlichen spielen hier 4 Protokolle eine Rolle:
- IP als das zu Grunde liegende Protokoll, mit dessen Hilfe Datenpakete von einem Rechner zum anderen gelangen. Die Datenpakete werden von einem Rechner zu einem anderen Rechner über verschiedene Router geschickt, die Rechner werden dabei über IP-Adressen adressiert.
- UDP (user datagram protocol) setzt auf IP auf und gestattet es, Telegramme (datagramme) von einer Anwendung zu einer anderen zu senden, wobei nicht garantiert wird, daß die Daten auch ankommen. Darum muß sich die Anwendung selbst kümmern. Der Rechner, auf dem die Zielanwendung läuft, wird durch eine IP-Adresse spezifiziert, die Anwendung auf diesem Rechner durch einen Port. Die Daten fliessen also von IP1:Port1 nach IP2:Port2.
- TCP (transmission control protocol) setzt gleichfalls auf IP auf und gestattet es, eine Verbindung zwischen zwei Anwendungen herzustellen, über die Daten gesichert übertragen werden (gesichert heißt hier, das Protokoll kümmert sich drum, daß die Datem auch wirklich ankommen). Dazu wird zuerst eine Verbindung zwischen den Anwendungen aufgebaut (der Server wartet auf einem bekannten Port auf Verbindungsanforderungen, der Client stellt eine Verbindung zu Ip-Adresse:Bekannter-Port her), dann werden die Daten übertragen und die Verbindung wird am Ende wieder abgebaut. Die Adressierung erfolgt wie bei UDP.
- ICMP (internet control message protocol) dient dazu, Steuer- und Fehlermeldungen zwischen Rechnern auszutauschen.
Wenn ich mit einem anderen Rechner kommunizieren will, muß ich mich entscheiden, ob ich Verbindungsorientiert und damit über tcp oder verbindungslos über udp kommunizieren will. In beiden Fällen adressiere ich meinen Kommunikationsparner über IP:Port. Versuche ich, eine TCP-Verbindung zu IP:Port aufzubauen und auf der Gegenseite gibt es niemanden, der an diesem Port wartet, wird der Verbindungsaufbau abgebrochen. Die Gegenseite (unser Router) sendet ein TCP-RST (TCP-Reset) und signalisiert damit die Ablehnung des Verbindungswunsches. Da unser Router aber etwas sendet, gilt das als Aktivität auf der Leitung und der ppp-Daemon legt nicht auf :( So ähnlich läuft das, wenn ich versuche, über udp ein Datagramm an eine Anwendung zu schicken. Ich sende Daten an IP:Port und eine an diesem Port wartende Anwendung empfängt sie. Gibt es diese Anwendung nicht, muß die Gegenseite das signalisieren. Da hier kein Verbindungsaufbau stattfindet, in dessen Rahmen man das signalieren kann, muß ein anders Protokoll her, icmp. Die Gegenseite sendet über icmp die Nachricht "port unreachable". Macht das unser Router ist das wieder rausgehender Traffic und die Leitung bleibt oben. Und als letztes Beispiel ping. Wenn jemand wissen will, ob ein Rechner mit einer bestimmten IP an ist, sendet er einfach ein ping an diesen Rechner. Das ping ist in diesem Fall ein icmp echo request, das von der Gegenseite mit einem icmp echo reply beantwortet werden sollte, wenn sie an ist. Angewendet auf unseren Router: Pingt uns jemand an, generiert der Router continuierliche echo replies, rausgehende Aktivität auf der Leitung und der ppp-Daemon legt nicht auf. Lange Rede, kurzer Sinn: Wir müssen wesentlich mehr filtern, unseren Ausdruck also modifizieren. Wir dürfen die Aktivität nicht nur auf rausgehenden Traffic beschränken, sondern zusätzlich auch noch die automatisch generierten Messages des Routers ausschließen. Eine Leitung ist demnach aktiv, wenn:
- es rausgehenden Traffic gibt,
- der kein TCP-RST ist (kein abgelehnter tcp-Verbindungsaufbau),
- und der auch kein icmp Paket ist, es sein denn, es ist ein echo request (also wir pingen jemanden an).
Für das Erkennen eines TCP-RST und eines ICMP echo requests müssen wir wissen, wie diese Dinge in den Paketen kodiert werden und wie man das dann im Filter spezifiziert. Die Formate der Header hängen hinten an, wir sehen, daß
- bei einem TCP-RST das Bit 2 des 13 Bytes im tcp header gesetzt ist
- bei einem ICMP echo request im Type Feld des ICMP-Paketes eine 8 steht.
Das stecken wir jetzt in den Filterausdruck, der dann wie folgt aussieht: 'outbound and not icmp[0] != 8 and not tcp[13] & 4 != 0' Damit halten Pakete, die vom lokalen Netz ins Internet gehen, die Verbindung offen, es sein denn es sind
- TCP-Verbindungsablehnungen
- icmp Pakete (mit Ausnahme von ping requests).
Umgesetzt wurde das ganze in fli4l 2.1. Der 2.4er Kern stellt den Filtermechanismus für ppp bereit, der pppd unterstützt dieses Interface. Leider wird der pppd sehr groß, wenn man active-filter aktiviert. Er muß den logischen Ausdruck in ein Format übersetzen, das der Kern versteht und deshalb einen kleinen Compiler/Optimierer dazulinken, der in etwa 90 KByte groß ist. Da das ganz schöner Ballast ist, wurde der Compiler entfernt und in ein separates Tools gepackt. Dieses Tool generiert den Paket-Filter-Code, der dann vom pppd einfach eingelesen und an dem Kern weitergereicht wird. Dadurch vergrößert der active-filter den pppd nur noch um 4 KByte. Aktiviert wird das ganze, indem man einfach in der Konfiguration *_FILTER='yes' setzt.
Alternative Lösung
Da 2.0 noch auf dem Linux-Kern 2.2 aufsetzt, der active filter nicht unterstützt, mußte für 2.0 eine alternative Lösung gefunden werden. Diese ist als opt_hangup in der opt-db zu finden und versucht, durch Überwachung der Liste der maskierten Verbindungen eine Inaktivität festzustellen und dann aufzulegen.
TCP Header Format
Quelle: RFC793
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Control Bits: 6 bits (from left to right):
URG: Urgent Pointer field significant
ACK: Acknowledgment field significant
PSH: Push Function
RST: Reset the connection
SYN: Synchronize sequence numbers
FIN: No more data from sender
ICMP Echo or Echo Reply Message
Quelle: RFC 792
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data ...
+-+-+-+-+-
Type
8 for echo message;
0 for echo reply message.
