Hi, while debugging DHCPv6 issues on my router, I noticed that IPv6 messages generated on the router have the wrong source address.
Disclaimer, I replaced the actual IPv6 prefixes with random values. Call me stupid or overly cautious. Fake addresses start with
Here is the output of
ip -6 addr:
[snip] 3: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000 inet6 1234:4567:1111::1/60 scope global dynamic valid_lft 86222sec preferred_lft 3422sec inet6 fdec:69e6:7d50::1/60 scope global valid_lft forever preferred_lft forever inet6 fe80::f29f:c2ff:fe60:91e0/64 scope link valid_lft forever preferred_lft forever 5: eth0.2@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000 inet6 1234:4567:89ab:cdef:f29f:c2ff:fe60:91e1/64 scope global dynamic valid_lft 2591818sec preferred_lft 604618sec inet6 1234:4567:89ab:cdef:1559:813d:406f:6f4d/128 scope global dynamic valid_lft 86222sec preferred_lft 3422sec inet6 fe80::f29f:c2ff:fe60:91e1/64 scope link valid_lft forever preferred_lft forever
My ISP assigns
1234:4567:89ab:cdef/64 to the public router interface and passes
1234:4567:1111/48 down via DHCPv6-PD.
Now i capture the a ICMPv6 ping to ipv6.google.com issued on the router itself using wireshark on the router. The roundtrip looks like this:
43 173.811099 1234:4567:1111::1 2a00:1450:400a:802::200e ICMPv6 118 Echo (ping) request id=0x1a40, seq=1, hop limit=64 (reply in 44) 44 173.812327 2a00:1450:400a:802::200e 1234:4567:1111::1 ICMPv6 118 Echo (ping) reply id=0x1a40, seq=1, hop limit=55 (request in 43)
Notice how the source address is
1234:4567:1111::1. My ISP assigns
1234:4567:1111::/48 to me using DHCPv6-PD. But notice how the address is only assigned to
br-lan and not to
eth0.2. Clearly the ping paket left the router on
eth0.2 (in fact that was the only interface i pointed wireshark at). So i'd expect it to pick one of the addresses assigned to
eth0.2, some address in
The problem is not unique to ping pakets. DHCPv6 pakets to my ISP also are sent from an address from the DHCPv6-PD prefix and not from an address of the external interface. (My ISP says this might be the source of my DHCPv6 problems, but that is a different story).
After reading up on IPv6 source address selection, a surprisingly interesting and complicated topic, I confirmed that Linux should pick an address from the outgoing interface. So let's check the routing table for IPv6:
default from 1234:4567:89ab:cdef:1559:813d:406f:6f4d via fe80::ca9c:1dff:fe93:343f dev eth0.2 proto static metric 512 pref medium default from 1234:4567:89ab:cdef::/64 via fe80::ca9c:1dff:fe93:343f dev eth0.2 proto static metric 512 pref medium default from 1234:4567:1111::/48 via fe80::ca9c:1dff:fe93:343f dev eth0.2 proto static metric 512 pref medium 1234:4567:89ab:cdef::/64 dev eth0.2 proto static metric 256 pref medium 1234:4567:1111::/64 dev br-lan proto static metric 1024 pref medium [snip]
Woah...the default routes are gated using source rules.
Conclusion: in order to know my outgoing interface I have to know my source address, but to know the source address I have to know the outgoing interface.
Trying to fix it
Now, I tried to replace the 3 default route entries with just a single one:
default via fe80::ca9c:1dff:fe93:343f dev eth0.2 proto static metric 512 pref medium
When I retried the
ping -6 ipv6.google.com Wireshark would show:
259 1507.821756 1234:4567:89ab:cdef:f29f:c2ff:fe60:91e1 2a00:1450:400a:802::200e ICMPv6 118 Echo (ping) request id=0xc943, seq=0, hop limit=64 (reply in 260) 260 1507.822988 2a00:1450:400a:802::200e 1234:4567:89ab:cdef:f29f:c2ff:fe60:91e1 ICMPv6 118 Echo (ping) reply id=0xc943, seq=0, hop limit=55 (request in 259)
Notice how the source address is now actually from a prefix assigned to
- Can the observed behaviour be considered a bug?
- Why is OpenWrt using complicated source routes instead of a single default route?