Today I found that fetching my mail with getmail would take two minutes. Two full minutes. Then I tried to SSH into my server and .. waited for two minutes.
When forcing SSH to use IPv4 (ssh -4 ...), I got an connection immediately. Pinging my server also showed different behavior on IPv4 and IPv6: ping -4 cweiske.de would work fine, ping -6 cweiske.de had 100% packet loss.
Network setup
IPv4
My home network is easy on the IPv4 side:
|Home server| <--> |Router| <--> |Internet| | | <--[DHCP]-----> | | +------+ +--------+ | | <--[DNS]------> | | +------+ +-----------+]]>
The home server forwards packets to the router, and is also responsible for DHCP.
IPv6
With IPv6, things got complicated:
|Home server| <--> |Router| <--> |Internet| | | <--[DNS]--------> | | | | +--------+ | | +-----------+ | | | | <--[global SLAAC]------------------> | | | | <--[Packets]-----------------------> | | +------+ +------+ ]]>
-
The router knows about the IPv6 prefix allocated to me for today and thus needs to
hand out global IPv6 addressesdistribute it to all machines. -
I need an additional stable IPv6 address for every device, because my provider-allotted IPv6 prefix changes every day, which causes the IPv6 addresses of all devices to change daily. This breaks any hostname-to-IP-mappings in /etc/hosts and the local DNS server. So I let my home server hand out the prefix for this Unique Local Addresses.
-
DNS for IPv6 is still handled by my home server, because only then I can provide names like addressbook.home.cweiske.de.
-
The home server may not forward packets for IPv6, because otherwise it will not listen for SLAAC prefix announcements from other routers:
/etc/sysctl.conf# Uncomment the next line to enable packet forwarding for IPv6 # Enabling this option disables Stateless Address Autoconfiguration # based on Router Advertisements for this host #net.ipv6.conf.all.forwarding=1
So for IPv6, the router is the only one who may actually route IP packets.
Routing
Back to my problem: I looked at my laptop's routing table and saw this:
$ route -6n Kernel-IPv6-Routentabelle Destination Next Hop Flag Met Ref Use If ::1/128 :: U 256 2 0 lo 2003:d9:ebc4:9400::/64 :: U 600 1 0 wlp1s0 2003:d9:ebc4:9400::/56 fe80::5e49:79ff:fe3b:b1de UG 600 1 0 wlp1s0 fdc3:e153::/64 :: U 600 1 0 wlp1s0 fe80::/64 :: U 600 2 0 wlp1s0 ::/0 fe80::d250:99ff:fe2c:f8c8 UG 600 1 0 wlp1s0 ::/0 fe80::5e49:79ff:fe3b:b1de UG 600 1 0 wlp1s0 ::1/128 :: Un 0 7 0 lo 2003:d9:ebc4:9400:1acf:5eff:fed7:c3bc/128 :: Un 0 2 0 wlp1s0 2003:d9:ebc4:9400:d4f2:9d24:a70e:82c8/128 :: Un 0 3 0 wlp1s0 fdc3:e153::1acf:5eff:fed7:c3bc/128 :: Un 0 2 0 wlp1s0 fe80::1acf:5eff:fed7:c3bc/128 :: Un 0 3 0 wlp1s0 ff00::/8 :: U 256 7 0 wlp1s0 ::/0 :: !n -1 1 0 lo
There were two routes for internet addresses, one to ..:f8c8, which is my home server, and one for ..:b1de, which is the router.
The problem was clearly visible now: My laptop sent IPv6 packets to my home server, which does not forward them, and never gets a response. After two minutes, it falls back to IPv4 and that works.
Wireshark
So my home server said that clients should route packets through it. I used the priceless Wireshark to inspect the SLAAC Router Advertisement packets:
Internet Protocol Version 6, Src: fe80::d250:99ff:fe2c:f8c8, Dst: fe80::1acf:5eff:fed7:c3bc Internet Control Message Protocol v6 Type: Router Advertisement (134) Code: 0 Checksum: 0x07e6 [correct] [Checksum Status: Good] Cur hop limit: 64 Flags: 0x00, Prf (Default Router Preference): Medium Router lifetime (s): 1800 Reachable time (ms): 0 Retrans timer (ms): 0 ICMPv6 Option (Prefix information : fdc3:e153::/64) ICMPv6 Option (MTU : 1492) ICMPv6 Option (Source link-layer address : d0:50:99:2c:f8:c8) ICMPv6 Option (DNS Search List Option home.cweiske.de) ICMPv6 Option (Recursive DNS Server fdc3:e153::3)
Internet Protocol Version 6, Src: fe80::5e49:79ff:fe3b:b1de, Dst: ff02::1 Internet Control Message Protocol v6 Type: Router Advertisement (134) Code: 0 Checksum: 0x3df4 [correct] [Checksum Status: Good] Cur hop limit: 255 Flags: 0x00, Prf (Default Router Preference): Medium Router lifetime (s): 1800 Reachable time (ms): 0 Retrans timer (ms): 0 ICMPv6 Option (Prefix information : 2003:d9:ebc1:7000::/64) ICMPv6 Option (Prefix information : 2003:d9:ebc4:9400::/64) ICMPv6 Option (Recursive DNS Server fdc3:e153::3) ICMPv6 Option (MTU : 1492) ICMPv6 Option (Route Information : Medium ::/0) ICMPv6 Option (Route Information : Medium 2003:d9:ebc4:9400::/56) ICMPv6 Option (Source link-layer address : 5c:49:79:3b:b1:de)
I saw that the router actually had "Route Information" in its advertisements, but the home server did not - but my laptop still used it as router.
RFC 4861 shed light onto the issue:
- Router Lifetime
[...]
A Lifetime of 0 indicates that the router is not a default router and SHOULD NOT appear on the default router list.
So every machine sending out SLAAC router advertisements is automatically usable as a router, unless it sends a lifetime of zero.
dnsmasq
Now I had to configure the dnsmasq instance on my home server to set the routing life time to 0.
The dnsmasq man page tells us how:
--ra-param=<interface>,[mtu:<integer>|<interface>|off,][high,|low,]<ra-interval>[,<router lifetime>]
The lifetime of the route may be changed or set to zero, which allows a router to advertise prefixes but not a route via itself. --ra-param=eth0,0,0
After I had this set, wireshark showed me a
Router lifetime (s): 0
and the latop only had one catchall-route, and everything worked fine.