dhcp: add "ignore NAKs" option.

This workarounds a known broken Vodafone Fiber router which replies
with both NAK and ACK:

![screenshot-2021-10-19_01-18-41](https://user-images.githubusercontent.com/1247578/137819133-a8f9ab28-8bc5-4cca-9c91-2eac15d88070.png)
master
Dario Nieuwenhuis 2021-10-19 01:17:28 +02:00
parent bcf6211fbe
commit 48debf7db8
1 changed files with 37 additions and 2 deletions

View File

@ -122,6 +122,9 @@ pub struct Dhcpv4Socket {
/// Max lease duration. If set, it sets a maximum cap to the server-provided lease duration.
/// Useful to react faster to IP configuration changes and to test whether renews work correctly.
max_lease_duration: Option<Duration>,
/// Ignore NAKs.
ignore_naks: bool,
}
/// DHCP client socket.
@ -141,17 +144,45 @@ impl Dhcpv4Socket {
config_changed: true,
transaction_id: 1,
max_lease_duration: None,
ignore_naks: false,
}
}
/// Get the configured max lease duration.
///
/// See also [`Self::set_max_lease_duration()`]
pub fn max_lease_duration(&self) -> Option<Duration> {
self.max_lease_duration
}
/// Set the max lease duration.
///
/// When set, the lease duration will be capped at the configured duration if the
/// DHCP server gives us a longer lease. This is generally not recommended, but
/// can be useful for debugging or reacting faster to network configuration changes.
///
/// If None, no max is applied (the lease duration from the DHCP server is used.)
pub fn set_max_lease_duration(&mut self, max_lease_duration: Option<Duration>) {
self.max_lease_duration = max_lease_duration;
}
/// Get whether to ignore NAKs.
///
/// See also [`Self::set_ignore_naks()`]
pub fn ignore_naks(&self) -> bool {
self.ignore_naks
}
/// Set whether to ignore NAKs.
///
/// This is not compliant with the DHCP RFCs, since theoretically
/// we must stop using the assigned IP when receiving a NAK. This
/// can increase reliability on broken networks with buggy routers
/// or rogue DHCP servers, however.
pub fn set_ignore_naks(&mut self, ignore_naks: bool) {
self.ignore_naks = ignore_naks;
}
pub(crate) fn poll_at(&self, _cx: &Context) -> PollAt {
let t = match &self.state {
ClientState::Discovering(state) => state.retry_at,
@ -242,7 +273,9 @@ impl Dhcpv4Socket {
}
}
(ClientState::Requesting(_), DhcpMessageType::Nak) => {
self.reset();
if !self.ignore_naks {
self.reset();
}
}
(ClientState::Renewing(state), DhcpMessageType::Ack) => {
if let Some((config, renew_at, expires_at)) =
@ -257,7 +290,9 @@ impl Dhcpv4Socket {
}
}
(ClientState::Renewing(_), DhcpMessageType::Nak) => {
self.reset();
if !self.ignore_naks {
self.reset();
}
}
_ => {
net_debug!(