summaryrefslogtreecommitdiff
path: root/src/libsystemd-network
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-08-13 04:47:54 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-08-13 05:26:22 +0900
commit1929c1fcb2f305206c01a6fc79cd038d6d9615f5 (patch)
treefb57455266aeef7a4518facaac1aa50d26c0c3d4 /src/libsystemd-network
parent38db7a4ed388b032faae221067b77d553a54e6a6 (diff)
downloadsystemd-1929c1fcb2f305206c01a6fc79cd038d6d9615f5.tar.gz
dhcp6: gracefully handle NoBinding error
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.
Diffstat (limited to 'src/libsystemd-network')
-rw-r--r--src/libsystemd-network/dhcp6-protocol.c11
-rw-r--r--src/libsystemd-network/dhcp6-protocol.h1
-rw-r--r--src/libsystemd-network/fuzz-dhcp6-client.c2
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c30
-rw-r--r--src/libsystemd-network/sd-dhcp6-lease.c2
5 files changed, 39 insertions, 7 deletions
diff --git a/src/libsystemd-network/dhcp6-protocol.c b/src/libsystemd-network/dhcp6-protocol.c
index c399a7ac50..f965ea40fe 100644
--- a/src/libsystemd-network/dhcp6-protocol.c
+++ b/src/libsystemd-network/dhcp6-protocol.c
@@ -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;
+ }
+}
diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
index f4e47857e3..18217691b7 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -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);
diff --git a/src/libsystemd-network/fuzz-dhcp6-client.c b/src/libsystemd-network/fuzz-dhcp6-client.c
index 3b53c5c6a8..a1c34365c0 100644
--- a/src/libsystemd-network/fuzz-dhcp6-client.c
+++ b/src/libsystemd-network/fuzz-dhcp6-client.c
@@ -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();
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 273dd35e04..0727050ed2 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -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");
diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c
index f588514cb6..57c23965ed 100644
--- a/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libsystemd-network/sd-dhcp6-lease.c
@@ -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) ? "" : ": ",