fix(network): validate MAC address length when parsing addresses from network manager
This fixes a bug in the HwAddress struct that allowed invalid MAC addresses to pass validation. --- - [x] I have disclosed use of any AI generated code in my commit messages. - If you are using an LLM, and do not fully understand the changes it is making to the code base, do not create a PR. - In our experience, AI generated code often results in overly complex code that lacks enough context for a proper fix or feature inclusion. This results in considerably longer code reviews. Due to this, AI authored or partially authored PRs may be closed without comment. - [x] I understand these changes in full and will be able to respond to review comments. - [x] My change is accurately described in the commit message. - [x] My contribution is tested and working as described. - [x] I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions.
This commit is contained in:
parent
84729d1dcd
commit
3bef2b08da
1 changed files with 85 additions and 21 deletions
|
|
@ -1,38 +1,102 @@
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug, PartialOrd, Ord)]
|
||||
#[derive(Clone, PartialEq, Eq, Default, Debug, PartialOrd, Ord)]
|
||||
pub struct HwAddress {
|
||||
address: u64,
|
||||
octets: Vec<u8>,
|
||||
}
|
||||
|
||||
impl HwAddress {
|
||||
pub fn from_str(arg: &str) -> Option<Self> {
|
||||
let columnless_vec = arg.split(":").collect::<Vec<&str>>();
|
||||
if columnless_vec.len() * 3 - 1 != arg.len() {
|
||||
let segments: Vec<&str> = arg.split(":").collect();
|
||||
|
||||
// Only accept 6-byte (EUI-48) or 8-byte (EUI-64) addresses
|
||||
if segments.len() != 6 && segments.len() != 8 {
|
||||
return None;
|
||||
}
|
||||
for byte in &columnless_vec {
|
||||
if byte.len() != 2 {
|
||||
|
||||
let mut octets: Vec<u8> = Vec::new();
|
||||
for segment in segments {
|
||||
if segment.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
let byte: u8 = u8::from_str_radix(segment, 16).ok()?;
|
||||
octets.push(byte);
|
||||
}
|
||||
u64::from_str_radix(columnless_vec.join("").as_str(), 16)
|
||||
.ok()
|
||||
.map(|address| HwAddress { address })
|
||||
}
|
||||
pub fn from_string(arg: &str) -> Option<Self> {
|
||||
HwAddress::from_str(arg)
|
||||
|
||||
Some(HwAddress { octets })
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for HwAddress {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let hex = format!("{:#x}", self.address)
|
||||
.trim_start_matches("0x")
|
||||
.chars()
|
||||
.collect::<Vec<_>>()
|
||||
.chunks(2)
|
||||
.map(|chunk| chunk.iter().cloned().collect::<String>())
|
||||
.collect::<Vec<String>>()
|
||||
.join(":");
|
||||
write!(f, "{}", hex)
|
||||
let hex_parts: Vec<String> = self
|
||||
.octets
|
||||
.iter()
|
||||
.map(|byte| format!("{:02x}", byte))
|
||||
.collect();
|
||||
write!(f, "{}", hex_parts.join(":"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_valid_6_byte_mac() {
|
||||
let mac: &str = "00:11:22:33:44:55";
|
||||
let hw_addr: HwAddress = HwAddress::from_str(mac).expect("should parse valid MAC");
|
||||
|
||||
// Access the internal octets field
|
||||
assert_eq!(hw_addr.octets.len(), 6);
|
||||
assert_eq!(hw_addr.octets, vec![0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display_6_byte_mac() {
|
||||
let hw_addr: HwAddress = HwAddress {
|
||||
octets: vec![0x00, 0x11, 0x22, 0x33, 0x44, 0x55],
|
||||
};
|
||||
|
||||
assert_eq!(format!("{}", hw_addr), "00:11:22:33:44:55");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_valid_8_byte_mac() {
|
||||
let mac: &str = "00:11:22:33:44:55:66:77";
|
||||
let hw_addr: HwAddress = HwAddress::from_str(mac).expect("should parse valid EUI-64 MAC");
|
||||
|
||||
assert_eq!(hw_addr.octets.len(), 8);
|
||||
assert_eq!(
|
||||
hw_addr.octets,
|
||||
vec![0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display_8_byte_mac() {
|
||||
let hw_addr: HwAddress = HwAddress {
|
||||
octets: vec![0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77],
|
||||
};
|
||||
|
||||
assert_eq!(format!("{}", hw_addr), "00:11:22:33:44:55:66:77");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reject_invalid_length_macs() {
|
||||
let invalid_macs: Vec<(&str, &str)> = vec![
|
||||
("00", "1-byte MAC"),
|
||||
("00:11:22:33", "4-byte MAC"),
|
||||
("00:11:22:33:44", "5-byte MAC"),
|
||||
("00:11:22:33:44:55:66", "7-byte MAC"),
|
||||
("00:11:22:33:44:55:66:77:88", "9-byte MAC"),
|
||||
("00:11:22:33:44:55:66:77:88:99:aa:bb", "12-byte MAC"),
|
||||
];
|
||||
|
||||
for (mac, description) in invalid_macs {
|
||||
assert!(
|
||||
HwAddress::from_str(mac).is_none(),
|
||||
"should reject {}",
|
||||
description
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue