]> git.lizzy.rs Git - rust.git/commitdiff
Disallow octal format in Ipv4 string
authorCheng XU <git@xuc.me>
Tue, 30 Mar 2021 02:24:23 +0000 (10:24 +0800)
committerCheng XU <git@xuc.me>
Tue, 30 Mar 2021 02:24:23 +0000 (10:24 +0800)
In its original specification, leading zero in Ipv4 string is interpreted
as octal literals. So a IP address 0127.0.0.1 actually means 87.0.0.1.

This confusion can lead to many security vulnerabilities. Therefore, in
[IETF RFC 6943], it suggests to disallow octal/hexadecimal format in Ipv4
string all together.

Existing implementation already disallows hexadecimal numbers. This commit
makes Parser reject octal numbers.

Fixes #83648.

[IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1

library/std/src/net/ip.rs
library/std/src/net/parser.rs
library/std/src/net/parser/tests.rs

index 2aa305d7f831eacc3d86e62587cc207ade95f6d8..7f8c33dac561ff11546e95f433ea512eecf00daa 100644 (file)
@@ -67,7 +67,9 @@ 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].
 ///
+/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
 /// [`FromStr`]: crate::str::FromStr
 ///
 /// # Examples
index 7064ed3ed236d9162b73fee4e4a2d03d1326d787..88a8cb76befbf61b794cbf994efa6cbeefafa964 100644 (file)
@@ -67,6 +67,11 @@ fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
         if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
     }
 
+    /// Peek the next character from the input
+    fn peek_char(&self) -> Option<char> {
+        self.state.first().map(|&b| char::from(b))
+    }
+
     /// Read the next character from the input
     fn read_char(&mut self) -> Option<char> {
         self.state.split_first().map(|(&b, tail)| {
@@ -132,7 +137,14 @@ fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
             let mut groups = [0; 4];
 
             for (i, slot) in groups.iter_mut().enumerate() {
-                *slot = p.read_separator('.', i, |p| p.read_number(10, None))?;
+                *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,
+                    }
+                })?;
             }
 
             Some(groups.into())
index 8d8889cd19d36757d44ae2ecbcd3e5b2a5fd88ce..6d2d48ecad02f8775a23f17f3d8436a5b334d82e 100644 (file)
@@ -8,11 +8,15 @@
 const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
 const IPV4_STR: &str = "192.168.0.1";
 const IPV4_STR_PORT: &str = "192.168.0.1:8080";
+const IPV4_STR_WITH_OCTAL: &str = "0127.0.0.1";
+const IPV4_STR_WITH_HEX: &str = "0x10.0.0.1";
 
 const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1);
 const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1";
 const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
 const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
+const IPV6_STR_V4_WITH_OCTAL: &str = "2001:db8::0127.0.0.1";
+const IPV6_STR_V4_WITH_HEX: &str = "2001:db8::0x10.0.0.1";
 const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
 const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080";
 
@@ -22,6 +26,8 @@ fn parse_ipv4() {
     assert_eq!(result, IPV4);
 
     assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err());
+    assert!(Ipv4Addr::from_str(IPV4_STR_WITH_OCTAL).is_err());
+    assert!(Ipv4Addr::from_str(IPV4_STR_WITH_HEX).is_err());
     assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err());
     assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err());
     assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err());
@@ -39,6 +45,8 @@ fn parse_ipv6() {
     let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap();
     assert_eq!(result, IPV6);
 
+    assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_OCTAL).is_err());
+    assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_HEX).is_err());
     assert!(Ipv6Addr::from_str(IPV4_STR).is_err());
     assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err());
     assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err());