From b8a95026eeabc5acd767dc9940a9cf5aecdeefbe Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Wed, 17 Jan 2024 15:23:51 +0530 Subject: Replace nom with std::io::Cursor std::io::Cursor suffices to parse the packet. --- src/vrrpv2.rs | 111 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/vrrpv2.rs b/src/vrrpv2.rs index 989a36b..228c19c 100644 --- a/src/vrrpv2.rs +++ b/src/vrrpv2.rs @@ -1,12 +1,7 @@ -//! Parser recognising a VRRP v2 packet. -use nom::error::Error; -use nom::multi::count; -use nom::number::complete::{be_u16, be_u32, u8}; -use nom::{bits::complete::take, IResult}; +use std::io::Read; +use std::io::{self, Cursor}; use std::net::Ipv4Addr; -type BitInput<'a> = (&'a [u8], usize); - /// A VRRP version 2 packet. /// /// Packet format @@ -56,35 +51,53 @@ pub enum VRRPv2AuthType { VRRPv2AuthReserved2 = 0x02, } -/// Helper function to let compiler infer generic parameters. -fn take_nibble(input: BitInput) -> IResult { - take(4usize)(input) +trait ByteReader { + fn read_u8(&mut self) -> io::Result; + fn read_u16(&mut self) -> io::Result; + fn read_u32(&mut self) -> io::Result; +} + +impl> ByteReader for Cursor { + fn read_u8(&mut self) -> io::Result { + let mut buffer = [0; 1]; + self.read_exact(&mut buffer)?; + Ok(u8::from_be_bytes(buffer)) + } + + fn read_u16(&mut self) -> io::Result { + let mut buffer = [0; 2]; + self.read_exact(&mut buffer)?; + Ok(u16::from_be_bytes(buffer)) + } + + fn read_u32(&mut self) -> io::Result { + let mut buffer = [0; 4]; + self.read_exact(&mut buffer)?; + Ok(u32::from_be_bytes(buffer)) + } } -fn parse(input: &[u8]) -> Result { - let Ok(((input, _), version)) = take_nibble((input, 0)) else { +fn parse(bytes: &[u8]) -> Result { + let mut rdr = Cursor::new(bytes); + let Ok(vertype) = rdr.read_u8() else { return Err(VRRPv2Error::ParseError); }; - if version != 2 { + if (vertype & 0xF) != 1 { return Err(VRRPv2Error::InvalidVersion); } - let Ok(((input, _), type_)) = take_nibble((input, 4)) else { - return Err(VRRPv2Error::ParseError); - }; - //Advertisement - if type_ != 1 { + if (vertype >> 4) != 2 { return Err(VRRPv2Error::InvalidType); } - let Ok((input, virtual_router_id)) = u8::<&[u8], Error<&[u8]>>(input) else { + let Ok(virtual_router_id) = rdr.read_u8() else { return Err(VRRPv2Error::ParseError); }; - let Ok((input, priority)) = u8::<&[u8], Error<&[u8]>>(input) else { + let Ok(priority) = rdr.read_u8() else { return Err(VRRPv2Error::ParseError); }; - let Ok((input, count_ip_addrs)) = u8::<&[u8], Error<&[u8]>>(input) else { + let Ok(count_ip_addrs) = rdr.read_u8() else { return Err(VRRPv2Error::ParseError); }; - let Ok((input, auth_type)) = u8::<&[u8], Error<&[u8]>>(input) else { + let Ok(auth_type) = rdr.read_u8() else { return Err(VRRPv2Error::ParseError); }; let auth_type = match auth_type { @@ -93,17 +106,19 @@ fn parse(input: &[u8]) -> Result { 2 => VRRPv2AuthType::VRRPv2AuthReserved2, _ => return Err(VRRPv2Error::InvalidAuthType), }; - let Ok((input, advertisement_interval)) = u8::<&[u8], Error<&[u8]>>(input) else { - return Err(VRRPv2Error::ParseError); - }; - let Ok((input, checksum)) = be_u16::<&[u8], Error<&[u8]>>(input) else { + let Ok(advertisement_interval) = rdr.read_u8() else { return Err(VRRPv2Error::ParseError); }; - let Ok((_, xs)) = count(be_u32::<&[u8], Error<&[u8]>>, usize::from(count_ip_addrs))(input) - else { + let Ok(checksum) = rdr.read_u16() else { return Err(VRRPv2Error::ParseError); }; - let ip_addrs: Vec = xs.into_iter().map(Ipv4Addr::from).collect(); + let mut ip_addrs = Vec::new(); + for _i in 0..count_ip_addrs { + let Ok(b) = rdr.read_u32() else { + return Err(VRRPv2Error::ParseError); + }; + ip_addrs.push(Ipv4Addr::from(b)); + } Ok(VRRPv2 { virtual_router_id, priority, @@ -115,24 +130,6 @@ fn parse(input: &[u8]) -> Result { }) } -// nightly has as_chunks that allows for a nicer code... -// let (chunks, remainder) = bytes.as_chunks(2); -// fold chunks and remainder without an if. -fn checksum(bytes: &[u8]) -> u16 { - let mut sum: u32 = 0; - for chunk in bytes.chunks(2) { - // Left over byte if any - if chunk.len() == 1 { - sum += u32::from(chunk[0]); - } else { - sum += u32::from(u16::from_be_bytes(chunk.try_into().unwrap())); - } - } - while (sum >> 16) > 0 { - sum = (sum & 0xffff) + (sum >> 16); - } - !(sum as u16) -} /// Parse and validate a byte array to construct a VRRPv2 struct. /// /// # Examples @@ -166,6 +163,22 @@ pub fn from_bytes(bytes: &[u8]) -> Result { Ok(vrrpv2) } +fn checksum(bytes: &[u8]) -> u16 { + let mut sum: u32 = 0; + for chunk in bytes.chunks(2) { + // Left over byte if any + if chunk.len() == 1 { + sum += u32::from(chunk[0]); + } else { + sum += u32::from(u16::from_be_bytes(chunk.try_into().unwrap())); + } + } + while (sum >> 16) > 0 { + sum = (sum & 0xffff) + (sum >> 16); + } + !(sum as u16) +} + #[test] fn test_incomplete_bytes() { let bytes = [0x21, 0x01]; @@ -175,7 +188,7 @@ fn test_incomplete_bytes() { #[test] fn test_invalid_version() { let bytes = [ - 0x31, 0x2a, 0x64, 0x1, 0x0, 0x1, 0xaa, 0x29, 0xc0, 0xa8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x20, 0x1, 0x2a, 0x0, 0x0, 0x1, 0xb5, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]; assert_eq!(from_bytes(&bytes), Err(VRRPv2Error::InvalidVersion)); @@ -184,7 +197,7 @@ fn test_invalid_version() { #[test] fn test_invalid_type() { let bytes = [ - 0x20, 0x1, 0x2a, 0x0, 0x0, 0x1, 0xb5, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x31, 0x2a, 0x64, 0x1, 0x0, 0x1, 0xaa, 0x29, 0xc0, 0xa8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]; assert_eq!(from_bytes(&bytes), Err(VRRPv2Error::InvalidType)); -- cgit v1.2.3