1 //! The following is derived from Rust's 2 //! library/std/src/net/ip_addr.rs at revision 3 //! 14230a7f8e117aa049d3ae661fa00ded7edefc68. 4 //! 5 //! All code in this file is licensed MIT or Apache 2.0 at your option. 6 //! 7 //! This defines `IpAddr`, `Ipv4Addr`, and `Ipv6Addr`. Ideally, these should be 8 //! defined in `core`. See [RFC 2832]. 9 //! 10 //! [RFC 2832]: https://github.com/rust-lang/rfcs/pull/2832 11 12 #![allow(unsafe_code)] 13 14 use core::cmp::Ordering; 15 use core::mem::transmute; 16 17 /// An IP address, either IPv4 or IPv6. 18 /// 19 /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their 20 /// respective documentation for more details. 21 /// 22 /// # Examples 23 /// 24 /// ``` 25 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 26 /// 27 /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); 28 /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); 29 /// 30 /// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); 31 /// assert_eq!("::1".parse(), Ok(localhost_v6)); 32 /// 33 /// assert_eq!(localhost_v4.is_ipv6(), false); 34 /// assert_eq!(localhost_v4.is_ipv4(), true); 35 /// ``` 36 #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] 37 #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] 38 pub enum IpAddr { 39 /// An IPv4 address. 40 #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] 41 V4(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv4Addr), 42 /// An IPv6 address. 43 #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] 44 V6(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv6Addr), 45 } 46 47 /// An IPv4 address. 48 /// 49 /// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. 50 /// They are usually represented as four octets. 51 /// 52 /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. 53 /// 54 /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 55 /// 56 /// # Textual representation 57 /// 58 /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal 59 /// notation, divided by `.` (this is called "dot-decimal notation"). 60 /// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which 61 /// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. 62 /// 63 /// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 64 /// [`FromStr`]: core::str::FromStr 65 /// 66 /// # Examples 67 /// 68 /// ``` 69 /// use std::net::Ipv4Addr; 70 /// 71 /// let localhost = Ipv4Addr::new(127, 0, 0, 1); 72 /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); 73 /// assert_eq!(localhost.is_loopback(), true); 74 /// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal 75 /// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal 76 /// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex 77 /// ``` 78 #[derive(Copy, Clone, PartialEq, Eq, Hash)] 79 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 80 pub struct Ipv4Addr { 81 octets: [u8; 4], 82 } 83 84 /// An IPv6 address. 85 /// 86 /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. 87 /// They are usually represented as eight 16-bit segments. 88 /// 89 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 90 /// 91 /// # Embedding IPv4 Addresses 92 /// 93 /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. 94 /// 95 /// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined: 96 /// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated. 97 /// 98 /// Both types of addresses are not assigned any special meaning by this implementation, 99 /// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`, 100 /// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is. 101 /// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address. 102 /// 103 /// ### IPv4-Compatible IPv6 Addresses 104 /// 105 /// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated. 106 /// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows: 107 /// 108 /// ```text 109 /// | 80 bits | 16 | 32 bits | 110 /// +--------------------------------------+--------------------------+ 111 /// |0000..............................0000|0000| IPv4 address | 112 /// +--------------------------------------+----+---------------------+ 113 /// ``` 114 /// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`. 115 /// 116 /// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`]. 117 /// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address. 118 /// 119 /// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 120 /// 121 /// ### IPv4-Mapped IPv6 Addresses 122 /// 123 /// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2]. 124 /// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows: 125 /// 126 /// ```text 127 /// | 80 bits | 16 | 32 bits | 128 /// +--------------------------------------+--------------------------+ 129 /// |0000..............................0000|FFFF| IPv4 address | 130 /// +--------------------------------------+----+---------------------+ 131 /// ``` 132 /// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`. 133 /// 134 /// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`]. 135 /// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address. 136 /// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use 137 /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. 138 /// 139 /// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 140 /// 141 /// # Textual representation 142 /// 143 /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent 144 /// an IPv6 address in text, but in general, each segments is written in hexadecimal 145 /// notation, and segments are separated by `:`. For more information, see 146 /// [IETF RFC 5952]. 147 /// 148 /// [`FromStr`]: core::str::FromStr 149 /// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 150 /// 151 /// # Examples 152 /// 153 /// ``` 154 /// use std::net::Ipv6Addr; 155 /// 156 /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); 157 /// assert_eq!("::1".parse(), Ok(localhost)); 158 /// assert_eq!(localhost.is_loopback(), true); 159 /// ``` 160 #[derive(Copy, Clone, PartialEq, Eq, Hash)] 161 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 162 pub struct Ipv6Addr { 163 octets: [u8; 16], 164 } 165 166 /// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. 167 /// 168 /// # Stability Guarantees 169 /// 170 /// Not all possible values for a multicast scope have been assigned. 171 /// Future RFCs may introduce new scopes, which will be added as variants to this enum; 172 /// because of this the enum is marked as `#[non_exhaustive]`. 173 /// 174 /// # Examples 175 /// ``` 176 /// #![feature(ip)] 177 /// 178 /// use std::net::Ipv6Addr; 179 /// use std::net::Ipv6MulticastScope::*; 180 /// 181 /// // An IPv6 multicast address with global scope (`ff0e::`). 182 /// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0); 183 /// 184 /// // Will print "Global scope". 185 /// match address.multicast_scope() { 186 /// Some(InterfaceLocal) => println!("Interface-Local scope"), 187 /// Some(LinkLocal) => println!("Link-Local scope"), 188 /// Some(RealmLocal) => println!("Realm-Local scope"), 189 /// Some(AdminLocal) => println!("Admin-Local scope"), 190 /// Some(SiteLocal) => println!("Site-Local scope"), 191 /// Some(OrganizationLocal) => println!("Organization-Local scope"), 192 /// Some(Global) => println!("Global scope"), 193 /// Some(_) => println!("Unknown scope"), 194 /// None => println!("Not a multicast address!") 195 /// } 196 /// 197 /// ``` 198 /// 199 /// [IPv6 multicast address]: Ipv6Addr 200 /// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 201 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] 202 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 203 #[non_exhaustive] 204 pub enum Ipv6MulticastScope { 205 /// Interface-Local scope. 206 InterfaceLocal, 207 /// Link-Local scope. 208 LinkLocal, 209 /// Realm-Local scope. 210 RealmLocal, 211 /// Admin-Local scope. 212 AdminLocal, 213 /// Site-Local scope. 214 SiteLocal, 215 /// Organization-Local scope. 216 OrganizationLocal, 217 /// Global scope. 218 Global, 219 } 220 221 impl IpAddr { 222 /// Returns [`true`] for the special 'unspecified' address. 223 /// 224 /// See the documentation for [`Ipv4Addr::is_unspecified()`] and 225 /// [`Ipv6Addr::is_unspecified()`] for more details. 226 /// 227 /// # Examples 228 /// 229 /// ``` 230 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 231 /// 232 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); 233 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); 234 /// ``` 235 #[cfg_attr( 236 staged_api, 237 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 238 )] 239 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 240 #[must_use] 241 #[inline] is_unspecified(&self) -> bool242 pub const fn is_unspecified(&self) -> bool { 243 match self { 244 IpAddr::V4(ip) => ip.is_unspecified(), 245 IpAddr::V6(ip) => ip.is_unspecified(), 246 } 247 } 248 249 /// Returns [`true`] if this is a loopback address. 250 /// 251 /// See the documentation for [`Ipv4Addr::is_loopback()`] and 252 /// [`Ipv6Addr::is_loopback()`] for more details. 253 /// 254 /// # Examples 255 /// 256 /// ``` 257 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 258 /// 259 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); 260 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); 261 /// ``` 262 #[cfg_attr( 263 staged_api, 264 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 265 )] 266 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 267 #[must_use] 268 #[inline] is_loopback(&self) -> bool269 pub const fn is_loopback(&self) -> bool { 270 match self { 271 IpAddr::V4(ip) => ip.is_loopback(), 272 IpAddr::V6(ip) => ip.is_loopback(), 273 } 274 } 275 276 /// Returns [`true`] if the address appears to be globally routable. 277 /// 278 /// See the documentation for [`Ipv4Addr::is_global()`] and 279 /// [`Ipv6Addr::is_global()`] for more details. 280 /// 281 /// # Examples 282 /// 283 /// ``` 284 /// #![feature(ip)] 285 /// 286 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 287 /// 288 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); 289 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); 290 /// ``` 291 #[cfg_attr( 292 staged_api, 293 rustc_const_unstable(feature = "const_ip", issue = "76205") 294 )] 295 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 296 #[must_use] 297 #[inline] is_global(&self) -> bool298 pub const fn is_global(&self) -> bool { 299 match self { 300 IpAddr::V4(ip) => ip.is_global(), 301 IpAddr::V6(ip) => ip.is_global(), 302 } 303 } 304 305 /// Returns [`true`] if this is a multicast address. 306 /// 307 /// See the documentation for [`Ipv4Addr::is_multicast()`] and 308 /// [`Ipv6Addr::is_multicast()`] for more details. 309 /// 310 /// # Examples 311 /// 312 /// ``` 313 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 314 /// 315 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); 316 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); 317 /// ``` 318 #[cfg_attr( 319 staged_api, 320 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 321 )] 322 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 323 #[must_use] 324 #[inline] is_multicast(&self) -> bool325 pub const fn is_multicast(&self) -> bool { 326 match self { 327 IpAddr::V4(ip) => ip.is_multicast(), 328 IpAddr::V6(ip) => ip.is_multicast(), 329 } 330 } 331 332 /// Returns [`true`] if this address is in a range designated for documentation. 333 /// 334 /// See the documentation for [`Ipv4Addr::is_documentation()`] and 335 /// [`Ipv6Addr::is_documentation()`] for more details. 336 /// 337 /// # Examples 338 /// 339 /// ``` 340 /// #![feature(ip)] 341 /// 342 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 343 /// 344 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); 345 /// assert_eq!( 346 /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), 347 /// true 348 /// ); 349 /// ``` 350 #[cfg_attr( 351 staged_api, 352 rustc_const_unstable(feature = "const_ip", issue = "76205") 353 )] 354 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 355 #[must_use] 356 #[inline] is_documentation(&self) -> bool357 pub const fn is_documentation(&self) -> bool { 358 match self { 359 IpAddr::V4(ip) => ip.is_documentation(), 360 IpAddr::V6(ip) => ip.is_documentation(), 361 } 362 } 363 364 /// Returns [`true`] if this address is in a range designated for benchmarking. 365 /// 366 /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and 367 /// [`Ipv6Addr::is_benchmarking()`] for more details. 368 /// 369 /// # Examples 370 /// 371 /// ``` 372 /// #![feature(ip)] 373 /// 374 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 375 /// 376 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); 377 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); 378 /// ``` 379 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 380 #[must_use] 381 #[inline] is_benchmarking(&self) -> bool382 pub const fn is_benchmarking(&self) -> bool { 383 match self { 384 IpAddr::V4(ip) => ip.is_benchmarking(), 385 IpAddr::V6(ip) => ip.is_benchmarking(), 386 } 387 } 388 389 /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] 390 /// otherwise. 391 /// 392 /// [`IPv4` address]: IpAddr::V4 393 /// 394 /// # Examples 395 /// 396 /// ``` 397 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 398 /// 399 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); 400 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); 401 /// ``` 402 #[cfg_attr( 403 staged_api, 404 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 405 )] 406 #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] 407 #[must_use] 408 #[inline] is_ipv4(&self) -> bool409 pub const fn is_ipv4(&self) -> bool { 410 matches!(self, IpAddr::V4(_)) 411 } 412 413 /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] 414 /// otherwise. 415 /// 416 /// [`IPv6` address]: IpAddr::V6 417 /// 418 /// # Examples 419 /// 420 /// ``` 421 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 422 /// 423 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); 424 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); 425 /// ``` 426 #[cfg_attr( 427 staged_api, 428 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 429 )] 430 #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] 431 #[must_use] 432 #[inline] is_ipv6(&self) -> bool433 pub const fn is_ipv6(&self) -> bool { 434 matches!(self, IpAddr::V6(_)) 435 } 436 437 /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it 438 /// return `self` as-is. 439 /// 440 /// # Examples 441 /// 442 /// ``` 443 /// #![feature(ip)] 444 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 445 /// 446 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); 447 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); 448 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); 449 /// ``` 450 #[inline] 451 #[must_use = "this returns the result of the operation, \ 452 without modifying the original"] 453 #[cfg_attr( 454 staged_api, 455 rustc_const_unstable(feature = "const_ip", issue = "76205") 456 )] 457 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] to_canonical(&self) -> IpAddr458 pub const fn to_canonical(&self) -> IpAddr { 459 match self { 460 &v4 @ IpAddr::V4(_) => v4, 461 IpAddr::V6(v6) => v6.to_canonical(), 462 } 463 } 464 } 465 466 impl Ipv4Addr { 467 /// Creates a new IPv4 address from four eight-bit octets. 468 /// 469 /// The result will represent the IP address `a`.`b`.`c`.`d`. 470 /// 471 /// # Examples 472 /// 473 /// ``` 474 /// use std::net::Ipv4Addr; 475 /// 476 /// let addr = Ipv4Addr::new(127, 0, 0, 1); 477 /// ``` 478 #[cfg_attr( 479 staged_api, 480 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 481 )] 482 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 483 #[must_use] 484 #[inline] new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr485 pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { 486 Ipv4Addr { 487 octets: [a, b, c, d], 488 } 489 } 490 491 /// An IPv4 address with the address pointing to localhost: `127.0.0.1` 492 /// 493 /// # Examples 494 /// 495 /// ``` 496 /// use std::net::Ipv4Addr; 497 /// 498 /// let addr = Ipv4Addr::LOCALHOST; 499 /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); 500 /// ``` 501 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 502 pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); 503 504 /// An IPv4 address representing an unspecified address: `0.0.0.0` 505 /// 506 /// This corresponds to the constant `INADDR_ANY` in other languages. 507 /// 508 /// # Examples 509 /// 510 /// ``` 511 /// use std::net::Ipv4Addr; 512 /// 513 /// let addr = Ipv4Addr::UNSPECIFIED; 514 /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); 515 /// ``` 516 #[doc(alias = "INADDR_ANY")] 517 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 518 pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); 519 520 /// An IPv4 address representing the broadcast address: `255.255.255.255` 521 /// 522 /// # Examples 523 /// 524 /// ``` 525 /// use std::net::Ipv4Addr; 526 /// 527 /// let addr = Ipv4Addr::BROADCAST; 528 /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); 529 /// ``` 530 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 531 pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); 532 533 /// Returns the four eight-bit integers that make up this address. 534 /// 535 /// # Examples 536 /// 537 /// ``` 538 /// use std::net::Ipv4Addr; 539 /// 540 /// let addr = Ipv4Addr::new(127, 0, 0, 1); 541 /// assert_eq!(addr.octets(), [127, 0, 0, 1]); 542 /// ``` 543 #[cfg_attr( 544 staged_api, 545 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 546 )] 547 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 548 #[must_use] 549 #[inline] octets(&self) -> [u8; 4]550 pub const fn octets(&self) -> [u8; 4] { 551 self.octets 552 } 553 554 /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). 555 /// 556 /// This property is defined in _UNIX Network Programming, Second Edition_, 557 /// W. Richard Stevens, p. 891; see also [ip7]. 558 /// 559 /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html 560 /// 561 /// # Examples 562 /// 563 /// ``` 564 /// use std::net::Ipv4Addr; 565 /// 566 /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); 567 /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); 568 /// ``` 569 #[cfg_attr( 570 staged_api, 571 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 572 )] 573 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 574 #[must_use] 575 #[inline] is_unspecified(&self) -> bool576 pub const fn is_unspecified(&self) -> bool { 577 u32::from_be_bytes(self.octets) == 0 578 } 579 580 /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). 581 /// 582 /// This property is defined by [IETF RFC 1122]. 583 /// 584 /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 585 /// 586 /// # Examples 587 /// 588 /// ``` 589 /// use std::net::Ipv4Addr; 590 /// 591 /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); 592 /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); 593 /// ``` 594 #[cfg_attr( 595 staged_api, 596 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 597 )] 598 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 599 #[must_use] 600 #[inline] is_loopback(&self) -> bool601 pub const fn is_loopback(&self) -> bool { 602 self.octets()[0] == 127 603 } 604 605 /// Returns [`true`] if this is a private address. 606 /// 607 /// The private address ranges are defined in [IETF RFC 1918] and include: 608 /// 609 /// - `10.0.0.0/8` 610 /// - `172.16.0.0/12` 611 /// - `192.168.0.0/16` 612 /// 613 /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 614 /// 615 /// # Examples 616 /// 617 /// ``` 618 /// use std::net::Ipv4Addr; 619 /// 620 /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); 621 /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); 622 /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); 623 /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); 624 /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); 625 /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); 626 /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); 627 /// ``` 628 #[cfg_attr( 629 staged_api, 630 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 631 )] 632 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 633 #[must_use] 634 #[inline] is_private(&self) -> bool635 pub const fn is_private(&self) -> bool { 636 match self.octets() { 637 [10, ..] => true, 638 [172, b, ..] if b >= 16 && b <= 31 => true, 639 [192, 168, ..] => true, 640 _ => false, 641 } 642 } 643 644 /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). 645 /// 646 /// This property is defined by [IETF RFC 3927]. 647 /// 648 /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 649 /// 650 /// # Examples 651 /// 652 /// ``` 653 /// use std::net::Ipv4Addr; 654 /// 655 /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); 656 /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); 657 /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); 658 /// ``` 659 #[cfg_attr( 660 staged_api, 661 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 662 )] 663 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 664 #[must_use] 665 #[inline] is_link_local(&self) -> bool666 pub const fn is_link_local(&self) -> bool { 667 matches!(self.octets(), [169, 254, ..]) 668 } 669 670 /// Returns [`true`] if the address appears to be globally reachable 671 /// as specified by the [IANA IPv4 Special-Purpose Address Registry]. 672 /// Whether or not an address is practically reachable will depend on your network configuration. 673 /// 674 /// Most IPv4 addresses are globally reachable; 675 /// unless they are specifically defined as *not* globally reachable. 676 /// 677 /// Non-exhaustive list of notable addresses that are not globally reachable: 678 /// 679 /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified)) 680 /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private)) 681 /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared)) 682 /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback)) 683 /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local)) 684 /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation)) 685 /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking)) 686 /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved)) 687 /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast)) 688 /// 689 /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry]. 690 /// 691 /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml 692 /// [unspecified address]: Ipv4Addr::UNSPECIFIED 693 /// [broadcast address]: Ipv4Addr::BROADCAST 694 695 /// 696 /// # Examples 697 /// 698 /// ``` 699 /// #![feature(ip)] 700 /// 701 /// use std::net::Ipv4Addr; 702 /// 703 /// // Most IPv4 addresses are globally reachable: 704 /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); 705 /// 706 /// // However some addresses have been assigned a special meaning 707 /// // that makes them not globally reachable. Some examples are: 708 /// 709 /// // The unspecified address (`0.0.0.0`) 710 /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false); 711 /// 712 /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16) 713 /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); 714 /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); 715 /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); 716 /// 717 /// // Addresses in the shared address space (`100.64.0.0/10`) 718 /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); 719 /// 720 /// // The loopback addresses (`127.0.0.0/8`) 721 /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false); 722 /// 723 /// // Link-local addresses (`169.254.0.0/16`) 724 /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); 725 /// 726 /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`) 727 /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); 728 /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); 729 /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); 730 /// 731 /// // Addresses reserved for benchmarking (`198.18.0.0/15`) 732 /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); 733 /// 734 /// // Reserved addresses (`240.0.0.0/4`) 735 /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); 736 /// 737 /// // The broadcast address (`255.255.255.255`) 738 /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false); 739 /// 740 /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry. 741 /// ``` 742 #[cfg_attr( 743 staged_api, 744 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 745 )] 746 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 747 #[must_use] 748 #[inline] is_global(&self) -> bool749 pub const fn is_global(&self) -> bool { 750 !(self.octets()[0] == 0 // "This network" 751 || self.is_private() 752 || self.is_shared() 753 || self.is_loopback() 754 || self.is_link_local() 755 // addresses reserved for future protocols (`192.0.0.0/24`) 756 ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) 757 || self.is_documentation() 758 || self.is_benchmarking() 759 || self.is_reserved() 760 || self.is_broadcast()) 761 } 762 763 /// Returns [`true`] if this address is part of the Shared Address Space defined in 764 /// [IETF RFC 6598] (`100.64.0.0/10`). 765 /// 766 /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 767 /// 768 /// # Examples 769 /// 770 /// ``` 771 /// #![feature(ip)] 772 /// use std::net::Ipv4Addr; 773 /// 774 /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); 775 /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); 776 /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); 777 /// ``` 778 #[cfg_attr( 779 staged_api, 780 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 781 )] 782 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 783 #[must_use] 784 #[inline] is_shared(&self) -> bool785 pub const fn is_shared(&self) -> bool { 786 self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) 787 } 788 789 /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for 790 /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` 791 /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. 792 /// 793 /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 794 /// [errata 423]: https://www.rfc-editor.org/errata/eid423 795 /// 796 /// # Examples 797 /// 798 /// ``` 799 /// #![feature(ip)] 800 /// use std::net::Ipv4Addr; 801 /// 802 /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); 803 /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); 804 /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); 805 /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); 806 /// ``` 807 #[cfg_attr( 808 staged_api, 809 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 810 )] 811 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 812 #[must_use] 813 #[inline] is_benchmarking(&self) -> bool814 pub const fn is_benchmarking(&self) -> bool { 815 self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 816 } 817 818 /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] 819 /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the 820 /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since 821 /// it is obviously not reserved for future use. 822 /// 823 /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 824 /// 825 /// # Warning 826 /// 827 /// As IANA assigns new addresses, this method will be 828 /// updated. This may result in non-reserved addresses being 829 /// treated as reserved in code that relies on an outdated version 830 /// of this method. 831 /// 832 /// # Examples 833 /// 834 /// ``` 835 /// #![feature(ip)] 836 /// use std::net::Ipv4Addr; 837 /// 838 /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); 839 /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); 840 /// 841 /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); 842 /// // The broadcast address is not considered as reserved for future use by this implementation 843 /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); 844 /// ``` 845 #[cfg_attr( 846 staged_api, 847 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 848 )] 849 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 850 #[must_use] 851 #[inline] is_reserved(&self) -> bool852 pub const fn is_reserved(&self) -> bool { 853 self.octets()[0] & 240 == 240 && !self.is_broadcast() 854 } 855 856 /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). 857 /// 858 /// Multicast addresses have a most significant octet between `224` and `239`, 859 /// and is defined by [IETF RFC 5771]. 860 /// 861 /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 862 /// 863 /// # Examples 864 /// 865 /// ``` 866 /// use std::net::Ipv4Addr; 867 /// 868 /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); 869 /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); 870 /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); 871 /// ``` 872 #[cfg_attr( 873 staged_api, 874 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 875 )] 876 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 877 #[must_use] 878 #[inline] is_multicast(&self) -> bool879 pub const fn is_multicast(&self) -> bool { 880 self.octets()[0] >= 224 && self.octets()[0] <= 239 881 } 882 883 /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). 884 /// 885 /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. 886 /// 887 /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 888 /// 889 /// # Examples 890 /// 891 /// ``` 892 /// use std::net::Ipv4Addr; 893 /// 894 /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); 895 /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); 896 /// ``` 897 #[cfg_attr( 898 staged_api, 899 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 900 )] 901 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 902 #[must_use] 903 #[inline] is_broadcast(&self) -> bool904 pub const fn is_broadcast(&self) -> bool { 905 u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) 906 } 907 908 /// Returns [`true`] if this address is in a range designated for documentation. 909 /// 910 /// This is defined in [IETF RFC 5737]: 911 /// 912 /// - `192.0.2.0/24` (TEST-NET-1) 913 /// - `198.51.100.0/24` (TEST-NET-2) 914 /// - `203.0.113.0/24` (TEST-NET-3) 915 /// 916 /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 917 /// 918 /// # Examples 919 /// 920 /// ``` 921 /// use std::net::Ipv4Addr; 922 /// 923 /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); 924 /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); 925 /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); 926 /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); 927 /// ``` 928 #[cfg_attr( 929 staged_api, 930 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 931 )] 932 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 933 #[must_use] 934 #[inline] is_documentation(&self) -> bool935 pub const fn is_documentation(&self) -> bool { 936 matches!( 937 self.octets(), 938 [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _] 939 ) 940 } 941 942 /// Converts this address to an [IPv4-compatible] [`IPv6` address]. 943 /// 944 /// `a.b.c.d` becomes `::a.b.c.d` 945 /// 946 /// Note that IPv4-compatible addresses have been officially deprecated. 947 /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead. 948 /// 949 /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses 950 /// [`IPv6` address]: Ipv6Addr 951 /// 952 /// # Examples 953 /// 954 /// ``` 955 /// use std::net::{Ipv4Addr, Ipv6Addr}; 956 /// 957 /// assert_eq!( 958 /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), 959 /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) 960 /// ); 961 /// ``` 962 #[cfg_attr( 963 staged_api, 964 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 965 )] 966 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 967 #[must_use = "this returns the result of the operation, \ 968 without modifying the original"] 969 #[inline] to_ipv6_compatible(&self) -> Ipv6Addr970 pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { 971 let [a, b, c, d] = self.octets(); 972 Ipv6Addr { 973 octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d], 974 } 975 } 976 977 /// Converts this address to an [IPv4-mapped] [`IPv6` address]. 978 /// 979 /// `a.b.c.d` becomes `::ffff:a.b.c.d` 980 /// 981 /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses 982 /// [`IPv6` address]: Ipv6Addr 983 /// 984 /// # Examples 985 /// 986 /// ``` 987 /// use std::net::{Ipv4Addr, Ipv6Addr}; 988 /// 989 /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), 990 /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); 991 /// ``` 992 #[cfg_attr( 993 staged_api, 994 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 995 )] 996 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 997 #[must_use = "this returns the result of the operation, \ 998 without modifying the original"] 999 #[inline] to_ipv6_mapped(&self) -> Ipv6Addr1000 pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { 1001 let [a, b, c, d] = self.octets(); 1002 Ipv6Addr { 1003 octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d], 1004 } 1005 } 1006 } 1007 1008 #[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] 1009 impl From<Ipv4Addr> for IpAddr { 1010 /// Copies this address to a new `IpAddr::V4`. 1011 /// 1012 /// # Examples 1013 /// 1014 /// ``` 1015 /// use std::net::{IpAddr, Ipv4Addr}; 1016 /// 1017 /// let addr = Ipv4Addr::new(127, 0, 0, 1); 1018 /// 1019 /// assert_eq!( 1020 /// IpAddr::V4(addr), 1021 /// IpAddr::from(addr) 1022 /// ) 1023 /// ``` 1024 #[inline] from(ipv4: Ipv4Addr) -> IpAddr1025 fn from(ipv4: Ipv4Addr) -> IpAddr { 1026 IpAddr::V4(ipv4) 1027 } 1028 } 1029 1030 #[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] 1031 impl From<Ipv6Addr> for IpAddr { 1032 /// Copies this address to a new `IpAddr::V6`. 1033 /// 1034 /// # Examples 1035 /// 1036 /// ``` 1037 /// use std::net::{IpAddr, Ipv6Addr}; 1038 /// 1039 /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); 1040 /// 1041 /// assert_eq!( 1042 /// IpAddr::V6(addr), 1043 /// IpAddr::from(addr) 1044 /// ); 1045 /// ``` 1046 #[inline] from(ipv6: Ipv6Addr) -> IpAddr1047 fn from(ipv6: Ipv6Addr) -> IpAddr { 1048 IpAddr::V6(ipv6) 1049 } 1050 } 1051 1052 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1053 impl PartialEq<Ipv4Addr> for IpAddr { 1054 #[inline] eq(&self, other: &Ipv4Addr) -> bool1055 fn eq(&self, other: &Ipv4Addr) -> bool { 1056 match self { 1057 IpAddr::V4(v4) => v4 == other, 1058 IpAddr::V6(_) => false, 1059 } 1060 } 1061 } 1062 1063 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1064 impl PartialEq<IpAddr> for Ipv4Addr { 1065 #[inline] eq(&self, other: &IpAddr) -> bool1066 fn eq(&self, other: &IpAddr) -> bool { 1067 match other { 1068 IpAddr::V4(v4) => self == v4, 1069 IpAddr::V6(_) => false, 1070 } 1071 } 1072 } 1073 1074 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1075 impl PartialOrd for Ipv4Addr { 1076 #[inline] partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering>1077 fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { 1078 Some(self.cmp(other)) 1079 } 1080 } 1081 1082 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1083 impl PartialOrd<Ipv4Addr> for IpAddr { 1084 #[inline] partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering>1085 fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { 1086 match self { 1087 IpAddr::V4(v4) => v4.partial_cmp(other), 1088 IpAddr::V6(_) => Some(Ordering::Greater), 1089 } 1090 } 1091 } 1092 1093 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1094 impl PartialOrd<IpAddr> for Ipv4Addr { 1095 #[inline] partial_cmp(&self, other: &IpAddr) -> Option<Ordering>1096 fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { 1097 match other { 1098 IpAddr::V4(v4) => self.partial_cmp(v4), 1099 IpAddr::V6(_) => Some(Ordering::Less), 1100 } 1101 } 1102 } 1103 1104 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1105 impl Ord for Ipv4Addr { 1106 #[inline] cmp(&self, other: &Ipv4Addr) -> Ordering1107 fn cmp(&self, other: &Ipv4Addr) -> Ordering { 1108 self.octets.cmp(&other.octets) 1109 } 1110 } 1111 1112 #[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] 1113 impl From<Ipv4Addr> for u32 { 1114 /// Converts an `Ipv4Addr` into a host byte order `u32`. 1115 /// 1116 /// # Examples 1117 /// 1118 /// ``` 1119 /// use std::net::Ipv4Addr; 1120 /// 1121 /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); 1122 /// assert_eq!(0x12345678, u32::from(addr)); 1123 /// ``` 1124 #[inline] from(ip: Ipv4Addr) -> u321125 fn from(ip: Ipv4Addr) -> u32 { 1126 u32::from_be_bytes(ip.octets) 1127 } 1128 } 1129 1130 #[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] 1131 impl From<u32> for Ipv4Addr { 1132 /// Converts a host byte order `u32` into an `Ipv4Addr`. 1133 /// 1134 /// # Examples 1135 /// 1136 /// ``` 1137 /// use std::net::Ipv4Addr; 1138 /// 1139 /// let addr = Ipv4Addr::from(0x12345678); 1140 /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); 1141 /// ``` 1142 #[inline] from(ip: u32) -> Ipv4Addr1143 fn from(ip: u32) -> Ipv4Addr { 1144 Ipv4Addr { 1145 octets: ip.to_be_bytes(), 1146 } 1147 } 1148 } 1149 1150 #[cfg_attr(staged_api, stable(feature = "from_slice_v4", since = "1.9.0"))] 1151 impl From<[u8; 4]> for Ipv4Addr { 1152 /// Creates an `Ipv4Addr` from a four element byte array. 1153 /// 1154 /// # Examples 1155 /// 1156 /// ``` 1157 /// use std::net::Ipv4Addr; 1158 /// 1159 /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); 1160 /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); 1161 /// ``` 1162 #[inline] from(octets: [u8; 4]) -> Ipv4Addr1163 fn from(octets: [u8; 4]) -> Ipv4Addr { 1164 Ipv4Addr { octets } 1165 } 1166 } 1167 1168 #[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] 1169 impl From<[u8; 4]> for IpAddr { 1170 /// Creates an `IpAddr::V4` from a four element byte array. 1171 /// 1172 /// # Examples 1173 /// 1174 /// ``` 1175 /// use std::net::{IpAddr, Ipv4Addr}; 1176 /// 1177 /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); 1178 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); 1179 /// ``` 1180 #[inline] from(octets: [u8; 4]) -> IpAddr1181 fn from(octets: [u8; 4]) -> IpAddr { 1182 IpAddr::V4(Ipv4Addr::from(octets)) 1183 } 1184 } 1185 1186 impl Ipv6Addr { 1187 /// Creates a new IPv6 address from eight 16-bit segments. 1188 /// 1189 /// The result will represent the IP address `a:b:c:d:e:f:g:h`. 1190 /// 1191 /// # Examples 1192 /// 1193 /// ``` 1194 /// use std::net::Ipv6Addr; 1195 /// 1196 /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); 1197 /// ``` 1198 #[cfg_attr( 1199 staged_api, 1200 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 1201 )] 1202 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1203 #[must_use] 1204 #[inline] new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr1205 pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { 1206 let addr16 = [ 1207 a.to_be(), 1208 b.to_be(), 1209 c.to_be(), 1210 d.to_be(), 1211 e.to_be(), 1212 f.to_be(), 1213 g.to_be(), 1214 h.to_be(), 1215 ]; 1216 Ipv6Addr { 1217 // All elements in `addr16` are big endian. 1218 // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. 1219 octets: unsafe { transmute::<_, [u8; 16]>(addr16) }, 1220 } 1221 } 1222 1223 /// An IPv6 address representing localhost: `::1`. 1224 /// 1225 /// # Examples 1226 /// 1227 /// ``` 1228 /// use std::net::Ipv6Addr; 1229 /// 1230 /// let addr = Ipv6Addr::LOCALHOST; 1231 /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); 1232 /// ``` 1233 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 1234 pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); 1235 1236 /// An IPv6 address representing the unspecified address: `::` 1237 /// 1238 /// # Examples 1239 /// 1240 /// ``` 1241 /// use std::net::Ipv6Addr; 1242 /// 1243 /// let addr = Ipv6Addr::UNSPECIFIED; 1244 /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); 1245 /// ``` 1246 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 1247 pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); 1248 1249 /// Returns the eight 16-bit segments that make up this address. 1250 /// 1251 /// # Examples 1252 /// 1253 /// ``` 1254 /// use std::net::Ipv6Addr; 1255 /// 1256 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), 1257 /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); 1258 /// ``` 1259 #[cfg_attr( 1260 staged_api, 1261 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1262 )] 1263 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1264 #[must_use] 1265 #[inline] segments(&self) -> [u16; 8]1266 pub const fn segments(&self) -> [u16; 8] { 1267 // All elements in `self.octets` must be big endian. 1268 // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. 1269 let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) }; 1270 // We want native endian u16 1271 [ 1272 u16::from_be(a), 1273 u16::from_be(b), 1274 u16::from_be(c), 1275 u16::from_be(d), 1276 u16::from_be(e), 1277 u16::from_be(f), 1278 u16::from_be(g), 1279 u16::from_be(h), 1280 ] 1281 } 1282 1283 /// Returns [`true`] for the special 'unspecified' address (`::`). 1284 /// 1285 /// This property is defined in [IETF RFC 4291]. 1286 /// 1287 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 1288 /// 1289 /// # Examples 1290 /// 1291 /// ``` 1292 /// use std::net::Ipv6Addr; 1293 /// 1294 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); 1295 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); 1296 /// ``` 1297 #[cfg_attr( 1298 staged_api, 1299 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1300 )] 1301 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 1302 #[must_use] 1303 #[inline] is_unspecified(&self) -> bool1304 pub const fn is_unspecified(&self) -> bool { 1305 u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) 1306 } 1307 1308 /// Returns [`true`] if this is the [loopback address] (`::1`), 1309 /// as defined in [IETF RFC 4291 section 2.5.3]. 1310 /// 1311 /// Contrary to IPv4, in IPv6 there is only one loopback address. 1312 /// 1313 /// [loopback address]: Ipv6Addr::LOCALHOST 1314 /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 1315 /// 1316 /// # Examples 1317 /// 1318 /// ``` 1319 /// use std::net::Ipv6Addr; 1320 /// 1321 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); 1322 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); 1323 /// ``` 1324 #[cfg_attr( 1325 staged_api, 1326 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1327 )] 1328 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 1329 #[must_use] 1330 #[inline] is_loopback(&self) -> bool1331 pub const fn is_loopback(&self) -> bool { 1332 u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) 1333 } 1334 1335 /// Returns [`true`] if the address appears to be globally reachable 1336 /// as specified by the [IANA IPv6 Special-Purpose Address Registry]. 1337 /// Whether or not an address is practically reachable will depend on your network configuration. 1338 /// 1339 /// Most IPv6 addresses are globally reachable; 1340 /// unless they are specifically defined as *not* globally reachable. 1341 /// 1342 /// Non-exhaustive list of notable addresses that are not globally reachable: 1343 /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) 1344 /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback)) 1345 /// - IPv4-mapped addresses 1346 /// - Addresses reserved for benchmarking 1347 /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation)) 1348 /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local)) 1349 /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local)) 1350 /// 1351 /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry]. 1352 /// 1353 /// Note that an address having global scope is not the same as being globally reachable, 1354 /// and there is no direct relation between the two concepts: There exist addresses with global scope 1355 /// that are not globally reachable (for example unique local addresses), 1356 /// and addresses that are globally reachable without having global scope 1357 /// (multicast addresses with non-global scope). 1358 /// 1359 /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml 1360 /// [unspecified address]: Ipv6Addr::UNSPECIFIED 1361 /// [loopback address]: Ipv6Addr::LOCALHOST 1362 /// 1363 /// # Examples 1364 /// 1365 /// ``` 1366 /// #![feature(ip)] 1367 /// 1368 /// use std::net::Ipv6Addr; 1369 /// 1370 /// // Most IPv6 addresses are globally reachable: 1371 /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true); 1372 /// 1373 /// // However some addresses have been assigned a special meaning 1374 /// // that makes them not globally reachable. Some examples are: 1375 /// 1376 /// // The unspecified address (`::`) 1377 /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false); 1378 /// 1379 /// // The loopback address (`::1`) 1380 /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false); 1381 /// 1382 /// // IPv4-mapped addresses (`::ffff:0:0/96`) 1383 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false); 1384 /// 1385 /// // Addresses reserved for benchmarking (`2001:2::/48`) 1386 /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); 1387 /// 1388 /// // Addresses reserved for documentation (`2001:db8::/32`) 1389 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); 1390 /// 1391 /// // Unique local addresses (`fc00::/7`) 1392 /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); 1393 /// 1394 /// // Unicast addresses with link-local scope (`fe80::/10`) 1395 /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false); 1396 /// 1397 /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry. 1398 /// ``` 1399 #[cfg_attr( 1400 staged_api, 1401 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1402 )] 1403 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1404 #[must_use] 1405 #[inline] is_global(&self) -> bool1406 pub const fn is_global(&self) -> bool { 1407 !(self.is_unspecified() 1408 || self.is_loopback() 1409 // IPv4-mapped Address (`::ffff:0:0/96`) 1410 || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) 1411 // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) 1412 || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) 1413 // Discard-Only Address Block (`100::/64`) 1414 || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _]) 1415 // IETF Protocol Assignments (`2001::/23`) 1416 || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) 1417 && !( 1418 // Port Control Protocol Anycast (`2001:1::1`) 1419 u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 1420 // Traversal Using Relays around NAT Anycast (`2001:1::2`) 1421 || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 1422 // AMT (`2001:3::/32`) 1423 || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _]) 1424 // AS112-v6 (`2001:4:112::/48`) 1425 || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) 1426 // ORCHIDv2 (`2001:20::/28`) 1427 || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F) 1428 )) 1429 || self.is_documentation() 1430 || self.is_unique_local() 1431 || self.is_unicast_link_local()) 1432 } 1433 1434 /// Returns [`true`] if this is a unique local address (`fc00::/7`). 1435 /// 1436 /// This property is defined in [IETF RFC 4193]. 1437 /// 1438 /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 1439 /// 1440 /// # Examples 1441 /// 1442 /// ``` 1443 /// #![feature(ip)] 1444 /// 1445 /// use std::net::Ipv6Addr; 1446 /// 1447 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); 1448 /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); 1449 /// ``` 1450 #[cfg_attr( 1451 staged_api, 1452 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1453 )] 1454 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1455 #[must_use] 1456 #[inline] is_unique_local(&self) -> bool1457 pub const fn is_unique_local(&self) -> bool { 1458 (self.segments()[0] & 0xfe00) == 0xfc00 1459 } 1460 1461 /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. 1462 /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. 1463 /// 1464 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 1465 /// [multicast address]: Ipv6Addr::is_multicast 1466 /// 1467 /// # Examples 1468 /// 1469 /// ``` 1470 /// #![feature(ip)] 1471 /// 1472 /// use std::net::Ipv6Addr; 1473 /// 1474 /// // The unspecified and loopback addresses are unicast. 1475 /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); 1476 /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); 1477 /// 1478 /// // Any address that is not a multicast address (`ff00::/8`) is unicast. 1479 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); 1480 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); 1481 /// ``` 1482 #[cfg_attr( 1483 staged_api, 1484 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1485 )] 1486 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1487 #[must_use] 1488 #[inline] is_unicast(&self) -> bool1489 pub const fn is_unicast(&self) -> bool { 1490 !self.is_multicast() 1491 } 1492 1493 /// Returns `true` if the address is a unicast address with link-local scope, 1494 /// as defined in [RFC 4291]. 1495 /// 1496 /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. 1497 /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], 1498 /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: 1499 /// 1500 /// ```text 1501 /// | 10 bits | 54 bits | 64 bits | 1502 /// +----------+-------------------------+----------------------------+ 1503 /// |1111111010| 0 | interface ID | 1504 /// +----------+-------------------------+----------------------------+ 1505 /// ``` 1506 /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, 1507 /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, 1508 /// and those addresses will have link-local scope. 1509 /// 1510 /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", 1511 /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. 1512 /// 1513 /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 1514 /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 1515 /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 1516 /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 1517 /// [loopback address]: Ipv6Addr::LOCALHOST 1518 /// 1519 /// # Examples 1520 /// 1521 /// ``` 1522 /// #![feature(ip)] 1523 /// 1524 /// use std::net::Ipv6Addr; 1525 /// 1526 /// // The loopback address (`::1`) does not actually have link-local scope. 1527 /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); 1528 /// 1529 /// // Only addresses in `fe80::/10` have link-local scope. 1530 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); 1531 /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); 1532 /// 1533 /// // Addresses outside the stricter `fe80::/64` also have link-local scope. 1534 /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); 1535 /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); 1536 /// ``` 1537 #[cfg_attr( 1538 staged_api, 1539 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1540 )] 1541 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1542 #[must_use] 1543 #[inline] is_unicast_link_local(&self) -> bool1544 pub const fn is_unicast_link_local(&self) -> bool { 1545 (self.segments()[0] & 0xffc0) == 0xfe80 1546 } 1547 1548 /// Returns [`true`] if this is an address reserved for documentation 1549 /// (`2001:db8::/32`). 1550 /// 1551 /// This property is defined in [IETF RFC 3849]. 1552 /// 1553 /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 1554 /// 1555 /// # Examples 1556 /// 1557 /// ``` 1558 /// #![feature(ip)] 1559 /// 1560 /// use std::net::Ipv6Addr; 1561 /// 1562 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); 1563 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); 1564 /// ``` 1565 #[cfg_attr( 1566 staged_api, 1567 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1568 )] 1569 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1570 #[must_use] 1571 #[inline] is_documentation(&self) -> bool1572 pub const fn is_documentation(&self) -> bool { 1573 (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) 1574 } 1575 1576 /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). 1577 /// 1578 /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. 1579 /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. 1580 /// 1581 /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 1582 /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 1583 /// 1584 /// ``` 1585 /// #![feature(ip)] 1586 /// 1587 /// use std::net::Ipv6Addr; 1588 /// 1589 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); 1590 /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); 1591 /// ``` 1592 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1593 #[must_use] 1594 #[inline] is_benchmarking(&self) -> bool1595 pub const fn is_benchmarking(&self) -> bool { 1596 (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) 1597 } 1598 1599 /// Returns [`true`] if the address is a globally routable unicast address. 1600 /// 1601 /// The following return false: 1602 /// 1603 /// - the loopback address 1604 /// - the link-local addresses 1605 /// - unique local addresses 1606 /// - the unspecified address 1607 /// - the address range reserved for documentation 1608 /// 1609 /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] 1610 /// 1611 /// ```no_rust 1612 /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer 1613 /// be supported in new implementations (i.e., new implementations must treat this prefix as 1614 /// Global Unicast). 1615 /// ``` 1616 /// 1617 /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 1618 /// 1619 /// # Examples 1620 /// 1621 /// ``` 1622 /// #![feature(ip)] 1623 /// 1624 /// use std::net::Ipv6Addr; 1625 /// 1626 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); 1627 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); 1628 /// ``` 1629 #[cfg_attr( 1630 staged_api, 1631 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1632 )] 1633 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1634 #[must_use] 1635 #[inline] is_unicast_global(&self) -> bool1636 pub const fn is_unicast_global(&self) -> bool { 1637 self.is_unicast() 1638 && !self.is_loopback() 1639 && !self.is_unicast_link_local() 1640 && !self.is_unique_local() 1641 && !self.is_unspecified() 1642 && !self.is_documentation() 1643 && !self.is_benchmarking() 1644 } 1645 1646 /// Returns the address's multicast scope if the address is multicast. 1647 /// 1648 /// # Examples 1649 /// 1650 /// ``` 1651 /// #![feature(ip)] 1652 /// 1653 /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; 1654 /// 1655 /// assert_eq!( 1656 /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), 1657 /// Some(Ipv6MulticastScope::Global) 1658 /// ); 1659 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); 1660 /// ``` 1661 #[cfg_attr( 1662 staged_api, 1663 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1664 )] 1665 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1666 #[must_use] 1667 #[inline] multicast_scope(&self) -> Option<Ipv6MulticastScope>1668 pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> { 1669 if self.is_multicast() { 1670 match self.segments()[0] & 0x000f { 1671 1 => Some(Ipv6MulticastScope::InterfaceLocal), 1672 2 => Some(Ipv6MulticastScope::LinkLocal), 1673 3 => Some(Ipv6MulticastScope::RealmLocal), 1674 4 => Some(Ipv6MulticastScope::AdminLocal), 1675 5 => Some(Ipv6MulticastScope::SiteLocal), 1676 8 => Some(Ipv6MulticastScope::OrganizationLocal), 1677 14 => Some(Ipv6MulticastScope::Global), 1678 _ => None, 1679 } 1680 } else { 1681 None 1682 } 1683 } 1684 1685 /// Returns [`true`] if this is a multicast address (`ff00::/8`). 1686 /// 1687 /// This property is defined by [IETF RFC 4291]. 1688 /// 1689 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 1690 /// 1691 /// # Examples 1692 /// 1693 /// ``` 1694 /// use std::net::Ipv6Addr; 1695 /// 1696 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); 1697 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); 1698 /// ``` 1699 #[cfg_attr( 1700 staged_api, 1701 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1702 )] 1703 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 1704 #[must_use] 1705 #[inline] is_multicast(&self) -> bool1706 pub const fn is_multicast(&self) -> bool { 1707 (self.segments()[0] & 0xff00) == 0xff00 1708 } 1709 1710 /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, 1711 /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. 1712 /// 1713 /// `::ffff:a.b.c.d` becomes `a.b.c.d`. 1714 /// All addresses *not* starting with `::ffff` will return `None`. 1715 /// 1716 /// [`IPv4` address]: Ipv4Addr 1717 /// [IPv4-mapped]: Ipv6Addr 1718 /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 1719 /// 1720 /// # Examples 1721 /// 1722 /// ``` 1723 /// use std::net::{Ipv4Addr, Ipv6Addr}; 1724 /// 1725 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); 1726 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), 1727 /// Some(Ipv4Addr::new(192, 10, 2, 255))); 1728 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); 1729 /// ``` 1730 #[cfg_attr( 1731 staged_api, 1732 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1733 )] 1734 #[cfg_attr(staged_api, stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0"))] 1735 #[must_use = "this returns the result of the operation, \ 1736 without modifying the original"] 1737 #[inline] to_ipv4_mapped(&self) -> Option<Ipv4Addr>1738 pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> { 1739 match self.octets() { 1740 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { 1741 Some(Ipv4Addr::new(a, b, c, d)) 1742 } 1743 _ => None, 1744 } 1745 } 1746 1747 /// Converts this address to an [`IPv4` address] if it is either 1748 /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1], 1749 /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2], 1750 /// otherwise returns [`None`]. 1751 /// 1752 /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use 1753 /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. 1754 /// 1755 /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`. 1756 /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. 1757 /// 1758 /// [`IPv4` address]: Ipv4Addr 1759 /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses 1760 /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses 1761 /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 1762 /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 1763 /// 1764 /// # Examples 1765 /// 1766 /// ``` 1767 /// use std::net::{Ipv4Addr, Ipv6Addr}; 1768 /// 1769 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); 1770 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), 1771 /// Some(Ipv4Addr::new(192, 10, 2, 255))); 1772 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), 1773 /// Some(Ipv4Addr::new(0, 0, 0, 1))); 1774 /// ``` 1775 #[cfg_attr( 1776 staged_api, 1777 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1778 )] 1779 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1780 #[must_use = "this returns the result of the operation, \ 1781 without modifying the original"] 1782 #[inline] to_ipv4(&self) -> Option<Ipv4Addr>1783 pub const fn to_ipv4(&self) -> Option<Ipv4Addr> { 1784 if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { 1785 let [a, b] = ab.to_be_bytes(); 1786 let [c, d] = cd.to_be_bytes(); 1787 Some(Ipv4Addr::new(a, b, c, d)) 1788 } else { 1789 None 1790 } 1791 } 1792 1793 /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it 1794 /// returns self wrapped in an `IpAddr::V6`. 1795 /// 1796 /// # Examples 1797 /// 1798 /// ``` 1799 /// #![feature(ip)] 1800 /// use std::net::Ipv6Addr; 1801 /// 1802 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); 1803 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); 1804 /// ``` 1805 #[cfg_attr( 1806 staged_api, 1807 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1808 )] 1809 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1810 #[must_use = "this returns the result of the operation, \ 1811 without modifying the original"] 1812 #[inline] to_canonical(&self) -> IpAddr1813 pub const fn to_canonical(&self) -> IpAddr { 1814 if let Some(mapped) = self.to_ipv4_mapped() { 1815 return IpAddr::V4(mapped); 1816 } 1817 IpAddr::V6(*self) 1818 } 1819 1820 /// Returns the sixteen eight-bit integers the IPv6 address consists of. 1821 /// 1822 /// ``` 1823 /// use std::net::Ipv6Addr; 1824 /// 1825 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), 1826 /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 1827 /// ``` 1828 #[cfg_attr( 1829 staged_api, 1830 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 1831 )] 1832 #[cfg_attr(staged_api, stable(feature = "ipv6_to_octets", since = "1.12.0"))] 1833 #[must_use] 1834 #[inline] octets(&self) -> [u8; 16]1835 pub const fn octets(&self) -> [u8; 16] { 1836 self.octets 1837 } 1838 } 1839 1840 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1841 impl PartialEq<IpAddr> for Ipv6Addr { 1842 #[inline] eq(&self, other: &IpAddr) -> bool1843 fn eq(&self, other: &IpAddr) -> bool { 1844 match other { 1845 IpAddr::V4(_) => false, 1846 IpAddr::V6(v6) => self == v6, 1847 } 1848 } 1849 } 1850 1851 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1852 impl PartialEq<Ipv6Addr> for IpAddr { 1853 #[inline] eq(&self, other: &Ipv6Addr) -> bool1854 fn eq(&self, other: &Ipv6Addr) -> bool { 1855 match self { 1856 IpAddr::V4(_) => false, 1857 IpAddr::V6(v6) => v6 == other, 1858 } 1859 } 1860 } 1861 1862 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1863 impl PartialOrd for Ipv6Addr { 1864 #[inline] partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering>1865 fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { 1866 Some(self.cmp(other)) 1867 } 1868 } 1869 1870 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1871 impl PartialOrd<Ipv6Addr> for IpAddr { 1872 #[inline] partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering>1873 fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { 1874 match self { 1875 IpAddr::V4(_) => Some(Ordering::Less), 1876 IpAddr::V6(v6) => v6.partial_cmp(other), 1877 } 1878 } 1879 } 1880 1881 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1882 impl PartialOrd<IpAddr> for Ipv6Addr { 1883 #[inline] partial_cmp(&self, other: &IpAddr) -> Option<Ordering>1884 fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { 1885 match other { 1886 IpAddr::V4(_) => Some(Ordering::Greater), 1887 IpAddr::V6(v6) => self.partial_cmp(v6), 1888 } 1889 } 1890 } 1891 1892 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1893 impl Ord for Ipv6Addr { 1894 #[inline] cmp(&self, other: &Ipv6Addr) -> Ordering1895 fn cmp(&self, other: &Ipv6Addr) -> Ordering { 1896 self.segments().cmp(&other.segments()) 1897 } 1898 } 1899 1900 #[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] 1901 impl From<Ipv6Addr> for u128 { 1902 /// Convert an `Ipv6Addr` into a host byte order `u128`. 1903 /// 1904 /// # Examples 1905 /// 1906 /// ``` 1907 /// use std::net::Ipv6Addr; 1908 /// 1909 /// let addr = Ipv6Addr::new( 1910 /// 0x1020, 0x3040, 0x5060, 0x7080, 1911 /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, 1912 /// ); 1913 /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); 1914 /// ``` 1915 #[inline] from(ip: Ipv6Addr) -> u1281916 fn from(ip: Ipv6Addr) -> u128 { 1917 u128::from_be_bytes(ip.octets) 1918 } 1919 } 1920 #[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] 1921 impl From<u128> for Ipv6Addr { 1922 /// Convert a host byte order `u128` into an `Ipv6Addr`. 1923 /// 1924 /// # Examples 1925 /// 1926 /// ``` 1927 /// use std::net::Ipv6Addr; 1928 /// 1929 /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); 1930 /// assert_eq!( 1931 /// Ipv6Addr::new( 1932 /// 0x1020, 0x3040, 0x5060, 0x7080, 1933 /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, 1934 /// ), 1935 /// addr); 1936 /// ``` 1937 #[inline] from(ip: u128) -> Ipv6Addr1938 fn from(ip: u128) -> Ipv6Addr { 1939 Ipv6Addr::from(ip.to_be_bytes()) 1940 } 1941 } 1942 1943 #[cfg_attr(staged_api, stable(feature = "ipv6_from_octets", since = "1.9.0"))] 1944 impl From<[u8; 16]> for Ipv6Addr { 1945 /// Creates an `Ipv6Addr` from a sixteen element byte array. 1946 /// 1947 /// # Examples 1948 /// 1949 /// ``` 1950 /// use std::net::Ipv6Addr; 1951 /// 1952 /// let addr = Ipv6Addr::from([ 1953 /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, 1954 /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, 1955 /// ]); 1956 /// assert_eq!( 1957 /// Ipv6Addr::new( 1958 /// 0x1918, 0x1716, 1959 /// 0x1514, 0x1312, 1960 /// 0x1110, 0x0f0e, 1961 /// 0x0d0c, 0x0b0a 1962 /// ), 1963 /// addr 1964 /// ); 1965 /// ``` 1966 #[inline] from(octets: [u8; 16]) -> Ipv6Addr1967 fn from(octets: [u8; 16]) -> Ipv6Addr { 1968 Ipv6Addr { octets } 1969 } 1970 } 1971 1972 #[cfg_attr(staged_api, stable(feature = "ipv6_from_segments", since = "1.16.0"))] 1973 impl From<[u16; 8]> for Ipv6Addr { 1974 /// Creates an `Ipv6Addr` from an eight element 16-bit array. 1975 /// 1976 /// # Examples 1977 /// 1978 /// ``` 1979 /// use std::net::Ipv6Addr; 1980 /// 1981 /// let addr = Ipv6Addr::from([ 1982 /// 525u16, 524u16, 523u16, 522u16, 1983 /// 521u16, 520u16, 519u16, 518u16, 1984 /// ]); 1985 /// assert_eq!( 1986 /// Ipv6Addr::new( 1987 /// 0x20d, 0x20c, 1988 /// 0x20b, 0x20a, 1989 /// 0x209, 0x208, 1990 /// 0x207, 0x206 1991 /// ), 1992 /// addr 1993 /// ); 1994 /// ``` 1995 #[inline] from(segments: [u16; 8]) -> Ipv6Addr1996 fn from(segments: [u16; 8]) -> Ipv6Addr { 1997 let [a, b, c, d, e, f, g, h] = segments; 1998 Ipv6Addr::new(a, b, c, d, e, f, g, h) 1999 } 2000 } 2001 2002 #[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] 2003 impl From<[u8; 16]> for IpAddr { 2004 /// Creates an `IpAddr::V6` from a sixteen element byte array. 2005 /// 2006 /// # Examples 2007 /// 2008 /// ``` 2009 /// use std::net::{IpAddr, Ipv6Addr}; 2010 /// 2011 /// let addr = IpAddr::from([ 2012 /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, 2013 /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, 2014 /// ]); 2015 /// assert_eq!( 2016 /// IpAddr::V6(Ipv6Addr::new( 2017 /// 0x1918, 0x1716, 2018 /// 0x1514, 0x1312, 2019 /// 0x1110, 0x0f0e, 2020 /// 0x0d0c, 0x0b0a 2021 /// )), 2022 /// addr 2023 /// ); 2024 /// ``` 2025 #[inline] from(octets: [u8; 16]) -> IpAddr2026 fn from(octets: [u8; 16]) -> IpAddr { 2027 IpAddr::V6(Ipv6Addr::from(octets)) 2028 } 2029 } 2030 2031 #[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] 2032 impl From<[u16; 8]> for IpAddr { 2033 /// Creates an `IpAddr::V6` from an eight element 16-bit array. 2034 /// 2035 /// # Examples 2036 /// 2037 /// ``` 2038 /// use std::net::{IpAddr, Ipv6Addr}; 2039 /// 2040 /// let addr = IpAddr::from([ 2041 /// 525u16, 524u16, 523u16, 522u16, 2042 /// 521u16, 520u16, 519u16, 518u16, 2043 /// ]); 2044 /// assert_eq!( 2045 /// IpAddr::V6(Ipv6Addr::new( 2046 /// 0x20d, 0x20c, 2047 /// 0x20b, 0x20a, 2048 /// 0x209, 0x208, 2049 /// 0x207, 0x206 2050 /// )), 2051 /// addr 2052 /// ); 2053 /// ``` 2054 #[inline] from(segments: [u16; 8]) -> IpAddr2055 fn from(segments: [u16; 8]) -> IpAddr { 2056 IpAddr::V6(Ipv6Addr::from(segments)) 2057 } 2058 } 2059