summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-05-23 11:28:51 +0200
committerThomas Haller <thaller@redhat.com>2022-05-31 18:32:35 +0200
commit65cfece4c5c7f2605c353c70f0973a84af4242f2 (patch)
tree62ca593d5d638491adea643d75e0beaa6ba310e9
parentf40bbb819f41e536d3af726fadc8c6b705bf7f62 (diff)
downloadNetworkManager-65cfece4c5c7f2605c353c70f0973a84af4242f2.tar.gz
n-dhcp4: fix internal state after declining lease
Previously, during decline we would clear probe->current_lease, however leave the state at GRANTED. That is a wrong state, and can easily lead to a crash later. For example, on the next timeout we will end up at n_dhcp4_client_dispatch_timer(), then current-lease gets accessed unconditionally: case N_DHCP4_CLIENT_PROBE_STATE_GRANTED: if (ns_now >= probe->current_lease->lifetime) { Instead, return to INIT state and schedule a timer. As suggested by RFC 2131, section 3.1, 5) ([1]). [1] https://datatracker.ietf.org/doc/html/rfc2131#section-3.1
-rw-r--r--src/n-dhcp4/src/n-dhcp4-c-probe.c15
-rw-r--r--src/n-dhcp4/src/n-dhcp4-private.h1
2 files changed, 14 insertions, 2 deletions
diff --git a/src/n-dhcp4/src/n-dhcp4-c-probe.c b/src/n-dhcp4/src/n-dhcp4-c-probe.c
index dcd51c6f3e..284aa428e9 100644
--- a/src/n-dhcp4/src/n-dhcp4-c-probe.c
+++ b/src/n-dhcp4/src/n-dhcp4-c-probe.c
@@ -1089,6 +1089,7 @@ int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incom
return r;
probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
+ probe->ns_decline_restart_delay = 0;
n_dhcp4_client_lease_unlink(probe->current_lease);
n_dhcp4_client_arm_timer(probe->client);
@@ -1128,11 +1129,21 @@ int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Inco
else
request = NULL; /* consumed */
- /* XXX: what state to transition to? */
-
n_dhcp4_client_lease_unlink(probe->current_lease);
probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease);
+ probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
+
+ /* RFC2131, 3.1, 5.) The client SHOULD wait a minimum of ten seconds before restarting
+ * the configuration process to avoid excessive network traffic in case of looping.
+ *
+ * Let's go beyond that, and use an exponential backoff. */
+ probe->ns_decline_restart_delay = C_CLAMP(probe->ns_decline_restart_delay * 2u,
+ UINT64_C(10) * UINT64_C(1000000000),
+ UINT64_C(300) * UINT64_C(1000000000));
+ probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + probe->ns_decline_restart_delay;
+
+ n_dhcp4_client_arm_timer(probe->client);
return 0;
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
diff --git a/src/n-dhcp4/src/n-dhcp4-private.h b/src/n-dhcp4/src/n-dhcp4-private.h
index 858c3d3ab0..6b366884be 100644
--- a/src/n-dhcp4/src/n-dhcp4-private.h
+++ b/src/n-dhcp4/src/n-dhcp4-private.h
@@ -378,6 +378,7 @@ struct NDhcp4ClientProbe {
uint64_t ns_deferred; /* timeout for deferred action */
uint64_t ns_reinit;
uint64_t ns_nak_restart_delay; /* restart delay after a nak */
+ uint64_t ns_decline_restart_delay; /* restart delay after a decline */
NDhcp4ClientLease *current_lease; /* current lease */
NDhcp4CConnection connection; /* client connection wrapper */