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

Remove Ipv6Addr::is_unicast_link_local_strict #85819

Merged
merged 1 commit into from
May 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 25 additions & 85 deletions library/std/src/net/ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1267,79 +1267,31 @@ impl Ipv6Addr {
(self.segments()[0] & 0xfe00) == 0xfc00
}

/// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
/// Returns `true` if the address is a unicast address with link-local scope,
/// as defined in [RFC 4291].
///
/// A common misconception is to think that "unicast link-local addresses start with
/// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
/// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
/// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
/// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
///
/// ```no_rust
/// | 10 |
/// | bits | 54 bits | 64 bits |
/// ```text
/// | 10 bits | 54 bits | 64 bits |
/// +----------+-------------------------+----------------------------+
/// |1111111010| 0 | interface ID |
/// +----------+-------------------------+----------------------------+
/// ```
/// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
/// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
/// and those addresses will have link-local scope.
///
/// This method validates the format defined in the RFC and won't recognize addresses
/// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
/// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
///
/// # Examples
///
/// ```
/// #![feature(ip)]
///
/// use std::net::Ipv6Addr;
///
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
/// assert!(ip.is_unicast_link_local_strict());
///
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
/// assert!(ip.is_unicast_link_local_strict());
///
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
/// assert!(!ip.is_unicast_link_local_strict());
/// assert!(ip.is_unicast_link_local());
///
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
/// assert!(!ip.is_unicast_link_local_strict());
/// assert!(ip.is_unicast_link_local());
/// ```
///
/// # See also
///
/// - [IETF RFC 4291 section 2.5.6]
/// - [RFC 4291 errata 4406] (which has been rejected but provides useful
/// insight)
/// - [`Ipv6Addr::is_unicast_link_local()`]
///
/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
/// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_link_local_strict(&self) -> bool {
matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
}

/// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
/// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
/// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
///
/// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
/// i.e. addresses with the following format:
///
/// ```no_rust
/// | 10 |
/// | bits | 54 bits | 64 bits |
/// +----------+-------------------------+----------------------------+
/// |1111111010| arbitratry value | interface ID |
/// +----------+-------------------------+----------------------------+
/// ```
///
/// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
/// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
/// If you need a strict validation fully compliant with the RFC, use
/// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
/// [RFC 4291]: https://tools.ietf.org/html/rfc4291
/// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
/// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
/// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
/// [loopback address]: Ipv6Addr::LOCALHOST
///
/// # Examples
///
Expand All @@ -1348,29 +1300,17 @@ impl Ipv6Addr {
///
/// use std::net::Ipv6Addr;
///
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
/// assert!(ip.is_unicast_link_local());
/// // The loopback address (`::1`) does not actually have link-local scope.
/// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
///
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
/// assert!(ip.is_unicast_link_local());
/// // Only addresses in `fe80::/10` have link-local scope.
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
///
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
/// assert!(ip.is_unicast_link_local());
/// assert!(!ip.is_unicast_link_local_strict());
///
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
/// assert!(ip.is_unicast_link_local());
/// assert!(!ip.is_unicast_link_local_strict());
/// // Addresses outside the stricter `fe80::/64` also have link-local scope.
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
/// ```
///
/// # See also
///
/// - [IETF RFC 4291 section 2.4]
/// - [RFC 4291 errata 4406] (which has been rejected but provides useful
/// insight)
///
/// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[inline]
Expand Down
18 changes: 2 additions & 16 deletions library/std/src/net/ip/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,6 @@ fn ipv6_properties() {
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
Comment on lines 482 to 483
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This thing with gaps ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bitset of which properties are true, one of the bits being unused shouldn't really matter. I think that is less invasive than renumbering all of them.

let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
Expand Down Expand Up @@ -524,11 +523,6 @@ fn ipv6_properties() {
} else {
assert!(!ip!($s).is_unicast_link_local());
}
if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
assert!(ip!($s).is_unicast_link_local_strict());
} else {
assert!(!ip!($s).is_unicast_link_local_strict());
}
if ($mask & unicast_site_local) == unicast_site_local {
assert!(ip!($s).is_unicast_site_local());
} else {
Expand Down Expand Up @@ -587,7 +581,6 @@ fn ipv6_properties() {
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
Expand Down Expand Up @@ -621,11 +614,7 @@ fn ipv6_properties() {
unicast_link_local
);

check!(
"fe80::",
&[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unicast_link_local | unicast_link_local_strict
);
check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);

check!(
"febf:ffff::",
Expand All @@ -650,7 +639,7 @@ fn ipv6_properties() {
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
],
unicast_link_local | unicast_link_local_strict
unicast_link_local
);

check!(
Expand Down Expand Up @@ -897,9 +886,6 @@ fn ipv6_const() {
const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
assert!(!IS_UNIQUE_LOCAL);

const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict();
assert!(!IS_UNICAST_LINK_LOCAL_STRICT);

const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
assert!(!IS_UNICAST_LINK_LOCAL);

Expand Down