iptables

Debian Swirl

http://www.black-board.net
Es ist nicht gestattet dieses Tutorial losgelöst von dem Namen BlackBoard und der URL zu verbreiten.


Das Tutorial befindet sich noch in der Entwicklung. Wenn du mitwirken möchtest, melde dich hier.
Dies ist ein Aufruf - wenn du Ahnung hast, mach mit!



1. Was sind die Aufgaben einer Firewall?


Nun streng genommen ist das, was wir mit iptables machen keine Firewall, sondern ein Paketfilter. iptables ist nicht in der Lage aus dem Datenstrom herauszufiltern, welches Programm welches Paket losgeschickt hat. Es ist lediglich in der Lage zuzuordnen welches Paket zu welchem Datenstrom gehört und was dieses Paket für Eigenschaften hat. Dies sind die einzigen Merkmale, die wir uns zu nutze machen können. Das heißt: iptables ist ein Paketfilter, allerdings ein sehr mächtiger.

Nun die Aufgaben dieses Paketfilters sind:

  1. die Maschine zu schützen auf der er läuft,
  2. den Nutzern des hinter der Maschine liegenden Netzwerkes Zugriff auf das Internet zu ermöglichen und
  3. Zugriff aus dem Internet auf die Maschinen im Netzwerk zu ermöglichen (falls gewünscht).
Ich gehe jetzt mal davon aus, dass der Debian-Server auch als Router laufen soll. Die vor uns liegende Aufgabe ist es ein Firewall-Script zu schreiben, das alle gewünschten Eigenschaften erfüllt.

2. iptables


Damit stünden wir vor dem Problem: Wo anfangen? Da dies ein Tutorial ist und kein tief greifendes Wissen vermittelt werden soll, gehe ich im Schnellverfahren durch alle wichtigen Punkte.

Aufbau des Netzwerkes:


Hier haben wir jetzt einen Server mit 2 Netzwerkschnittstellen. Die eine (ppp0) zeigt ins Internet, die andere ins lokale Netzwerk (eth0). Das lokale Netzwerk kann durch 192.168.1.0/255.255.255.0 oder 192.168.1.0/24 beschrieben werden.

iptables kennt drei Haupt-Schlangen durch die der Datenstrom geregelt wird. INPUT ist die Eingangs-Schlange, OUTPUT ist die Ausgangs-Schlange und FORWARD ist die Schlange, die sich um den Verkehr kümmert, der über den Server ins Internet und zurück geht.


Bevor wir Anfangen können, müssen wir die Kernel-Module laden, die iptables benötigt:

modprobe ip_tables
modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ip_conntrack_irc


Jetzt erlauben wir, dass Pakete "über den Server fließen dürfen" und erledigen noch ein paar Sicherheits- und Logging-Einstellungen.

echo 1 > /proc/sys/net/ipv4/ip_forward # ip-forwarding
echo 1 > /proc/sys/net/ipv4/ip_dynaddr # dhcp
echo 1 > /proc/sys/net/ipv4/tcp_syncookies # Enable TCP SYN Cookie Protection
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts # Enable broadcast echo Protection
echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses # Enable bad error message Protection
# Enable IP spoofing protection turn on Source Address Verification
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo 1 > $f
done
# Disable ICMP Redirect Acceptance
for f in /proc/sys/net/ipv4/conf/*/accept_redirects; do
echo 0 > $f
done
for f in /proc/sys/net/ipv4/conf/*/send_redirects; do
echo 0 > $f
done
# Disable Source Routed Packets
for f in /proc/sys/net/ipv4/conf/*/accept_source_route; do
echo 0 > $f
done
# Log Spoofed Packets, Source Routed Packets, Redirect Packets
if [ $logging = "enbaled" ]; then log=1; else log=0; fi
for f in /proc/sys/net/ipv4/conf/*/log_martians; do
echo $log > $f
done


Das alles kann so natürlich nicht auf die Kommandozeile, sondern muss in ein Skript.

Jetzt können wir schon anfangen. Als erstes spülen wir die Schlangen aus, damit keine alten Regeln zurückbleiben:

iptables -F INPUT
iptables -F OUTPUT
iptables -F FORWARD


Das F steht hier für Flush und bedeutet, dass die entsprechende Schlange ausgespült wird. Nun setzen wir die Standard-Vorgehensweise (default policy) der Schlangen auf DROP, da es passieren kann, dass das Script während des Ausführens hängen bleibt, und wir den Server völlig offen zurücklassen.

iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

Jetzt spülen wir noch benutzerdefinierte Schlangen aus und löschen diese:

iptables -F
iptables -X

Dann können wir auch schon mit den Filter-Regeln anfangen. Die Syntax ist folgende:

iptables -A <SCHLANGE> [optionen] [-p <protocol>] [--dport <destination port>] [--sport <source port>] [-i <eingangs-interface>] [-o <ausgangs-interface>] [-s <source adresse>] [-d destination adresse] -j <ZIEL>

Was uns interessiert sind SCHLANGE und ZIEL. Als Schlange kommen INPUT, OUTPUT und FORWARD in Frage. ZIEL ist entweder ACCEPT, REJECT oder DROP. Wir nehmen DROP, da bei REJECT der anderen Seite eine Meldung geschickt wird, dass dieser Port geschlossen ist. DROP erspart uns daher Zeit und Bandbreite und macht diesen Port unsichtbar für mögliche Angreifer.

Das wichtigste ist, dass wir dem Server sein Loopback-Interface freischalten. Ohne Loopback werdet ihr nicht mehr glücklich werden, da vieles einfach nicht mehr funktionieren wird.

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

Jetzt legen wir fest, dass alle bestehenden Verbindungen weiterhin erlaubt sind:

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

Die INPUT und FORWARD Schlangen können jetzt beinahe beliebig gefüllt werden. Zugriff von innen vollständig erlauben:

iptables -A INPUT -i eth0 -s 192.168.1.0/24 -j ACCEPT
iptables -A FORWARD -i eth0 -o ppp0 -s 192.168.1.0/24 -j ACCEPT

Zugriff von außen nur über FTP, SSH und HTTP:

iptables -A INPUT -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport 80 -j ACCEPT

Auch passives FTP und SSH ist so möglich, da wir ja oben bestehende Verbindungen von überall her erlaubt haben. D.h. wenn sich der Port ändert, macht das nichts, da iptables das als Teil der selben Sitzung erkennen kann.

Das gleiche gilt für FORWARD von außen nach innen. Auch dies brauchen wir nicht extra zu erlauben, da niemand von außen eine neue Verbindung nach innen aufbauen soll. Gut, jetzt haben wir alles erlaubt, was wir brauchen, d.h. alles was jetzt noch bleibt ist böse - also weg damit!

iptables -A INPUT -j DROP
iptables -A FORWARD -j DROP

Unserem treuen Server verbieten wir natürlich nichts:

iptables -A OUTPUT -j ACCEPT

Damit wären wir auch schon fertig und hätten einen Paketfilter, der den Server und die Leute im Netzwerk schützt. Die Sache hat nur einen Haken: Die Leute im Netzwerk können nicht ohne den Server nach draußen. Aller Verkehr
muss jetzt über den Server laufen. Für manche mag das ok sein, wenn man zum Beispiel einen Proxyserver und Fetchmail eingerichtet hat. Aber alles weiter wäre den Benutzern im lokalen Netzwerk verweigert. Daher kommt ein neues Schlagwort ins Spiel - Network Address Translation, kurz NAT.


3. NAT mit iptables


Das bedeutet, dass iptables Listen anlegt, welche Verbindung von welchem Rechner aus geöffnet wurde und die Rückantwort wieder an diesen Rechner schickt. Dabei maskiert der Server die lokale IP des Rechners mit seiner offiziellen Internet-IP. Dazu brauchen wir 3 weitere Schlangen, die irgendwo zwischen den 3 Haupt-Schlangen liegen. Das sind: -t nat POSTROUTING, PREROUTING und OUTPUT.

Auch diese Ketten müssen wir ausspülen und auf DROP setzen:

iptables -t nat -F
iptables -t nat -X
iptables -t nat -P PREROUTING DROP
iptables -t nat -P POSTROUTING DROP
iptables -t nat -P OUTPUT DROP

Der Befehl zum maskieren ist dann ganz einfach:

iptables -t nat -A POSTROUTING -o ppp0 -p all -s 192.168.1.0/24 -j MASQUERADE

Aber das NAT ermöglicht uns noch mehr. Angenommen wir haben einen eDonkey-Client auf der Adresse 192.168.1.4 und möchten für eine High ID gerne, dass die Ports 4662/tcp und 4665/udp automatisch auf diese Adresse laufen.

iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 4662 -j DNAT --to 192.168.1.4
iptables -t nat -A PREROUTING -i ppp0 -p udp --dport 4665 -j DNAT --to 192.168.1.4

Dazu muss oben allerdings noch erlaubt werden, dass von außen neue Verbindungen über die FORWARD-Schlange gehen dürfen:

iptables -A FORWARD -i ppp0 -p tcp --dport 4662 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i ppp0 -p udp --dport 4665 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

Das muss man logischerweise vor dem iptables -A FORWARD -j DROP einfügen. Als letztes muss die default-policy noch zurückgesetzt werden, da sich sonst nicht wirklich viel tut.

iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -t nat -P PREROUTING ACCEPT
iptables -t nat -P POSTROUTING ACCEPT
iptables -t nat -P OUTPUT ACCEPT

Damit wären wir soweit fertig.

Das ganze kommt jetzt in ein Script und muss auf Herz und Nieren geprüft werden. Ist alles ok, packen wir es in unser /etc/ppp/ip-up Script. Wenn ihr die Firewall in /sbin/firewall liegen habt, dann fügt einfach /sbin/firewall ans Ende des ip-up Skriptes an. (und chmod 700 nicht vergessen).

Dies alles soll nur als Leitfaden für ein eigenes Firewall-Skript gelten. Mein eigenes iptables-Script ist wesentlich komplexer. Aber für den Hausgebrauch und als Einstieg sollte das ausreichen.

Für manche mag es noch interessant sein das Firewall-Script in einer Art Init-Script zu gestalten. Das sieht dann so aus:


#!/bin/bash

case "$1" in
status)
iptables -L
iptables -t nat -L
;;
start)
#der ganze FW kram
;;
stop)
#flushen
#masq anschalten
#die Firewall ist dann deaktiviert!
;;
restart|reload)
$0 start
;;
*)
echo "Usage: $0 {status|start|stop|reload}"
exit 1
;;
esac

Verfasser


Letzte Aktualisierung 19.06.2006 von LX