diff --git a/holo-vrrp/src/packet.rs b/holo-vrrp/src/packet.rs index 4168cbf5..33a93893 100644 --- a/holo-vrrp/src/packet.rs +++ b/holo-vrrp/src/packet.rs @@ -9,9 +9,6 @@ use std::net::{IpAddr, Ipv4Addr}; //use bitflags::bitflags; use bytes::{Buf, BufMut, Bytes, BytesMut}; use holo_utils::bytes::{BytesExt, BytesMutExt}; -//use holo_utils::bytes::TLS_BUF; -//use num_derive::FromPrimitive; -//use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; // Type aliases. @@ -73,18 +70,21 @@ pub enum DecodeError { pub enum PacketLengthError { // A maximum number of 16 IP addresses are allowed for - // VRRP. - AddressCount(u8), + // VRRP. Referenced from count_ip field + AddressCount(usize), // specified on the vrrp-ietf. when length of the // vrrp packet is less than 16 bytes. - TooLow(u8), + TooShort(usize), + + // total + TooLong(usize), + + // when the number of ips specified under count_ip + // does not correspond to the actual length of the packet + // (total_length = 16 + (4 * no of ips)) + CorruptedLength - // customized. while for addresscount we look for the count_ip - // field in the header, in case the total length of the IP address - // is not specified correctly there, we will also manually look - // if there are too many bytes in the whole packet. - TooHigh(u8), } // ===== impl Packet ===== @@ -109,12 +109,41 @@ impl VRRPPacket { } // Decodes VRRP packet from a bytes buffer. - pub fn decode(data: &[u8]) -> Result { + pub fn decode(data: &[u8]) -> Result { + + // 1. pkt length verification + let pkt_size = data.len(); + let count_ip = data[3]; + + if pkt_size < 16 { + return Err(DecodeError::PacketLengthError(PacketLengthError::TooShort(pkt_size))) + } + + if pkt_size > 80 { + return Err(DecodeError::PacketLengthError(PacketLengthError::TooLong(pkt_size))) + } + + if count_ip > 16 { + return Err( + DecodeError::PacketLengthError(PacketLengthError::AddressCount(count_ip as usize)) + ) + } + + // check if the ip_count has been verified with the actual length + // A Mallory may have tried carrying out something naughty + if (count_ip * 4) + 16 != pkt_size as u8 { + return Err( + DecodeError::PacketLengthError(PacketLengthError::CorruptedLength) + ) + } + + + let mut buf: Bytes = Bytes::copy_from_slice(data); let ver_type = buf.get_u8(); let vrid = buf.get_u8(); let priority = buf.get_u8(); - let count_ip = buf.get_u8(); + let count_ip = buf.get_u8(); let auth_type = buf.get_u8(); let adver_int = buf.get_u8(); let checksum = buf.get_u16(); @@ -126,6 +155,7 @@ impl VRRPPacket { let auth_data = buf.get_u32(); let auth_data2 = buf.get_u32(); + Ok(Self { ver_type, vrid, @@ -167,15 +197,18 @@ impl std::fmt::Display for DecodeError { impl std::fmt::Display for PacketLengthError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - PacketLengthError::TooHigh(rx_len) => { + PacketLengthError::TooLong(rx_len) => { write!(f, "Too many bytes for VRRP packet: {rx_len}") }, - PacketLengthError::TooLow(rx_len) => { + PacketLengthError::TooShort(rx_len) => { write!(f, "Not enough bytes for VRRP packets: {rx_len}") }, PacketLengthError::AddressCount(rx_count) => { write!(f, "Too many IP addresses {rx_count}") }, + PacketLengthError::CorruptedLength => { + write!(f, "Count_ip not corresponding with no of bytes in packet") + }, } } } diff --git a/holo-vrrp/tests/packet/mod.rs b/holo-vrrp/tests/packet/mod.rs index 8151c7f1..d7acfbfb 100644 --- a/holo-vrrp/tests/packet/mod.rs +++ b/holo-vrrp/tests/packet/mod.rs @@ -4,4 +4,91 @@ // SPDX-License-Identifier: MIT // + +use bytes::Buf; // TODO +use holo_vrrp::packet::{VRRPPacket, DecodeError, PacketLengthError}; + +/* +generally in the packet tests we will use the following packet structure +with slight modifications to be done on a per test basis(the changes will +be specified) + +Valid VRRP packet with the following params: + - ver_type: 21 [version: 2, header_type: 1] + - vrid: 51 + - priority: 101 + - count_ip: 1 + - auth_type: 0 + - adver_int: 1 + - checksum: 0x54db + - ip_addresses: [192.168.100.100] + - auth_data: 0 + - auth_data2: 0 + */ +fn valid_pkt_data() -> [u8; 20] { + [ + 0x21, 0x33, 0x65, 0x01, + 0x00, 0x01, 0x54, 0xbd, + 0xc0, 0xa8, 0x64, 0x64, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + ] +} + +// test the valid packet being decoded +#[test] +fn test_valid_decoding(){ + let vrrp_pkt = VRRPPacket::decode(&valid_pkt_data()); + assert!(vrrp_pkt.is_ok()); +} + + +// make the VRRP packet too short. We will use 10 bytes. +#[test] +fn test_pkt_too_short() { + let vrrp_pkt = VRRPPacket::decode(&[0x00; 10]); + assert_eq!( + vrrp_pkt, + Err(DecodeError::PacketLengthError(PacketLengthError::TooShort(10))) + ); +} + +// the length of the entire packet is too long +#[test] +fn test_pkt_too_long() { + let vrrp_pkt = VRRPPacket::decode(&[0x00; 100]); + assert_eq!( + vrrp_pkt, + Err(DecodeError::PacketLengthError(PacketLengthError::TooLong(100))) + ); +} + +// test when the packet is too long in length +// we set count_ip as 17 +#[test] +fn test_count_ip_too_high() { + let data: &mut [u8] = &mut valid_pkt_data(); + data[3] = 17; + let vrrp_pkt = VRRPPacket::decode(data); + assert_eq!( + vrrp_pkt, + Err(DecodeError::PacketLengthError(PacketLengthError::AddressCount(17))) + ); +} + + + +// let us claim we have 3 ip addresses yet we have only one +// we set count_ip as 17 +#[test] +fn test_count_ip_corrupted() { + let data: &mut [u8] = &mut valid_pkt_data(); + data[3] = 3; + let vrrp_pkt = VRRPPacket::decode(data); + assert_eq!( + vrrp_pkt, + Err(DecodeError::PacketLengthError(PacketLengthError::CorruptedLength)) + ); +} +