src/vrrpv2.rs
changeset 20 fd3474f42783
parent 19 1567e8a5a0cb
child 21 17afb5ba9c2b
--- a/src/vrrpv2.rs	Wed Jan 10 16:29:32 2024 +0530
+++ b/src/vrrpv2.rs	Wed Jan 17 15:23:51 2024 +0530
@@ -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 @@
     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>;
 }
 
-fn parse(input: &[u8]) -> Result<VRRPv2, VRRPv2Error> {
-    let Ok(((input, _), version)) = take_nibble((input, 0)) else {
-        return Err(VRRPv2Error::ParseError);
-    };
-    if version != 2 {
-        return Err(VRRPv2Error::InvalidVersion);
+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))
     }
-    let Ok(((input, _), type_)) = take_nibble((input, 4)) else {
+
+    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(bytes: &[u8]) -> Result<VRRPv2, VRRPv2Error> {
+    let mut rdr = Cursor::new(bytes);
+    let Ok(vertype) = rdr.read_u8() else {
         return Err(VRRPv2Error::ParseError);
     };
-    //Advertisement
-    if type_ != 1 {
+    if (vertype & 0xF) != 1 {
+        return Err(VRRPv2Error::InvalidVersion);
+    }
+    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 @@
         2 => VRRPv2AuthType::VRRPv2AuthReserved2,
         _ => return Err(VRRPv2Error::InvalidAuthType),
     };
-    let Ok((input, advertisement_interval)) = u8::<&[u8], Error<&[u8]>>(input) else {
+    let Ok(advertisement_interval) = rdr.read_u8() else {
         return Err(VRRPv2Error::ParseError);
     };
-    let Ok((input, checksum)) = be_u16::<&[u8], Error<&[u8]>>(input) else {
+    let Ok(checksum) = rdr.read_u16() else {
         return Err(VRRPv2Error::ParseError);
     };
-    let Ok((_, xs)) = count(be_u32::<&[u8], Error<&[u8]>>, usize::from(count_ip_addrs))(input)
-    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 @@
     })
 }
 
-// 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 @@
     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 @@
 #[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 @@
 #[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));