Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize Ipv6Addr::is_unique_local and Ipv6Addr::is_unicast_link_local #129238

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

umgefahren
Copy link

Make Ipv6Addr::is_unique_local and Ipv6Addr::is_unicast_link_local stable (+const).

Newly stable API:

impl Ipv6Addr {
	// Newly stable under `ipv6_is_unique_local`
	const fn is_unique_local(&self) -> bool;

	// Newly stable under `ipv6_is_unique_local`
	const fn is_unicast_link_local(&self) -> bool;
}

These stabilise a subset of the following tracking issue:

I have looked and could not find any issues with is_unique_local and is_unicast_link_local. There is a well received comment calling for stabilisation of the latter function.

Both functions are well defined and consistent with implementations in other languages:

cc implementor @little-dude
(I can't find the original PR for is_unqiue_local)

r? libs-api
@rustbot label +T-libs-api +needs-fcp

@rustbot
Copy link
Collaborator

rustbot commented Aug 18, 2024

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @joshtriplett (or someone else) some time within the next two weeks.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. needs-fcp This change is insta-stable, so needs a completed FCP to proceed. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Aug 18, 2024
@umgefahren
Copy link
Author

umgefahren commented Aug 18, 2024

r? dtolnay

Since @dtolnay reviewed the last stabilisation PR in this domain.

@rustbot
Copy link
Collaborator

rustbot commented Aug 18, 2024

Failed to set assignee to dtolney: invalid assignee

Note: Only org members with at least the repository "read" role, users with write permissions, or people who have commented on the PR may be assigned.

@rustbot rustbot assigned dtolnay and unassigned joshtriplett Aug 18, 2024
@dtolnay dtolnay removed the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Aug 19, 2024
@dtolnay
Copy link
Member

dtolnay commented Aug 19, 2024

Both functions are well defined and consistent with implementations in other languages:

  • Go

This one isn't entirely true. (I didn't try any of the other languages.)

Rust: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6770cd0cf0a2e5439580dfaf5bf41471

#![feature(ip)]

fn main() {
    let ip = std::net::Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 169, 254, 0, 0]);
    println!("{} {}", ip, ip.is_unicast_link_local());
}
::ffff:169.254.0.0 false

Go: https://go.dev/play/p/b4E92eet5Yg

package main

import (
    "fmt"
    "net/netip"
)

func main() {
    ip := netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 169, 254, 0, 0})
    fmt.Println(ip, ip.IsLinkLocalUnicast())
}
::ffff:169.254.0.0 true

The difference comes down to this "not assigned any special meaning", which is not the case in Go:

/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined:
/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated.
///
/// Both types of addresses are not assigned any special meaning by this implementation,
/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`,
/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is.
/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address.

@dtolnay
Copy link
Member

dtolnay commented Aug 19, 2024

@rust-lang/libs-api:
@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Aug 19, 2024

Team member @dtolnay has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Aug 19, 2024
@tgross35
Copy link
Contributor

Is is_unicast_global worth including as part of the unicast family?

These methods, along with similar unstabilized ones, have unfortunately had a pretty rough time getting finalized. I added unresolved questions to the tracking issue at #27709 to list some of these concerns. Most relevant here:

There is a tool designed to check our IP methods against those from other languages, could you try to run it to see where we stand? https://github.com/rust-lang/libs-team/tree/main/tools/ipcheck?

(I can't find the original PR for is_unqiue_local)

It predates rust 1 :) #22015 also typo unqiue/unique if you were searching for that exact string.

@umgefahren
Copy link
Author

umgefahren commented Oct 2, 2024

I ran the ipcheck tool, some of my changes I applied can be seen in my PR: rust-lang/libs-team#454

Complete output of a run

Found Rust implementation.
Found .NET implementation.
Found Go implementation.
Found Java implementation.

addr .NET Go Java
0.0.0.0 ✔️ ✔️ ✔️
0.1.2.3 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
1.1.1.1 ✔️ ✔️ ✔️
127.0.0.1 ✔️ ✔️ ✔️
255.255.255.255 ✔️ ✔️ ✔️
10.0.0.1 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
16.89.10.65 ✔️ ✔️ ✔️
45.22.13.197 ✔️ ✔️ ✔️
100.64.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
100.128.0.0 ✔️ ✔️ ✔️
169.254.0.0 ✔️ ✔️ ✔️
172.16.10.10 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.7 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.8 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.9 ✔️ ✔️ ✔️
192.0.0.10 ✔️ ✔️ ✔️
192.0.0.169 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.170 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.171 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.172 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.0.255 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.0.2.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.31.196.2 ✔️ ✔️ ✔️
192.52.193.2 ✔️ ✔️ ✔️
192.88.99.2 ✔️ ✔️ ✔️
192.168.0.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
192.175.48.2 ✔️ ✔️ ✔️
198.18.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
198.51.100.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
203.0.113.6 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
240.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
255.255.255.254 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:0.0.0.0 ✔️ { is_unspecified : false (Rust) ≠ true (Go) } ✔️
::ffff:0.1.2.3 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:1.1.1.1 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:127.0.0.1 { is_loopback : false (Rust) ≠ true (.NET) } { is_loopback : false (Rust) ≠ true (Go) } { is_loopback : false (Rust) ≠ true (Java) }
::ffff:255.255.255.255 ✔️ ✔️ ✔️
::ffff:10.0.0.1 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:16.89.10.65 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:45.22.13.197 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:100.64.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:100.128.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:169.254.0.0 ✔️ { is_unicast_link_local : false (Rust) ≠ true (Go) } ✔️
::ffff:172.16.10.10 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.7 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.8 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.9 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.10 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.169 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.170 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.171 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.172 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.0.255 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.0.2.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.31.196.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.52.193.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.88.99.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.168.0.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:192.175.48.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:198.18.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:198.51.100.2 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:203.0.113.6 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:240.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::ffff:255.255.255.254 ✔️ { is_global : false (Rust) ≠ true (Go) } ✔️
::1 ✔️ ✔️ ✔️
:: ✔️ ✔️ ✔️
64:ff9b:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } ✔️ ✔️
64:ff9b:1:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
100:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2001:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2001:1::1 { to_ipv4 : null (Rust) ≠ "0.0.0.1" (.NET) } ✔️ ✔️
2001:1::2 { to_ipv4 : null (Rust) ≠ "0.0.0.2" (.NET) } ✔️ ✔️
2001:2:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2001:0002:6c::430 { to_ipv4 : null (Rust) ≠ "0.0.4.48" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2001:3:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } ✔️ ✔️
2001:4:112:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } ✔️ ✔️
2001:10:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2001:10:240:ab::a { to_ipv4 : null (Rust) ≠ "0.0.0.10" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2001:20:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } ✔️ ✔️
2001:30:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } ✔️ ✔️
2001:db8:8:4::2 { to_ipv4 : null (Rust) ≠ "0.0.0.2" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2002:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2002:cb0a:3cdd:1::1 { to_ipv4 : null (Rust) ≠ "0.0.0.1" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
2620:4f:8000:: { to_ipv4 : null (Rust) ≠ "0.0.0.0" (.NET) } ✔️ ✔️
fdf8:f53b:82e4::53 { to_ipv4 : null (Rust) ≠ "0.0.0.83" (.NET) } { is_global : false (Rust) ≠ true (Go) } ✔️
fe80::200:5aee:feaa:20a2 { to_ipv4 : null (Rust) ≠ "254.170.32.162" (.NET) } ✔️ ✔️
ff01:0:0:0:0:0:0:2 { to_ipv4 : null (Rust) ≠ "0.0.0.2" (.NET) } { is_global : true (Rust) ≠ false (Go) } ✔️

Operations with only a Rust implementation:

  • is_benchmarking
  • is_documentation
  • is_reserved
  • is_shared
  • is_unique_local
  • mc_scope_admin_local
  • mc_scope_realm_local
  • mc_scope_reserved
  • mc_scope_unassigned

Summary

As far as I can see the difference in output in is_loopback and is_unicast_link_local is a matter of opinion. They boil down to the differentiation of how IPv4 to IPv6 addresses are handled, as @dtolnay already pointed out: #129238 (comment)

However since Rust went a different way anyway in handling these cases, I would recon that we can assume Rust is compatible with other languages, however there exists a pitfall.

@umgefahren
Copy link
Author

I'm open to discussion here. If you want to see how it looks, I could include it in this.

@thvdveld
Copy link
Contributor

thvdveld commented Oct 8, 2024

I agree with @tgross35 that adding this would make it more consistent with Ipv6MulticastScope. I'd be in favour of adding this.

@tgross35
Copy link
Contributor

tgross35 commented Oct 8, 2024

@thvdveld do you have an idea how this should look? If so, that could be submitted as an ACP (or just put up a PR changing it)

@thvdveld
Copy link
Contributor

What I get from https://www.rfc-editor.org/rfc/rfc4291#section-2.5: there are only two scope types for unicast addresses: global unicast and link-local unicast. However, I think we could also add UniqueLocal, Unspecified, Benchmarking, Documentation, Loopback, but I'm not sure if those are really a scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. needs-fcp This change is insta-stable, so needs a completed FCP to proceed. proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants