Add suppor for DHCP maximum message size option.
parent
d7916c9a92
commit
39462d24f4
|
@ -294,6 +294,7 @@ impl Client {
|
|||
client_identifier: Some(mac),
|
||||
server_identifier: None,
|
||||
parameter_request_list: None,
|
||||
max_size: Some(raw_socket.payload_recv_capacity() as u16),
|
||||
dns_servers: None,
|
||||
};
|
||||
let mut send_packet = |iface, endpoint, dhcp_repr| {
|
||||
|
@ -305,7 +306,6 @@ impl Client {
|
|||
match self.state {
|
||||
ClientState::Discovering => {
|
||||
self.next_egress = now + Duration::from_secs(DISCOVER_TIMEOUT);
|
||||
|
||||
let endpoint = IpEndpoint {
|
||||
addr: Ipv4Address::BROADCAST.into(),
|
||||
port: UDP_SERVER_PORT,
|
||||
|
|
|
@ -52,6 +52,7 @@ pub enum DhcpOption<'a> {
|
|||
ServerIdentifier(Ipv4Address),
|
||||
Router(Ipv4Address),
|
||||
SubnetMask(Ipv4Address),
|
||||
MaximumDhcpMessageSize(u16),
|
||||
Other { kind: u8, data: &'a [u8] }
|
||||
}
|
||||
|
||||
|
@ -99,6 +100,9 @@ impl<'a> DhcpOption<'a> {
|
|||
(field::OPT_SUBNET_MASK, 4) => {
|
||||
option = DhcpOption::SubnetMask(Ipv4Address::from_bytes(data));
|
||||
}
|
||||
(field::OPT_MAX_DHCP_MESSAGE_SIZE, 2) => {
|
||||
option = DhcpOption::MaximumDhcpMessageSize(u16::from_be_bytes([data[0], data[1]]));
|
||||
}
|
||||
(_, _) => {
|
||||
option = DhcpOption::Other { kind: kind, data: data };
|
||||
}
|
||||
|
@ -122,6 +126,9 @@ impl<'a> DhcpOption<'a> {
|
|||
&DhcpOption::SubnetMask(ip) => {
|
||||
2 + ip.as_bytes().len()
|
||||
},
|
||||
&DhcpOption::MaximumDhcpMessageSize(_) => {
|
||||
4
|
||||
}
|
||||
&DhcpOption::Other { data, .. } => 2 + data.len()
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +174,10 @@ impl<'a> DhcpOption<'a> {
|
|||
buffer[0] = field::OPT_SUBNET_MASK;
|
||||
buffer[2..6].copy_from_slice(mask.as_bytes());
|
||||
}
|
||||
&DhcpOption::MaximumDhcpMessageSize(size) => {
|
||||
buffer[0] = field::OPT_MAX_DHCP_MESSAGE_SIZE;
|
||||
buffer[2..4].copy_from_slice(&size.to_be_bytes()[..]);
|
||||
}
|
||||
&DhcpOption::Other { kind, data: provided } => {
|
||||
buffer[0] = kind;
|
||||
buffer[2..skip_length].copy_from_slice(provided);
|
||||
|
@ -661,6 +672,8 @@ pub struct Repr<'a> {
|
|||
pub parameter_request_list: Option<&'a [u8]>,
|
||||
/// DNS servers
|
||||
pub dns_servers: Option<[Option<Ipv4Address>; 3]>,
|
||||
/// The maximum size dhcp packet the interface can receive
|
||||
pub max_size: Option<u16>,
|
||||
}
|
||||
|
||||
impl<'a> Repr<'a> {
|
||||
|
@ -672,6 +685,7 @@ impl<'a> Repr<'a> {
|
|||
if self.requested_ip.is_some() { len += 6; }
|
||||
if self.client_identifier.is_some() { len += 9; }
|
||||
if self.server_identifier.is_some() { len += 6; }
|
||||
if self.max_size.is_some() { len += 4; }
|
||||
if let Some(list) = self.parameter_request_list { len += list.len() + 2; }
|
||||
|
||||
len
|
||||
|
@ -710,6 +724,7 @@ impl<'a> Repr<'a> {
|
|||
let mut subnet_mask = None;
|
||||
let mut parameter_request_list = None;
|
||||
let mut dns_servers = None;
|
||||
let mut max_size = None;
|
||||
|
||||
let mut options = packet.options()?;
|
||||
while options.len() > 0 {
|
||||
|
@ -736,6 +751,9 @@ impl<'a> Repr<'a> {
|
|||
}
|
||||
DhcpOption::SubnetMask(mask) => {
|
||||
subnet_mask = Some(mask);
|
||||
},
|
||||
DhcpOption::MaximumDhcpMessageSize(size) => {
|
||||
max_size = Some(size);
|
||||
}
|
||||
DhcpOption::Other {kind: field::OPT_PARAMETER_REQUEST_LIST, data} => {
|
||||
parameter_request_list = Some(data);
|
||||
|
@ -760,7 +778,7 @@ impl<'a> Repr<'a> {
|
|||
Ok(Repr {
|
||||
transaction_id, client_hardware_address, client_ip, your_ip, server_ip, relay_agent_ip,
|
||||
broadcast, requested_ip, server_identifier, router,
|
||||
subnet_mask, client_identifier, parameter_request_list, dns_servers,
|
||||
subnet_mask, client_identifier, parameter_request_list, dns_servers, max_size,
|
||||
message_type: message_type?,
|
||||
})
|
||||
}
|
||||
|
@ -802,6 +820,9 @@ impl<'a> Repr<'a> {
|
|||
if let Some(ip) = self.requested_ip {
|
||||
let tmp = options; options = DhcpOption::RequestedIp(ip).emit(tmp);
|
||||
}
|
||||
if let Some(size) = self.max_size {
|
||||
let tmp = options; options = DhcpOption::MaximumDhcpMessageSize(size).emit(tmp);
|
||||
}
|
||||
if let Some(list) = self.parameter_request_list {
|
||||
let option = DhcpOption::Other{ kind: field::OPT_PARAMETER_REQUEST_LIST, data: list };
|
||||
let tmp = options; options = option.emit(tmp);
|
||||
|
@ -837,7 +858,7 @@ mod test {
|
|||
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, 0x63, 0x82, 0x53, 0x63,
|
||||
0x35, 0x01, 0x01, 0x3d, 0x07, 0x01, 0x00, 0x0b, 0x82, 0x01, 0xfc, 0x42, 0x32, 0x04, 0x00, 0x00,
|
||||
0x00, 0x00, 0x37, 0x04, 0x01, 0x03, 0x06, 0x2a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x39, 0x2, 0x5, 0xdc, 0x37, 0x04, 0x01, 0x03, 0x06, 0x2a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
static ACK_BYTES: &[u8] = &[
|
||||
|
@ -866,6 +887,7 @@ mod test {
|
|||
|
||||
const IP_NULL: Ipv4Address = Ipv4Address([0, 0, 0, 0]);
|
||||
const CLIENT_MAC: EthernetAddress = EthernetAddress([0x0, 0x0b, 0x82, 0x01, 0xfc, 0x42]);
|
||||
const DHCP_SIZE: u16 = 1500;
|
||||
|
||||
#[test]
|
||||
fn test_deconstruct_discover() {
|
||||
|
@ -883,18 +905,22 @@ mod test {
|
|||
assert_eq!(packet.relay_agent_ip(), IP_NULL);
|
||||
assert_eq!(packet.client_hardware_address(), CLIENT_MAC);
|
||||
let options = packet.options().unwrap();
|
||||
assert_eq!(options.len(), 3 + 9 + 6 + 6 + 1 + 7);
|
||||
assert_eq!(options.len(), 3 + 9 + 6 + 4 + 6 + 1 + 7);
|
||||
|
||||
let (options, message_type) = DhcpOption::parse(options).unwrap();
|
||||
assert_eq!(message_type, DhcpOption::MessageType(MessageType::Discover));
|
||||
assert_eq!(options.len(), 9 + 6 + 6 + 1 + 7);
|
||||
assert_eq!(options.len(), 9 + 6 + 4 + 6 + 1 + 7);
|
||||
|
||||
let (options, client_id) = DhcpOption::parse(options).unwrap();
|
||||
assert_eq!(client_id, DhcpOption::ClientIdentifier(CLIENT_MAC));
|
||||
assert_eq!(options.len(), 6 + 6 + 1 + 7);
|
||||
assert_eq!(options.len(), 6 + 4 + 6 + 1 + 7);
|
||||
|
||||
let (options, client_id) = DhcpOption::parse(options).unwrap();
|
||||
assert_eq!(client_id, DhcpOption::RequestedIp(IP_NULL));
|
||||
assert_eq!(options.len(), 4 + 6 + 1 + 7);
|
||||
|
||||
let (options, msg_size) = DhcpOption::parse(options).unwrap();
|
||||
assert_eq!(msg_size, DhcpOption::MaximumDhcpMessageSize(DHCP_SIZE));
|
||||
assert_eq!(options.len(), 6 + 1 + 7);
|
||||
|
||||
let (options, client_id) = DhcpOption::parse(options).unwrap();
|
||||
|
@ -910,7 +936,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_construct_discover() {
|
||||
let mut bytes = vec![0xa5; 272];
|
||||
let mut bytes = vec![0xa5; 276];
|
||||
let mut packet = Packet::new_unchecked(&mut bytes);
|
||||
packet.set_magic_number(MAGIC_COOKIE);
|
||||
packet.set_sname_and_boot_file_to_zero();
|
||||
|
@ -932,6 +958,7 @@ mod test {
|
|||
let tmp = options; options = DhcpOption::MessageType(MessageType::Discover).emit(tmp);
|
||||
let tmp = options; options = DhcpOption::ClientIdentifier(CLIENT_MAC).emit(tmp);
|
||||
let tmp = options; options = DhcpOption::RequestedIp(IP_NULL).emit(tmp);
|
||||
let tmp = options; options = DhcpOption::MaximumDhcpMessageSize(DHCP_SIZE).emit(tmp);
|
||||
let option = DhcpOption::Other {
|
||||
kind: field::OPT_PARAMETER_REQUEST_LIST, data: &[1, 3, 6, 42],
|
||||
};
|
||||
|
@ -940,7 +967,7 @@ mod test {
|
|||
}
|
||||
|
||||
let packet = &mut packet.into_inner()[..];
|
||||
for byte in &mut packet[265..272] {
|
||||
for byte in &mut packet[269..276] {
|
||||
*byte = 0; // padding bytes
|
||||
}
|
||||
|
||||
|
@ -959,6 +986,7 @@ mod test {
|
|||
subnet_mask: None,
|
||||
relay_agent_ip: IP_NULL,
|
||||
broadcast: false,
|
||||
max_size: Some(DHCP_SIZE),
|
||||
requested_ip: Some(IP_NULL),
|
||||
client_identifier: Some(CLIENT_MAC),
|
||||
server_identifier: None,
|
||||
|
|
Loading…
Reference in New Issue