Skip to content

Commit 2eee495

Browse files
committed
fix Ipv6Addr::to_ipv4
The IPv4 address used in the IPv4-compatible IPv6 address must be a globally-unique IPv4 unicast address.
1 parent 12799ad commit 2eee495

File tree

1 file changed

+20
-19
lines changed

1 file changed

+20
-19
lines changed

library/std/src/net/ip.rs

+20-19
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@ impl Ipv4Addr {
758758
///
759759
/// a.b.c.d becomes ::a.b.c.d
760760
///
761+
/// Note: The IPv4 address used in the IPv4-compatible IPv6 address must be a
762+
/// globally-unique IPv4 unicast address. This implementation does *not* check for it.
763+
///
761764
/// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html
762765
///
763766
/// # Examples
@@ -1493,6 +1496,9 @@ impl Ipv6Addr {
14931496
///
14941497
/// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
14951498
///
1499+
/// Note: The IPv4 address used in the IPv4-compatible IPv6 address must be a
1500+
/// globally-unique IPv4 unicast address.
1501+
///
14961502
/// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html
14971503
/// [`None`]: ../../std/option/enum.Option.html#variant.None
14981504
///
@@ -1504,14 +1510,19 @@ impl Ipv6Addr {
15041510
/// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
15051511
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
15061512
/// Some(Ipv4Addr::new(192, 10, 2, 255)));
1507-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
1508-
/// Some(Ipv4Addr::new(0, 0, 0, 1)));
1513+
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), None);
1514+
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
1515+
/// Some(Ipv4Addr::new(18, 52, 86, 120)));
15091516
/// ```
15101517
#[stable(feature = "rust1", since = "1.0.0")]
15111518
pub fn to_ipv4(&self) -> Option<Ipv4Addr> {
1512-
match self.segments() {
1513-
[0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => {
1514-
Some(Ipv4Addr::new((g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8))
1519+
match self.octets() {
1520+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
1521+
Some(Ipv4Addr::new(a, b, c, d))
1522+
}
1523+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] => {
1524+
let ipv4 = Ipv4Addr::new(a, b, c, d);
1525+
if ipv4.is_global() { Some(ipv4) } else { None }
15151526
}
15161527
_ => None,
15171528
}
@@ -1542,13 +1553,7 @@ impl fmt::Display for Ipv6Addr {
15421553
if f.precision().is_none() && f.width().is_none() {
15431554
let segments = self.segments();
15441555

1545-
// Special case for :: and ::1; otherwise they get written with the
1546-
// IPv4 formatter
1547-
if self.is_unspecified() {
1548-
f.write_str("::")
1549-
} else if self.is_loopback() {
1550-
f.write_str("::1")
1551-
} else if let Some(ipv4) = self.to_ipv4() {
1556+
if let Some(ipv4) = self.to_ipv4() {
15521557
match segments[5] {
15531558
// IPv4 Compatible address
15541559
0 => write!(f, "::{}", ipv4),
@@ -2025,8 +2030,8 @@ mod tests {
20252030
assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
20262031

20272032
// ipv4-compatible address
2028-
let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
2029-
assert_eq!(a1.to_string(), "::192.0.2.128");
2033+
let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x102, 0x304);
2034+
assert_eq!(a1.to_string(), "::1.2.3.4");
20302035

20312036
// v6 address with no zero segments
20322037
assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
@@ -2495,11 +2500,7 @@ mod tests {
24952500

24962501
check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
24972502

2498-
check!(
2499-
"::0.0.0.2",
2500-
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
2501-
global | unicast_global
2502-
);
2503+
check!("::2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
25032504

25042505
check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
25052506

0 commit comments

Comments
 (0)