From 605504c5bf5b02026dee02bfe682ff9adf3e22cd Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sat, 19 Jun 2021 16:41:38 +0200 Subject: [PATCH] Add Ipv6Addr::is_ipv4_mapped This change consists of cherry-picking the content from the original PR[1], which got closed due to inactivity, and applying the following changes: * Resolving merge conflicts (obviously) * Linked to to_ipv4_mapped instead of to_ipv4 in the documentation (seems more appropriate) * Added the must_use and rustc_const_unstable attributes the original didn't have I think it's a reasonably useful method. [1] https://github.com/rust-lang/rust/pull/86490 --- library/core/src/net/ip_addr.rs | 25 +++++++++++++++++++++++++ library/core/tests/net/ip_addr.rs | 12 +++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 8bf15c736c3..65debde100a 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1777,6 +1777,31 @@ pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 } + /// Returns [`true`] if the address is an IPv4-mapped address (`::ffff:0:0/96`). + /// + /// IPv4-mapped addresses can be converted to their canonical IPv4 address with + /// [`to_ipv4_mapped`](Ipv6Addr::to_ipv4_mapped). + /// + /// # Examples + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// let ipv4_mapped = Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(); + /// assert_eq!(ipv4_mapped.is_ipv4_mapped(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff).is_ipv4_mapped(), true); + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_ipv4_mapped(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[must_use] + #[inline] + pub const fn is_ipv4_mapped(&self) -> bool { + matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + } + /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. /// diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs index 7530fc08487..12ef678735d 100644 --- a/library/core/tests/net/ip_addr.rs +++ b/library/core/tests/net/ip_addr.rs @@ -508,6 +508,7 @@ macro_rules! check { | multicast_realm_local | multicast_site_local | multicast_organization_local; + let ipv4_mapped: u32 = 1 << 17; if ($mask & unspecified) == unspecified { assert!(ip!($s).is_unspecified()); @@ -584,6 +585,11 @@ macro_rules! check { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::Global); } + if ($mask & ipv4_mapped) == ipv4_mapped { + assert!(ip!($s).is_ipv4_mapped()); + } else { + assert!(!ip!($s).is_ipv4_mapped()); + } } } @@ -602,6 +608,7 @@ macro_rules! check { let multicast_site_local: u32 = 1 << 13; let multicast_organization_local: u32 = 1 << 14; let multicast_global: u32 = 1 << 15; + let ipv4_mapped: u32 = 1 << 17; check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); @@ -614,7 +621,7 @@ macro_rules! check { check!( "::ffff:127.0.0.1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], - unicast_global + unicast_global | ipv4_mapped ); check!( @@ -982,6 +989,9 @@ fn ipv6_const() { const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); + const IS_IPV4_MAPPED: bool = IP_ADDRESS.is_ipv4_mapped(); + assert!(!IS_IPV4_MAPPED); + const IP_V4: Option = IP_ADDRESS.to_ipv4(); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); }