Handle RFC 4007: IPv6 zone indices for link-local scoped addresses
Source: https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses
I had a use for this in SSH forwarding, and wondered if the OCaml SSH stack would be able to support this at some point, so I tried:
utop # Ipaddr.V6.of_string "fe80::1234:5678:9012%em0";;
- : Ipaddr.V6.t option = None
Relevant RFC: RFC 4007 section 6
An implementation SHOULD support at least numerical indices that are non-negative decimal integers as <zone_id>. The default zone index, which should typically be 0 (see Section 6), is included in the integers. When <zone_id> is the default, the delimiter characters "%" and <zone_id> can be omitted. Similarly, if a textual representation of an IPv6 address is given without a zone index, it should be interpreted as
%<default ID>, where <default ID> is the default zone index of the scope that has.
So we should support things like fe80::1%0.
RFC 4007 continues:
An implementation MAY support other kinds of non-null strings as <zone_id>. However, the strings must not conflict with the delimiter character. The precise format and semantics of additional strings is implementation dependent.
In Linux and BSD it seems like the IP stacks (or socket libraries or whatever) accept strings to specify the network interface, like %wifi0, or at least provides a way to resolve the numeric ID from the string automatically. This seems more useful than the numerical ID to me, but that is not compatible with Windows (where you would have to look up the interface).
FreeBSD also accepts stuff like fe80::123:4567:8910:1112%lagg0.1181 (for if lagg0 vlan 1181).
(Thanks a lot to @tykling for helping explain the use of % and for providing FreeBSD examples)
-
I'm not sure what the best way to expose these zone ID hints would be, but for starters I think it would be nice to simply strip trailing
%..*and parse the vanilla IPv6 address. -
Reading wikipedia, addresses this range should support zone indices:
fe80::/10
- Reading RFC 3513 section 2.7 I interpret it to extend to the "transient local" multicast addresses in this range too (please correct me if I got the CIDR prefix wrong):
ff12::/16
Some test cases:
fe80::1ff:fe23:4567:890a%0
fe80::1%em0
fe80::1ff:fe23:4567:890a%123
ff12::ff00:fe23:4567:890a%10
fe80::123:4567:8910:1112%lagg0.1181
(this was not fixed in 2.9.0 / #13141 , I believe that was a typo in the issue ID there)
It looks like the Unix module doesn't support this either: https://github.com/ocaml/ocaml/issues/6479