Blame SOURCES/1004-n-dhcp4-discard-NAKs-from-other-servers-rhbz2065188.patch

c029b9
From 49e9c3560289f5d02ad1bbf95ae3b2d8d81baa37 Mon Sep 17 00:00:00 2001
c029b9
From: Beniamino Galvani <bgalvani@redhat.com>
c029b9
Date: Thu, 10 Mar 2022 12:07:49 +0100
c029b9
Subject: [PATCH] n-dhcp4: discard NAKs from other servers in SELECTING
c029b9
c029b9
I got a report of a scenario where multiple servers reply to a REQUEST
c029b9
in SELECTING, and all servers send NAKs except the one which sent the
c029b9
offer, which replies with a ACK. In that scenario, n-dhcp4 is not able
c029b9
to obtain a lease because it restarts from INIT as soon as the first
c029b9
NAK is received. For comparison, dhclient can get a lease because it
c029b9
ignores all NAKs in SELECTING.
c029b9
c029b9
Arguably, the network is misconfigured there, but it would be great if
c029b9
n-dhcp4 could still work in such scenario.
c029b9
c029b9
According to RFC 2131, ACK and NAK messages from server must contain a
c029b9
server-id option. The RFC doesn't explicitly say that the client
c029b9
should check the option, but I think it's a reasonable thing to do, at
c029b9
least for NAKs.
c029b9
c029b9
This patch stores the server-id of the REQUEST in SELECTING, and
c029b9
compares it with the server-id from NAKs, to discard other servers'
c029b9
replies.
c029b9
c029b9
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1144
c029b9
---
c029b9
 src/n-dhcp4/src/n-dhcp4-c-connection.c | 19 +++++++++++++++++++
c029b9
 src/n-dhcp4/src/n-dhcp4-private.h      |  1 +
c029b9
 2 files changed, 20 insertions(+)
c029b9
c029b9
diff --git a/src/n-dhcp4/src/n-dhcp4-c-connection.c b/src/n-dhcp4/src/n-dhcp4-c-connection.c
c029b9
index 4aba97393d..2f660e3b30 100644
c029b9
--- a/src/n-dhcp4/src/n-dhcp4-c-connection.c
c029b9
+++ b/src/n-dhcp4/src/n-dhcp4-c-connection.c
c029b9
@@ -705,6 +705,7 @@ int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection,
c029b9
         message->userdata.start_time = offer->userdata.start_time;
c029b9
         message->userdata.base_time = offer->userdata.base_time;
c029b9
         message->userdata.client_addr = client.s_addr;
c029b9
+        message->userdata.server_id = server.s_addr;
c029b9
         n_dhcp4_incoming_get_xid(offer, &xid;;
c029b9
         n_dhcp4_outgoing_set_xid(message, xid);
c029b9
 
c029b9
@@ -1224,6 +1225,24 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
c029b9
                                       serv_addr, sizeof(serv_addr)));
c029b9
         }
c029b9
 
c029b9
+        if (type == N_DHCP4_MESSAGE_NAK &&
c029b9
+            connection->request->userdata.server_id != INADDR_ANY) {
c029b9
+                struct in_addr server;
c029b9
+
c029b9
+                r = n_dhcp4_incoming_query_server_identifier(message, &server);
c029b9
+                if (r)
c029b9
+                        return N_DHCP4_E_AGAIN;
c029b9
+
c029b9
+                if (connection->request->userdata.server_id != server.s_addr) {
c029b9
+                        n_dhcp4_log(connection->log_queue,
c029b9
+                                    LOG_DEBUG,
c029b9
+                                    "discarded NAK with wrong server-id %s",
c029b9
+                                    inet_ntop(AF_INET, &server,
c029b9
+                                              serv_addr, sizeof(serv_addr)));
c029b9
+                        return N_DHCP4_E_AGAIN;
c029b9
+                }
c029b9
+        }
c029b9
+
c029b9
         switch (type) {
c029b9
         case N_DHCP4_MESSAGE_OFFER:
c029b9
         case N_DHCP4_MESSAGE_ACK:
c029b9
diff --git a/src/n-dhcp4/src/n-dhcp4-private.h b/src/n-dhcp4/src/n-dhcp4-private.h
c029b9
index db7b24ff7d..191e946e70 100644
c029b9
--- a/src/n-dhcp4/src/n-dhcp4-private.h
c029b9
+++ b/src/n-dhcp4/src/n-dhcp4-private.h
c029b9
@@ -202,6 +202,7 @@ struct NDhcp4Outgoing {
c029b9
                 uint8_t type;
c029b9
                 uint8_t message_type;
c029b9
                 uint32_t client_addr;
c029b9
+                uint32_t server_id;
c029b9
                 uint64_t start_time;
c029b9
                 uint64_t base_time;
c029b9
                 uint64_t send_time;
c029b9
-- 
c029b9
2.35.1
c029b9