Skip to content

Commit 1f0aa40

Browse files
committed
std::net: add Ipv6Addr::is_unicast_link_local_strict()
RFC 4291 is a little unclear about what is a unicast link local address. According to section 2.4, the entire fe80::/10 range is reserved for these addresses, but section 2.5.3 defines a stricter format for such addresses. After a discussion[0] is has been decided to add a different method for each definition, so this commit: - renames is_unicast_link_local() into is_unicast_link_local_strict() - relaxed the check in is_unicast_link_local() [0]: #27709 (comment)
1 parent 5aea184 commit 1f0aa40

File tree

1 file changed

+96
-6
lines changed

1 file changed

+96
-6
lines changed

src/libstd/net/ip.rs

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,12 +1027,81 @@ impl Ipv6Addr {
10271027
(self.segments()[0] & 0xfe00) == 0xfc00
10281028
}
10291029

1030-
/// Returns [`true`] if the address is unicast and link-local (fe80::/10).
1030+
/// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
10311031
///
1032-
/// This property is defined in [IETF RFC 4291].
1032+
/// A common mis-conception is to think that "unicast link-local addresses start with
1033+
/// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses:
10331034
///
1034-
/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
1035+
/// ```no_rust
1036+
/// | 10 |
1037+
/// | bits | 54 bits | 64 bits |
1038+
/// +----------+-------------------------+----------------------------+
1039+
/// |1111111010| 0 | interface ID |
1040+
/// +----------+-------------------------+----------------------------+
1041+
/// ```
1042+
///
1043+
/// This method validates the format defined in the RFC and won't recognize the following
1044+
/// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example.
1045+
/// If you need a less strict validation use [`is_unicast_link_local()`] instead.
1046+
///
1047+
/// # Examples
1048+
///
1049+
/// ```
1050+
/// #![feature(ip)]
1051+
///
1052+
/// use std::net::Ipv6Addr;
1053+
///
1054+
/// fn main() {
1055+
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
1056+
/// assert!(ip.is_unicast_link_local_strict());
1057+
///
1058+
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
1059+
/// assert!(ip.is_unicast_link_local_strict());
1060+
///
1061+
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
1062+
/// assert!(!ip.is_unicast_link_local_strict());
1063+
/// assert!(ip.is_unicast_link_local());
1064+
///
1065+
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
1066+
/// assert!(!ip.is_unicast_link_local_strict());
1067+
/// assert!(ip.is_unicast_link_local());
1068+
/// }
1069+
/// ```
1070+
///
1071+
/// # See also
1072+
///
1073+
/// - [IETF RFC 4291 section 2.5.6]
1074+
/// - [RFC 4291 errata 4406]
1075+
///
1076+
/// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
10351077
/// [`true`]: ../../std/primitive.bool.html
1078+
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
1079+
/// [`is_unicast_link_local()`](#method.is_unicast_link_local)
1080+
///
1081+
pub fn is_unicast_link_local_strict(&self) -> bool {
1082+
(self.segments()[0] & 0xffff) == 0xfe80
1083+
&& (self.segments()[1] & 0xffff) == 0
1084+
&& (self.segments()[2] & 0xffff) == 0
1085+
&& (self.segments()[3] & 0xffff) == 0
1086+
}
1087+
1088+
/// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
1089+
///
1090+
/// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
1091+
/// i.e. addresses with the following format:
1092+
///
1093+
/// ```no_rust
1094+
/// | 10 |
1095+
/// | bits | 54 bits | 64 bits |
1096+
/// +----------+-------------------------+----------------------------+
1097+
/// |1111111010| arbitratry value | interface ID |
1098+
/// +----------+-------------------------+----------------------------+
1099+
/// ```
1100+
///
1101+
/// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be
1102+
/// unicast link-local addresses, whereas [`is_unicast_link_local_strict()`] does not. If you
1103+
/// need a strict validation fully compliant with the RFC, use
1104+
/// [`is_unicast_link_local_strict()`].
10361105
///
10371106
/// # Examples
10381107
///
@@ -1042,11 +1111,32 @@ impl Ipv6Addr {
10421111
/// use std::net::Ipv6Addr;
10431112
///
10441113
/// fn main() {
1045-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(),
1046-
/// false);
1047-
/// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
1114+
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
1115+
/// assert!(ip.is_unicast_link_local());
1116+
///
1117+
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
1118+
/// assert!(ip.is_unicast_link_local());
1119+
///
1120+
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
1121+
/// assert!(ip.is_unicast_link_local());
1122+
/// assert!(!ip.is_unicast_link_local_strict());
1123+
///
1124+
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
1125+
/// assert!(ip.is_unicast_link_local());
1126+
/// assert!(!ip.is_unicast_link_local_strict());
10481127
/// }
10491128
/// ```
1129+
///
1130+
/// # See also
1131+
///
1132+
/// - [IETF RFC 4291 section 2.4]
1133+
/// - [RFC 4291 errata 4406]
1134+
///
1135+
/// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
1136+
/// [`true`]: ../../std/primitive.bool.html
1137+
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
1138+
/// [`is_unicast_link_local_strict()`](#method.is_unicast_link_local_strict)
1139+
///
10501140
pub fn is_unicast_link_local(&self) -> bool {
10511141
(self.segments()[0] & 0xffc0) == 0xfe80
10521142
}

0 commit comments

Comments
 (0)