Unrelated to the article, but the scope ID in IPv6 addresses is super useful for the networking software I write.
The socket API for IPv4 requires a strange ceremony of calling if_nametoindex to map an interface name to an index then setting IP_BOUND_IF in order to bind a socket to a particular network interface. (Sorry, this only works on BSD and Mac OS; Linux instead uses SO_BINDTODEVICE for whatever reason).
When you don't supply a network interface, the OS "helpfully" guesses an interface, and that interface is usually the wrong one for multicast and broadcast packets.
I made a PXE boot server in Rust recently, and I lost at least 30 minutes of my time figuring out why DHCP responses wouldn't be receieved by an EFI client. The problem was that 255.255.255.255:68 is inherently ambiguous when multiple network interfaces exist.
In the case of the IPv6 API, you have to specify the interface up front (e.g. ff05::1:3%en0) or else you won't even be able to send a packet. I used to find this design tedious, but I prefer writing scope IDs explicitly in an address rather than having libc (or my own code) iterate over a linked list provided by the kernel to get an integer then supply that integer to a setsockopt (and remember that Linux has a quirk here).
Unrelated to the article, but the scope ID in IPv6 addresses is super useful for the networking software I write.
The socket API for IPv4 requires a strange ceremony of calling if_nametoindex to map an interface name to an index then setting IP_BOUND_IF in order to bind a socket to a particular network interface. (Sorry, this only works on BSD and Mac OS; Linux instead uses SO_BINDTODEVICE for whatever reason).
When you don't supply a network interface, the OS "helpfully" guesses an interface, and that interface is usually the wrong one for multicast and broadcast packets.
I made a PXE boot server in Rust recently, and I lost at least 30 minutes of my time figuring out why DHCP responses wouldn't be receieved by an EFI client. The problem was that 255.255.255.255:68 is inherently ambiguous when multiple network interfaces exist.
In the case of the IPv6 API, you have to specify the interface up front (e.g. ff05::1:3%en0) or else you won't even be able to send a packet. I used to find this design tedious, but I prefer writing scope IDs explicitly in an address rather than having libc (or my own code) iterate over a linked list provided by the kernel to get an integer then supply that integer to a setsockopt (and remember that Linux has a quirk here).
Falsehoods programmers think about addresses:
- parsing addresses is well defined (try parsing ::1%3)
- since 127.0.0.2 is on loopback, ::2 surely also would be
- interface number on Linux is unique
- unix domain socket names are zero-terminated (abstract are not)
- sin6_flowinfo matters (it doens;t unless you opt-in with setsockopt)
- sin6_scope_id matters (it doesn't unless on site-local range)
(I wonder if scope_id would work on ipv4-mapped-IPv6, but if I remember right I checked and it didn't)
- In ipv4, scope_id doesnt exist (true but it can be achieved by binding to interface)
and so on...
Years ago I tried to document all the quirks I knew about https://idea.popcount.org/2019-12-06-addressing/
You can use ::ffff:127.0.0.2 for most purposes, but you can't ping it.
Thanks. At Oxide we do use the scope ID quite a bit, as my colleague Cliff Biffle says here: https://hachyderm.io/@cliffle/115492946627058792
Another day, another reason ipv6 should have been ipv4 with more bits.