30.4. IPFW

IPFW ist eine Stateful-Firewall für FreeBSD, die sowohl IPv4 als auch IPv6 unterstützt. Die Firewall setzt sich aus mehreren Komponenten zusammen: dem Kernel Firewall Filter-Prozessor mit integriertem Paket-Accounting, Protokollfunktionen, NAT, dem dummynet(4) Traffic-Shaper, sowie Weiterleitungs-, Bridge- und ipstealth-Funktionen.

FreeBSD enthält mit /etc/rc.firewall ein Beispielregelwerk, welches mehrere Firewall-Typen für gebräuchliche Szenarien definiert und unerfahrene Anwender dabei unterstützen soll, ein geeignetes Regelwerk zu erstellen. IPFW besitzt eine leistungsstarke Syntax, mit der erfahrene Benutzer ihre eigenen Regeln anfertigen können, um den Sicherheitsanforderungen der jeweiligen Umgebung gerecht zu werden.

Diser Abschnitt beschreibt, wie IPFW aktiviert wird und bietet einen Überblick über die Regelsyntax. Zudem werden mehrere Regelsätze für gebräuchliche Konfigurationsszenarien vorgestellt.

30.4.1. IPFW aktivieren

Das FreeBSD Basissystem enthält für IPFW ein ladbares Kernelmodul, was bedeutet, dass kein angepasster Kernel benötigt wird, um IPFW zu benutzen.

Wenn Sie eine statische Unterstützung für IPFW in den Kernel kompilieren wollen, lesen Sie Abschnitt 30.4.6, „IPFW Kerneloptionen“.

Um IPFW beim Systemstart zu aktivieren, fügen Sie firewall_enable="YES" in /etc/rc.conf ein:

# sysrc firewall_enable="YES"

Wenn Sie einen der von FreeBSD zur Verfügung gestellten Firewall-Profile benutzen möchten, fügen Sie eine weitere Zeile hinzu, in der Sie das Profil bestimmen:

# sysrc firewall_type="open"

Folgende Profile stehen zur Verfügung:

  • open: gestattet jeglichen Datenverkehr.

  • client: schützt lediglich diesen Rechner.

  • simple: schützt das gesamte Netzwerk.

  • closed: blockiert den gesamten IP-Datenverkehr, mit Ausnahme des Verkehrs über die Loopback-Schnittstelle.

  • workstation: schützt lediglich diesen Rechner und verwendet zustandsorientierte Regeln.

  • UNKNOWN: deaktiviert das Laden von Firewallregeln.

  • filename: absoluter Pfad zu einer Datei, in der die Firewallregeln definiert sind.

Wenn Sie firewall_type auf client oder simple setzen, müssen Sie die voreingestellten Regeln in /etc/rc.firewall anpassen, damit sie der Konfiguration des Systems entsprechen.

Beachten Sie, dass das Profil filename verwendet wird, um ein benutzerdefiniertes Regelwerk zu laden.

Eine alternative Möglichkeit, um ein benutzerdefiniertes Regelwerk zu laden, bietet die Variable firewall_script. Setzen Sie die Variable auf den absoluten Pfad eines ausführbaren Skripts, welches die Befehle für IPFW enthält. Die Beispiele in diesem Abschnitt gehen davon aus, dass firewall_script auf /etc/ipfw.rules gesetzt ist.

# sysrc firewall_script="/etc/ipfw.rules"

Die Protokollierung wird mit diesem Befehl aktiviert:

# sysrc firewall_logging="YES"

Warnung:

Es werden nur Firewallregeln mit der Option log protokolliert. Die voreingestellten Regeln enthalten diese Option nicht und müssen manuell hinzugefügt werden. Daher ist es ratsam, diese Regeln zu bearbeiten. Außerdemkann eine Rotation der Protokolle erwünscht sein, wenn die Protokolle in einer separaten Datei gespeichert werden.

Es existiert keine Variable für /etc/rc.conf, um die Protokollierung zu begrenzen. Um die Anzahl der Protokoll-Nachrichten pro Verbindungsversuch zu begrenzen, legen Sie die Anzahl der Einträge in /etc/sysctl.conf fest:

# echo "net.inet.ip.fw.verbose_limit=5" >> /etc/sysctl.conf

Um die Protokollierung über die spezielle Schnittstelle ipfw0 zu aktivieren, fügen Sie stattdessen folgende Zeile in /etc/rc.conf hinzu:

# sysrc firewall_logif="YES"

Benutzen Sie dann tcpdump, um zu sehen, was protokolliert wird:

# tcpdump -t -n -i ipfw0

Tipp:

Durch die Protokollierung entsteht kein Aufwand, es sei denn, tcpdump wird an die Schnittstelle angebunden.

Nachdem Sie die Änderungen vorgenommen haben, können Sie die Firewall starten. Um auch die Anzahl der Protokoll-Nachrichten zu konfigurieren, setzen Sie mit sysctl den gewünschten Wert:

# service firewall start
# sysctl net.inet.ip.fw.verbose_limit=5

30.4.2. IPFW Regel-Syntax

Wenn ein Paket die Firewall betritt, also von der Firewall geprüft und verarbeitet wird, wird die erste Regel des Regelwerkes auf das Paket angewandt. Auf diese Weise wird in aufsteigender Reihenfolge der Regelnummer mit allen weiteren Regeln verfahren. Falls die Selektionsparameter einer Regel auf ein Paket zutreffen, wird das Aktionsfeld der Regel ausgeführt und die Prüfung des Pakets beendet, nachfolgende Regeln werden also nicht mehr geprüft. Diese Suchmethode wird als erster Treffer gewinnt bezeichnet. Falls keine Regel auf das betreffende Paket zutrifft, wird die obligatorische IPFW-Rückfallregel mit der Nummer 65535 angewendet und das Paket wird ohne Rückantwort verworfen. Wenn das Paket jedoch einer Regel mit dem Schlüsselwort count, skipto oder tee entspricht, wird die Prüfung des Pakets weiter fortgeführt. Weitere Details darüber, wie diese Schlüsselwörter die Regelverarbeitung beeinflussen, finden Sie in ipfw(8).

Bei der Erstellung der IPFW-Regeln müssen die Schlüsselwörter in der folgenden Reihenfolge geschrieben werden. Einige Schlüsselwörter müssen zwingend angegeben werden, während andere optional sind. Die Wörter in Großbuchstaben repräsentieren Variablen und die Wörter in Kleinbuchstaben müssen den Variablen vorangestellt werden. Das Zeichen # wird benutzt, um einen Kommentar einzuleiten und kann am Ende einer Regel oder in einer eigenen Zeile stehen. Leerzeilen werden ignoriert.

CMD RULE_NUMBER set SET_NUMBER ACTION log LOG_AMOUNT PROTO from SRC SRC_PORT to DST DST_PORT OPTIONS

Dieser Abschnitt bietet einen Überblick über diese Schlüsselwörter und deren Optionen. Es ist keine vollständige Liste aller verfügbaren Optionen. Eine vollständige Beschreibung der Regel-Syntax, die Sie verwenden können um IPFW-Regeln zu erstellen, finden Sie in ipfw(8).

CMD

Jede Regel muss mit ipfw add beginnen.

RULE_NUMBER

Jede Regel gehört zu einer Nummer zwischen 1 und 65534. Die Nummer wird verwendet, um die Reihenfolge der Regelverarbeitung zu kennzeichnen. Es ist möglich, dass mehrere Regeln dieselbe Nummer haben. In diesem Fall werden sie entsprechend der Reihenfolge angewendet, in der sie aufgenommen wurden.

SET_NUMBER

Jede Regel ist einer Set-Nummer zwischen 0 und 31 zugeordnet. Sets können einzeln aktiviert oder deaktiviert werden. Dies macht es möglich, eine Reihe von Regeln schnell hinzuzufügen oder zu löschen. Wenn SET_NUMBER nicht angegeben ist, wird die Regel zu Set 0 hinzugefügt.

ACTION

Eine Regel kann mit einer der folgenden Aktionen verknüpft werden. Die festgelegte Aktion wird ausgeführt, wenn das Paket den Selektionskriterien der Regel entspricht.

allow | accept | pass | permit: All diese Aktionen sind gleichbedeutend und erlauben Pakete, die mit der Regel übereinstimmen.

check-state: Diese Aktion überprüft die Regel in der dynamischen Zustandstabelle. Bei einer Übereinstimmung wird die mit der dynamischen Regel verknüpfte Aktion ausgeführt, andernfalls wird mit der Prüfung gegen die nächste Regel fortgefahren. Die Regel check-state hat selbst kein Selektionskriterium. Sollte keine check-state-Regel im Regelwerk vorhanden sein, wird die dynamische Zustandstabelle beim ersten Vorkommen einer keep-state- oder limit-Regel überprüft.

count: Aktualisiert die Zähler für alle Pakete, die mit dieser Regel übereinstimmen. Die Prüfung wird mit der nächsten Regel fortgesetzt.

deny | drop: Diese Aktionen sind gleichbedeutend und verwerfen Pakete, die mit dieser Regel übereinstimmen.

Es stehen noch weitere Aktionen zur Verfügung. Einzelheiten finden Sie in ipfw(8).

LOG_AMOUNT

Erfüllt ein Paket die Selektionskriterien mit dem Schlüsselwort log, wird dies von syslogd(8) mit der Annotation SECURITY protokolliert. Dies erfolgt allerdings nur, wenn die Anzahl der protokollierten Pakete der betreffenden Regel die definierte LOG_AMOUNT-Grenze nicht übersteigt. Wenn LOG_AMOUNT nicht definiert ist, wird die Grenze aus dem Wert von net.inet.ip.fw.verbose_limit benutzt. Ein Wert von 0 bedeutet eine unbegrenzte Protokollierung. Wird eine definierte Grenze erreicht, wird die Protokollierung für diese Regel deaktiviert. Um die Protokollierung zu reaktivieren, können Sie den Protokoll- oder Paketzähler mit ipfw resetlog zurücksetzen.

Anmerkung:

Die Protokollierung findet statt, nachdem alle Selektionskriterien geprüft und bevor die endgültige Aktion auf das Paket angewendet wird. Der Administrator entscheidet, welche Regel protokolliert werden soll.

PROTO

Dieser optionale Wert wird verwendet, um einen beliebigen Protokollnamen oder -nummer aus /etc/protocols gegen das Paket zu prüfen.

SRC

Nach dem Schlüsslwortfrom muss die Quelladresse stehen, oder ein Schlüsselwort, das die Quelladresse darstellt. Eine Adresse wird dargestellt duch any, me (jede Adresse dieses Systems), me6 (jede IPv6-Adresse dieses Systems), oder table gefolgt von der Nummer der Tabelle, welche die Adressen enthält. IP-Adressen können in CIDR-Notation geschrieben werden. Beispielsweise 1.2.3.4/25 oder 1.2.3.4:255.255.255.128.

SRC_PORT

Optional kann ein Quellport über eine Nummer oder einen Namen aus /etc/services spezifiziert werden.

DST

Nach dem Schlüsselwort to muss die Zieladresse stehen, oder ein Schlüsselwort, das die Zieladresse darstellt. Es können die gleichen Schlüsselwörter und Adressen benutzt werden, die bereits im SRC-Abschnitt beschrieben wurden.

DST_PORT

Optional kann ein Zielport über eine Nummer oder einen Namen aus /etc/services spezifiziert werden.

OPTIONS

Nach der Quell- und Zieladresse können noch weitere Optionen angegeben werden. Wie der Name bereits sagt, sind OPTIONS optional. Häufig verwendete Optionen sind in oder out, mit denen die Richtug des Pakets bestimmt wird, icmptypes gefolgt vom Typ der ICMP-Nachricht, sowie keep-state.

Wenn ein Paket auf eine keep-state-Regel zutrifft, wird die Firewall eine dynamische Regel erstellen, die dem bidirektionalen Datenverkehr zwischen den gleichen Quell- und Zieladressen mit dem gleichen Protokoll entspricht.

Dynamische Regeln sind für einen sogenannten SYN-flood-Angriff anfällig, bei dem eine riesige Anzahl an dynamischen Regeln erzeugt wird. Verwenden Sie die Option limit, um einen solchen Angriff entgegenzuwirken. Diese Option begrenzt die Anzahl der gleichzeitig möglichen Sitzungen. Es handelt sich dabei um einen Zähler, der die Anzahl von dynamischen Regeln in Kombination mit der Quelladresse verfolgt. Übersteigt der Zähler den durch limit definierten Wert, wird das Paket verworfen.

Es stehen noch viele weitere Optionen zur Verfügung. ipfw(8) enthält eine Beschreibung der einzelnen Optionen.

30.4.3. Beispiel für einen Regelsatz

Dieser Abschnitt die Erstellung eines Firewall-Skripts namens /etc/ipfw.rules mit zustandsorientierten (stateful Regeln. Alle Regeln in diesem Beispiel verwenden die Optionen in und out, um die Richtung des Pakets zu verdeutlichen. Zusätzlich wird via interface-name benutzt, um die Schnittstelle für das Paket zu prüfen.

Anmerkung:

Bei den anfänglichen Tests mit dem Firewall-Regelsatz sollten Sie vielleicht folgende Einstellung vornehmen:

net.inet.ip.fw.default_to_accept="1"

Dies legt die Standardregel von ipfw(8) etwas großzügiger fest, als das voreingestellte default deny ip from any to any. Dadurch sinkt die Gefahr, sich nach einem Neustart des Systems auszusperren.

Das Firewall-Skript beginnt mit einem Hinweis, dass es sich um ein Bourne Shell-Skript handelt. Danach werden alle vorhandenen Filterregeln gelöscht. Anschließend wird die Variable cmd erstellt, sodass ipfw add nicht jedes mal von Hand eingegeben werden muss. Die Variable pif repräsentiert die mit dem Internet verbundene Schnittstelle.

#!/bin/sh
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
pif="dc0"     # interface name of NIC attached to Internet

Jetzt folgen die eigentlichen Filterregeln. Diese ersten beiden Regeln erlauben den Datenverkehr aus dem internen Netzwerk und über die Loopback-Schnittstelle:

# Change xl0 to LAN NIC interface name
$cmd 00005 allow all from any to any via xl0

# No restrictions on Loopback Interface
$cmd 00010 allow all from any to any via lo0

Die nächste Regel erlaubt Pakete, für die ein Eintrag in der dynamischen Zustandstabelle existiert:

$cmd 00101 check-state

Die nächsten Regeln definieren, welche internen Rechner Verbindungen zu anderen Rechnern im Internet aufbauen dürfen. Hier werden wieder zustandsorientierte Regeln verwendet:

# Allow access to public DNS
# Replace x.x.x.x with the IP address of a public DNS server
# and repeat for each DNS server in /etc/resolv.conf
$cmd 00110 allow tcp from any to x.x.x.x 53 out via $pif setup keep-state
$cmd 00111 allow udp from any to x.x.x.x 53 out via $pif keep-state

# Allow access to ISP's DHCP server for cable/DSL configurations.
# Use the first rule and check log for IP address.
# Then, uncomment the second rule, input the IP address, and delete the first rule
$cmd 00120 allow log udp from any to any 67 out via $pif keep-state
#$cmd 00120 allow udp from any to x.x.x.x 67 out via $pif keep-state

# Allow outbound HTTP and HTTPS connections
$cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state
$cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state

# Allow outbound email connections
$cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state
$cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state

# Allow outbound ping
$cmd 00250 allow icmp from any to any out via $pif keep-state

# Allow outbound NTP
$cmd 00260 allow udp from any to any 123 out via $pif keep-state

# Allow outbound SSH
$cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state

# deny and log all other outbound connections
$cmd 00299 deny log all from any to any out via $pif

Die folgenden Regeln steuern die Verbindungen von Rechern aus dem Internet ins interne Netzwerk. Zuerst werden Pakete verworfen, die typischerweise im Zusammenhang mit Angriffen stehen. Danach werden bestimmte Arten von Verbindungen erlaubt. Alle Dienste aus dem öffentlichen Internet beinhalten die Option limit, um Flooding zu unterbinden.

# Deny all inbound traffic from non-routable reserved address spaces
$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif     #RFC 1918 private IP
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif      #RFC 1918 private IP
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif         #RFC 1918 private IP
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif        #loopback
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif          #loopback
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif     #DHCP auto-config
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif       #reserved for docs
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif    #Sun cluster interconnect
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif        #Class D & E multicast

# Deny public pings$
$cmd 00310 deny icmp from any to any in via $pif$
$
# Deny ident$
$cmd 00315 deny tcp from any to any 113 in via $pif$
$
# Deny all Netbios services.$
$cmd 00320 deny tcp from any to any 137 in via $pif$
$cmd 00321 deny tcp from any to any 138 in via $pif$
$cmd 00322 deny tcp from any to any 139 in via $pif$
$cmd 00323 deny tcp from any to any 81 in via $pif$

# Deny fragments
$cmd 00330 deny all from any to any frag in via $pif

# Deny ACK packets that did not match the dynamic rule table
$cmd 00332 deny tcp from any to any established in via $pif

# Allow traffic from ISP's DHCP server.
# Replace x.x.x.x with the same IP address used in rule 00120.
#$cmd 00360 allow udp from any to x.x.x.x 67 in via $pif keep-state

# Allow HTTP connections to internal web server
$cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2

# Allow inbound SSH connections
$cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2

# Reject and log all other incoming connections
$cmd 00499 deny log all from any to any in via $pif

Die letzte Regel protokolliert alle Pakete, die mit keiner Regel im Regelsatz übereinstimmen:

# Everything else is denied and logged
$cmd 00999 deny log all from any to any

30.4.4. In-Kernel NAT

Beigetragen von Chern Lee.
Aktualisiert von Dries Michiels.

Die IPFW-Firewall von FreeBSD hat zwei NAT-Implementierungen: die Userland-Implementierung natd(8) und die neuere, kernelinterne NAT-Implementierung. Beide arbeiten in Verbindung mit IPFW, um die Übersetzung von Netzwerkadressen zu ermöglichen. Damit kann eine Lösung zur gemeinsamen Nutzung der Internetverbindung bereitgestellt werden, so dass mehrere interne Rechner unter Verwendung einer einzigen öffentlichen IP-Adresse eine Verbindung zum Internet herstellen können.

Um dies zu tun, muss der mit dem Internet verbundene FreeBSD-Rechner als Gateway eingerichtet sein. Das System muss über zwei Netzwerkschnittstellen verfügen, wobei eine Schnittstelle mit dem Internet verbunden ist und die andere mit dem internen Netzwerk. Jeder Rechner im internen Netzwerk sollte eine RFC 1918 konforme Adresse zugewiesen bekommen.

Es ist noch ein wenig Konfiguration nötig, um die In-Kernel NAT-Funktion von IPFW zu aktivieren. Um die In-Kernel NAT-Unterstützung beim Booten zu aktivieren, müssen folgende Einträge in /etc/rc.conf vorhanden sein:

gateway_enable="YES"
firewall_enable="YES"
firewall_nat_enable="YES"

Anmerkung:

Wenn firewall_nat_enable gesetzt ist, firewall_enable jedoch nicht, hat dies keine Auswirkung, da die NAT-Implementierung im Kernel nur mit IPFW kompatibel ist.

Wenn der Regelsatz zustandsorientierte Regeln enthält, ist die Position der NAT-Regel kritisch und die skipto-Aktion wird benutzt. Die Aktion skipto benötigt eine Regelnummer, damit IPFW weiß, zu welcher Regel es springen muss. Das folgende Beispiel baut auf den im vorherigen Abschnitt gezeigten Firewall-Relgelsatz auf. Es werden einige neue Einträge hinzugefügt und bestehende Regeln modifiziert, um In-Kernel NAT zu konfigurieren. Zunächst werden einige Variablen hinzugefügt, darunter Regelnummern, die keep-state-Option und eine Liste mit TCP-Ports um die Anzahl der Regeln zu reduzieren:

#!/bin/sh
ipfw -q -f flush
cmd="ipfw -q add"
skip="skipto 1000"
pif=dc0
ks="keep-state"
good_tcpo="22,25,37,53,80,443,110"

Bei In-Kernel NAT muss aufgrund der Architektur von libalias(3), einer Bibliothek, die als Kernel-Modul implementiert ist, um die In-Kernel NAT-Funktion für IPFW bereitzustellen, TCP segment offloading (TSO) deaktiviert werden. TSO kann pro Netzwerkschnittstelle mit ifconfig(8), oder systemweit mit sysctl(8) deaktiviert werden. Um TSO systemweit zu deaktivieren, muss folgende Zeile in /etc/sysctl.conf enthalten sein:

net.inet.tcp.tso="0"

Danach wird eine NAT-Instanz konfiguriert. Mit In-Kernel NAT ist es möglich, mehrere NAT-Instanzen mit jeweils eigener Konfiguration zu betreiben. In diesem Beispiel wird jedoch nur eine NAT-Instanz mit der Nummer 1 benötigt. Die Konfiguration kann ein paar Optionen enthalten, zum Beispiel: if, dass die öffentliche Netzwerkschnittstelle angibt, same_ports, das dafür sorgt, dass Alias-Ports und lokale Portnummern identisch zugeordnet werden, unreg_only führt dazu, dass nur unregistrierte (private) Adressräume von der NAT-Instanz verarbeitet werden, und reset, was dazu beiträgt, dass eine NAT-Instanz auch dann erhalten bleibt, wenn sich die öffentliche IP-Adresse des Rechners ändert. Weitere mögliche Optionen, die an einzelne NAT-Instanzen übergeben werden können, finden Sie in ipfw(8). Wenn eine zustandsorientierte NAT-Firewall konfiguriert wird, ist es notwendig, dass übersetzte Pakete zur weiteren Verarbeitung in die Firewall eingespielt werden können, was durch die Deaktivierung des one_pass-Verhaltens beim Start des Firewall-Skripts erreicht werden kann.

ipfw disable one_pass
ipfw -q nat 1 config if $pif same_ports unreg_only reset

Die NAT-Regel für eingehende Pakete wird nach den beiden Regeln, die das interne Netzwerk und die Loopback-Schnittstelle erlauben, und nach der Reassamble-Regel, aber vor der check-state-Regel eingefügt. Es ist wichtig, dass die Nummer der NAT-Regel (in diesem Beispiel 100) höher ist, als die drei vorherigen Regeln und niedriger, als die check-state-Regel. Darüber hinaus wird aufgrund des Verhaltens von In-Kernel NAT empfohlen, eine Reassamble-Regel kurz vor der ersten NAT-Regel, aber hinter den Regeln zu platzieren, die den Datenverkehr auf einer vertrauenswürdigen Schnittstelle erlauben. In der Regel sollte es nicht zu einer Fragmentierung kommen, aber bei getunnelten IPSEC/ESP/GRE-Verkehr kann es vorkommen, und das Zusammensetzen von Fragmenten ist notwendig, bevor das komplette Paket an das In-Kernel NAT übergeben werden kann.

Anmerkung:

Die Reassamble-Regel wird beim Userland natd(8) nicht benötigt, da die Aktion divert von IPFW dies bereits automatisch übernimmt, bevor das Paket an den Socket ausgeliefert wird. Dies ist auch in ipfw(8) dokumentiert.

Beachten Sie, dass die aktuelle NAT-Instanznummer und NAT-Regelnummer in diesem Beispiel nicht mit der voreingestellten NAT-Instanznummer und Regelnummer übereinstimmt, wenn sie mit dem rc.firewall-Skript von FreeBSD erstellt wurde.

$cmd 005 allow all from any to any via xl0  # exclude LAN traffic
$cmd 010 allow all from any to any via lo0  # exclude loopback traffic
$cmd 099 reass all from any to any in       # reassemble inbound packets
$cmd 100 nat 1 ip from any to any in via $pif # NAT any inbound packets
# Allow the packet through if it has an existing entry in the dynamic rules table
$cmd 101 check-state

Die Regeln für den ausgehenden Verkehr werden ebenfalls modifiziert, um Aktionen mit der $skipto-Variable zu erlauben und anzuzeigen, dass die Prüfung mit der Regel 1000 fortgesetzt wird. Die sieben Regeln für TCP wurden durch die Regel 125 ersetzt, da die sieben erlaubten ausgehenden Ports in der Variable $good_tcp0 enthalten sind.

Anmerkung:

Beachten Sie, dass die Leistung von IPFW weitgehend von der Anzahl der im Regelsatz vorhandenen Regeln bestimmt wird.

# Authorized outbound packets
$cmd 120 $skip udp from any to x.x.x.x 53 out via $pif $ks
$cmd 121 $skip udp from any to x.x.x.x 67 out via $pif $ks
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
$cmd 130 $skip icmp from any to any out via $pif $ks

Die eingehenden Regeln bleiben unverändert, mit Ausnahme der letzten Regel, in der das via $pif entfernt wird, um ein- und ausgehende Pakete prüfen zu können. Nach der letzten Regel für ausgehende Pakete muss die NAT-Regel folgen. Die Regel muss eine höhere Nummer als die letzte Regel haben und die Nummer muss über die skipto-Aktion referenziert werden. In diesem Regelsatz leitet die Regel mit der Nummer 1000 alle ausgehenden Pakete zur konfigurierten NAT-Instanz weiter. Die darauf folgende Regel lässt alle von NAT verarbeiteten Pakete passieren.

$cmd 999 deny log all from any to any
$cmd 1000 nat 1 ip from any to any out via $pif # skipto location for outbound stateful rules
$cmd 1001 allow ip from any to any

In diesem Beispiel steuern die Regeln 100, 101, 125, 1000 und 1001 die Adressübersetzung der ein- und ausgehende Pakete, so dass immer die private LAN IP-Adresse in der dynamische Zustandstabelle registriert werden.

Nehmen wir beispielsweise einen Web-Browser, der neue HTTP-Sitzungen über Port 80 aufbaut. Wenn nun das erste ausgehende Paket von der Firewall geprüft wird, trifft es nicht auf Regel 100 zu, da das Paket nach außen geleitet wird und nicht nach innen. Das Paket trifft auch nicht auf Regel 101 zu, da es das erste ist und somit noch nicht in der dynamischen Zustandstabelle enthalten ist. Das Paket entspricht schließlich Regel 125, da es ausgehend auf einem erlaubten Port gesendet wird und von einer IP-Adresse aus dem internen LAN stammt. Für Pakete, die auf diese Regel zutreffen, werden zwei Aktionen ausgeführt. Zuerst wird durch die Aktion keep-state ein dynamischer Eintrag in der Statustabelle erstellt und die angegebene Aktion skipto 1000 ausgeführt. Als nächstes durchläuft das Paket NAT und wird dann an das Internet gesendet. Nachdem dieses Paket am Webserver angekommen ist, wird dort eine Antwort erzeugt und zurückgeschickt. Dieses Paket wird wieder von oben nach unten durch das Regelwerk geprüft. Dieses Mal trifft Regel 100 auf das Paket zu und die Zieladresse wird auf die zugehörige (lokale) LAN-Adresse abgebildet. Danach wird das Paket von der Regel check-state verarbeitet. Die Zustandstabelle erkennt, dass eine zugehörige aktive Sitzung vorliegt und das Paket wird freigegeben und in das LAN geleitet.

Für den eingehenden Datenverkehr muss der Regelsatz unerwünschte Pakete blockieren und Pakete für autorisierte Dienste durchlassen. Ein Paket, das mit einer Regel für den eingehenden Datenverkehr übereinstimmt, wird in der dynamischen Zustandstabelle eingetragen und dann an das LAN freigegeben. Das Antwortpaket wird von der Regel check-state als Paket einer aktiven Sitzung erkannt. Das Paket wird dann von Regel 1000 per NAT verarbeitet, bevor es über die externe Schnittstelle verschickt wird.

Anmerkung:

Der Wechsel vom Userland natd(8) zu In-Kernel NAT mag zunächst nahtlos erscheinen, aber es gibt einen kleinen Haken. Bei Verwendung des GENERIC-Kernels wird IPFW das Kernelmodul libalias.ko laden, wenn firewall_nat_enable in rc.conf aktiviert ist. Das Kernelmodul libalias.ko stellt nur grundlegende NAT-Funktionalität bereit, während die Userland-Implementierung natd(8) alle Funktionalitäten ohne zusätzliche Konfiguration zur Verfügung stellt. Die gesamte Funktionalität bezieht sich auf die folgenden Kernelmodule, die bei Bedarf zusätzlich zu libalias.ko geladen werden können: alias_cuseeme.ko, alias_ftp.ko, alias_bbt.ko, skinny.ko, irc.ko, alias_pptp.ko und alias_smedia.ko unter Verwendung der kld_list Direktive in rc.conf. Wenn ein angepasster Kernel benutzt wird, kann die volle Funktionalität der Userland-Bibliothek im Kernel mit options LIBALIAS gebaut werden.

30.4.4.1. Weiterleitung von Ports

Der Nachteil von NAT ist, dass die Rechner im LAN nicht aus dem Internet zugänglich sind. Diese Rechner können zwar ausgehende Verbindungen zur Außenwelt aufbauen, jedoch keine eingehenden Verbindungen empfangen. Dies stellt ein Problem dar, wenn Sie auf einem Rechner im LAN Dienste anbieten möchten, die aus dem Internet erreichbar sein sollen. In diesem Fall können Sie die Ports, welche über das Internet erreichbar sein sollen, über die NAT-Maschine an den Rechner im LAN weiterleiten.

Angenommen es gibt einen IRC-Server auf Rechner A und einen Webserver auf Rechner B. Damit dies funktioniert, müssen die Verbindungen auf den Ports 6667 (IRC) und 80 (HTTP) an die jeweiligen Rechner weitergeleitet werden.

Bei In-Kernel NAT wird die gesamte Konfiguration in der NAT-Instanz selbst vorgenommen. Alle Optionen, die in einer NAT-Instanz benutzt werden können, sind in ipfw(8) dokumentiert. Die Syntax für IPFW folgt dabei der von natd. Die Syntax für -redirect_port lautet:

redirect_port proto targetIP:targetPORT[-targetPORT]
  [aliasIP:]aliasPORT[-aliasPORT]
  [remoteIP[:remotePORT[-remotePORT]]]

Für das obige Beispiel sollten die Argumente wie folgt aussehen:

redirect_port tcp 192.168.0.2:6667 6667
redirect_port tcp 192.168.0.3:80 80

Nachdem diese Argumente der Konfiguration der NAT-Instanz 1 im obigen Regelsatz hinzugefügt wurden, werden die TCP-Ports an die Rechner im LAN weitergeleitet, auf denen IRC- und HTTP-Dienste laufen.

ipfw -q nat 1 config if $pif same_ports unreg_only reset \
  redirect_port tcp 192.168.0.2:6667 6667 \
  redirect_port tcp 192.168.0.3:80 80

Portbereiche können über redirect_port festgelegt werden. Zum Beispiel würde tcp 192.168.0.2:2000-3000 2000-3000 alle Verbindungen auf die Ports 2000 bis 3000 an die Ports 2000 bis 3000 an Rechner A weiterleiten.

30.4.4.2. Weiterleiten von Adressen

Das Weiterleiten von Adressen ist nützlich, wenn mehr als eine IP-Adresse zur Verfügung steht. Jeder Rechner im LAN kann über ipfw(8) seine eigene externe IP-Adresse zugewiesen bekommen. IPFW wird dann den ausgehenden Datenverkehr der Rechner aus dem LAN mit der entsprechenden externen IP-Adresse umschreiben. Auch der eingehenden Datenverkehr über die externe IP-Adresse wird an die entsprechenden Rechner im LAN weitergeleitet. Diese Methode ist auch als statisches NAT bekannt. Wenn Ihnen beispielsweise die IP-Adressen 128.1.1.1, 128.1.1.2 und 128.1.1.3 zur Verfügung stehen, kann 128.1.1.1 als externe Adresse der ipfw(8)-Maschine verwendet werden, während 128.1.1.2 und 128.1.1.3 an Rechner A und Rechner B im LAN weitergeleitet werden.

Die Syntax für redirect_address lautet wie im Folgenden, wobei localIP die interne IP-Adresse des Rechners im LAN, und publicIP die externe IP-Adresse ist, die dem Rechner im LAN entspricht.

redirect_address localIP publicIP

Auf das Beispiel bezogen, würden die Argumente so lauten:

redirect_address 192.168.0.2 128.1.1.2
redirect_address 192.168.0.3 128.1.1.3

Genau wie bei redirect_port, werden diese Argumente in der Konfiguration der NAT-Instanz gesetzt. Bei der Weiterleitung von Adressen ist keine Portumleitung notwendig, da alle Daten, die auf einer bestimmten IP-Adresse empfangen werden, weitergeleitet werden.

Die externe IP-Adresse der ipfw(8)-Maschine muss auf der externen Schnittstelle aktiv und mit einem Alias versehen sein. Weitere Einzelheiten sind in rc.conf(5); beschrieben.

30.4.4.3. Userland NAT

Zunächst sei gesagt, dass natd(8), die Userland-Implementierung aufwändiger ist als In-Kernel NAT. Damit natd(8) Pakete übersetzen kann, müssen die Pakete vom Kernel ins Userland und zurück kopiert werden, was zusätzlichen Aufwand mit sich bringt. Dieser Aufwand entfällt bei In-Kernel NAT.

Um den Userland NAT-Daemon natd(8) beim Systemstart zu aktivieren, ist etwas Konfiguration in /etc/rc.conf nötig. natd_interface wird auf den Namen der mit dem Internet verbundenen Schnittstelle gesetzt. Das rc(8)-Skript von natd(8) wird selbstständig prüfen, ob eine dynamische IP-Adresse benutzt wird und sich selbst so konfigurieren, dass es damit umgehen kann.

gateway_enable="YES"
natd_enable="YES"
natd_interface="rl0"

Generell kann der obige Regelsatz, wie er für In-Kernel NAT erklärt wurde, auch zusammen mit natd(8) benutzt werden. Die Ausnahmen sind die Konfiguration der In-Kernel NAT-Instanz (ipfw -q nat 1 config ...), die nicht zusammen mit der Regel 99 benötigt wird, da die divert-Aktion sich um die Fragmentierung kümmert. Die Regeln 100 und 1000 müssen leicht modifiziert werden, wie unten gezeigt.

$cmd 100 divert natd ip from any to any in via $pif
$cmd 1000 divert natd ip from any to any out via $pif

Um eine Port- oder Adressumleitung zu konfigurieren, wird eine ähnliche Syntax wie bei In-Kernel NAT verwendet. Anstatt die Konfiguration in unserem Regelsatz-Skript wie bei In-Kernel NAT anzugeben, wird die Konfiguration von natd(8) am besten in einer Konfigurationsdatei vorgenommen. Dazu muss eine zusätzliche Option in /etc/rc.conf übergeben werden, welche den Pfad zur Konfigurationsdatei angibt.

natd_flags="-f /etc/natd.conf"

Anmerkung:

Die Konfigurationsdatei muss eine Liste von Optionen enthalten, eine pro Zeile. Weitere Informationen über die Konfigurationsdatei und mögliche Variablen finden Sie in natd(8). Hier zwei Beispieleinträge, einer pro Zeile:

redirect_port tcp 192.168.0.2:6667 6667
redirect_address 192.168.0.3 128.1.1.3

30.4.5. Das IPFW Kommando

ipfw kann benutzt werden, um einzelne Regeln im laufenden Betrieb hinzuzufügen oder zu entfernen. Problematisch ist jedoch, dass diese Änderungen bei einem Neustart des Systems verloren gehen. Daher ist es empfehlenswert, eigene Regeln in einer Datei zu definieren und diese zu laden, um die Regeln der Firewall im laufenden Betrieb anzupassen.

ipfw ist auch hilfreich, um die geladenen Regeln der auf der Konsole auszugeben. IPFW erzeugt dynamisch einen Zähler, der jedes Paket, auf das eine Regel zutrifft, zählt. Dadurch ist es möglich, die Funktion einer Regel zu überprüfen.

Eine Auflistung aller geladenen Regeln erhalten Sie mit:

# ipfw list

Eine Auflistung aller Regeln inklusive des letzten Treffers erhalten Sie mit:

# ipfw -t list

Das nächste Beispiel zeigt Informationen über die Anzahl der Pakete, die von einer Regel gefiltert wurden sowie die Regel selbst. Der erste Spalte zeigt die Nummer der Regel, gefolgt von der Anzahl der gefilterten Pakete und der Anzahl der Pakete in Bytes. Zum Schluss steht die Regel selbst:

# ipfw -a list

Das folgende Kommando zeigt zusätzlich alle dynamischen Regeln an:

# ipfw -d list

Um diese Auflistung um die abgelaufenen Regeln zu erweitern, geben Sie folgendes Kommando ein:

# ipfw -d -e list

Hiermit werden alle Zähler auf Null zurückgesetzt:

# ipfw zero

Es ist auch möglich, einen spezifischen Zähler zurückzusetzen:

# ipfw zero NUM

30.4.5.1. Protokollierung von Firewall-Nachrichten

Auch bei aktivierter Protokollierung wird IPFW von selbst keine Regeln protokollieren. Der Administrator muss entscheiden, welche Regeln aus dem Regelwerk protokolliert werden sollen. In diesen Regeln muss dann das Schlüsselwort log hinzugefügt werden. Normalerweise werden nur geblockte Pakete protokolliert. Es ist üblich, die ipfw default deny everything-Regel am Ende des Regelwerks mit dem Schlüsselwort log zu duplizieren. Dadurch ist es möglich, alle Pakete zu sehen, auf die keine Regel zutraf.

Protokollierung ist allerdings ein zweischneidiges Schwert. Bei mangelnder Vorsicht oder einem DoS-Angriff wird die Festplatte mit einer enormen Flut von Protokolldaten belastet. Protokoll-Nachrichten werden nicht nur an syslogd(8) geschickt, sondern auch auf der Konsole angezeigt, was dann schnell lästig werden kann.

Die Kerneloption IPFIREWALL_VERBOSE_LIMIT=5 begrenzt die Anzahl identischer Nachrichten an syslogd(8) für eine gegebene Regel auf fünf Nachrichten. Ist diese Option im Kernel aktiviert, wird nach Erreichen den festgelegten Anzahl die Protokollierung von aufeinanderfolgenden Nachrichten auf den festgelegten Wert begrenzt, da beispielsweise die Speicherung von 200 gleichen Protokoll-Nachrichten sinnlos ist. Daher werden durch diese Option nur fünf gleichartige Nachrichten protokolliert. Alle weiteren Nachrichten werden nur gezählt und deren Gesamtzahl wird schließlich von syslogd(8) wie folgt ausgegeben:

Last message repeated 45 times

Alle protokollierten Pakete werden in der Voreinstellung in /var/log/security gespeichert. Dies wird in /etc/syslog.conf definiert.

30.4.5.2. Ein Firewall-Regelwerk erstellen

Die meisten fortgeschrittenen IPFW-Benutzer erzeugen eine Datei, welche die Regeln für die Firewall enthält, um diese als Skript ausführen zu können. Der Vorteil einer derartigen Konfiguration besteht darin, dass dadurch mehrere Regeln gleichzeitig geändert und aktiviert werden können, ohne dass dazu das System neu gestartet werden muss. Dies ist zudem beim Testen von Regeländerungen sehr hilfreich. Weil es sich bei der Datei um ein Skript handelt, ist es auch möglich, häufig verwendete Befehle durch Aliase zu ersetzen und diese dann in mehreren Regeln zu nutzen.

Die Syntax des folgenden Skripts entspricht der Syntax von sh(1), csh(1) sowie tcsh(1). Felder, die symbolisch substituiert werden, haben das Präfix $ (Dollarzeichen). Symbolische Felder haben das $-Präfix nicht. Der Wert, mit dem das symbolische Feld belegt wird, muss in doppelten Anführungszeichen ("") stehen.

Die Datei mit den Regeln könnte wie folgt aufgebaut sein:

############### start of example ipfw rules script #############
#
ipfw -q -f flush       # Delete all rules
# Set defaults
oif="tun0"             # out interface
odns="192.0.2.11"      # ISP's DNS server IP address
cmd="ipfw -q add "     # build rule prefix
ks="keep-state"        # just too lazy to key this each time
$cmd 00500 check-state
$cmd 00502 deny all from any to any frag
$cmd 00501 deny tcp from any to any established
$cmd 00600 allow tcp from any to any 80 out via $oif setup $ks
$cmd 00610 allow tcp from any to $odns 53 out via $oif setup $ks
$cmd 00611 allow udp from any to $odns 53 out via $oif $ks
################### End of example ipfw rules script ############

Die Regeln in diesem Beispiel sind nicht wichtig. Wichtig ist es, zu zeigen, wie die symbolische Substitution innerhalb der Regeln verwendet wird.

Wenn dieses Beispiel in etc/ipfw.rules gespeichert wurde, so könnten alle Regeln durch die Ausführung des folgenden Kommandos neu geladen werden:

# sh /etc/ipfw.rules

Anstelle von /etc/ipfw.rules kann ein beliebig anderer Name oder Speicherort verwendet werden.

Alternativ können die einzelnen Befehle dieses Skripts auch von Hand eingegeben werden:

# ipfw -q -f flush
# ipfw -q add check-state
# ipfw -q add deny all from any to any frag
# ipfw -q add deny tcp from any to any established
# ipfw -q add allow tcp from any to any 80 out via tun0 setup keep-state
# ipfw -q add allow tcp from any to 192.0.2.11 53 out via tun0 setup keep-state
# ipfw -q add 00611 allow udp from any to 192.0.2.11 53 out via tun0 keep-state

30.4.6. IPFW Kerneloptionen

Um die Unterstützung für IPFW statisch in den Kernel zu kompilieren, lesen Sie die Anweisungen in Kapitel 8, Konfiguration des FreeBSD-Kernels. Die folgenden Optionen können in der Kernelkonfigurationsdatei verwendet werden:

options    IPFIREWALL			# enables IPFW
options    IPFIREWALL_VERBOSE		# enables logging for rules with log keyword to syslogd(8)
options    IPFIREWALL_VERBOSE_LIMIT=5	# limits number of logged packets per-entry
options    IPFIREWALL_DEFAULT_TO_ACCEPT	# sets default policy to pass what is not explicitly denied
options    IPFIREWALL_NAT		# enables basic in-kernel NAT support
options    LIBALIAS			# enables full in-kernel NAT support
options    IPFIREWALL_NAT64		# enables in-kernel NAT64 support
options    IPFIREWALL_NPTV6		# enables in-kernel IPv6 NPT support
options    IPFIREWALL_PMOD		# enables protocols modification module support
options    IPDIVERT			# enables NAT through natd(8)

Anmerkung:

IPFW kann auch als Kernelmodul geladen werden: Die oben genannten Optionen werden standardmäßig als Module erstellt, oder können zur Laufzeit über Parameter festgelegt werden.

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <de-bsd-questions@de.FreeBSD.org>.

Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <de-bsd-translators@de.FreeBSD.org>.