Skip to content

Enable support for DHCP option 15 (domain name) #972

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ defmt = ["dep:defmt", "heapless/defmt-03"]
"proto-sixlowpan" = ["proto-ipv6"]
"proto-sixlowpan-fragmentation" = ["proto-sixlowpan", "_proto-fragmentation"]
"proto-dns" = []
"proto-domainname" = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature's name could be confusing as "domainname protocol" sounds a lot like DNS. I suggest proto-dhcpv4-domainname.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion!

"proto-ipsec" = ["proto-ipsec-ah", "proto-ipsec-esp"]
"proto-ipsec-ah" = []
"proto-ipsec-esp" = []
Expand Down Expand Up @@ -96,7 +97,7 @@ default = [
"std", "log", # needed for `cargo test --no-default-features --features default` :/
"medium-ethernet", "medium-ip", "medium-ieee802154",
"phy-raw_socket", "phy-tuntap_interface",
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-dns",
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-dns", "proto-domainname",
"proto-ipv4-fragmentation", "proto-sixlowpan-fragmentation",
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dhcpv4", "socket-dns", "socket-mdns",
"packetmeta-id", "async"
Expand Down Expand Up @@ -249,6 +250,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 = []
Expand Down
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions gen_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
35 changes: 30 additions & 5 deletions src/socket/dhcpv4.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use core::str::FromStr;
#[cfg(feature = "async")]
use core::task::Waker;

#[cfg(feature = "proto-domainname")]
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;
Expand All @@ -9,7 +12,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;
Expand All @@ -22,6 +25,8 @@ const DEFAULT_PARAMETER_REQUEST_LIST: &[u8] = &[
dhcpv4_field::OPT_SUBNET_MASK,
dhcpv4_field::OPT_ROUTER,
dhcpv4_field::OPT_DOMAIN_NAME_SERVER,
#[cfg(feature = "proto-domainname")]
dhcpv4_field::OPT_DOMAIN_NAME,
];

/// IPv4 configuration data provided by the DHCP server.
Expand All @@ -38,6 +43,9 @@ pub struct Config<'a> {
pub router: Option<Ipv4Address>,
/// DNS servers
pub dns_servers: Vec<Ipv4Address, DHCP_MAX_DNS_SERVER_COUNT>,
/// Domain name
#[cfg(feature = "proto-domainname")]
pub domain_name: Option<String<DHCP_MAX_DOMAIN_NAME_SIZE>>,
/// Received DHCP packet
pub packet: Option<DhcpPacket<&'a [u8]>>,
}
Expand Down Expand Up @@ -494,6 +502,11 @@ impl<'a> Socket<'a> {
address: Ipv4Cidr::new(dhcp_repr.your_ip, prefix_len),
router: dhcp_repr.router,
dns_servers,
#[cfg(feature = "proto-domainname")]
domain_name: dhcp_repr
.domain_name
.map(String::from_str)
.and_then(Result::ok),
packet: None,
};

Expand Down Expand Up @@ -589,6 +602,8 @@ impl<'a> Socket<'a> {
renew_duration: None,
rebind_duration: None,
dns_servers: None,
#[cfg(feature = "proto-domainname")]
domain_name: None,
additional_options: self.outgoing_options,
};

Expand Down Expand Up @@ -739,6 +754,8 @@ impl<'a> Socket<'a> {
address: state.config.address,
router: state.config.router,
dns_servers: state.config.dns_servers.clone(),
#[cfg(feature = "proto-domainname")]
domain_name: state.config.domain_name.clone(),
packet: self
.receive_packet_buffer
.as_deref()
Expand Down Expand Up @@ -779,6 +796,7 @@ impl<'a> Socket<'a> {
#[cfg(test)]
mod test {

use core::str::FromStr;
use std::ops::{Deref, DerefMut};

use super::*;
Expand Down Expand Up @@ -886,6 +904,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]);

Expand Down Expand Up @@ -969,6 +988,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,
Expand All @@ -979,7 +999,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
};
Expand All @@ -994,6 +1014,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
Expand All @@ -1007,7 +1028,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
};

Expand All @@ -1021,6 +1042,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
Expand All @@ -1042,7 +1064,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
};

Expand All @@ -1054,7 +1076,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
};

Expand Down Expand Up @@ -1097,6 +1119,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,
},
Expand Down Expand Up @@ -1132,6 +1155,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,
}))
Expand Down Expand Up @@ -1170,6 +1194,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,
}))
Expand Down
28 changes: 28 additions & 0 deletions src/wire/dhcpv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,9 @@ pub struct Repr<'a> {
pub parameter_request_list: Option<&'a [u8]>,
/// DNS servers
pub dns_servers: Option<Vec<Ipv4Address, MAX_DNS_SERVER_COUNT>>,
/// Domain name
#[cfg(feature = "proto-domainname")]
pub domain_name: Option<&'a str>,
/// The maximum size dhcp packet the interface can receive
pub max_size: Option<u16>,
/// The DHCP IP lease duration, specified in seconds.
Expand Down Expand Up @@ -692,6 +695,11 @@ impl<'a> Repr<'a> {
len += 2;
len += dns_servers.iter().count() * core::mem::size_of::<u32>();
}
#[cfg(feature = "proto-domainname")]
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;
}
Expand Down Expand Up @@ -738,6 +746,8 @@ impl<'a> Repr<'a> {
let mut subnet_mask = None;
let mut parameter_request_list = None;
let mut dns_servers = None;
#[cfg(feature = "proto-domainname")]
let mut domain_name = None;
let mut max_size = None;
let mut lease_duration = None;
let mut renew_duration = None;
Expand Down Expand Up @@ -802,6 +812,10 @@ impl<'a> Repr<'a> {
net_trace!("DHCP domain name servers contained invalid address");
}
}
#[cfg(feature = "proto-domainname")]
(field::OPT_DOMAIN_NAME, _) => {
domain_name = core::str::from_utf8(data).ok();
}
_ => {}
}
}
Expand All @@ -824,6 +838,8 @@ impl<'a> Repr<'a> {
client_identifier,
parameter_request_list,
dns_servers,
#[cfg(feature = "proto-domainname")]
domain_name,
max_size,
lease_duration,
renew_duration,
Expand Down Expand Up @@ -940,6 +956,14 @@ impl<'a> Repr<'a> {
})?;
}

#[cfg(feature = "proto-domainname")]
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)?;
}
Expand Down Expand Up @@ -1167,6 +1191,8 @@ mod test {
server_identifier: None,
parameter_request_list: None,
dns_servers: None,
#[cfg(feature = "proto-domainname")]
domain_name: None,
max_size: None,
renew_duration: None,
rebind_duration: None,
Expand Down Expand Up @@ -1197,6 +1223,8 @@ mod test {
server_identifier: None,
parameter_request_list: Some(&[1, 3, 6, 42]),
dns_servers: None,
#[cfg(feature = "proto-domainname")]
domain_name: None,
additional_options: &[],
}
}
Expand Down
Loading