» SelfLinux » Sicherheit » IP-Tables » Abschnitt 8 SelfLinux-0.12.1
zurück   Startseite Kapitelanfang Inhaltsverzeichnis GFDL   weiter

SelfLinux-Logo
Dokument IP-Tables  Autor
 Formatierung
 GFDL
 

10 Verbindungsverfolgung (Connection Tracking)


10.1 Grundlegendes zur Verbindungsverfolgung

Unter Verbindungsverfolgung oder auch connection tracking versteht man das Speichern von Statusinformationen einer Verbindung (z.B. Quell- und Zieladresse, Portnummern, Protokolltyp, Timeouts,...). Bei iptables ist dafür die state-Option zuständig (siehe  Explizite Erweiterungen).

Die Verbindungsverfolgung erfolgt entweder in der PREROUTING- oder in der OUTPUT- Kette. Die Pakete werden automatisch defragmentiert, Fragmente (siehe  Fragmente filtern) brauchen also nicht behandelt werden.

Die Statustabellen für UDP- und TCP Verbindungen werden in /proc/net/ip_conntrack gehalten. Wie die Einträge in dieser Tabelle aussehen, wird später gezeigt. Die maximale Anzahl der Verbindungen, die diese Tabelle aufnehmen kann, wird in /proc/sys/net/ipv4/ip_conntrack_max gespeichert und je nach verfügbaren Hauptspeicher mit einem Standardwert belegt (z.B. 512 MB, ip_conntrack_max = 32760).

Die nächsten drei Unterkapiteln erläutern die Verbindungsverfolgung für die Protokolle udp, tcp und icmp, im letzten Kapitel wird das FTP-Protokoll behandelt.


10.2 UDP

UDP wird auch als verbindungsloses (zustandsloses) Protokoll bezeichnet, da im Header keine Sequenznummern oder Ähnliches zu finden sind. Das bedeutet aber nicht, dass man UDP-Verbindungen nicht aufspüren und verfolgen kann. Es gibt immer noch andere nützliche Informationen, welche das genau sind, zeigt der folgende Eintrag in der Statustabelle:

udp  17 21 src=192.168.1.3 dst=192.168.1.88 sport=1032 dport=53 [UNREPLIED] src=192.168.1.88 dst=192.168.1.3 sport=53 dport=1032 use=1

Aus diesem Eintrag kann Folgendes herausgefunden werden:

  • Protocol = udp (IP Protokollnummer ist 17)
  • Der Eintrag läuft nach 21 Sekunden ab, und ist danach nicht mehr gültig.
  • Quell und Zieladressen mit entsprechenden Ports der Anfrage
  • Quell und Zieladressen mit entsprechenden Ports der erwarteten Antwort
  • Die Verbindung ist als UNREPLIED markiert, es wurde also noch nichts empfangen

Die folgenden Regel erlaubt UDP-Verbindungen vom eigenen Rechner (bei einer restriktiven Politik)

root@linux # iptables -A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT
root@linux # iptables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT

Udp Timeouts (Zeitlimits) werden vor dem Kompilieren in /usr/src/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c gesetzt, und zwar genau an dieser Stelle:

ip_conntrack_proto_udp.c
*** Datei /usr/src/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c
#define UDP_TIMEOUT (30*HZ)
#define UDP_STREAM_TIMEOUT (180*HZ)
****** Ende Datei
     

Eine einzelne TCP-Anforderung wird normalerweise 30 Sekunden in der Tabelle vorgehalten, im Falle unseres Eintrages (Beispiel oben) sind es nur noch 21 Sekunden. Das bedeutet, dass die Verbindungsanfrage bereits seit 9 Sekunden bestand ohne dass ein Antwortpaket empfangen wurde. Wenn nun ein Antwortpaket eintrifft, wird das Zeitlimit auf 30 Sekunden zurückgesetzt und die UNREPLIED Markierung gelöscht. Der Tabelleneintrag hätte nun folgendes Aussehen:

udp 17 28 src=192.168.1.3 dst=192.168.1.88 sport=1032 dport=53 src=192.168.1.88 dst=192.168.1.3 sport=53 dport=1032 use=1

Sollten mehrere Verbindungsanfragen (multiple requests) und Verbindungsantworten zwischen gleichen Socket-Paaren auftreten, so wird ein Stream festgestellt und das Zeitlimit auf 180 Sekunden erhöht. Der Tabelleneintrag hätte nun folgendes Aussehen:

udp  17 177 src=192.168.1.2 dst=192.168.1.50 sport=1032 dport=53 src=192.168.1.50 dst=192.168.1.2 sport=53 dport=1032 [ASSURED] use=1

Man erkennt die Markierung ASSURED, das bedeutet, dass die Verbindung am längsten aufrechterhalten wird. Wir erinnern uns an den Parameter ip_conntrack_max, der die maximale Verbindungsanzahl festlegte. Bei Erreichen dieses Limits werden die mit UNREPLIED markierten Verbindungen zuerst gelöscht und die mit ASSURED Markierten zuletzt.

Anmerkung: Es gibt weder für UDP noch für TCP Verbindungen ein absolutes Zeitlimit.


10.3 TCP

Jede TCP-Verbindung wird mittels eines Drei-Wege-Händeschüttelns (three-way handshake) aufgebaut. Kurz zur Erinnerung:
Es beginnt mit einer Synchronisationsanforderung (SYN) des Client, der Server bestätigt diese Synchronisationsanforderung (SYN+ACK) und letztendlich bestätigt der Client die aufgebaute Verbindung (ACK). Alle weiteren TCP-Pakete dieser Verbindung werden ebenfalls mit einem ACK-Flag gekennzeichnet.

Neben SYN und ACK-Flags beinhaltet der TCP-Header eine 32 bit Sequenz (Sequence Number) eine ACK-Nummer (Acknowledgment Number), sodass ein TCP-Paket eindeutig einer Verbindung zugewiesen werden kann.

Zur Verfolgung von TCP-Verbindungen dienen beispielsweise folgende Regeln:

root@linux # iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
root@linux # iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT

10.3.1 Tabelleneinträge während des Verbindungsaufbaus

An dieser Stelle sollen die Tabelleneinträge während des Verbindungsaufbau analysiert werden:

1) Eine Verbindungsanforderung (SYN-Paket) wandert in die OUTPUT-Kette und wird dort akzeptiert.

tcp  6 119 SYN_SENT src=140.208.5.62 dst=207.46.230.218 sport=1 dport=80 [UNREPLIED] src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1 use=1

Der Verbindungsstatus ist SYN_SENT und die Verbindung wurde als UNREPLIED markiert.

2) Nach Empfang eines SYN+ACK Paketes wird der Verbindungsstatus auf SYN_RECV gesetzt und die UNREPLIED Markierung verschwindet.

tcp  6 57 SYN_RECV src=140.208.5.62 dst=207.46.230.218 sport=1 dport=80 src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1 use=1

3) Nun sollte eine Bestätigung, also ein ACK-Paket, folgen. Dieses müsste dieselbe Sequenznummer wie das ACK Paket des Servers aufweisen. Bei Übereinstimmung erhält die Verbindung eine ESTABLISHED Markierung und der Tabelleneintrag wird als ASSURED markiert. (Hinweis: Bei Erreichen des ip_conntrack_max Limits werden die mit UNREPLIED markierten Verbindungen zuerst gelöscht und die mit ASSURED Markierten zuletzt.)

tcp  6 431985 ESTABLISHED src=140.208.5.62 dst=207.46.230.218 sport=1 dport=80 src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1 [ASSURED] use=1

10.3.2 Die Statustabelle aus Sicht der Verbindungsverfolgung

Bei der Verbindungsverfolgung gibt es lediglich den Status NEW, ESTABLISHED, RELATED und INVALID ( Explizite Erweiterungen).

Achtung! Dieser Status ist nicht äquivalent zum TCP Status. Wenn beispielsweise ein ACK-Paket zu einem nicht-existierenden Rechner hinter der Firewall versendet wird, wird ein Verbindungseintrag in der Statustabelle erzeugt, weil es als erstes Paket einer noch nicht bestehenden Verbindung (und damit als NEW) gilt. Unter dem Gesichtspunkt, dass solche ACK Pakete die Statustabelle überfluten können, ist die folgende Regel sehr sinnvoll:

root@linux # iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

Diese Regel stellt sicher, dass der Aufbau von TCP-Verbindungen ausschlißlich durch SYN-Pakete initiiert werden kann. Sie hat jedoch einen kleinen Nachteil:
Manchmal treten bei TCP-Verbindungen äußerst lange Wartezeiten auf, und die korrespondierenden Einträge verschwinden dann aus der Statustabelle. Wenn aber nun die Verbindung mit ACK-Paketen (Daten) von außen fortgesetzt wird, dann verhindert die Regel den Transport nach innen. Anders ausgedrückt: Die Firewall dachte, die Verbindung wurde abgebrochen und entfernte deshalb den Eintrag in der Statustabelle. Das ankommende Datenpaket (ACK) kann keiner Verbindung zugeordnet werden und gilt deshalb als "NEW". Die obenstehende Regel blockiert aber TCP-Pakete ohne SYN-Flag, die zu keiner Verbindung zugeordnet werden können. [besser Workaround  tcp-window-tracking]


10.3.3 Zeitbeschränkungen (Timeouts)

Die Zeitbeschränkungen ähneln sehr denen von UDP. Wenn eine Verbindung ein Paket erhält, wird der Timeout zurückgesetzt. Die Zeitbeschränkungen sind fest eincompiliert und in der Datei ersichtlich:
/usr/src/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
Wichtig sind die folgenden Zeilen:

ip_conntrack_proto_tcp.c
[static unsigned long tcp_timeouts]
= { 30 MINS,    /*      TCP_CONNTRACK_NONE,           */
    5 DAYS,     /*      TCP_CONNTRACK_ESTABLISHED,    */
    2 MINS,     /*      TCP_CONNTRACK_SYN_SENT,       */
    60 SECS,    /*      TCP_CONNTRACK_SYN_RECV,       */
    2 MINS,     /*      TCP_CONNTRACK_FIN_WAIT,       */
    2 MINS,     /*      TCP_CONNTRACK_TIME_WAIT,      */
    10 SECS,    /*      TCP_CONNTRACK_CLOSE,          */
    60 SECS,    /*      TCP_CONNTRACK_CLOSE_WAIT,     */
    30 SECS,    /*      TCP_CONNTRACK_LAST_ACK,       */
    2 MINS,     /*      TCP_CONNTRACK_LISTEN,         */
};
      

10.3.4 Terminierung der Verbindung

Der Verbindungsabbau kann auf zwei unterschiedliche Arten erfolgen. Der natürliche Weg (FIN+ACK) wurde kurz skizziert:

      Verbindungspartner 1     Verbindungspartner 2
                        .........
                        .........
         FIN+ACK   --->
                        <---    ACK
      

Sollte die Statustabelle den Verbindungswert auf TIME_WAIT setzen, dann wird der Eintrag nach zwei Minuten automatisch gelöscht.

Der andere Weg des Verbindungsabbaus ist, wenn ein Verbindungspartner ein Reset-Paket sendet (RST-Flag gesetzt). Reset Pakete werden nicht bestätigt (kein resultierendes ACK-Paket). Der Verbindungsstatus in der Tabelle wird auf CLOSE geändert und läuft nach 10 Sekunden ab. Das passiert häufig bei (ausgelasteten) HTTP-Servern.


10.4 ICMP

Es gibt nur vier ICMP-Typen, deren Pakete als NEW oder ESTABLISHED markiert werden können.

  1. Echo request (ping, 8) und echo reply (pong, 0).
  2. Timestamp request (13) und reply (14).
  3. Information request (15) und reply (16).
  4. Address mask request (17) und reply (18).

Die Anforderung (request) wird in jedem fall mit NEW markiert und die Antwort (reply) mit ESTABLISHED.

Pakete anderer ICMP-Typen können nur eine verwandtschaftliche Beziehung zu einer Verbindung haben und werden deshalb mit RELATED markiert.

Hier ein paar Beispiele:

root@linux # iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED, RELATED -j ACCEPT
root@linux # iptables -A INPUT -p icmp -m state --state ESTABLISHED, RELATED -j ACCEPT
  1. Ein icmp echo request ist NEW somit in der OUTPUT Kette erlaubt.
  2. Ein icmp echo reply als Antwort auf einen echo request ist ESTABLISHED und somit in der INPUT Kette erlaubt. Ein echo reply würde immer in der OUTPUT Kette herausgefiltert werden, da keine korrespondierende Echo-Anforderung (echo request) die INPUT-Kette passieren kann.
  3. Ein icmp redirect gilt als RELATED und passiert somit sowohl INPUT- als auch OUTPUT-Kette, vorausgesetzt es existiert eine korrespondierende TCP- oder UDP-Verbindung in der Statustabelle.

10.5 Verbindungsverfolgung und ftp


10.5.1 FTP-Freigabe

Man benötigt das ip_conntrack_ftp Kernelmodul.

Für den Hausgebrauch (einzelner PC am Internet) eignen sich die folgenden zwei Regeln, um FTP-Verbindungen zu akzeptieren:

root@linux # iptables -A INPUT -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
root@linux # iptables -A OUTPUT -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT

(Voraussetzung: icmp RELATED wird erlaubt,  siehe vorangehendes Unterkapitel)

Leider ist es damit noch nicht getan, eine FTP-Verbindung benötigt einen eigenständigen Datenkanal, welcher durch zwei unterschiedliche Arten aufgebaut werden kann. Die folgenden zwei Unterkapitel beschreiben die Vorgehensweise.


10.5.2 Aktives ftp

Der FTP-Client sendet eine Port-Nummer über den FTP-Kanal zum FTP-Server. Dieser verbindet sich von Port 20 zu diesem Port und sendet über diese neue Verbindung (ftp-data) die Daten, z.B. das Resultat eines ls oder eines get-Kommandos. Die FTP-Datenverbindung (ftp-data) wird also vom Server aufgebaut, und nicht wie die FTP-Verbindung vom Client.

Um aktives FTP zu erlauben (Der Zielport ist nicht bekannt), müsste eine generelle Regel für alle einkommenden Verbindungen von Port 20 (FTP-Server) auf hohe Port-Nummern (>1023) des Clients anlegt werden. Dies stellt jedoch eine sehr unsichere Lösung dar.

Eine besseren Ansatz besteht in der Verbindungsverfolgung. Dazu muß das Modul ip_conntrack_ftp eingebunden werden. Es durchsucht das PORT Kommando nach der Port-Nummer, mit der sich der Server verbinden wird. Damit kann eine Beziehung zwischen ftp und ftp-data hergestellt werden (RELATED). Die folgenden Regeln sind also vollkommen ausreichend:

root@linux # iptables -A INPUT -p tcp --sport 20 -m state --state ESTABLISHED,RELATED -j ACCEPT
root@linux # iptables -A OUTPUT -p tcp --dport 20 -m state --state ESTABLISHED -j ACCEPT

10.5.3 Passives ftp

Im Gegensatz zu aktivem ftp wird die gewünschte PORT-Nummer der Datenverbindung nicht vom Client sondern vom Server festgelegt (via PORT-Kommando). Der Client verbindet sich dann zu diesem Port auf dem Server und der Datenverkehr kann beginnen. Obwohl diese Vorgehensweise als sicherer gilt, sollte man bedenken, dass fast gar nichts mehr über die Portnummern der Verbindung bekannt ist.

Analog zu aktiven FTP kann man die Filterregeln aufstellen, allerdings wird anstelle von NEW für die OUTPUT Kette der Parameter RELATED angewendet:

root@linux # iptables -A INPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED -j ACCEPT
root@linux # iptables -A OUTPUT -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED,RELATED -j ACCEPT

10.6 Patches

Zur erweiterten Verbindungsverfolgung (andere Protokolle) eignen sich auch folgende Patches, die unter de http://www.netfilter.org/documentation/HOWTO/de/netfilter-extensions-HOWTO.html dokumentiert sind und von dort auch heruntergeladen werden können.

  • amanda-conntrack-nat
  • eggdrop-conntrack
  • h323-conntrack-nat
  • ip_conntrack-timeouts
  • mms-conntrack-nat
  • pptp-conntrack-nat
  • quake3-conntrack
  • rpc
  • rsh
  • talk-conntrack-nat
  • tcp-window-tracking
  • tftp-conntrack-nat


zurück   Seitenanfang Startseite Kapitelanfang Inhaltsverzeichnis GFDL   weiter