Skip to content

Commit

Permalink
Initial packet validations and tests
Browse files Browse the repository at this point in the history
on decode being done.

Currently only length validations.

tocome: other validations e.g checksum
  • Loading branch information
Paul-weqe committed Jun 19, 2024
1 parent c701030 commit 9a4e77e
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 15 deletions.
63 changes: 48 additions & 15 deletions holo-vrrp/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 =====
Expand All @@ -109,12 +109,41 @@ impl VRRPPacket {
}

// Decodes VRRP packet from a bytes buffer.
pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {

// 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();
Expand All @@ -126,6 +155,7 @@ impl VRRPPacket {
let auth_data = buf.get_u32();
let auth_data2 = buf.get_u32();


Ok(Self {
ver_type,
vrid,
Expand Down Expand Up @@ -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")
},
}
}
}
Expand Down
87 changes: 87 additions & 0 deletions holo-vrrp/tests/packet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
);
}

0 comments on commit 9a4e77e

Please sign in to comment.