From 734bfdeaf290a64f4170f79770dfac7151951942 Mon Sep 17 00:00:00 2001 From: Smitty Date: Thu, 8 Jul 2021 14:13:42 -0400 Subject: [PATCH 1/6] Disallow octal zeros in IPv4 addresses --- library/std/src/net/ip/tests.rs | 8 ++++++++ library/std/src/net/parser.rs | 26 +++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 2109980ad058d..5ff0bd697b142 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -20,6 +20,14 @@ fn test_from_str_ipv4() { // no number between dots let none: Option = "255.0..1".parse().ok(); assert_eq!(None, none); + // octal + let none: Option = "255.0.0.01".parse().ok(); + assert_eq!(None, none); + // octal zero + let none: Option = "255.0.0.00".parse().ok(); + assert_eq!(None, none); + let none: Option = "255.0.00.0".parse().ok(); + assert_eq!(None, none); } #[test] diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index 88a8cb76befbf..d43d40400abad 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -12,7 +12,7 @@ use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::str::FromStr; -trait ReadNumberHelper: crate::marker::Sized { +trait ReadNumberHelper: crate::marker::Sized + crate::cmp::PartialEq { const ZERO: Self; fn checked_mul(&self, other: u32) -> Option; fn checked_add(&self, other: u32) -> Option; @@ -111,10 +111,12 @@ impl<'a> Parser<'a> { &mut self, radix: u32, max_digits: Option, + allow_zero_prefix: bool, ) -> Option { self.read_atomically(move |p| { let mut result = T::ZERO; let mut digit_count = 0; + let has_leading_zero = p.peek_char() == Some('0'); while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { result = result.checked_mul(radix)?; @@ -127,7 +129,16 @@ impl<'a> Parser<'a> { } } - if digit_count == 0 { None } else { Some(result) } + if digit_count == 0 { + None + } else if !allow_zero_prefix + && has_leading_zero + && (result != T::ZERO || result == T::ZERO && digit_count > 1) + { + None + } else { + Some(result) + } }) } @@ -140,10 +151,7 @@ impl<'a> Parser<'a> { *slot = p.read_separator('.', i, |p| { // Disallow octal number in IP string. // https://tools.ietf.org/html/rfc6943#section-3.1.1 - match (p.peek_char(), p.read_number(10, None)) { - (Some('0'), Some(number)) if number != 0 => None, - (_, number) => number, - } + p.read_number(10, None, false) })?; } @@ -175,7 +183,7 @@ impl<'a> Parser<'a> { } } - let group = p.read_separator(':', i, |p| p.read_number(16, Some(4))); + let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true)); match group { Some(g) => *slot = g, @@ -227,7 +235,7 @@ impl<'a> Parser<'a> { fn read_port(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char(':')?; - p.read_number(10, None) + p.read_number(10, None, true) }) } @@ -235,7 +243,7 @@ impl<'a> Parser<'a> { fn read_scope_id(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char('%')?; - p.read_number(10, None) + p.read_number(10, None, true) }) } From 69de693af96790a2414a6d37148b524fde457f53 Mon Sep 17 00:00:00 2001 From: Smitty Date: Fri, 9 Jul 2021 12:35:49 -0400 Subject: [PATCH 2/6] Clarify docs on what IPv4 octal addresses are The way octal literals are written in IP addresses differs from the way they are written in Rust code, so the way that octal/hex literals in IPs are written is explictly mentioned. --- library/std/src/net/ip.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 4b6d60d121e13..7d0c84e17704d 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -59,7 +59,8 @@ pub enum IpAddr { /// /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal /// notation, divided by `.` (this is called "dot-decimal notation"). -/// Notably, octal numbers and hexadecimal numbers are not allowed per [IETF RFC 6943]. +/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which +/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. /// /// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 /// [`FromStr`]: crate::str::FromStr @@ -72,6 +73,8 @@ pub enum IpAddr { /// let localhost = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); +/// assert!("012.004.002.000".parse::().is_err()); // all octets are in octal +/// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] From b9b97bbb9d3503381de4b1beb5fcbf69e8e4c68d Mon Sep 17 00:00:00 2001 From: Smitty Date: Fri, 9 Jul 2021 12:54:02 -0400 Subject: [PATCH 3/6] Reject too-long IPs quicker Now that there can't be a bunch of leading zeros, parsing can be optimized a bit. --- library/std/src/net/parser.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index d43d40400abad..df6bbdeab8994 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -289,7 +289,12 @@ impl FromStr for IpAddr { impl FromStr for Ipv4Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - Parser::new(s).parse_with(|p| p.read_ipv4_addr()) + // don't try to parse if too long + if s.len() > 15 { + Err(AddrParseError(())) + } else { + Parser::new(s).parse_with(|p| p.read_ipv4_addr()) + } } } From a331e5fd2c925134b8a457ded7c34f9558bb8e26 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 11 Jul 2021 11:33:39 -0400 Subject: [PATCH 4/6] Simplify leading zero checks --- library/std/src/net/parser.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index df6bbdeab8994..e233d605ce55a 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -12,7 +12,7 @@ use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::str::FromStr; -trait ReadNumberHelper: crate::marker::Sized + crate::cmp::PartialEq { +trait ReadNumberHelper: crate::marker::Sized { const ZERO: Self; fn checked_mul(&self, other: u32) -> Option; fn checked_add(&self, other: u32) -> Option; @@ -131,10 +131,7 @@ impl<'a> Parser<'a> { if digit_count == 0 { None - } else if !allow_zero_prefix - && has_leading_zero - && (result != T::ZERO || result == T::ZERO && digit_count > 1) - { + } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 { None } else { Some(result) From ace518de9a28559ff8e062b67c6a4b55287ca1a9 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 11 Jul 2021 11:37:23 -0400 Subject: [PATCH 5/6] Add example with a bunch of leading zeos --- library/std/src/net/ip.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 7d0c84e17704d..af1f72f0ae23b 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -74,6 +74,7 @@ pub enum IpAddr { /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); /// assert!("012.004.002.000".parse::().is_err()); // all octets are in octal +/// assert!("0000000.0.0.0".parse::().is_err()); // first octet is a zero in octal /// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` #[derive(Copy)] From 403d269f20c9b1d71efccf1e95ef76470dd7ebe5 Mon Sep 17 00:00:00 2001 From: Smittyvb Date: Tue, 10 Aug 2021 16:43:17 -0400 Subject: [PATCH 6/6] Specify maximum IP address length Co-authored-by: Cheng XU <3105373+xu-cheng@users.noreply.github.com> --- library/std/src/net/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index e233d605ce55a..4e16a55edece2 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -148,7 +148,7 @@ impl<'a> Parser<'a> { *slot = p.read_separator('.', i, |p| { // Disallow octal number in IP string. // https://tools.ietf.org/html/rfc6943#section-3.1.1 - p.read_number(10, None, false) + p.read_number(10, Some(3), false) })?; }