diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/vrrpv2.rs | 111 | 
1 files changed, 62 insertions, 49 deletions
| 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<BitInput, u8> { -    take(4usize)(input) +trait ByteReader { +    fn read_u8(&mut self) -> io::Result<u8>; +    fn read_u16(&mut self) -> io::Result<u16>; +    fn read_u32(&mut self) -> io::Result<u32>; +} + +impl<T: AsRef<[u8]>> ByteReader for Cursor<T> { +    fn read_u8(&mut self) -> io::Result<u8> { +        let mut buffer = [0; 1]; +        self.read_exact(&mut buffer)?; +        Ok(u8::from_be_bytes(buffer)) +    } + +    fn read_u16(&mut self) -> io::Result<u16> { +        let mut buffer = [0; 2]; +        self.read_exact(&mut buffer)?; +        Ok(u16::from_be_bytes(buffer)) +    } + +    fn read_u32(&mut self) -> io::Result<u32> { +        let mut buffer = [0; 4]; +        self.read_exact(&mut buffer)?; +        Ok(u32::from_be_bytes(buffer)) +    }  } -fn parse(input: &[u8]) -> Result<VRRPv2, VRRPv2Error> { -    let Ok(((input, _), version)) = take_nibble((input, 0)) else { +fn parse(bytes: &[u8]) -> Result<VRRPv2, VRRPv2Error> { +    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<VRRPv2, VRRPv2Error> {          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<Ipv4Addr> = 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<VRRPv2, VRRPv2Error> {      })  } -// 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<VRRPv2, VRRPv2Error> {      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)); | 
