Skip to content

Commit

Permalink
Disallow octal format in Ipv4 string
Browse files Browse the repository at this point in the history
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
  • Loading branch information
xu-cheng committed Mar 30, 2021
1 parent 3aedcf0 commit 974192c
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 1 deletion.
2 changes: 2 additions & 0 deletions library/std/src/net/ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion library/std/src/net/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ impl<'a> Parser<'a> {
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)| {
Expand Down Expand Up @@ -132,7 +137,14 @@ impl<'a> Parser<'a> {
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())
Expand Down
8 changes: 8 additions & 0 deletions library/std/src/net/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ const SCOPE_ID: u32 = 1337;
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";

Expand All @@ -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());
Expand All @@ -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());
Expand Down

0 comments on commit 974192c

Please sign in to comment.