Some time ago I was porting a piece of IPv6-only network software from Linux to OpenBSD.
This post is to explain the caveats of using
struct sockaddr_in6 and its member
It turns out, OpenBSD does not play too well with
sin6_scope_id and uses a rather odd method of populating the scope ID to user space.
Linux and sin6_scope
Let’s start with Linux and have a look at the documentation first.
struct sockaddr_in6 and its members are described in
manual page ipv6(7) on Linux as follows:
sin6_scope_id is an ID depending on the scope of the address. It is new in Linux 2.4. Linux supports it only for link-local addresses, in that case sin6_scope_id contains the interface index.
struct sockaddr_in6 looks like this:
The scope ID is a 32 bit unsigned integer. It populates the interface index which is equivalent to the scope ID.
For the first example let’s assume we have an interface with ID 3 and a link-local address of
How about we fetch the link-local address of that interface?
Even though it is not the best way to do it, for the sake of argument let’s say we use
struct sockaddr_in6 to accomplish this.
We ask the kernel to fill the struct for us and this is what we get back in response:
fe80::1(as raw data)
No surprises here, right? Our software can safely rely on the contents of
struct sockaddr_in6. Hooray!
OpenBSD and sin6_scope
On OpenBSD the same approach requires more attention from a software-porting developer.
Let’s have a look at the documentation first, shall we?
struct sockaddr_in6 on manual page inet6 of section 4 (drivers).
Not quite were I expected it, but still a good place.
First thing that pops out is that on OpenBSD,
struct sockaddr_in6 has an additional member
This make its use more versatile. It is irrelevant for the next example, though.
However, despite of that the struct looks pretty much the same.
Back to our software: Once again we ask the kernel to fill the struct for us and here is what we get back:
fe80:3::1(as raw data)
Wait. What? Yes, this can give you a headache when you encounter this for the first time. At least it gave me one.
The OpenBSD kernel, for some odd reason, does not make use of
sin6_scope_id but rather squishes the interface ID in the second group of the link-local IPv6 address.
That is just ugly!
Is this a stupid bug, then?
Well, I’d say it is an ugly bug, but it is neither stupid nor doomed to fail. Technically, it is safe to store the scope ID in the address. However, developers porting software need to be aware of that and clean up the link-local address before using it. You would not want to use it in user space or present the address to a regular user without extracting the scope ID first.
Some people pointed out that this behavior does not go well with link-local addresses like
the space of
fe80::/10 for link-scoped unicast addresses, but only
fe80::/64 must be used for actual link-local addresses.
Section 2.5.6 of RFC 4291 IP Version 6 Addressing Architecture clearly states this little known constraint to
Link-Local addresses are for use on a single link. Link-Local addresses have the following format: | 10 | | bits | 54 bits | 64 bits | +----------+-------------------------+----------------------------+ |1111111010| 0 | interface ID | +----------+-------------------------+----------------------------+
Feel free to add your comments!