summaryrefslogtreecommitdiff
path: root/src/vrrpv2.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/vrrpv2.rs')
-rw-r--r--src/vrrpv2.rs111
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));