]>
Commit | Line | Data |
---|---|---|
c34b1796 AL |
1 | #![unstable(feature = "ip", reason = "extra functionality has not been \ |
2 | scrutinized to the level that it should \ | |
ea8adc8c | 3 | be to be stable", |
e9174d1e | 4 | issue = "27709")] |
c34b1796 | 5 | |
532ac7d7 XL |
6 | use crate::cmp::Ordering; |
7 | use crate::fmt; | |
8 | use crate::hash; | |
9 | use crate::sys::net::netc as c; | |
10 | use crate::sys_common::{AsInner, FromInner}; | |
85aaf69f | 11 | |
cc61c64b | 12 | /// An IP address, either IPv4 or IPv6. |
9e0c209e | 13 | /// |
cc61c64b XL |
14 | /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their |
15 | /// respective documentation for more details. | |
9e0c209e | 16 | /// |
0531ce1d XL |
17 | /// The size of an `IpAddr` instance may vary depending on the target operating |
18 | /// system. | |
19 | /// | |
cc61c64b XL |
20 | /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html |
21 | /// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html | |
9e0c209e | 22 | /// |
cc61c64b | 23 | /// # Examples |
9e0c209e | 24 | /// |
9e0c209e | 25 | /// ``` |
cc61c64b | 26 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
9e0c209e | 27 | /// |
cc61c64b XL |
28 | /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); |
29 | /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); | |
9e0c209e | 30 | /// |
cc61c64b XL |
31 | /// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); |
32 | /// assert_eq!("::1".parse(), Ok(localhost_v6)); | |
9e0c209e | 33 | /// |
cc61c64b XL |
34 | /// assert_eq!(localhost_v4.is_ipv6(), false); |
35 | /// assert_eq!(localhost_v4.is_ipv4(), true); | |
9e0c209e | 36 | /// ``` |
9cc50fc6 | 37 | #[stable(feature = "ip_addr", since = "1.7.0")] |
c34b1796 AL |
38 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] |
39 | pub enum IpAddr { | |
cc61c64b | 40 | /// An IPv4 address. |
9cc50fc6 | 41 | #[stable(feature = "ip_addr", since = "1.7.0")] |
7453a54e | 42 | V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), |
cc61c64b | 43 | /// An IPv6 address. |
9cc50fc6 | 44 | #[stable(feature = "ip_addr", since = "1.7.0")] |
7453a54e | 45 | V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), |
c34b1796 AL |
46 | } |
47 | ||
cc61c64b XL |
48 | /// An IPv4 address. |
49 | /// | |
50 | /// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. | |
51 | /// They are usually represented as four octets. | |
52 | /// | |
53 | /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. | |
54 | /// | |
0531ce1d XL |
55 | /// The size of an `Ipv4Addr` struct may vary depending on the target operating |
56 | /// system. | |
57 | /// | |
cc61c64b XL |
58 | /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 |
59 | /// [`IpAddr`]: ../../std/net/enum.IpAddr.html | |
60 | /// | |
61 | /// # Textual representation | |
62 | /// | |
63 | /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal | |
64 | /// notation, divided by `.` (this is called "dot-decimal notation"). | |
65 | /// | |
66 | /// [`FromStr`]: ../../std/str/trait.FromStr.html | |
67 | /// | |
68 | /// # Examples | |
69 | /// | |
70 | /// ``` | |
71 | /// use std::net::Ipv4Addr; | |
72 | /// | |
73 | /// let localhost = Ipv4Addr::new(127, 0, 0, 1); | |
74 | /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); | |
75 | /// assert_eq!(localhost.is_loopback(), true); | |
76 | /// ``` | |
85aaf69f | 77 | #[derive(Copy)] |
c34b1796 | 78 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 79 | pub struct Ipv4Addr { |
92a42be0 | 80 | inner: c::in_addr, |
85aaf69f SL |
81 | } |
82 | ||
cc61c64b XL |
83 | /// An IPv6 address. |
84 | /// | |
85 | /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. | |
86 | /// They are usually represented as eight 16-bit segments. | |
87 | /// | |
88 | /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. | |
89 | /// | |
0531ce1d XL |
90 | /// The size of an `Ipv6Addr` struct may vary depending on the target operating |
91 | /// system. | |
92 | /// | |
cc61c64b XL |
93 | /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
94 | /// [`IpAddr`]: ../../std/net/enum.IpAddr.html | |
95 | /// | |
96 | /// # Textual representation | |
97 | /// | |
98 | /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent | |
99 | /// an IPv6 address in text, but in general, each segments is written in hexadecimal | |
100 | /// notation, and segments are separated by `:`. For more information, see | |
101 | /// [IETF RFC 5952]. | |
102 | /// | |
103 | /// [`FromStr`]: ../../std/str/trait.FromStr.html | |
104 | /// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 | |
105 | /// | |
106 | /// # Examples | |
107 | /// | |
108 | /// ``` | |
109 | /// use std::net::Ipv6Addr; | |
110 | /// | |
111 | /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); | |
112 | /// assert_eq!("::1".parse(), Ok(localhost)); | |
113 | /// assert_eq!(localhost.is_loopback(), true); | |
114 | /// ``` | |
85aaf69f | 115 | #[derive(Copy)] |
c34b1796 | 116 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 117 | pub struct Ipv6Addr { |
92a42be0 | 118 | inner: c::in6_addr, |
85aaf69f SL |
119 | } |
120 | ||
121 | #[allow(missing_docs)] | |
122 | #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] | |
123 | pub enum Ipv6MulticastScope { | |
124 | InterfaceLocal, | |
125 | LinkLocal, | |
126 | RealmLocal, | |
127 | AdminLocal, | |
128 | SiteLocal, | |
129 | OrganizationLocal, | |
130 | Global | |
131 | } | |
132 | ||
5bcae85e | 133 | impl IpAddr { |
cc61c64b XL |
134 | /// Returns [`true`] for the special 'unspecified' address. |
135 | /// | |
136 | /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and | |
137 | /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. | |
476ff2be | 138 | /// |
5bcae85e SL |
139 | /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified |
140 | /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified | |
cc61c64b | 141 | /// [`true`]: ../../std/primitive.bool.html |
476ff2be SL |
142 | /// |
143 | /// # Examples | |
144 | /// | |
145 | /// ``` | |
146 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; | |
147 | /// | |
148 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); | |
149 | /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); | |
150 | /// ``` | |
5bcae85e SL |
151 | #[stable(feature = "ip_shared", since = "1.12.0")] |
152 | pub fn is_unspecified(&self) -> bool { | |
b7449926 XL |
153 | match self { |
154 | IpAddr::V4(ip) => ip.is_unspecified(), | |
155 | IpAddr::V6(ip) => ip.is_unspecified(), | |
5bcae85e SL |
156 | } |
157 | } | |
158 | ||
cc61c64b XL |
159 | /// Returns [`true`] if this is a loopback address. |
160 | /// | |
161 | /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and | |
162 | /// [`Ipv6Addr::is_loopback`][IPv6] for more details. | |
476ff2be | 163 | /// |
5bcae85e SL |
164 | /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback |
165 | /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback | |
cc61c64b | 166 | /// [`true`]: ../../std/primitive.bool.html |
476ff2be SL |
167 | /// |
168 | /// # Examples | |
169 | /// | |
170 | /// ``` | |
171 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; | |
172 | /// | |
173 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); | |
174 | /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); | |
175 | /// ``` | |
5bcae85e SL |
176 | #[stable(feature = "ip_shared", since = "1.12.0")] |
177 | pub fn is_loopback(&self) -> bool { | |
b7449926 XL |
178 | match self { |
179 | IpAddr::V4(ip) => ip.is_loopback(), | |
180 | IpAddr::V6(ip) => ip.is_loopback(), | |
5bcae85e SL |
181 | } |
182 | } | |
183 | ||
cc61c64b XL |
184 | /// Returns [`true`] if the address appears to be globally routable. |
185 | /// | |
186 | /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and | |
187 | /// [`Ipv6Addr::is_global`][IPv6] for more details. | |
476ff2be | 188 | /// |
5bcae85e SL |
189 | /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global |
190 | /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global | |
cc61c64b | 191 | /// [`true`]: ../../std/primitive.bool.html |
476ff2be SL |
192 | /// |
193 | /// # Examples | |
194 | /// | |
195 | /// ``` | |
196 | /// #![feature(ip)] | |
197 | /// | |
198 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; | |
199 | /// | |
e74abb32 XL |
200 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); |
201 | /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); | |
476ff2be | 202 | /// ``` |
5bcae85e | 203 | pub fn is_global(&self) -> bool { |
b7449926 XL |
204 | match self { |
205 | IpAddr::V4(ip) => ip.is_global(), | |
206 | IpAddr::V6(ip) => ip.is_global(), | |
5bcae85e SL |
207 | } |
208 | } | |
209 | ||
cc61c64b XL |
210 | /// Returns [`true`] if this is a multicast address. |
211 | /// | |
212 | /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and | |
213 | /// [`Ipv6Addr::is_multicast`][IPv6] for more details. | |
476ff2be | 214 | /// |
5bcae85e SL |
215 | /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast |
216 | /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast | |
cc61c64b | 217 | /// [`true`]: ../../std/primitive.bool.html |
476ff2be SL |
218 | /// |
219 | /// # Examples | |
220 | /// | |
221 | /// ``` | |
222 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; | |
223 | /// | |
224 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); | |
225 | /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); | |
226 | /// ``` | |
5bcae85e SL |
227 | #[stable(feature = "ip_shared", since = "1.12.0")] |
228 | pub fn is_multicast(&self) -> bool { | |
b7449926 XL |
229 | match self { |
230 | IpAddr::V4(ip) => ip.is_multicast(), | |
231 | IpAddr::V6(ip) => ip.is_multicast(), | |
5bcae85e SL |
232 | } |
233 | } | |
234 | ||
cc61c64b XL |
235 | /// Returns [`true`] if this address is in a range designated for documentation. |
236 | /// | |
237 | /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and | |
238 | /// [`Ipv6Addr::is_documentation`][IPv6] for more details. | |
476ff2be | 239 | /// |
5bcae85e SL |
240 | /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation |
241 | /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation | |
cc61c64b | 242 | /// [`true`]: ../../std/primitive.bool.html |
476ff2be SL |
243 | /// |
244 | /// # Examples | |
245 | /// | |
246 | /// ``` | |
247 | /// #![feature(ip)] | |
248 | /// | |
249 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; | |
250 | /// | |
e74abb32 XL |
251 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); |
252 | /// assert_eq!( | |
253 | /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), | |
254 | /// true | |
255 | /// ); | |
476ff2be | 256 | /// ``` |
5bcae85e | 257 | pub fn is_documentation(&self) -> bool { |
b7449926 XL |
258 | match self { |
259 | IpAddr::V4(ip) => ip.is_documentation(), | |
260 | IpAddr::V6(ip) => ip.is_documentation(), | |
5bcae85e SL |
261 | } |
262 | } | |
c30ab7b3 | 263 | |
cc61c64b XL |
264 | /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. |
265 | /// | |
266 | /// [`true`]: ../../std/primitive.bool.html | |
267 | /// [`false`]: ../../std/primitive.bool.html | |
268 | /// [IPv4 address]: #variant.V4 | |
476ff2be SL |
269 | /// |
270 | /// # Examples | |
271 | /// | |
272 | /// ``` | |
476ff2be SL |
273 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
274 | /// | |
e74abb32 XL |
275 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); |
276 | /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); | |
476ff2be | 277 | /// ``` |
32a655c1 | 278 | #[stable(feature = "ipaddr_checker", since = "1.16.0")] |
c30ab7b3 | 279 | pub fn is_ipv4(&self) -> bool { |
b7449926 | 280 | match self { |
c30ab7b3 SL |
281 | IpAddr::V4(_) => true, |
282 | IpAddr::V6(_) => false, | |
283 | } | |
284 | } | |
285 | ||
cc61c64b XL |
286 | /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. |
287 | /// | |
288 | /// [`true`]: ../../std/primitive.bool.html | |
289 | /// [`false`]: ../../std/primitive.bool.html | |
290 | /// [IPv6 address]: #variant.V6 | |
476ff2be SL |
291 | /// |
292 | /// # Examples | |
293 | /// | |
294 | /// ``` | |
476ff2be SL |
295 | /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
296 | /// | |
e74abb32 XL |
297 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); |
298 | /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); | |
476ff2be | 299 | /// ``` |
32a655c1 | 300 | #[stable(feature = "ipaddr_checker", since = "1.16.0")] |
c30ab7b3 | 301 | pub fn is_ipv6(&self) -> bool { |
b7449926 | 302 | match self { |
c30ab7b3 SL |
303 | IpAddr::V4(_) => false, |
304 | IpAddr::V6(_) => true, | |
305 | } | |
306 | } | |
5bcae85e SL |
307 | } |
308 | ||
85aaf69f | 309 | impl Ipv4Addr { |
9346a6ac | 310 | /// Creates a new IPv4 address from four eight-bit octets. |
85aaf69f | 311 | /// |
bd371182 | 312 | /// The result will represent the IP address `a`.`b`.`c`.`d`. |
476ff2be SL |
313 | /// |
314 | /// # Examples | |
315 | /// | |
316 | /// ``` | |
317 | /// use std::net::Ipv4Addr; | |
318 | /// | |
319 | /// let addr = Ipv4Addr::new(127, 0, 0, 1); | |
320 | /// ``` | |
c34b1796 | 321 | #[stable(feature = "rust1", since = "1.0.0")] |
60c5eb7d | 322 | #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv4", since = "1.32.0"))] |
b7449926 | 323 | pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { |
9fa01778 XL |
324 | // FIXME: should just be u32::from_be_bytes([a, b, c, d]), |
325 | // once that method is no longer rustc_const_unstable | |
85aaf69f | 326 | Ipv4Addr { |
92a42be0 | 327 | inner: c::in_addr { |
b7449926 XL |
328 | s_addr: u32::to_be( |
329 | ((a as u32) << 24) | | |
330 | ((b as u32) << 16) | | |
331 | ((c as u32) << 8) | | |
332 | (d as u32) | |
333 | ), | |
85aaf69f SL |
334 | } |
335 | } | |
336 | } | |
337 | ||
b7449926 | 338 | /// An IPv4 address with the address pointing to localhost: 127.0.0.1. |
ea8adc8c XL |
339 | /// |
340 | /// # Examples | |
341 | /// | |
342 | /// ``` | |
ea8adc8c XL |
343 | /// use std::net::Ipv4Addr; |
344 | /// | |
b7449926 | 345 | /// let addr = Ipv4Addr::LOCALHOST; |
ea8adc8c XL |
346 | /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); |
347 | /// ``` | |
b7449926 XL |
348 | #[stable(feature = "ip_constructors", since = "1.30.0")] |
349 | pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); | |
ea8adc8c | 350 | |
b7449926 | 351 | /// An IPv4 address representing an unspecified address: 0.0.0.0 |
ea8adc8c XL |
352 | /// |
353 | /// # Examples | |
354 | /// | |
355 | /// ``` | |
ea8adc8c XL |
356 | /// use std::net::Ipv4Addr; |
357 | /// | |
b7449926 | 358 | /// let addr = Ipv4Addr::UNSPECIFIED; |
ea8adc8c XL |
359 | /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); |
360 | /// ``` | |
b7449926 XL |
361 | #[stable(feature = "ip_constructors", since = "1.30.0")] |
362 | pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); | |
363 | ||
364 | /// An IPv4 address representing the broadcast address: 255.255.255.255 | |
365 | /// | |
366 | /// # Examples | |
367 | /// | |
368 | /// ``` | |
369 | /// use std::net::Ipv4Addr; | |
370 | /// | |
371 | /// let addr = Ipv4Addr::BROADCAST; | |
372 | /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); | |
373 | /// ``` | |
374 | #[stable(feature = "ip_constructors", since = "1.30.0")] | |
375 | pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); | |
ea8adc8c | 376 | |
bd371182 | 377 | /// Returns the four eight-bit integers that make up this address. |
476ff2be SL |
378 | /// |
379 | /// # Examples | |
380 | /// | |
381 | /// ``` | |
382 | /// use std::net::Ipv4Addr; | |
383 | /// | |
384 | /// let addr = Ipv4Addr::new(127, 0, 0, 1); | |
385 | /// assert_eq!(addr.octets(), [127, 0, 0, 1]); | |
386 | /// ``` | |
c34b1796 | 387 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 388 | pub fn octets(&self) -> [u8; 4] { |
9fa01778 XL |
389 | // This returns the order we want because s_addr is stored in big-endian. |
390 | self.inner.s_addr.to_ne_bytes() | |
85aaf69f SL |
391 | } |
392 | ||
cc61c64b | 393 | /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). |
5bcae85e SL |
394 | /// |
395 | /// This property is defined in _UNIX Network Programming, Second Edition_, | |
476ff2be SL |
396 | /// W. Richard Stevens, p. 891; see also [ip7]. |
397 | /// | |
398 | /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html | |
cc61c64b | 399 | /// [`true`]: ../../std/primitive.bool.html |
476ff2be SL |
400 | /// |
401 | /// # Examples | |
402 | /// | |
403 | /// ``` | |
404 | /// use std::net::Ipv4Addr; | |
405 | /// | |
406 | /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); | |
407 | /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); | |
408 | /// ``` | |
5bcae85e | 409 | #[stable(feature = "ip_shared", since = "1.12.0")] |
60c5eb7d | 410 | #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv4", since = "1.32.0"))] |
a1dfa0c6 | 411 | pub const fn is_unspecified(&self) -> bool { |
85aaf69f SL |
412 | self.inner.s_addr == 0 |
413 | } | |
414 | ||
cc61c64b | 415 | /// Returns [`true`] if this is a loopback address (127.0.0.0/8). |
9cc50fc6 | 416 | /// |
cc61c64b | 417 | /// This property is defined by [IETF RFC 1122]. |
476ff2be | 418 | /// |
cc61c64b XL |
419 | /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 |
420 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
421 | /// |
422 | /// # Examples | |
423 | /// | |
424 | /// ``` | |
425 | /// use std::net::Ipv4Addr; | |
426 | /// | |
427 | /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); | |
428 | /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); | |
429 | /// ``` | |
9cc50fc6 | 430 | #[stable(since = "1.7.0", feature = "ip_17")] |
85aaf69f SL |
431 | pub fn is_loopback(&self) -> bool { |
432 | self.octets()[0] == 127 | |
433 | } | |
434 | ||
cc61c64b | 435 | /// Returns [`true`] if this is a private address. |
85aaf69f | 436 | /// |
cc61c64b | 437 | /// The private address ranges are defined in [IETF RFC 1918] and include: |
85aaf69f SL |
438 | /// |
439 | /// - 10.0.0.0/8 | |
440 | /// - 172.16.0.0/12 | |
441 | /// - 192.168.0.0/16 | |
476ff2be | 442 | /// |
cc61c64b XL |
443 | /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 |
444 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
445 | /// |
446 | /// # Examples | |
447 | /// | |
448 | /// ``` | |
449 | /// use std::net::Ipv4Addr; | |
450 | /// | |
451 | /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); | |
452 | /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); | |
453 | /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); | |
454 | /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); | |
455 | /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); | |
456 | /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); | |
457 | /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); | |
458 | /// ``` | |
9cc50fc6 | 459 | #[stable(since = "1.7.0", feature = "ip_17")] |
85aaf69f | 460 | pub fn is_private(&self) -> bool { |
b7449926 XL |
461 | match self.octets() { |
462 | [10, ..] => true, | |
463 | [172, b, ..] if b >= 16 && b <= 31 => true, | |
464 | [192, 168, ..] => true, | |
465 | _ => false, | |
85aaf69f SL |
466 | } |
467 | } | |
468 | ||
cc61c64b | 469 | /// Returns [`true`] if the address is link-local (169.254.0.0/16). |
9cc50fc6 | 470 | /// |
cc61c64b | 471 | /// This property is defined by [IETF RFC 3927]. |
476ff2be | 472 | /// |
cc61c64b XL |
473 | /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 |
474 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
475 | /// |
476 | /// # Examples | |
477 | /// | |
478 | /// ``` | |
479 | /// use std::net::Ipv4Addr; | |
480 | /// | |
481 | /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); | |
482 | /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); | |
483 | /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); | |
484 | /// ``` | |
9cc50fc6 | 485 | #[stable(since = "1.7.0", feature = "ip_17")] |
85aaf69f | 486 | pub fn is_link_local(&self) -> bool { |
b7449926 XL |
487 | match self.octets() { |
488 | [169, 254, ..] => true, | |
489 | _ => false, | |
490 | } | |
85aaf69f SL |
491 | } |
492 | ||
cc61c64b | 493 | /// Returns [`true`] if the address appears to be globally routable. |
54a0048b | 494 | /// See [iana-ipv4-special-registry][ipv4-sr]. |
85aaf69f | 495 | /// |
d9579d0f AL |
496 | /// The following return false: |
497 | /// | |
dc9dc135 XL |
498 | /// - private addresses (see [`is_private()`](#method.is_private)) |
499 | /// - the loopback address (see [`is_loopback()`](#method.is_loopback)) | |
500 | /// - the link-local address (see [`is_link_local()`](#method.is_link_local)) | |
501 | /// - the broadcast address (see [`is_broadcast()`](#method.is_broadcast)) | |
502 | /// - addresses used for documentation (see [`is_documentation()`](#method.is_documentation)) | |
503 | /// - the unspecified address (see [`is_unspecified()`](#method.is_unspecified)), and the whole | |
504 | /// 0.0.0.0/8 block | |
505 | /// - addresses reserved for future protocols (see | |
506 | /// [`is_ietf_protocol_assignment()`](#method.is_ietf_protocol_assignment), except | |
507 | /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable | |
508 | /// - addresses reserved for future use (see [`is_reserved()`](#method.is_reserved) | |
509 | /// - addresses reserved for networking devices benchmarking (see | |
510 | /// [`is_benchmarking`](#method.is_benchmarking)) | |
476ff2be | 511 | /// |
3b2f2976 | 512 | /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml |
cc61c64b | 513 | /// [`true`]: ../../std/primitive.bool.html |
476ff2be SL |
514 | /// |
515 | /// # Examples | |
516 | /// | |
517 | /// ``` | |
518 | /// #![feature(ip)] | |
519 | /// | |
520 | /// use std::net::Ipv4Addr; | |
521 | /// | |
e74abb32 XL |
522 | /// // private addresses are not global |
523 | /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); | |
524 | /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); | |
525 | /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); | |
dc9dc135 | 526 | /// |
e74abb32 XL |
527 | /// // the 0.0.0.0/8 block is not global |
528 | /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); | |
529 | /// // in particular, the unspecified address is not global | |
530 | /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); | |
dc9dc135 | 531 | /// |
e74abb32 XL |
532 | /// // the loopback address is not global |
533 | /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); | |
dc9dc135 | 534 | /// |
e74abb32 XL |
535 | /// // link local addresses are not global |
536 | /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); | |
dc9dc135 | 537 | /// |
e74abb32 XL |
538 | /// // the broadcast address is not global |
539 | /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); | |
dc9dc135 | 540 | /// |
60c5eb7d | 541 | /// // the address space designated for documentation is not global |
e74abb32 XL |
542 | /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); |
543 | /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); | |
544 | /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); | |
dc9dc135 | 545 | /// |
e74abb32 XL |
546 | /// // shared addresses are not global |
547 | /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); | |
dc9dc135 | 548 | /// |
e74abb32 XL |
549 | /// // addresses reserved for protocol assignment are not global |
550 | /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); | |
551 | /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); | |
dc9dc135 | 552 | /// |
e74abb32 XL |
553 | /// // addresses reserved for future use are not global |
554 | /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); | |
dc9dc135 | 555 | /// |
e74abb32 XL |
556 | /// // addresses reserved for network devices benchmarking are not global |
557 | /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); | |
dc9dc135 | 558 | /// |
e74abb32 XL |
559 | /// // All the other addresses are global |
560 | /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); | |
561 | /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); | |
476ff2be | 562 | /// ``` |
85aaf69f | 563 | pub fn is_global(&self) -> bool { |
dc9dc135 XL |
564 | // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two |
565 | // globally routable addresses in the 192.0.0.0/24 range. | |
566 | if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { | |
567 | return true; | |
568 | } | |
569 | !self.is_private() | |
570 | && !self.is_loopback() | |
571 | && !self.is_link_local() | |
572 | && !self.is_broadcast() | |
573 | && !self.is_documentation() | |
574 | && !self.is_shared() | |
575 | && !self.is_ietf_protocol_assignment() | |
576 | && !self.is_reserved() | |
577 | && !self.is_benchmarking() | |
578 | // Make sure the address is not in 0.0.0.0/8 | |
579 | && self.octets()[0] != 0 | |
580 | } | |
581 | ||
582 | /// Returns [`true`] if this address is part of the Shared Address Space defined in | |
583 | /// [IETF RFC 6598] (`100.64.0.0/10`). | |
584 | /// | |
585 | /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 | |
586 | /// [`true`]: ../../std/primitive.bool.html | |
587 | /// | |
588 | /// # Examples | |
589 | /// | |
590 | /// ``` | |
591 | /// #![feature(ip)] | |
592 | /// use std::net::Ipv4Addr; | |
593 | /// | |
e74abb32 XL |
594 | /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); |
595 | /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); | |
596 | /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); | |
dc9dc135 XL |
597 | /// ``` |
598 | pub fn is_shared(&self) -> bool { | |
599 | self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) | |
600 | } | |
601 | ||
602 | /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to | |
603 | /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890]. | |
604 | /// | |
605 | /// Note that parts of this block are in use: | |
606 | /// | |
607 | /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600]) | |
608 | /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) | |
609 | /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) | |
610 | /// | |
611 | /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 | |
612 | /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 | |
613 | /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 | |
614 | /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155 | |
615 | /// [`true`]: ../../std/primitive.bool.html | |
616 | /// | |
617 | /// # Examples | |
618 | /// | |
619 | /// ``` | |
620 | /// #![feature(ip)] | |
621 | /// use std::net::Ipv4Addr; | |
622 | /// | |
e74abb32 XL |
623 | /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); |
624 | /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); | |
625 | /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); | |
626 | /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); | |
627 | /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); | |
628 | /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); | |
dc9dc135 XL |
629 | /// ``` |
630 | pub fn is_ietf_protocol_assignment(&self) -> bool { | |
631 | self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 | |
632 | } | |
633 | ||
634 | /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for | |
635 | /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` | |
636 | /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. | |
637 | /// | |
60c5eb7d XL |
638 | /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 |
639 | /// [errata 423]: https://www.rfc-editor.org/errata/eid423 | |
dc9dc135 XL |
640 | /// [`true`]: ../../std/primitive.bool.html |
641 | /// | |
642 | /// # Examples | |
643 | /// | |
644 | /// ``` | |
645 | /// #![feature(ip)] | |
646 | /// use std::net::Ipv4Addr; | |
647 | /// | |
e74abb32 XL |
648 | /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); |
649 | /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); | |
650 | /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); | |
651 | /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); | |
dc9dc135 XL |
652 | /// ``` |
653 | pub fn is_benchmarking(&self) -> bool { | |
654 | self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 | |
655 | } | |
656 | ||
657 | /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] | |
658 | /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the | |
659 | /// broadcast address `255.255.255.255`, but this implementation explicitely excludes it, since | |
660 | /// it is obviously not reserved for future use. | |
661 | /// | |
662 | /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 | |
663 | /// [`true`]: ../../std/primitive.bool.html | |
664 | /// | |
665 | /// # Warning | |
666 | /// | |
667 | /// As IANA assigns new addresses, this method will be | |
668 | /// updated. This may result in non-reserved addresses being | |
669 | /// treated as reserved in code that relies on an outdated version | |
670 | /// of this method. | |
671 | /// | |
672 | /// # Examples | |
673 | /// | |
674 | /// ``` | |
675 | /// #![feature(ip)] | |
676 | /// use std::net::Ipv4Addr; | |
677 | /// | |
e74abb32 XL |
678 | /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); |
679 | /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); | |
dc9dc135 | 680 | /// |
e74abb32 XL |
681 | /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); |
682 | /// // The broadcast address is not considered as reserved for future use by this implementation | |
683 | /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); | |
dc9dc135 XL |
684 | /// ``` |
685 | pub fn is_reserved(&self) -> bool { | |
686 | self.octets()[0] & 240 == 240 && !self.is_broadcast() | |
85aaf69f SL |
687 | } |
688 | ||
cc61c64b | 689 | /// Returns [`true`] if this is a multicast address (224.0.0.0/4). |
85aaf69f | 690 | /// |
9cc50fc6 | 691 | /// Multicast addresses have a most significant octet between 224 and 239, |
cc61c64b | 692 | /// and is defined by [IETF RFC 5771]. |
476ff2be | 693 | /// |
cc61c64b XL |
694 | /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 |
695 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
696 | /// |
697 | /// # Examples | |
698 | /// | |
699 | /// ``` | |
700 | /// use std::net::Ipv4Addr; | |
701 | /// | |
702 | /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); | |
703 | /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); | |
704 | /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); | |
705 | /// ``` | |
9cc50fc6 | 706 | #[stable(since = "1.7.0", feature = "ip_17")] |
85aaf69f SL |
707 | pub fn is_multicast(&self) -> bool { |
708 | self.octets()[0] >= 224 && self.octets()[0] <= 239 | |
709 | } | |
710 | ||
cc61c64b | 711 | /// Returns [`true`] if this is a broadcast address (255.255.255.255). |
9346a6ac | 712 | /// |
cc61c64b | 713 | /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. |
476ff2be | 714 | /// |
cc61c64b XL |
715 | /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 |
716 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
717 | /// |
718 | /// # Examples | |
719 | /// | |
720 | /// ``` | |
721 | /// use std::net::Ipv4Addr; | |
722 | /// | |
723 | /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); | |
724 | /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); | |
725 | /// ``` | |
9cc50fc6 | 726 | #[stable(since = "1.7.0", feature = "ip_17")] |
9346a6ac | 727 | pub fn is_broadcast(&self) -> bool { |
b7449926 | 728 | self == &Self::BROADCAST |
9346a6ac AL |
729 | } |
730 | ||
cc61c64b | 731 | /// Returns [`true`] if this address is in a range designated for documentation. |
9346a6ac | 732 | /// |
cc61c64b | 733 | /// This is defined in [IETF RFC 5737]: |
d9579d0f | 734 | /// |
9346a6ac AL |
735 | /// - 192.0.2.0/24 (TEST-NET-1) |
736 | /// - 198.51.100.0/24 (TEST-NET-2) | |
737 | /// - 203.0.113.0/24 (TEST-NET-3) | |
476ff2be | 738 | /// |
cc61c64b XL |
739 | /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 |
740 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
741 | /// |
742 | /// # Examples | |
743 | /// | |
744 | /// ``` | |
745 | /// use std::net::Ipv4Addr; | |
746 | /// | |
747 | /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); | |
748 | /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); | |
749 | /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); | |
750 | /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); | |
751 | /// ``` | |
9cc50fc6 | 752 | #[stable(since = "1.7.0", feature = "ip_17")] |
9346a6ac | 753 | pub fn is_documentation(&self) -> bool { |
b7449926 XL |
754 | match self.octets() { |
755 | [192, 0, 2, _] => true, | |
756 | [198, 51, 100, _] => true, | |
757 | [203, 0, 113, _] => true, | |
758 | _ => false, | |
9346a6ac AL |
759 | } |
760 | } | |
761 | ||
cc61c64b | 762 | /// Converts this address to an IPv4-compatible [IPv6 address]. |
85aaf69f SL |
763 | /// |
764 | /// a.b.c.d becomes ::a.b.c.d | |
476ff2be | 765 | /// |
cc61c64b XL |
766 | /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html |
767 | /// | |
476ff2be SL |
768 | /// # Examples |
769 | /// | |
770 | /// ``` | |
771 | /// use std::net::{Ipv4Addr, Ipv6Addr}; | |
772 | /// | |
e74abb32 XL |
773 | /// assert_eq!( |
774 | /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), | |
775 | /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) | |
776 | /// ); | |
476ff2be | 777 | /// ``` |
c34b1796 | 778 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 779 | pub fn to_ipv6_compatible(&self) -> Ipv6Addr { |
9fa01778 XL |
780 | let octets = self.octets(); |
781 | Ipv6Addr::from([ | |
782 | 0, 0, 0, 0, | |
783 | 0, 0, 0, 0, | |
784 | 0, 0, 0, 0, | |
785 | octets[0], octets[1], octets[2], octets[3], | |
786 | ]) | |
85aaf69f SL |
787 | } |
788 | ||
cc61c64b | 789 | /// Converts this address to an IPv4-mapped [IPv6 address]. |
85aaf69f SL |
790 | /// |
791 | /// a.b.c.d becomes ::ffff:a.b.c.d | |
476ff2be | 792 | /// |
cc61c64b XL |
793 | /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html |
794 | /// | |
476ff2be SL |
795 | /// # Examples |
796 | /// | |
797 | /// ``` | |
798 | /// use std::net::{Ipv4Addr, Ipv6Addr}; | |
799 | /// | |
800 | /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), | |
801 | /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); | |
802 | /// ``` | |
c34b1796 | 803 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 804 | pub fn to_ipv6_mapped(&self) -> Ipv6Addr { |
9fa01778 XL |
805 | let octets = self.octets(); |
806 | Ipv6Addr::from([ | |
807 | 0, 0, 0, 0, | |
808 | 0, 0, 0, 0, | |
809 | 0, 0, 0xFF, 0xFF, | |
810 | octets[0], octets[1], octets[2], octets[3], | |
811 | ]) | |
85aaf69f | 812 | } |
85aaf69f SL |
813 | } |
814 | ||
c30ab7b3 | 815 | #[stable(feature = "ip_addr", since = "1.7.0")] |
c34b1796 | 816 | impl fmt::Display for IpAddr { |
532ac7d7 | 817 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
b7449926 XL |
818 | match self { |
819 | IpAddr::V4(ip) => ip.fmt(fmt), | |
820 | IpAddr::V6(ip) => ip.fmt(fmt), | |
c34b1796 AL |
821 | } |
822 | } | |
823 | } | |
824 | ||
32a655c1 SL |
825 | #[stable(feature = "ip_from_ip", since = "1.16.0")] |
826 | impl From<Ipv4Addr> for IpAddr { | |
827 | fn from(ipv4: Ipv4Addr) -> IpAddr { | |
828 | IpAddr::V4(ipv4) | |
829 | } | |
830 | } | |
831 | ||
832 | #[stable(feature = "ip_from_ip", since = "1.16.0")] | |
833 | impl From<Ipv6Addr> for IpAddr { | |
834 | fn from(ipv6: Ipv6Addr) -> IpAddr { | |
835 | IpAddr::V6(ipv6) | |
836 | } | |
837 | } | |
838 | ||
c34b1796 | 839 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 840 | impl fmt::Display for Ipv4Addr { |
532ac7d7 | 841 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
85aaf69f SL |
842 | let octets = self.octets(); |
843 | write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) | |
844 | } | |
845 | } | |
846 | ||
c34b1796 | 847 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 848 | impl fmt::Debug for Ipv4Addr { |
532ac7d7 | 849 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
85aaf69f SL |
850 | fmt::Display::fmt(self, fmt) |
851 | } | |
852 | } | |
853 | ||
c34b1796 | 854 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
855 | impl Clone for Ipv4Addr { |
856 | fn clone(&self) -> Ipv4Addr { *self } | |
857 | } | |
858 | ||
c34b1796 | 859 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
860 | impl PartialEq for Ipv4Addr { |
861 | fn eq(&self, other: &Ipv4Addr) -> bool { | |
862 | self.inner.s_addr == other.inner.s_addr | |
863 | } | |
864 | } | |
c34b1796 | 865 | |
7cac9316 | 866 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
867 | impl PartialEq<Ipv4Addr> for IpAddr { |
868 | fn eq(&self, other: &Ipv4Addr) -> bool { | |
b7449926 XL |
869 | match self { |
870 | IpAddr::V4(v4) => v4 == other, | |
32a655c1 SL |
871 | IpAddr::V6(_) => false, |
872 | } | |
873 | } | |
874 | } | |
875 | ||
7cac9316 | 876 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
877 | impl PartialEq<IpAddr> for Ipv4Addr { |
878 | fn eq(&self, other: &IpAddr) -> bool { | |
b7449926 XL |
879 | match other { |
880 | IpAddr::V4(v4) => self == v4, | |
32a655c1 SL |
881 | IpAddr::V6(_) => false, |
882 | } | |
883 | } | |
884 | } | |
885 | ||
c34b1796 | 886 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
887 | impl Eq for Ipv4Addr {} |
888 | ||
85aaf69f SL |
889 | #[stable(feature = "rust1", since = "1.0.0")] |
890 | impl hash::Hash for Ipv4Addr { | |
891 | fn hash<H: hash::Hasher>(&self, s: &mut H) { | |
ff7c6d11 XL |
892 | // `inner` is #[repr(packed)], so we need to copy `s_addr`. |
893 | {self.inner.s_addr}.hash(s) | |
85aaf69f SL |
894 | } |
895 | } | |
896 | ||
c34b1796 | 897 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
898 | impl PartialOrd for Ipv4Addr { |
899 | fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { | |
900 | Some(self.cmp(other)) | |
901 | } | |
902 | } | |
903 | ||
7cac9316 | 904 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
905 | impl PartialOrd<Ipv4Addr> for IpAddr { |
906 | fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { | |
b7449926 XL |
907 | match self { |
908 | IpAddr::V4(v4) => v4.partial_cmp(other), | |
32a655c1 SL |
909 | IpAddr::V6(_) => Some(Ordering::Greater), |
910 | } | |
911 | } | |
912 | } | |
913 | ||
7cac9316 | 914 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
915 | impl PartialOrd<IpAddr> for Ipv4Addr { |
916 | fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { | |
b7449926 XL |
917 | match other { |
918 | IpAddr::V4(v4) => self.partial_cmp(v4), | |
32a655c1 SL |
919 | IpAddr::V6(_) => Some(Ordering::Less), |
920 | } | |
921 | } | |
922 | } | |
923 | ||
c34b1796 | 924 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
925 | impl Ord for Ipv4Addr { |
926 | fn cmp(&self, other: &Ipv4Addr) -> Ordering { | |
b7449926 | 927 | u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) |
85aaf69f SL |
928 | } |
929 | } | |
930 | ||
92a42be0 SL |
931 | impl AsInner<c::in_addr> for Ipv4Addr { |
932 | fn as_inner(&self) -> &c::in_addr { &self.inner } | |
85aaf69f | 933 | } |
92a42be0 SL |
934 | impl FromInner<c::in_addr> for Ipv4Addr { |
935 | fn from_inner(addr: c::in_addr) -> Ipv4Addr { | |
85aaf69f SL |
936 | Ipv4Addr { inner: addr } |
937 | } | |
938 | } | |
939 | ||
d9579d0f AL |
940 | #[stable(feature = "ip_u32", since = "1.1.0")] |
941 | impl From<Ipv4Addr> for u32 { | |
9fa01778 | 942 | /// Converts an `Ipv4Addr` into a host byte order `u32`. |
0531ce1d XL |
943 | /// |
944 | /// # Examples | |
945 | /// | |
946 | /// ``` | |
947 | /// use std::net::Ipv4Addr; | |
948 | /// | |
949 | /// let addr = Ipv4Addr::new(13, 12, 11, 10); | |
950 | /// assert_eq!(0x0d0c0b0au32, u32::from(addr)); | |
951 | /// ``` | |
d9579d0f AL |
952 | fn from(ip: Ipv4Addr) -> u32 { |
953 | let ip = ip.octets(); | |
9fa01778 | 954 | u32::from_be_bytes(ip) |
d9579d0f AL |
955 | } |
956 | } | |
957 | ||
958 | #[stable(feature = "ip_u32", since = "1.1.0")] | |
959 | impl From<u32> for Ipv4Addr { | |
9fa01778 | 960 | /// Converts a host byte order `u32` into an `Ipv4Addr`. |
0531ce1d XL |
961 | /// |
962 | /// # Examples | |
963 | /// | |
964 | /// ``` | |
965 | /// use std::net::Ipv4Addr; | |
966 | /// | |
967 | /// let addr = Ipv4Addr::from(0x0d0c0b0au32); | |
968 | /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); | |
969 | /// ``` | |
d9579d0f | 970 | fn from(ip: u32) -> Ipv4Addr { |
9fa01778 | 971 | Ipv4Addr::from(ip.to_be_bytes()) |
d9579d0f AL |
972 | } |
973 | } | |
974 | ||
54a0048b SL |
975 | #[stable(feature = "from_slice_v4", since = "1.9.0")] |
976 | impl From<[u8; 4]> for Ipv4Addr { | |
0531ce1d XL |
977 | /// # Examples |
978 | /// | |
979 | /// ``` | |
980 | /// use std::net::Ipv4Addr; | |
981 | /// | |
982 | /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); | |
983 | /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); | |
984 | /// ``` | |
54a0048b SL |
985 | fn from(octets: [u8; 4]) -> Ipv4Addr { |
986 | Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) | |
987 | } | |
988 | } | |
989 | ||
8bb4bdeb XL |
990 | #[stable(feature = "ip_from_slice", since = "1.17.0")] |
991 | impl From<[u8; 4]> for IpAddr { | |
9fa01778 | 992 | /// Creates an `IpAddr::V4` from a four element byte array. |
0531ce1d XL |
993 | /// |
994 | /// # Examples | |
995 | /// | |
996 | /// ``` | |
997 | /// use std::net::{IpAddr, Ipv4Addr}; | |
998 | /// | |
999 | /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); | |
1000 | /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); | |
1001 | /// ``` | |
8bb4bdeb XL |
1002 | fn from(octets: [u8; 4]) -> IpAddr { |
1003 | IpAddr::V4(Ipv4Addr::from(octets)) | |
1004 | } | |
1005 | } | |
1006 | ||
85aaf69f | 1007 | impl Ipv6Addr { |
9346a6ac | 1008 | /// Creates a new IPv6 address from eight 16-bit segments. |
85aaf69f | 1009 | /// |
a1dfa0c6 | 1010 | /// The result will represent the IP address `a:b:c:d:e:f:g:h`. |
476ff2be SL |
1011 | /// |
1012 | /// # Examples | |
1013 | /// | |
1014 | /// ``` | |
1015 | /// use std::net::Ipv6Addr; | |
1016 | /// | |
1017 | /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); | |
1018 | /// ``` | |
c34b1796 | 1019 | #[stable(feature = "rust1", since = "1.0.0")] |
60c5eb7d | 1020 | #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv6", since = "1.32.0"))] |
b7449926 XL |
1021 | pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, |
1022 | g: u16, h: u16) -> Ipv6Addr { | |
1023 | Ipv6Addr { | |
1024 | inner: c::in6_addr { | |
1025 | s6_addr: [ | |
1026 | (a >> 8) as u8, a as u8, | |
1027 | (b >> 8) as u8, b as u8, | |
1028 | (c >> 8) as u8, c as u8, | |
1029 | (d >> 8) as u8, d as u8, | |
1030 | (e >> 8) as u8, e as u8, | |
1031 | (f >> 8) as u8, f as u8, | |
1032 | (g >> 8) as u8, g as u8, | |
1033 | (h >> 8) as u8, h as u8 | |
1034 | ], | |
1035 | } | |
1036 | } | |
1037 | ||
85aaf69f SL |
1038 | } |
1039 | ||
b7449926 | 1040 | /// An IPv6 address representing localhost: `::1`. |
ea8adc8c XL |
1041 | /// |
1042 | /// # Examples | |
1043 | /// | |
1044 | /// ``` | |
ea8adc8c XL |
1045 | /// use std::net::Ipv6Addr; |
1046 | /// | |
b7449926 | 1047 | /// let addr = Ipv6Addr::LOCALHOST; |
ea8adc8c XL |
1048 | /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); |
1049 | /// ``` | |
b7449926 XL |
1050 | #[stable(feature = "ip_constructors", since = "1.30.0")] |
1051 | pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); | |
ea8adc8c | 1052 | |
b7449926 | 1053 | /// An IPv6 address representing the unspecified address: `::` |
ea8adc8c XL |
1054 | /// |
1055 | /// # Examples | |
1056 | /// | |
1057 | /// ``` | |
ea8adc8c XL |
1058 | /// use std::net::Ipv6Addr; |
1059 | /// | |
b7449926 | 1060 | /// let addr = Ipv6Addr::UNSPECIFIED; |
ea8adc8c XL |
1061 | /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); |
1062 | /// ``` | |
b7449926 XL |
1063 | #[stable(feature = "ip_constructors", since = "1.30.0")] |
1064 | pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); | |
ea8adc8c | 1065 | |
bd371182 | 1066 | /// Returns the eight 16-bit segments that make up this address. |
476ff2be SL |
1067 | /// |
1068 | /// # Examples | |
1069 | /// | |
1070 | /// ``` | |
1071 | /// use std::net::Ipv6Addr; | |
1072 | /// | |
1073 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), | |
1074 | /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); | |
1075 | /// ``` | |
c34b1796 | 1076 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 1077 | pub fn segments(&self) -> [u16; 8] { |
92a42be0 SL |
1078 | let arr = &self.inner.s6_addr; |
1079 | [ | |
9fa01778 XL |
1080 | u16::from_be_bytes([arr[0], arr[1]]), |
1081 | u16::from_be_bytes([arr[2], arr[3]]), | |
1082 | u16::from_be_bytes([arr[4], arr[5]]), | |
1083 | u16::from_be_bytes([arr[6], arr[7]]), | |
1084 | u16::from_be_bytes([arr[8], arr[9]]), | |
1085 | u16::from_be_bytes([arr[10], arr[11]]), | |
1086 | u16::from_be_bytes([arr[12], arr[13]]), | |
1087 | u16::from_be_bytes([arr[14], arr[15]]), | |
92a42be0 | 1088 | ] |
85aaf69f SL |
1089 | } |
1090 | ||
cc61c64b | 1091 | /// Returns [`true`] for the special 'unspecified' address (::). |
9cc50fc6 | 1092 | /// |
cc61c64b | 1093 | /// This property is defined in [IETF RFC 4291]. |
476ff2be | 1094 | /// |
cc61c64b XL |
1095 | /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
1096 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
1097 | /// |
1098 | /// # Examples | |
1099 | /// | |
1100 | /// ``` | |
1101 | /// use std::net::Ipv6Addr; | |
1102 | /// | |
1103 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); | |
1104 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); | |
1105 | /// ``` | |
9cc50fc6 | 1106 | #[stable(since = "1.7.0", feature = "ip_17")] |
85aaf69f SL |
1107 | pub fn is_unspecified(&self) -> bool { |
1108 | self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] | |
1109 | } | |
1110 | ||
cc61c64b | 1111 | /// Returns [`true`] if this is a loopback address (::1). |
9cc50fc6 | 1112 | /// |
cc61c64b | 1113 | /// This property is defined in [IETF RFC 4291]. |
476ff2be | 1114 | /// |
cc61c64b XL |
1115 | /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
1116 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
1117 | /// |
1118 | /// # Examples | |
1119 | /// | |
1120 | /// ``` | |
1121 | /// use std::net::Ipv6Addr; | |
1122 | /// | |
1123 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); | |
1124 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); | |
1125 | /// ``` | |
9cc50fc6 | 1126 | #[stable(since = "1.7.0", feature = "ip_17")] |
85aaf69f SL |
1127 | pub fn is_loopback(&self) -> bool { |
1128 | self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] | |
1129 | } | |
1130 | ||
cc61c64b | 1131 | /// Returns [`true`] if the address appears to be globally routable. |
85aaf69f | 1132 | /// |
cc61c64b | 1133 | /// The following return [`false`]: |
d9579d0f AL |
1134 | /// |
1135 | /// - the loopback address | |
60c5eb7d | 1136 | /// - link-local and unique local unicast addresses |
d9579d0f | 1137 | /// - interface-, link-, realm-, admin- and site-local multicast addresses |
476ff2be | 1138 | /// |
cc61c64b XL |
1139 | /// [`true`]: ../../std/primitive.bool.html |
1140 | /// [`false`]: ../../std/primitive.bool.html | |
1141 | /// | |
476ff2be SL |
1142 | /// # Examples |
1143 | /// | |
1144 | /// ``` | |
1145 | /// #![feature(ip)] | |
1146 | /// | |
1147 | /// use std::net::Ipv6Addr; | |
1148 | /// | |
e74abb32 XL |
1149 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); |
1150 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); | |
1151 | /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); | |
476ff2be | 1152 | /// ``` |
85aaf69f SL |
1153 | pub fn is_global(&self) -> bool { |
1154 | match self.multicast_scope() { | |
1155 | Some(Ipv6MulticastScope::Global) => true, | |
1156 | None => self.is_unicast_global(), | |
1157 | _ => false | |
1158 | } | |
1159 | } | |
1160 | ||
dc9dc135 | 1161 | /// Returns [`true`] if this is a unique local address (`fc00::/7`). |
85aaf69f | 1162 | /// |
cc61c64b | 1163 | /// This property is defined in [IETF RFC 4193]. |
476ff2be | 1164 | /// |
cc61c64b XL |
1165 | /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 |
1166 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
1167 | /// |
1168 | /// # Examples | |
1169 | /// | |
1170 | /// ``` | |
1171 | /// #![feature(ip)] | |
1172 | /// | |
1173 | /// use std::net::Ipv6Addr; | |
1174 | /// | |
e74abb32 XL |
1175 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); |
1176 | /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); | |
476ff2be | 1177 | /// ``` |
85aaf69f SL |
1178 | pub fn is_unique_local(&self) -> bool { |
1179 | (self.segments()[0] & 0xfe00) == 0xfc00 | |
1180 | } | |
1181 | ||
dc9dc135 | 1182 | /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). |
3157f602 | 1183 | /// |
dc9dc135 XL |
1184 | /// A common mis-conception is to think that "unicast link-local addresses start with |
1185 | /// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses: | |
1186 | /// | |
1187 | /// ```no_rust | |
1188 | /// | 10 | | |
1189 | /// | bits | 54 bits | 64 bits | | |
1190 | /// +----------+-------------------------+----------------------------+ | |
1191 | /// |1111111010| 0 | interface ID | | |
1192 | /// +----------+-------------------------+----------------------------+ | |
1193 | /// ``` | |
1194 | /// | |
1195 | /// This method validates the format defined in the RFC and won't recognize the following | |
1196 | /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. | |
1197 | /// If you need a less strict validation use [`is_unicast_link_local()`] instead. | |
1198 | /// | |
1199 | /// # Examples | |
1200 | /// | |
1201 | /// ``` | |
1202 | /// #![feature(ip)] | |
1203 | /// | |
1204 | /// use std::net::Ipv6Addr; | |
1205 | /// | |
e74abb32 XL |
1206 | /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); |
1207 | /// assert!(ip.is_unicast_link_local_strict()); | |
dc9dc135 | 1208 | /// |
e74abb32 XL |
1209 | /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); |
1210 | /// assert!(ip.is_unicast_link_local_strict()); | |
dc9dc135 | 1211 | /// |
e74abb32 XL |
1212 | /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); |
1213 | /// assert!(!ip.is_unicast_link_local_strict()); | |
1214 | /// assert!(ip.is_unicast_link_local()); | |
dc9dc135 | 1215 | /// |
e74abb32 XL |
1216 | /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); |
1217 | /// assert!(!ip.is_unicast_link_local_strict()); | |
1218 | /// assert!(ip.is_unicast_link_local()); | |
dc9dc135 XL |
1219 | /// ``` |
1220 | /// | |
1221 | /// # See also | |
1222 | /// | |
1223 | /// - [IETF RFC 4291 section 2.5.6] | |
1224 | /// - [RFC 4291 errata 4406] | |
1225 | /// - [`is_unicast_link_local()`] | |
476ff2be | 1226 | /// |
cc61c64b | 1227 | /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
dc9dc135 | 1228 | /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 |
cc61c64b | 1229 | /// [`true`]: ../../std/primitive.bool.html |
dc9dc135 XL |
1230 | /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 |
1231 | /// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local | |
1232 | /// | |
1233 | pub fn is_unicast_link_local_strict(&self) -> bool { | |
1234 | (self.segments()[0] & 0xffff) == 0xfe80 | |
1235 | && (self.segments()[1] & 0xffff) == 0 | |
1236 | && (self.segments()[2] & 0xffff) == 0 | |
1237 | && (self.segments()[3] & 0xffff) == 0 | |
1238 | } | |
1239 | ||
1240 | /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). | |
1241 | /// | |
1242 | /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], | |
1243 | /// i.e. addresses with the following format: | |
1244 | /// | |
1245 | /// ```no_rust | |
1246 | /// | 10 | | |
1247 | /// | bits | 54 bits | 64 bits | | |
1248 | /// +----------+-------------------------+----------------------------+ | |
1249 | /// |1111111010| arbitratry value | interface ID | | |
1250 | /// +----------+-------------------------+----------------------------+ | |
1251 | /// ``` | |
1252 | /// | |
1253 | /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be | |
1254 | /// unicast link-local addresses, whereas [`is_unicast_link_local_strict()`] does not. If you | |
1255 | /// need a strict validation fully compliant with the RFC, use | |
1256 | /// [`is_unicast_link_local_strict()`]. | |
476ff2be SL |
1257 | /// |
1258 | /// # Examples | |
1259 | /// | |
1260 | /// ``` | |
1261 | /// #![feature(ip)] | |
1262 | /// | |
1263 | /// use std::net::Ipv6Addr; | |
1264 | /// | |
e74abb32 XL |
1265 | /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); |
1266 | /// assert!(ip.is_unicast_link_local()); | |
dc9dc135 | 1267 | /// |
e74abb32 XL |
1268 | /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); |
1269 | /// assert!(ip.is_unicast_link_local()); | |
dc9dc135 | 1270 | /// |
e74abb32 XL |
1271 | /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); |
1272 | /// assert!(ip.is_unicast_link_local()); | |
1273 | /// assert!(!ip.is_unicast_link_local_strict()); | |
dc9dc135 | 1274 | /// |
e74abb32 XL |
1275 | /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); |
1276 | /// assert!(ip.is_unicast_link_local()); | |
1277 | /// assert!(!ip.is_unicast_link_local_strict()); | |
476ff2be | 1278 | /// ``` |
dc9dc135 XL |
1279 | /// |
1280 | /// # See also | |
1281 | /// | |
1282 | /// - [IETF RFC 4291 section 2.4] | |
1283 | /// - [RFC 4291 errata 4406] | |
1284 | /// | |
1285 | /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 | |
1286 | /// [`true`]: ../../std/primitive.bool.html | |
1287 | /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 | |
1288 | /// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict | |
1289 | /// | |
85aaf69f SL |
1290 | pub fn is_unicast_link_local(&self) -> bool { |
1291 | (self.segments()[0] & 0xffc0) == 0xfe80 | |
1292 | } | |
1293 | ||
dc9dc135 XL |
1294 | /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The |
1295 | /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: | |
1296 | /// | |
1297 | /// ```no_rust | |
1298 | /// | 10 | | |
1299 | /// | bits | 54 bits | 64 bits | | |
1300 | /// +----------+-------------------------+----------------------------+ | |
1301 | /// |1111111011| subnet ID | interface ID | | |
1302 | /// +----------+-------------------------+----------------------------+ | |
1303 | /// ``` | |
476ff2be | 1304 | /// |
cc61c64b | 1305 | /// [`true`]: ../../std/primitive.bool.html |
dc9dc135 | 1306 | /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 |
cc61c64b | 1307 | /// |
476ff2be SL |
1308 | /// # Examples |
1309 | /// | |
1310 | /// ``` | |
1311 | /// #![feature(ip)] | |
1312 | /// | |
1313 | /// use std::net::Ipv6Addr; | |
1314 | /// | |
e74abb32 XL |
1315 | /// assert_eq!( |
1316 | /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), | |
1317 | /// false | |
1318 | /// ); | |
1319 | /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); | |
476ff2be | 1320 | /// ``` |
dc9dc135 XL |
1321 | /// |
1322 | /// # Warning | |
1323 | /// | |
1324 | /// As per [RFC 3879], the whole `FEC0::/10` prefix is | |
1325 | /// deprecated. New software must not support site-local | |
1326 | /// addresses. | |
1327 | /// | |
1328 | /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 | |
85aaf69f SL |
1329 | pub fn is_unicast_site_local(&self) -> bool { |
1330 | (self.segments()[0] & 0xffc0) == 0xfec0 | |
1331 | } | |
1332 | ||
cc61c64b | 1333 | /// Returns [`true`] if this is an address reserved for documentation |
3157f602 XL |
1334 | /// (2001:db8::/32). |
1335 | /// | |
cc61c64b | 1336 | /// This property is defined in [IETF RFC 3849]. |
476ff2be | 1337 | /// |
cc61c64b XL |
1338 | /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 |
1339 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be SL |
1340 | /// |
1341 | /// # Examples | |
1342 | /// | |
1343 | /// ``` | |
1344 | /// #![feature(ip)] | |
1345 | /// | |
1346 | /// use std::net::Ipv6Addr; | |
1347 | /// | |
e74abb32 XL |
1348 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); |
1349 | /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); | |
476ff2be | 1350 | /// ``` |
54a0048b SL |
1351 | pub fn is_documentation(&self) -> bool { |
1352 | (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) | |
1353 | } | |
1354 | ||
cc61c64b | 1355 | /// Returns [`true`] if the address is a globally routable unicast address. |
85aaf69f | 1356 | /// |
d9579d0f AL |
1357 | /// The following return false: |
1358 | /// | |
1359 | /// - the loopback address | |
1360 | /// - the link-local addresses | |
d9579d0f | 1361 | /// - unique local addresses |
54a0048b SL |
1362 | /// - the unspecified address |
1363 | /// - the address range reserved for documentation | |
476ff2be | 1364 | /// |
dc9dc135 XL |
1365 | /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] |
1366 | /// | |
1367 | /// ```no_rust | |
1368 | /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer | |
1369 | /// be supported in new implementations (i.e., new implementations must treat this prefix as | |
1370 | /// Global Unicast). | |
1371 | /// ``` | |
1372 | /// | |
cc61c64b | 1373 | /// [`true`]: ../../std/primitive.bool.html |
dc9dc135 | 1374 | /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 |
cc61c64b | 1375 | /// |
476ff2be SL |
1376 | /// # Examples |
1377 | /// | |
1378 | /// ``` | |
1379 | /// #![feature(ip)] | |
1380 | /// | |
1381 | /// use std::net::Ipv6Addr; | |
1382 | /// | |
e74abb32 XL |
1383 | /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); |
1384 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); | |
476ff2be | 1385 | /// ``` |
85aaf69f SL |
1386 | pub fn is_unicast_global(&self) -> bool { |
1387 | !self.is_multicast() | |
dc9dc135 XL |
1388 | && !self.is_loopback() |
1389 | && !self.is_unicast_link_local() | |
1390 | && !self.is_unique_local() | |
1391 | && !self.is_unspecified() | |
1392 | && !self.is_documentation() | |
85aaf69f SL |
1393 | } |
1394 | ||
1395 | /// Returns the address's multicast scope if the address is multicast. | |
476ff2be SL |
1396 | /// |
1397 | /// # Examples | |
1398 | /// | |
1399 | /// ``` | |
1400 | /// #![feature(ip)] | |
1401 | /// | |
1402 | /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; | |
1403 | /// | |
e74abb32 XL |
1404 | /// assert_eq!( |
1405 | /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), | |
1406 | /// Some(Ipv6MulticastScope::Global) | |
1407 | /// ); | |
1408 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); | |
476ff2be | 1409 | /// ``` |
85aaf69f SL |
1410 | pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> { |
1411 | if self.is_multicast() { | |
1412 | match self.segments()[0] & 0x000f { | |
1413 | 1 => Some(Ipv6MulticastScope::InterfaceLocal), | |
1414 | 2 => Some(Ipv6MulticastScope::LinkLocal), | |
1415 | 3 => Some(Ipv6MulticastScope::RealmLocal), | |
1416 | 4 => Some(Ipv6MulticastScope::AdminLocal), | |
1417 | 5 => Some(Ipv6MulticastScope::SiteLocal), | |
1418 | 8 => Some(Ipv6MulticastScope::OrganizationLocal), | |
1419 | 14 => Some(Ipv6MulticastScope::Global), | |
1420 | _ => None | |
1421 | } | |
1422 | } else { | |
1423 | None | |
1424 | } | |
1425 | } | |
1426 | ||
cc61c64b XL |
1427 | /// Returns [`true`] if this is a multicast address (ff00::/8). |
1428 | /// | |
1429 | /// This property is defined by [IETF RFC 4291]. | |
85aaf69f | 1430 | /// |
cc61c64b XL |
1431 | /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
1432 | /// [`true`]: ../../std/primitive.bool.html | |
476ff2be | 1433 | /// |
476ff2be SL |
1434 | /// # Examples |
1435 | /// | |
1436 | /// ``` | |
1437 | /// use std::net::Ipv6Addr; | |
1438 | /// | |
1439 | /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); | |
1440 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); | |
1441 | /// ``` | |
9cc50fc6 | 1442 | #[stable(since = "1.7.0", feature = "ip_17")] |
85aaf69f SL |
1443 | pub fn is_multicast(&self) -> bool { |
1444 | (self.segments()[0] & 0xff00) == 0xff00 | |
1445 | } | |
1446 | ||
cc61c64b | 1447 | /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is |
85aaf69f SL |
1448 | /// neither IPv4-compatible or IPv4-mapped. |
1449 | /// | |
1450 | /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d | |
476ff2be | 1451 | /// |
cc61c64b XL |
1452 | /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html |
1453 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
1454 | /// | |
1455 | /// # Examples | |
1456 | /// | |
476ff2be SL |
1457 | /// ``` |
1458 | /// use std::net::{Ipv4Addr, Ipv6Addr}; | |
1459 | /// | |
1460 | /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); | |
1461 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), | |
1462 | /// Some(Ipv4Addr::new(192, 10, 2, 255))); | |
1463 | /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), | |
1464 | /// Some(Ipv4Addr::new(0, 0, 0, 1))); | |
1465 | /// ``` | |
c34b1796 | 1466 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
1467 | pub fn to_ipv4(&self) -> Option<Ipv4Addr> { |
1468 | match self.segments() { | |
1469 | [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => { | |
1470 | Some(Ipv4Addr::new((g >> 8) as u8, g as u8, | |
1471 | (h >> 8) as u8, h as u8)) | |
1472 | }, | |
1473 | _ => None | |
1474 | } | |
1475 | } | |
54a0048b SL |
1476 | |
1477 | /// Returns the sixteen eight-bit integers the IPv6 address consists of. | |
476ff2be SL |
1478 | /// |
1479 | /// ``` | |
1480 | /// use std::net::Ipv6Addr; | |
1481 | /// | |
1482 | /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), | |
1483 | /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); | |
1484 | /// ``` | |
5bcae85e | 1485 | #[stable(feature = "ipv6_to_octets", since = "1.12.0")] |
60c5eb7d | 1486 | #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv6", since = "1.32.0"))] |
a1dfa0c6 | 1487 | pub const fn octets(&self) -> [u8; 16] { |
54a0048b SL |
1488 | self.inner.s6_addr |
1489 | } | |
85aaf69f SL |
1490 | } |
1491 | ||
c34b1796 | 1492 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 1493 | impl fmt::Display for Ipv6Addr { |
532ac7d7 | 1494 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
85aaf69f SL |
1495 | match self.segments() { |
1496 | // We need special cases for :: and ::1, otherwise they're formatted | |
1497 | // as ::0.0.0.[01] | |
1498 | [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"), | |
1499 | [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"), | |
1500 | // Ipv4 Compatible address | |
1501 | [0, 0, 0, 0, 0, 0, g, h] => { | |
1502 | write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8, | |
1503 | (h >> 8) as u8, h as u8) | |
1504 | } | |
1505 | // Ipv4-Mapped address | |
1506 | [0, 0, 0, 0, 0, 0xffff, g, h] => { | |
1507 | write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8, | |
1508 | (h >> 8) as u8, h as u8) | |
1509 | }, | |
1510 | _ => { | |
1511 | fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { | |
1512 | let mut longest_span_len = 0; | |
1513 | let mut longest_span_at = 0; | |
1514 | let mut cur_span_len = 0; | |
1515 | let mut cur_span_at = 0; | |
1516 | ||
c34b1796 | 1517 | for i in 0..8 { |
85aaf69f SL |
1518 | if segments[i] == 0 { |
1519 | if cur_span_len == 0 { | |
1520 | cur_span_at = i; | |
1521 | } | |
1522 | ||
1523 | cur_span_len += 1; | |
1524 | ||
1525 | if cur_span_len > longest_span_len { | |
1526 | longest_span_len = cur_span_len; | |
1527 | longest_span_at = cur_span_at; | |
1528 | } | |
1529 | } else { | |
1530 | cur_span_len = 0; | |
1531 | cur_span_at = 0; | |
1532 | } | |
1533 | } | |
1534 | ||
1535 | (longest_span_at, longest_span_len) | |
1536 | } | |
1537 | ||
1538 | let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); | |
1539 | ||
1540 | if zeros_len > 1 { | |
532ac7d7 | 1541 | fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
92a42be0 | 1542 | if !segments.is_empty() { |
54a0048b | 1543 | write!(fmt, "{:x}", segments[0])?; |
92a42be0 | 1544 | for &seg in &segments[1..] { |
54a0048b | 1545 | write!(fmt, ":{:x}", seg)?; |
92a42be0 SL |
1546 | } |
1547 | } | |
1548 | Ok(()) | |
85aaf69f SL |
1549 | } |
1550 | ||
54a0048b SL |
1551 | fmt_subslice(&self.segments()[..zeros_at], fmt)?; |
1552 | fmt.write_str("::")?; | |
92a42be0 | 1553 | fmt_subslice(&self.segments()[zeros_at + zeros_len..], fmt) |
85aaf69f SL |
1554 | } else { |
1555 | let &[a, b, c, d, e, f, g, h] = &self.segments(); | |
1556 | write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", | |
1557 | a, b, c, d, e, f, g, h) | |
1558 | } | |
1559 | } | |
1560 | } | |
1561 | } | |
1562 | } | |
1563 | ||
c34b1796 | 1564 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 1565 | impl fmt::Debug for Ipv6Addr { |
532ac7d7 | 1566 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
85aaf69f SL |
1567 | fmt::Display::fmt(self, fmt) |
1568 | } | |
1569 | } | |
1570 | ||
c34b1796 | 1571 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
1572 | impl Clone for Ipv6Addr { |
1573 | fn clone(&self) -> Ipv6Addr { *self } | |
1574 | } | |
1575 | ||
c34b1796 | 1576 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
1577 | impl PartialEq for Ipv6Addr { |
1578 | fn eq(&self, other: &Ipv6Addr) -> bool { | |
1579 | self.inner.s6_addr == other.inner.s6_addr | |
1580 | } | |
1581 | } | |
c34b1796 | 1582 | |
7cac9316 | 1583 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
1584 | impl PartialEq<IpAddr> for Ipv6Addr { |
1585 | fn eq(&self, other: &IpAddr) -> bool { | |
b7449926 | 1586 | match other { |
32a655c1 | 1587 | IpAddr::V4(_) => false, |
b7449926 | 1588 | IpAddr::V6(v6) => self == v6, |
32a655c1 SL |
1589 | } |
1590 | } | |
1591 | } | |
1592 | ||
7cac9316 | 1593 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
1594 | impl PartialEq<Ipv6Addr> for IpAddr { |
1595 | fn eq(&self, other: &Ipv6Addr) -> bool { | |
b7449926 | 1596 | match self { |
32a655c1 | 1597 | IpAddr::V4(_) => false, |
b7449926 | 1598 | IpAddr::V6(v6) => v6 == other, |
32a655c1 SL |
1599 | } |
1600 | } | |
1601 | } | |
1602 | ||
c34b1796 | 1603 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
1604 | impl Eq for Ipv6Addr {} |
1605 | ||
85aaf69f SL |
1606 | #[stable(feature = "rust1", since = "1.0.0")] |
1607 | impl hash::Hash for Ipv6Addr { | |
1608 | fn hash<H: hash::Hasher>(&self, s: &mut H) { | |
1609 | self.inner.s6_addr.hash(s) | |
1610 | } | |
1611 | } | |
1612 | ||
c34b1796 | 1613 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
1614 | impl PartialOrd for Ipv6Addr { |
1615 | fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { | |
1616 | Some(self.cmp(other)) | |
1617 | } | |
1618 | } | |
1619 | ||
7cac9316 | 1620 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
1621 | impl PartialOrd<Ipv6Addr> for IpAddr { |
1622 | fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { | |
b7449926 | 1623 | match self { |
32a655c1 | 1624 | IpAddr::V4(_) => Some(Ordering::Less), |
b7449926 | 1625 | IpAddr::V6(v6) => v6.partial_cmp(other), |
32a655c1 SL |
1626 | } |
1627 | } | |
1628 | } | |
1629 | ||
7cac9316 | 1630 | #[stable(feature = "ip_cmp", since = "1.16.0")] |
32a655c1 SL |
1631 | impl PartialOrd<IpAddr> for Ipv6Addr { |
1632 | fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { | |
b7449926 | 1633 | match other { |
32a655c1 | 1634 | IpAddr::V4(_) => Some(Ordering::Greater), |
b7449926 | 1635 | IpAddr::V6(v6) => self.partial_cmp(v6), |
32a655c1 SL |
1636 | } |
1637 | } | |
1638 | } | |
1639 | ||
c34b1796 | 1640 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
1641 | impl Ord for Ipv6Addr { |
1642 | fn cmp(&self, other: &Ipv6Addr) -> Ordering { | |
92a42be0 | 1643 | self.segments().cmp(&other.segments()) |
85aaf69f SL |
1644 | } |
1645 | } | |
1646 | ||
92a42be0 SL |
1647 | impl AsInner<c::in6_addr> for Ipv6Addr { |
1648 | fn as_inner(&self) -> &c::in6_addr { &self.inner } | |
85aaf69f | 1649 | } |
92a42be0 SL |
1650 | impl FromInner<c::in6_addr> for Ipv6Addr { |
1651 | fn from_inner(addr: c::in6_addr) -> Ipv6Addr { | |
85aaf69f SL |
1652 | Ipv6Addr { inner: addr } |
1653 | } | |
1654 | } | |
9346a6ac | 1655 | |
0531ce1d | 1656 | #[stable(feature = "i128", since = "1.26.0")] |
8bb4bdeb | 1657 | impl From<Ipv6Addr> for u128 { |
9fa01778 XL |
1658 | /// Convert an `Ipv6Addr` into a host byte order `u128`. |
1659 | /// | |
1660 | /// # Examples | |
1661 | /// | |
1662 | /// ``` | |
1663 | /// use std::net::Ipv6Addr; | |
1664 | /// | |
1665 | /// let addr = Ipv6Addr::new( | |
1666 | /// 0x1020, 0x3040, 0x5060, 0x7080, | |
1667 | /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, | |
1668 | /// ); | |
1669 | /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); | |
1670 | /// ``` | |
8bb4bdeb | 1671 | fn from(ip: Ipv6Addr) -> u128 { |
9fa01778 XL |
1672 | let ip = ip.octets(); |
1673 | u128::from_be_bytes(ip) | |
8bb4bdeb XL |
1674 | } |
1675 | } | |
0531ce1d | 1676 | #[stable(feature = "i128", since = "1.26.0")] |
8bb4bdeb | 1677 | impl From<u128> for Ipv6Addr { |
9fa01778 XL |
1678 | /// Convert a host byte order `u128` into an `Ipv6Addr`. |
1679 | /// | |
1680 | /// # Examples | |
1681 | /// | |
1682 | /// ``` | |
1683 | /// use std::net::Ipv6Addr; | |
1684 | /// | |
1685 | /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); | |
1686 | /// assert_eq!( | |
1687 | /// Ipv6Addr::new( | |
1688 | /// 0x1020, 0x3040, 0x5060, 0x7080, | |
1689 | /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, | |
1690 | /// ), | |
1691 | /// addr); | |
1692 | /// ``` | |
8bb4bdeb | 1693 | fn from(ip: u128) -> Ipv6Addr { |
9fa01778 | 1694 | Ipv6Addr::from(ip.to_be_bytes()) |
8bb4bdeb XL |
1695 | } |
1696 | } | |
1697 | ||
54a0048b SL |
1698 | #[stable(feature = "ipv6_from_octets", since = "1.9.0")] |
1699 | impl From<[u8; 16]> for Ipv6Addr { | |
1700 | fn from(octets: [u8; 16]) -> Ipv6Addr { | |
b7449926 | 1701 | let inner = c::in6_addr { s6_addr: octets }; |
54a0048b SL |
1702 | Ipv6Addr::from_inner(inner) |
1703 | } | |
1704 | } | |
1705 | ||
7cac9316 | 1706 | #[stable(feature = "ipv6_from_segments", since = "1.16.0")] |
32a655c1 SL |
1707 | impl From<[u16; 8]> for Ipv6Addr { |
1708 | fn from(segments: [u16; 8]) -> Ipv6Addr { | |
1709 | let [a, b, c, d, e, f, g, h] = segments; | |
1710 | Ipv6Addr::new(a, b, c, d, e, f, g, h) | |
1711 | } | |
1712 | } | |
1713 | ||
8bb4bdeb XL |
1714 | |
1715 | #[stable(feature = "ip_from_slice", since = "1.17.0")] | |
1716 | impl From<[u8; 16]> for IpAddr { | |
9fa01778 | 1717 | /// Creates an `IpAddr::V6` from a sixteen element byte array. |
0531ce1d XL |
1718 | /// |
1719 | /// # Examples | |
1720 | /// | |
1721 | /// ``` | |
1722 | /// use std::net::{IpAddr, Ipv6Addr}; | |
1723 | /// | |
1724 | /// let addr = IpAddr::from([ | |
1725 | /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, | |
1726 | /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, | |
1727 | /// ]); | |
1728 | /// assert_eq!( | |
1729 | /// IpAddr::V6(Ipv6Addr::new( | |
1730 | /// 0x1918, 0x1716, | |
1731 | /// 0x1514, 0x1312, | |
1732 | /// 0x1110, 0x0f0e, | |
1733 | /// 0x0d0c, 0x0b0a | |
1734 | /// )), | |
1735 | /// addr | |
1736 | /// ); | |
1737 | /// ``` | |
8bb4bdeb XL |
1738 | fn from(octets: [u8; 16]) -> IpAddr { |
1739 | IpAddr::V6(Ipv6Addr::from(octets)) | |
1740 | } | |
1741 | } | |
1742 | ||
1743 | #[stable(feature = "ip_from_slice", since = "1.17.0")] | |
1744 | impl From<[u16; 8]> for IpAddr { | |
9fa01778 | 1745 | /// Creates an `IpAddr::V6` from an eight element 16-bit array. |
0531ce1d XL |
1746 | /// |
1747 | /// # Examples | |
1748 | /// | |
1749 | /// ``` | |
1750 | /// use std::net::{IpAddr, Ipv6Addr}; | |
1751 | /// | |
1752 | /// let addr = IpAddr::from([ | |
1753 | /// 525u16, 524u16, 523u16, 522u16, | |
1754 | /// 521u16, 520u16, 519u16, 518u16, | |
1755 | /// ]); | |
1756 | /// assert_eq!( | |
1757 | /// IpAddr::V6(Ipv6Addr::new( | |
1758 | /// 0x20d, 0x20c, | |
1759 | /// 0x20b, 0x20a, | |
1760 | /// 0x209, 0x208, | |
1761 | /// 0x207, 0x206 | |
1762 | /// )), | |
1763 | /// addr | |
1764 | /// ); | |
1765 | /// ``` | |
8bb4bdeb XL |
1766 | fn from(segments: [u16; 8]) -> IpAddr { |
1767 | IpAddr::V6(Ipv6Addr::from(segments)) | |
1768 | } | |
1769 | } | |
1770 | ||
9346a6ac | 1771 | // Tests for this module |
c30ab7b3 | 1772 | #[cfg(all(test, not(target_os = "emscripten")))] |
9346a6ac | 1773 | mod tests { |
532ac7d7 | 1774 | use crate::net::*; |
532ac7d7 | 1775 | use crate::net::test::{tsa, sa6, sa4}; |
dc9dc135 | 1776 | use crate::str::FromStr; |
9346a6ac AL |
1777 | |
1778 | #[test] | |
1779 | fn test_from_str_ipv4() { | |
1780 | assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); | |
1781 | assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); | |
1782 | assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); | |
1783 | ||
1784 | // out of range | |
1785 | let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok(); | |
1786 | assert_eq!(None, none); | |
1787 | // too short | |
1788 | let none: Option<Ipv4Addr> = "255.0.0".parse().ok(); | |
1789 | assert_eq!(None, none); | |
1790 | // too long | |
1791 | let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok(); | |
1792 | assert_eq!(None, none); | |
1793 | // no number between dots | |
1794 | let none: Option<Ipv4Addr> = "255.0..1".parse().ok(); | |
1795 | assert_eq!(None, none); | |
1796 | } | |
1797 | ||
1798 | #[test] | |
1799 | fn test_from_str_ipv6() { | |
1800 | assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); | |
1801 | assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); | |
1802 | ||
1803 | assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); | |
1804 | assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); | |
1805 | ||
1806 | assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), | |
1807 | "2a02:6b8::11:11".parse()); | |
1808 | ||
1809 | // too long group | |
1810 | let none: Option<Ipv6Addr> = "::00000".parse().ok(); | |
1811 | assert_eq!(None, none); | |
1812 | // too short | |
1813 | let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok(); | |
1814 | assert_eq!(None, none); | |
1815 | // too long | |
1816 | let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok(); | |
1817 | assert_eq!(None, none); | |
1818 | // triple colon | |
1819 | let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok(); | |
1820 | assert_eq!(None, none); | |
1821 | // two double colons | |
1822 | let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok(); | |
1823 | assert_eq!(None, none); | |
ff7c6d11 XL |
1824 | // `::` indicating zero groups of zeros |
1825 | let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok(); | |
1826 | assert_eq!(None, none); | |
9346a6ac AL |
1827 | } |
1828 | ||
1829 | #[test] | |
1830 | fn test_from_str_ipv4_in_ipv6() { | |
1831 | assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), | |
1832 | "::192.0.2.33".parse()); | |
1833 | assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), | |
1834 | "::FFFF:192.0.2.33".parse()); | |
1835 | assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), | |
1836 | "64:ff9b::192.0.2.33".parse()); | |
1837 | assert_eq!(Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), | |
1838 | "2001:db8:122:c000:2:2100:192.0.2.33".parse()); | |
1839 | ||
1840 | // colon after v4 | |
1841 | let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok(); | |
1842 | assert_eq!(None, none); | |
1843 | // not enough groups | |
1844 | let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok(); | |
1845 | assert_eq!(None, none); | |
1846 | // too many groups | |
1847 | let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); | |
1848 | assert_eq!(None, none); | |
1849 | } | |
1850 | ||
1851 | #[test] | |
1852 | fn test_from_str_socket_addr() { | |
1853 | assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), | |
1854 | "77.88.21.11:80".parse()); | |
b039eaaf SL |
1855 | assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), |
1856 | "77.88.21.11:80".parse()); | |
9346a6ac AL |
1857 | assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), |
1858 | "[2a02:6b8:0:1::1]:53".parse()); | |
b039eaaf SL |
1859 | assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, |
1860 | 0, 0, 0, 1), 53, 0, 0)), | |
1861 | "[2a02:6b8:0:1::1]:53".parse()); | |
9346a6ac AL |
1862 | assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), |
1863 | "[::127.0.0.1]:22".parse()); | |
b039eaaf SL |
1864 | assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, |
1865 | 0x7F00, 1), 22, 0, 0)), | |
1866 | "[::127.0.0.1]:22".parse()); | |
9346a6ac AL |
1867 | |
1868 | // without port | |
1869 | let none: Option<SocketAddr> = "127.0.0.1".parse().ok(); | |
1870 | assert_eq!(None, none); | |
1871 | // without port | |
1872 | let none: Option<SocketAddr> = "127.0.0.1:".parse().ok(); | |
1873 | assert_eq!(None, none); | |
1874 | // wrong brackets around v4 | |
1875 | let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok(); | |
1876 | assert_eq!(None, none); | |
1877 | // port out of range | |
1878 | let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok(); | |
1879 | assert_eq!(None, none); | |
1880 | } | |
1881 | ||
1882 | #[test] | |
1883 | fn ipv6_addr_to_string() { | |
1884 | // ipv4-mapped address | |
1885 | let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); | |
1886 | assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); | |
1887 | ||
1888 | // ipv4-compatible address | |
1889 | let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); | |
1890 | assert_eq!(a1.to_string(), "::192.0.2.128"); | |
1891 | ||
1892 | // v6 address with no zero segments | |
1893 | assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), | |
1894 | "8:9:a:b:c:d:e:f"); | |
1895 | ||
1896 | // reduce a single run of zeros | |
1897 | assert_eq!("ae::ffff:102:304", | |
1898 | Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()); | |
1899 | ||
1900 | // don't reduce just a single zero segment | |
1901 | assert_eq!("1:2:3:4:5:6:0:8", | |
1902 | Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); | |
1903 | ||
1904 | // 'any' address | |
1905 | assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); | |
1906 | ||
1907 | // loopback address | |
1908 | assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); | |
1909 | ||
1910 | // ends in zeros | |
1911 | assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); | |
1912 | ||
1913 | // two runs of zeros, second one is longer | |
1914 | assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); | |
1915 | ||
1916 | // two runs of zeros, equal length | |
1917 | assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); | |
1918 | } | |
1919 | ||
1920 | #[test] | |
1921 | fn ipv4_to_ipv6() { | |
1922 | assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), | |
1923 | Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()); | |
1924 | assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), | |
1925 | Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()); | |
1926 | } | |
1927 | ||
1928 | #[test] | |
1929 | fn ipv6_to_ipv4() { | |
1930 | assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), | |
1931 | Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); | |
1932 | assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), | |
1933 | Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); | |
1934 | assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), | |
1935 | None); | |
1936 | } | |
1937 | ||
5bcae85e SL |
1938 | #[test] |
1939 | fn ip_properties() { | |
dc9dc135 XL |
1940 | macro_rules! ip { |
1941 | ($s:expr) => { | |
1942 | IpAddr::from_str($s).unwrap() | |
1943 | } | |
5bcae85e SL |
1944 | } |
1945 | ||
dc9dc135 XL |
1946 | macro_rules! check { |
1947 | ($s:expr) => { | |
1948 | check!($s, 0); | |
1949 | }; | |
1950 | ||
1951 | ($s:expr, $mask:expr) => {{ | |
1952 | let unspec: u8 = 1 << 0; | |
1953 | let loopback: u8 = 1 << 1; | |
1954 | let global: u8 = 1 << 2; | |
1955 | let multicast: u8 = 1 << 3; | |
1956 | let doc: u8 = 1 << 4; | |
1957 | ||
1958 | if ($mask & unspec) == unspec { | |
1959 | assert!(ip!($s).is_unspecified()); | |
1960 | } else { | |
1961 | assert!(!ip!($s).is_unspecified()); | |
1962 | } | |
1963 | ||
1964 | if ($mask & loopback) == loopback { | |
1965 | assert!(ip!($s).is_loopback()); | |
1966 | } else { | |
1967 | assert!(!ip!($s).is_loopback()); | |
1968 | } | |
1969 | ||
1970 | if ($mask & global) == global { | |
1971 | assert!(ip!($s).is_global()); | |
1972 | } else { | |
1973 | assert!(!ip!($s).is_global()); | |
1974 | } | |
1975 | ||
1976 | if ($mask & multicast) == multicast { | |
1977 | assert!(ip!($s).is_multicast()); | |
1978 | } else { | |
1979 | assert!(!ip!($s).is_multicast()); | |
1980 | } | |
1981 | ||
1982 | if ($mask & doc) == doc { | |
1983 | assert!(ip!($s).is_documentation()); | |
1984 | } else { | |
1985 | assert!(!ip!($s).is_documentation()); | |
1986 | } | |
1987 | }} | |
5bcae85e SL |
1988 | } |
1989 | ||
dc9dc135 XL |
1990 | let unspec: u8 = 1 << 0; |
1991 | let loopback: u8 = 1 << 1; | |
1992 | let global: u8 = 1 << 2; | |
1993 | let multicast: u8 = 1 << 3; | |
1994 | let doc: u8 = 1 << 4; | |
1995 | ||
1996 | check!("0.0.0.0", unspec); | |
1997 | check!("0.0.0.1"); | |
1998 | check!("0.1.0.0"); | |
1999 | check!("10.9.8.7"); | |
2000 | check!("127.1.2.3", loopback); | |
2001 | check!("172.31.254.253"); | |
2002 | check!("169.254.253.242"); | |
2003 | check!("192.0.2.183", doc); | |
2004 | check!("192.1.2.183", global); | |
2005 | check!("192.168.254.253"); | |
2006 | check!("198.51.100.0", doc); | |
2007 | check!("203.0.113.0", doc); | |
2008 | check!("203.2.113.0", global); | |
2009 | check!("224.0.0.0", global|multicast); | |
2010 | check!("239.255.255.255", global|multicast); | |
2011 | check!("255.255.255.255"); | |
2012 | // make sure benchmarking addresses are not global | |
2013 | check!("198.18.0.0"); | |
2014 | check!("198.18.54.2"); | |
2015 | check!("198.19.255.255"); | |
2016 | // make sure addresses reserved for protocol assignment are not global | |
2017 | check!("192.0.0.0"); | |
2018 | check!("192.0.0.255"); | |
2019 | check!("192.0.0.100"); | |
2020 | // make sure reserved addresses are not global | |
2021 | check!("240.0.0.0"); | |
2022 | check!("251.54.1.76"); | |
2023 | check!("254.255.255.255"); | |
2024 | // make sure shared addresses are not global | |
2025 | check!("100.64.0.0"); | |
2026 | check!("100.127.255.255"); | |
2027 | check!("100.100.100.0"); | |
2028 | ||
2029 | check!("::", unspec); | |
2030 | check!("::1", loopback); | |
2031 | check!("::0.0.0.2", global); | |
2032 | check!("1::", global); | |
2033 | check!("fc00::"); | |
2034 | check!("fdff:ffff::"); | |
2035 | check!("fe80:ffff::"); | |
2036 | check!("febf:ffff::"); | |
2037 | check!("fec0::", global); | |
2038 | check!("ff01::", multicast); | |
2039 | check!("ff02::", multicast); | |
2040 | check!("ff03::", multicast); | |
2041 | check!("ff04::", multicast); | |
2042 | check!("ff05::", multicast); | |
2043 | check!("ff08::", multicast); | |
2044 | check!("ff0e::", global|multicast); | |
2045 | check!("2001:db8:85a3::8a2e:370:7334", doc); | |
2046 | check!("102:304:506:708:90a:b0c:d0e:f10", global); | |
5bcae85e SL |
2047 | } |
2048 | ||
9346a6ac AL |
2049 | #[test] |
2050 | fn ipv4_properties() { | |
dc9dc135 XL |
2051 | macro_rules! ip { |
2052 | ($s:expr) => { | |
2053 | Ipv4Addr::from_str($s).unwrap() | |
2054 | } | |
9346a6ac AL |
2055 | } |
2056 | ||
dc9dc135 XL |
2057 | macro_rules! check { |
2058 | ($s:expr) => { | |
2059 | check!($s, 0); | |
2060 | }; | |
2061 | ||
2062 | ($s:expr, $mask:expr) => {{ | |
2063 | let unspec: u16 = 1 << 0; | |
2064 | let loopback: u16 = 1 << 1; | |
2065 | let private: u16 = 1 << 2; | |
2066 | let link_local: u16 = 1 << 3; | |
2067 | let global: u16 = 1 << 4; | |
2068 | let multicast: u16 = 1 << 5; | |
2069 | let broadcast: u16 = 1 << 6; | |
2070 | let documentation: u16 = 1 << 7; | |
2071 | let benchmarking: u16 = 1 << 8; | |
2072 | let ietf_protocol_assignment: u16 = 1 << 9; | |
2073 | let reserved: u16 = 1 << 10; | |
2074 | let shared: u16 = 1 << 11; | |
2075 | ||
2076 | if ($mask & unspec) == unspec { | |
2077 | assert!(ip!($s).is_unspecified()); | |
2078 | } else { | |
2079 | assert!(!ip!($s).is_unspecified()); | |
2080 | } | |
2081 | ||
2082 | if ($mask & loopback) == loopback { | |
2083 | assert!(ip!($s).is_loopback()); | |
2084 | } else { | |
2085 | assert!(!ip!($s).is_loopback()); | |
2086 | } | |
2087 | ||
2088 | if ($mask & private) == private { | |
2089 | assert!(ip!($s).is_private()); | |
2090 | } else { | |
2091 | assert!(!ip!($s).is_private()); | |
2092 | } | |
2093 | ||
2094 | if ($mask & link_local) == link_local { | |
2095 | assert!(ip!($s).is_link_local()); | |
2096 | } else { | |
2097 | assert!(!ip!($s).is_link_local()); | |
2098 | } | |
2099 | ||
2100 | if ($mask & global) == global { | |
2101 | assert!(ip!($s).is_global()); | |
2102 | } else { | |
2103 | assert!(!ip!($s).is_global()); | |
2104 | } | |
2105 | ||
2106 | if ($mask & multicast) == multicast { | |
2107 | assert!(ip!($s).is_multicast()); | |
2108 | } else { | |
2109 | assert!(!ip!($s).is_multicast()); | |
2110 | } | |
2111 | ||
2112 | if ($mask & broadcast) == broadcast { | |
2113 | assert!(ip!($s).is_broadcast()); | |
2114 | } else { | |
2115 | assert!(!ip!($s).is_broadcast()); | |
2116 | } | |
2117 | ||
2118 | if ($mask & documentation) == documentation { | |
2119 | assert!(ip!($s).is_documentation()); | |
2120 | } else { | |
2121 | assert!(!ip!($s).is_documentation()); | |
2122 | } | |
2123 | ||
2124 | if ($mask & benchmarking) == benchmarking { | |
2125 | assert!(ip!($s).is_benchmarking()); | |
2126 | } else { | |
2127 | assert!(!ip!($s).is_benchmarking()); | |
2128 | } | |
2129 | ||
2130 | if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { | |
2131 | assert!(ip!($s).is_ietf_protocol_assignment()); | |
2132 | } else { | |
2133 | assert!(!ip!($s).is_ietf_protocol_assignment()); | |
2134 | } | |
2135 | ||
2136 | if ($mask & reserved) == reserved { | |
2137 | assert!(ip!($s).is_reserved()); | |
2138 | } else { | |
2139 | assert!(!ip!($s).is_reserved()); | |
2140 | } | |
2141 | ||
2142 | if ($mask & shared) == shared { | |
2143 | assert!(ip!($s).is_shared()); | |
2144 | } else { | |
2145 | assert!(!ip!($s).is_shared()); | |
2146 | } | |
2147 | }} | |
2148 | } | |
2149 | ||
2150 | let unspec: u16 = 1 << 0; | |
2151 | let loopback: u16 = 1 << 1; | |
2152 | let private: u16 = 1 << 2; | |
2153 | let link_local: u16 = 1 << 3; | |
2154 | let global: u16 = 1 << 4; | |
2155 | let multicast: u16 = 1 << 5; | |
2156 | let broadcast: u16 = 1 << 6; | |
2157 | let documentation: u16 = 1 << 7; | |
2158 | let benchmarking: u16 = 1 << 8; | |
2159 | let ietf_protocol_assignment: u16 = 1 << 9; | |
2160 | let reserved: u16 = 1 << 10; | |
2161 | let shared: u16 = 1 << 11; | |
2162 | ||
2163 | check!("0.0.0.0", unspec); | |
2164 | check!("0.0.0.1"); | |
2165 | check!("0.1.0.0"); | |
2166 | check!("10.9.8.7", private); | |
2167 | check!("127.1.2.3", loopback); | |
2168 | check!("172.31.254.253", private); | |
2169 | check!("169.254.253.242", link_local); | |
2170 | check!("192.0.2.183", documentation); | |
2171 | check!("192.1.2.183", global); | |
2172 | check!("192.168.254.253", private); | |
2173 | check!("198.51.100.0", documentation); | |
2174 | check!("203.0.113.0", documentation); | |
2175 | check!("203.2.113.0", global); | |
2176 | check!("224.0.0.0", global|multicast); | |
2177 | check!("239.255.255.255", global|multicast); | |
2178 | check!("255.255.255.255", broadcast); | |
2179 | check!("198.18.0.0", benchmarking); | |
2180 | check!("198.18.54.2", benchmarking); | |
2181 | check!("198.19.255.255", benchmarking); | |
2182 | check!("192.0.0.0", ietf_protocol_assignment); | |
2183 | check!("192.0.0.255", ietf_protocol_assignment); | |
2184 | check!("192.0.0.100", ietf_protocol_assignment); | |
2185 | check!("240.0.0.0", reserved); | |
2186 | check!("251.54.1.76", reserved); | |
2187 | check!("254.255.255.255", reserved); | |
2188 | check!("100.64.0.0", shared); | |
2189 | check!("100.127.255.255", shared); | |
2190 | check!("100.100.100.0", shared); | |
9346a6ac AL |
2191 | } |
2192 | ||
2193 | #[test] | |
2194 | fn ipv6_properties() { | |
dc9dc135 XL |
2195 | macro_rules! ip { |
2196 | ($s:expr) => { | |
2197 | Ipv6Addr::from_str($s).unwrap() | |
2198 | } | |
2199 | } | |
2200 | ||
2201 | macro_rules! check { | |
2202 | ($s:expr, &[$($octet:expr),*], $mask:expr) => { | |
2203 | assert_eq!($s, ip!($s).to_string()); | |
2204 | let octets = &[$($octet),*]; | |
2205 | assert_eq!(&ip!($s).octets(), octets); | |
2206 | assert_eq!(Ipv6Addr::from(*octets), ip!($s)); | |
2207 | ||
2208 | let unspecified: u16 = 1 << 0; | |
2209 | let loopback: u16 = 1 << 1; | |
2210 | let unique_local: u16 = 1 << 2; | |
2211 | let global: u16 = 1 << 3; | |
2212 | let unicast_link_local: u16 = 1 << 4; | |
2213 | let unicast_link_local_strict: u16 = 1 << 5; | |
2214 | let unicast_site_local: u16 = 1 << 6; | |
2215 | let unicast_global: u16 = 1 << 7; | |
2216 | let documentation: u16 = 1 << 8; | |
2217 | let multicast_interface_local: u16 = 1 << 9; | |
2218 | let multicast_link_local: u16 = 1 << 10; | |
2219 | let multicast_realm_local: u16 = 1 << 11; | |
2220 | let multicast_admin_local: u16 = 1 << 12; | |
2221 | let multicast_site_local: u16 = 1 << 13; | |
2222 | let multicast_organization_local: u16 = 1 << 14; | |
2223 | let multicast_global: u16 = 1 << 15; | |
2224 | let multicast: u16 = multicast_interface_local | |
2225 | | multicast_admin_local | |
2226 | | multicast_global | |
2227 | | multicast_link_local | |
2228 | | multicast_realm_local | |
2229 | | multicast_site_local | |
2230 | | multicast_organization_local; | |
2231 | ||
2232 | if ($mask & unspecified) == unspecified { | |
2233 | assert!(ip!($s).is_unspecified()); | |
2234 | } else { | |
2235 | assert!(!ip!($s).is_unspecified()); | |
2236 | } | |
2237 | if ($mask & loopback) == loopback { | |
2238 | assert!(ip!($s).is_loopback()); | |
2239 | } else { | |
2240 | assert!(!ip!($s).is_loopback()); | |
2241 | } | |
2242 | if ($mask & unique_local) == unique_local { | |
2243 | assert!(ip!($s).is_unique_local()); | |
2244 | } else { | |
2245 | assert!(!ip!($s).is_unique_local()); | |
2246 | } | |
2247 | if ($mask & global) == global { | |
2248 | assert!(ip!($s).is_global()); | |
2249 | } else { | |
2250 | assert!(!ip!($s).is_global()); | |
2251 | } | |
2252 | if ($mask & unicast_link_local) == unicast_link_local { | |
2253 | assert!(ip!($s).is_unicast_link_local()); | |
2254 | } else { | |
2255 | assert!(!ip!($s).is_unicast_link_local()); | |
2256 | } | |
2257 | if ($mask & unicast_link_local_strict) == unicast_link_local_strict { | |
2258 | assert!(ip!($s).is_unicast_link_local_strict()); | |
2259 | } else { | |
2260 | assert!(!ip!($s).is_unicast_link_local_strict()); | |
2261 | } | |
2262 | if ($mask & unicast_site_local) == unicast_site_local { | |
2263 | assert!(ip!($s).is_unicast_site_local()); | |
2264 | } else { | |
2265 | assert!(!ip!($s).is_unicast_site_local()); | |
2266 | } | |
2267 | if ($mask & unicast_global) == unicast_global { | |
2268 | assert!(ip!($s).is_unicast_global()); | |
2269 | } else { | |
2270 | assert!(!ip!($s).is_unicast_global()); | |
2271 | } | |
2272 | if ($mask & documentation) == documentation { | |
2273 | assert!(ip!($s).is_documentation()); | |
2274 | } else { | |
2275 | assert!(!ip!($s).is_documentation()); | |
2276 | } | |
2277 | if ($mask & multicast) != 0 { | |
2278 | assert!(ip!($s).multicast_scope().is_some()); | |
2279 | assert!(ip!($s).is_multicast()); | |
2280 | } else { | |
2281 | assert!(ip!($s).multicast_scope().is_none()); | |
2282 | assert!(!ip!($s).is_multicast()); | |
2283 | } | |
2284 | if ($mask & multicast_interface_local) == multicast_interface_local { | |
2285 | assert_eq!(ip!($s).multicast_scope().unwrap(), | |
2286 | Ipv6MulticastScope::InterfaceLocal); | |
2287 | } | |
2288 | if ($mask & multicast_link_local) == multicast_link_local { | |
2289 | assert_eq!(ip!($s).multicast_scope().unwrap(), | |
2290 | Ipv6MulticastScope::LinkLocal); | |
2291 | } | |
2292 | if ($mask & multicast_realm_local) == multicast_realm_local { | |
2293 | assert_eq!(ip!($s).multicast_scope().unwrap(), | |
2294 | Ipv6MulticastScope::RealmLocal); | |
2295 | } | |
2296 | if ($mask & multicast_admin_local) == multicast_admin_local { | |
2297 | assert_eq!(ip!($s).multicast_scope().unwrap(), | |
2298 | Ipv6MulticastScope::AdminLocal); | |
2299 | } | |
2300 | if ($mask & multicast_site_local) == multicast_site_local { | |
2301 | assert_eq!(ip!($s).multicast_scope().unwrap(), | |
2302 | Ipv6MulticastScope::SiteLocal); | |
2303 | } | |
2304 | if ($mask & multicast_organization_local) == multicast_organization_local { | |
2305 | assert_eq!(ip!($s).multicast_scope().unwrap(), | |
2306 | Ipv6MulticastScope::OrganizationLocal); | |
2307 | } | |
2308 | if ($mask & multicast_global) == multicast_global { | |
2309 | assert_eq!(ip!($s).multicast_scope().unwrap(), | |
2310 | Ipv6MulticastScope::Global); | |
2311 | } | |
2312 | } | |
9346a6ac AL |
2313 | } |
2314 | ||
dc9dc135 XL |
2315 | let unspecified: u16 = 1 << 0; |
2316 | let loopback: u16 = 1 << 1; | |
2317 | let unique_local: u16 = 1 << 2; | |
2318 | let global: u16 = 1 << 3; | |
2319 | let unicast_link_local: u16 = 1 << 4; | |
2320 | let unicast_link_local_strict: u16 = 1 << 5; | |
2321 | let unicast_site_local: u16 = 1 << 6; | |
2322 | let unicast_global: u16 = 1 << 7; | |
2323 | let documentation: u16 = 1 << 8; | |
2324 | let multicast_interface_local: u16 = 1 << 9; | |
2325 | let multicast_link_local: u16 = 1 << 10; | |
2326 | let multicast_realm_local: u16 = 1 << 11; | |
2327 | let multicast_admin_local: u16 = 1 << 12; | |
2328 | let multicast_site_local: u16 = 1 << 13; | |
2329 | let multicast_organization_local: u16 = 1 << 14; | |
2330 | let multicast_global: u16 = 1 << 15; | |
2331 | ||
2332 | check!("::", | |
2333 | &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2334 | unspecified); | |
2335 | ||
2336 | check!("::1", | |
2337 | &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], | |
2338 | loopback); | |
2339 | ||
2340 | check!("::0.0.0.2", | |
2341 | &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], | |
2342 | global | unicast_global); | |
2343 | ||
2344 | check!("1::", | |
2345 | &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2346 | global | unicast_global); | |
2347 | ||
2348 | check!("fc00::", | |
2349 | &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2350 | unique_local); | |
2351 | ||
2352 | check!("fdff:ffff::", | |
2353 | &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2354 | unique_local); | |
2355 | ||
2356 | check!("fe80:ffff::", | |
2357 | &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2358 | unicast_link_local); | |
2359 | ||
2360 | check!("fe80::", | |
2361 | &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2362 | unicast_link_local|unicast_link_local_strict); | |
2363 | ||
2364 | check!("febf:ffff::", | |
2365 | &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2366 | unicast_link_local); | |
2367 | ||
2368 | check!("febf::", | |
2369 | &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2370 | unicast_link_local); | |
2371 | ||
2372 | check!("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", | |
2373 | &[0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | |
2374 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], | |
2375 | unicast_link_local); | |
2376 | ||
2377 | check!("fe80::ffff:ffff:ffff:ffff", | |
2378 | &[0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2379 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], | |
2380 | unicast_link_local|unicast_link_local_strict); | |
2381 | ||
2382 | check!("fe80:0:0:1::", | |
2383 | &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], | |
2384 | unicast_link_local); | |
2385 | ||
2386 | check!("fec0::", | |
2387 | &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2388 | unicast_site_local|unicast_global|global); | |
2389 | ||
2390 | check!("ff01::", | |
2391 | &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2392 | multicast_interface_local); | |
2393 | ||
2394 | check!("ff02::", | |
2395 | &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2396 | multicast_link_local); | |
2397 | ||
2398 | check!("ff03::", | |
2399 | &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2400 | multicast_realm_local); | |
2401 | ||
2402 | check!("ff04::", | |
2403 | &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2404 | multicast_admin_local); | |
2405 | ||
2406 | check!("ff05::", | |
2407 | &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2408 | multicast_site_local); | |
2409 | ||
2410 | check!("ff08::", | |
2411 | &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2412 | multicast_organization_local); | |
2413 | ||
2414 | check!("ff0e::", | |
2415 | &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
2416 | multicast_global | global); | |
2417 | ||
2418 | check!("2001:db8:85a3::8a2e:370:7334", | |
2419 | &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], | |
2420 | documentation); | |
2421 | ||
2422 | check!("102:304:506:708:90a:b0c:d0e:f10", | |
2423 | &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], | |
2424 | global| unicast_global); | |
9346a6ac AL |
2425 | } |
2426 | ||
2427 | #[test] | |
2428 | fn to_socket_addr_socketaddr() { | |
2429 | let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); | |
2430 | assert_eq!(Ok(vec![a]), tsa(a)); | |
2431 | } | |
d9579d0f AL |
2432 | |
2433 | #[test] | |
2434 | fn test_ipv4_to_int() { | |
8bb4bdeb XL |
2435 | let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); |
2436 | assert_eq!(u32::from(a), 0x11223344); | |
d9579d0f AL |
2437 | } |
2438 | ||
2439 | #[test] | |
2440 | fn test_int_to_ipv4() { | |
8bb4bdeb XL |
2441 | let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); |
2442 | assert_eq!(Ipv4Addr::from(0x11223344), a); | |
2443 | } | |
2444 | ||
2445 | #[test] | |
2446 | fn test_ipv6_to_int() { | |
2447 | let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); | |
2448 | assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); | |
2449 | } | |
2450 | ||
2451 | #[test] | |
2452 | fn test_int_to_ipv6() { | |
2453 | let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); | |
2454 | assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); | |
d9579d0f | 2455 | } |
92a42be0 | 2456 | |
ea8adc8c XL |
2457 | #[test] |
2458 | fn ipv4_from_constructors() { | |
b7449926 XL |
2459 | assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); |
2460 | assert!(Ipv4Addr::LOCALHOST.is_loopback()); | |
2461 | assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); | |
2462 | assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); | |
2463 | assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); | |
2464 | assert!(Ipv4Addr::BROADCAST.is_broadcast()); | |
ea8adc8c XL |
2465 | } |
2466 | ||
2467 | #[test] | |
2468 | fn ipv6_from_contructors() { | |
b7449926 XL |
2469 | assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); |
2470 | assert!(Ipv6Addr::LOCALHOST.is_loopback()); | |
2471 | assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); | |
2472 | assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); | |
ea8adc8c XL |
2473 | } |
2474 | ||
54a0048b | 2475 | #[test] |
32a655c1 | 2476 | fn ipv4_from_octets() { |
54a0048b SL |
2477 | assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) |
2478 | } | |
2479 | ||
92a42be0 | 2480 | #[test] |
32a655c1 SL |
2481 | fn ipv6_from_segments() { |
2482 | let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, | |
2483 | 0x8899, 0xaabb, 0xccdd, 0xeeff]); | |
2484 | let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, | |
2485 | 0x8899, 0xaabb, 0xccdd, 0xeeff); | |
2486 | assert_eq!(new, from_u16s); | |
2487 | } | |
2488 | ||
2489 | #[test] | |
2490 | fn ipv6_from_octets() { | |
2491 | let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, | |
2492 | 0x8899, 0xaabb, 0xccdd, 0xeeff]); | |
2493 | let from_u8s = Ipv6Addr::from([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | |
2494 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]); | |
2495 | assert_eq!(from_u16s, from_u8s); | |
2496 | } | |
2497 | ||
2498 | #[test] | |
2499 | fn cmp() { | |
2500 | let v41 = Ipv4Addr::new(100, 64, 3, 3); | |
2501 | let v42 = Ipv4Addr::new(192, 0, 2, 2); | |
2502 | let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap(); | |
2503 | let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap(); | |
2504 | assert!(v41 < v42); | |
2505 | assert!(v61 < v62); | |
2506 | ||
2507 | assert_eq!(v41, IpAddr::V4(v41)); | |
2508 | assert_eq!(v61, IpAddr::V6(v61)); | |
2509 | assert!(v41 != IpAddr::V4(v42)); | |
2510 | assert!(v61 != IpAddr::V6(v62)); | |
2511 | ||
2512 | assert!(v41 < IpAddr::V4(v42)); | |
2513 | assert!(v61 < IpAddr::V6(v62)); | |
2514 | assert!(IpAddr::V4(v41) < v42); | |
2515 | assert!(IpAddr::V6(v61) < v62); | |
2516 | ||
2517 | assert!(v41 < IpAddr::V6(v61)); | |
2518 | assert!(IpAddr::V4(v41) < v61); | |
92a42be0 | 2519 | } |
c30ab7b3 SL |
2520 | |
2521 | #[test] | |
2522 | fn is_v4() { | |
2523 | let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); | |
2524 | assert!(ip.is_ipv4()); | |
2525 | assert!(!ip.is_ipv6()); | |
2526 | } | |
2527 | ||
2528 | #[test] | |
2529 | fn is_v6() { | |
2530 | let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); | |
2531 | assert!(!ip.is_ipv4()); | |
2532 | assert!(ip.is_ipv6()); | |
2533 | } | |
9346a6ac | 2534 | } |