FreeBSD IPv4 Jails auf IPv6 erweitern

-Nuke-

Well-Known Member
Heyho.

Ich muss gleich mal sagen, dass ich mich mit IPv6 nicht sonderlich auskenne und das will ich damit auch ändern. Also ich habe ein Server von Hetzner und darauf läuft auch eigentlich alles ziemlich gut (es ist noch FreeBSD 10.3 falls relevant. Update auf 11.0 folgt noch). IPv6 auf dem Host direkt ist wohl schon durch die Hetzner-Config gut eingerichtet. Ich erreichte Dienste direkt auf dem Host (was im Endeffekt nur SSH ist) über IPv4 und IPv6. Dienste in Jails leite ich mittels pf vom Host an die Jails weiter. Über IPv6 erreiche ich die Jail-Dienste NICHT. Also z.B. telnet <ip4addr> 80 geht. telnet <ipv6addr> 80 geht nicht.

Da dort keinerlei IPv6 relevanten Daten drin stehen oder Konfigurationen vorgenommen wurden, ist das auch nicht weiter verwunderlich.

Ping an IPv4 Adressen geht in raw_socket Jails. Ping6 wiederum nicht, weil IPv6 nicht unterstützt ist. Ping4 und Ping6 funktionieren auf dem Host normal.

Die Config in der rc.conf von Hetzner sieht da so aus (Adressen mal entfernt und in <ipv4addr> und <ipv6addr> gepackt):

Code:
ifconfig_re0="inet <ipv4addr> netmask 0xffffffe0 broadcast <ipv4addr>"
gateway_if="re0"
gateway_ip="<ipv4addr>"
static_routes="gateway default"
route_gateway="-host $gateway_ip -interface $gateway_if"
route_default="default $gateway_ip"
ipv6_default_interface="re0"
ifconfig_re0_ipv6="<ipv6addr>"
ipv6_defaultrouter="fe80::1%re0"

Jails binde ich an ein lokales lo Interface und kriegen da ihre IP:
Code:
cloned_interfaces="lo1"
ifconfig_lo1_name="jail0"
ipv4_addrs_jail0="10.0.0.1/24 10.0.0.1-20/32"

Meine (gekürzte) pf.conf sieht da im großen und ganzen so aus (hat halt nur mehr rdr Einträge die alle so aussehen:

Code:
ALLIF = "{ jail0, re0 }"
PUBIF="re0"
JAILIF="jail0"
PUBIP="<ipv4addr>"
JAILNET="10.0.0.0/24"

REVERSEJAIL="10.0.0.1"

scrub in all
set skip on lo0

# Rules
nat pass on $PUBIF from $JAILNET to any -> $PUBIP
rdr pass on $PUBIF proto tcp from any to $PUBIP port {http, https} -> $REVERSEJAIL

pass out on $ALLIF all keep state
pass in on $ALLIF all keep state

Jetzt würde ich gerne alles noch mal für IPv6 haben. Aber wie und welche Adressen gebe ich den Jails da und muss da was in der pf geändert werden?
 
Hi Nuke,
ich steh aktuell vor der gleichen Aufgabe und meinen Gedanken nach, fügst du dem "re0" Interface IPv6 aliase zu, bindest die Adressen an die jeweilige jail (jail.conf) und dann fehlt nur noch die Firewall. Die mir momentan auch noch Probleme macht, da ich nicht weiß ob ich alles richtig abgedeckt habe.

rc.conf
Code:
ipconfig_re0_ipv6="inet6 2a01:dead:beef:dead::1 prefixlen 64"
ifconfig_re0_aliases="inet6 2a01:dead:beef:dead::2 prefixlen 64 \
  inet6 2a01:dead:beef:dead::3 prefixlen 64 \
  inet6 2a01:dead:beef:dead::4 prefixlen 64 \
  inet6 2a01:dead:beef:dead::5 prefixlen 64 \
  inet6 2a01:dead:beef:dead::6 prefixlen 64"

jail.conf
Code:
# ...
# web/db
httpd {
  host.hostname = "httpd.example.com";
  ip4.addr = "10.0.0.2";
  ipv6.addr = "2a01:dead:beef:dead::2/64";
  # ? ipv4.addr = "jail0|10.0.0.2";
  # ? ipv6.addr = "re0|2a01:dead:beef:dead::2/64";
}
# ...

pf.conf
Code:
ext_if = "re0"
int_if = "jail0"
vpn_if = "tun0"

table <rfc1918> persist { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 224.0.0.0/5 }

icmp_types = "echoreq"
jails = "{ 10.0.0.1, 10.0.0.2 }"
vpn_network = "10.0.1.0/24"
ext_ip = "111.122.133.144"
ext_ipv6 = "2a01:dead:beef:dead::/64"
host = "10.0.0.1"
host_v6 = "2a01:dead:beef:dead::1"
httpd = "10.0.0.2"
httpd_v6 = "2a01:dead:beef:dead::2"

set block-policy drop
set skip on lo0
set loginterface $ext_if
set optimization normal
set require-order yes
set fingerprints "/etc/pf.os"
set ruleset-optimization basic

scrub in all fragment reassemble random-id

# NAT/RDR
nat on $ext_if inet proto { tcp udp icmp } from $jails to any -> $ext_ip
nat on $ext_if inet proto { tcp udp icmp } from $vpn_network to any -> $ext_ip
rdr on $ext_if inet proto tcp from any to $ext_if port { 2142 } -> $host
rdr on $ext_if inet proto udp from any to $ext_if port { 1194 } -> $host
rdr on $ext_if inet proto tcp from any to $ext_if port { 80 443 } -> $httpd

block log all
block return
block in quick on $ext_if inet from <rfc1918> to any
block return out quick on $ext_if proto { tcp udp icmp icmp6 } from ! { $ext_ip, $ext_ipv6 } to any
antispoof quick for $ext_if

# JAIL to JAIL
pass in quick on $int_if inet proto tcp from $jails to $host port { 2142 }
pass in quick on $int_if inet proto udp from $jails to $host port { 1194 }
pass in quick on $int_if inet proto tcp from $jails to $httpd port { 80 443 2143 }

# VPN
pass in quick on $vpn_if

# WAN to HOST -> JAIL
pass in quick on $ext_if inet proto tcp from any to $host port { 2142 }
pass in quick on $ext_if inet6 proto tcp from any to $host_v6 port { 2142 }
pass in quick on $ext_if inet proto udp from any to $host port { 1194 }
pass in quick on $ext_if inet6 proto udp from any to $host_v6 port { 1194 }
pass in quick on $ext_if inet proto tcp from any to $httpd port { 80 443 }
pass in quick on $ext_if inet6 proto tcp from any to $httpd_v6 port { 80 443 }
pass in quick on $ext_if inet proto icmp all icmp-type $icmp_types
pass in quick on $ext_if inet6 proto icmp6 all
pass out quick all
 
@-Nuke- Eine Nachfrage zunächst: Nutzt Du öffentliche IPv6-Adressen für die Jails, die einfach durch-geroutet werden können... oder willst Du analog zu der IPv4-Konfiguration auch bei IPv6 private Adressen NAT'ten? Falls letzteres, kann ich hier gerne meine Konfigs posten.
 
OK.

Ich nutze ein separates Loopback-Interface für die Kommunikation mit und zwischen den Jails: lo1.

Daher steht in /etc/rc.conf
Code:
cloned_interfaces="${cloned_interfaces} lo1"

In /etc/jail.conf sind mehrere Jails konfiguriert, hier der Eintrag für die mit dem Webserver:
Code:
web {
  path  = /usr/jails/web;
  host.hostname = web;
  interface = lo1;
  ip4.addr =  10.0.0.1;
  ip6.addr =  fd0c:800b:c17d:b1f0::1;
}

Und die (gekürzte) /etc/pf.conf sieht so aus:
Code:
ext_if = "vtnet0"
int_if = "lo1"

ip4_pub = XXX
ip6_pub = YYY

jails_ip4 = "{ 10.0.0.0/28 }"
jails_ip6 = "{ fd0c:800b:c17d:b1f0::0/116 }"

jail_services = "{ http, https }"

icmp_types="{ 2, 128, 133, 134, 135, 136, 137 }"

# options
set block-policy return
set skip on lo

# scrub incoming packets
scrub in all

nat pass on $ext_if inet proto { tcp udp icmp } from $jails_ip4 to any -> $ip4_pub
nat pass on $ext_if inet6 proto { tcp udp icmp6 } from $jails_ip6 to any -> $ip6_pub
rdr pass on $ext_if inet proto tcp from any to (vtnet0) port $jail_services -> 10.0.0.1
rdr pass on $ext_if inet6 proto tcp from any to (vtnet0) port $jail_services -> fd0c:800b:c17d:b1f0::1

# setup a default deny policy
block log all
antispoof quick for $ext_if

pass in on $ext_if proto tcp from any to (vtnet0) port XYZ
pass in on $ext_if proto { tcp udp icmp } from $jails_ip4 to any
pass in on $ext_if proto { tcp udp icmp6 } from $jails_ip6 to any
pass out on $ext_if proto { tcp udp icmp icmp6 } all

pass in inet proto icmp all icmp-type echoreq
pass in inet6 proto icmp6 all icmp6-type $icmp_types

Wie ich gelernt habe, ist es tatsächlich wichtig, bei IPv6 einiges an ICMP6-Verkehr durchzulassen, sonst klappt die Erkennung der Nachbarn nicht.
 
Dankeschön. Auf diesem Weg hat es geklappt. Ist vielleicht auch ganz interessant für dich, gadean :)

Aber mal noch weiteren Kram zu IPv6 lesen... xD
 
wenn man schon 2^64 öffentliche IPs hat, warum will man denn dann immer noch NAT machen?! Einfach die IPv6 IPs in der jail.conf eintragen, und den Port via pf aufmachen:

Code:
pass on vtnet0 proto udp from any to $ns2_v6 port 53

Aliase in der rc.conf braucht man übrigens auch nicht, das wird automagisch beim start der jail gemacht.
 
@derOliver Wenn man parallel noch IPv4 nutzen muss, finde ich es einfacher, beide Protokolle gleich zu behandeln. Dann muss ich nicht jedes Mal überlegen, wie ich das bei IPv4 und wie bei IPv6 gemacht habe. Die pf.conf wird dadurch für mich übersichtlicher.

Hinzu kommt: Zwei von drei meiner Jails stellen eh nur Dienste für die Web-Jail zur Verfügung (Datenbank-Server) - die sollen nie von außen erreichbar sein. Dann erleichtert dieses Setup den Umzug (oder die Einrichtung eines Entwicklungs-Servers): In der /etc/jail.conf muss ich nix ändern, weil nur von mir vergebene private Adressen genutzt werden. In der pf.conf muss ich nur je eine öffentliche IPv4 und IPv6-Adresse ändern - die Adressen der Jails bleiben immer gleich.
 
Eben. Von meinen ~15 Jails müssen so ziemlich genau nur 3 von außen erreichbar sein. Nämlich der DNS, Jabber und der Reverseproxy. Alles andere läuft privat hinter diesen Jails. Ich gebe einfach allen Domain-Inhabern eine IPv4 und eine IPv6 durch und fertig ist's.

Dass die IPs auch über die jail.conf angelegt werden können wusste ich gar nicht. Vielleicht ging das zum Einrichtungszeitpunkt auch noch gar nicht. Macht auf jeden Fall die rc.conf übersichtlicher :D
 
@derOliver Danke für die Info mit den Aliasen.

Die Frage mit dem NAT"ten" hab ich mir auch gestellt, auf der einen Seite ist es unnötig weil genug Adressen verfügbar sind und es nur mehr "Komplexität" schafft, andererseits macht es die Konfiguration und den transport der Jails einfacher ... da kommt man echt ins grübeln :D

@SolarCatcher Deine Adresse ist doch eine "Unique Local Unicast"? Der Präfix "fd" ist fest, die Site-Id wird lt. Wiki zufällig generiert, darauf folgt dann die Subnet-ID (frei wählbar), nun stell ich mir die Frage, wo du die Site-ID her hast, oder kann man die ebenfalls einfach frei wählen, was aber dann dem RFC widerspricht?

PS: Genau deswegen hab ich mich so lange vor IPv6 gedrück, so viele Fragen und bisher kaum ein Überblick was nun "best practice" etc. oder "no-gos" sind :D
 
Ja IPv6 ist echt ein dicker Brocken der erst mal verdaut werden muss xD Mein Problem "warum erst jetzt" ist relativ einfach. Ich hab erst vor kurzem den Internet-Anbieter gewechselt und habe erst jetzt Zugang zu IPv6. :D

Auch dieses:
ifconfig_igb1_ipv6="inet6 accept_rtadv"
rtsold_enable="YES"

In der rc.conf auf dem Client ist mir noch ein kleines Rätsel... Hab ich auch nur so aus dem Handbuch übernommen. Aber was der Router da nun genau macht und was der Client damit anfängt... puhhh :D
 
ifconfig_igb1_ipv6="inet6 accept_rtadv"
rtsold_enable="YES"
Bei IPv6 macht man "eigentlich" kein DHCP mehr, wenn man nicht immer die selben Adressen vergeben will oder mehr als nur den DNS Server an die Clients rausgibt. Es wird dann "Router Advertisement" gemacht und der Client erzeugt sich selbst eine Adresse, die er auch dann und wann rotiert.
 
Zurück
Oben