From 25482d832c00b084c65fe0f541d0203cdb11dfad Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 16 Apr 2026 03:02:27 +0900 Subject: [PATCH 1/5] sd-dhcp-lease: drop sd_dhcp_lease.have_subnet_mask and have_broadcast NULL address is invalid in both cases. Let's refuse to use them when NULL. --- src/libsystemd-network/dhcp-lease-internal.h | 4 ---- src/libsystemd-network/sd-dhcp-lease.c | 15 +++------------ 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index 3f5d638d67..b436287aee 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -40,11 +40,7 @@ struct sd_dhcp_lease { be32_t address; be32_t server_address; be32_t next_server; - - bool have_subnet_mask; be32_t subnet_mask; - - bool have_broadcast; be32_t broadcast; struct in_addr *router; diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 1eec439d81..bfe4874be5 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -69,7 +69,7 @@ int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (!lease->have_broadcast) + if (lease->broadcast == INADDR_ANY) return -ENODATA; addr->s_addr = lease->broadcast; @@ -259,7 +259,7 @@ int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (!lease->have_subnet_mask) + if (lease->subnet_mask == INADDR_ANY) return -ENODATA; addr->s_addr = lease->subnet_mask; @@ -920,16 +920,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void r = lease_parse_be32(option, len, &lease->subnet_mask); if (r < 0) log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m"); - else - lease->have_subnet_mask = true; break; case SD_DHCP_OPTION_BROADCAST: r = lease_parse_be32(option, len, &lease->broadcast); if (r < 0) log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m"); - else - lease->have_broadcast = true; break; case SD_DHCP_OPTION_ROUTER: @@ -1579,8 +1575,6 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { r = inet_pton(AF_INET, netmask, &lease->subnet_mask); if (r <= 0) log_debug("Failed to parse netmask %s, ignoring.", netmask); - else - lease->have_subnet_mask = true; } if (server_address) { @@ -1599,8 +1593,6 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { r = inet_pton(AF_INET, broadcast, &lease->broadcast); if (r <= 0) log_debug("Failed to parse broadcast address %s, ignoring.", broadcast); - else - lease->have_broadcast = true; } if (dns) { @@ -1759,7 +1751,7 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { assert(lease); - if (lease->have_subnet_mask) + if (lease->subnet_mask != INADDR_ANY) return 0; if (lease->address == 0) @@ -1773,7 +1765,6 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { return r; lease->subnet_mask = mask.s_addr; - lease->have_subnet_mask = true; return 0; } From e507487b6dde82a391e62b7c4dc5c9500d00a2e0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 2 May 2026 22:40:22 +0900 Subject: [PATCH 2/5] dhcp-protocol: introduce more sub-options for DHCP Relay Agent Information option These new values will be used later. --- src/libsystemd-network/dhcp-protocol.h | 5 +++++ src/systemd/sd-dhcp-protocol.h | 27 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index c2df5a574a..49f0125b20 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -124,4 +124,9 @@ enum { DHCP_FQDN_FLAG_N = (1 << 3), }; +/* For SD_DHCP_RELAY_AGENT_FLAGS sub-option. */ +enum { + DHCP_RELAY_AGENT_FLAG_UNICAST = 1 << 0, +}; + DECLARE_STRING_TABLE_LOOKUP_TO_STRING(dhcp_option_code, int); diff --git a/src/systemd/sd-dhcp-protocol.h b/src/systemd/sd-dhcp-protocol.h index 55ce189cf4..8ba28777a3 100644 --- a/src/systemd/sd-dhcp-protocol.h +++ b/src/systemd/sd-dhcp-protocol.h @@ -193,10 +193,31 @@ enum { SD_DHCP_OPTION_END = 255 /* [RFC2132] */ }; -/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */ +/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option. See + * https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#relay-agent-sub-options */ enum { - SD_DHCP_RELAY_AGENT_CIRCUIT_ID = 1, - SD_DHCP_RELAY_AGENT_REMOTE_ID = 2 + SD_DHCP_RELAY_AGENT_CIRCUIT_ID = 1, + SD_DHCP_RELAY_AGENT_REMOTE_ID = 2, + /* suboption code 3 is reserved */ + SD_DHCP_RELAY_AGENT_DOCSIS_DEVICE_CLASS = 4, + SD_DHCP_RELAY_AGENT_LINK_SELECTION = 5, + SD_DHCP_RELAY_AGENT_SUBSCRIBER_ID = 6, + SD_DHCP_RELAY_AGENT_RADIUS_ATTRIBUTE = 7, + SD_DHCP_RELAY_AGENT_AUTHENTICATION = 8, + SD_DHCP_RELAY_AGENT_VENDOR_SPECIFIC_INFORMATION = 9, + SD_DHCP_RELAY_AGENT_FLAGS = 10, + SD_DHCP_RELAY_AGENT_SERVER_IDENTIFIER_OVERRIDE = 11, + SD_DHCP_RELAY_AGENT_IDENTIFIER = 12, + SD_DHCP_RELAY_AGENT_ACCESS_TECHNOLOGY_TYPE = 13, + SD_DHCP_RELAY_AGENT_ACCESS_NETWORK_NAME = 14, + SD_DHCP_RELAY_AGENT_ACCESS_POINT_NAME = 15, + SD_DHCP_RELAY_AGENT_ACCESS_POINT_BSSID = 16, + SD_DHCP_RELAY_AGENT_OPERATOR_IDENTIFIER = 17, + SD_DHCP_RELAY_AGENT_OPERATOR_REALM = 18, + SD_DHCP_RELAY_AGENT_SOURCE_PORT = 19, + /* suboption code 20-150 are unassigned */ + SD_DHCP_RELAY_AGENT_VIRTUAL_SUBNET_SELECTION = 151, + SD_DHCP_RELAY_AGENT_VIRTUAL_SUBNET_SELECTION_CONTROL = 152 }; _SD_END_DECLARATIONS; From f51e7eeb7c29020fb43b307b7dd09bb630cba1a0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 4 May 2026 14:16:00 +0900 Subject: [PATCH 3/5] fuzz: modernize fuzz-dhcp-server - Do not include .c file. - Use ASSERT_OK() and friends. --- src/libsystemd-network/fuzz-dhcp-server.c | 55 +++++++++++------------ 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/libsystemd-network/fuzz-dhcp-server.c b/src/libsystemd-network/fuzz-dhcp-server.c index bcd8af629e..037acdec07 100644 --- a/src/libsystemd-network/fuzz-dhcp-server.c +++ b/src/libsystemd-network/fuzz-dhcp-server.c @@ -1,22 +1,19 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include #include +#include "sd-event.h" + +#include "alloc-util.h" +#include "dhcp-server-internal.h" +#include "dhcp-server-lease-internal.h" +#include "fd-util.h" #include "fuzz.h" +#include "hashmap.h" #include "rm-rf.h" -#include "sd-dhcp-server.c" +#include "tests.h" #include "tmpfile-util.h" -/* stub out network so that the server doesn't send */ -ssize_t sendto(int __fd, const void *__buf, size_t __n, int flags, const struct sockaddr *__addr, socklen_t __addr_len) { - return __n; -} - -ssize_t sendmsg(int __fd, const struct msghdr *__message, int flags) { - return 0; -} - static int add_lease(sd_dhcp_server *server, const struct in_addr *server_address, uint8_t i) { _cleanup_(sd_dhcp_server_lease_unrefp) sd_dhcp_server_lease *lease = NULL; int r; @@ -64,43 +61,41 @@ static int add_static_lease(sd_dhcp_server *server, uint8_t i) { } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL; - _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; struct in_addr address = { .s_addr = htobe32(UINT32_C(10) << 24 | UINT32_C(1))}; - _cleanup_free_ uint8_t *duped = NULL; - _cleanup_close_ int dir_fd = -EBADF; if (size < sizeof(DHCPMessage)) return 0; fuzz_setup_logging(); - assert_se(duped = memdup(data, size)); + _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL; + _cleanup_close_ int dir_fd = ASSERT_OK(mkdtemp_open(NULL, 0, &tmpdir)); - dir_fd = mkdtemp_open(NULL, 0, &tmpdir); - assert_se(dir_fd >= 0); + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + ASSERT_OK(sd_event_new(&event)); - assert_se(sd_dhcp_server_new(&server, 1) >= 0); - assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0); - assert_se(sd_dhcp_server_set_lease_file(server, dir_fd, "leases") >= 0); - server->fd = open("/dev/null", O_RDWR|O_CLOEXEC|O_NOCTTY); - assert_se(server->fd >= 0); - assert_se(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0) >= 0); + _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; + ASSERT_OK(sd_dhcp_server_new(&server, 1)); + ASSERT_OK(sd_dhcp_server_attach_event(server, event, SD_EVENT_PRIORITY_NORMAL)); + server->fd = ASSERT_OK_ERRNO(open("/dev/null", O_RDWR|O_CLOEXEC|O_NOCTTY)); + ASSERT_OK(sd_dhcp_server_set_lease_file(server, dir_fd, "leases")); + ASSERT_OK(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0)); /* add leases to the pool to expose additional code paths */ - assert_se(add_lease(server, &address, 2) >= 0); - assert_se(add_lease(server, &address, 3) >= 0); + ASSERT_OK(add_lease(server, &address, 2)); + ASSERT_OK(add_lease(server, &address, 3)); /* add static leases */ - assert_se(add_static_lease(server, 3) >= 0); - assert_se(add_static_lease(server, 4) >= 0); + ASSERT_OK(add_static_lease(server, 3)); + ASSERT_OK(add_static_lease(server, 4)); + _cleanup_free_ uint8_t *duped = ASSERT_NOT_NULL(memdup(data, size)); (void) dhcp_server_handle_message(server, (DHCPMessage*) duped, size, NULL); - assert_se(dhcp_server_save_leases(server) >= 0); + ASSERT_OK(dhcp_server_save_leases(server)); server->bound_leases_by_address = hashmap_free(server->bound_leases_by_address); server->bound_leases_by_client_id = hashmap_free(server->bound_leases_by_client_id); - assert_se(dhcp_server_load_leases(server) >= 0); + ASSERT_OK(dhcp_server_load_leases(server)); return 0; } From 9179cb31ed9ddf8b5189b63b075816fd0ef222a9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 7 May 2026 11:18:05 +0900 Subject: [PATCH 4/5] sd-dhcp-server: coding style fix --- src/libsystemd-network/sd-dhcp-server.c | 4 ++-- src/systemd/sd-dhcp-server.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 48c481809f..a377f9398e 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -119,7 +119,7 @@ int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) { return in4_addr_is_set(&server->relay_target); } -static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) { +static sd_dhcp_server* dhcp_server_free(sd_dhcp_server *server) { assert(server); sd_dhcp_server_stop(server); @@ -236,7 +236,7 @@ int sd_dhcp_server_detach_event(sd_dhcp_server *server) { return 0; } -sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) { +sd_event* sd_dhcp_server_get_event(sd_dhcp_server *server) { assert_return(server, NULL); return server->event; diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 4f2fc68835..1fb7d2e9ee 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -41,7 +41,7 @@ _SD_DECLARE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server); int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority); int sd_dhcp_server_detach_event(sd_dhcp_server *server); -sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server); +sd_event* sd_dhcp_server_get_event(sd_dhcp_server *server); typedef void (*sd_dhcp_server_callback_t)(sd_dhcp_server *server, uint64_t event, void *userdata); From 74f3cc4576b527e85b9f7ee6e53d03469e7e25cb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 10 May 2026 22:28:03 +0900 Subject: [PATCH 5/5] sd-dhcp-server-lease: rename dhcp_server_lease_append_json() -> dhcp_server_lease_build_json() It does not append, but build a new JSON variant. --- src/libsystemd-network/sd-dhcp-server-lease.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server-lease.c b/src/libsystemd-network/sd-dhcp-server-lease.c index 0268bbf2c2..a7d9947c29 100644 --- a/src/libsystemd-network/sd-dhcp-server-lease.c +++ b/src/libsystemd-network/sd-dhcp-server-lease.c @@ -237,7 +237,7 @@ int sd_dhcp_server_set_static_lease( return 0; } -static int dhcp_server_lease_append_json(sd_dhcp_server_lease *lease, sd_json_variant **ret) { +static int dhcp_server_lease_build_json(sd_dhcp_server_lease *lease, sd_json_variant **ret) { assert(lease); assert(ret); @@ -271,7 +271,7 @@ int dhcp_server_bound_leases_append_json(sd_dhcp_server *server, sd_json_variant HASHMAP_FOREACH(lease, server->bound_leases_by_client_id) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL; - r = dhcp_server_lease_append_json(lease, &w); + r = dhcp_server_lease_build_json(lease, &w); if (r < 0) return r; @@ -303,7 +303,7 @@ int dhcp_server_static_leases_append_json(sd_dhcp_server *server, sd_json_varian HASHMAP_FOREACH(lease, server->static_leases_by_client_id) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL; - r = dhcp_server_lease_append_json(lease, &w); + r = dhcp_server_lease_build_json(lease, &w); if (r < 0) return r;