Ipfw, nat, jail und lokale Dienste

0815dragon

BSD-Neuling
Hallo zusammen,

ich bin gerade dabei mich in das Thema Jails einzuarbeiten und versuche eine passende Konfiguration für IPFW zu erstellen. In der Vergangenheit habe ich alle Dienste auf dem Host laufen lassen. Jetzt möchte ich das ganze etwas trennen und die aus dem www erreichbaren Dienste in Jails packen.

Daher überarbeite ich meine Firewall Konfiguration doch mit NAT stelle ich mich etwas blöd an....

Mein Ziel ist, bestimmte Dienste (z.B. Samba) nur dem lokalen Netz zur verfügung zu stellen.
Einige Jails (beispielsweise jail_www) sollen dagegen auch "von aussen" erreichbar sein.
Eine Jail (jail_mysql) dagegen wieder nicht.

Das hier ist mein aktueller Arbeitstand.
Code:
#!/bin/sh

#=====================================================#
# Command                                             #
#=====================================================#
IPF="ipfw -q"

#=====================================================#
# Configuration of host and NAT interfaces            #
#=====================================================#
lan_if="re0"
nat_if="re0"
nat_ip=`ifconfig $nat_if | grep -v inet6 | grep inet | awk '{ print $2; }'`

#=====================================================#
# Jails                                               #
#=====================================================#
jails_lan="10.0.0.0/24"
#jail_ip_www="10.0.0.10"
#jail_ip_mysql="10.0.0.11"
#jail_ip_mumble="10.0.0.12"

#=====================================================#
# Clean all                                           #
#=====================================================#
ipfw -q -f flush

#=====================================================#
# Firewall settings                                   #
#=====================================================#
#loopback
$IPF add 10 allow all from any to any via lo0
$IPF add 20 deny all from any to 127.0.0.0/8
$IPF add 30 deny all from 127.0.0.0/8 to any
$IPF add 40 deny tcp from any to any frag

# --------------------------------------------------- #
#statefull
$IPF add 100 check-state
$IPF add 110 allow tcp from any to any established
$IPF add 120 allow all from any to any out keep-state
$IPF add 130 allow icmp from any to any
$IPF add 140 allow igmp from any to any

# --------------------------------------------------- #
#host to jail
$IPF add 1000 allow any from me to $jail_ip_www setup keep-state
$IPF add 1010 allow any from me to $jail_ip_mysql setup keep-state
$IPF add 1020 allow any from me to $jail_ip_mumble setup keep-state

# --------------------------------------------------- #
#NAT for jails
#jail_ip_www
$IPF nat 1 config if $nat_if
$IPF add 1100 nat 1 all from $jail_ip_www to any
$IPF add 1110 nat 1 all from any to $nat_ip

#jail_ip_www
$IPF nat 2 config if $nat_if
$IPF add 1200 nat 2 all from $jail_ip_mysql to any
$IPF add 1210 nat 2 all from any to $nat_ip

#jail_ip_mumble
$IPF nat 3 config if $nat_if
$IPF add 1300 nat 3 all from $jail_ip_mumble to any
$IPF add 1310 nat 3 all from any to $nat_if

# --------------------------------------------------- #
#TODO:

#open ports ftp(20,21), ssh(22), http(80), vlc-Stream(1234)
#netbios (81), samba-nmbd (137,138), samba-smbd (139,445), mediatomb(1900,49152)
$IPF add 2100 allow tcp from any to me 21 in
$IPF add 2110 allow tcp from me to any 21 out
$IPF add 2120 allow tcp from any to me 22 in
$IPF add 2130 allow tcp from me to any 22 out
$IPF add 2140 allow tcp from any to any 80 in
$IPF add 2150 allow tcp from any to any 80 out
#$IPF add 2160 allow udp from any to any 1234 in
#$IPF add 2170 allow udp from any to any 1234 out
$IPF add 2180 allow tcp from 192.168.178.0/24 to me 81 in
$IPF add 2190 allow tcp from me to 192.168.178.0/24 81 out
$IPF add 2200 allow udp from 192.168.178.0/24 to me 81 in
$IPF add 2210 allow udp from me to 192.168.178.0/24 81 out
$IPF add 2220 allow tcp from 192.168.178.0/24 to me 137 in
$IPF add 2230 allow tcp from me to 192.168.178.0/24 137 out
$IPF add 2240 allow udp from 192.168.178.0/24 to me 137 in
$IPF add 2250 allow udp from me to 192.168.178.0/24 137 out
$IPF add 2260 allow tcp from 192.168.178.0/24 to me 138 in
$IPF add 2270 allow tcp from me to 192.168.178.0/24 138 out
$IPF add 2280 allow udp from 192.168.178.0/24 to me 138 in
$IPF add 2290 allow udp from me to 192.168.178.0/24 138 out
$IPF add 2300 allow tcp from 192.168.178.0/24 to me 139 in
$IPF add 2310 allow tcp from me to 192.168.178.0/24 139 out
$IPF add 2320 allow udp from 192.168.178.0/24 to me 139 in
$IPF add 2330 allow udp from me to 192.168.178.0/24 139 out
$IPF add 2340 allow tcp from 192.168.178.0/24 to me 445 in
$IPF add 2350 allow tcp from me to 192.168.178.0/24 445 out
$IPF add 2360 allow udp from 192.168.178.0/24 to me 445 in
$IPF add 2370 allow udp from me to 192.168.178.0/24 445 out
$IPF add 2380 allow tcp from 192.168.178.0/24 to me 1900 in
$IPF add 2390 allow tcp from me to 192.168.178.0/24 1900 out
$IPF add 2400 allow udp from 192.168.178.0/24 to me 1900 in
$IPF add 2410 allow udp from me to 192.167.178.0/24 1900 out
$IPF add 2420 allow tcp from 192.168.178.0/24 to me 49152 in
$IPF add 2430 allow tcp from me to 192.168.178.0/24 49152 out
$IPF add 2440 allow udp from 192.168.178.0/24 to me 49152 in
$IPF add 2450 allow udp from me to 192.168.178.0/24 49152 out

# deny and log everything
$IPF 5000 deny log all from any to any in

Die NAT Konfiguration ist, glaube ich, komplett verkehrt.
Vom Gefühl her sollten die Regeln der Ports noch vor den NAT Regeln positioniert werden, oder?

Könnten ihr kurz über die Konfiguration fliegen und mir helfen den Knoten in meinem Kopf zu entwirren?
Vielen Dank für eure Hilfe!

Gruss
 
Hier im Forum verwenden fast alle, sofern überhaupt, PF als Firewall, IPFW ist sehr unbeliebt. Ich weiß nicht warum, denn man muß schon abgehobene Sachen machen, um mit IPFW an Grenzen zu stoßen.

Mit NAT habe ich wenig Erfahrung, daher ohne Gewähr :

Sowohl für den ein- als auch den ausgehenden Traffic arbeitest Du zuerst die Deny-Regeln ab (hast Du nicht) sowie die Allow-Regeln, die nichts mit NAT zu tun haben, zuletzt NAT. Solange Du nicht »ipfw disable one_pass« einstellst, macht NAT automatisch auch Allow (*), und Du kannst danach nicht weiter filtern, außer nach dem Forwarding auf dem Interface in Richtung Jail (**). Mit »ipfw disable one_pass« dagegen macht er einfach mit der auf die NAT-Regel folgenden Regel weiter, aber das würde ich nicht benutzen. Du kannst vielmehr alle drei NAT-Vorschriften zu einer zusammenfassen:
Code:
$IPF nat 1 config if $nat_if
$IPF add 1100 nat 1 all from $jail_ip_www,$jail_ip_mysql,$jail_ip_mumble to any out via $nat_if
$IPF add 1110 nat 1 all from any to me in via $nat_if
»in/out via $nat_if« ist vielleicht unnötig, aber generell wäre ich bei permissiven Regeln sehr pingelig.

(*) Was ich jetzt nicht auswendig weiß: Macht er automatisch Allow nur für die Pakete, deren IP er tatsächlich ändert, oder auch z. B. bei solchen, deren Endstation auf dem Firewall-Host liegt? Das müßtest Du probieren.
(**) An der Stelle würde ich die ganzen Allow-Regeln unterbringen, möglichst auch ein bißchen zusammengefaßt, z. B. Port-Angabe »81,137-139,445,1900,49152« in einer Regel, ebenso »tcp« und »udp« zu »all« zusammengefaßt. Da kannst Du auch ein bißchen präziser sein, welche Ports an welche Jail gehen dürfen und welche Jail von wo erreichbar sein soll.

Warum willst Du Dich überhaupt mit NAT herumschlagen und gibst Deinen Jails nicht einfach Adressen aus dem LAN-Bereich (192...)? IMO ist der Gewinn an Sicherheit eher gering.

Denke generell daran, daß Du vier Stellen hast, an denen Du filtern mußt/kannst:

a) in via $nat_if
b) out Richtung einer Jail
c) in von einer Jail
d) out via $nat_if

a) und b) haben natürlich eine größere Schnittmenge, c) und d) ebenso. Also: Was Du an a) erlaubst, mußt Du evtl. auch an b) erlauben usw.

Tip: Manchmal ist es hilfreich, Allow-Regeln in Deny-Regeln umzuschreiben mit Hilfe des Schlüsselwortes »not«, also statt »allow irgendwas« ein »deny not irgendwas«.
Und überhaupt würde ich die neuere Syntax verwenden, also ohne »from« und »to«, sondern mit »src-ip«, »src-port«, »dst-ip«, »dst-port« und »proto«. Die können in beliebiger Reihenfolge stehen, und wenn sie fehlen, heißt das soviel wie »any«.
 
Die Syntax von pf ist einfach 100x besser als die von IPFW. Die zwangsweise Angabe von Regelnummern erinnert an BASIC Programmierung.</offtopic>
 
"Zwangsweise Angabe von Regelnummern"? Das stimmt doch überhaupt nicht! Du kannst die Nummern weglassen.
 
IPFW generiert sich dann selbst seine Nummer. Intern hält es sich aber immer welche vor.
 
Nein, ipfw generierte schon immer implizit Nummern, wenn man keine angab. Früher waren die automatisch vergebenen Nummern nur sehr nahe beieinander, inzwischen gibt es dafür aber inzwischen das sysctl "net.inet.ip.fw.autoinc_step" mit der Standardeinstellung 100. In FreeBSD 11-CURRENT ist übrigens schon vor einigen Monaten ipfw 3 eingegangen. Das hat zwar immer noch Nummern, bringt aber gerade bei Tabellen große Fortschritte, die es komfortabler machen.
 
Wie greift man denn eigentlich in PF interaktiv auf eine einzelne Regel zu, um sie z. B. zu löschen oder einen lokalen Zähler zurückzusetzen? Und wie findet man sich in Logfiles zurecht? Und zumindest als Sprunglabels gibt es Nummern auch in PF, nehme ich an!?
 
Hallo,

vielen Dank für die Informationen. Damit ist mir erstmal geholfen :-)
Eine Frage hätte ich aber noch:
Wie ist das mit der neuen Syntax gemeint?
also ohne »from« und »to«, sondern mit »src-ip«, »src-port«, »dst-ip«, »dst-port« und »proto«. Die können in beliebiger Reihenfolge stehen, und wenn sie fehlen, heißt das soviel wie »any«.
Wenn ich das richtig verstanden habe würde eine Regel jetzt in etwa so aussehen:
Code:
$IPF add 2190 allow tcp src-ip me 192.168.178.0/24 81 out

Danke und Gruss
 
Code:
$IPF add 2190 allow proto tcp src-ip me dst-ip 192.168.178.0/24 dst-port 81 out
Wenn Du den nächsten Entwurf Deines Skripts fertig hast, dann poste ihn doch wieder hier, damit ich noch mehr kritisieren kann. :D
 
Na dann leg los:p
Ich habe versucht die neuere Syntax zu verwenden, so wie ich es aus deinen Kommentaren verstanden habe

Code:
#!/bin/sh

#=====================================================#
# Command                                             #
#=====================================================#
IPF="ipfw -q"

#=====================================================#
# Configuration of host and NAT interfaces            #
#=====================================================#
lan_if="re0"
nat_if="re0"
nat_ip=`ifconfig $nat_if | grep -v inet6 | grep inet | awk '{ print $2; }'`

#=====================================================#
# Jails                                               #
#=====================================================#
jails_lan="10.0.0.0/24"
jail_ip_www="10.0.0.10"
jail_ip_mysql="10.0.0.11"
jail_ip_mumble="10.0.0.12"

#=====================================================#
# Clean all                                           #
#=====================================================#
ipfw -q -f flush

#=====================================================#
# Firewall settings                                   #
#=====================================================#
#loopback
$IPF add 10 deny not via lo0
$IPF add 20 deny dst-ip 127.0.0.0/8
$IPF add 30 deny src-ip 127.0.0.0/8
$IPF add 40 deny tcp frag

# --------------------------------------------------- #
#statefull
$IPF add 100 check-state
$IPF add 110 deny not tcp established
$IPF add 120 deny not out keep-state
$IPF add 130 deny not icmp
$IPF add 140 deny not igmp

# --------------------------------------------------- #
#open ports
$IPF add 200 deny not proto all src-ip 192.168.178.0/24 dst-ip me dst-port 81,137-139,445,1900,49152 in
$IPF add 210 deny not proto all src-ip me dst-ip 192.168.178.0/24 dst-port 81,137-139,445,1900,49152 out
$IPF add 220 deny not proto tcp src-ip any dst-ip me dst-port 21,22 in
$IPF add 230 deny not proto tcp src-ip me dst-ip any dst-port 21,22 out

# --------------------------------------------------- #
#host to jail
$IPF add 1000 deny not src-ip me dst-ip $jail_ip_www, $jail_ip_mysql, $jail_ip_mumble setup keep-state

# --------------------------------------------------- #
#NAT for jails
$IPF nat 1 config if $nat_if redirect_port $jail_ip_www:80 80 redirect_port $jail_ip_mumble:64738 64738
$IPF add 1100 nat 1 all src-ip $jail_ip_www,$jail_ip_mysql,$jail_ip_mumble out via $nat_if
$IPF add 1110 nat 1 all dst-ip me in via $nat_if


# --------------------------------------------------- #
# deny and log everything
$IPF 5000 deny log all from src-ip any dst-ip any in

Danke und Gruss
 
Ärch! Das mit "deny not" hast Du völlig mißverstanden. "not" verneint eine bestimmte Option, also z. B. "deny proto udp not dst-ip me" heißt: Weg mit allem UDP-Zeugs, das nicht an mich gerichtet ist. Auf keinen Fall wollte ich, daß Du stur alle "allow"-Anweisungen durch "deny not" ersetzt, allein schon deshalb, weil es ein "deny not" nicht gibt. Ich wollte nur anregen, ohne mich auf eine konkrete Stelle bei Dir zu beziehen, mal über eine Umdrehung von Regeln nachzudenken, d. h. statt einige Dinge ausdrücklich zu erlauben vielleicht einige andere Dinge ausdrücklich zu verbieten. Deny-Regeln können nämlich eher auch vor dem NAT durchlaufen werden, weil das, was weggeschmissen wird, sowieso nicht mehr geNATet werden muß. Das kann manches vereinfachen.

Und nun zu den einzelnen Regeln:
110: Würde ich ganz streichen, denn das sollte durch "keep-state" und "check-state" abgedeckt sein.
120: Hier erlaubst Du alles, was hinausgeht, ins LAN, ins Internet oder in eine Jail. Das sollte man zumindest mit einem "setup" verbinden, d. h., nur neu aufgebaute Verbindungen nach draußen. Bestehende Verbindungen werden dann über Regel 100 automatisch aufrechterhalten. Außerdem hast Du nicht an die Jails gedacht. Die mußt Du hier erst mal ausklammern, indem Du "src-ip me" und "out via $lan_if" verlangst. Summa summarum:
Code:
$IPF add 120 allow src-ip me out via $lan_if setup keep-state
130 und 140: "proto icmp" bzw. "proto igmp"!
210: Das muß doch src-port heißen, oder? Die Ports sind doch offene Ports auf Deinem Rechner, sei es im Grundsystem oder einer Jail, auf denen die Serverprozesse lauschen.
230: siehe 210, auch hier sind es für ausgehende Pakete keine dst-ports, sondern src-ports. Du mußt immer bedenken, wo die Pakete herkommen und wo sie hingehen.
1000: Hier würde ich "src-ip me" weglassen, dann sind auch gleich die durch NAT weitergeleiteten Pakete mit dabei. Andernfalls brauchst Du für die eine Extra-Regel, sonst werden sie zwar schön geNATet, aber nicht mehr hinausgelassen. Und noch "out" angeben, sicherheitshalber.
nat 1: Hier hast Du wohl das redirect für mysql vergessen.
1100: Nicht "all", sondern "proto all", aber das ist eh überflüssig. Dito in den folgenden Regeln.
1110: Wie gesagt, bin ich mir hier nicht sicher, ob das NAT auch die Pakete hereinläßt, deren IP gar nicht geändert wurde. Ich denke, nein. Wenn ja, dann müßtest Du das vorher wegfiltern, also "deny" für alles, was an "dst-ip me" und nicht an die geforwardeten Ports gerichtet ist.
5000: Das gibt sehr viel Müll im Logfile. Laß das "log" hier weg (und das "from" sowieso!) und mach eine Regel
Code:
$IPF add 4999 deny log in setup
 
Zurück
Oben