From e0cc79198f9f76c8ca528e1b85f4268d57cec914 Mon Sep 17 00:00:00 2001 From: fuckwit Date: Mon, 22 May 2023 22:43:16 +0200 Subject: [PATCH] parse server name and file name --- src/lib.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e5329c6..17dc8e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,8 @@ +#![allow(unused)] use std::{net::Ipv4Addr, path::Path}; use nom::{ - bytes::complete::take, + bytes::complete::{take, take_until}, number::complete::{be_u16, be_u32, be_u8}, IResult, }; @@ -14,15 +15,18 @@ struct DhcpMessage<'a> { hops: u8, transaction_id: u32, seconds: u16, - flags: u16, + flags: Flags, client_address: Ipv4Addr, server_address: Ipv4Addr, gateway_address: Ipv4Addr, client_hardware_address: &'a [u8], - server_hostname: &'a str, - boot_file_name: &'a Path, + server_name: &'a str, + file_name: &'a Path, } +#[derive(Debug)] +struct Flags(u16); + #[derive(Debug)] enum Operation { Request = 1, @@ -61,6 +65,10 @@ fn parse_dhcp_operation(i: &[u8]) -> IResult<&[u8], Operation> { be_u8(i).map(|(i, v)| (i, v.into())) } +fn parse_dhcp_flags(i: &[u8]) -> IResult<&[u8], Flags> { + be_u16(i).map(|(i, v)| (i, Flags(v))) +} + fn parse_dhcp_hardware_type(i: &[u8]) -> IResult<&[u8], HardwareType> { be_u8(i).map(|(i, v)| (i, v.into())) } @@ -71,6 +79,28 @@ fn parse_ipv4_address(i: &[u8]) -> IResult<&[u8], Ipv4Addr> { Ok((i, ip)) } +fn parse_client_hardware_address(i: &[u8], hardware_address_length: u8) -> IResult<&[u8], &[u8]> { + let (i, val) = take(hardware_address_length)(i)?; + let (i, _padding) = take(0x10 - hardware_address_length)(i)?; + Ok((i, val)) +} + +fn parse_server_name(i: &[u8]) -> IResult<&[u8], &str> { + let (i, val) = take(64usize)(i)?; + let nullbyte_position = val.iter().position(|v| *v == b'\0').unwrap_or(64); + let val = unsafe { std::str::from_utf8_unchecked(&val[..nullbyte_position]) }; + + Ok((i, val)) +} + +fn parse_file(i: &[u8]) -> IResult<&[u8], &Path> { + let (i, val) = take(128usize)(i)?; + let nullbyte_position = val.iter().position(|v| *v == b'\0').unwrap_or(128); + let val = unsafe { std::str::from_utf8_unchecked(&val[..nullbyte_position]) }; + + Ok((i, Path::new(val))) +} + fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], DhcpMessage> { let (packet, operation) = parse_dhcp_operation(packet)?; let (packet, hardware_type) = parse_dhcp_hardware_type(packet)?; @@ -78,11 +108,16 @@ fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], DhcpMessage> { let (packet, hops) = be_u8(packet)?; let (packet, transaction_id) = be_u32(packet)?; let (packet, seconds) = be_u16(packet)?; - let (packet, flags) = be_u16(packet)?; + let (packet, flags) = parse_dhcp_flags(packet)?; let (packet, client_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) = take(6usize)(packet)?; + let (packet, client_hardware_address) = + parse_client_hardware_address(packet, hardware_address_length)?; + let potential_options = packet; + + let (packet, server_name) = parse_server_name(packet)?; + let (packet, file_name) = parse_file(packet)?; Ok(( packet, @@ -98,8 +133,8 @@ fn parse_dhcp_packet(packet: &[u8]) -> IResult<&[u8], DhcpMessage> { server_address, gateway_address, client_hardware_address, - server_hostname: "", - boot_file_name: Path::new(""), + server_name, + file_name, }, )) } @@ -110,6 +145,21 @@ mod tests { static DHCP_PACKET2: &'static [u8] = &[ 0x01, 0x01, 0x06, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x54, 0x05, 0xdb, 0xa6, 0x96, 0xd0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //CHADDR padding + 0x49, 0x20, 0x62, 0x69, 0x6D, 0x73, 0x20, 0x31, 0x20, 0x44, 0x48, 0x43, 0x50, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // server name with padding + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // file with padding ]; #[test]