Things you didn’t known about IPv6 link-local address

I regained interest in trying IPv6 at home since my ISP provides the option to switch to IPv6 (also some might say it’s not IPv6 to the end user as it is intended in IPv6 design documents). But before ticking the appropriate box on the router interface, I wanted to give a shot at serverless network configuration.

I’m running ftp, nfs, afp, ntp, http, smtp, imap and some other servers at home and as I have a couple of machines to run that on, I soon needed a dns and a ldap server for good measure. For reasons I won’t detail, I wanted to give a shot at dns-less (bind) network but still keep name resolution with mdns (avahi, yay auto-discovery of services).

Now to get back to IPv6, I’ve seen MacOS X do a couple of things out of the box with link-local addresses and naive as I am at times, I thought GNU/Linux would do the same. I’ve had IPv6 enabled for a long time in my kernels but never managed to ping others machines without starting a dhcp v6 server (radvd). So digging a bit, I soon discovered that basic tools you find on a GNU/Linux system are useless with link-local address. Take ping6 for example, you want to ping a host you have the address of so you type:

$ ping6 fe80::21b:63ff:feab:e6a6
connect: Invalid argument

Meh ??? It’s a valid address, WTF is it telling me. Google to the rescue, you have to specify the network interface you want to use to send the packet. It’s ok ping6 has a -I parameter that allows you to select the one you want, and you also find that there is a weird syntax that allows you to do that inline:

$ ping6 -I eth0 fe80::21b:63ff:feab:e6a6
PING fe80::21b:63ff:feab:e6a6%eth0(fe80::21b:63ff:feab:e6a6) 56 data bytes
64 bytes from fe80::21b:63ff:feab:e6a6: icmp_seq=1 ttl=64 time=0.041 ms
$ ping6 fe80::21b:63ff:feab:e6a6%eth0
PING fe80::21b:63ff:feab:e6a6%eth0(fe80::21b:63ff:feab:e6a6) 56 data bytes
64 bytes from fe80::21b:63ff:feab:e6a6: icmp_seq=1 ttl=64 time=0.041 ms

You’re all happy now that you sent your first ping over IPv6, now since avahi tells the local world about this machine’s address, you want to try using it’s hostname:

$ ping6 -I eth0 shinobu.local
PING shinobu.local(shinobu.local) from fe80::21b:63ff:feab:e6a6 eth0: 56 data bytes
64 bytes from shinobu.local: icmp_seq=1 ttl=64 time=0.377 ms
$ ping6 shinobu.local%eth0
unknown host

Hu ho, what’s going on here. This post is getting way longer than I expected so let’s jump to the conclusion.

I have found no trick to make a program know about the network interface I want to use when using hostnames so if you want to use ssh or wget that don’t have a way to specify the network interface you’re screwed. Ho yes, there is a solution, you can write wrapper scripts that will resolve the address for you and rewrite the command with the address%iface format, but that’s crazy. Os X seems to do this just fine, how come free software can’t ? (this is a rethorical question in case you wonder).

Finally, having a dhcp v6 server providing a global scope address solves these issues but to the cost of having a device to run it on. A device you depend on and that must be online all the time. Say good bye to auto-discovery, etc on your network.