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 <dorfman@est.org>
This commit is contained in:
Colin Foster
2024-10-28 19:50:06 -05:00
committed by Yu Watanabe
parent 4ad29bad7b
commit 2871f967cc

View File

@@ -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