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).
I think the answer is very obvious here: Debug should not omit fields. serde should not skip fields. Which means that there needs to be a way to put flowinfo into textual representation. Since there are already incompatibilities in how ipv6 addresses are handled ("%enp4s0f0" is supported by ping but not by Rust), might as well make something up, like "1234::5678%9-Q0x42". Tools like "ping" accept "-Q 0x42" option already, so most network engineers would be able to guess what does "-Q0x42" tacked to the end of address means.
Since this is backward-compatible when QoS is not set, I'd just change Display to emit it. But I am guessing some people may complain, so special implementation for Debug would work too...
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/
Thanks. At Oxide we do use the scope ID quite a bit, as my colleague Cliff Biffle says here: https://hachyderm.io/@cliffle/115492946627058792
It's sad that the only other loopback v6's appear to be v4's /8 in the form mapped into a slice of v7 address space
You can use ::ffff:127.0.0.2 for most purposes, but you can't ping it.
> you can't ping it
WTF?..
(My Linux machine can, but I’ve no clue if I should trust that now.)
Hm, it has always failed for me on Debian.
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).
I think the answer is very obvious here: Debug should not omit fields. serde should not skip fields. Which means that there needs to be a way to put flowinfo into textual representation. Since there are already incompatibilities in how ipv6 addresses are handled ("%enp4s0f0" is supported by ping but not by Rust), might as well make something up, like "1234::5678%9-Q0x42". Tools like "ping" accept "-Q 0x42" option already, so most network engineers would be able to guess what does "-Q0x42" tacked to the end of address means.
Since this is backward-compatible when QoS is not set, I'd just change Display to emit it. But I am guessing some people may complain, so special implementation for Debug would work too...
Thanks, referred to your comment here: https://github.com/rust-lang/rust/issues/148546#issuecomment...
Another day, another reason ipv6 should have been ipv4 with more bits.
Has anyone done a piece a Second System Syndrome and IPv6? (Surely?)