Rework structure
Remove the "file per option" structure and replace it with a macro that generates the `DhcpOption` impl. This also generates a `Code` enum with all the options are variants. This will later be used for parameter requests and programmatic checking if certain options exist. Also fixes a bug where I have left out the `your_address` field.
This commit is contained in:
parent
2639aeca24
commit
b095fa96de
30
src/lib.rs
30
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<T>(&self) -> Option<Result<T::Item, DhcpOptionError>>
|
||||
pub fn get_option<T>(&self) -> Option<Result<T::Item, DhcpOptionError>>
|
||||
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() {
|
||||
|
19
src/main.rs
Normal file
19
src/main.rs
Normal file
@ -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::<dhcp::options::HostNameOption>()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
println!("Hostname: {hostname}");
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
(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))
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
let data = core::str::from_utf8(&option.data)?;
|
||||
Ok(data.to_string())
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
let data = core::str::from_utf8(&option.data)?;
|
||||
Ok(data.to_string())
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
let data = core::str::from_utf8(&option.data)?;
|
||||
Ok(data.to_string())
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
let data = core::str::from_utf8(&option.data)?;
|
||||
Ok(data.to_string())
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
TryFrom::try_from(option)
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
define_dhcp_options!(
|
||||
1, SubnetMask, Ipv4Addr,
|
||||
2, TimeOffset, u32,
|
||||
3, RouterOption, Vec<Ipv4Addr>,
|
||||
4, TimeServerOption, Vec<Ipv4Addr>,
|
||||
5, NameServerOption, Vec<Ipv4Addr>,
|
||||
6, DomainNameServerOption, Vec<Ipv4Addr>,
|
||||
7, LogServerOption, Vec<Ipv4Addr>,
|
||||
8, CookieServerOption, Vec<Ipv4Addr>,
|
||||
9, LprServerOption, Vec<Ipv4Addr>,
|
||||
10, ImpressServerOption, Vec<Ipv4Addr>,
|
||||
11, ResourceLocationServerOption, Vec<Ipv4Addr>,
|
||||
12, HostNameOption, String,
|
||||
13, BootFileSizeOption, u16,
|
||||
14, MeritDumpFile, String,
|
||||
15, DomainName, String,
|
||||
16, SwapServer, Vec<Ipv4Addr>,
|
||||
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<u16>,
|
||||
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<Ipv4Addr>,
|
||||
42, NetworkTimeProtocolServersOption, Vec<Ipv4Addr>,
|
||||
43, VendorSpecificInformation, Vec<u8>,
|
||||
44, NetBIOSOverTCPIPNameServerOption, Vec<Ipv4Addr>,
|
||||
45, NetBIOSOverTCPIPDatagramDistributionServerOption, Vec<Ipv4Addr>,
|
||||
46, NetBIOSOverTCPIPNodeTypeOption, u8, //TODO: Make separate type. RFC2132 section 8.6
|
||||
47, NetBIOSOverTCPIPScopeOption, String,
|
||||
48, XWindowSystemFontServerOption, Vec<Ipv4Addr>
|
||||
|
||||
);
|
||||
|
||||
impl<'a> TryFrom<&RawDhcpOption<'a>> for Ipv4Addr {
|
||||
type Error = DhcpOptionError;
|
||||
|
||||
fn try_from(option: &RawDhcpOption<'a>) -> Result<Self, Self::Error> {
|
||||
(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<Self, Self::Error> {
|
||||
(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<u16> {
|
||||
type Error = DhcpOptionError;
|
||||
|
||||
fn try_from(option: &RawDhcpOption<'a>) -> Result<Self, Self::Error> {
|
||||
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<Self, Self::Error> {
|
||||
(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<Self, Self::Error> {
|
||||
(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<Ipv4Addr> {
|
||||
type Error = DhcpOptionError;
|
||||
|
||||
fn try_from(option: &RawDhcpOption<'a>) -> Result<Self, Self::Error> {
|
||||
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<u8> {
|
||||
type Error = DhcpOptionError;
|
||||
|
||||
fn try_from(option: &RawDhcpOption<'a>) -> Result<Self, Self::Error> {
|
||||
Ok(option.data.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&RawDhcpOption<'a>> for String {
|
||||
type Error = DhcpOptionError;
|
||||
|
||||
fn try_from(option: &RawDhcpOption<'a>) -> Result<Self, Self::Error> {
|
||||
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<Self, Self::Error> {
|
||||
Ok(option.data[0] == 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&RawDhcpOption<'a>> for Vec<(Ipv4Addr, Ipv4Addr)> {
|
||||
type Error = DhcpOptionError;
|
||||
|
||||
fn try_from(option: &RawDhcpOption<'a>) -> Result<Self, Self::Error> {
|
||||
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<core::str::Utf8Error> for DhcpOptionError {
|
||||
fn from(value: core::str::Utf8Error) -> Self {
|
||||
DhcpOptionError::UTF8Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
let data = core::str::from_utf8(&option.data)?;
|
||||
Ok(data.to_string())
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
(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],
|
||||
))
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
(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],
|
||||
))
|
||||
}
|
||||
}
|
@ -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<Self::Item, DhcpOptionError> {
|
||||
(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"),
|
||||
))
|
||||
}
|
||||
}
|
@ -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<Ipv4Addr>;
|
||||
|
||||
fn parse(option: &RawDhcpOption) -> Result<Self::Item, DhcpOptionError> {
|
||||
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())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user