From: Yu Watanabe Date: Sun, 19 Apr 2026 06:19:41 +0000 (+0900) Subject: dhcp-message: introduce dhcp_message_{append,get}_option_addresses() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=174a61135cad747dfcaa66bb9312fe63e94a8364;p=thirdparty%2Fsystemd.git dhcp-message: introduce dhcp_message_{append,get}_option_addresses() These functions support multiple addresses. These are for e.g. DHCP options 6 (DNS servers), 42 (NTP servers) and so on. --- diff --git a/src/libsystemd-network/dhcp-message.c b/src/libsystemd-network/dhcp-message.c index 6344a7a41aa..816d16955d6 100644 --- a/src/libsystemd-network/dhcp-message.c +++ b/src/libsystemd-network/dhcp-message.c @@ -173,6 +173,19 @@ int dhcp_message_append_option_address(sd_dhcp_message *message, uint8_t code, c return dhcp_message_append_option_be32(message, code, addr->s_addr); } +int dhcp_message_append_option_addresses(sd_dhcp_message *message, uint8_t code, size_t n_addr, const struct in_addr *addr) { + assert(message); + assert(n_addr == 0 || addr); + + if (n_addr == 0) + return 0; + + if (size_multiply_overflow(sizeof(struct in_addr), n_addr)) + return -ENOBUFS; + + return dhcp_message_append_option(message, code, sizeof(struct in_addr) * n_addr, addr); +} + int dhcp_message_get_option(sd_dhcp_message *message, uint8_t code, size_t length, void *ret) { int r; @@ -243,6 +256,31 @@ int dhcp_message_get_option_address(sd_dhcp_message *message, uint8_t code, stru return dhcp_message_get_option_be32(message, code, ret ? &ret->s_addr : NULL); } +int dhcp_message_get_option_addresses(sd_dhcp_message *message, uint8_t code, size_t *ret_n_addr, struct in_addr **ret_addr) { + int r; + + assert(message); + assert(ret_n_addr || !ret_addr); + + _cleanup_(iovec_done) struct iovec iov = {}; + r = dhcp_message_get_option_alloc(message, code, &iov); + if (r < 0) + return r; + + if (iov.iov_len % sizeof(struct in_addr) != 0) + return -EBADMSG; + + size_t n = iov.iov_len / sizeof(struct in_addr); + if (n == 0) + return -ENODATA; + + if (ret_addr) + *ret_addr = (struct in_addr*) TAKE_PTR(iov.iov_base); + if (ret_n_addr) + *ret_n_addr = n; + return 0; +} + static int dhcp_message_verify_header( const struct iovec *iov, uint8_t op, diff --git a/src/libsystemd-network/dhcp-message.h b/src/libsystemd-network/dhcp-message.h index e0e5d875883..6d4e1939b0f 100644 --- a/src/libsystemd-network/dhcp-message.h +++ b/src/libsystemd-network/dhcp-message.h @@ -36,6 +36,7 @@ int dhcp_message_append_option_u16(sd_dhcp_message *message, uint8_t code, uint1 int dhcp_message_append_option_be32(sd_dhcp_message *message, uint8_t code, be32_t data); int dhcp_message_append_option_sec(sd_dhcp_message *message, uint8_t code, usec_t usec); int dhcp_message_append_option_address(sd_dhcp_message *message, uint8_t code, const struct in_addr *addr); +int dhcp_message_append_option_addresses(sd_dhcp_message *message, uint8_t code, size_t n_addr, const struct in_addr *addr); int dhcp_message_get_option(sd_dhcp_message *message, uint8_t code, size_t length, void *ret); int dhcp_message_get_option_alloc(sd_dhcp_message *message, uint8_t code, struct iovec *ret); @@ -45,6 +46,7 @@ int dhcp_message_get_option_u16(sd_dhcp_message *message, uint8_t code, uint16_t int dhcp_message_get_option_be32(sd_dhcp_message *message, uint8_t code, be32_t *ret); int dhcp_message_get_option_sec(sd_dhcp_message *message, uint8_t code, bool max_as_infinity, usec_t *ret); int dhcp_message_get_option_address(sd_dhcp_message *message, uint8_t code, struct in_addr *ret); +int dhcp_message_get_option_addresses(sd_dhcp_message *message, uint8_t code, size_t *ret_n_addr, struct in_addr **ret_addr); int dhcp_message_parse( const struct iovec *iov, diff --git a/src/libsystemd-network/test-dhcp-message.c b/src/libsystemd-network/test-dhcp-message.c index 92d22d4de1c..7c1c255f951 100644 --- a/src/libsystemd-network/test-dhcp-message.c +++ b/src/libsystemd-network/test-dhcp-message.c @@ -62,6 +62,23 @@ static void verify_address(sd_dhcp_message *m, const struct in_addr *expected) { ASSERT_EQ(a.s_addr, expected->s_addr); } +static void verify_addresses( + sd_dhcp_message *m, + size_t n_ntp, const struct in_addr *ntp) { + + struct in_addr a; + ASSERT_OK(dhcp_message_get_option_be32(m, SD_DHCP_OPTION_NTP_SERVER, &a.s_addr)); + ASSERT_EQ(a.s_addr, ntp->s_addr); + ASSERT_OK(dhcp_message_get_option_address(m, SD_DHCP_OPTION_NTP_SERVER, &a)); + ASSERT_EQ(a.s_addr, ntp->s_addr); + + size_t n; + _cleanup_free_ struct in_addr *addrs = NULL; + ASSERT_OK(dhcp_message_get_option_addresses(m, SD_DHCP_OPTION_NTP_SERVER, &n, &addrs)); + ASSERT_EQ(n, n_ntp); + ASSERT_EQ(memcmp(addrs, ntp, sizeof(struct in_addr) * n), 0); +} + TEST(dhcp_message) { _cleanup_(sd_dhcp_message_unrefp) sd_dhcp_message *m = NULL; @@ -80,6 +97,14 @@ TEST(dhcp_message) { /* 192.0.2.42 */ struct in_addr addr = { .s_addr = htobe32(0xC000022a) }; + /* 192.0.2.1 - 4 */ + struct in_addr ntp[4] = { + { .s_addr = htobe32(0xC0000201) }, + { .s_addr = htobe32(0xC0000202) }, + { .s_addr = htobe32(0xC0000203) }, + { .s_addr = htobe32(0xC0000204) }, + }; + ASSERT_OK(dhcp_message_init_header( m, BOOTREQUEST, @@ -124,6 +149,11 @@ TEST(dhcp_message) { ASSERT_OK(dhcp_message_append_option_address(m, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, &addr)); verify_address(m, &addr); + /* multiple addresses */ + ASSERT_OK(dhcp_message_append_option_address(m, SD_DHCP_OPTION_NTP_SERVER, &ntp[0])); + ASSERT_OK(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_NTP_SERVER, ELEMENTSOF(ntp) - 1, ntp + 1)); + verify_addresses(m, ELEMENTSOF(ntp), ntp); + /* build and parse */ _cleanup_(iovw_done_free) struct iovec_wrapper iovw = {}; ASSERT_OK(dhcp_message_build(m, &iovw)); @@ -149,6 +179,7 @@ TEST(dhcp_message) { verify_u16(m2, 512); verify_sec(m2, lease_time); verify_address(m2, &addr); + verify_addresses(m2, ELEMENTSOF(ntp), ntp); /* build again, and verify the packet */ _cleanup_(iovw_done_free) struct iovec_wrapper iovw2 = {};