From df34ffc6909cf2d903d87ae99c14c79de8fa1d83 Mon Sep 17 00:00:00 2001 From: pj1234678 <13920460+pj1234678@users.noreply.github.com> Date: Thu, 24 Sep 2026 15:25:03 -0700 Subject: [PATCH] Delete src directory --- src/lib.rs | 9 -- src/options.rs | 367 ------------------------------------------------- src/packet.rs | 298 --------------------------------------- src/server.rs | 171 ----------------------- 4 files changed, 845 deletions(-) delete mode 100644 src/lib.rs delete mode 100644 src/options.rs delete mode 100644 src/packet.rs delete mode 100644 src/server.rs diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index e239a0f..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod options; -pub mod packet; -pub mod server; - -#[cfg(test)] -mod tests { - #[test] - fn it_works() {} -} diff --git a/src/options.rs b/src/options.rs deleted file mode 100644 index 742f493..0000000 --- a/src/options.rs +++ /dev/null @@ -1,367 +0,0 @@ -///use num_traits::FromPrimitive; -use std::net::Ipv4Addr; - -#[derive(PartialEq, Clone, Debug)] -pub struct RawDhcpOption { - pub code: u8, - pub data: Vec, -} - -#[derive(PartialEq, Debug)] -pub enum DhcpOption { - DhcpMessageType(MessageType), - ServerIdentifier(Ipv4Addr), - ParameterRequestList(Vec), - RequestedIpAddress(Ipv4Addr), - HostName(String), - Router(Vec), - DomainNameServer(Vec), - IpAddressLeaseTime(u32), - SubnetMask(Ipv4Addr), - Message(String), - Unrecognized(RawDhcpOption), -} - -impl DhcpOption { - pub fn to_raw(&self) -> RawDhcpOption { - match self { - Self::DhcpMessageType(mtype) => RawDhcpOption { - code: DHCP_MESSAGE_TYPE, - data: vec![*mtype as u8], - }, - Self::ServerIdentifier(addr) => RawDhcpOption { - code: SERVER_IDENTIFIER, - data: addr.octets().to_vec(), - }, - Self::ParameterRequestList(prl) => RawDhcpOption { - code: PARAMETER_REQUEST_LIST, - data: prl.clone(), - }, - Self::RequestedIpAddress(addr) => RawDhcpOption { - code: REQUESTED_IP_ADDRESS, - data: addr.octets().to_vec(), - }, - Self::HostName(name) => RawDhcpOption { - code: HOST_NAME, - data: name.as_bytes().to_vec(), - }, - Self::Router(addrs) => RawDhcpOption { - code: ROUTER, - data: { - let mut v = vec![]; - for a in addrs { - v.extend(a.octets().iter()); - } - v - }, - }, - Self::DomainNameServer(addrs) => RawDhcpOption { - code: DOMAIN_NAME_SERVER, - data: { - let mut v = vec![]; - for a in addrs { - v.extend(a.octets().iter()); - } - v - }, - }, - Self::IpAddressLeaseTime(secs) => RawDhcpOption { - code: IP_ADDRESS_LEASE_TIME, - data: secs.to_be_bytes().to_vec(), - }, - Self::SubnetMask(mask) => RawDhcpOption { - code: SUBNET_MASK, - data: mask.octets().to_vec(), - }, - Self::Message(msg) => RawDhcpOption { - code: MESSAGE, - data: msg.as_bytes().to_vec(), - }, - Self::Unrecognized(raw) => raw.clone(), - } - } - - pub fn code(&self) -> u8 { - match self { - Self::DhcpMessageType(_) => DHCP_MESSAGE_TYPE, - Self::ServerIdentifier(_) => SERVER_IDENTIFIER, - Self::ParameterRequestList(_) => PARAMETER_REQUEST_LIST, - Self::RequestedIpAddress(_) => REQUESTED_IP_ADDRESS, - Self::HostName(_) => HOST_NAME, - Self::Router(_) => ROUTER, - Self::DomainNameServer(_) => DOMAIN_NAME_SERVER, - Self::IpAddressLeaseTime(_) => IP_ADDRESS_LEASE_TIME, - Self::SubnetMask(_) => SUBNET_MASK, - Self::Message(_) => MESSAGE, - Self::Unrecognized(x) => x.code, - } - } -} - -// DHCP Options; -pub const SUBNET_MASK: u8 = 1; -pub const TIME_OFFSET: u8 = 2; -pub const ROUTER: u8 = 3; -pub const TIME_SERVER: u8 = 4; -pub const NAME_SERVER: u8 = 5; -pub const DOMAIN_NAME_SERVER: u8 = 6; -pub const LOG_SERVER: u8 = 7; -pub const COOKIE_SERVER: u8 = 8; -pub const LPR_SERVER: u8 = 9; -pub const IMPRESS_SERVER: u8 = 10; -pub const RESOURCE_LOCATION_SERVER: u8 = 11; -pub const HOST_NAME: u8 = 12; -pub const BOOT_FILE_SIZE: u8 = 13; -pub const MERIT_DUMP_FILE: u8 = 14; -pub const DOMAIN_NAME: u8 = 15; -pub const SWAP_SERVER: u8 = 16; -pub const ROOT_PATH: u8 = 17; -pub const EXTENSIONS_PATH: u8 = 18; - -// IP LAYER PARAMETERS PER HOST; -pub const IP_FORWARDING_ENABLE_DISABLE: u8 = 19; -pub const NON_LOCAL_SOURCE_ROUTING_ENABLE_DISABLE: u8 = 20; -pub const POLICY_FILTER: u8 = 21; -pub const MAXIMUM_DATAGRAM_REASSEMBLY_SIZE: u8 = 22; -pub const DEFAULT_IP_TIME_TO_LIVE: u8 = 23; -pub const PATH_MTU_AGING_TIMEOUT: u8 = 24; -pub const PATH_MTU_PLATEAU_TABLE: u8 = 25; - -// IP LAYER PARAMETERS PER INTERFACE; -pub const INTERFACE_MTU: u8 = 26; -pub const ALL_SUBNETS_ARE_LOCAL: u8 = 27; -pub const BROADCAST_ADDRESS: u8 = 28; -pub const PERFORM_MASK_DISCOVERY: u8 = 29; -pub const MASK_SUPPLIER: u8 = 30; -pub const PERFORM_ROUTER_DISCOVERY: u8 = 31; -pub const ROUTER_SOLICITATION_ADDRESS: u8 = 32; -pub const STATIC_ROUTE: u8 = 33; - -// LINK LAYER PARAMETERS PER INTERFACE; -pub const TRAILER_ENCAPSULATION: u8 = 34; -pub const ARP_CACHE_TIMEOUT: u8 = 35; -pub const ETHERNET_ENCAPSULATION: u8 = 36; - -// TCP PARAMETERS; -pub const TCP_DEFAULT_TTL: u8 = 37; -pub const TCP_KEEPALIVE_INTERVAL: u8 = 38; -pub const TCP_KEEPALIVE_GARBAGE: u8 = 39; - -// APPLICATION AND SERVICE PARAMETERS; -pub const NETWORK_INFORMATION_SERVICE_DOMAIN: u8 = 40; -pub const NETWORK_INFORMATION_SERVERS: u8 = 41; -pub const NETWORK_TIME_PROTOCOL_SERVERS: u8 = 42; -pub const VENDOR_SPECIFIC_INFORMATION: u8 = 43; -pub const NETBIOS_OVER_TCPIP_NAME_SERVER: u8 = 44; -pub const NETBIOS_OVER_TCPIP_DATAGRAM_DISTRIBUTION_SERVER: u8 = 45; -pub const NETBIOS_OVER_TCPIP_NODE_TYPE: u8 = 46; -pub const NETBIOS_OVER_TCPIP_SCOPE: u8 = 47; -pub const XWINDOW_SYSTEM_FONT_SERVER: u8 = 48; -pub const XWINDOW_SYSTEM_DISPLAY_MANAGER: u8 = 49; -pub const NETWORK_INFORMATION_SERVICEPLUS_DOMAIN: u8 = 64; -pub const NETWORK_INFORMATION_SERVICEPLUS_SERVERS: u8 = 65; -pub const MOBILE_IP_HOME_AGENT: u8 = 68; -pub const SIMPLE_MAIL_TRANSPORT_PROTOCOL: u8 = 69; -pub const POST_OFFICE_PROTOCOL_SERVER: u8 = 70; -pub const NETWORK_NEWS_TRANSPORT_PROTOCOL: u8 = 71; -pub const DEFAULT_WORLD_WIDE_WEB_SERVER: u8 = 72; -pub const DEFAULT_FINGER_SERVER: u8 = 73; -pub const DEFAULT_INTERNET_RELAY_CHAT_SERVER: u8 = 74; -pub const STREETTALK_SERVER: u8 = 75; -pub const STREETTALK_DIRECTORY_ASSISTANCE: u8 = 76; - -pub const RELAY_AGENT_INFORMATION: u8 = 82; - -// DHCP EXTENSIONS -pub const REQUESTED_IP_ADDRESS: u8 = 50; -pub const IP_ADDRESS_LEASE_TIME: u8 = 51; -pub const OVERLOAD: u8 = 52; -pub const DHCP_MESSAGE_TYPE: u8 = 53; -pub const SERVER_IDENTIFIER: u8 = 54; -pub const PARAMETER_REQUEST_LIST: u8 = 55; -pub const MESSAGE: u8 = 56; -pub const MAXIMUM_DHCP_MESSAGE_SIZE: u8 = 57; -pub const RENEWAL_TIME_VALUE: u8 = 58; -pub const REBINDING_TIME_VALUE: u8 = 59; -pub const VENDOR_CLASS_IDENTIFIER: u8 = 60; -pub const CLIENT_IDENTIFIER: u8 = 61; - -pub const TFTP_SERVER_NAME: u8 = 66; -pub const BOOTFILE_NAME: u8 = 67; - -pub const USER_CLASS: u8 = 77; - -pub const CLIENT_ARCHITECTURE: u8 = 93; - -pub const TZ_POSIX_STRING: u8 = 100; -pub const TZ_DATABASE_STRING: u8 = 101; - -pub const CLASSLESS_ROUTE_FORMAT: u8 = 121; - -/// Returns title of DHCP Option code, if known. -pub fn title(code: u8) -> Option<&'static str> { - Some(match code { - SUBNET_MASK => "Subnet Mask", - - TIME_OFFSET => "Time Offset", - ROUTER => "Router", - TIME_SERVER => "Time Server", - NAME_SERVER => "Name Server", - DOMAIN_NAME_SERVER => "Domain Name Server", - LOG_SERVER => "Log Server", - COOKIE_SERVER => "Cookie Server", - LPR_SERVER => "LPR Server", - IMPRESS_SERVER => "Impress Server", - RESOURCE_LOCATION_SERVER => "Resource Location Server", - HOST_NAME => "Host Name", - BOOT_FILE_SIZE => "Boot File Size", - MERIT_DUMP_FILE => "Merit Dump File", - DOMAIN_NAME => "Domain Name", - SWAP_SERVER => "Swap Server", - ROOT_PATH => "Root Path", - EXTENSIONS_PATH => "Extensions Path", - - // IP LAYER PARAMETERS PER HOST", - IP_FORWARDING_ENABLE_DISABLE => "IP Forwarding Enable/Disable", - NON_LOCAL_SOURCE_ROUTING_ENABLE_DISABLE => "Non-Local Source Routing Enable/Disable", - POLICY_FILTER => "Policy Filter", - MAXIMUM_DATAGRAM_REASSEMBLY_SIZE => "Maximum Datagram Reassembly Size", - DEFAULT_IP_TIME_TO_LIVE => "Default IP Time-to-live", - PATH_MTU_AGING_TIMEOUT => "Path MTU Aging Timeout", - PATH_MTU_PLATEAU_TABLE => "Path MTU Plateau Table", - - // IP LAYER PARAMETERS PER INTERFACE", - INTERFACE_MTU => "Interface MTU", - ALL_SUBNETS_ARE_LOCAL => "All Subnets are Local", - BROADCAST_ADDRESS => "Broadcast Address", - PERFORM_MASK_DISCOVERY => "Perform Mask Discovery", - MASK_SUPPLIER => "Mask Supplier", - PERFORM_ROUTER_DISCOVERY => "Perform Router Discovery", - ROUTER_SOLICITATION_ADDRESS => "Router Solicitation Address", - STATIC_ROUTE => "Static Route", - - // LINK LAYER PARAMETERS PER INTERFACE", - TRAILER_ENCAPSULATION => "Trailer Encapsulation", - ARP_CACHE_TIMEOUT => "ARP Cache Timeout", - ETHERNET_ENCAPSULATION => "Ethernet Encapsulation", - - // TCP PARAMETERS", - TCP_DEFAULT_TTL => "TCP Default TTL", - TCP_KEEPALIVE_INTERVAL => "TCP Keepalive Interval", - TCP_KEEPALIVE_GARBAGE => "TCP Keepalive Garbage", - - // APPLICATION AND SERVICE PARAMETERS", - NETWORK_INFORMATION_SERVICE_DOMAIN => "Network Information Service Domain", - NETWORK_INFORMATION_SERVERS => "Network Information Servers", - NETWORK_TIME_PROTOCOL_SERVERS => "Network Time Protocol Servers", - VENDOR_SPECIFIC_INFORMATION => "Vendor Specific Information", - NETBIOS_OVER_TCPIP_NAME_SERVER => "NetBIOS over TCP/IP Name Server", - NETBIOS_OVER_TCPIP_DATAGRAM_DISTRIBUTION_SERVER => { - "NetBIOS over TCP/IP Datagram Distribution Server" - } - NETBIOS_OVER_TCPIP_NODE_TYPE => "NetBIOS over TCP/IP Node Type", - NETBIOS_OVER_TCPIP_SCOPE => "NetBIOS over TCP/IP Scope", - XWINDOW_SYSTEM_FONT_SERVER => "X Window System Font Server", - XWINDOW_SYSTEM_DISPLAY_MANAGER => "X Window System Display Manager", - NETWORK_INFORMATION_SERVICEPLUS_DOMAIN => "Network Information Service+ Domain", - NETWORK_INFORMATION_SERVICEPLUS_SERVERS => "Network Information Service+ Servers", - MOBILE_IP_HOME_AGENT => "Mobile IP Home Agent", - SIMPLE_MAIL_TRANSPORT_PROTOCOL => "Simple Mail Transport Protocol (SMTP) Server", - POST_OFFICE_PROTOCOL_SERVER => "Post Office Protocol (POP3) Server", - NETWORK_NEWS_TRANSPORT_PROTOCOL => "Network News Transport Protocol (NNTP) Server", - DEFAULT_WORLD_WIDE_WEB_SERVER => "Default World Wide Web (WWW) Server", - DEFAULT_FINGER_SERVER => "Default Finger Server", - DEFAULT_INTERNET_RELAY_CHAT_SERVER => "Default Internet Relay Chat (IRC) Server", - STREETTALK_SERVER => "StreetTalk Server", - STREETTALK_DIRECTORY_ASSISTANCE => "StreetTalk Directory Assistance (STDA) Server", - - RELAY_AGENT_INFORMATION => "Relay Agent Information", - - // DHCP EXTENSIONS - REQUESTED_IP_ADDRESS => "Requested IP Address", - IP_ADDRESS_LEASE_TIME => "IP Address Lease Time", - OVERLOAD => "Overload", - DHCP_MESSAGE_TYPE => "DHCP Message Type", - SERVER_IDENTIFIER => "Server Identifier", - PARAMETER_REQUEST_LIST => "Parameter Request List", - MESSAGE => "Message", - MAXIMUM_DHCP_MESSAGE_SIZE => "Maximum DHCP Message Size", - RENEWAL_TIME_VALUE => "Renewal (T1) Time Value", - REBINDING_TIME_VALUE => "Rebinding (T2) Time Value", - VENDOR_CLASS_IDENTIFIER => "Vendor class identifier", - CLIENT_IDENTIFIER => "Client-identifier", - - // Find below - TFTP_SERVER_NAME => "TFTP server name", - BOOTFILE_NAME => "Bootfile name", - - USER_CLASS => "User Class", - - CLIENT_ARCHITECTURE => "Client Architecture", - - TZ_POSIX_STRING => "TZ-POSIX String", - TZ_DATABASE_STRING => "TZ-Database String", - CLASSLESS_ROUTE_FORMAT => "Classless Route Format", - - _ => return None, - }) -} - -/// -/// DHCP Message Type. -/// -/// # Standards -/// -/// The semantics of the various DHCP message types are described in RFC 2131 (see Table 2). -/// Their numeric values are described in Section 9.6 of RFC 2132, which begins: -/// -/// > This option is used to convey the type of the DHCP message. The code for this option is 53, -/// > and its length is 1. -/// -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum MessageType { - /// Client broadcast to locate available servers. - Discover = 1, - - /// Server to client in response to DHCPDISCOVER with offer of configuration parameters. - Offer = 2, - - /// Client message to servers either (a) requesting offered parameters from one server and - /// implicitly declining offers from all others, (b) confirming correctness of previously - /// allocated address after, e.g., system reboot, or (c) extending the lease on a particular - /// network address. - Request = 3, - - /// Client to server indicating network address is already in use. - Decline = 4, - - /// Server to client with configuration parameters, including committed network address. - Ack = 5, - - /// Server to client indicating client's notion of network address is incorrect (e.g., client - /// has moved to new subnet) or client's lease as expired. - Nak = 6, - - /// Client to server relinquishing network address and cancelling remaining lease. - Release = 7, - - /// Client to server, asking only for local configuration parameters; client already has - /// externally configured network address. - Inform = 8, -} - -impl MessageType { - pub fn from(val: u8) -> Result { - match val { - 1 => Ok(MessageType::Discover), - 2 => Ok(MessageType::Offer), - 3 => Ok(MessageType::Request), - 4 => Ok(MessageType::Decline), - 5 => Ok(MessageType::Ack), - 6 => Ok(MessageType::Nak), - 7 => Ok(MessageType::Release), - 8 => Ok(MessageType::Inform), - _ => Err(format!("Invalid DHCP Message Type: {:?}", val)), - } - } -} diff --git a/src/packet.rs b/src/packet.rs deleted file mode 100644 index 2d41431..0000000 --- a/src/packet.rs +++ /dev/null @@ -1,298 +0,0 @@ -use crate::options::*; - -use std::net::Ipv4Addr; - -pub enum CustomErr { - NomError((I, ErrorKind)), - NonUtf8String, - UnrecognizedMessageType, - InvalidHlen, -} - -pub enum ErrorKind { - Tag, - MapRes, - ManyTill, - Eof, - Custom(u32), -} - -type IResult = Result<(I, O), CustomErr>; - -/// DHCP Packet Structure -#[derive(Debug)] -pub struct Packet { - pub reply: bool, // false = request, true = reply - pub hops: u8, - pub xid: u32, // Random identifier - pub secs: u16, - pub broadcast: bool, - pub ciaddr: Ipv4Addr, - pub yiaddr: Ipv4Addr, - pub siaddr: Ipv4Addr, - pub giaddr: Ipv4Addr, - pub chaddr: [u8; 6], - pub options: Vec, -} - -fn decode_reply(input: &[u8]) -> IResult<&[u8], bool> { - let (input, reply) = custom_take(1usize)(input)?; - Ok(( - input, - match reply[0] { - BOOT_REPLY => true, - BOOT_REQUEST => false, - _ => { - // @TODO: Throw an error - false - } - }, - )) -} - -fn decode_ipv4(p: &[u8]) -> IResult<&[u8], Ipv4Addr> { - let (input, addr) = custom_take(4usize)(p)?; - Ok((input, Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3]))) -} -fn custom_many0(mut f: F) -> impl FnMut(I) -> IResult> -where - I: Clone + PartialEq, - F: FnMut(I) -> IResult, -{ - move |input: I| { - let mut acc = Vec::new(); - let mut remaining = input.clone(); - - loop { - match f(remaining.clone()) { - Ok((input, o)) => { - if input == remaining { - return Ok((input, acc)); - } - acc.push(o); - remaining = input; - } - Err(CustomErr::NomError(_)) => return Ok((remaining, acc)), - Err(e) => return Err(e), - } - } - } -} -pub fn decode_option(input: &[u8]) -> IResult<&[u8], DhcpOption> { - let (input, code) = custom_be_u8(input)?; - assert!(code != END); - - let (input, len) = custom_be_u8(input)?; - let (input, data) = custom_take(len.into())(input)?; - let option = match code { - DHCP_MESSAGE_TYPE => { - DhcpOption::DhcpMessageType(match MessageType::from(custom_be_u8(data)?.1) { - Ok(x) => x, - Err(_) => return Err(CustomErr::UnrecognizedMessageType), - }) - } - SERVER_IDENTIFIER => DhcpOption::ServerIdentifier(decode_ipv4(data)?.1), - PARAMETER_REQUEST_LIST => DhcpOption::ParameterRequestList(data.to_vec()), - REQUESTED_IP_ADDRESS => DhcpOption::RequestedIpAddress(decode_ipv4(data)?.1), - HOST_NAME => DhcpOption::HostName(match std::str::from_utf8(data) { - Ok(s) => s.to_string(), - Err(_) => return Err(CustomErr::NonUtf8String), - }), - ROUTER => DhcpOption::Router(custom_many0(decode_ipv4)(data)?.1), - DOMAIN_NAME_SERVER => DhcpOption::DomainNameServer(custom_many0(decode_ipv4)(data)?.1), - IP_ADDRESS_LEASE_TIME => DhcpOption::IpAddressLeaseTime(custom_be_u32(data)?.1), - SUBNET_MASK => DhcpOption::SubnetMask(decode_ipv4(data)?.1), - MESSAGE => DhcpOption::Message(match std::str::from_utf8(data) { - Ok(s) => s.to_string(), - Err(_) => return Err(CustomErr::NonUtf8String), - }), - _ => DhcpOption::Unrecognized(RawDhcpOption { - code, - data: data.to_vec(), - }), - }; - Ok((input, option)) -} -fn custom_take<'a>(n: usize) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> { - move |input: &'a [u8]| { - if input.len() >= n { - Ok((&input[n..], &input[0..n])) - } else { - Err(CustomErr::InvalidHlen) - } - } -} - -fn custom_tag<'a>(tag: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> { - move |input: &'a [u8]| { - if input.starts_with(tag) { - Ok((&input[tag.len()..], &input[..tag.len()])) - } else { - Err(CustomErr::NomError((input, ErrorKind::Tag))) - } - } -} -fn custom_be_u8(input: &[u8]) -> IResult<&[u8], u8> { - if input.is_empty() { - return Err(CustomErr::InvalidHlen); - } - - Ok((&input[1..], input[0])) -} - -fn custom_be_u16(input: &[u8]) -> IResult<&[u8], u16> { - if input.len() < 2 { - return Err(CustomErr::InvalidHlen); - } - - let value = u16::from_be_bytes([input[0], input[1]]); - Ok((&input[2..], value)) -} -fn custom_be_u32(input: &[u8]) -> IResult<&[u8], u32> { - if input.len() < 4 { - return Err(CustomErr::InvalidHlen); - } - - let value = u32::from_be_bytes([input[0], input[1], input[2], input[3]]); - Ok((&input[4..], value)) -} - -/// Parses Packet from byte array -fn decode(input: &[u8]) -> IResult<&[u8], Packet> { - let (options_input, input) = custom_take(236usize)(input)?; - - let (input, reply) = decode_reply(input)?; - let (input, _htype) = custom_take(1usize)(input)?; - let (input, hlen) = custom_be_u8(input)?; - let (input, hops) = custom_be_u8(input)?; - let (input, xid) = custom_be_u32(input)?; - let (input, secs) = custom_be_u16(input)?; - let (input, flags) = custom_be_u16(input)?; - let (input, ciaddr) = decode_ipv4(input)?; - let (input, yiaddr) = decode_ipv4(input)?; - let (input, siaddr) = decode_ipv4(input)?; - let (input, giaddr) = decode_ipv4(input)?; - - if hlen != 6 { - return Err(CustomErr::InvalidHlen); - } - let (_, chaddr) = custom_take(6usize)(input)?; - - let input = options_input; - let (input, _) = custom_tag(&COOKIE)(input)?; - - let mut options = Vec::new(); - let mut rest = input; - - while let Ok((new_rest, option)) = decode_option(rest) { - rest = new_rest; - options.push(option); - if rest.starts_with(&[END]) { - break; - } - } - - let input = rest.split_at(1).1; // Skip the END tag byte - - Ok(( - input, - Packet { - reply, - hops, - secs, - broadcast: flags & 128 == 128, - ciaddr, - yiaddr, - siaddr, - giaddr, - options, - chaddr: [ - chaddr[0], chaddr[1], chaddr[2], chaddr[3], chaddr[4], chaddr[5], - ], - xid, - }, - )) -} - -impl Packet { - pub fn from(input: &[u8]) -> Result> { - Ok(decode(input)?.1) - } - - /// Extracts requested option payload from packet if available - pub fn option(&self, code: u8) -> Option<&DhcpOption> { - self.options.iter().find(|&option| option.code() == code) - } - - /// Convenience function for extracting a packet's message type. - pub fn message_type(&self) -> Result { - match self.option(DHCP_MESSAGE_TYPE) { - Some(DhcpOption::DhcpMessageType(msgtype)) => Ok(*msgtype), - Some(option) => Err(format![ - "Got wrong enum code {} for DHCP_MESSAGE_TYPE", - option.code() - ]), - None => Err("Packet does not have MessageType option".to_string()), - } - } - pub fn encode<'a>(&'a self, p: &'a mut [u8]) -> &[u8] { - let broadcast_flag = if self.broadcast { 128 } else { 0 }; - let mut length = 240; - - p[..12].copy_from_slice(&[ - if self.reply { BOOT_REPLY } else { BOOT_REQUEST }, - 1, - 6, - self.hops, - ((self.xid >> 24) & 0xFF) as u8, - ((self.xid >> 16) & 0xFF) as u8, - ((self.xid >> 8) & 0xFF) as u8, - (self.xid & 0xFF) as u8, - (self.secs >> 8) as u8, - (self.secs & 255) as u8, - broadcast_flag, - 0, - ]); - - p[12..16].copy_from_slice(&self.ciaddr.octets()); - p[16..20].copy_from_slice(&self.yiaddr.octets()); - p[20..24].copy_from_slice(&self.siaddr.octets()); - p[24..28].copy_from_slice(&self.giaddr.octets()); - p[28..34].copy_from_slice(&self.chaddr); - p[34..236].fill(0); - p[236..240].copy_from_slice(&COOKIE); - - for option in &self.options { - let option = option.to_raw(); - let option_len = option.data.len(); - if length + 2 + option_len >= 272 { - break; - } - if let Some(dest) = p.get_mut(length..length + 2 + option_len) { - dest[0] = option.code; - dest[1] = option_len as u8; - dest[2..].copy_from_slice(&option.data); - } - length += 2 + option_len; - } - - if let Some(end_segment) = p.get_mut(length..length + 1) { - end_segment[0] = END; - } - length += 1; - - if let Some(pad_segment) = p.get_mut(length..272) { - pad_segment.fill(PAD); - } - - &p[..length] - } -} - -const COOKIE: [u8; 4] = [99, 130, 83, 99]; - -const BOOT_REQUEST: u8 = 1; // From Client; -const BOOT_REPLY: u8 = 2; // From Server; - -const END: u8 = 255; -const PAD: u8 = 0; diff --git a/src/server.rs b/src/server.rs deleted file mode 100644 index c1d4802..0000000 --- a/src/server.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! This is a convenience module that simplifies the writing of a DHCP server service. - -use std::cell::Cell; -use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; - -use crate::options; -use crate::options::{DhcpOption, MessageType}; -use crate::packet::*; - -pub struct Server { - out_buf: Cell<[u8; 1500]>, - socket: UdpSocket, - src: SocketAddr, - server_ip: Ipv4Addr, - broadcast_ip: Ipv4Addr, -} - -pub trait Handler { - fn handle_request(&mut self, server: &Server, in_packet: Packet); -} - -pub fn filter_options_by_req(opts: &mut Vec, req_params: &[u8]) { - let mut pos = 0; - let h = &[ - options::DHCP_MESSAGE_TYPE, - options::SERVER_IDENTIFIER, - options::SUBNET_MASK, - options::IP_ADDRESS_LEASE_TIME, - options::DOMAIN_NAME_SERVER, - options::ROUTER, - ] as &[u8]; - - // Process options from req_params - for r in req_params.iter() { - let mut found = false; - for (i, o) in opts[pos..].iter().enumerate() { - if o.code() == *r { - found = true; - if pos + i != pos { - opts.swap(pos + i, pos); - } - pos += 1; - break; - } - } - if !found { - // Option not found, continue searching - } - } - - // Process options from h - for r in h.iter() { - let mut found = false; - for (i, o) in opts[pos..].iter().enumerate() { - if o.code() == *r { - found = true; - if pos + i != pos { - opts.swap(pos + i, pos); - } - pos += 1; - break; - } - } - if !found { - // Option not found, continue searching - } - } - - // Truncate the options list if necessary - opts.truncate(pos); -} - -impl Server { - pub fn serve( - udp_soc: UdpSocket, - server_ip: Ipv4Addr, - broadcast_ip: Ipv4Addr, - mut handler: H, - ) -> std::io::Error { - let mut in_buf: [u8; 1500] = [0; 1500]; - let mut s = Server { - out_buf: Cell::new([0; 1500]), - socket: udp_soc, - server_ip, - broadcast_ip, - src: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0), - }; - loop { - match s.socket.recv_from(&mut in_buf) { - Err(e) => return e, - Ok((l, src)) => { - if let Ok(p) = Packet::from(&in_buf[..l]) { - s.src = src; - - handler.handle_request(&s, p); - } - } - } - } - } - - /// Constructs and sends a reply packet back to the client. - /// additional_options should not include DHCP_MESSAGE_TYPE nor SERVER_IDENTIFIER as these - /// are added automatically. - pub fn reply( - &self, - msg_type: MessageType, - additional_options: Vec, - offer_ip: Ipv4Addr, - req_packet: Packet, - ) -> std::io::Result { - let ciaddr = match msg_type { - MessageType::Nak => Ipv4Addr::new(0, 0, 0, 0), - _ => req_packet.ciaddr, - }; - - //let mt = &[msg_type as u8]; - - let mut opts: Vec = Vec::with_capacity(additional_options.len() + 2); - opts.push(DhcpOption::DhcpMessageType(msg_type)); - opts.push(DhcpOption::ServerIdentifier(self.server_ip)); - /*opts.push(DhcpOption { - code: options::DHCP_MESSAGE_TYPE, - data: mt, - }); - opts.push(DhcpOption { - code: options::SERVER_IDENTIFIER, - data: &self.server_ip, - });*/ - opts.extend(additional_options); - - if let Some(DhcpOption::ParameterRequestList(prl)) = - req_packet.option(options::PARAMETER_REQUEST_LIST) - { - filter_options_by_req(&mut opts, prl); - } - - self.send(Packet { - reply: true, - hops: 0, - xid: req_packet.xid, - secs: 0, - broadcast: req_packet.broadcast, - ciaddr, - yiaddr: offer_ip, - siaddr: Ipv4Addr::new(0, 0, 0, 0), - giaddr: req_packet.giaddr, - chaddr: req_packet.chaddr, - options: opts, - }) - } - - /// Checks the packet see if it was intended for this DHCP server (as opposed to some other also on the network). - pub fn for_this_server(&self, packet: &Packet) -> bool { - match packet.option(options::SERVER_IDENTIFIER) { - Some(DhcpOption::ServerIdentifier(x)) => x == &self.server_ip, - _ => false, - } - } - - /// Encodes and sends a DHCP packet back to the client. - pub fn send(&self, p: Packet) -> std::io::Result { - let mut addr = self.src; - if p.broadcast || addr.ip() == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) { - addr.set_ip(std::net::IpAddr::V4(self.broadcast_ip)); - } - println!("Sending Response to: {:?}", addr); // Print the address - - self.socket.send_to(p.encode(&mut self.out_buf.get()), addr) - } -}