From 6516224e327fc7cb62aa6782dccabb40d1325660 Mon Sep 17 00:00:00 2001 From: Xnoe Date: Tue, 25 Oct 2022 23:15:46 +0100 Subject: [PATCH] Added support for Classless Static Routes --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/dhcp.rs | 43 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8148521..9356200 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ [[package]] name = "dhcprs" -version = "0.1.2" +version = "0.1.3" dependencies = [ "eui48", ] diff --git a/Cargo.toml b/Cargo.toml index e44d551..4907ecf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dhcprs" -version = "0.1.2" +version = "0.1.3" edition = "2021" description = "A library for encoding and decoding DHCP/BOOTP packets" license-file = "LICENSE" diff --git a/src/dhcp.rs b/src/dhcp.rs index 87fdc61..9b8f7cf 100644 --- a/src/dhcp.rs +++ b/src/dhcp.rs @@ -166,10 +166,10 @@ pub enum DHCPOption { /*// RFC4833 TimezonePOSIX(String), // 100 N IEEE 1003.1 String - TimezoneDB(String), // 101 N Reference to TZ Database + TimezoneDB(String), // 101 N Reference to TZ Database*/ // RFC3442 - ClasslessStaticRoute(Vec<(Ipv4Addr, u32, Ipv4Addr)>), // 121 n d1 ... dN r1 r2 r3 r4 d1 ... dN r1 r2 r3 r4*/ + ClasslessStaticRoute(Vec<(Ipv4Addr, u8, Ipv4Addr)>), // 121 n d1 ... dN r1 r2 r3 r4 d1 ... dN r1 r2 r3 r4 // Catchall Option(u8, Vec), @@ -184,6 +184,12 @@ macro_rules! break_unwrap { }; } +macro_rules! div_ceil { + ($lhs:expr, $rhs:expr) => { + $lhs / $rhs + if $lhs % $rhs != 0 { 1 } else { 0 } + } +} + impl DHCPOption { pub fn from_bytes(bytes: &[u8]) -> Vec { let mut options: Vec = Vec::new(); @@ -1230,6 +1236,28 @@ impl DHCPOption { options.push(DHCPOption::STDAServer(addresses)); } + 121 => { + let mut length = break_unwrap!(iterator.next()); + let mut routes: Vec<(Ipv4Addr, u8, Ipv4Addr)> = Vec::new(); + + while length > 0 { + let prefix_length = break_unwrap!(iterator.next()); + let descriptor_length = div_ceil!(prefix_length, 8); + + let mut prefix_octets: [u8; 4] = [0;4]; + for count in 0..descriptor_length { + prefix_octets[count as usize] = break_unwrap!(iterator.next()); + } + + let router = Ipv4Addr::new(break_unwrap!(iterator.next()),break_unwrap!(iterator.next()),break_unwrap!(iterator.next()),break_unwrap!(iterator.next())); + + routes.push((Ipv4Addr::from(prefix_octets), prefix_length, router)); + length -= 1 + descriptor_length + 4; + } + + options.push(DHCPOption::ClasslessStaticRoute(routes)); + } + // Catchall for if we cannot decode the option to a specific enum variant. n => { let count = break_unwrap!(iterator.next()); @@ -1801,6 +1829,17 @@ impl DHCPOption { bytes.push(b.len() as u8); bytes.extend_from_slice(&b); } + + DHCPOption::ClasslessStaticRoute(routes) => { + bytes.push(121); + bytes.push(routes.iter().fold(0, |acc, (_, prefix_length, _)| acc + 1 + div_ceil!(prefix_length, 8) + 4)); + for (prefix, prefix_length, router) in routes { + let descriptor_length = div_ceil!(prefix_length, 8); + bytes.push(prefix_length); + bytes.extend_from_slice(&prefix.octets()[..descriptor_length as usize]); + bytes.extend_from_slice(&router.octets()); + } + } } }