From c73478d49fd2068318d28159cca204995a257dfb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 10 May 2026 23:04:15 +0900 Subject: [PATCH 1/4] dhcp-server-request: also save IP_PKTINFO of received message It will be used later. This also drops redundant ifindex check, as the socket is already initialized with socket_bind_to_ifindex(). --- src/libsystemd-network/dhcp-server-request.c | 12 ++++-------- src/libsystemd-network/dhcp-server-request.h | 3 ++- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/libsystemd-network/dhcp-server-request.c b/src/libsystemd-network/dhcp-server-request.c index a553fc43b62..a914f3ef1d6 100644 --- a/src/libsystemd-network/dhcp-server-request.c +++ b/src/libsystemd-network/dhcp-server-request.c @@ -426,7 +426,7 @@ static int dhcp_server_process_release(sd_dhcp_server *server, DHCPRequest *req) return 0; } -int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, const triple_timestamp *timestamp) { +int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, struct msghdr *mh) { int r; assert(server); @@ -437,7 +437,8 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz if (r < 0) return r; - dhcp_request_set_timestamp(req, timestamp); + dhcp_request_set_timestamp(req, mh ? TRIPLE_TIMESTAMP_FROM_CMSG(mh) : NULL); + req->pktinfo = mh ? CMSG_FIND_DATA(mh, IPPROTO_IP, IP_PKTINFO, struct in_pktinfo) : NULL; r = dhcp_server_cleanup_expired_leases(server); if (r < 0) @@ -493,12 +494,7 @@ static int server_receive_message(sd_event_source *s, int fd, uint32_t revents, return 0; } - /* TODO: figure out if this can be done as a filter on the socket, like for IPv6 */ - struct in_pktinfo *info = CMSG_FIND_DATA(&msg, IPPROTO_IP, IP_PKTINFO, struct in_pktinfo); - if (info && info->ipi_ifindex != server->ifindex) - return 0; - - r = dhcp_server_handle_message(server, buf, (size_t) len, TRIPLE_TIMESTAMP_FROM_CMSG(&msg)); + r = dhcp_server_handle_message(server, buf, (size_t) len, &msg); if (r < 0) log_dhcp_server_errno(server, r, "Couldn't process incoming message, ignoring: %m"); diff --git a/src/libsystemd-network/dhcp-server-request.h b/src/libsystemd-network/dhcp-server-request.h index f37d81bd145..161499a3ed5 100644 --- a/src/libsystemd-network/dhcp-server-request.h +++ b/src/libsystemd-network/dhcp-server-request.h @@ -17,6 +17,7 @@ typedef struct DHCPRequest { /* sender hardware address, may not be set for non-ethernet interface */ struct hw_addr_data hw_addr; triple_timestamp timestamp; + struct in_pktinfo *pktinfo; /* options */ uint8_t type; @@ -35,5 +36,5 @@ typedef struct DHCPRequest { int dhcp_request_get_lifetime_timestamp(DHCPRequest *req, clockid_t clock, usec_t *ret); -int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, const triple_timestamp *timestamp); +int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, struct msghdr *mh); int dhcp_server_setup_io_event_source(sd_dhcp_server *server); From 94b39d22ddba59c4b6ba2366b1d4f472e9497acb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 11 May 2026 00:25:02 +0900 Subject: [PATCH 2/4] dhcp-server-request: logs more when received invalid messages --- src/libsystemd-network/dhcp-server-request.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libsystemd-network/dhcp-server-request.c b/src/libsystemd-network/dhcp-server-request.c index a914f3ef1d6..6b6b85bae60 100644 --- a/src/libsystemd-network/dhcp-server-request.c +++ b/src/libsystemd-network/dhcp-server-request.c @@ -252,7 +252,7 @@ static int dhcp_server_process_discover(sd_dhcp_server *server, DHCPRequest *req sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(static_lease->address)); if (l && l != existing_lease) /* The address is already assigned to another host. Refusing. */ - return 0; + return -EADDRINUSE; /* Found a matching static lease. */ req->static_lease = static_lease; @@ -286,8 +286,7 @@ static int dhcp_server_process_discover(sd_dhcp_server *server, DHCPRequest *req } if (req->address == INADDR_ANY) - /* no free addresses left */ - return 0; + return -EADDRNOTAVAIL; /* no free addresses left */ if (server->rapid_commit && dhcp_message_get_option_flag(req->message, SD_DHCP_OPTION_RAPID_COMMIT) >= 0) @@ -319,7 +318,7 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) return 0; /* The message is not for us. Let's silently ignore the packet. */ if (req->message->header.ciaddr != INADDR_ANY) /* this MUST be zero */ - return 0; + return -EBADMSG; /* this must be filled in with the yiaddr from the chosen OFFER */ r = dhcp_message_get_option_be32(req->message, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, &address); From e294a8eada9e3cfaf420e0b6c0ab68a0af4aff2e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 11 May 2026 00:26:33 +0900 Subject: [PATCH 3/4] dhcp-server-request: rework when we should reply DHCPNAK Previously, DHCPNAK was sent only when the client is in INIT-REBOOT state. But, on selecting or renewing, the request is directed to a specific server, so we can safely reply with DHCPNAK. Also, verify existing bound lease even when there is no static lease for the client. --- src/libsystemd-network/dhcp-server-request.c | 129 +++++++++++++++---- src/libsystemd-network/test-dhcp-server.c | 8 +- 2 files changed, 111 insertions(+), 26 deletions(-) diff --git a/src/libsystemd-network/dhcp-server-request.c b/src/libsystemd-network/dhcp-server-request.c index 6b6b85bae60..036515d58ba 100644 --- a/src/libsystemd-network/dhcp-server-request.c +++ b/src/libsystemd-network/dhcp-server-request.c @@ -295,6 +295,65 @@ static int dhcp_server_process_discover(sd_dhcp_server *server, DHCPRequest *req return dhcp_server_send_reply(server, req, DHCP_OFFER); } +static int server_guess_client_state(sd_dhcp_server *server, DHCPRequest *req) { + int r; + + assert(server); + assert(req); + assert(req->message); + + /* This guesses the client is in the renewing or rebinding state. + * + * If giaddr is zero, then there is no relay agent between the client and us. In that case, a + * DHCPREQUEST sent to a unicast destination address implies the client is in RENEWING state, while a + * broadcast destination address implies REBINDING state. Note, if packet destination information is + * unavailable, we conservatively assume REBINDING. + * + * If giaddr is non-zero, then there is a relay agent. The relay forwards packets to us using unicast + * transport, so the outer IPv4 destination address no longer reflects whether the original client + * message was broadcast or unicast. If the message contains the Relay Agent Information option with + * Relay Agent Flags suboption, then we can know if the original message is unicast or broadcast. If + * the message does not have the option, then we assume the client is in the rebinding state. */ + + if (req->message->header.giaddr == INADDR_ANY) { + if (!req->pktinfo) + return DHCP_STATE_REBINDING; + + /* 255.255.255.255 ? */ + if (req->pktinfo->ipi_addr.s_addr == INADDR_BROADCAST) + return DHCP_STATE_REBINDING; + + /* subnet-directed broadcast, e.g., 192.0.2.0/24 -> 192.0.2.255 ? */ + if (req->pktinfo->ipi_addr.s_addr == (server->subnet | ~server->netmask)) + return DHCP_STATE_REBINDING; + + /* unicast, hence renewing. */ + return DHCP_STATE_RENEWING; + } + + _cleanup_(tlv_unrefp) TLV *agent_info = NULL; + r = dhcp_message_get_option_sub_tlv( + req->message, + SD_DHCP_OPTION_RELAY_AGENT_INFORMATION, + TLV_DHCP4_SUBOPTION, + &agent_info); + if (r == -ENODATA) + return DHCP_STATE_REBINDING; + if (r < 0) + return r; + + struct iovec iov = {}; + r = tlv_get_full(agent_info, SD_DHCP_RELAY_AGENT_FLAGS, sizeof(uint8_t), &iov); + if (r == -ENODATA) + return DHCP_STATE_REBINDING; + if (r < 0) + return r; + + assert(iov.iov_len == sizeof(uint8_t)); + uint8_t flags = *(const uint8_t*) iov.iov_base; + return FLAGS_SET(flags, DHCP_RELAY_AGENT_FLAG_UNICAST) ? DHCP_STATE_RENEWING : DHCP_STATE_REBINDING; +} + static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) { int r; @@ -305,15 +364,13 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) *existing_lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id), *static_lease = dhcp_server_get_static_lease(server, req); + DHCPState state; be32_t address; - bool init_reboot = false; /* see RFC 2131, section 4.3.2 */ if (req->server_address != INADDR_ANY) { - log_dhcp_server(server, "REQUEST (selecting) (0x%x)", - be32toh(req->message->header.xid)); + state = DHCP_STATE_SELECTING; - /* SELECTING */ if (req->server_address != server->address) return 0; /* The message is not for us. Let's silently ignore the packet. */ @@ -329,10 +386,10 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) return -EBADMSG; } else if (req->message->header.ciaddr != INADDR_ANY) { - log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)", - be32toh(req->message->header.xid)); - - /* REBINDING / RENEWING */ + r = server_guess_client_state(server, req); + if (r < 0) + return r; + state = r; /* this must NOT be filled */ if (dhcp_message_get_option_be32(req->message, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, /* ret= */ NULL) >= 0) @@ -341,20 +398,52 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) address = req->message->header.ciaddr; } else { - log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)", - be32toh(req->message->header.xid)); + state = DHCP_STATE_INIT_REBOOT; - /* INIT-REBOOT */ r = dhcp_message_get_option_be32(req->message, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, &address); if (r < 0) return r; if (address == INADDR_ANY) return -EBADMSG; - - init_reboot = true; } + log_dhcp_server(server, "REQUEST (%s) (0x%x)", dhcp_state_to_string(state), be32toh(req->message->header.xid)); + + /* In the below, when we found some inconsistency with the bound lease or static lease, we send + * DHCPNAK if the client is in the selecting, renewing, or init-reboot state. Otherwise, i.e., + * if in the rebinding state, we silently ignore the message. This is because, the network may have + * multiple DHCP servers, and the address may be managed by another server, and the request may be + * for that server. + * + * On selecting: + * We have already verified the message has matching server identifier, hence we have responsibility + * to manage the request, hence we should aggressively reply DHCPNAK. + * + * On renewing: + * The message is sent directly to us using unicast transport, so replying with DHCPNAK is unlikely + * to interfere with another server. + * + * On rebinding: + * The message is sent using broadcast delivery, hence if the network has multiple DHCP servers, then + * another server may reply DHCPACK. We should not disturb their process. Hence, silently ignore the + * message. + * + * On init-reboot: + * Even though the message is broadcast, for faster rebooting, we should aggressively reply DHCPNAK. + * Even if this is unnecessarily aggressive, the client will soon enter the usual DISCOVER -> REQUEST + * cycle, so that should not cause any big issues. */ + bool send_nak = IN_SET(state, DHCP_STATE_SELECTING, DHCP_STATE_RENEWING, DHCP_STATE_INIT_REBOOT); + + /* Check if the requested address is already assigned to another host. + * - if 'l' is NULL, then the address is not assigned to any host. + * - if 'l' is non-NULL, and equivalent to 'existing_lease', then the address is assigned to the host. + * - if 'l' is non-NULL, but different from 'existing_lease', then the address is already assigned to + * another host. In this case, we explicitly know that the address should not be used by the host. */ + sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address)); + if (l && l != existing_lease) + return send_nak ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0; + /* Check if the request is consistent with the static lease. */ if (static_lease) { /* Found a static lease for the client ID. In this case, the server is explicitly configured @@ -362,12 +451,7 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) if (static_lease->address != address) /* The client requested an address which is different from the static lease. Refusing. */ - return init_reboot ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0; - - sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address)); - if (l && l != existing_lease) - /* The requested address is already assigned to another host. Refusing. */ - return init_reboot ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0; + return send_nak ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0; req->static_lease = static_lease; req->address = address; @@ -376,14 +460,15 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) } if (dhcp_server_address_is_in_pool(server, address)) { - /* The requested address is in the pool. */ + /* The requested address is in the pool. In the above, we have checked the address is free or + * already assigned to the host. Hence, ACK. */ req->address = address; return dhcp_server_ack(server, req); } - /* Refuse otherwise. */ - if (init_reboot) + /* No static lease is configured for the host, and the requested address is not in our pool. Refusing. */ + if (send_nak) return dhcp_server_send_reply(server, req, DHCP_NAK); return 0; diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index a112c0632ad..ef4a9719ba3 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -218,11 +218,11 @@ TEST(dhcp_server_handle_message) { /* request neither bound nor static address */ test.option_type.type = DHCP_REQUEST; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 29); - ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL)); + ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); /* request the currently assigned address */ test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30); - ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL)); + ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); /* request the new static address */ test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 31); @@ -252,12 +252,12 @@ TEST(dhcp_server_handle_message) { /* request address reserved for static lease (unmatching client ID) */ test.option_client_id.id[6] = 'H'; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42); - ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL)); + ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); /* request unmatching address */ test.option_client_id.id[6] = 'G'; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 41); - ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL)); + ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); /* request matching address */ test.option_client_id.id[6] = 'G'; From b4f7e30d0b9b7b2734edffc12ed14d0298fd9022 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 11 May 2026 01:49:56 +0900 Subject: [PATCH 4/4] dhcp-server-request: rename dhcp_server_handle_message() -> dhcp_server_process_message() Then, make it take struct iovec. No functional change, just refactoring. --- src/libsystemd-network/dhcp-server-request.c | 8 +-- src/libsystemd-network/dhcp-server-request.h | 3 +- src/libsystemd-network/fuzz-dhcp-server.c | 5 +- src/libsystemd-network/test-dhcp-server.c | 61 ++++++++++---------- 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/libsystemd-network/dhcp-server-request.c b/src/libsystemd-network/dhcp-server-request.c index 036515d58ba..f7b835a8d26 100644 --- a/src/libsystemd-network/dhcp-server-request.c +++ b/src/libsystemd-network/dhcp-server-request.c @@ -510,14 +510,14 @@ static int dhcp_server_process_release(sd_dhcp_server *server, DHCPRequest *req) return 0; } -int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, struct msghdr *mh) { +int dhcp_server_process_message(sd_dhcp_server *server, const struct iovec *iov, struct msghdr *mh) { int r; assert(server); - assert(message); + assert(iov); _cleanup_(dhcp_request_freep) DHCPRequest *req = NULL; - r = dhcp_server_parse_message(server, &IOVEC_MAKE(message, length), &req); + r = dhcp_server_parse_message(server, iov, &req); if (r < 0) return r; @@ -578,7 +578,7 @@ static int server_receive_message(sd_event_source *s, int fd, uint32_t revents, return 0; } - r = dhcp_server_handle_message(server, buf, (size_t) len, &msg); + r = dhcp_server_process_message(server, &IOVEC_MAKE(buf, len), &msg); if (r < 0) log_dhcp_server_errno(server, r, "Couldn't process incoming message, ignoring: %m"); diff --git a/src/libsystemd-network/dhcp-server-request.h b/src/libsystemd-network/dhcp-server-request.h index 161499a3ed5..3fc9f02f8ab 100644 --- a/src/libsystemd-network/dhcp-server-request.h +++ b/src/libsystemd-network/dhcp-server-request.h @@ -5,7 +5,6 @@ #include "dhcp-client-id-internal.h" #include "dhcp-message.h" -#include "dhcp-protocol.h" #include "ether-addr-util.h" #include "sd-forward.h" #include "sparse-endian.h" @@ -36,5 +35,5 @@ typedef struct DHCPRequest { int dhcp_request_get_lifetime_timestamp(DHCPRequest *req, clockid_t clock, usec_t *ret); -int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, struct msghdr *mh); +int dhcp_server_process_message(sd_dhcp_server *server, const struct iovec *iov, struct msghdr *mh); int dhcp_server_setup_io_event_source(sd_dhcp_server *server); diff --git a/src/libsystemd-network/fuzz-dhcp-server.c b/src/libsystemd-network/fuzz-dhcp-server.c index 34c1f8371a9..408f1590a4f 100644 --- a/src/libsystemd-network/fuzz-dhcp-server.c +++ b/src/libsystemd-network/fuzz-dhcp-server.c @@ -7,9 +7,11 @@ #include "alloc-util.h" #include "dhcp-server-internal.h" #include "dhcp-server-lease-internal.h" +#include "dhcp-server-request.h" #include "fd-util.h" #include "fuzz.h" #include "hashmap.h" +#include "iovec-util.h" #include "rm-rf.h" #include "tests.h" #include "tmpfile-util.h" @@ -89,9 +91,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 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)); ASSERT_OK(sd_dhcp_server_start(server)); - (void) dhcp_server_handle_message(server, (DHCPMessage*) duped, size, NULL); + (void) dhcp_server_process_message(server, &IOVEC_MAKE(data, size), /* mh= */ NULL); ASSERT_OK(dhcp_server_save_leases(server)); server->bound_leases_by_address = hashmap_free(server->bound_leases_by_address); diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index ef4a9719ba3..18c6d1fd460 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -11,6 +11,7 @@ #include "dhcp-server-internal.h" #include "dhcp-server-request.h" #include "fd-util.h" +#include "iovec-util.h" #include "tests.h" TEST(basic) { @@ -60,7 +61,7 @@ TEST(basic) { ASSERT_OK(sd_dhcp_server_start(server)); } -TEST(dhcp_server_handle_message) { +TEST(dhcp_server_process_message) { struct { DHCPMessageHeader header; struct { @@ -131,61 +132,61 @@ TEST(dhcp_server_handle_message) { server->socket_fd = TAKE_FD(socket_fd[0]); ASSERT_OK(sd_dhcp_server_start(server)); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); test.end = 0; /* TODO, shouldn't this fail? */ - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); test.end = SD_DHCP_OPTION_END; - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); test.option_type.code = 0; test.option_type.length = 0; test.option_type.type = 0; - ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), ENODATA); + ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), ENODATA); test.option_type.code = SD_DHCP_OPTION_MESSAGE_TYPE; test.option_type.length = 1; test.option_type.type = DHCP_DISCOVER; - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); test.header.op = 0; - ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), EBADMSG); + ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), EBADMSG); test.header.op = BOOTREQUEST; - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); /* Neither client ID nor hardware type is set. There is no way to manage the bound lease for the request. */ test.header.htype = 0; - ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), EBADMSG); + ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), EBADMSG); test.header.htype = ARPHRD_ETHER; - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); test.header.hlen = 0; - ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), EBADMSG); + ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), EBADMSG); test.header.hlen = ETHER_ADDR_LEN; - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); /* DHCPREQUEST (init-boot) without requested IP */ test.option_type.type = DHCP_REQUEST; - ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), ENODATA); + ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), ENODATA); test.option_requested_ip.code = SD_DHCP_OPTION_REQUESTED_IP_ADDRESS; test.option_requested_ip.length = 4; test.option_requested_ip.address = htobe32(0x12345678); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK); test.option_server_id.code = SD_DHCP_OPTION_SERVER_IDENTIFIER; test.option_server_id.length = 4; test.option_server_id.address = htobe32(INADDR_LOOPBACK); test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); test.option_server_id.address = htobe32(0x12345678); test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); - ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL)); + ASSERT_OK_ZERO(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL)); test.option_server_id.address = htobe32(INADDR_LOOPBACK); test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 4); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); test.option_client_id.code = SD_DHCP_OPTION_CLIENT_IDENTIFIER; test.option_client_id.length = 7; @@ -196,10 +197,10 @@ TEST(dhcp_server_handle_message) { test.option_client_id.id[4] = 'D'; test.option_client_id.id[5] = 'E'; test.option_client_id.id[6] = 'F'; - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); /* add the static lease for the client ID */ ASSERT_OK(sd_dhcp_server_stop(server)); @@ -213,25 +214,25 @@ TEST(dhcp_server_handle_message) { /* discover */ test.option_type.type = DHCP_DISCOVER; - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER); /* request neither bound nor static address */ test.option_type.type = DHCP_REQUEST; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 29); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK); /* request the currently assigned address */ test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK); /* request the new static address */ test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 31); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); /* release the bound static lease */ test.header.ciaddr = htobe32(INADDR_LOOPBACK + 31); test.option_type.type = DHCP_RELEASE; - ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL)); + ASSERT_OK_ZERO(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL)); /* drop the static lease for the client ID */ ASSERT_OK(sd_dhcp_server_stop(server)); @@ -247,27 +248,27 @@ TEST(dhcp_server_handle_message) { test.header.ciaddr = 0; test.option_type.type = DHCP_REQUEST; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 29); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); /* request address reserved for static lease (unmatching client ID) */ test.option_client_id.id[6] = 'H'; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK); /* request unmatching address */ test.option_client_id.id[6] = 'G'; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 41); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK); /* request matching address */ test.option_client_id.id[6] = 'G'; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); /* try again */ test.option_client_id.id[6] = 'G'; test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42); - ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK); + ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK); } TEST(sd_dhcp_server_set_static_lease) {