diff --git a/Cargo.toml b/Cargo.toml index 2f3e266bd..b6868342f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -249,6 +249,11 @@ dns-max-name-size-64 = [] dns-max-name-size-128 = [] dns-max-name-size-255 = [] # Default +dhcp-max-domain-name-size-32 = [] +dhcp-max-domain-name-size-64 = [] # Default +dhcp-max-domain-name-size-128 = [] +dhcp-max-domain-name-size-256 = [] + rpl-relations-buffer-count-1 = [] rpl-relations-buffer-count-2 = [] rpl-relations-buffer-count-4 = [] diff --git a/build.rs b/build.rs index e1746d23f..69098aee5 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,7 @@ static CONFIGS: &[(&str, usize)] = &[ ("DNS_MAX_RESULT_COUNT", 1), ("DNS_MAX_SERVER_COUNT", 1), ("DNS_MAX_NAME_SIZE", 255), + ("DHCP_MAX_DOMAIN_NAME_SIZE", 64), ("RPL_RELATIONS_BUFFER_COUNT", 16), ("RPL_PARENTS_BUFFER_COUNT", 8), // END AUTOGENERATED CONFIG FEATURES diff --git a/gen_config.py b/gen_config.py index 1407ca2d6..9792ee9fd 100644 --- a/gen_config.py +++ b/gen_config.py @@ -40,6 +40,7 @@ def feature(name, default, min, max, pow2=None): feature("dns_max_result_count", default=1, min=1, max=32, pow2=4) feature("dns_max_server_count", default=1, min=1, max=32, pow2=4) feature("dns_max_name_size", default=255, min=64, max=255, pow2=True) +feature("dhcp_max_domain_name_size", default=64, min=32, max=256, pow2=True) feature("rpl_relations_buffer_count", default=16, min=1, max=128, pow2=True) feature("rpl_parents_buffer_count", default=8, min=2, max=32, pow2=True) diff --git a/src/lib.rs b/src/lib.rs index 2e99c9576..a6a10edc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,6 +136,7 @@ pub mod config { pub const DNS_MAX_NAME_SIZE: usize = 255; pub const DNS_MAX_RESULT_COUNT: usize = 1; pub const DNS_MAX_SERVER_COUNT: usize = 1; + pub const DHCP_MAX_DOMAIN_NAME_SIZE: usize = 64; pub const FRAGMENTATION_BUFFER_SIZE: usize = 1500; pub const IFACE_MAX_ADDR_COUNT: usize = 8; pub const IFACE_MAX_MULTICAST_GROUP_COUNT: usize = 4; diff --git a/src/socket/dhcpv4.rs b/src/socket/dhcpv4.rs index b1b3cb583..fda4c5783 100644 --- a/src/socket/dhcpv4.rs +++ b/src/socket/dhcpv4.rs @@ -1,6 +1,8 @@ +use core::str::FromStr; #[cfg(feature = "async")] use core::task::Waker; +use crate::config::DHCP_MAX_DOMAIN_NAME_SIZE; use crate::iface::Context; use crate::time::{Duration, Instant}; use crate::wire::dhcpv4::field as dhcpv4_field; @@ -9,7 +11,7 @@ use crate::wire::{ UdpRepr, DHCP_CLIENT_PORT, DHCP_MAX_DNS_SERVER_COUNT, DHCP_SERVER_PORT, UDP_HEADER_LEN, }; use crate::wire::{DhcpOption, HardwareAddress}; -use heapless::Vec; +use heapless::{String, Vec}; #[cfg(feature = "async")] use super::WakerRegistration; @@ -22,6 +24,7 @@ const DEFAULT_PARAMETER_REQUEST_LIST: &[u8] = &[ dhcpv4_field::OPT_SUBNET_MASK, dhcpv4_field::OPT_ROUTER, dhcpv4_field::OPT_DOMAIN_NAME_SERVER, + dhcpv4_field::OPT_DOMAIN_NAME, ]; /// IPv4 configuration data provided by the DHCP server. @@ -38,6 +41,8 @@ pub struct Config<'a> { pub router: Option, /// DNS servers pub dns_servers: Vec, + /// Domain name + pub domain_name: Option>, /// Received DHCP packet pub packet: Option>, } @@ -494,6 +499,10 @@ impl<'a> Socket<'a> { address: Ipv4Cidr::new(dhcp_repr.your_ip, prefix_len), router: dhcp_repr.router, dns_servers, + domain_name: dhcp_repr + .domain_name + .map(String::from_str) + .and_then(Result::ok), packet: None, }; @@ -589,6 +598,7 @@ impl<'a> Socket<'a> { renew_duration: None, rebind_duration: None, dns_servers: None, + domain_name: None, additional_options: self.outgoing_options, }; @@ -739,6 +749,7 @@ impl<'a> Socket<'a> { address: state.config.address, router: state.config.router, dns_servers: state.config.dns_servers.clone(), + domain_name: state.config.domain_name.clone(), packet: self .receive_packet_buffer .as_deref() @@ -779,6 +790,7 @@ impl<'a> Socket<'a> { #[cfg(test)] mod test { + use core::str::FromStr; use std::ops::{Deref, DerefMut}; use super::*; @@ -886,6 +898,7 @@ mod test { const DNS_IP_2: Ipv4Address = Ipv4Address([1, 1, 1, 2]); const DNS_IP_3: Ipv4Address = Ipv4Address([1, 1, 1, 3]); const DNS_IPS: &[Ipv4Address] = &[DNS_IP_1, DNS_IP_2, DNS_IP_3]; + const DOMAIN_NAME: &str = "my.domain"; const MASK_24: Ipv4Address = Ipv4Address([255, 255, 255, 0]); @@ -969,6 +982,7 @@ mod test { server_identifier: None, parameter_request_list: None, dns_servers: None, + domain_name: None, max_size: None, renew_duration: None, rebind_duration: None, @@ -979,7 +993,7 @@ mod test { const DHCP_DISCOVER: DhcpRepr = DhcpRepr { message_type: DhcpMessageType::Discover, client_identifier: Some(MY_MAC), - parameter_request_list: Some(&[1, 3, 6]), + parameter_request_list: Some(&[1, 3, 6, 15]), max_size: Some(1432), ..DHCP_DEFAULT }; @@ -994,6 +1008,7 @@ mod test { router: Some(SERVER_IP), subnet_mask: Some(MASK_24), dns_servers: Some(Vec::from_slice(DNS_IPS).unwrap()), + domain_name: Some(DOMAIN_NAME), lease_duration: Some(1000), ..DHCP_DEFAULT @@ -1007,7 +1022,7 @@ mod test { max_size: Some(1432), requested_ip: Some(MY_IP), - parameter_request_list: Some(&[1, 3, 6]), + parameter_request_list: Some(&[1, 3, 6, 15]), ..DHCP_DEFAULT }; @@ -1021,6 +1036,7 @@ mod test { router: Some(SERVER_IP), subnet_mask: Some(MASK_24), dns_servers: Some(Vec::from_slice(DNS_IPS).unwrap()), + domain_name: Some(DOMAIN_NAME), lease_duration: Some(1000), ..DHCP_DEFAULT @@ -1042,7 +1058,7 @@ mod test { max_size: Some(1432), requested_ip: None, - parameter_request_list: Some(&[1, 3, 6]), + parameter_request_list: Some(&[1, 3, 6, 15]), ..DHCP_DEFAULT }; @@ -1054,7 +1070,7 @@ mod test { max_size: Some(1432), requested_ip: None, - parameter_request_list: Some(&[1, 3, 6]), + parameter_request_list: Some(&[1, 3, 6, 15]), ..DHCP_DEFAULT }; @@ -1097,6 +1113,7 @@ mod test { }, address: Ipv4Cidr::new(MY_IP, 24), dns_servers: Vec::from_slice(DNS_IPS).unwrap(), + domain_name: Some(String::from_str(DOMAIN_NAME).unwrap()), router: Some(SERVER_IP), packet: None, }, @@ -1132,6 +1149,7 @@ mod test { }, address: Ipv4Cidr::new(MY_IP, 24), dns_servers: Vec::from_slice(DNS_IPS).unwrap(), + domain_name: Some(String::from_str(DOMAIN_NAME).unwrap()), router: Some(SERVER_IP), packet: None, })) @@ -1170,6 +1188,7 @@ mod test { }, address: Ipv4Cidr::new(MY_IP, 24), dns_servers: Vec::from_slice(DNS_IPS).unwrap(), + domain_name: Some(String::from_str(DOMAIN_NAME).unwrap()), router: Some(SERVER_IP), packet: None, })) diff --git a/src/wire/dhcpv4.rs b/src/wire/dhcpv4.rs index b00f26ff7..8ac5a8d3a 100644 --- a/src/wire/dhcpv4.rs +++ b/src/wire/dhcpv4.rs @@ -12,6 +12,7 @@ use crate::wire::{EthernetAddress, Ipv4Address}; pub const SERVER_PORT: u16 = 67; pub const CLIENT_PORT: u16 = 68; pub const MAX_DNS_SERVER_COUNT: usize = 3; +pub const MAX_DOMAIN_NAME_LEN: usize = 255; const DHCP_MAGIC_NUMBER: u32 = 0x63825363; @@ -647,6 +648,8 @@ pub struct Repr<'a> { pub parameter_request_list: Option<&'a [u8]>, /// DNS servers pub dns_servers: Option>, + /// Domain name + pub domain_name: Option<&'a str>, /// The maximum size dhcp packet the interface can receive pub max_size: Option, /// The DHCP IP lease duration, specified in seconds. @@ -692,6 +695,10 @@ impl<'a> Repr<'a> { len += 2; len += dns_servers.iter().count() * core::mem::size_of::(); } + if let Some(domain_name) = &self.domain_name { + len += 2; + len += domain_name.as_bytes().len(); + } if let Some(list) = self.parameter_request_list { len += list.len() + 2; } @@ -738,6 +745,7 @@ impl<'a> Repr<'a> { let mut subnet_mask = None; let mut parameter_request_list = None; let mut dns_servers = None; + let mut domain_name = None; let mut max_size = None; let mut lease_duration = None; let mut renew_duration = None; @@ -802,6 +810,11 @@ impl<'a> Repr<'a> { net_trace!("DHCP domain name servers contained invalid address"); } } + (field::OPT_DOMAIN_NAME, _) => { + if let Ok(name) = core::str::from_utf8(data) { + domain_name = Some(name); + } + } _ => {} } } @@ -824,6 +837,7 @@ impl<'a> Repr<'a> { client_identifier, parameter_request_list, dns_servers, + domain_name, max_size, lease_duration, renew_duration, @@ -940,6 +954,13 @@ impl<'a> Repr<'a> { })?; } + if let Some(domain_name) = &self.domain_name { + options.emit(DhcpOption { + kind: field::OPT_DOMAIN_NAME, + data: domain_name.as_bytes(), + })?; + } + for option in self.additional_options { options.emit(*option)?; } @@ -1167,6 +1188,7 @@ mod test { server_identifier: None, parameter_request_list: None, dns_servers: None, + domain_name: None, max_size: None, renew_duration: None, rebind_duration: None, @@ -1197,6 +1219,7 @@ mod test { server_identifier: None, parameter_request_list: Some(&[1, 3, 6, 42]), dns_servers: None, + domain_name: None, additional_options: &[], } } diff --git a/src/wire/mod.rs b/src/wire/mod.rs index c197afed9..d78220a50 100644 --- a/src/wire/mod.rs +++ b/src/wire/mod.rs @@ -272,7 +272,8 @@ pub use self::tcp::{ pub use self::dhcpv4::{ DhcpOption, DhcpOptionWriter, Flags as DhcpFlags, MessageType as DhcpMessageType, OpCode as DhcpOpCode, Packet as DhcpPacket, Repr as DhcpRepr, CLIENT_PORT as DHCP_CLIENT_PORT, - MAX_DNS_SERVER_COUNT as DHCP_MAX_DNS_SERVER_COUNT, SERVER_PORT as DHCP_SERVER_PORT, + MAX_DNS_SERVER_COUNT as DHCP_MAX_DNS_SERVER_COUNT, + MAX_DOMAIN_NAME_LEN as DHCP_MAX_DOMAIN_NAME_LEN, SERVER_PORT as DHCP_SERVER_PORT, }; #[cfg(feature = "proto-dns")]