use crate::errors::application::dhcpv6::Dhcpv6PacketParseError;
use std::fmt;
#[derive(Debug, PartialEq)]
pub struct Dhcpv6Packet<'a> {
pub message_type: u8,
pub transaction_id: u32,
pub options: &'a [u8],
}
impl<'a> fmt::Display for Dhcpv6Packet<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"DHCPv6 Packet: message_type={}, transaction_id={:06X}, options={:02X?}",
self.message_type, self.transaction_id, self.options
)
}
}
impl<'a> TryFrom<&'a [u8]> for Dhcpv6Packet<'a> {
type Error = Dhcpv6PacketParseError;
fn try_from(payload: &'a [u8]) -> Result<Self, Self::Error> {
if payload.len() < 4 {
return Err(Dhcpv6PacketParseError::PacketLength);
}
let message_type = payload[0];
if !(1..=13).contains(&message_type) {
return Err(Dhcpv6PacketParseError::MessageType { message_type });
}
let transaction_id = u32::from_be_bytes([0, payload[1], payload[2], payload[3]]);
let options = &payload[4..];
Ok(Dhcpv6Packet {
message_type,
transaction_id,
options,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_dhcpv6_packet() {
let payload = vec![
0x01, 0x12, 0x34, 0x56, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x03, 0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
];
match Dhcpv6Packet::try_from(payload.as_slice()) {
Ok(packet) => {
assert_eq!(packet.message_type, 1);
assert_eq!(packet.transaction_id, 0x123456);
assert_eq!(
packet.options,
&[
0x00, 0x01, 0x00, 0x0A, 0x00, 0x03, 0x00, 0x01, 0x00, 0x11, 0x22, 0x33,
0x44, 0x55
]
);
}
Err(_) => panic!("Expected valid DHCPv6 packet"),
}
}
#[test]
fn test_parse_dhcpv6_packet_short_payload() {
let short_payload = vec![0x01, 0x12, 0x34]; match Dhcpv6Packet::try_from(short_payload.as_slice()) {
Ok(_) => panic!("Expected invalid DHCPv6 packet due to short payload"),
Err(e) => assert_eq!(e, Dhcpv6PacketParseError::PacketLength),
}
}
#[test]
fn test_parse_dhcpv6_packet_invalid_type() {
let invalid_payload = vec![
0x0E, 0x12, 0x34, 0x56, 0x00, 0x00, 0x00, 0x00, ];
match Dhcpv6Packet::try_from(invalid_payload.as_slice()) {
Ok(_) => panic!("Expected invalid DHCPv6 packet due to invalid message type"),
Err(e) => assert_eq!(e, Dhcpv6PacketParseError::MessageType { message_type: 14 }),
}
}
#[test]
fn test_parse_dhcpv6_relay_agent() {
let relay_payload = vec![
0x0C, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, ];
match Dhcpv6Packet::try_from(relay_payload.as_slice()) {
Ok(packet) => {
assert_eq!(packet.message_type, 12);
}
Err(e) => panic!("Expected valid DHCPv6 Relay packet, got {:?}", e),
}
}
}