wgctrl-sys: correct InterfaceName parsing and simplify a bit
It was dropping the last character in the name, and I modified it to instead just error on any &str that has a '\0' in it. The strictness feels acceptable and simplifies the code a bit.pull/37/head
parent
b1e1ff8f4f
commit
bcd68df772
|
@ -123,23 +123,19 @@ impl FromStr for InterfaceName {
|
||||||
/// Extra validation logic ported from [iproute2](https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/lib/utils.c#n827)
|
/// Extra validation logic ported from [iproute2](https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/lib/utils.c#n827)
|
||||||
fn from_str(name: &str) -> Result<Self, InvalidInterfaceName> {
|
fn from_str(name: &str) -> Result<Self, InvalidInterfaceName> {
|
||||||
let len = name.len();
|
let len = name.len();
|
||||||
// Ensure its short enough to include a trailing NUL
|
if len == 0 {
|
||||||
if len > (libc::IFNAMSIZ - 1) {
|
return Err(InvalidInterfaceName::Empty);
|
||||||
return Err(InvalidInterfaceName::TooLong(len));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len == 0 || name.trim_start_matches('\0').is_empty() {
|
// Ensure its short enough to include a trailing NUL
|
||||||
return Err(InvalidInterfaceName::Empty);
|
if len > (libc::IFNAMSIZ - 1) {
|
||||||
|
return Err(InvalidInterfaceName::TooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = [c_char::default(); libc::IFNAMSIZ];
|
let mut buf = [c_char::default(); libc::IFNAMSIZ];
|
||||||
// Check for interior NULs and other invalid characters.
|
// Check for interior NULs and other invalid characters.
|
||||||
for (out, b) in buf.iter_mut().zip(name.as_bytes()[..(len - 1)].iter()) {
|
for (out, b) in buf.iter_mut().zip(name.as_bytes().iter()) {
|
||||||
if *b == 0 {
|
if *b == 0 || *b == b'/' || b.is_ascii_whitespace() {
|
||||||
return Err(InvalidInterfaceName::InteriorNul);
|
|
||||||
}
|
|
||||||
|
|
||||||
if *b == b'/' || b.is_ascii_whitespace() {
|
|
||||||
return Err(InvalidInterfaceName::InvalidChars);
|
return Err(InvalidInterfaceName::InvalidChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,28 +193,24 @@ impl fmt::Display for InterfaceName {
|
||||||
/// An interface name was bad.
|
/// An interface name was bad.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum InvalidInterfaceName {
|
pub enum InvalidInterfaceName {
|
||||||
/// Provided name had an interior NUL byte.
|
|
||||||
InteriorNul,
|
|
||||||
/// Provided name was longer then the interface name length limit
|
/// Provided name was longer then the interface name length limit
|
||||||
/// of the system.
|
/// of the system.
|
||||||
TooLong(usize),
|
TooLong,
|
||||||
|
|
||||||
// These checks are done in the kernel as well, but no reason to let bad names
|
// These checks are done in the kernel as well, but no reason to let bad names
|
||||||
// get that far: https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/lib/utils.c?id=1f420318bda3cc62156e89e1b56d60cc744b48ad#n827.
|
// get that far: https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/lib/utils.c?id=1f420318bda3cc62156e89e1b56d60cc744b48ad#n827.
|
||||||
/// Interface name was an empty string.
|
/// Interface name was an empty string.
|
||||||
Empty,
|
Empty,
|
||||||
/// Interface name contained a `/` or space character.
|
/// Interface name contained a nul, `/` or whitespace character.
|
||||||
InvalidChars,
|
InvalidChars,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InvalidInterfaceName {
|
impl fmt::Display for InvalidInterfaceName {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::InteriorNul => f.write_str("interface name contained an interior NUL byte"),
|
Self::TooLong => write!(
|
||||||
Self::TooLong(size) => write!(
|
|
||||||
f,
|
f,
|
||||||
"interface name was {} bytes long but the system's max is {}",
|
"interface name longer than system max of {} chars",
|
||||||
size,
|
|
||||||
libc::IFNAMSIZ
|
libc::IFNAMSIZ
|
||||||
),
|
),
|
||||||
Self::Empty => f.write_str("an empty interface name was provided"),
|
Self::Empty => f.write_str("an empty interface name was provided"),
|
||||||
|
@ -317,17 +309,17 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_interface_names() {
|
fn test_interface_names() {
|
||||||
assert!("wg-01".parse::<InterfaceName>().is_ok());
|
assert_eq!("wg-01".parse::<InterfaceName>().unwrap().as_str_lossy(), "wg-01");
|
||||||
assert!("longer-nul\0".parse::<InterfaceName>().is_ok());
|
assert!("longer-nul\0".parse::<InterfaceName>().is_err());
|
||||||
|
|
||||||
let invalid_names = &[
|
let invalid_names = &[
|
||||||
("", InvalidInterfaceName::Empty), // Empty Rust string
|
("", InvalidInterfaceName::Empty), // Empty Rust string
|
||||||
("\0", InvalidInterfaceName::Empty), // Empty C string
|
("\0", InvalidInterfaceName::InvalidChars), // Empty C string
|
||||||
("ifname\0nul", InvalidInterfaceName::InteriorNul), // Contains interior NUL
|
("ifname\0nul", InvalidInterfaceName::InvalidChars), // Contains interior NUL
|
||||||
("if name", InvalidInterfaceName::InvalidChars), // Contains a space
|
("if name", InvalidInterfaceName::InvalidChars), // Contains a space
|
||||||
("ifna/me", InvalidInterfaceName::InvalidChars), // Contains a slash
|
("ifna/me", InvalidInterfaceName::InvalidChars), // Contains a slash
|
||||||
("if na/me", InvalidInterfaceName::InvalidChars), // Contains a space and slash
|
("if na/me", InvalidInterfaceName::InvalidChars), // Contains a space and slash
|
||||||
("interfacelongname", InvalidInterfaceName::TooLong(17)), // Too long
|
("interfacelongname", InvalidInterfaceName::TooLong), // Too long
|
||||||
];
|
];
|
||||||
|
|
||||||
for (name, expected) in invalid_names {
|
for (name, expected) in invalid_names {
|
||||||
|
|
Loading…
Reference in New Issue