rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.38k stars 12.72k forks source link

IPv6 link-local address parsing & round-tripping #65976

Open raggi opened 5 years ago

raggi commented 5 years ago

Consider the following link local IPv6 sockaddr string:

[fe80::f03c:91ff:fedf:75ee%eth0]:8080

This address does not parse or round-trip: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b36d93fe7d2a8699397c6dfafa2a3edf

The output formatting also elides the scopeid, which means that printed addresses are not valid addresses - particularly on multi-homed devices, where the un-scoped address will not function.

I believe that the correct change here is to both parse scopeid's and to include non-zero scopeids in Display. I'm happy to implement this if that is agreeable? It would need to take a dependency on if_nametoindex and if_indextoname (POSIX, net/if.h) in order to function on most Unix style platforms.

erickt commented 5 years ago

Windows also has this api, although that doc instead recommends:

The if_nametoindex function is implemented for portability of applications with Unix environments, but the ConvertInterface functions are preferred. The if_nametoindex function can be replaced by a call to the ConvertInterfaceNameToLuidA function to convert the ANSI interface name to a NET_LUID followed by a call to the ConvertInterfaceLuidToIndex to convert the NET_LUID to the local interface index.

mkeeter commented 2 years ago

As another data point, I also ran into this recently and was surprised / confused.

Doing a quick survey of programs, I found ping6 works with the textual scope id, e.g. ping6 fe80::004:06ff:fe08:0a0c%en0, while Scapy does not.

MalloryA commented 1 year ago

The relevant RFC here seems to be RFC 4007 which shows both the interface indices and names:

             fe80::1234%1
             ff02::5678%5
             ff08::9abc%10
            fe80::1234%ne0
            ff02::5678%pvc1.3
            ff08::9abc%interface10

As it stands, Rust is not compliant with IETF specifications for IP addresses, which happens to be the exact situation cited by the std-dev-guide as a situation where it may be necessary to introduce a breaking change:

Behavioral changes to stable functions generally can't be accepted. [...] An exception is when a behavior is specified in an RFC (such as IETF specifications for IP addresses). If a behavioral change fixes non-conformance then it can be considered a bug fix. In these cases, @rust-lang/libs should still be pinged for input.

The struct is currently this:

pub struct SocketAddrV6 {
    ip: Ipv6Addr,
    port: u16,
    flowinfo: u32,
    scope_id: u32,
}

I suspect we could reduce the breakage by:

@rust-lang/libs - input please?

e-dant commented 5 months ago

I also stumbled into this recently. This would be really nice to have.