@@ -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