]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp6-client: introduce client_process_*()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 6 Feb 2022 12:59:07 +0000 (21:59 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 14 Feb 2022 05:43:45 +0000 (14:43 +0900)
This is mostly for shortening `client_receive_message()`.

This also fixes the following:
- do not trigger SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST notification
  when non-reply message,
- add several missing error handlings caused in client_start().

src/libsystemd-network/fuzz-dhcp6-client-send.c
src/libsystemd-network/sd-dhcp6-client.c

index 39a5f4fd4dda6b6a28d49594b2a8193977b40c77..d05bb55c433e5230bfd1ce6615a266ae50519edf 100644 (file)
@@ -22,7 +22,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
         _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
         struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
-        triple_timestamp t = {};
         usec_t time_now;
         int r;
 
@@ -43,8 +42,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         assert_se(sd_dhcp6_client_start(client) >= 0);
         assert_se(sd_dhcp6_client_set_transaction_id(client, htobe32(0x00ffffff) & ((const DHCP6Message *) data)->transaction_id) == 0);
 
-        triple_timestamp_get(&t);
-        r = client_receive_advertise(client, (DHCP6Message *) data, size, &t, NULL);
+        r = client_process_advertise_or_rapid_commit_reply(client, (DHCP6Message *) data, size, NULL, NULL);
         if (r < 0)
                 goto cleanup;
 
@@ -52,8 +50,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         if (r < 0)
                 goto cleanup;
 
-        if (r == DHCP6_STATE_REQUEST)
-                client->state = DHCP6_STATE_REQUEST;
+        if (client->state != DHCP6_STATE_REQUEST)
+                client->state = DHCP6_STATE_SOLICITATION;
         (void) client_send_message(client, time_now);
 cleanup:
         assert_se(sd_dhcp6_client_stop(client) >= 0);
index 457e8ca915e4e0c7894e59f6c60374244a77593f..2784a4ee24fd4745147bcdcb7273cadc6d874a6b 100644 (file)
@@ -1020,7 +1020,22 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
         return 0;
 }
 
-static int client_receive_reply(
+static int log_invalid_message_type(sd_dhcp6_client *client, const DHCP6Message *message) {
+        const char *type_str;
+
+        assert(client);
+        assert(message);
+
+        type_str = dhcp6_message_type_to_string(message->type);
+        if (type_str)
+                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+                                              "Received unexpected %s message, ignoring.", type_str);
+        else
+                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+                                              "Received unsupported message type %u, ignoring.", message->type);
+}
+
+static int client_process_information(
                 sd_dhcp6_client *client,
                 DHCP6Message *message,
                 size_t len,
@@ -1028,35 +1043,62 @@ static int client_receive_reply(
                 const struct in6_addr *server_address) {
 
         _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
-        bool rapid_commit;
         int r;
 
-        assert(client);
-        assert(message);
-
         if (message->type != DHCP6_MESSAGE_REPLY)
-                return 0;
+                return log_invalid_message_type(client, message);
 
         r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
         if (r < 0)
-                return r;
+                return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
 
-        if (client->state == DHCP6_STATE_SOLICITATION) {
-                r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
-                if (r < 0)
-                        return r;
+        sd_dhcp6_lease_unref(client->lease);
+        client->lease = TAKE_PTR(lease);
 
-                if (!rapid_commit)
-                        return 0;
+        client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
+        r = client_start(client, DHCP6_STATE_STOPPED);
+        if (r < 0) {
+                client_stop(client, r);
+                return r;
         }
 
+        return 0;
+}
+
+static int client_process_reply(
+                sd_dhcp6_client *client,
+                DHCP6Message *message,
+                size_t len,
+                const triple_timestamp *timestamp,
+                const struct in6_addr *server_address) {
+
+        _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
+        int r;
+
+        assert(client);
+        assert(message);
+
+        if (message->type != DHCP6_MESSAGE_REPLY)
+                return log_invalid_message_type(client, message);
+
+        r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
+        if (r < 0)
+                return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
+
         sd_dhcp6_lease_unref(client->lease);
         client->lease = TAKE_PTR(lease);
 
-        return DHCP6_STATE_BOUND;
+        r = client_start(client, DHCP6_STATE_BOUND);
+        if (r < 0) {
+                client_stop(client, r);
+                return r;
+        }
+
+        client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
+        return 0;
 }
 
-static int client_receive_advertise(
+static int client_process_advertise_or_rapid_commit_reply(
                 sd_dhcp6_client *client,
                 DHCP6Message *message,
                 size_t len,
@@ -1064,18 +1106,43 @@ static int client_receive_advertise(
                 const struct in6_addr *server_address) {
 
         _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
-        uint8_t pref_advertise = 0, pref_lease = 0;
+        uint8_t pref_advertise, pref_lease = 0;
         int r;
 
         assert(client);
         assert(message);
 
-        if (message->type != DHCP6_MESSAGE_ADVERTISE)
-                return 0;
+        if (!IN_SET(message->type, DHCP6_MESSAGE_ADVERTISE, DHCP6_MESSAGE_REPLY))
+                return log_invalid_message_type(client, message);
 
         r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
         if (r < 0)
-                return r;
+                return log_dhcp6_client_errno(client, r, "Failed to process received %s message, ignoring: %m",
+                                              dhcp6_message_type_to_string(message->type));
+
+        if (message->type == DHCP6_MESSAGE_REPLY) {
+                bool rapid_commit;
+
+                r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
+                if (r < 0)
+                        return r;
+
+                if (!rapid_commit)
+                        return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+                                                      "Received reply message without rapid commit flag, ignoring.");
+
+                sd_dhcp6_lease_unref(client->lease);
+                client->lease = TAKE_PTR(lease);
+
+                r = client_start(client, DHCP6_STATE_BOUND);
+                if (r < 0) {
+                        client_stop(client, r);
+                        return r;
+                }
+
+                client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
+                return 0;
+        }
 
         r = dhcp6_lease_get_preference(lease, &pref_advertise);
         if (r < 0)
@@ -1088,15 +1155,20 @@ static int client_receive_advertise(
         }
 
         if (!client->lease || pref_advertise > pref_lease) {
+                /* If this is the first advertise message or has higher preference, then save the lease. */
                 sd_dhcp6_lease_unref(client->lease);
                 client->lease = TAKE_PTR(lease);
-                r = 0;
         }
 
-        if (pref_advertise == 255 || client->retransmit_count > 1)
-                r = DHCP6_STATE_REQUEST;
+        if (pref_advertise == 255 || client->retransmit_count > 1) {
+                r = client_start(client, DHCP6_STATE_REQUEST);
+                if (r < 0) {
+                        client_stop(client, r);
+                        return r;
+                }
+        }
 
-        return r;
+        return 0;
 }
 
 static int client_receive_message(
@@ -1124,7 +1196,6 @@ static int client_receive_message(
         _cleanup_free_ DHCP6Message *message = NULL;
         struct in6_addr *server_address = NULL;
         ssize_t buflen, len;
-        int r = 0;
 
         assert(s);
         assert(client);
@@ -1175,73 +1246,31 @@ static int client_receive_message(
                         triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
         }
 
-        if (!IN_SET(message->type, DHCP6_MESSAGE_ADVERTISE, DHCP6_MESSAGE_REPLY, DHCP6_MESSAGE_RECONFIGURE)) {
-                const char *type_str = dhcp6_message_type_to_string(message->type);
-                if (type_str)
-                        log_dhcp6_client(client, "Received unexpected %s message, ignoring.", type_str);
-                else
-                        log_dhcp6_client(client, "Received unsupported message type %u, ignoring.", message->type);
-                return 0;
-        }
-
         if (client->transaction_id != (message->transaction_id & htobe32(0x00ffffff)))
                 return 0;
 
         switch (client->state) {
         case DHCP6_STATE_INFORMATION_REQUEST:
-                r = client_receive_reply(client, message, len, &t, server_address);
-                if (r < 0) {
-                        log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
+                if (client_process_information(client, message, len, &t, server_address) < 0)
                         return 0;
-                }
-
-                client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
-
-                client_start(client, DHCP6_STATE_STOPPED);
-
                 break;
 
         case DHCP6_STATE_SOLICITATION:
-                r = client_receive_advertise(client, message, len, &t, server_address);
-                if (r < 0) {
-                        log_dhcp6_client_errno(client, r, "Failed to process received advertise message, ignoring: %m");
+                if (client_process_advertise_or_rapid_commit_reply(client, message, len, &t, server_address) < 0)
                         return 0;
-                }
-
-                if (r == DHCP6_STATE_REQUEST) {
-                        client_start(client, r);
-                        break;
-                }
+                break;
 
-                _fallthrough_; /* for Solicitation Rapid Commit option check */
         case DHCP6_STATE_REQUEST:
         case DHCP6_STATE_RENEW:
         case DHCP6_STATE_REBIND:
-
-                r = client_receive_reply(client, message, len, &t, server_address);
-                if (r < 0) {
-                        log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
+                if (client_process_reply(client, message, len, &t, server_address) < 0)
                         return 0;
-                }
-
-                if (r == DHCP6_STATE_BOUND) {
-                        r = client_start(client, DHCP6_STATE_BOUND);
-                        if (r < 0) {
-                                client_stop(client, r);
-                                return 0;
-                        }
-
-                        client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
-                }
-
                 break;
 
         case DHCP6_STATE_BOUND:
-
-                break;
-
         case DHCP6_STATE_STOPPED:
                 return 0;
+
         default:
                 assert_not_reached();
         }