Skip to content

Commit

Permalink
Auto merge of rust-lang#83652 - xu-cheng:ipv4-octal, r=sfackler
Browse files Browse the repository at this point in the history
Disallow octal format in Ipv4 string

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 rust-lang#83648.

[IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
  • Loading branch information
bors committed Mar 30, 2021
2 parents 926ec1c + 974192c commit 74874a6
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 74874a6

Please sign in to comment.