From e5b0b87f516007405ed23849d74348ecca024dd3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 6 Feb 2022 14:18:44 +0900 Subject: [PATCH] sd-dhcp6-client: introduce dhcp6_ia_free() --- src/libsystemd-network/dhcp6-internal.h | 2 +- src/libsystemd-network/dhcp6-lease-internal.h | 10 +++- src/libsystemd-network/dhcp6-option.c | 37 ++++++------ src/libsystemd-network/sd-dhcp6-client.c | 56 +++++++++---------- src/libsystemd-network/sd-dhcp6-lease.c | 33 +++++------ src/libsystemd-network/test-dhcp6-client.c | 42 ++++++-------- 6 files changed, 89 insertions(+), 91 deletions(-) diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 7ceb3a8b281..131922b658e 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -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, diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index ffe88f31c73..5d009781b27 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -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); diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index e7a55c1b022..049380cdd9b 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -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; } diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 65b8cce1657..30795082bdf 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -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; } diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 96c32cf8f97..87c3a89aced 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -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; } diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 91eec940589..53def1b07f7 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -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) { -- 2.47.3