]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dhcp6: gracefully handle NoBinding error
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 12 Aug 2022 19:47:54 +0000 (04:47 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 12 Aug 2022 20:26:22 +0000 (05:26 +0900)
When we receive NoBinding status code, the requesting binding (address or
any other information) does not exist anymore in the server. Hence,
resending the request is meaningless. Let's restart the transaction from
the beginning in that case.

src/libsystemd-network/dhcp6-protocol.c
src/libsystemd-network/dhcp6-protocol.h
src/libsystemd-network/fuzz-dhcp6-client.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-dhcp6-lease.c

index c399a7ac50e2b1cb25b22230942541242ca1cbc3..f965ea40fea9c882ccc6f0c68f441d154ede7a23 100644 (file)
@@ -82,3 +82,14 @@ static const char * const dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status);
+
+int dhcp6_message_status_to_errno(DHCP6Status s) {
+        switch (s) {
+        case DHCP6_STATUS_SUCCESS:
+                return 0;
+        case DHCP6_STATUS_NO_BINDING:
+                return -EADDRNOTAVAIL;
+        default:
+                return -EINVAL;
+        }
+}
index f4e47857e3e97137254f421bc380ad6ddd40a7e7..18217691b7511afd8ccce48dd420bb1c4e42c89b 100644 (file)
@@ -154,3 +154,4 @@ const char *dhcp6_message_type_to_string(DHCP6MessageType s) _const_;
 DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_;
 const char *dhcp6_message_status_to_string(DHCP6Status s) _const_;
 DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_;
+int dhcp6_message_status_to_errno(DHCP6Status s);
index 3b53c5c6a80d98320ed9c12dca69879b75c5f4cd..a1c34365c0301dbcd80e038da770da091b5932ab 100644 (file)
@@ -48,7 +48,7 @@ static void fuzz_client(sd_dhcp6_client *client, const uint8_t *data, size_t siz
                         assert_se(IN_SET(client->state, DHCP6_STATE_REQUEST, DHCP6_STATE_BOUND));
                         break;
                 case DHCP6_STATE_REQUEST:
-                        assert_se(client->state == DHCP6_STATE_BOUND);
+                        assert_se(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_SOLICITATION));
                         break;
                 default:
                         assert_not_reached();
index 273dd35e0422174774aadf498b4413e9f07e81c7..0727050ed2d80aa827e110d161c2682ff22194a6 100644 (file)
@@ -543,13 +543,9 @@ static void client_notify(sd_dhcp6_client *client, int event) {
                 client->callback(client, event, client->userdata);
 }
 
-static void client_stop(sd_dhcp6_client *client, int error) {
-        DHCP6_CLIENT_DONT_DESTROY(client);
-
+static void client_cleanup(sd_dhcp6_client *client) {
         assert(client);
 
-        client_notify(client, error);
-
         client->lease = sd_dhcp6_lease_unref(client->lease);
 
         /* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode,
@@ -566,6 +562,16 @@ static void client_stop(sd_dhcp6_client *client, int error) {
         client_set_state(client, DHCP6_STATE_STOPPED);
 }
 
+static void client_stop(sd_dhcp6_client *client, int error) {
+        DHCP6_CLIENT_DONT_DESTROY(client);
+
+        assert(client);
+
+        client_notify(client, error);
+
+        client_cleanup(client);
+}
+
 static int client_append_common_options_in_managed_mode(
                 sd_dhcp6_client *client,
                 uint8_t **opt,
@@ -1133,6 +1139,20 @@ static int client_process_reply(
                 return log_invalid_message_type(client, message);
 
         r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
+        if (r == -EADDRNOTAVAIL) {
+
+                /* If NoBinding status code is received, we cannot request the address anymore.
+                 * Let's restart transaction from the beginning. */
+
+                if (client->state == DHCP6_STATE_REQUEST)
+                        /* The lease is not acquired yet, hence it is not necessary to notify the restart. */
+                        client_cleanup(client);
+                else
+                        /* We need to notify the previous lease was expired. */
+                        client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
+
+                return client_start_transaction(client, DHCP6_STATE_SOLICITATION);
+        }
         if (r < 0)
                 return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
 
index f588514cb646ba537e177ca47b6c423766e694c3..57c23965eda3ab3b73b0bfdf61856213fa879756 100644 (file)
@@ -512,7 +512,7 @@ static int dhcp6_lease_parse_message(
                                 return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
 
                         if (r > 0)
-                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+                                return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r),
                                                               "Received %s message with non-zero status: %s%s%s",
                                                               dhcp6_message_type_to_string(message->type),
                                                               strempty(msg), isempty(msg) ? "" : ": ",