]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp6-client: introduce dhcp6_ia_free()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 6 Feb 2022 05:18:44 +0000 (14:18 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 14 Feb 2022 05:43:45 +0000 (14:43 +0900)
src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-lease-internal.h
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-dhcp6-lease.c
src/libsystemd-network/test-dhcp6-client.c

index 7ceb3a8b28137c254e7fdf9b4be455c2e0072db1..131922b658ea8bd448297ced7afb4c2a7219bdd0 100644 (file)
@@ -101,7 +101,7 @@ int dhcp6_option_parse_ia(
                 uint16_t option_code,
                 size_t option_data_len,
                 const uint8_t *option_data,
-                DHCP6IA *ret);
+                DHCP6IA **ret);
 int dhcp6_option_parse_addresses(
                 const uint8_t *optval,
                 size_t optlen,
index ffe88f31c73cd86ac70e088e43c8a4df5d3afde6..5d009781b27f1ddf8af26dbd222091b511a44869 100644 (file)
@@ -10,6 +10,7 @@
 #include "sd-dhcp6-lease.h"
 
 #include "dhcp6-internal.h"
+#include "macro.h"
 
 struct sd_dhcp6_lease {
         unsigned n_ref;
@@ -23,8 +24,8 @@ struct sd_dhcp6_lease {
         triple_timestamp timestamp;
         struct in6_addr server_address;
 
-        DHCP6IA ia_na;
-        DHCP6IA ia_pd;
+        DHCP6IA *ia_na;
+        DHCP6IA *ia_pd;
 
         DHCP6Address *addr_iter;
         DHCP6Address *prefix_iter;
@@ -41,7 +42,10 @@ struct sd_dhcp6_lease {
 };
 
 int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
-DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
+
+void dhcp6_ia_clear_addresses(DHCP6IA *ia);
+DHCP6IA *dhcp6_ia_free(DHCP6IA *ia);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6IA*, dhcp6_ia_free);
 
 int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
 int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len);
index e7a55c1b0226951a203a1ccaaeca522529e73a6a..049380cdd9bce2d98f48a66d9075a55fab65c502 100644 (file)
@@ -725,9 +725,9 @@ int dhcp6_option_parse_ia(
                 uint16_t option_code,
                 size_t option_data_len,
                 const uint8_t *option_data,
-                DHCP6IA *ret) {
+                DHCP6IA **ret) {
 
-        _cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
+        _cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL;
         uint32_t lt_t1, lt_t2, lt_min = UINT32_MAX;
         size_t header_len;
         int r;
@@ -761,19 +761,25 @@ int dhcp6_option_parse_ia(
         if (option_data_len < header_len)
                 return -EBADMSG;
 
-        ia.type = option_code;
-        memcpy(&ia.header, option_data, header_len);
+        ia = new(DHCP6IA, 1);
+        if (!ia)
+                return -ENOMEM;
+
+        *ia = (DHCP6IA) {
+                .type = option_code,
+        };
+        memcpy(&ia->header, option_data, header_len);
 
         /* According to RFC8415, IAs which do not match the client's IAID should be ignored,
          * but not necessary to ignore or refuse the whole message. */
-        if (ia.header.id != iaid)
+        if (ia->header.id != iaid)
                 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
                                               "Received an IA option with a different IAID "
                                               "from the one chosen by the client, ignoring.");
 
         /* It is not necessary to check if the lifetime_t2 is zero here, as in that case it will be updated later. */
-        lt_t1 = be32toh(ia.header.lifetime_t1);
-        lt_t2 = be32toh(ia.header.lifetime_t2);
+        lt_t1 = be32toh(ia->header.lifetime_t1);
+        lt_t2 = be32toh(ia->header.lifetime_t2);
 
         if (lt_t1 > lt_t2)
                 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
@@ -795,25 +801,25 @@ int dhcp6_option_parse_ia(
 
                 switch (subopt) {
                 case SD_DHCP6_OPTION_IAADDR: {
-                        r = dhcp6_option_parse_ia_address(client, &ia, subdata, subdata_len);
+                        r = dhcp6_option_parse_ia_address(client, ia, subdata, subdata_len);
                         if (r == -ENOMEM)
                                 return r;
                         if (r < 0)
                                 /* Ignore non-critical errors in the sub-option. */
                                 continue;
 
-                        lt_min = MIN(lt_min, be32toh(ia.addresses->iaaddr.lifetime_valid));
+                        lt_min = MIN(lt_min, be32toh(ia->addresses->iaaddr.lifetime_valid));
                         break;
                 }
                 case SD_DHCP6_OPTION_IA_PD_PREFIX: {
-                        r = dhcp6_option_parse_ia_pdprefix(client, &ia, subdata, subdata_len);
+                        r = dhcp6_option_parse_ia_pdprefix(client, ia, subdata, subdata_len);
                         if (r == -ENOMEM)
                                 return r;
                         if (r < 0)
                                 /* Ignore non-critical errors in the sub-option. */
                                 continue;
 
-                        lt_min = MIN(lt_min, be32toh(ia.addresses->iapdprefix.lifetime_valid));
+                        lt_min = MIN(lt_min, be32toh(ia->addresses->iapdprefix.lifetime_valid));
                         break;
                 }
                 case SD_DHCP6_OPTION_STATUS_CODE: {
@@ -837,7 +843,7 @@ int dhcp6_option_parse_ia(
                 }
         }
 
-        if (!ia.addresses)
+        if (!ia->addresses)
                 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENODATA),
                                               "Received an IA option without valid IA addresses or PD prefixes, ignoring.");
 
@@ -849,16 +855,15 @@ int dhcp6_option_parse_ia(
                 lt_t1 = lt_min / 2;
                 lt_t2 = lt_min / 10 * 8;
 
-                ia.header.lifetime_t1 = htobe32(lt_t1);
-                ia.header.lifetime_t1 = htobe32(lt_t2);
+                ia->header.lifetime_t1 = htobe32(lt_t1);
+                ia->header.lifetime_t1 = htobe32(lt_t2);
 
                 log_dhcp6_client(client, "Received an IA option with both T1 and T2 equal to zero. "
                                  "Adjusting them based on the minimum valid lifetime of IA addresses or PD prefixes: "
                                  "T1=%"PRIu32"sec, T2=%"PRIu32"sec", lt_t1, lt_t2);
         }
 
-        *ret = ia;
-        ret->addresses = TAKE_PTR(ia.addresses);
+        *ret = TAKE_PTR(ia);
         return 0;
 }
 
index 65b8cce16574fa74ff1df0bf17ba5823a0b9d045..30795082bdf022c84d4b63d11cbea0697a9dbc65 100644 (file)
@@ -799,9 +799,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 assert(client->lease);
 
                 r = client_append_common_options_in_managed_mode(client, &opt, &optlen,
-                                                                 client->lease->ia_na.addresses ? &client->lease->ia_na : NULL,
-                                                                 client->lease->ia_pd.addresses ? &client->lease->ia_pd : NULL,
-                                                                 NULL);
+                                                                 client->lease->ia_na, client->lease->ia_pd, NULL);
                 if (r < 0)
                         return r;
                 break;
@@ -971,7 +969,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
                 if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
                         uint32_t expire = 0;
 
-                        r = dhcp6_lease_ia_rebind_expire(&client->lease->ia_na, &expire);
+                        r = dhcp6_lease_ia_rebind_expire(client->lease->ia_na, &expire);
                         if (r < 0) {
                                 client_stop(client, r);
                                 return 0;
@@ -1146,7 +1144,7 @@ int client_parse_message(
                         break;
                 }
                 case SD_DHCP6_OPTION_IA_NA: {
-                        _cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
+                        _cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL;
 
                         if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
                                 log_dhcp6_client(client, "Ignoring IA NA option in information requesting mode.");
@@ -1159,21 +1157,21 @@ int client_parse_message(
                         if (r < 0)
                                 continue;
 
-                        if (lease->ia_na.addresses) {
+                        if (lease->ia_na) {
                                 log_dhcp6_client(client, "Received duplicate matching IA_NA option, ignoring.");
                                 continue;
                         }
 
-                        lease->ia_na = ia;
-                        ia = (DHCP6IA) {};
+                        dhcp6_ia_free(lease->ia_na);
+                        lease->ia_na = TAKE_PTR(ia);
 
-                        lt_t1 = MIN(lt_t1, be32toh(lease->ia_na.header.lifetime_t1));
-                        lt_t2 = MIN(lt_t2, be32toh(lease->ia_na.header.lifetime_t2));
+                        lt_t1 = MIN(lt_t1, be32toh(lease->ia_na->header.lifetime_t1));
+                        lt_t2 = MIN(lt_t2, be32toh(lease->ia_na->header.lifetime_t2));
 
                         break;
                 }
                 case SD_DHCP6_OPTION_IA_PD: {
-                        _cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
+                        _cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL;
 
                         if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
                                 log_dhcp6_client(client, "Ignoring IA PD option in information requesting mode.");
@@ -1186,16 +1184,16 @@ int client_parse_message(
                         if (r < 0)
                                 continue;
 
-                        if (lease->ia_pd.addresses) {
+                        if (lease->ia_pd) {
                                 log_dhcp6_client(client, "Received duplicate matching IA_PD option, ignoring.");
                                 continue;
                         }
 
-                        lease->ia_pd = ia;
-                        ia = (DHCP6IA) {};
+                        dhcp6_ia_free(lease->ia_pd);
+                        lease->ia_pd = TAKE_PTR(ia);
 
-                        lt_t1 = MIN(lt_t1, be32toh(lease->ia_pd.header.lifetime_t1));
-                        lt_t2 = MIN(lt_t2, be32toh(lease->ia_pd.header.lifetime_t2));
+                        lt_t1 = MIN(lt_t1, be32toh(lease->ia_pd->header.lifetime_t1));
+                        lt_t2 = MIN(lt_t2, be32toh(lease->ia_pd->header.lifetime_t2));
 
                         break;
                 }
@@ -1267,17 +1265,17 @@ int client_parse_message(
                         return log_dhcp6_client_errno(client, r, "%s has no server id",
                                                       dhcp6_message_type_to_string(message->type));
 
-                if (!lease->ia_na.addresses && !lease->ia_pd.addresses)
+                if (!lease->ia_na && !lease->ia_pd)
                         return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "No IA_PD prefix or IA_NA address received. Ignoring.");
 
-                if (lease->ia_na.addresses) {
-                        lease->ia_na.header.lifetime_t1 = htobe32(lt_t1);
-                        lease->ia_na.header.lifetime_t2 = htobe32(lt_t2);
+                if (lease->ia_na) {
+                        lease->ia_na->header.lifetime_t1 = htobe32(lt_t1);
+                        lease->ia_na->header.lifetime_t2 = htobe32(lt_t2);
                 }
 
-                if (lease->ia_pd.addresses) {
-                        lease->ia_pd.header.lifetime_t1 = htobe32(lt_t1);
-                        lease->ia_pd.header.lifetime_t2 = htobe32(lt_t2);
+                if (lease->ia_pd) {
+                        lease->ia_pd->header.lifetime_t1 = htobe32(lt_t1);
+                        lease->ia_pd->header.lifetime_t2 = htobe32(lt_t2);
                 }
         }
 
@@ -1544,16 +1542,16 @@ static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
         assert_return(client, -EINVAL);
         assert_return(client->lease, -EINVAL);
 
-        if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia_na.addresses) {
-                *lifetime_t1 = be32toh(client->lease->ia_na.header.lifetime_t1);
-                *lifetime_t2 = be32toh(client->lease->ia_na.header.lifetime_t2);
+        if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia_na) {
+                *lifetime_t1 = be32toh(client->lease->ia_na->header.lifetime_t1);
+                *lifetime_t2 = be32toh(client->lease->ia_na->header.lifetime_t2);
 
                 return 0;
         }
 
-        if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->ia_pd.addresses) {
-                *lifetime_t1 = be32toh(client->lease->ia_pd.header.lifetime_t1);
-                *lifetime_t2 = be32toh(client->lease->ia_pd.header.lifetime_t2);
+        if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->ia_pd) {
+                *lifetime_t1 = be32toh(client->lease->ia_pd->header.lifetime_t1);
+                *lifetime_t2 = be32toh(client->lease->ia_pd->header.lifetime_t2);
 
                 return 0;
         }
index 96c32cf8f9762cc236efed0f22a024f8f0c1b733..87c3a89acedafb6846882d0ca39394186451c65d 100644 (file)
@@ -54,21 +54,24 @@ int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
         return 0;
 }
 
-DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
-        DHCP6Address *address;
+void dhcp6_ia_clear_addresses(DHCP6IA *ia) {
+        DHCP6Address *a, *n;
 
-        if (!ia)
-                return NULL;
+        assert(ia);
 
-        while (ia->addresses) {
-                address = ia->addresses;
+        LIST_FOREACH_SAFE(addresses, a, n, ia->addresses)
+                free(a);
 
-                LIST_REMOVE(addresses, ia->addresses, address);
+        ia->addresses = NULL;
+}
 
-                free(address);
-        }
+DHCP6IA *dhcp6_ia_free(DHCP6IA *ia) {
+        if (!ia)
+                return NULL;
 
-        return NULL;
+        dhcp6_ia_clear_addresses(ia);
+
+        return mfree(ia);
 }
 
 int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
@@ -188,7 +191,7 @@ int sd_dhcp6_lease_get_address(
 
 void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
         if (lease)
-                lease->addr_iter = lease->ia_na.addresses;
+                lease->addr_iter = lease->ia_na ? lease->ia_na->addresses : NULL;
 }
 
 int sd_dhcp6_lease_get_pd(
@@ -218,7 +221,7 @@ int sd_dhcp6_lease_get_pd(
 
 void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
         if (lease)
-                lease->prefix_iter = lease->ia_pd.addresses;
+                lease->prefix_iter = lease->ia_pd ? lease->ia_pd->addresses : NULL;
 }
 
 int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
@@ -399,8 +402,8 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
 
         free(lease->clientid);
         free(lease->serverid);
-        dhcp6_lease_free_ia(&lease->ia_na);
-        dhcp6_lease_free_ia(&lease->ia_pd);
+        dhcp6_ia_free(lease->ia_na);
+        dhcp6_ia_free(lease->ia_pd);
         free(lease->dns);
         free(lease->fqdn);
         strv_free(lease->domains);
@@ -424,8 +427,6 @@ int dhcp6_lease_new(sd_dhcp6_lease **ret) {
 
         lease->n_ref = 1;
 
-        LIST_HEAD_INIT(lease->ia_na.addresses);
-
         *ret = lease;
         return 0;
 }
index 91eec940589b1d48696628ac280c7fce8bf52b9b..53def1b07f7da4beef25b212d97bb5cd87a64621 100644 (file)
@@ -297,16 +297,15 @@ static void test_option_status(void) {
                 /* PD prefix status option */
                 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
         };
+        _cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL;
         DHCP6Option *option;
-        DHCP6IA ia, pd;
         be32_t iaid;
-        int r = 0;
+        int r;
 
         log_debug("/* %s */", __func__);
 
         memcpy(&iaid, option1 + 4, sizeof(iaid));
 
-        zero(ia);
         option = (DHCP6Option*) option1;
         assert_se(sizeof(option1) == sizeof(DHCP6Option) + be16toh(option->len));
 
@@ -315,55 +314,46 @@ static void test_option_status(void) {
 
         r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
         assert_se(r == -EINVAL);
-        assert_se(!ia.addresses);
 
         option->len = htobe16(17);
         r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
         assert_se(r == -EBADMSG);
-        assert_se(!ia.addresses);
 
         option->len = htobe16(sizeof(DHCP6Option));
         r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
         assert_se(r == -EBADMSG);
-        assert_se(!ia.addresses);
 
-        zero(ia);
         option = (DHCP6Option*) option2;
         assert_se(sizeof(option2) == sizeof(DHCP6Option) + be16toh(option->len));
-
         r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
         assert_se(r == -ENODATA);
-        assert_se(!ia.addresses);
 
-        zero(ia);
         option = (DHCP6Option*) option3;
         assert_se(sizeof(option3) == sizeof(DHCP6Option) + be16toh(option->len));
-
         r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
         assert_se(r >= 0);
-        assert_se(ia.addresses);
-        dhcp6_lease_free_ia(&ia);
+        assert_se(ia);
+        assert_se(ia->addresses);
+        ia = dhcp6_ia_free(ia);
 
-        zero(pd);
         option = (DHCP6Option*) option4;
         assert_se(sizeof(option4) == sizeof(DHCP6Option) + be16toh(option->len));
-
-        r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &pd);
+        r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
         assert_se(r >= 0);
-        assert_se(pd.addresses);
-        assert_se(memcmp(&pd.header.id, &option4[4], 4) == 0);
-        assert_se(memcmp(&pd.header.lifetime_t1, &option4[8], 4) == 0);
-        assert_se(memcmp(&pd.header.lifetime_t2, &option4[12], 4) == 0);
-        dhcp6_lease_free_ia(&pd);
+        assert_se(ia);
+        assert_se(ia->addresses);
+        assert_se(memcmp(&ia->header.id, &option4[4], 4) == 0);
+        assert_se(memcmp(&ia->header.lifetime_t1, &option4[8], 4) == 0);
+        assert_se(memcmp(&ia->header.lifetime_t2, &option4[12], 4) == 0);
+        ia = dhcp6_ia_free(ia);
 
-        zero(pd);
         option = (DHCP6Option*) option5;
         assert_se(sizeof(option5) == sizeof(DHCP6Option) + be16toh(option->len));
-
-        r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &pd);
+        r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
         assert_se(r >= 0);
-        assert_se(pd.addresses);
-        dhcp6_lease_free_ia(&pd);
+        assert_se(ia);
+        assert_se(ia->addresses);
+        ia = dhcp6_ia_free(ia);
 }
 
 static void test_client_parse_message_issue_22099(void) {