From 2871f967cc90a42ff952a82fd1db11007e1a9ab4 Mon Sep 17 00:00:00 2001 From: Colin Foster Date: Mon, 28 Oct 2024 19:50:06 -0500 Subject: [PATCH] test-dhcp-client: add test for bootp clients Verify that BOOTP replies are successfully handled by the sd-dhcp-client when configured for BOOTP. Co-authored-by: Avram Dorfman --- src/libsystemd-network/test-dhcp-client.c | 211 ++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 72d8ad4d0cf..cc08c3fbd22 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -35,6 +35,14 @@ static struct hw_addr_data hw_addr = { }; typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp); +struct bootp_addr_data { + uint8_t *offer_buf; + size_t offer_len; + int netmask_offset; + int ip_offset; +}; +struct bootp_addr_data *bootp_test_context; + static bool verbose = true; static int test_fd[2]; static test_callback_recv_t callback_recv; @@ -531,6 +539,202 @@ static void test_addr_acq(sd_event *e) { xid = 0; } +static uint8_t test_addr_bootp_reply[] = { + 0x45, 0x00, 0x01, 0x48, 0x00, 0x00, 0x40, 0x00, + 0xff, 0x11, 0x70, 0xa3, 0x0a, 0x00, 0x00, 0x02, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x43, 0x00, 0x44, + 0x01, 0x2c, 0x2b, 0x91, 0x02, 0x01, 0x06, 0x00, + 0x69, 0xd3, 0x79, 0x11, 0x17, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x46, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x2d, 0xf4, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0x00, + 0x00, 0x00, 0x36, 0x04, 0x0a, 0x00, 0x00, 0x02, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +static uint8_t test_addr_bootp_reply_bootpd[] = { + 0x45, 0x00, 0x01, 0x48, 0xbe, 0xad, 0x40, 0x00, + 0x40, 0x11, 0x73, 0x43, 0xc0, 0xa8, 0x43, 0x31, + 0xc0, 0xa8, 0x43, 0x32, 0x00, 0x43, 0x00, 0x44, + 0x01, 0x34, 0x08, 0xfa, 0x02, 0x01, 0x06, 0x00, + 0x82, 0x57, 0xda, 0xf1, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x43, 0x32, + 0xc0, 0xa8, 0x43, 0x31, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0x3e, 0xa5, 0x53, 0x57, 0x72, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, + 0xff, 0xf0, 0x03, 0x04, 0xc0, 0xa8, 0x43, 0x31, + 0x06, 0x04, 0x0a, 0x00, 0x01, 0x01, 0x0c, 0x15, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x74, + 0x72, 0x69, 0x78, 0x69, 0x65, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static struct bootp_addr_data bootp_addr_data[] = { + { + .offer_buf = test_addr_bootp_reply, + .offer_len = sizeof(test_addr_bootp_reply), + .netmask_offset = 270, + .ip_offset = 44, + }, + { + .offer_buf = test_addr_bootp_reply_bootpd, + .offer_len = sizeof(test_addr_bootp_reply_bootpd), + .netmask_offset = 270, + .ip_offset = 44, + }, +}; + +static int test_bootp_acquired(sd_dhcp_client *client, int event, + void *userdata) { + sd_dhcp_lease *lease = NULL; + sd_event *e = userdata; + struct in_addr addr; + + ASSERT_NOT_NULL(client); + assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING)); + + ASSERT_OK(sd_dhcp_client_get_lease(client, &lease)); + ASSERT_NOT_NULL(lease); + + ASSERT_OK(sd_dhcp_lease_get_address(lease, &addr)); + ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->ip_offset], + sizeof(addr.s_addr)), 0); + + ASSERT_OK(sd_dhcp_lease_get_netmask(lease, &addr)); + ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->netmask_offset], + sizeof(addr.s_addr)), 0); + + if (verbose) + log_info(" BOOTP address acquired"); + + sd_event_exit(e, 0); + + return 0; +} + +static int test_bootp_recv_request(size_t size, DHCPMessage *request) { + uint16_t udp_check = 0; + size_t res; + + xid = request->xid; + + if (verbose) + log_info(" recv BOOTP Request 0x%08x", be32toh(xid)); + + callback_recv = NULL; + + memcpy(&bootp_test_context->offer_buf[26], &udp_check, sizeof(udp_check)); + memcpy(&bootp_test_context->offer_buf[32], &xid, sizeof(xid)); + memcpy(&bootp_test_context->offer_buf[56], hw_addr.bytes, hw_addr.length); + + res = write(test_fd[1], bootp_test_context->offer_buf, + bootp_test_context->offer_len); + ASSERT_EQ(res, bootp_test_context->offer_len); + + if (verbose) + log_info(" sent BOOTP Reply"); + + return 0; +}; + +static void test_acquire_bootp(sd_event *e) { + sd_dhcp_client *client = NULL; + int res; + + if (verbose) + log_info("* %s", __func__); + + ASSERT_OK(sd_dhcp_client_new(&client, false)); + ASSERT_NOT_NULL(client); + + ASSERT_OK(sd_dhcp_client_attach_event(client, e, 0)); + + ASSERT_OK(sd_dhcp_client_set_bootp(client, true)); + + ASSERT_OK(sd_dhcp_client_set_ifindex(client, 42)); + ASSERT_OK(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER)); + + ASSERT_OK(sd_dhcp_client_set_callback(client, test_bootp_acquired, e)); + + callback_recv = test_bootp_recv_request; + + ASSERT_OK(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME, + 30 * USEC_PER_SEC, 0, + NULL, INT_TO_PTR(-ETIMEDOUT))); + + res = sd_dhcp_client_start(client); + assert_se(IN_SET(res, 0, -EINPROGRESS)); + + ASSERT_OK(sd_event_loop(e)); + + ASSERT_OK(sd_dhcp_client_set_callback(client, NULL, NULL)); + ASSERT_OK(sd_dhcp_client_stop(client)); + client = sd_dhcp_client_unref(client); + ASSERT_NULL(client); + + test_fd[1] = safe_close(test_fd[1]); + + callback_recv = NULL; + xid = 0; +} + int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e; @@ -548,6 +752,13 @@ int main(int argc, char *argv[]) { test_discover_message(e); test_addr_acq(e); + FOREACH_ELEMENT(i, bootp_addr_data) { + sd_event_unref(e); + ASSERT_OK(sd_event_new(&e)); + bootp_test_context = i; + test_acquire_bootp(e); + } + #if HAVE_VALGRIND_VALGRIND_H /* Make sure the async_close thread has finished. * valgrind would report some of the phread_* structures -- 2.47.3