dhcp: cleanups for sd-dhcp-lease.c and rewrite test-dhcp-client (#42135)

This commit is contained in:
Yu Watanabe
2026-05-17 20:12:37 +09:00
committed by GitHub
7 changed files with 1378 additions and 596 deletions

View File

@@ -30,6 +30,8 @@ DECLARE_STRING_TABLE_LOOKUP_TO_STRING(dhcp_state, DHCPState);
struct sd_dhcp_client {
unsigned n_ref;
int socket_fd; /* socket fd set externally, used by unit tests */
DHCPState state;
sd_event *event;
int event_priority;

View File

@@ -20,6 +20,10 @@ static int client_get_socket(sd_dhcp_client *client, int domain) {
assert(client);
assert(IN_SET(domain, AF_PACKET, AF_INET));
/* When a socket fd is given externally, unconditionally use it. */
if (client->socket_fd >= 0)
return client->socket_fd;
if (!client->receive_message)
return -EBADF;
@@ -50,6 +54,12 @@ static int client_setup_io_event(
assert(callback);
assert(description);
/* When the socket fd is given externally, the fd is used for both UDP and RAW packet operations.
* Hence, first we need to disable the previous event source, otherwise sd_event_add_io() will fail
* with -EEXIST. */
if (fd == client->socket_fd)
client->receive_message = sd_event_source_disable_unref(client->receive_message);
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
r = sd_event_add_io(client->event, &s, fd, EPOLLIN, callback, client);
if (r < 0)
@@ -63,9 +73,14 @@ static int client_setup_io_event(
if (r < 0)
return r;
r = sd_event_source_set_io_fd_own(s, true);
if (r < 0)
return r;
/* When the socket fd is given externally, do not close it while we are running. The IO event source
* is freed when not necessary, hence the lifetime of the socket fd should not be tied to the one of
* the event source in that case. */
if (fd != client->socket_fd) {
r = sd_event_source_set_io_fd_own(s, true);
if (r < 0)
return r;
}
sd_event_source_disable_unref(client->receive_message);
client->receive_message = TAKE_PTR(s);
@@ -143,7 +158,7 @@ static int client_send_raw(
return 0;
}
if (fd_close < 0)
if (fd_close < 0 && fd != client->socket_fd)
return 0; /* Already opened socket is reused. Not necessary to setup new IO event source. */
r = client_setup_io_event(client, fd, client_receive_message_raw, "dhcp4-receive-message-raw");
@@ -200,7 +215,7 @@ static int client_send_udp(
return 0;
}
if (fd_close < 0)
if (fd_close < 0 && fd != client->socket_fd)
return 0; /* Already opened socket is reused. Not necessary to setup new IO event source. */
r = client_setup_io_event(client, fd, client_receive_message_udp, "dhcp4-receive-message-udp");

View File

@@ -9,41 +9,20 @@
#include "dhcp-client-internal.h"
#include "dhcp-lease-internal.h"
#include "dhcp-message.h"
#include "dhcp-network.h"
#include "fd-util.h"
#include "fuzz.h"
#include "iovec-util.h"
#include "iovec-wrapper.h"
#include "tests.h"
int dhcp_network_bind_raw_socket(
int ifindex,
union sockaddr_union *link,
uint32_t id,
const struct hw_addr_data *hw_addr,
const struct hw_addr_data *bcast_addr,
uint16_t arp_type,
uint16_t port,
bool so_priority_set,
int so_priority) {
return ASSERT_OK_ERRNO(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
}
int dhcp_network_send_raw_socket(int fd, const union sockaddr_union *link, const struct iovec_wrapper *iovw) {
return 0;
}
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
return ASSERT_OK_ERRNO(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
}
int dhcp_network_send_udp_socket(int fd, be32_t address, uint16_t port, const struct iovec_wrapper *iovw) {
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
static const uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
static const uint8_t bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static const struct hw_addr_data hw_addr = {
.length = ETH_ALEN,
.ether = {{ 'A', 'B', 'C', '1', '2', '3' }},
}, bcast_addr = {
.length = ETH_ALEN,
.ether = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }},
};
ASSERT_OK_ERRNO(setenv("SYSTEMD_NETWORK_TEST_MODE", "1", /* overwrite= */ true));
@@ -57,10 +36,25 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ASSERT_OK(sd_dhcp_client_new(&client));
ASSERT_NOT_NULL(client);
_cleanup_close_pair_ int socket_fd[2] = EBADF_PAIR;
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, socket_fd));
client->socket_fd = TAKE_FD(socket_fd[0]);
/* Set a fake socket address, as the client will never call dhcp_network_bind_raw_socket() when
* socket_fd is set. */
client->link.ll = (struct sockaddr_ll) {
.sll_family = AF_PACKET,
.sll_protocol = htobe16(ETH_P_IP),
.sll_ifindex = 42,
.sll_hatype = ARPHRD_ETHER,
.sll_halen = bcast_addr.length,
};
memcpy(client->link.ll.sll_addr, bcast_addr.bytes, bcast_addr.length);
ASSERT_OK(sd_dhcp_client_attach_event(client, e, /* priority= */ 0));
ASSERT_OK(sd_dhcp_client_set_ifindex(client, 42));
ASSERT_OK(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER));
ASSERT_OK(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER));
ASSERT_OK(sd_dhcp_client_start(client));
client->xid = 2;

View File

@@ -15,6 +15,7 @@
#include "dns-domain.h"
#include "errno-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "iovec-util.h"
#include "iovec-wrapper.h"
@@ -1387,6 +1388,8 @@ static sd_dhcp_client* dhcp_client_free(sd_dhcp_client *client) {
client_initialize(client);
safe_close(client->socket_fd);
sd_event_source_unref(client->timeout_resend);
sd_event_source_unref(client->timeout_t1);
sd_event_source_unref(client->timeout_t2);
@@ -1420,6 +1423,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) {
*client = (sd_dhcp_client) {
.n_ref = 1,
.socket_fd = -EBADF,
.state = DHCP_STATE_STOPPED,
.ifindex = -1,
.port = DHCP_PORT_CLIENT,

View File

@@ -33,67 +33,67 @@ int sd_dhcp_lease_get_timestamp(sd_dhcp_lease *lease, clockid_t clock, uint64_t
assert_return(lease, -EINVAL);
assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
assert_return(clock_supported(clock), -EOPNOTSUPP);
assert_return(ret, -EINVAL);
if (!triple_timestamp_is_set(&lease->timestamp))
return -ENODATA;
*ret = triple_timestamp_by_clock(&lease->timestamp, clock);
if (ret)
*ret = triple_timestamp_by_clock(&lease->timestamp, clock);
return 0;
}
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *ret) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
if (lease->address == 0)
if (lease->address == INADDR_ANY)
return -ENODATA;
addr->s_addr = lease->address;
if (ret)
ret->s_addr = lease->address;
return 0;
}
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *ret) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
if (lease->broadcast == INADDR_ANY)
return -ENODATA;
addr->s_addr = lease->broadcast;
if (ret)
ret->s_addr = lease->broadcast;
return 0;
}
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint64_t *ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (lease->lifetime <= 0)
return -ENODATA;
*ret = lease->lifetime;
if (ret)
*ret = lease->lifetime;
return 0;
}
int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint64_t *ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (lease->t1 <= 0)
return -ENODATA;
*ret = lease->t1;
if (ret)
*ret = lease->t1;
return 0;
}
int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint64_t *ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (lease->t2 <= 0)
return -ENODATA;
*ret = lease->t2;
if (ret)
*ret = lease->t2;
return 0;
}
@@ -106,7 +106,7 @@ int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint64_t *ret) {
usec_t t, timestamp; \
int r; \
\
assert_return(ret, -EINVAL); \
assert_return(lease, -EINVAL); \
\
r = sd_dhcp_lease_get_##name(lease, &t); \
if (r < 0) \
@@ -116,7 +116,8 @@ int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint64_t *ret) {
if (r < 0) \
return r; \
\
*ret = usec_add(t, timestamp); \
if (ret) \
*ret = usec_add(t, timestamp); \
return 0; \
}
@@ -124,21 +125,21 @@ DEFINE_GET_TIMESTAMP(lifetime);
DEFINE_GET_TIMESTAMP(t1);
DEFINE_GET_TIMESTAMP(t2);
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *ret) {
assert_return(lease, -EINVAL);
assert_return(mtu, -EINVAL);
if (lease->mtu <= 0)
return -ENODATA;
*mtu = lease->mtu;
if (ret)
*ret = lease->mtu;
return 0;
}
int sd_dhcp_lease_get_servers(
sd_dhcp_lease *lease,
sd_dhcp_lease_server_type_t what,
const struct in_addr **addr) {
const struct in_addr **ret) {
assert_return(lease, -EINVAL);
assert_return(what >= 0, -EINVAL);
@@ -147,30 +148,30 @@ int sd_dhcp_lease_get_servers(
if (lease->servers[what].size <= 0)
return -ENODATA;
if (addr)
*addr = lease->servers[what].addr;
if (ret)
*ret = lease->servers[what].addr;
return (int) lease->servers[what].size;
}
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, addr);
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **ret) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, ret);
}
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, addr);
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **ret) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, ret);
}
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, addr);
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **ret) {
return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, ret);
}
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **ret) {
assert_return(lease, -EINVAL);
assert_return(domainname, -EINVAL);
if (!lease->domainname)
return -ENODATA;
*domainname = lease->domainname;
if (ret)
*ret = lease->domainname;
return 0;
}
@@ -187,45 +188,45 @@ int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **ret) {
int sd_dhcp_lease_get_captive_portal(sd_dhcp_lease *lease, const char **ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (!lease->captive_portal)
return -ENODATA;
*ret = lease->captive_portal;
if (ret)
*ret = lease->captive_portal;
return 0;
}
int sd_dhcp_lease_get_dnr(sd_dhcp_lease *lease, sd_dns_resolver **ret_resolvers) {
int sd_dhcp_lease_get_dnr(sd_dhcp_lease *lease, sd_dns_resolver **ret) {
assert_return(lease, -EINVAL);
assert_return(ret_resolvers, -EINVAL);
if (!lease->dnr)
return -ENODATA;
*ret_resolvers = lease->dnr;
if (ret)
*ret = lease->dnr;
return lease->n_dnr;
}
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **ret) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
if (lease->router_size <= 0)
return -ENODATA;
*addr = lease->router;
if (ret)
*ret = lease->router;
return (int) lease->router_size;
}
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *ret) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
if (lease->subnet_mask == INADDR_ANY)
return -ENODATA;
addr->s_addr = lease->subnet_mask;
if (ret)
ret->s_addr = lease->subnet_mask;
return 0;
}
@@ -257,14 +258,14 @@ int sd_dhcp_lease_get_prefix(sd_dhcp_lease *lease, struct in_addr *ret_prefix, u
return 0;
}
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ret) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
if (lease->server_address == 0)
if (lease->server_address == INADDR_ANY)
return -ENODATA;
addr->s_addr = lease->server_address;
if (ret)
ret->s_addr = lease->server_address;
return 0;
}
@@ -306,19 +307,16 @@ int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***re
return dhcp_lease_get_routes(lease->classless_routes, lease->n_classless_routes, ret);
}
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
size_t r;
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***ret) {
assert_return(lease, -EINVAL);
assert_return(domains, -EINVAL);
r = strv_length(lease->search_domains);
if (r > 0) {
*domains = lease->search_domains;
return (int) r;
}
size_t n = strv_length(lease->search_domains);
if (n == 0)
return -ENODATA;
return -ENODATA;
if (ret)
*ret = lease->search_domains;
return (int) n;
}
int sd_dhcp_lease_get_6rd(
@@ -352,7 +350,7 @@ int sd_dhcp_lease_has_6rd(sd_dhcp_lease *lease) {
return lease && lease->sixrd_n_br_addresses > 0;
}
static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
static sd_dhcp_lease* dhcp_lease_free(sd_dhcp_lease *lease) {
assert(lease);
sd_dhcp_message_unref(lease->message);
@@ -393,12 +391,12 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (!lease->timezone)
return -ENODATA;
*ret = lease->timezone;
if (ret)
*ret = lease->timezone;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,7 @@ __extension__ typedef enum _SD_ENUM_TYPE_S64(sd_dhcp_lease_server_type_t) {
_SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE)
} sd_dhcp_lease_server_type_t;
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *ret);
int sd_dhcp_lease_get_timestamp(sd_dhcp_lease *lease, clockid_t clock, uint64_t *ret);
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint64_t *ret);
int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint64_t *ret);
@@ -52,21 +52,21 @@ int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint64_t *ret);
int sd_dhcp_lease_get_lifetime_timestamp(sd_dhcp_lease *lease, clockid_t clock, uint64_t *ret);
int sd_dhcp_lease_get_t1_timestamp(sd_dhcp_lease *lease, clockid_t clock, uint64_t *ret);
int sd_dhcp_lease_get_t2_timestamp(sd_dhcp_lease *lease, clockid_t clock, uint64_t *ret);
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *ret);
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *ret);
int sd_dhcp_lease_get_prefix(sd_dhcp_lease *lease, struct in_addr *ret_prefix, uint8_t *ret_prefixlen);
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **ret);
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ret);
int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **ret);
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **ret);
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **ret);
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **ret);
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *ret);
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **ret);
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***ret);
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **ret);
int sd_dhcp_lease_get_captive_portal(sd_dhcp_lease *lease, const char **ret);
int sd_dhcp_lease_get_dnr(sd_dhcp_lease *lease, sd_dns_resolver **ret_resolvers);
int sd_dhcp_lease_get_dnr(sd_dhcp_lease *lease, sd_dns_resolver **ret);
int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **ret);