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.

5 thoughts on “Things you didn’t known about IPv6 link-local address”

  1. it’s perfectly normal and perfectly standard behavior.

    the thing is, linux machine can have multiple ipv6 interfaces, and every of them has fe80::/8 prefix. so to know which one of fe80::/8 you want to ping you must specify interface (for example ping -I fe80::1) or to use “interface scope”, for example ping fe80::1%eth0 (the string after % is interface name or id). Interface scoping is also standard thing, and you can see this on other operating systems.

    1. I know that after searches I’ve done before writing this post. The problem is not that this is standard, it is that applications do not “just work” like they do for IPv4.
      Anyway I’m not arguing about technical merits of the spec or how Linux is doing it, I’m simply venting off frustation for things being so complicated when they should not be.

  2. Linklocal addresses aren’t meant to be used for hostnames just for routing purposes and contacting your neighbours so you can determine which link they responded to although you only have one real ip.

  3. Bonjour/Zerconf knows the interface that a link-local device was discovered on. A client program should use this information to know which interface to use to make the outgoing connection.

    It works on mac osx, see ping6 figures out to use %en1:

    jdks-mbp13:~ jeffk$ ping6 jdks-mbp15.local.
    PING6(56=40+8+8 bytes) fe80::daa2:5eff:fe98:a207%en1 --> fe80::21f:5bff:fecf:1f44%en1
    

    It does work on linux with ipv4 (non-link local addresses):

    jeffk@ada:~$ ping jdks-mbp15.local.
    PING jdks-mbp15.local. (192.168.147.197) 56(84) bytes of data.
    64 bytes from jdks-mbp15.local (192.168.147.197): icmp_seq=1 ttl=64 time=312 ms

    But it does not work on a linux client for ipv6 with ipv6 link-local addresses:

    jeffk@ada:~$ ping6 jdks-mbp15.local.
    unknown host
    

    In my opinion the Linux client is broken. ssh is as well. This is a problem for ipv6 only networks that do not have ipv4 enabled, which is what my requirements are.

    Regards,
    Jeff Koftinoff

  4. Oh, and to clarify, the linux device can ping the raw ipv6 address with scope id manually, just can’t utilize zeroconf for ipv6 at all:

    jeffk@ada:~$ ping6 fe80::21f:5bff:fecf:1f44%wlan0
    PING fe80::21f:5bff:fecf:1f44%wlan0(fe80::21f:5bff:fecf:1f44) 56 data bytes
    64 bytes from fe80::21f:5bff:fecf:1f44: icmp_seq=1 ttl=64 time=149 ms
    64 bytes from fe80::21f:5bff:fecf:1f44: icmp_seq=2 ttl=64 time=1.85 ms
    ^C
    

Comments are closed.