@@ -1027,12 +1027,81 @@ impl Ipv6Addr {
1027
1027
( self . segments ( ) [ 0 ] & 0xfe00 ) == 0xfc00
1028
1028
}
1029
1029
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` ).
1031
1031
///
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:
1033
1034
///
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
1035
1077
/// [`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()`].
1036
1105
///
1037
1106
/// # Examples
1038
1107
///
@@ -1042,11 +1111,32 @@ impl Ipv6Addr {
1042
1111
/// use std::net::Ipv6Addr;
1043
1112
///
1044
1113
/// 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());
1048
1127
/// }
1049
1128
/// ```
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
+ ///
1050
1140
pub fn is_unicast_link_local ( & self ) -> bool {
1051
1141
( self . segments ( ) [ 0 ] & 0xffc0 ) == 0xfe80
1052
1142
}
0 commit comments