Replace nom with std::io::Cursor
authorSunil Nimmagadda <sunil@nimmagadda.net>
Wed, 17 Jan 2024 15:23:51 +0530
changeset 20 fd3474f42783
parent 19 1567e8a5a0cb
child 21 17afb5ba9c2b
Replace nom with std::io::Cursor std::io::Cursor suffices to parse the packet.
Cargo.lock
Cargo.toml
src/vrrpv2.rs
--- a/Cargo.lock	Wed Jan 10 16:29:32 2024 +0530
+++ b/Cargo.lock	Wed Jan 17 15:23:51 2024 +0530
@@ -3,283 +3,42 @@
 version = 3
 
 [[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bytes"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
-[[package]]
 name = "libc"
-version = "0.2.137"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
-
-[[package]]
-name = "lock_api"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
-dependencies = [
- "autocfg",
- "scopeguard",
-]
-
-[[package]]
-name = "log"
-version = "0.4.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "memchr"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
-
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
-name = "mio"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
-dependencies = [
- "libc",
- "log",
- "wasi",
- "windows-sys",
-]
-
-[[package]]
-name = "nom"
-version = "7.1.1"
+version = "0.2.151"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
-name = "num_cpus"
-version = "1.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
-name = "parking_lot"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
-dependencies = [
- "lock_api",
- "parking_lot_core",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall",
- "smallvec",
- "windows-sys",
-]
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.47"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "scopeguard"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-
-[[package]]
-name = "signal-hook-registry"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
 
 [[package]]
 name = "socket2"
-version = "0.4.7"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
 dependencies = [
  "libc",
- "winapi",
-]
-
-[[package]]
-name = "syn"
-version = "1.0.104"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
+ "windows-sys",
 ]
 
 [[package]]
-name = "tokio"
-version = "1.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
-dependencies = [
- "autocfg",
- "bytes",
- "libc",
- "memchr",
- "mio",
- "num_cpus",
- "parking_lot",
- "pin-project-lite",
- "signal-hook-registry",
- "socket2",
- "tokio-macros",
- "winapi",
-]
-
-[[package]]
-name = "tokio-macros"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
-
-[[package]]
 name = "vrrpd"
 version = "0.1.0"
 dependencies = [
- "nom",
- "tokio",
+ "socket2",
 ]
 
 [[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+name = "windows-sys"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
+ "windows-targets",
 ]
 
 [[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
+name = "windows-targets"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows-sys"
-version = "0.42.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
@@ -292,42 +51,42 @@
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
--- a/Cargo.toml	Wed Jan 10 16:29:32 2024 +0530
+++ b/Cargo.toml	Wed Jan 17 15:23:51 2024 +0530
@@ -4,5 +4,4 @@
 edition = "2021"
 
 [dependencies]
-tokio = { version = "1.22.0", features = ["full"] }
-nom = "7"
+socket2 = { version = "0.5.5", features = ["all"] }
--- 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));