From a8b90daa8a343c4c08595458f11023e3b5d952cf Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 21 Dec 2021 15:28:04 +0100 Subject: [PATCH] Fix more problems with DHCP timers - Number of retries could overflow. If we retry something more than 255 times and it fails, just stop, instead of flooding the network with bogus requests - The timeout could also overflow. It was stored in microseconds in a time_t, which allows a bit more than an hour. This is fine for the initial timeout (which starts at a few seconds and will go up to 64 seconds), but after that we switch to a slower rate driven by the "state time". In particular, this can be the lease time, which DHCP servers may set to several days, or at least easily more than an hour. - The computaiton of the timeout in the "slow lease" case attempted to do "not less than a minute", but missed a conversion from microseconds to seconds so it ended up doing "not less than 60 microseconds" The combination of all these things means we can end up with a negative timeout, and we will send a burst of requests without ever stopping, flooding the network. Change-Id: I0eb811c90f4a4dd8c9d92bff728bc2bbb52fbd56 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4826 Tested-by: Commit checker robot Reviewed-by: Fredrik Holmqvist Reviewed-by: waddlesplash --- src/servers/net/DHCPClient.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/servers/net/DHCPClient.cpp b/src/servers/net/DHCPClient.cpp index f6ffb5eedf..0f046779ad 100644 --- a/src/servers/net/DHCPClient.cpp +++ b/src/servers/net/DHCPClient.cpp @@ -163,7 +163,7 @@ struct socket_timeout { UpdateSocket(socket); } - time_t timeout; // in micro secs + bigtime_t timeout; // in micro secs uint8 tries; bool Shift(int socket, bigtime_t stateMaxTime, const char* device); @@ -448,17 +448,22 @@ socket_timeout::UpdateSocket(int socket) const bool socket_timeout::Shift(int socket, bigtime_t stateMaxTime, const char* device) { + if (tries == UINT8_MAX) + return false; + tries++; - timeout += timeout; - if (timeout > AS_USECS(MAX_TIMEOUT)) - timeout = AS_USECS(MAX_TIMEOUT); if (tries > MAX_RETRIES) { - if (stateMaxTime == -1) + bigtime_t now = system_time(); + if (stateMaxTime == -1 || stateMaxTime < now) return false; - bigtime_t remaining = (stateMaxTime - system_time()) / 2 + 1; - timeout = std::max(remaining, bigtime_t(60)); - } + bigtime_t remaining = (stateMaxTime - now) / 2 + 1; + timeout = std::max(remaining, bigtime_t(AS_USECS(60))); + } else + timeout += timeout; + + if (timeout > AS_USECS(MAX_TIMEOUT)) + timeout = AS_USECS(MAX_TIMEOUT); syslog(LOG_DEBUG, "%s: Timeout shift: %" B_PRIdTIME " msecs (try %" B_PRIu8 ")\n", device, timeout / 1000, tries);