18. IPv6 Router
IPv6 wurde von der IETF (Internet Engineering Task Force) 1998 standardisiert.
Alle grossen Linux-Distributionen, auch Slackware 11.0, das Basis-System von
Linuxrouter, sind IPv6-fähig.
Für das vorliegende HowTo wurde Linuxrouter mit fixer IPv4 Adresse,
FTTH (fiber-to-the-home) Anbindung, und mit der folgenden Software-Ausstattung
betrieben:
Basis System: Slackware 11.0
Kernel: linux-2.6.39
gcc-3.4.6
libc-2.3.6
dhcpcd-2.0.4 (IPv4 DHCP client)
iptables-1.4.21
iproute2-3.1.0
wide-dhcpv6c-20080615
radvd-0.9.1 (optional)
|
|
Zur Zeit (2019) stellen die Internet Service Provider (ISP) ihren Kunden IPv6
entweder nativ oder mittels einer IPv6-in-IPv4 Tunnel-Technologie namens
6RD (IPv6 Rapid Deployment) zur Verfügung.
6RD-Unterstützung ist im Linux-Kernel seit Version >=2.6.33 verfügbar,
es empfiehlt sich somit, bei der Bereitstellung eines IPv6-Routers einen Kernel
mit entsprechender Version zu verwenden. Es liegt auf der Hand, dass
IPv6-Netfilter-Unterstützung ebenfalls erforderlich ist.
General Setup -->
Networking support --> Networking options -->
[*] The IPv6 protocol -->
[*] IPv6: IPv6-inIPv4 tunnel (SIT driver)
[*] IPv6: IPv6 Rapid Deployment (6RD))
Networking support --> Networking options -->
[*] Network packet filtering framework (Netfilter) -->
IPv6: Netfilter Configuration -->
[*] Select as required
|
|
iproute2 , die Sammlung von Netzwerk-Tools von A. Kuznetsov ist
zwingend erforderlich, wenn es nötig sein sollte, ein 6RD Tunnel-Interface zu
konfigurieren. Das Kompilieren von iproute2 auf älteren Systemen
kann herausfordernd sein. Eine Version wählen, die ungefähr dem Alter des
verwendeten Kernels entspricht und nicht versuchen, sämtliche mögliche
Features der Toolbox zu kompilieren.
wide-dhcpv6 ist eine Implementation von DHCPv6, die ursprünglich
für das KAME Projekt entwickelt wurde. Der wide-dhcpv6 -client konfiguriert
die Linuxrouter-Interfaces und ist erforderlich, wenn natives IPv6 eingesetzt wird.
BEACHTEN: wide-dhcpv6 lässt sich auf Slackware (auf Linux?) nur kompilieren,
wenn zuvor die zugehörigen Debian-Patches eingespielt wurden! Der Dank für diesen
entscheidenden Tipp geht an den Autor von
https://www.blinkenlights.ch
wide-dhcpv6-20080615.tar.gz downloaden von:
https://sourceforge.net
wide-dhcpv6_20080615-12.debian.tar.gz downloaden von:
http://http.debian.net
wide-dhcpv6-20080615 kompilieren und auf dem Router installieren.
radvd , der «Router Advertisement Daemon» muss installiert
werden, falls sich die Hosts der lokalen LANs mittels «IPv6 Stateless Address
Autoconfiguration» (SLAAC) selbst konfigurieren und dafür von Linuxrouter mit
ihrem IPv6-Address-Präfix versorgt werden müssen. Wenn die lokalen Maschinen
manuell or mittels DHCPv6 konfiguriert werden, kann auf radvd verzichtet werden.
Download: http://www.litech.org/
IPv6 verwendet 128 bit Adressen. Eine IPv6 Adresse ist unterteilt in einen Netzwerk
Teil («routing prefix») von 64 bit und einen «interface identifier»
von 64 bit.
IPv6 Adressen sind nicht nur länger als die gewohnten 32 bit IPv4 IPs, sie haben
auch einen anderen Funktionsumfang. Eine Eigenschaft von IPv6 Netzen, die ein
Umdenken erfordert, ist, dass es mit IPv6 normal - sozusagen Teil des Systems ist -
dass mehrere IPs, die verschiedenen Klassen angehören und verschiedene Funktionen
haben, an die gleiche Netzwerkkarte gebunden werden.
Beispielsweise wird ein IPv6-fähiger Kernel einem für IPv4 konfigurierten Interface
selbständig eine «link-local» IPv6 Adresse zuweisen, die mit dem Präfix
«fe80» beginnt und Teile der Hardware-Adresse der Netzwerkkarte beinhaltet.
Link-local Adressen sind nicht «routable», werden aber für IPv6 Features wie
das «Neighbor Discovery Protocol» benötigt.
Um die Kommunikation zwischen verschiedenen internen Netzwerk-Segmenten sicherzustellen,
und auch aus Gründen der Übersichtlichkeit, ist es sinnvoll, ein internes
IPv6-Address-Schema bereitzustellen. Das Stichwort hierzu lautet ULA
«Unique Local Address». ULAs sind nicht im Internet aber zwischen
verschiedenen internen Netzwerk-Segmenten «routable». ULAs beginnen mit
dem Adressblock fd00::/8 und sind als /48 Präfix definiert. Die folgenden
16 bit dienen als Subnet ID, die letzten 64 bit definieren das Interface.
RFC4193
beschreibt, wie die 40 bit des «routing prefix» generiert werden können,
um einen global einmaligen Präfix sicherzustellen. Für ein internes Netzwerk
mit drei Segmenten (aus Sicht des Routers eth0, eth2, eth3), kann ein Address-Schema
somit wie folgt aussehen:
fdxx:yyyy:zzz::1 -> router address for eth0
fdxx:yyyy:zzz::2 -> first host in network 0 connected to eth0
fdxx:yyyy:zzz:2::1 -> router address for eth2
fdxx:yyyy:zzz:2::2 -> first host in network 2 connected to eth2
fdxx:yyyy:zzz:3::1 -> router address for eth3
fdxx:yyyy:zzz:3::2 -> first host in network 3 connected to eth3
|
|
Für den Zugang zum globalen IPv6 Internet benötigt eine Netzwerkkarte
zusätzlich zur ULA eine UGA (Unique Global Address). Der weltweit einmalige
IPv6-Präfix der UGA kann nicht selbst generiert werden, sondern muss vom
Internet Service Provider zugewiesen werden. Verbreitete Verfahren hierzu sind
«native» IPv6 und die 6RD-Tunnel-Technologie.
Die Idee von 6RD besteht darin, dass ein IPv4 CE (Customer Equipment, hier
Linuxrouter) IPv6-Pakete als Payload in IPv4-Paketen unterbringt und diese an
den IPv4 BR (Border Relay) des Providers sendet. Der BR entpackt die ankommenden
IPv4 Frames und leitet den IPv6 Content ins IPv6 Internet weiter.
6RD benötigt:
-Den IPv6 Präfix des Internet Service Providers. Beispiel: 2a02:1200::/28
-Die fixe IPv4 IP von Linuxrouter. Fiktives Beispiel: 172.20.121.122
-Die IPv4 Addresse des Tunnelendpunkts auf auf Seite ISP. Beispiel: 193.5.29.1
Aus den obigen Parametern wird der «delegated prefix» generiert,
dazu wird die öffentliche IPv4 IP von Linuxrouter nach Hex konvertiert und zum
IPv6 Präfix hinzugefügt:
printf "%02x%02x:%02x%02x\n" 172 20 121 122
ac14:797a
Your IPv6 delegated prefix (public address block) is therefore:
2a02:120a:c147:97a0::/60
|
|
Da der Provider einen /28 Präfix verwendet, bleiben 4 bit für die
Definition von 2^4 Subnetzen. Es können somit die folgenden lokalen Netze
konfiguriert werden:
2a02:120a:c147:97a0::/64
up to
2a02:120a:c147:97af::/64
|
|
Für die Konfiguration des 6RD-Tunnels gehen wir von vier Netzwerkkarten aus:
eth1 ist das Internet Interface, eth0, eth2, eth3 bedienen lokale Netze.
Den internen NICs werden UGAs zugewiesen:
# ifconfig eth0 inet6 add 2a02:120a:c147:97a0::1/64
# ifconfig eth2 inet6 add 2a02:120a:c147:97a2::1/64
# ifconfig eth3 inet6 add 2a02:120a:c147:97a3::1/64
|
|
Für eth1 wird «hugo», der 6RD-Tunnel konfiguriert.
Create your 6rd tunnel and bind it to your public IP:
# ip tunnel add hugo mode sit local 172.20.121.122 ttl 64
Add your provider's 6RD prefix to the tunnel:
# ip tunnel 6rd dev hugo 6rd-prefix 2a02:1200::/28
Assign an IPv6 address to the tunnel link:
# ip -6 addr add 2a02:120a:c147:97a1::1/28
Bring your link up:
# ip link set hugo up
# ip link show hugo
Add a route to direct outgoing IPv6 traffic into the tunnel:
# ip -6 route add 2000::/3 via ::193.5.29.1 dev hugo
|
|
Die so erstellte IPv6 Verbindung testen mittels:
# ping6 ipv6.google.com
# traceroute6 ipv6.google.com
https://test-ipv6.com/
|
|
Den internen Maschinen manuell oder mittels radvd und router-solicitation
ihre UGAs und default Routen zuweisen. Beispiel:
# ifconfig eth0 inet6 add 2a02:120a:c147:97a3::2/64 -> first host in network 3 connected to eth3
# ip -6 route add 2000::/3 via 2a02:120a:c147:97a3::1 dev eth0 -> route to global IPv6 addresses
|
|
Falls der Internet Service Provider «native» IPv6 zur Verfügung stellt,
IPv6 Pakete also nicht in IPv4 einzupacken sind, sollte sich die IPv6 Anbindung
einfacher gestalten. Unter der Annahme, dass Linuxrouter via eth1 mit dem WAN verbunden
ist, und die öffentliche IP mittels DHCP bezogen wird, wird der Router beim Booten
für eth1:
-Per DHCP Client seine IPv4 Adresse konfigurieren.
-Mittels SLAAC eine fe80 Adress generieren.
-Mittels SLAAC/router-solicitation eine «Scope:Global» IPv6 Adresse zuweisen. (*)
Die IPv6 Verbindung zum Provider ist damit im Prinzip gegeben. Was noch fehlt sind
die GUAs (Global Unicast Address) für die LANs. Diese werden mittels
«Prefix Delegation» generiert. PD ist ein Verfahren, mit dem der Internet
Service Provider seinen Kunden einen global einmaligen IPv6 Präfix aus seinem
Address-Pool zur Verfügung stellt (für eine vertiefte Diskussion siehe
ipv6_prefix_delegation).
Basierend auf diesem Präfix generiert der wide-dhcpv6c Daemon die
GUAs der internen Interfaces.
Die Konfiguration von wide-dhcpv6c erfolgt mittels
/etc/dhcpv6/dhcp6c.conf , der Start des Daemons erfolgt in
bewährter Slackware/BSD Manier mittels /etc/rc.d/rc.dhcp6c .
Die folgende Konfiguration weist eth0, eth2, eth3 je eine Unique Global Address
von folgender Form zu:
2001:xxxx:yyyy:zzz3::1/64 -> eth3
2001:xxxx:yyyy:zzz2::1/64 -> eth2
2001:xxxx:yyyy:zzz0::1/64 -> eth0
# /etc/dhcpv6/dhcp6c.conf
# wide-dhcpv6-20080615 client configuration file.
# For dhcp6c configuration options see:
# /usr/local/wide-dhcpv6/man/man5/dhcp6c.conf.5
# 2019-05-28
# Send a prefix delegation request via WAN interface to the ISP's pd server
interface eth1 {
send ia-pd 0;
};
# Assign Unique Global Addresses to eth3, eth2, eth0
id-assoc pd 0 {
prefix-interface eth3 {
sla-id 3; # Set your subnet address to :xxx3:
sla-len 8; # Subnet bits (provider uses /56 prefix )
ifid 1; # Configure eth3 as link ::1
};
prefix-interface eth2 {
sla-id 2;
sla-len 8;
ifid 1;
};
prefix-interface eth0 {
sla-id 0;
sla-len 8;
ifid 1;
};
};
|
|
Den internen Maschinen, manuell oder mittels radvd und router-solicitation
ihre UGAs zuweisen. Beispiel:
# ifconfig eth0 inet6 add 2001:xxxx:yyyy:zzz3::2/64 -> first host in network 3 connected to eth3
# ip -6 route add 2000::/3 via 2001:xxxx:yyyy:zzz3::1 -> route to global IPv6 addresses
|
|
*) BEACHTEN: Eine Linux Maschine, die sich als Router fühlt, wird router-advertisements
ignorieren. Dies ist nachvollziehbar, denn eine Service Maschine wie ein Router sollte
manuell und statisch konfiguriert werden. Im vorliegenden Fall ist dieses Verhalten
jedoch nicht erwünscht.
Der Kernel sieht sich dann als Router, wenn ip_forward aktiviert
ist - was bei Linuxrouter aus naheliegenden Gründen gegeben ist.
Um das Default-Verhalten des Kernels zu übersteuern, muss für Kernel >=2.6.37
der Kernel-Parameter accept_ra für eth1 auf den Wert
2 gesetzt werden (vorzugsweise im Firewall Script nachdem ip_forward=1
gesetzt wurde). Ohne diesen Eintrag wird SLAAC für das WAN Interface eth1 fehlschlagen
und IPv6 wird nicht funktionieren.
echo 2 > /proc/sys/net/ipv6/conf/eth1/accept_ra
|
|
Der grundsätzliche Aufbau eines Firewalls für IPv6 Pakete unterscheidet
sich nicht von IPv4:
-Alle Verbindungen per Default-Regeln unterbinden.
-Überlegen, welche Verbindungen benötigt werden.
-Diese zulassen.
Da lokale IPv6 Hosts über globale, eindeutige, «routable» IPs
verfügen, entfallen Hilfskonstrukte wie NAT oder Port Forwarding, was das
Firewall Script übersichtlicher macht. («stateful»
Paket-Filter-Regeln sind selbstverständlich nach wie vor möglich.)
NAT wurde bekanntermassen nie als Security-Feature konzipiert, hat aber trotzdem
eine gewisse Trennung zwischen Internet und LAN bewirkt. Mit IPv6 entfällt diese
Trennung. IPv6 IPs sind im Internet bekannt und werden von den Routern weitergeleitet.
Wenn ein IPv4 Firewall Script nicht ordnungsgemäss zu Ende läuft, wird der
Administrator oder User dies bemerken, weil Verbindungsversuche ins Internet fehlschlagen.
Mit IPv6 ist dies nicht notwendigerweise der Fall, und es ist möglich, dass ein LAN
ohne Firewall-Schutz mit dem Internet verbunden wird. Es ist daher empfehlenswert
ip_forward erst am Schluss des Firewall-Scripts zu aktivieren - was
auch bei einem IPv4-Firewall kein schlechtes Vorgehen sein dürfte!
Der grösste Unterschied zu IPv4 betrifft ICMP. Pings haben unter IPv6 eine
wichtige Rolle, und einige Typen müssen zwingend zugelassen werden, ansonsten
das IPv6 Netzwerk nicht funktionieren wird. Eine ICMPv6 Parameterliste wird von
ICMPv6
bereitgestellt.
Ein IPv6 Referenz-Firewall-Script ist auf
cert_firewall
verfügbar. Es handelt sich allerdings um einen Vorschlag für eine LAN-Maschine
und nicht für einen Router. Das Script kann aber angepasst werden und ist als Referenz
für den ersten Wurf eines Router-Scripts sehr hilfreich, denn - wie der folgende Abschnitt
zeigt - ist ICMPv6 nicht unkomplex!
Beispiel für die ICMPv6 Regeln eine Router-Firewalls:
#
# ===========================================================================
# RULES FOR ICMPV6
# ===========================================================================
#
# ---------------------------------------------------------------------------
# Allow incoming and outgoing ICMPv6 packets from the Internet to the router
# ---------------------------------------------------------------------------
#
# Allow mandatory ICMPv6 types in the INPUT and OUTPUT chains.
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type destination-unreachable -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type packet-too-big -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type time-exceeded -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type parameter-problem -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type destination-unreachable -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type packet-too-big -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type time-exceeded -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type parameter-problem -j ACCEPT
# Accept multicast listener messages.
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type 130 -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type 131 -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type 132 -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type 130 -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type 131 -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type 132 -j ACCEPT
# Allow router-solicitation and NDP (Neigbour Discovery Protocol)
# between Linuxrouter and ISP.
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type router-solicitation -j REJECT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type router-advertisement -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type neighbor-solicitation -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type neighbor-advertisement -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type router-solicitation -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type router-advertisement -j REJECT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type neighbor-solicitation -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type neighbor-advertisement -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type redirect -j REJECT
# Allow router-solicitation from internal hosts (Linuxrouter running radvd).
${IP6TABLES} -A INPUT -p ICMPV6 -i ${INT} --icmpv6-type router-solicitation -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${INT} --icmpv6-type router-advertisement -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${DMZ1} --icmpv6-type router-solicitation -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${DMZ1} --icmpv6-type router-advertisement -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${DMZ2} --icmpv6-type router-solicitation -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${DMZ2} --icmpv6-type router-advertisement -j ACCEPT
# Allow incoming pings to the router.
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type echo-request -j ACCEPT
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type echo-reply -j ACCEPT
# Allow outgoing pings from the router.
${IP6TABLES} -A OUTPUT -p ICMPV6 -o ${EXT6} --icmpv6-type echo-request -j ACCEPT
${IP6TABLES} -A INPUT -p ICMPV6 -i ${EXT6} --icmpv6-type echo-reply -j ACCEPT
# Drop all other ICMPv6 types.
${IP6TABLES} -A INPUT -p ICMPV6 -j DROP
${IP6TABLES} -A OUTPUT -p ICMPV6 -j DROP
# Set ICMPv6 FORWARD rules as appropriate.
# ...
|
|
ipv6_security.pdf
diskutiert das Thema «IPv6 Security» im Detail und enthält zahlreiche
Hinweise, die im IPv6 Firewall-Script berücksichtigt werden können.
|