Skip to content

Commit 734bfde

Browse files
committed
Disallow octal zeros in IPv4 addresses
1 parent 969a6c2 commit 734bfde

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ fn test_from_str_ipv4() {
2020
// no number between dots
2121
let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
2222
assert_eq!(None, none);
23+
// octal
24+
let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
25+
assert_eq!(None, none);
26+
// octal zero
27+
let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
28+
assert_eq!(None, none);
29+
let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
30+
assert_eq!(None, none);
2331
}
2432

2533
#[test]

library/std/src/net/parser.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::fmt;
1212
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
1313
use crate::str::FromStr;
1414

15-
trait ReadNumberHelper: crate::marker::Sized {
15+
trait ReadNumberHelper: crate::marker::Sized + crate::cmp::PartialEq {
1616
const ZERO: Self;
1717
fn checked_mul(&self, other: u32) -> Option<Self>;
1818
fn checked_add(&self, other: u32) -> Option<Self>;
@@ -111,10 +111,12 @@ impl<'a> Parser<'a> {
111111
&mut self,
112112
radix: u32,
113113
max_digits: Option<usize>,
114+
allow_zero_prefix: bool,
114115
) -> Option<T> {
115116
self.read_atomically(move |p| {
116117
let mut result = T::ZERO;
117118
let mut digit_count = 0;
119+
let has_leading_zero = p.peek_char() == Some('0');
118120

119121
while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
120122
result = result.checked_mul(radix)?;
@@ -127,7 +129,16 @@ impl<'a> Parser<'a> {
127129
}
128130
}
129131

130-
if digit_count == 0 { None } else { Some(result) }
132+
if digit_count == 0 {
133+
None
134+
} else if !allow_zero_prefix
135+
&& has_leading_zero
136+
&& (result != T::ZERO || result == T::ZERO && digit_count > 1)
137+
{
138+
None
139+
} else {
140+
Some(result)
141+
}
131142
})
132143
}
133144

@@ -140,10 +151,7 @@ impl<'a> Parser<'a> {
140151
*slot = p.read_separator('.', i, |p| {
141152
// Disallow octal number in IP string.
142153
// https://tools.ietf.org/html/rfc6943#section-3.1.1
143-
match (p.peek_char(), p.read_number(10, None)) {
144-
(Some('0'), Some(number)) if number != 0 => None,
145-
(_, number) => number,
146-
}
154+
p.read_number(10, None, false)
147155
})?;
148156
}
149157

@@ -175,7 +183,7 @@ impl<'a> Parser<'a> {
175183
}
176184
}
177185

178-
let group = p.read_separator(':', i, |p| p.read_number(16, Some(4)));
186+
let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true));
179187

180188
match group {
181189
Some(g) => *slot = g,
@@ -227,15 +235,15 @@ impl<'a> Parser<'a> {
227235
fn read_port(&mut self) -> Option<u16> {
228236
self.read_atomically(|p| {
229237
p.read_given_char(':')?;
230-
p.read_number(10, None)
238+
p.read_number(10, None, true)
231239
})
232240
}
233241

234242
/// Read a `%` followed by a scope ID in base 10.
235243
fn read_scope_id(&mut self) -> Option<u32> {
236244
self.read_atomically(|p| {
237245
p.read_given_char('%')?;
238-
p.read_number(10, None)
246+
p.read_number(10, None, true)
239247
})
240248
}
241249

0 commit comments

Comments
 (0)