]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dhcp-message: introduce dhcp_message_{append,get}_option_addresses()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 19 Apr 2026 06:19:41 +0000 (15:19 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 12 May 2026 15:27:49 +0000 (00:27 +0900)
These functions support multiple addresses.

These are for e.g. DHCP options 6 (DNS servers), 42 (NTP servers) and so on.

src/libsystemd-network/dhcp-message.c
src/libsystemd-network/dhcp-message.h
src/libsystemd-network/test-dhcp-message.c

index 6344a7a41aa7962866da7924e5bde1523511e1af..816d16955d6ba6cbc1d09aa89c346d10b672285f 100644 (file)
@@ -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,
index e0e5d8758836b4608acfb3aea0e1dc81b12412ac..6d4e1939b0f2c129565d9568e83fdad86554c5ce 100644 (file)
@@ -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,
index 92d22d4de1c88b2490b08918fb36e91b21c6c4cc..7c1c255f951f670c721efae47140e15fa6f8f151 100644 (file)
@@ -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 = {};