3
votes

I have written some simple code that uses ioctl SIOCGIFCONF to query all network interfaces on a system and, using inet_ntop, return the textual representation of the address found. The odd thing is that when a link-local IPv6 address is discovered, the OSX version of the code appears to embed the scope within the address.

Here's a line from /sbin/ifconfig on OSX after autoconfiguring the interfaces (:

en1: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
        ether 00:17:f2:0b:52:73 
        inet6 fe80::217:f2ff:fe0b:5273%en1 prefixlen 64 scopeid 0x5 

and the IP address as returned by ioctl SIOCGIFCONF:

IPv6 addr: fe80:5::217:f2ff:fe0b:5273

It looks like the value for scope (5) was inserted immediately after fe80.

The same code on Linux returns the ipv6 address without any extra data.

Two questions occur to me: 1) Is it legitimate to write an ipv6 address like this? 2) Is the OSX behavior documented anywhere?

References please!

1
On most platforms inet_ntop and inet_pton do not support IPv6 zones, you must only use getnameinfo and getaddrinfo.Steve-o
Thanks, Steve, didn't know that. My question remains: should an IPv6 address have a zone info? Not mentioned in RFC4291 chapter 2.2. Text Representation of AddressesSpaceghost
Only link-local scope addresses, i.e. fe80:: prefixes.Steve-o

1 Answers

4
votes

I'm not sure about your second question, but as for your first question, yes, it is common to see IPv6 addresses which much be scoped (such as link-local addresses) written like this, but it is definitely not consistent across platforms. The reason is because a link-local address would be ambiguous without it.

My answer to this other question might be helpful.


Edit: I just realized the subtlety in this question. The BSD IPv6 stack internally stores the interface index in the 2nd 16-bit word of a link-local IPv6 address. This should never go out on the wire. It's actually a RFC violation, because link-local addresses are defined to have 0 bits in this area. (which is, incidentally, why they can get away with storing extra information here) I believe this is a bug, and the scope should really be communicated to the rest of the system in some other way. So you should probably check for it and strip it out by hand.


Edit 2: I went and dug up the place in the kernel source where they set this value:

  466 static int
  467 in6_ifattach_linklocal(
  468         struct ifnet *ifp,
  469         struct ifnet *altifp,   /* secondary EUI64 source */
  470         struct in6_aliasreq *ifra_passed)
  471 {
      ...
  494                 ifra.ifra_addr.sin6_family = AF_INET6;
  495                 ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
  496                 ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
  497 #if SCOPEDROUTING
  498                 ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0
  499 #else
  500                 ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */
  501 #endif

Note the /* XXX */ on line 500. ;-) My guess is that this was some sort of temporary workaround/hack to get routing to work correctly without rewriting parts of the routing code. With link-local addresses you would need to make routing decisions based on the source and destination interfaces. By putting the if_index at that place in the address, they can probably just do a longest prefix match on the 128-bit address alone rather than relying on some kind of metadata.