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