Skip to content

Commit dc08641

Browse files
committed
Auto merge of #85819 - CDirkx:is_unicast_link_local_strict, r=joshtriplett
Remove `Ipv6Addr::is_unicast_link_local_strict` Removes the unstable method `Ipv6Addr::is_unicast_link_local_strict` and keeps the behaviour of `Ipv6Addr::is_unicast_link_local`, see also #85604 where I have tried to summarize related discussion so far. My intent is for `is_unicast_link_local`, `is_unicast_site_local` and `is_unicast_global` to have the semantics of checking if an address has Link-Local, Site-Local or Global scope, see also #85696 which changes the behaviour of `is_unicast_global` and renames these methods to `has_unicast_XXX_scope` to reflect this. For checking Link-Local scope we currently have two methods: `is_unicast_link_local` and `is_unicast_link_local_strict`. This is because of what appears to be conflicting definitions in [IETF RFC 4291](https://datatracker.ietf.org/doc/html/rfc4291). From [IETF RFC 4291 section 2.4](https://datatracker.ietf.org/doc/html/rfc4291#section-2.4): "Link-Local unicast" (`FE80::/10`) ```text Address type Binary prefix IPv6 notation Section ------------ ------------- ------------- ------- Unspecified 00...0 (128 bits) ::/128 2.5.2 Loopback 00...1 (128 bits) ::1/128 2.5.3 Multicast 11111111 FF00::/8 2.7 Link-Local unicast 1111111010 FE80::/10 2.5.6 Global Unicast (everything else) ``` From [IETF RFC 4291 section 2.5.6](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.6): "Link-Local IPv6 Unicast Addresses" (`FE80::/64`) ```text | 10 bits | 54 bits | 64 bits | +----------+-------------------------+----------------------------+ |1111111010| 0 | interface ID | +----------+-------------------------+----------------------------+ ``` With `is_unicast_link_local` checking `FE80::/10` and `is_unicast_link_local_strict` checking `FE80::/64`. There is also [IETF RFC 5156 section 2.4](https://datatracker.ietf.org/doc/html/rfc5156#section-2.4) which defines "Link-Scoped Unicast" as `FE80::/10`. It has been pointed out that implementations in other languages and the linux kernel all use `FE80::/10` (#76098 (comment), #76098 (comment)). Given all of this I believe the correct interpretation to be the following: All addresses in `FE80::/10` are defined as having Link-Local scope, however currently only the block `FE80::/64` has been allocated for "Link-Local IPv6 Unicast Addresses". This might change in the future however; more addresses in `FE80::/10` could be allocated and those will have Link-Local scope. I therefore believe the current behaviour of `is_unicast_link_local` to be correct (if interpreting it to have the semantics of `has_unicast_link_local_scope`) and `is_unicast_link_local_strict` to be unnecessary, confusing and even a potential source of future bugs: Currently there is no real difference in checking `FE80::/10` or `FE80::/64`, since any address in practice will be `FE80::/64`. However if an application uses `is_unicast_link_local_strict` to implement link-local (so non-global) behaviour, it will be incorrect in the future if addresses outside of `FE80::/64` are allocated. r? `@joshtriplett` as reviewer of all the related PRs
2 parents b348385 + c1f0c15 commit dc08641

File tree

2 files changed

+27
-101
lines changed

2 files changed

+27
-101
lines changed

library/std/src/net/ip.rs

+25-85
Original file line numberDiff line numberDiff line change
@@ -1267,79 +1267,31 @@ impl Ipv6Addr {
12671267
(self.segments()[0] & 0xfe00) == 0xfc00
12681268
}
12691269

1270-
/// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
1270+
/// Returns `true` if the address is a unicast address with link-local scope,
1271+
/// as defined in [RFC 4291].
12711272
///
1272-
/// A common misconception is to think that "unicast link-local addresses start with
1273-
/// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
1273+
/// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
1274+
/// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
1275+
/// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
12741276
///
1275-
/// ```no_rust
1276-
/// | 10 |
1277-
/// | bits | 54 bits | 64 bits |
1277+
/// ```text
1278+
/// | 10 bits | 54 bits | 64 bits |
12781279
/// +----------+-------------------------+----------------------------+
12791280
/// |1111111010| 0 | interface ID |
12801281
/// +----------+-------------------------+----------------------------+
12811282
/// ```
1283+
/// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
1284+
/// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
1285+
/// and those addresses will have link-local scope.
12821286
///
1283-
/// This method validates the format defined in the RFC and won't recognize addresses
1284-
/// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
1285-
/// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
1286-
///
1287-
/// # Examples
1288-
///
1289-
/// ```
1290-
/// #![feature(ip)]
1291-
///
1292-
/// use std::net::Ipv6Addr;
1293-
///
1294-
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
1295-
/// assert!(ip.is_unicast_link_local_strict());
1296-
///
1297-
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
1298-
/// assert!(ip.is_unicast_link_local_strict());
1299-
///
1300-
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
1301-
/// assert!(!ip.is_unicast_link_local_strict());
1302-
/// assert!(ip.is_unicast_link_local());
1303-
///
1304-
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
1305-
/// assert!(!ip.is_unicast_link_local_strict());
1306-
/// assert!(ip.is_unicast_link_local());
1307-
/// ```
1308-
///
1309-
/// # See also
1310-
///
1311-
/// - [IETF RFC 4291 section 2.5.6]
1312-
/// - [RFC 4291 errata 4406] (which has been rejected but provides useful
1313-
/// insight)
1314-
/// - [`Ipv6Addr::is_unicast_link_local()`]
1315-
///
1316-
/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
1317-
/// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
1318-
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
1319-
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1320-
#[unstable(feature = "ip", issue = "27709")]
1321-
#[inline]
1322-
pub const fn is_unicast_link_local_strict(&self) -> bool {
1323-
matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
1324-
}
1325-
1326-
/// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
1287+
/// 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",
1288+
/// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
13271289
///
1328-
/// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
1329-
/// i.e. addresses with the following format:
1330-
///
1331-
/// ```no_rust
1332-
/// | 10 |
1333-
/// | bits | 54 bits | 64 bits |
1334-
/// +----------+-------------------------+----------------------------+
1335-
/// |1111111010| arbitratry value | interface ID |
1336-
/// +----------+-------------------------+----------------------------+
1337-
/// ```
1338-
///
1339-
/// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
1340-
/// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
1341-
/// If you need a strict validation fully compliant with the RFC, use
1342-
/// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
1290+
/// [RFC 4291]: https://tools.ietf.org/html/rfc4291
1291+
/// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
1292+
/// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
1293+
/// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
1294+
/// [loopback address]: Ipv6Addr::LOCALHOST
13431295
///
13441296
/// # Examples
13451297
///
@@ -1348,29 +1300,17 @@ impl Ipv6Addr {
13481300
///
13491301
/// use std::net::Ipv6Addr;
13501302
///
1351-
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
1352-
/// assert!(ip.is_unicast_link_local());
1303+
/// // The loopback address (`::1`) does not actually have link-local scope.
1304+
/// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
13531305
///
1354-
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
1355-
/// assert!(ip.is_unicast_link_local());
1306+
/// // Only addresses in `fe80::/10` have link-local scope.
1307+
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
1308+
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
13561309
///
1357-
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
1358-
/// assert!(ip.is_unicast_link_local());
1359-
/// assert!(!ip.is_unicast_link_local_strict());
1360-
///
1361-
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
1362-
/// assert!(ip.is_unicast_link_local());
1363-
/// assert!(!ip.is_unicast_link_local_strict());
1310+
/// // Addresses outside the stricter `fe80::/64` also have link-local scope.
1311+
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
1312+
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
13641313
/// ```
1365-
///
1366-
/// # See also
1367-
///
1368-
/// - [IETF RFC 4291 section 2.4]
1369-
/// - [RFC 4291 errata 4406] (which has been rejected but provides useful
1370-
/// insight)
1371-
///
1372-
/// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
1373-
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
13741314
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
13751315
#[unstable(feature = "ip", issue = "27709")]
13761316
#[inline]

library/std/src/net/ip/tests.rs

+2-16
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,6 @@ fn ipv6_properties() {
480480
let unique_local: u16 = 1 << 2;
481481
let global: u16 = 1 << 3;
482482
let unicast_link_local: u16 = 1 << 4;
483-
let unicast_link_local_strict: u16 = 1 << 5;
484483
let unicast_site_local: u16 = 1 << 6;
485484
let unicast_global: u16 = 1 << 7;
486485
let documentation: u16 = 1 << 8;
@@ -524,11 +523,6 @@ fn ipv6_properties() {
524523
} else {
525524
assert!(!ip!($s).is_unicast_link_local());
526525
}
527-
if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
528-
assert!(ip!($s).is_unicast_link_local_strict());
529-
} else {
530-
assert!(!ip!($s).is_unicast_link_local_strict());
531-
}
532526
if ($mask & unicast_site_local) == unicast_site_local {
533527
assert!(ip!($s).is_unicast_site_local());
534528
} else {
@@ -587,7 +581,6 @@ fn ipv6_properties() {
587581
let unique_local: u16 = 1 << 2;
588582
let global: u16 = 1 << 3;
589583
let unicast_link_local: u16 = 1 << 4;
590-
let unicast_link_local_strict: u16 = 1 << 5;
591584
let unicast_site_local: u16 = 1 << 6;
592585
let unicast_global: u16 = 1 << 7;
593586
let documentation: u16 = 1 << 8;
@@ -621,11 +614,7 @@ fn ipv6_properties() {
621614
unicast_link_local
622615
);
623616

624-
check!(
625-
"fe80::",
626-
&[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
627-
unicast_link_local | unicast_link_local_strict
628-
);
617+
check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
629618

630619
check!(
631620
"febf:ffff::",
@@ -650,7 +639,7 @@ fn ipv6_properties() {
650639
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
651640
0xff, 0xff
652641
],
653-
unicast_link_local | unicast_link_local_strict
642+
unicast_link_local
654643
);
655644

656645
check!(
@@ -897,9 +886,6 @@ fn ipv6_const() {
897886
const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
898887
assert!(!IS_UNIQUE_LOCAL);
899888

900-
const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict();
901-
assert!(!IS_UNICAST_LINK_LOCAL_STRICT);
902-
903889
const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
904890
assert!(!IS_UNICAST_LINK_LOCAL);
905891

0 commit comments

Comments
 (0)