diff --git a/src/lib.rs b/src/lib.rs index 4715ae2..abbd320 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![allow(unused)] #![feature(ip_in_core)] #![feature(error_in_core)] -mod options; +pub mod options; extern crate alloc; //#![no_std] @@ -17,7 +17,7 @@ use nom::{ }; #[derive(Debug)] -struct Dhcpv4Message<'a> { +pub struct Dhcpv4Message<'a> { operation: Operation, hardware_type: HardwareType, hardware_address_length: u8, @@ -26,6 +26,7 @@ struct Dhcpv4Message<'a> { seconds: u16, flags: Flags, client_address: Ipv4Addr, + your_address: Ipv4Addr, server_address: Ipv4Addr, gateway_address: Ipv4Addr, client_hardware_address: &'a [u8], @@ -35,7 +36,7 @@ struct Dhcpv4Message<'a> { } impl<'a> Dhcpv4Message<'_> { - fn get_option(&self) -> Option> + pub fn get_option(&self) -> Option> where T: DhcpOption, { @@ -129,7 +130,7 @@ fn parse_file(i: &[u8]) -> IResult<&[u8], &str> { Ok((i, val)) } -fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], Dhcpv4Message> { +pub fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], Dhcpv4Message> { let (packet, operation) = parse_operation(packet)?; let (packet, hardware_type) = parse_dhcp_hardware_type(packet)?; let (packet, hardware_address_length) = be_u8(packet)?; @@ -138,6 +139,7 @@ fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], Dhcpv4Message> { let (packet, seconds) = be_u16(packet)?; let (packet, flags) = parse_flags(packet)?; let (packet, client_address) = parse_ipv4_address(packet)?; + let (packet, your_address) = parse_ipv4_address(packet)?; let (packet, server_address) = parse_ipv4_address(packet)?; let (packet, gateway_address) = parse_ipv4_address(packet)?; let (packet, client_hardware_address) = @@ -148,7 +150,9 @@ fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], Dhcpv4Message> { let mut options = Vec::new(); let mut server_name = None; let mut file_name = None; - if let Ok((mut packet, magic)) = take::<_, _, ()>(4usize)(packet) { + let mut packet = packet; + if let Ok((packet2, magic)) = take::<_, _, ()>(4usize)(packet) { + while !packet.is_empty() && packet[0] != 0xff { let (remaining, option) = parse_option(packet)?; options.push(option); @@ -171,6 +175,7 @@ fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], Dhcpv4Message> { seconds, flags, client_address, + your_address, server_address, gateway_address, client_hardware_address, @@ -193,6 +198,7 @@ mod tests { 0x00, 0x02, // secs 0x00, 0x01, // flags 0x7f, 0x00, 0x00, 0x01, // ciaddr + 0x7f, 0x00, 0x00, 0x01, // yiaddr 0x7f, 0x00, 0x00, 0x01, // siaddr 0x7f, 0x00, 0x00, 0x01, // giaddr // chaddr @@ -216,6 +222,20 @@ mod tests { 0x00, 0x00, 0x00, // Paddings 0x03, 0x08, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x02// Router Option ]; + + static PACKET: &'static [u8] = &[ + 1, // op + 1, // htype + 6, // htype len + 0, // hops + 218, 125, 111, 190, // xid + 0, 0, //seconds + 0, 0, //flags + 0, 0, 0, 0, // ciaddr + 0, 0, 0, 0, // yiaddr + 0, 0, 0, 0, // siaddr + 0, 0, 0, 0, // giaddr + 232, 219, 132, 155, 251, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 130, 83, 99, 53, 1, 3, 57, 2, 5, 220, 50, 4, 192, 168, 1, 106, 54, 4, 192, 168, 1, 1, 55, 5, 1, 3, 28, 6, 42, 12, 10, 69, 83, 80, 45, 57, 66, 70, 66, 55, 66, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; #[test] fn parses() { diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1638b13 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,19 @@ +use dhcp::parse_dhcp_packet; +use std::net::UdpSocket; + +fn main() { + let sock = UdpSocket::bind("0.0.0.0:67").unwrap(); + + let mut buf = [0; 504]; + while let Ok((size, addr)) = sock.recv_from(&mut buf) { + println!("Got {size} bytes from {addr}"); + //println!("{buf:?}"); + let (_, msg) = parse_dhcp_packet(&buf).unwrap(); + dbg!(&msg); + let hostname = msg + .get_option::() + .unwrap() + .unwrap(); + println!("Hostname: {hostname}"); + } +} diff --git a/src/options/boot_file_size_option.rs b/src/options/boot_file_size_option.rs deleted file mode 100644 index 02f7181..0000000 --- a/src/options/boot_file_size_option.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::{DhcpOptionError, RawDhcpOption}; -use crate::options::DhcpOption; - -pub struct BootFileSizeOption; - -impl DhcpOption for BootFileSizeOption { - const CODE: u8 = 13; - type Item = u16; - - fn parse(option: &RawDhcpOption) -> Result { - (option.length == 2) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, 2))?; - let data = option.data[..2].try_into().expect("Parser pulled 2 bytes"); - Ok(u16::from_be_bytes(data)) - } -} diff --git a/src/options/cookie_server_option.rs b/src/options/cookie_server_option.rs deleted file mode 100644 index 3235185..0000000 --- a/src/options/cookie_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{DhcpOptionError, RawDhcpOption}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct CookieServerOption; - -impl DhcpOption for CookieServerOption { - const CODE: u8 = 8; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} \ No newline at end of file diff --git a/src/options/domain_name.rs b/src/options/domain_name.rs deleted file mode 100644 index 886e37a..0000000 --- a/src/options/domain_name.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct DomainName; - -impl DhcpOption for DomainName { - const CODE: u8 = 15; - type Item = String; - - fn parse(option: &RawDhcpOption) -> Result { - let data = core::str::from_utf8(&option.data)?; - Ok(data.to_string()) - } -} diff --git a/src/options/domain_name_server_option.rs b/src/options/domain_name_server_option.rs deleted file mode 100644 index 05ea70d..0000000 --- a/src/options/domain_name_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{DhcpOptionError, RawDhcpOption}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct DomainNameServerOption; - -impl DhcpOption for DomainNameServerOption { - const CODE: u8 = 6; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} diff --git a/src/options/extensions_path.rs b/src/options/extensions_path.rs deleted file mode 100644 index 59a901a..0000000 --- a/src/options/extensions_path.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct ExtensionsPath; - -impl DhcpOption for ExtensionsPath { - const CODE: u8 = 18; - type Item = String; - - fn parse(option: &RawDhcpOption) -> Result { - let data = core::str::from_utf8(&option.data)?; - Ok(data.to_string()) - } -} diff --git a/src/options/host_name_option.rs b/src/options/host_name_option.rs deleted file mode 100644 index 1dd585d..0000000 --- a/src/options/host_name_option.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct HostNameOption; - -impl DhcpOption for HostNameOption { - const CODE: u8 = 12; - type Item = String; - - fn parse(option: &RawDhcpOption) -> Result { - let data = core::str::from_utf8(&option.data)?; - Ok(data.to_string()) - } -} diff --git a/src/options/impress_server_option.rs b/src/options/impress_server_option.rs deleted file mode 100644 index 1d49474..0000000 --- a/src/options/impress_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct ImpressServerOption; - -impl DhcpOption for ImpressServerOption { - const CODE: u8 = 10; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} diff --git a/src/options/log_server_option.rs b/src/options/log_server_option.rs deleted file mode 100644 index b49ddb7..0000000 --- a/src/options/log_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct LogServerOption; - -impl DhcpOption for LogServerOption { - const CODE: u8 = 7; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} diff --git a/src/options/lpr_server_option.rs b/src/options/lpr_server_option.rs deleted file mode 100644 index 914e56c..0000000 --- a/src/options/lpr_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct LPRServerOption; - -impl DhcpOption for LPRServerOption { - const CODE: u8 = 9; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} diff --git a/src/options/merit_dump_file.rs b/src/options/merit_dump_file.rs deleted file mode 100644 index ec0dfd4..0000000 --- a/src/options/merit_dump_file.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct MeritDumpFile; - -impl DhcpOption for MeritDumpFile { - const CODE: u8 = 14; - type Item = String; - - fn parse(option: &RawDhcpOption) -> Result { - let data = core::str::from_utf8(&option.data)?; - Ok(data.to_string()) - } -} diff --git a/src/options/mod.rs b/src/options/mod.rs index 9de9f87..0ad5fdc 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -1,38 +1,215 @@ -mod boot_file_size_option; -mod cookie_server_option; -mod domain_name_server_option; -mod host_name_option; -mod impress_server_option; -mod log_server_option; -mod lpr_server_option; -mod name_server_option; -mod resource_location_server_option; -mod router_option; -mod subnet_mask; -mod time_offset; -mod time_server_option; -mod merit_dump_file; -mod domain_name; -mod swap_server; -mod root_path; -mod extensions_path; +use core::net::Ipv4Addr; -pub use boot_file_size_option::BootFileSizeOption; -pub use cookie_server_option::CookieServerOption; -pub use domain_name_server_option::DomainNameServerOption; -pub use impress_server_option::ImpressServerOption; -pub use log_server_option::LogServerOption; -pub use lpr_server_option::LPRServerOption; -pub use name_server_option::NameServerOption; -pub use resource_location_server_option::ResourceLocationServerOption; -pub use router_option::RouterOption; -pub use subnet_mask::SubnetMask; -pub use time_offset::TimeOffset; -pub use merit_dump_file::MeritDumpFile; -pub use domain_name::DomainName; -pub use swap_server::SwapServer; -pub use root_path::RootPath; -pub use extensions_path::ExtensionsPath; +macro_rules! define_dhcp_options { + ($($code:expr, $name:ident, $data:ty),+) => { + enum Code { + $($name = $code),+ + } + $( + pub struct $name(pub $data); + + impl DhcpOption for $name { + const CODE: u8 = $code; + type Item = $data; + + fn parse(option: &RawDhcpOption) -> Result { + TryFrom::try_from(option) + } + } + )+ + }; +} + +#[rustfmt::skip] +define_dhcp_options!( + 1, SubnetMask, Ipv4Addr, + 2, TimeOffset, u32, + 3, RouterOption, Vec, + 4, TimeServerOption, Vec, + 5, NameServerOption, Vec, + 6, DomainNameServerOption, Vec, + 7, LogServerOption, Vec, + 8, CookieServerOption, Vec, + 9, LprServerOption, Vec, + 10, ImpressServerOption, Vec, + 11, ResourceLocationServerOption, Vec, + 12, HostNameOption, String, + 13, BootFileSizeOption, u16, + 14, MeritDumpFile, String, + 15, DomainName, String, + 16, SwapServer, Vec, + 17, RootPath, String, + 18, ExtensionPath, String, + 19, IPForwardingOption, bool, + 20, NonLocalSourceRoutingOption, bool, + 21, PolicyFilterOption, Vec<(Ipv4Addr, Ipv4Addr)>, + 22, MaximumDatagramReassemblySize, u16, + 23, DefaultIPTimeToLive, u8, + 24, PathMTUAgingTimeoutOption, u32, + 25, PathMTUPlateauTableOption, Vec, + 26, InterfaceMTUOption, u16, + 27, AllSubnetsAreLocalOption, bool, + 28, BroadcastAddressOption, Ipv4Addr, + 29, PerformMaskDiscoveryOption, bool, + 30, MaskSupplierOption, bool, + 31, PerformRouterDiscoveryOption, bool, + 32, RouterSolicitationAddressOption, Ipv4Addr, + 33, StaticRouteOption, Vec<(Ipv4Addr, Ipv4Addr)>, + 34, TrailerEncapsulationOption, bool, + 35, ARPCacheTimeoutOption, u32, + 36, EthernetEncapsulationOption, bool, + 37, TCPDefaultTTLOption, u8, + 38, TCPKeepaliveIntervalOption, u32, + 39, TCPKeepaliveGarbageOption, bool, + 40, NetworkInformationServiceDomainOption, String, + 41, NetworkInformationServersOption, Vec, + 42, NetworkTimeProtocolServersOption, Vec, + 43, VendorSpecificInformation, Vec, + 44, NetBIOSOverTCPIPNameServerOption, Vec, + 45, NetBIOSOverTCPIPDatagramDistributionServerOption, Vec, + 46, NetBIOSOverTCPIPNodeTypeOption, u8, //TODO: Make separate type. RFC2132 section 8.6 + 47, NetBIOSOverTCPIPScopeOption, String, + 48, XWindowSystemFontServerOption, Vec + +); + +impl<'a> TryFrom<&RawDhcpOption<'a>> for Ipv4Addr { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + (option.length == 4) + .then_some(()) + .ok_or(DhcpOptionError::InvalidLength(option.length, 4))?; + Ok(Ipv4Addr::new( + option.data[0], + option.data[1], + option.data[2], + option.data[3], + )) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for u16 { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + (option.length == 2) + .then_some(()) + .ok_or(DhcpOptionError::InvalidLength(option.length, 2))?; + let data = option.data[..2].try_into().expect("Parser pulled 2 bytes"); + Ok(u16::from_be_bytes(data)) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for Vec { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + let rem = option.length % 2; + (rem == 0) + .then_some(()) + .ok_or(DhcpOptionError::InvalidLength( + option.length, + option.length + 2 - rem, + ))?; + Ok(option + .data + .chunks(2) + .map(|c| u16::from_be_bytes(c.try_into().expect("validated before"))) + .collect()) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for u8 { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + (option.length == 1) + .then_some(()) + .ok_or(DhcpOptionError::InvalidLength(option.length, 1))?; + Ok(option.data[0]) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for u32 { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + (option.length == 4) + .then_some(()) + .ok_or(DhcpOptionError::InvalidLength(option.length, 2))?; + let data = option.data[..4].try_into().expect("Parser pulled 4 bytes"); + Ok(u32::from_be_bytes(data)) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for Vec { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + let rem = option.length % 4; + (rem == 0) + .then_some(()) + .ok_or(DhcpOptionError::InvalidLength( + option.length, + option.length + 4 - rem, + ))?; + Ok(option + .data + .chunks(4) + .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) + .collect()) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for Vec { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + Ok(option.data.to_vec()) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for String { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + let data = core::str::from_utf8(option.data)?; + Ok(data.to_string()) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for bool { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + Ok(option.data[0] == 1) + } +} + +impl<'a> TryFrom<&RawDhcpOption<'a>> for Vec<(Ipv4Addr, Ipv4Addr)> { + type Error = DhcpOptionError; + + fn try_from(option: &RawDhcpOption<'a>) -> Result { + let rem = option.length % 8; + (rem == 0) + .then_some(()) + .ok_or(DhcpOptionError::InvalidLength( + option.length, + option.length + 8 - rem, + ))?; + Ok(option + .data + .chunks(8) + .map(|c| { + ( + Ipv4Addr::new(c[0], c[1], c[2], c[3]), + Ipv4Addr::new(c[4], c[5], c[6], c[7]), + ) + }) + .collect()) + } +} #[derive(Debug)] pub struct RawDhcpOption<'a> { @@ -71,4 +248,4 @@ impl From for DhcpOptionError { fn from(value: core::str::Utf8Error) -> Self { DhcpOptionError::UTF8Error } -} \ No newline at end of file +} diff --git a/src/options/name_server_option.rs b/src/options/name_server_option.rs deleted file mode 100644 index ba6699d..0000000 --- a/src/options/name_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct NameServerOption; - -impl DhcpOption for NameServerOption { - const CODE: u8 = 5; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} diff --git a/src/options/resource_location_server_option.rs b/src/options/resource_location_server_option.rs deleted file mode 100644 index 2ed71a3..0000000 --- a/src/options/resource_location_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct ResourceLocationServerOption; - -impl DhcpOption for ResourceLocationServerOption { - const CODE: u8 = 11; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} diff --git a/src/options/root_path.rs b/src/options/root_path.rs deleted file mode 100644 index b8047fd..0000000 --- a/src/options/root_path.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct RootPath; - -impl DhcpOption for RootPath { - const CODE: u8 = 17; - type Item = String; - - fn parse(option: &RawDhcpOption) -> Result { - let data = core::str::from_utf8(&option.data)?; - Ok(data.to_string()) - } -} diff --git a/src/options/router_option.rs b/src/options/router_option.rs deleted file mode 100644 index ea80258..0000000 --- a/src/options/router_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct RouterOption; - -impl DhcpOption for RouterOption { - const CODE: u8 = 3; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -} diff --git a/src/options/subnet_mask.rs b/src/options/subnet_mask.rs deleted file mode 100644 index 8f81c69..0000000 --- a/src/options/subnet_mask.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{DhcpOptionError, RawDhcpOption}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct SubnetMask; - -impl DhcpOption for SubnetMask { - const CODE: u8 = 1; - type Item = Ipv4Addr; - - fn parse(option: &RawDhcpOption) -> Result { - (option.length == 4) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, 4))?; - Ok(Ipv4Addr::new( - option.data[0], - option.data[1], - option.data[2], - option.data[3], - )) - } -} diff --git a/src/options/swap_server.rs b/src/options/swap_server.rs deleted file mode 100644 index 7cefca6..0000000 --- a/src/options/swap_server.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{DhcpOptionError, RawDhcpOption}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct SwapServer; - -impl DhcpOption for SwapServer { - const CODE: u8 = 16; - type Item = Ipv4Addr; - - fn parse(option: &RawDhcpOption) -> Result { - (option.length == 4) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, 4))?; - Ok(Ipv4Addr::new( - option.data[0], - option.data[1], - option.data[2], - option.data[3], - )) - } -} diff --git a/src/options/time_offset.rs b/src/options/time_offset.rs deleted file mode 100644 index 7e921f0..0000000 --- a/src/options/time_offset.rs +++ /dev/null @@ -1,20 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; - -pub struct TimeOffset; - -impl DhcpOption for TimeOffset { - const CODE: u8 = 2; - type Item = u32; - - fn parse(option: &RawDhcpOption) -> Result { - (option.length == 4) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, 4))?; - Ok(u32::from_be_bytes( - option.data[..4] - .try_into() - .expect("The parser pulled exactly 4 bytes"), - )) - } -} diff --git a/src/options/time_server_option.rs b/src/options/time_server_option.rs deleted file mode 100644 index 5a5a04d..0000000 --- a/src/options/time_server_option.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{RawDhcpOption, DhcpOptionError}; -use crate::options::DhcpOption; -use core::net::Ipv4Addr; - -pub struct TimeServerOption; - -impl DhcpOption for TimeServerOption { - const CODE: u8 = 4; - type Item = Vec; - - fn parse(option: &RawDhcpOption) -> Result { - let rem = option.length % 4; - (rem == 0) - .then_some(()) - .ok_or(DhcpOptionError::InvalidLength(option.length, option.length + 4 - rem))?; - Ok(option - .data - .chunks(4) - .map(|c| Ipv4Addr::new(c[0], c[1], c[2], c[3])) - .collect()) - } -}