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.
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.
:
absoluter Pfad zu einer Datei, in der die Firewallregeln
definiert sind.filename
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"
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
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
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).
Jede Regel muss mit ipfw add
beginnen.
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.
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.
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).
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.
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.
Dieser optionale Wert wird verwendet, um einen
beliebigen Protokollnamen oder -nummer aus
/etc/protocols
gegen das Paket zu
prüfen.
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
.
Optional kann ein Quellport über eine Nummer oder
einen Namen aus /etc/services
spezifiziert werden.
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.
Optional kann ein Zielport über eine Nummer oder
einen Namen aus /etc/services
spezifiziert werden.
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.
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.
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
FreeBSDs integrierter NAT-Daemon, natd(8), arbeitet in Verbindung mit IPFW, um Network Address Translation bereitzustellen. NAT wird verwendet, um mehreren internen Rechnern, über eine einzige IP-Adresse, eine gemeinsame Verbindung zum Internet zu ermöglichen.
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"
Wenn firewall_enable
nicht gesetzt
ist, firewall_nat_enable
jedoch schon,
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. Darüber hinaus ist es aufgrund der Architektur
von libalias(3), einer Bibliothek die als Kernelmodul
implementiert ist und für das In-Kernel NAT
von IPFW benutzt wird, notwendig,
TCP segmentation offloading
(TSO) zu deaktivieren.
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"
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"
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 nimmt ein paar Argumente und
Schalter an, 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). Darüber hinaus ist es aufgrund
der zustandsorientierten NAT-Firewall
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.
Die Reassamble-Regel wird beim Userland natd(8)
nicht benötigt, da die Aktion divert
von
IPFW dies bereits automatisch
übernimmt. Dies ist auch in ipfw(8)
dokumentiert.
Beachten Sie, dass die aktuelle
NAT-Instanznummer und
NAT-Regelnummer 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 # reassamble 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.
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.
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 geladene
Kernelmodul 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
, um die volle Funktionalität
der Userland-Implementierung zu erreichen. Wenn ein
angepasster Kernel benutzt wird, kann die volle
Funktionalität der Userland-Bibliothek im Kernel mit
option LIBALIAS
gebaut werden.
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.1683.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.
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.
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 einzigen Ausnahmen sind,
dass die Konfiguration der In-Kernel
NAT-Instanz
(ipfw -q nat 1 config ...)
nicht
anwendbar ist und die Regeln müssen wie unten beschrieben
leicht geändert werden, und Regel 99 wird nicht mehr
benötigt, da die divert
-Aktion sich um die
Fragmentierung kümmert.
$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"
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
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
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.
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
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 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)
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>.