From d0a7921cf63728da8eb664ebcf62930179a7a0db Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Wed, 23 Jun 2021 18:19:54 +0000 Subject: [PATCH 1/5] Emit dns servers in DHCPv4 repr. Fixes #504 --- src/wire/dhcpv4.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/wire/dhcpv4.rs b/src/wire/dhcpv4.rs index 32a6ef0..40fab86 100644 --- a/src/wire/dhcpv4.rs +++ b/src/wire/dhcpv4.rs @@ -700,6 +700,11 @@ impl<'a> Repr<'a> { if self.router.is_some() { len += 6; } if self.subnet_mask.is_some() { len += 6; } if self.lease_duration.is_some() { len += 6; } + if let Some(dns_servers) = self.dns_servers { + len += 2; + len += dns_servers.iter() + .filter(|d| d.is_some()).map(|_| 4).sum::(); + } if let Some(list) = self.parameter_request_list { len += list.len() + 2; } len @@ -842,6 +847,14 @@ impl<'a> Repr<'a> { if let Some(duration) = self.lease_duration { let tmp = options; options = DhcpOption::IpLeaseTime(duration).emit(tmp); } + if let Some(dns_servers) = self.dns_servers { + let data = dns_servers.iter().filter(|o| o.is_some()) + .map(|ip| ip.unwrap().as_bytes().to_owned()) + .flatten() + .collect::>(); + let option = DhcpOption::Other{ kind: field::OPT_DOMAIN_NAME_SERVER, data: &data[..] }; + let tmp = options; options = option.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); @@ -1088,6 +1101,29 @@ mod test { repr.emit(&mut packet).unwrap(); } + #[test] + fn test_emit_offer_dns() { + let repr = { + let mut repr = offer_repr(); + repr.dns_servers = Some([ + Some(Ipv4Address([163, 1, 74, 6])), + Some(Ipv4Address([163, 1, 74, 7])), + Some(Ipv4Address([163, 1, 74, 3]))]); + repr + }; + let mut bytes = vec![0xa5; repr.buffer_len()]; + let mut packet = Packet::new_unchecked(&mut bytes); + repr.emit(&mut packet).unwrap(); + + let packet = Packet::new_unchecked(&bytes); + let repr_parsed = Repr::parse(&packet).unwrap(); + + assert_eq!(repr_parsed.dns_servers, Some([ + Some(Ipv4Address([163, 1, 74, 6])), + Some(Ipv4Address([163, 1, 74, 7])), + Some(Ipv4Address([163, 1, 74, 3]))])); + } + #[test] fn test_emit_dhcp_option() { static DATA: &[u8] = &[1, 3, 6]; From c07cbfea0e3c3c47da59c171d0373bc4dda84aa6 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Wed, 23 Jun 2021 18:33:32 +0000 Subject: [PATCH 2/5] Get rid of vec --- src/wire/dhcpv4.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/wire/dhcpv4.rs b/src/wire/dhcpv4.rs index 40fab86..54b519e 100644 --- a/src/wire/dhcpv4.rs +++ b/src/wire/dhcpv4.rs @@ -8,6 +8,8 @@ use crate::wire::arp::Hardware; const DHCP_MAGIC_NUMBER: u32 = 0x63825363; +pub const MAX_DNS_SERVERS: usize = 3; + enum_with_unknown! { /// The possible opcodes of a DHCP packet. pub enum OpCode(u8) { @@ -680,7 +682,7 @@ pub struct Repr<'a> { /// the client is interested in. pub parameter_request_list: Option<&'a [u8]>, /// DNS servers - pub dns_servers: Option<[Option; 3]>, + pub dns_servers: Option<[Option; MAX_DNS_SERVERS]>, /// The maximum size dhcp packet the interface can receive pub max_size: Option, /// The DHCP IP lease duration, specified in seconds. @@ -782,7 +784,7 @@ impl<'a> Repr<'a> { parameter_request_list = Some(data); } DhcpOption::Other {kind: field::OPT_DOMAIN_NAME_SERVER, data} => { - let mut servers = [None; 3]; + let mut servers = [None; MAX_DNS_SERVERS]; for (server, chunk) in servers.iter_mut().zip(data.chunks(4)) { *server = Some(Ipv4Address::from_bytes(chunk)); } @@ -848,11 +850,17 @@ impl<'a> Repr<'a> { let tmp = options; options = DhcpOption::IpLeaseTime(duration).emit(tmp); } if let Some(dns_servers) = self.dns_servers { - let data = dns_servers.iter().filter(|o| o.is_some()) - .map(|ip| ip.unwrap().as_bytes().to_owned()) - .flatten() - .collect::>(); - let option = DhcpOption::Other{ kind: field::OPT_DOMAIN_NAME_SERVER, data: &data[..] }; + const IP_SIZE: usize = core::mem::size_of::(); + let mut servers = [0; MAX_DNS_SERVERS * IP_SIZE]; + + let data_len = dns_servers.iter().filter(|o| o.is_some()) + .enumerate() + .map(|(i, ip)| { + servers[(i * IP_SIZE)..((i + 1) * IP_SIZE)] + .copy_from_slice(ip.unwrap().as_bytes()); + i + 1 + }).last().unwrap_or(0); + let option = DhcpOption::Other{ kind: field::OPT_DOMAIN_NAME_SERVER, data: &servers[..IP_SIZE * data_len] }; let tmp = options; options = option.emit(tmp); } if let Some(list) = self.parameter_request_list { From 5211338f574620eec94c5c3b368cf954d3d608fa Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Wed, 23 Jun 2021 19:33:36 +0000 Subject: [PATCH 3/5] remove unwrap --- src/wire/dhcpv4.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/wire/dhcpv4.rs b/src/wire/dhcpv4.rs index 54b519e..cc701b8 100644 --- a/src/wire/dhcpv4.rs +++ b/src/wire/dhcpv4.rs @@ -704,8 +704,7 @@ impl<'a> Repr<'a> { if self.lease_duration.is_some() { len += 6; } if let Some(dns_servers) = self.dns_servers { len += 2; - len += dns_servers.iter() - .filter(|d| d.is_some()).map(|_| 4).sum::(); + len += dns_servers.iter().flatten().count() * core::mem::size_of::(); } if let Some(list) = self.parameter_request_list { len += list.len() + 2; } @@ -853,14 +852,14 @@ impl<'a> Repr<'a> { const IP_SIZE: usize = core::mem::size_of::(); let mut servers = [0; MAX_DNS_SERVERS * IP_SIZE]; - let data_len = dns_servers.iter().filter(|o| o.is_some()) + let data_len = dns_servers.iter().flatten() .enumerate() .map(|(i, ip)| { servers[(i * IP_SIZE)..((i + 1) * IP_SIZE)] - .copy_from_slice(ip.unwrap().as_bytes()); - i + 1 - }).last().unwrap_or(0); - let option = DhcpOption::Other{ kind: field::OPT_DOMAIN_NAME_SERVER, data: &servers[..IP_SIZE * data_len] }; + .copy_from_slice(ip.as_bytes()); + () + }).count() * IP_SIZE; + let option = DhcpOption::Other{ kind: field::OPT_DOMAIN_NAME_SERVER, data: &servers[..data_len] }; let tmp = options; options = option.emit(tmp); } if let Some(list) = self.parameter_request_list { From 4c05c3a9b924a5e7411baf8fb7d695918f7fb3c5 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Wed, 23 Jun 2021 19:35:48 +0000 Subject: [PATCH 4/5] Make clippy happy --- src/wire/dhcpv4.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wire/dhcpv4.rs b/src/wire/dhcpv4.rs index cc701b8..781aa43 100644 --- a/src/wire/dhcpv4.rs +++ b/src/wire/dhcpv4.rs @@ -857,7 +857,6 @@ impl<'a> Repr<'a> { .map(|(i, ip)| { servers[(i * IP_SIZE)..((i + 1) * IP_SIZE)] .copy_from_slice(ip.as_bytes()); - () }).count() * IP_SIZE; let option = DhcpOption::Other{ kind: field::OPT_DOMAIN_NAME_SERVER, data: &servers[..data_len] }; let tmp = options; options = option.emit(tmp); From 0974b3c6be33db2ae646d167a26dc74c814d2a69 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Thu, 24 Jun 2021 18:18:26 +0000 Subject: [PATCH 5/5] map -> inspect --- src/wire/dhcpv4.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wire/dhcpv4.rs b/src/wire/dhcpv4.rs index 781aa43..af45be4 100644 --- a/src/wire/dhcpv4.rs +++ b/src/wire/dhcpv4.rs @@ -854,7 +854,7 @@ impl<'a> Repr<'a> { let data_len = dns_servers.iter().flatten() .enumerate() - .map(|(i, ip)| { + .inspect(|(i, ip)| { servers[(i * IP_SIZE)..((i + 1) * IP_SIZE)] .copy_from_slice(ip.as_bytes()); }).count() * IP_SIZE;