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,
#include "sd-dhcp6-lease.h"
#include "dhcp6-internal.h"
+#include "macro.h"
struct sd_dhcp6_lease {
unsigned n_ref;
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;
};
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);
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;
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),
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: {
}
}
- 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.");
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;
}
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;
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;
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.");
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.");
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;
}
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);
}
}
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;
}
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) {
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(
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) {
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);
lease->n_ref = 1;
- LIST_HEAD_INIT(lease->ia_na.addresses);
-
*ret = lease;
return 0;
}
/* 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));
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) {