| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License.. |
| |
| use sgx_trts::libc as c; |
| use core::cmp::Ordering; |
| use core::fmt; |
| use core::hash; |
| use crate::io::Write; |
| use crate::sys_common::{AsInner, FromInner}; |
| |
| /// An IP address, either IPv4 or IPv6. |
| /// |
| /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their |
| /// respective documentation for more details. |
| /// |
| /// The size of an `IpAddr` instance may vary depending on the target operating |
| /// system. |
| /// |
| /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html |
| /// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html |
| /// |
| #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] |
| pub enum IpAddr { |
| /// An IPv4 address. |
| V4(Ipv4Addr), |
| /// An IPv6 address. |
| V6(Ipv6Addr), |
| } |
| |
| /// An IPv4 address. |
| /// |
| /// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. |
| /// They are usually represented as four octets. |
| /// |
| /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. |
| /// |
| /// The size of an `Ipv4Addr` struct may vary depending on the target operating |
| /// system. |
| /// |
| /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 |
| /// [`IpAddr`]: ../../std/net/enum.IpAddr.html |
| /// |
| /// # Textual representation |
| /// |
| /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal |
| /// notation, divided by `.` (this is called "dot-decimal notation"). |
| /// |
| /// [`FromStr`]: ../../std/str/trait.FromStr.html |
| /// |
| #[derive(Copy)] |
| pub struct Ipv4Addr { |
| inner: c::in_addr, |
| } |
| |
| /// An IPv6 address. |
| /// |
| /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. |
| /// They are usually represented as eight 16-bit segments. |
| /// |
| /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. |
| /// |
| /// The size of an `Ipv6Addr` struct may vary depending on the target operating |
| /// system. |
| /// |
| /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
| /// [`IpAddr`]: ../../std/net/enum.IpAddr.html |
| /// |
| /// # Textual representation |
| /// |
| /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent |
| /// an IPv6 address in text, but in general, each segments is written in hexadecimal |
| /// notation, and segments are separated by `:`. For more information, see |
| /// [IETF RFC 5952]. |
| /// |
| /// [`FromStr`]: ../../std/str/trait.FromStr.html |
| /// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 |
| /// |
| #[derive(Copy)] |
| pub struct Ipv6Addr { |
| inner: c::in6_addr, |
| } |
| |
| #[allow(missing_docs)] |
| #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] |
| pub enum Ipv6MulticastScope { |
| InterfaceLocal, |
| LinkLocal, |
| RealmLocal, |
| AdminLocal, |
| SiteLocal, |
| OrganizationLocal, |
| Global, |
| } |
| |
| impl IpAddr { |
| /// Returns [`true`] for the special 'unspecified' address. |
| /// |
| /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and |
| /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. |
| /// |
| /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified |
| /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_unspecified(&self) -> bool { |
| match self { |
| IpAddr::V4(ip) => ip.is_unspecified(), |
| IpAddr::V6(ip) => ip.is_unspecified(), |
| } |
| } |
| |
| /// Returns [`true`] if this is a loopback address. |
| /// |
| /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and |
| /// [`Ipv6Addr::is_loopback`][IPv6] for more details. |
| /// |
| /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback |
| /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_loopback(&self) -> bool { |
| match self { |
| IpAddr::V4(ip) => ip.is_loopback(), |
| IpAddr::V6(ip) => ip.is_loopback(), |
| } |
| } |
| |
| /// Returns [`true`] if the address appears to be globally routable. |
| /// |
| /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and |
| /// [`Ipv6Addr::is_global`][IPv6] for more details. |
| /// |
| /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global |
| /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_global(&self) -> bool { |
| match self { |
| IpAddr::V4(ip) => ip.is_global(), |
| IpAddr::V6(ip) => ip.is_global(), |
| } |
| } |
| |
| /// Returns [`true`] if this is a multicast address. |
| /// |
| /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and |
| /// [`Ipv6Addr::is_multicast`][IPv6] for more details. |
| /// |
| /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast |
| /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_multicast(&self) -> bool { |
| match self { |
| IpAddr::V4(ip) => ip.is_multicast(), |
| IpAddr::V6(ip) => ip.is_multicast(), |
| } |
| } |
| |
| /// Returns [`true`] if this address is in a range designated for documentation. |
| /// |
| /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and |
| /// [`Ipv6Addr::is_documentation`][IPv6] for more details. |
| /// |
| /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation |
| /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_documentation(&self) -> bool { |
| match self { |
| IpAddr::V4(ip) => ip.is_documentation(), |
| IpAddr::V6(ip) => ip.is_documentation(), |
| } |
| } |
| |
| /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. |
| /// |
| /// [`true`]: ../../std/primitive.bool.html |
| /// [`false`]: ../../std/primitive.bool.html |
| /// [IPv4 address]: #variant.V4 |
| /// |
| pub fn is_ipv4(&self) -> bool { |
| matches!(self, IpAddr::V4(_)) |
| } |
| |
| /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. |
| /// |
| /// [`true`]: ../../std/primitive.bool.html |
| /// [`false`]: ../../std/primitive.bool.html |
| /// [IPv6 address]: #variant.V6 |
| /// |
| pub fn is_ipv6(&self) -> bool { |
| matches!(self, IpAddr::V6(_)) |
| } |
| } |
| |
| impl Ipv4Addr { |
| /// Creates a new IPv4 address from four eight-bit octets. |
| /// |
| /// The result will represent the IP address `a`.`b`.`c`.`d`. |
| /// |
| pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { |
| // FIXME: should just be u32::from_be_bytes([a, b, c, d]), |
| // once that method is no longer rustc_const_unstable |
| Ipv4Addr { |
| inner: c::in_addr { |
| s_addr: u32::to_be( |
| ((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | (d as u32), |
| ), |
| }, |
| } |
| } |
| |
| /// An IPv4 address with the address pointing to localhost: 127.0.0.1. |
| /// |
| pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); |
| |
| /// An IPv4 address representing an unspecified address: 0.0.0.0 |
| /// |
| pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); |
| |
| /// An IPv4 address representing the broadcast address: 255.255.255.255 |
| /// |
| pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); |
| |
| /// Returns the four eight-bit integers that make up this address. |
| /// |
| pub fn octets(&self) -> [u8; 4] { |
| // This returns the order we want because s_addr is stored in big-endian. |
| self.inner.s_addr.to_ne_bytes() |
| } |
| |
| /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). |
| /// |
| /// This property is defined in _UNIX Network Programming, Second Edition_, |
| /// W. Richard Stevens, p. 891; see also [ip7]. |
| /// |
| /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub const fn is_unspecified(&self) -> bool { |
| self.inner.s_addr == 0 |
| } |
| |
| /// Returns [`true`] if this is a loopback address (127.0.0.0/8). |
| /// |
| /// This property is defined by [IETF RFC 1122]. |
| /// |
| /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_loopback(&self) -> bool { |
| self.octets()[0] == 127 |
| } |
| |
| /// Returns [`true`] if this is a private address. |
| /// |
| /// The private address ranges are defined in [IETF RFC 1918] and include: |
| /// |
| /// - 10.0.0.0/8 |
| /// - 172.16.0.0/12 |
| /// - 192.168.0.0/16 |
| /// |
| /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_private(&self) -> bool { |
| match self.octets() { |
| [10, ..] => true, |
| [172, b, ..] if b >= 16 && b <= 31 => true, |
| [192, 168, ..] => true, |
| _ => false, |
| } |
| } |
| |
| /// Returns [`true`] if the address is link-local (169.254.0.0/16). |
| /// |
| /// This property is defined by [IETF RFC 3927]. |
| /// |
| /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_link_local(&self) -> bool { |
| match self.octets() { |
| [169, 254, ..] => true, |
| _ => false, |
| } |
| } |
| |
| /// Returns [`true`] if the address appears to be globally routable. |
| /// See [iana-ipv4-special-registry][ipv4-sr]. |
| /// |
| /// The following return false: |
| /// |
| /// - private addresses (see [`is_private()`](#method.is_private)) |
| /// - the loopback address (see [`is_loopback()`](#method.is_loopback)) |
| /// - the link-local address (see [`is_link_local()`](#method.is_link_local)) |
| /// - the broadcast address (see [`is_broadcast()`](#method.is_broadcast)) |
| /// - addresses used for documentation (see [`is_documentation()`](#method.is_documentation)) |
| /// - the unspecified address (see [`is_unspecified()`](#method.is_unspecified)), and the whole |
| /// 0.0.0.0/8 block |
| /// - addresses reserved for future protocols (see |
| /// [`is_ietf_protocol_assignment()`](#method.is_ietf_protocol_assignment), except |
| /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable |
| /// - addresses reserved for future use (see [`is_reserved()`](#method.is_reserved) |
| /// - addresses reserved for networking devices benchmarking (see |
| /// [`is_benchmarking`](#method.is_benchmarking)) |
| /// |
| /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_global(&self) -> bool { |
| // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two |
| // globally routable addresses in the 192.0.0.0/24 range. |
| if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { |
| return true; |
| } |
| !self.is_private() |
| && !self.is_loopback() |
| && !self.is_link_local() |
| && !self.is_broadcast() |
| && !self.is_documentation() |
| && !self.is_shared() |
| && !self.is_ietf_protocol_assignment() |
| && !self.is_reserved() |
| && !self.is_benchmarking() |
| // Make sure the address is not in 0.0.0.0/8 |
| && self.octets()[0] != 0 |
| } |
| |
| /// Returns [`true`] if this address is part of the Shared Address Space defined in |
| /// [IETF RFC 6598] (`100.64.0.0/10`). |
| /// |
| /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_shared(&self) -> bool { |
| self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) |
| } |
| |
| /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to |
| /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890]. |
| /// |
| /// Note that parts of this block are in use: |
| /// |
| /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600]) |
| /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) |
| /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) |
| /// |
| /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 |
| /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 |
| /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 |
| /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_ietf_protocol_assignment(&self) -> bool { |
| self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 |
| } |
| |
| /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for |
| /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` |
| /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. |
| /// |
| /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 |
| /// [errata 423]: https://www.rfc-editor.org/errata/eid423 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_benchmarking(&self) -> bool { |
| self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 |
| } |
| |
| /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] |
| /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the |
| /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since |
| /// it is obviously not reserved for future use. |
| /// |
| /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| /// # Warning |
| /// |
| /// As IANA assigns new addresses, this method will be |
| /// updated. This may result in non-reserved addresses being |
| /// treated as reserved in code that relies on an outdated version |
| /// of this method. |
| /// |
| pub fn is_reserved(&self) -> bool { |
| self.octets()[0] & 240 == 240 && !self.is_broadcast() |
| } |
| |
| /// Returns [`true`] if this is a multicast address (224.0.0.0/4). |
| /// |
| /// Multicast addresses have a most significant octet between 224 and 239, |
| /// and is defined by [IETF RFC 5771]. |
| /// |
| /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_multicast(&self) -> bool { |
| self.octets()[0] >= 224 && self.octets()[0] <= 239 |
| } |
| |
| /// Returns [`true`] if this is a broadcast address (255.255.255.255). |
| /// |
| /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. |
| /// |
| /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_broadcast(&self) -> bool { |
| self == &Self::BROADCAST |
| } |
| |
| /// Returns [`true`] if this address is in a range designated for documentation. |
| /// |
| /// This is defined in [IETF RFC 5737]: |
| /// |
| /// - 192.0.2.0/24 (TEST-NET-1) |
| /// - 198.51.100.0/24 (TEST-NET-2) |
| /// - 203.0.113.0/24 (TEST-NET-3) |
| /// |
| /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_documentation(&self) -> bool { |
| match self.octets() { |
| [192, 0, 2, _] => true, |
| [198, 51, 100, _] => true, |
| [203, 0, 113, _] => true, |
| _ => false, |
| } |
| } |
| |
| /// Converts this address to an IPv4-compatible [IPv6 address]. |
| /// |
| /// a.b.c.d becomes ::a.b.c.d |
| /// |
| /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html |
| /// |
| pub fn to_ipv6_compatible(&self) -> Ipv6Addr { |
| let octets = self.octets(); |
| Ipv6Addr::from([ |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, octets[0], octets[1], octets[2], octets[3], |
| ]) |
| } |
| |
| /// Converts this address to an IPv4-mapped [IPv6 address]. |
| /// |
| /// a.b.c.d becomes ::ffff:a.b.c.d |
| /// |
| /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html |
| /// |
| pub fn to_ipv6_mapped(&self) -> Ipv6Addr { |
| let octets = self.octets(); |
| Ipv6Addr::from([ |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, octets[0], octets[1], octets[2], octets[3], |
| ]) |
| } |
| } |
| |
| impl fmt::Display for IpAddr { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match self { |
| IpAddr::V4(ip) => ip.fmt(fmt), |
| IpAddr::V6(ip) => ip.fmt(fmt), |
| } |
| } |
| } |
| |
| impl From<Ipv4Addr> for IpAddr { |
| fn from(ipv4: Ipv4Addr) -> IpAddr { |
| IpAddr::V4(ipv4) |
| } |
| } |
| |
| impl From<Ipv6Addr> for IpAddr { |
| /// Copies this address to a new `IpAddr::V6`. |
| /// |
| fn from(ipv6: Ipv6Addr) -> IpAddr { |
| IpAddr::V6(ipv6) |
| } |
| } |
| |
| impl fmt::Display for Ipv4Addr { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address |
| let mut buf = [0u8; IPV4_BUF_LEN]; |
| let mut buf_slice = &mut buf[..]; |
| let octets = self.octets(); |
| // Note: The call to write should never fail, hence the unwrap |
| write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); |
| let len = IPV4_BUF_LEN - buf_slice.len(); |
| // This unsafe is OK because we know what is being written to the buffer |
| let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; |
| fmt.pad(buf) |
| } |
| } |
| |
| impl fmt::Debug for Ipv4Addr { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| fmt::Display::fmt(self, fmt) |
| } |
| } |
| |
| impl Clone for Ipv4Addr { |
| fn clone(&self) -> Ipv4Addr { |
| *self |
| } |
| } |
| |
| impl PartialEq for Ipv4Addr { |
| fn eq(&self, other: &Ipv4Addr) -> bool { |
| self.inner.s_addr == other.inner.s_addr |
| } |
| } |
| |
| impl PartialEq<Ipv4Addr> for IpAddr { |
| fn eq(&self, other: &Ipv4Addr) -> bool { |
| match self { |
| IpAddr::V4(v4) => v4 == other, |
| IpAddr::V6(_) => false, |
| } |
| } |
| } |
| |
| impl PartialEq<IpAddr> for Ipv4Addr { |
| fn eq(&self, other: &IpAddr) -> bool { |
| match other { |
| IpAddr::V4(v4) => self == v4, |
| IpAddr::V6(_) => false, |
| } |
| } |
| } |
| |
| impl Eq for Ipv4Addr {} |
| |
| impl hash::Hash for Ipv4Addr { |
| fn hash<H: hash::Hasher>(&self, s: &mut H) { |
| // `inner` is #[repr(packed)], so we need to copy `s_addr`. |
| { self.inner.s_addr }.hash(s) |
| } |
| } |
| |
| impl PartialOrd for Ipv4Addr { |
| fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { |
| Some(self.cmp(other)) |
| } |
| } |
| |
| impl PartialOrd<Ipv4Addr> for IpAddr { |
| fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { |
| match self { |
| IpAddr::V4(v4) => v4.partial_cmp(other), |
| IpAddr::V6(_) => Some(Ordering::Greater), |
| } |
| } |
| } |
| |
| impl PartialOrd<IpAddr> for Ipv4Addr { |
| fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { |
| match other { |
| IpAddr::V4(v4) => self.partial_cmp(v4), |
| IpAddr::V6(_) => Some(Ordering::Less), |
| } |
| } |
| } |
| |
| impl Ord for Ipv4Addr { |
| fn cmp(&self, other: &Ipv4Addr) -> Ordering { |
| u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) |
| } |
| } |
| |
| impl AsInner<c::in_addr> for Ipv4Addr { |
| fn as_inner(&self) -> &c::in_addr { |
| &self.inner |
| } |
| } |
| impl FromInner<c::in_addr> for Ipv4Addr { |
| fn from_inner(addr: c::in_addr) -> Ipv4Addr { |
| Ipv4Addr { inner: addr } |
| } |
| } |
| |
| impl From<Ipv4Addr> for u32 { |
| /// Converts an `Ipv4Addr` into a host byte order `u32`. |
| /// |
| fn from(ip: Ipv4Addr) -> u32 { |
| let ip = ip.octets(); |
| u32::from_be_bytes(ip) |
| } |
| } |
| |
| impl From<u32> for Ipv4Addr { |
| /// Converts a host byte order `u32` into an `Ipv4Addr`. |
| /// |
| fn from(ip: u32) -> Ipv4Addr { |
| Ipv4Addr::from(ip.to_be_bytes()) |
| } |
| } |
| |
| impl From<[u8; 4]> for Ipv4Addr { |
| /// Creates an `Ipv4Addr` from a four element byte array. |
| /// |
| fn from(octets: [u8; 4]) -> Ipv4Addr { |
| Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) |
| } |
| } |
| |
| impl From<[u8; 4]> for IpAddr { |
| /// Creates an `IpAddr::V4` from a four element byte array. |
| /// |
| fn from(octets: [u8; 4]) -> IpAddr { |
| IpAddr::V4(Ipv4Addr::from(octets)) |
| } |
| } |
| |
| impl Ipv6Addr { |
| /// Creates a new IPv6 address from eight 16-bit segments. |
| /// |
| /// The result will represent the IP address `a:b:c:d:e:f:g:h`. |
| /// |
| pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { |
| Ipv6Addr { |
| inner: c::in6_addr { |
| s6_addr: [ |
| (a >> 8) as u8, |
| a as u8, |
| (b >> 8) as u8, |
| b as u8, |
| (c >> 8) as u8, |
| c as u8, |
| (d >> 8) as u8, |
| d as u8, |
| (e >> 8) as u8, |
| e as u8, |
| (f >> 8) as u8, |
| f as u8, |
| (g >> 8) as u8, |
| g as u8, |
| (h >> 8) as u8, |
| h as u8, |
| ], |
| }, |
| } |
| } |
| |
| /// An IPv6 address representing localhost: `::1`. |
| /// |
| pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); |
| |
| /// An IPv6 address representing the unspecified address: `::` |
| /// |
| pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); |
| |
| /// Returns the eight 16-bit segments that make up this address. |
| /// |
| pub fn segments(&self) -> [u16; 8] { |
| let arr = &self.inner.s6_addr; |
| [ |
| u16::from_be_bytes([arr[0], arr[1]]), |
| u16::from_be_bytes([arr[2], arr[3]]), |
| u16::from_be_bytes([arr[4], arr[5]]), |
| u16::from_be_bytes([arr[6], arr[7]]), |
| u16::from_be_bytes([arr[8], arr[9]]), |
| u16::from_be_bytes([arr[10], arr[11]]), |
| u16::from_be_bytes([arr[12], arr[13]]), |
| u16::from_be_bytes([arr[14], arr[15]]), |
| ] |
| } |
| |
| /// Returns [`true`] for the special 'unspecified' address (::). |
| /// |
| /// This property is defined in [IETF RFC 4291]. |
| /// |
| /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_unspecified(&self) -> bool { |
| self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] |
| } |
| |
| /// Returns [`true`] if this is a loopback address (::1). |
| /// |
| /// This property is defined in [IETF RFC 4291]. |
| /// |
| /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_loopback(&self) -> bool { |
| self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] |
| } |
| |
| /// Returns [`true`] if the address appears to be globally routable. |
| /// |
| /// The following return [`false`]: |
| /// |
| /// - the loopback address |
| /// - link-local and unique local unicast addresses |
| /// - interface-, link-, realm-, admin- and site-local multicast addresses |
| /// |
| /// [`true`]: ../../std/primitive.bool.html |
| /// [`false`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_global(&self) -> bool { |
| match self.multicast_scope() { |
| Some(Ipv6MulticastScope::Global) => true, |
| None => self.is_unicast_global(), |
| _ => false, |
| } |
| } |
| |
| /// Returns [`true`] if this is a unique local address (`fc00::/7`). |
| /// |
| /// This property is defined in [IETF RFC 4193]. |
| /// |
| /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_unique_local(&self) -> bool { |
| (self.segments()[0] & 0xfe00) == 0xfc00 |
| } |
| |
| /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). |
| /// |
| /// A common mis-conception is to think that "unicast link-local addresses start with |
| /// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses: |
| /// |
| /// ```no_rust |
| /// | 10 | |
| /// | bits | 54 bits | 64 bits | |
| /// +----------+-------------------------+----------------------------+ |
| /// |1111111010| 0 | interface ID | |
| /// +----------+-------------------------+----------------------------+ |
| /// ``` |
| /// |
| /// This method validates the format defined in the RFC and won't recognize the following |
| /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. |
| /// If you need a less strict validation use [`is_unicast_link_local()`] instead. |
| /// |
| /// # See also |
| /// |
| /// - [IETF RFC 4291 section 2.5.6] |
| /// - [RFC 4291 errata 4406] |
| /// - [`is_unicast_link_local()`] |
| /// |
| /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
| /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 |
| /// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local |
| /// |
| pub fn is_unicast_link_local_strict(&self) -> bool { |
| (self.segments()[0] & 0xffff) == 0xfe80 |
| && (self.segments()[1] & 0xffff) == 0 |
| && (self.segments()[2] & 0xffff) == 0 |
| && (self.segments()[3] & 0xffff) == 0 |
| } |
| |
| /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). |
| /// |
| /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], |
| /// i.e. addresses with the following format: |
| /// |
| /// ```no_rust |
| /// | 10 | |
| /// | bits | 54 bits | 64 bits | |
| /// +----------+-------------------------+----------------------------+ |
| /// |1111111010| arbitratry value | interface ID | |
| /// +----------+-------------------------+----------------------------+ |
| /// ``` |
| /// |
| /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be |
| /// unicast link-local addresses, whereas [`is_unicast_link_local_strict()`] does not. If you |
| /// need a strict validation fully compliant with the RFC, use |
| /// [`is_unicast_link_local_strict()`]. |
| /// |
| /// # See also |
| /// |
| /// - [IETF RFC 4291 section 2.4] |
| /// - [RFC 4291 errata 4406] |
| /// |
| /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 |
| /// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict |
| /// |
| pub fn is_unicast_link_local(&self) -> bool { |
| (self.segments()[0] & 0xffc0) == 0xfe80 |
| } |
| |
| /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The |
| /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: |
| /// |
| /// ```no_rust |
| /// | 10 | |
| /// | bits | 54 bits | 64 bits | |
| /// +----------+-------------------------+----------------------------+ |
| /// |1111111011| subnet ID | interface ID | |
| /// +----------+-------------------------+----------------------------+ |
| /// ``` |
| /// |
| /// [`true`]: ../../std/primitive.bool.html |
| /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 |
| /// |
| /// # Warning |
| /// |
| /// As per [RFC 3879], the whole `FEC0::/10` prefix is |
| /// deprecated. New software must not support site-local |
| /// addresses. |
| /// |
| /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 |
| pub fn is_unicast_site_local(&self) -> bool { |
| (self.segments()[0] & 0xffc0) == 0xfec0 |
| } |
| |
| /// Returns [`true`] if this is an address reserved for documentation |
| /// (2001:db8::/32). |
| /// |
| /// This property is defined in [IETF RFC 3849]. |
| /// |
| /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_documentation(&self) -> bool { |
| (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) |
| } |
| |
| /// Returns [`true`] if the address is a globally routable unicast address. |
| /// |
| /// The following return false: |
| /// |
| /// - the loopback address |
| /// - the link-local addresses |
| /// - unique local addresses |
| /// - the unspecified address |
| /// - the address range reserved for documentation |
| /// |
| /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] |
| /// |
| /// ```no_rust |
| /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer |
| /// be supported in new implementations (i.e., new implementations must treat this prefix as |
| /// Global Unicast). |
| /// ``` |
| /// |
| /// [`true`]: ../../std/primitive.bool.html |
| /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 |
| /// |
| pub fn is_unicast_global(&self) -> bool { |
| !self.is_multicast() |
| && !self.is_loopback() |
| && !self.is_unicast_link_local() |
| && !self.is_unique_local() |
| && !self.is_unspecified() |
| && !self.is_documentation() |
| } |
| |
| /// Returns the address's multicast scope if the address is multicast. |
| /// |
| pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> { |
| if self.is_multicast() { |
| match self.segments()[0] & 0x000f { |
| 1 => Some(Ipv6MulticastScope::InterfaceLocal), |
| 2 => Some(Ipv6MulticastScope::LinkLocal), |
| 3 => Some(Ipv6MulticastScope::RealmLocal), |
| 4 => Some(Ipv6MulticastScope::AdminLocal), |
| 5 => Some(Ipv6MulticastScope::SiteLocal), |
| 8 => Some(Ipv6MulticastScope::OrganizationLocal), |
| 14 => Some(Ipv6MulticastScope::Global), |
| _ => None, |
| } |
| } else { |
| None |
| } |
| } |
| |
| /// Returns [`true`] if this is a multicast address (ff00::/8). |
| /// |
| /// This property is defined by [IETF RFC 4291]. |
| /// |
| /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 |
| /// [`true`]: ../../std/primitive.bool.html |
| /// |
| pub fn is_multicast(&self) -> bool { |
| (self.segments()[0] & 0xff00) == 0xff00 |
| } |
| |
| /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is |
| /// neither IPv4-compatible or IPv4-mapped. |
| /// |
| /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d |
| /// |
| /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html |
| /// [`None`]: ../../std/option/enum.Option.html#variant.None |
| /// |
| pub fn to_ipv4(&self) -> Option<Ipv4Addr> { |
| match self.segments() { |
| [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => { |
| Some(Ipv4Addr::new((g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8)) |
| } |
| _ => None, |
| } |
| } |
| |
| /// Returns the sixteen eight-bit integers the IPv6 address consists of. |
| /// |
| pub const fn octets(&self) -> [u8; 16] { |
| self.inner.s6_addr |
| } |
| } |
| |
| impl fmt::Display for Ipv6Addr { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| // Note: The calls to write should never fail, hence the unwraps in the function |
| // Long enough for the longest possible IPv6: 39 |
| const IPV6_BUF_LEN: usize = 39; |
| let mut buf = [0u8; IPV6_BUF_LEN]; |
| let mut buf_slice = &mut buf[..]; |
| |
| match self.segments() { |
| // We need special cases for :: and ::1, otherwise they're formatted |
| // as ::0.0.0.[01] |
| [0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(), |
| [0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(), |
| // Ipv4 Compatible address |
| [0, 0, 0, 0, 0, 0, g, h] => { |
| write!( |
| buf_slice, |
| "::{}.{}.{}.{}", |
| (g >> 8) as u8, |
| g as u8, |
| (h >> 8) as u8, |
| h as u8 |
| ) |
| .unwrap(); |
| } |
| // Ipv4-Mapped address |
| [0, 0, 0, 0, 0, 0xffff, g, h] => { |
| write!( |
| buf_slice, |
| "::ffff:{}.{}.{}.{}", |
| (g >> 8) as u8, |
| g as u8, |
| (h >> 8) as u8, |
| h as u8 |
| ) |
| .unwrap(); |
| } |
| _ => { |
| fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { |
| let mut longest_span_len = 0; |
| let mut longest_span_at = 0; |
| let mut cur_span_len = 0; |
| let mut cur_span_at = 0; |
| |
| for i in 0..8 { |
| if segments[i] == 0 { |
| if cur_span_len == 0 { |
| cur_span_at = i; |
| } |
| |
| cur_span_len += 1; |
| |
| if cur_span_len > longest_span_len { |
| longest_span_len = cur_span_len; |
| longest_span_at = cur_span_at; |
| } |
| } else { |
| cur_span_len = 0; |
| cur_span_at = 0; |
| } |
| } |
| |
| (longest_span_at, longest_span_len) |
| } |
| |
| let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); |
| |
| if zeros_len > 1 { |
| fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) { |
| if !segments.is_empty() { |
| write!(*buf, "{:x}", segments[0]).unwrap(); |
| for &seg in &segments[1..] { |
| write!(*buf, ":{:x}", seg).unwrap(); |
| } |
| } |
| } |
| |
| fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice); |
| write!(buf_slice, "::").unwrap(); |
| fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice); |
| } else { |
| let &[a, b, c, d, e, f, g, h] = &self.segments(); |
| write!( |
| buf_slice, |
| "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", |
| a, b, c, d, e, f, g, h |
| ) |
| .unwrap(); |
| } |
| } |
| } |
| let len = IPV6_BUF_LEN - buf_slice.len(); |
| // This is safe because we know exactly what can be in this buffer |
| let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; |
| fmt.pad(buf) |
| } |
| } |
| |
| impl fmt::Debug for Ipv6Addr { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| fmt::Display::fmt(self, fmt) |
| } |
| } |
| |
| impl Clone for Ipv6Addr { |
| fn clone(&self) -> Ipv6Addr { |
| *self |
| } |
| } |
| |
| impl PartialEq for Ipv6Addr { |
| fn eq(&self, other: &Ipv6Addr) -> bool { |
| self.inner.s6_addr == other.inner.s6_addr |
| } |
| } |
| |
| impl PartialEq<IpAddr> for Ipv6Addr { |
| fn eq(&self, other: &IpAddr) -> bool { |
| match other { |
| IpAddr::V4(_) => false, |
| IpAddr::V6(v6) => self == v6, |
| } |
| } |
| } |
| |
| impl PartialEq<Ipv6Addr> for IpAddr { |
| fn eq(&self, other: &Ipv6Addr) -> bool { |
| match self { |
| IpAddr::V4(_) => false, |
| IpAddr::V6(v6) => v6 == other, |
| } |
| } |
| } |
| |
| impl Eq for Ipv6Addr {} |
| |
| impl hash::Hash for Ipv6Addr { |
| fn hash<H: hash::Hasher>(&self, s: &mut H) { |
| self.inner.s6_addr.hash(s) |
| } |
| } |
| |
| impl PartialOrd for Ipv6Addr { |
| fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { |
| Some(self.cmp(other)) |
| } |
| } |
| |
| impl PartialOrd<Ipv6Addr> for IpAddr { |
| fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { |
| match self { |
| IpAddr::V4(_) => Some(Ordering::Less), |
| IpAddr::V6(v6) => v6.partial_cmp(other), |
| } |
| } |
| } |
| |
| impl PartialOrd<IpAddr> for Ipv6Addr { |
| fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { |
| match other { |
| IpAddr::V4(_) => Some(Ordering::Greater), |
| IpAddr::V6(v6) => self.partial_cmp(v6), |
| } |
| } |
| } |
| |
| impl Ord for Ipv6Addr { |
| fn cmp(&self, other: &Ipv6Addr) -> Ordering { |
| self.segments().cmp(&other.segments()) |
| } |
| } |
| |
| impl AsInner<c::in6_addr> for Ipv6Addr { |
| fn as_inner(&self) -> &c::in6_addr { |
| &self.inner |
| } |
| } |
| impl FromInner<c::in6_addr> for Ipv6Addr { |
| fn from_inner(addr: c::in6_addr) -> Ipv6Addr { |
| Ipv6Addr { inner: addr } |
| } |
| } |
| |
| impl From<Ipv6Addr> for u128 { |
| /// Convert an `Ipv6Addr` into a host byte order `u128`. |
| /// |
| fn from(ip: Ipv6Addr) -> u128 { |
| let ip = ip.octets(); |
| u128::from_be_bytes(ip) |
| } |
| } |
| |
| impl From<u128> for Ipv6Addr { |
| /// Convert a host byte order `u128` into an `Ipv6Addr`. |
| /// |
| fn from(ip: u128) -> Ipv6Addr { |
| Ipv6Addr::from(ip.to_be_bytes()) |
| } |
| } |
| |
| impl From<[u8; 16]> for Ipv6Addr { |
| fn from(octets: [u8; 16]) -> Ipv6Addr { |
| let inner = c::in6_addr { s6_addr: octets }; |
| Ipv6Addr::from_inner(inner) |
| } |
| } |
| |
| impl From<[u16; 8]> for Ipv6Addr { |
| /// Creates an `Ipv6Addr` from an eight element 16-bit array. |
| /// |
| fn from(segments: [u16; 8]) -> Ipv6Addr { |
| let [a, b, c, d, e, f, g, h] = segments; |
| Ipv6Addr::new(a, b, c, d, e, f, g, h) |
| } |
| } |
| |
| |
| impl From<[u8; 16]> for IpAddr { |
| /// Creates an `IpAddr::V6` from a sixteen element byte array. |
| /// |
| fn from(octets: [u8; 16]) -> IpAddr { |
| IpAddr::V6(Ipv6Addr::from(octets)) |
| } |
| } |
| |
| impl From<[u16; 8]> for IpAddr { |
| /// Creates an `IpAddr::V6` from an eight element 16-bit array. |
| /// |
| fn from(segments: [u16; 8]) -> IpAddr { |
| IpAddr::V6(Ipv6Addr::from(segments)) |
| } |
| } |