]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp-client: split out client_parse_message() 29258/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 20 Sep 2023 19:39:49 +0000 (04:39 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 22 Sep 2023 16:38:21 +0000 (01:38 +0900)
No functional change, just refactoring and preparation for later
commits.

src/libsystemd-network/fuzz-dhcp-client.c
src/libsystemd-network/sd-dhcp-client.c

index d2bbf660b0d1af7fac4950f02629be96d661f5f8..9b9e741e5341c51409f87ebe949b1a2974742f8a 100644 (file)
@@ -73,6 +73,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         res = sd_dhcp_client_start(client);
         assert_se(IN_SET(res, 0, -EINPROGRESS));
         client->xid = 2;
+        client->state = DHCP_STATE_SELECTING;
 
         (void) client_handle_offer(client, (DHCPMessage*) data, size);
 
index e3f637736ececbd8578628f287725ebb02b81a68..cfdee5d6b4e43e35d9a1a79f72bf8c1596ab7b06 100644 (file)
@@ -1546,10 +1546,20 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
         return client_initialize_time_events(client);
 }
 
-static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
+static int client_parse_message(
+                sd_dhcp_client *client,
+                DHCPMessage *message,
+                size_t len,
+                sd_dhcp_lease **ret) {
+
         _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
+        _cleanup_free_ char *error_message = NULL;
         int r;
 
+        assert(client);
+        assert(message);
+        assert(ret);
+
         r = dhcp_lease_new(&lease);
         if (r < 0)
                 return r;
@@ -1562,28 +1572,66 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_
                         return r;
         }
 
-        r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
-        if (r != DHCP_OFFER)
-                return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
-                                             "received message was not an OFFER, ignoring");
+        r = dhcp_option_parse(message, len, dhcp_lease_parse_options, lease, &error_message);
+        if (r < 0)
+                return log_dhcp_client_errno(client, r, "Failed to parse DHCP options, ignoring: %m");
 
-        lease->next_server = offer->siaddr;
-        lease->address = offer->yiaddr;
+        switch (client->state) {
+        case DHCP_STATE_SELECTING:
+                if (r != DHCP_OFFER)
+                        return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
+                                                     "received message was not an OFFER, ignoring.");
 
-        if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
-                lease->lifetime = client->fallback_lease_lifetime;
+                if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
+                        lease->lifetime = client->fallback_lease_lifetime;
+
+                break;
+
+        case DHCP_STATE_REBOOTING:
+        case DHCP_STATE_REQUESTING:
+        case DHCP_STATE_RENEWING:
+        case DHCP_STATE_REBINDING:
+                if (r == DHCP_NAK)
+                        return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
+                                                     "NAK: %s", strna(error_message));
+                if (r != DHCP_ACK)
+                        return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
+                                                     "received message was not an ACK, ignoring.");
+                break;
+
+        default:
+                assert_not_reached();
+        }
+
+        lease->next_server = message->siaddr;
+        lease->address = message->yiaddr;
 
         if (lease->address == 0 ||
             lease->server_address == 0 ||
             lease->lifetime == 0)
                 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
-                                             "received lease lacks address, server address or lease lifetime, ignoring");
+                                             "received lease lacks address, server address or lease lifetime, ignoring.");
 
         r = dhcp_lease_set_default_subnet_mask(lease);
         if (r < 0)
                 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
                                              "received lease lacks subnet mask, and a fallback one cannot be generated, ignoring.");
 
+        *ret = TAKE_PTR(lease);
+        return 0;
+}
+
+static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
+        _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
+        int r;
+
+        assert(client);
+        assert(message);
+
+        r = client_parse_message(client, message, len, &lease);
+        if (r < 0)
+                return r;
+
         dhcp_lease_unref_and_replace(client->lease, lease);
 
         if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
@@ -1643,46 +1691,16 @@ static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
         return true;
 }
 
-static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
+static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
         _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
-        _cleanup_free_ char *error_message = NULL;
         int r;
 
-        r = dhcp_lease_new(&lease);
-        if (r < 0)
-                return r;
-
-        if (client->client_id_len > 0) {
-                r = dhcp_lease_set_client_id(lease,
-                                             (uint8_t *) &client->client_id,
-                                             client->client_id_len);
-                if (r < 0)
-                        return r;
-        }
-
-        r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
-        if (r == DHCP_NAK)
-                return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
-                                             "NAK: %s", strna(error_message));
-
-        if (r != DHCP_ACK)
-                return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
-                                             "received message was not an ACK, ignoring");
-
-        lease->next_server = ack->siaddr;
-
-        lease->address = ack->yiaddr;
-
-        if (lease->address == INADDR_ANY ||
-            lease->server_address == INADDR_ANY ||
-            lease->lifetime == 0)
-                return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
-                                             "received lease lacks address, server address or lease lifetime, ignoring");
+        assert(client);
+        assert(message);
 
-        r = dhcp_lease_set_default_subnet_mask(lease);
+        r = client_parse_message(client, message, len, &lease);
         if (r < 0)
-                return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
-                                             "received lease lacks subnet mask, and a fallback one cannot be generated, ignoring.");
+                return r;
 
         if (!client->lease)
                 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
@@ -1851,10 +1869,10 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
         case DHCP_STATE_SELECTING:
 
                 r = client_handle_offer(client, message, len);
-                if (r == -ENOMSG)
-                        return 0; /* invalid message, let's ignore it */
-                if (r < 0)
+                if (ERRNO_IS_NEG_RESOURCE(r))
                         goto error;
+                if (r < 0)
+                        return 0; /* invalid message, let's ignore it */
 
                 r = client_enter_requesting(client);
                 break;
@@ -1865,8 +1883,8 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
         case DHCP_STATE_REBINDING:
 
                 r = client_handle_ack(client, message, len);
-                if (r == -ENOMSG)
-                        return 0; /* invalid message, let's ignore it */
+                if (ERRNO_IS_NEG_RESOURCE(r))
+                        goto error;
                 if (r == -EADDRNOTAVAIL) {
                         /* got a NAK, let's restart the client */
                         client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
@@ -1886,7 +1904,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
                         return 0;
                 }
                 if (r < 0)
-                        goto error;
+                        return 0; /* invalid message, let's ignore it */
 
                 r = client_enter_bound(client, r);
                 break;