]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-dhcp-client.c
ssh-generator: generate /etc/issue.d/ with VSOCK ssh info data (#37819)
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-client.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
be391925 2/***
810adae9 3 Copyright © 2013 Intel Corporation. All rights reserved.
be391925
PF
4***/
5
ddb82ec2 6#include <net/if_arp.h>
39b7f596 7#include <stdio.h>
5cdf13c7 8#include <stdlib.h>
8c00042c
PF
9#include <sys/socket.h>
10#include <unistd.h>
50b35193
ZJS
11#if HAVE_VALGRIND_VALGRIND_H
12# include <valgrind/valgrind.h>
13#endif
be391925 14
07630cea 15#include "sd-dhcp-client.h"
5cdf13c7 16#include "sd-dhcp-lease.h"
6e00a806 17#include "sd-event.h"
290c7324 18
b5efdb8a 19#include "alloc-util.h"
97c3506d 20#include "dhcp-duid-internal.h"
9bcbb614 21#include "dhcp-network.h"
8664ded7
YW
22#include "dhcp-option.h"
23#include "dhcp-packet.h"
3b75435d 24#include "ether-addr-util.h"
3ffd4af2 25#include "fd-util.h"
93a1f792 26#include "log.h"
6d7c4033 27#include "tests.h"
be391925 28
3b75435d
YW
29static struct hw_addr_data hw_addr = {
30 .length = ETH_ALEN,
31 .ether = {{ 'A', 'B', 'C', '1', '2', '3' }},
32}, bcast_addr = {
33 .length = ETH_ALEN,
34 .ether = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }},
35};
6c8a0f07
PF
36typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
37
2871f967
CF
38struct bootp_addr_data {
39 uint8_t *offer_buf;
40 size_t offer_len;
41 int netmask_offset;
42 int ip_offset;
43};
44struct bootp_addr_data *bootp_test_context;
45
5bac5235 46static bool verbose = true;
8c00042c 47static int test_fd[2];
6c8a0f07 48static test_callback_recv_t callback_recv;
234ed3eb 49static be32_t xid;
8c00042c 50
52efd56a 51static void test_request_basic(sd_event *e) {
b25ef18b
TG
52 int r;
53
be391925
PF
54 sd_dhcp_client *client;
55
ede286f9 56 if (verbose)
38557d9f 57 log_info("* %s", __func__);
ede286f9 58
db3d2358 59 /* Initialize client without Anonymize settings. */
60 r = sd_dhcp_client_new(&client, false);
be391925 61
12e0f830
TG
62 assert_se(r >= 0);
63 assert_se(client);
be391925 64
b25ef18b 65 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 66 assert_se(r >= 0);
b25ef18b 67
8161f608
YW
68 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
69 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
70 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(NULL, 0) == -EINVAL);
be391925 71
2f8e7633 72 assert_se(sd_dhcp_client_set_ifindex(client, 15) == 0);
8161f608
YW
73 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(client, -42) == -EINVAL);
74 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(client, -1) == -EINVAL);
75 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(client, 0) == -EINVAL);
2f8e7633 76 assert_se(sd_dhcp_client_set_ifindex(client, 1) == 0);
be391925 77
9740eae6
SA
78 assert_se(sd_dhcp_client_set_hostname(client, "host") == 1);
79 assert_se(sd_dhcp_client_set_hostname(client, "host.domain") == 1);
80 assert_se(sd_dhcp_client_set_hostname(client, NULL) == 1);
81 assert_se(sd_dhcp_client_set_hostname(client, "~host") == -EINVAL);
82 assert_se(sd_dhcp_client_set_hostname(client, "~host.domain") == -EINVAL);
83
4081756a
YW
84 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_SUBNET_MASK) == 0);
85 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_ROUTER) == 0);
db3d2358 86 /* This PRL option is not set when using Anonymize, but in this test
87 * Anonymize settings are not being used. */
4081756a
YW
88 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 0);
89 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME) == 0);
90 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == 0);
91
92 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PAD) == -EINVAL);
93 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_END) == -EINVAL);
94 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
95 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
96 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
be391925 97
db3d2358 98 /* RFC7844: option 33 (SD_DHCP_OPTION_STATIC_ROUTE) is set in the
99 * default PRL when using Anonymize, so it is changed to other option
da172fa9
FK
100 * that is not set by default, to check that it was set successfully.
101 * Options not set by default (using or not anonymize) are option 17
db3d2358 102 * (SD_DHCP_OPTION_ROOT_PATH) and 42 (SD_DHCP_OPTION_NTP_SERVER) */
4081756a
YW
103 assert_se(sd_dhcp_client_set_request_option(client, 17) == 1);
104 assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
105 assert_se(sd_dhcp_client_set_request_option(client, 42) == 1);
db3d2358 106 assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
6e00a806
ZJS
107
108 sd_dhcp_client_unref(client);
be391925
PF
109}
110
dbb35f1f 111static void test_request_anonymize(sd_event *e) {
112 int r;
113
114 sd_dhcp_client *client;
115
116 if (verbose)
38557d9f 117 log_info("* %s", __func__);
dbb35f1f 118
119 /* Initialize client with Anonymize settings. */
120 r = sd_dhcp_client_new(&client, true);
121
122 assert_se(r >= 0);
123 assert_se(client);
124
125 r = sd_dhcp_client_attach_event(client, e, 0);
126 assert_se(r >= 0);
127
3cb62efe 128 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_NETBIOS_NAME_SERVER) == 0);
dbb35f1f 129 /* This PRL option is not set when using Anonymize */
4081756a
YW
130 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 1);
131 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
dbb35f1f 132
133 /* RFC7844: option 101 (SD_DHCP_OPTION_NEW_TZDB_TIMEZONE) is not set in the
134 * default PRL when using Anonymize, */
4081756a 135 assert_se(sd_dhcp_client_set_request_option(client, 101) == 1);
dbb35f1f 136 assert_se(sd_dhcp_client_set_request_option(client, 101) == 0);
dbb35f1f 137
138 sd_dhcp_client_unref(client);
139}
140
52efd56a 141static void test_checksum(void) {
39b7f596
PF
142 uint8_t buf[20] = {
143 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
144 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0xff, 0xff, 0xff, 0xff
146 };
147
ede286f9 148 if (verbose)
38557d9f 149 log_info("* %s", __func__);
ede286f9 150
0bbc2c1f 151 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
39b7f596
PF
152}
153
43fc0955 154static void test_dhcp_identifier_set_iaid(void) {
6d13616b
TH
155 uint32_t iaid_legacy;
156 be32_t iaid;
43fc0955 157
70201ae7
JW
158 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy_unstable_byteorder = */ true, &iaid_legacy) >= 0);
159 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy_unstable_byteorder = */ false, &iaid) >= 0);
43fc0955 160
6d13616b 161 /* we expect, that the MAC address was hashed. The legacy value is in native
43fc0955 162 * endianness. */
6d13616b
TH
163 assert_se(iaid_legacy == 0x8dde4ba8u);
164 assert_se(iaid == htole32(0x8dde4ba8u));
165#if __BYTE_ORDER == __LITTLE_ENDIAN
166 assert_se(iaid == iaid_legacy);
167#else
fe92eb79 168 assert_se(iaid == bswap_32(iaid_legacy));
6d13616b 169#endif
43fc0955
TH
170}
171
52efd56a 172static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
79893116 173 switch (code) {
5c9feb2d 174 case SD_DHCP_OPTION_CLIENT_IDENTIFIER: {
97c3506d 175 sd_dhcp_duid duid;
5bac5235 176 uint32_t iaid;
5bac5235 177
97c3506d 178 assert_se(sd_dhcp_duid_set_en(&duid) >= 0);
70201ae7 179 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy_unstable_byteorder = */ true, &iaid) >= 0);
5bac5235 180
97c3506d 181 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid.size);
5bac5235 182 assert_se(len == 19);
e4735228 183 assert_se(((uint8_t*) option)[0] == 0xff);
5bac5235 184
e4735228 185 assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
97c3506d 186 assert_se(memcmp((uint8_t*) option + 5, &duid.duid, duid.size) == 0);
d790d3f1 187 break;
5bac5235 188 }
d790d3f1
PF
189
190 default:
5c9feb2d 191 ;
d790d3f1
PF
192 }
193
290c7324
PF
194 return 0;
195}
196
52efd56a 197int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) {
290c7324 198 size_t size;
3d41b6b8 199 _cleanup_free_ DHCPPacket *discover = NULL;
290c7324 200 uint16_t ip_check, udp_check;
290c7324 201
12e0f830
TG
202 assert_se(s >= 0);
203 assert_se(packet);
290c7324 204
d47e1de4 205 size = sizeof(DHCPPacket);
12e0f830 206 assert_se(len > size);
290c7324
PF
207
208 discover = memdup(packet, len);
209
12e0f830
TG
210 assert_se(discover->ip.ttl == IPDEFTTL);
211 assert_se(discover->ip.protocol == IPPROTO_UDP);
212 assert_se(discover->ip.saddr == INADDR_ANY);
213 assert_se(discover->ip.daddr == INADDR_BROADCAST);
214 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
215 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
290c7324
PF
216
217 ip_check = discover->ip.check;
218
219 discover->ip.ttl = 0;
220 discover->ip.check = discover->udp.len;
221
0bbc2c1f 222 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
12e0f830 223 assert_se(udp_check == 0xffff);
290c7324
PF
224
225 discover->ip.ttl = IPDEFTTL;
226 discover->ip.check = ip_check;
227
0bbc2c1f 228 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
12e0f830 229 assert_se(ip_check == 0xffff);
290c7324 230
12e0f830 231 assert_se(discover->dhcp.xid);
3b75435d 232 assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0);
6c8a0f07 233
290c7324
PF
234 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
235
12e0f830 236 assert_se(callback_recv);
6c8a0f07 237 callback_recv(size, &discover->dhcp);
290c7324
PF
238
239 return 575;
240}
241
52efd56a 242int dhcp_network_bind_raw_socket(
1a6c9136 243 int ifindex,
52efd56a
LP
244 union sockaddr_union *link,
245 uint32_t id,
073a1daa
YW
246 const struct hw_addr_data *_hw_addr,
247 const struct hw_addr_data *_bcast_addr,
ea577968 248 uint16_t arp_type,
249 uint16_t port,
250 bool so_priority_set,
251 int so_priority) {
52efd56a 252
3e29b889 253 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
8c00042c
PF
254 return -errno;
255
256 return test_fd[0];
257}
258
afe42aef 259int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
fe0885f8
ZJS
260 int fd;
261
3e29b889 262 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
fe0885f8
ZJS
263 if (fd < 0)
264 return -errno;
265
266 return fd;
234fc2df
PF
267}
268
52efd56a 269int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) {
234fc2df
PF
270 return 0;
271}
272
52efd56a 273static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
6c8a0f07
PF
274 int res;
275
f693e9b3 276 res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
12e0f830 277 assert_se(res == DHCP_DISCOVER);
6c8a0f07
PF
278
279 if (verbose)
38557d9f 280 log_info(" recv DHCP Discover 0x%08x", be32toh(dhcp->xid));
6c8a0f07
PF
281
282 return 0;
283}
284
52efd56a 285static void test_discover_message(sd_event *e) {
290c7324 286 sd_dhcp_client *client;
b25ef18b 287 int res, r;
290c7324 288
ede286f9 289 if (verbose)
38557d9f 290 log_info("* %s", __func__);
ede286f9 291
db3d2358 292 r = sd_dhcp_client_new(&client, false);
12e0f830
TG
293 assert_se(r >= 0);
294 assert_se(client);
290c7324 295
b25ef18b 296 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 297 assert_se(r >= 0);
b25ef18b 298
2f8e7633 299 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
3b75435d 300 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
290c7324 301
12e0f830 302 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
290c7324 303
6c8a0f07
PF
304 callback_recv = test_discover_message_verify;
305
290c7324
PF
306 res = sd_dhcp_client_start(client);
307
4c701096 308 assert_se(IN_SET(res, 0, -EINPROGRESS));
8c00042c 309
f5fbe71d 310 sd_event_run(e, UINT64_MAX);
6c8a0f07
PF
311
312 sd_dhcp_client_stop(client);
e5b04c8d 313 sd_dhcp_client_unref(client);
6c8a0f07 314
2afa65c3 315 test_fd[1] = safe_close(test_fd[1]);
6c8a0f07
PF
316
317 callback_recv = NULL;
290c7324
PF
318}
319
234ed3eb
PF
320static uint8_t test_addr_acq_offer[] = {
321 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
322 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
323 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
324 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
325 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
327 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
355 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
356 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
357 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
358 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
359 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
360 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362};
363
364static uint8_t test_addr_acq_ack[] = {
365 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
366 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
367 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
368 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
370 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
371 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
372 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
373 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
374 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
399 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
d47e1de4 400 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
234ed3eb
PF
401 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
402 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
403 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
404 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406};
407
727b5734 408static int test_addr_acq_acquired(sd_dhcp_client *client, int event,
c4acff12 409 void *userdata) {
234ed3eb
PF
410 sd_event *e = userdata;
411 sd_dhcp_lease *lease;
412 struct in_addr addr;
f8862395 413 const struct in_addr *addrs;
234ed3eb 414
12e0f830 415 assert_se(client);
727b5734 416 assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
234ed3eb 417
12e0f830
TG
418 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
419 assert_se(lease);
234ed3eb 420
12e0f830
TG
421 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
422 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
234ed3eb
PF
423 sizeof(addr.s_addr)) == 0);
424
12e0f830
TG
425 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
426 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
234ed3eb
PF
427 sizeof(addr.s_addr)) == 0);
428
f8862395
TH
429 assert_se(sd_dhcp_lease_get_router(lease, &addrs) == 1);
430 assert_se(memcmp(&addrs[0].s_addr, &test_addr_acq_ack[308],
431 sizeof(addrs[0].s_addr)) == 0);
234ed3eb
PF
432
433 if (verbose)
38557d9f 434 log_info(" DHCP address acquired");
234ed3eb
PF
435
436 sd_event_exit(e, 0);
727b5734
SS
437
438 return 0;
234ed3eb
PF
439}
440
c4acff12 441static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
234ed3eb 442 uint16_t udp_check = 0;
d790d3f1 443 uint8_t *msg_bytes = (uint8_t *)request;
234ed3eb
PF
444 int res;
445
f693e9b3 446 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
12e0f830
TG
447 assert_se(res == DHCP_REQUEST);
448 assert_se(xid == request->xid);
234ed3eb 449
22805d92 450 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
d790d3f1 451
234ed3eb 452 if (verbose)
38557d9f 453 log_info(" recv DHCP Request 0x%08x", be32toh(xid));
234ed3eb
PF
454
455 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
456 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
3b75435d 457 memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length);
234ed3eb
PF
458
459 callback_recv = NULL;
460
461 res = write(test_fd[1], test_addr_acq_ack,
462 sizeof(test_addr_acq_ack));
12e0f830 463 assert_se(res == sizeof(test_addr_acq_ack));
234ed3eb
PF
464
465 if (verbose)
38557d9f 466 log_info(" send DHCP Ack");
234ed3eb
PF
467
468 return 0;
469};
470
c4acff12 471static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
234ed3eb 472 uint16_t udp_check = 0;
d790d3f1 473 uint8_t *msg_bytes = (uint8_t *)discover;
234ed3eb
PF
474 int res;
475
f693e9b3 476 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
12e0f830 477 assert_se(res == DHCP_DISCOVER);
234ed3eb 478
22805d92 479 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
d790d3f1 480
234ed3eb
PF
481 xid = discover->xid;
482
483 if (verbose)
38557d9f 484 log_info(" recv DHCP Discover 0x%08x", be32toh(xid));
234ed3eb
PF
485
486 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
487 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
3b75435d 488 memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length);
234ed3eb
PF
489
490 callback_recv = test_addr_acq_recv_request;
491
492 res = write(test_fd[1], test_addr_acq_offer,
493 sizeof(test_addr_acq_offer));
12e0f830 494 assert_se(res == sizeof(test_addr_acq_offer));
234ed3eb
PF
495
496 if (verbose)
38557d9f 497 log_info(" sent DHCP Offer");
234ed3eb
PF
498
499 return 0;
500}
501
c4acff12 502static void test_addr_acq(sd_event *e) {
234ed3eb
PF
503 sd_dhcp_client *client;
504 int res, r;
505
506 if (verbose)
38557d9f 507 log_info("* %s", __func__);
234ed3eb 508
db3d2358 509 r = sd_dhcp_client_new(&client, false);
12e0f830
TG
510 assert_se(r >= 0);
511 assert_se(client);
234ed3eb
PF
512
513 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 514 assert_se(r >= 0);
234ed3eb 515
2f8e7633 516 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
3b75435d 517 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
234ed3eb 518
afa3509a 519 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
234ed3eb
PF
520
521 callback_recv = test_addr_acq_recv_discover;
522
ba4e0427 523 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
f8ef1df3 524 30 * USEC_PER_SEC, 0,
2e37084f 525 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
8fc8e3ab 526
234ed3eb 527 res = sd_dhcp_client_start(client);
4c701096 528 assert_se(IN_SET(res, 0, -EINPROGRESS));
234ed3eb 529
3b981f74 530 assert_se(sd_event_loop(e) >= 0);
234ed3eb 531
fc292b5f
TG
532 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
533 assert_se(sd_dhcp_client_stop(client) >= 0);
e5b04c8d 534 sd_dhcp_client_unref(client);
234ed3eb 535
2afa65c3 536 test_fd[1] = safe_close(test_fd[1]);
234ed3eb
PF
537
538 callback_recv = NULL;
539 xid = 0;
540}
541
2871f967
CF
542static uint8_t test_addr_bootp_reply[] = {
543 0x45, 0x00, 0x01, 0x48, 0x00, 0x00, 0x40, 0x00,
544 0xff, 0x11, 0x70, 0xa3, 0x0a, 0x00, 0x00, 0x02,
545 0xff, 0xff, 0xff, 0xff, 0x00, 0x43, 0x00, 0x44,
546 0x01, 0x2c, 0x2b, 0x91, 0x02, 0x01, 0x06, 0x00,
547 0x69, 0xd3, 0x79, 0x11, 0x17, 0x00, 0x80, 0x00,
548 0x00, 0x00, 0x00, 0x00, 0x0a, 0x46, 0x00, 0x02,
549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
550 0x50, 0x2d, 0xf4, 0x1f, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0x00,
577 0x00, 0x00, 0x36, 0x04, 0x0a, 0x00, 0x00, 0x02,
578 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
579 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
580 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
581 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
582 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
583};
584
585static uint8_t test_addr_bootp_reply_bootpd[] = {
586 0x45, 0x00, 0x01, 0x48, 0xbe, 0xad, 0x40, 0x00,
587 0x40, 0x11, 0x73, 0x43, 0xc0, 0xa8, 0x43, 0x31,
588 0xc0, 0xa8, 0x43, 0x32, 0x00, 0x43, 0x00, 0x44,
589 0x01, 0x34, 0x08, 0xfa, 0x02, 0x01, 0x06, 0x00,
590 0x82, 0x57, 0xda, 0xf1, 0x00, 0x01, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x43, 0x32,
592 0xc0, 0xa8, 0x43, 0x31, 0x00, 0x00, 0x00, 0x00,
593 0xc2, 0x3e, 0xa5, 0x53, 0x57, 0x72, 0x00, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x00, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff,
620 0xff, 0xf0, 0x03, 0x04, 0xc0, 0xa8, 0x43, 0x31,
621 0x06, 0x04, 0x0a, 0x00, 0x01, 0x01, 0x0c, 0x15,
622 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x64,
623 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x74,
624 0x72, 0x69, 0x78, 0x69, 0x65, 0xff, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627};
628
629static struct bootp_addr_data bootp_addr_data[] = {
630 {
631 .offer_buf = test_addr_bootp_reply,
632 .offer_len = sizeof(test_addr_bootp_reply),
633 .netmask_offset = 270,
634 .ip_offset = 44,
635 },
636 {
637 .offer_buf = test_addr_bootp_reply_bootpd,
638 .offer_len = sizeof(test_addr_bootp_reply_bootpd),
639 .netmask_offset = 270,
640 .ip_offset = 44,
641 },
642};
643
644static int test_bootp_acquired(sd_dhcp_client *client, int event,
645 void *userdata) {
646 sd_dhcp_lease *lease = NULL;
647 sd_event *e = userdata;
648 struct in_addr addr;
649
650 ASSERT_NOT_NULL(client);
651 assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
652
653 ASSERT_OK(sd_dhcp_client_get_lease(client, &lease));
654 ASSERT_NOT_NULL(lease);
655
656 ASSERT_OK(sd_dhcp_lease_get_address(lease, &addr));
657 ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->ip_offset],
658 sizeof(addr.s_addr)), 0);
659
660 ASSERT_OK(sd_dhcp_lease_get_netmask(lease, &addr));
661 ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->netmask_offset],
662 sizeof(addr.s_addr)), 0);
663
664 if (verbose)
665 log_info(" BOOTP address acquired");
666
667 sd_event_exit(e, 0);
668
669 return 0;
670}
671
672static int test_bootp_recv_request(size_t size, DHCPMessage *request) {
673 uint16_t udp_check = 0;
674 size_t res;
675
676 xid = request->xid;
677
678 if (verbose)
679 log_info(" recv BOOTP Request 0x%08x", be32toh(xid));
680
681 callback_recv = NULL;
682
683 memcpy(&bootp_test_context->offer_buf[26], &udp_check, sizeof(udp_check));
684 memcpy(&bootp_test_context->offer_buf[32], &xid, sizeof(xid));
685 memcpy(&bootp_test_context->offer_buf[56], hw_addr.bytes, hw_addr.length);
686
687 res = write(test_fd[1], bootp_test_context->offer_buf,
688 bootp_test_context->offer_len);
689 ASSERT_EQ(res, bootp_test_context->offer_len);
690
691 if (verbose)
692 log_info(" sent BOOTP Reply");
693
694 return 0;
695};
696
697static void test_acquire_bootp(sd_event *e) {
698 sd_dhcp_client *client = NULL;
699 int res;
700
701 if (verbose)
702 log_info("* %s", __func__);
703
704 ASSERT_OK(sd_dhcp_client_new(&client, false));
705 ASSERT_NOT_NULL(client);
706
707 ASSERT_OK(sd_dhcp_client_attach_event(client, e, 0));
708
709 ASSERT_OK(sd_dhcp_client_set_bootp(client, true));
710
711 ASSERT_OK(sd_dhcp_client_set_ifindex(client, 42));
712 ASSERT_OK(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER));
713
714 ASSERT_OK(sd_dhcp_client_set_callback(client, test_bootp_acquired, e));
715
716 callback_recv = test_bootp_recv_request;
717
718 ASSERT_OK(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
719 30 * USEC_PER_SEC, 0,
720 NULL, INT_TO_PTR(-ETIMEDOUT)));
721
722 res = sd_dhcp_client_start(client);
723 assert_se(IN_SET(res, 0, -EINPROGRESS));
724
725 ASSERT_OK(sd_event_loop(e));
726
727 ASSERT_OK(sd_dhcp_client_set_callback(client, NULL, NULL));
728 ASSERT_OK(sd_dhcp_client_stop(client));
729 client = sd_dhcp_client_unref(client);
730 ASSERT_NULL(client);
731
732 test_fd[1] = safe_close(test_fd[1]);
733
734 callback_recv = NULL;
735 xid = 0;
736}
737
c4acff12 738int main(int argc, char *argv[]) {
4afd3348 739 _cleanup_(sd_event_unrefp) sd_event *e;
6e00a806 740
8b50b319
YW
741 assert_se(setenv("SYSTEMD_NETWORK_TEST_MODE", "1", 1) >= 0);
742
6d7c4033 743 test_setup_logging(LOG_DEBUG);
d3d8ac2f 744
12e0f830 745 assert_se(sd_event_new(&e) >= 0);
d3d8ac2f
PF
746
747 test_request_basic(e);
dbb35f1f 748 test_request_anonymize(e);
39b7f596 749 test_checksum();
43fc0955 750 test_dhcp_identifier_set_iaid();
be391925 751
d3d8ac2f 752 test_discover_message(e);
234ed3eb 753 test_addr_acq(e);
290c7324 754
2871f967
CF
755 FOREACH_ELEMENT(i, bootp_addr_data) {
756 sd_event_unref(e);
757 ASSERT_OK(sd_event_new(&e));
758 bootp_test_context = i;
759 test_acquire_bootp(e);
760 }
761
50b35193 762#if HAVE_VALGRIND_VALGRIND_H
374c22b3
ZJS
763 /* Make sure the async_close thread has finished.
764 * valgrind would report some of the phread_* structures
765 * as not cleaned up properly. */
50b35193
ZJS
766 if (RUNNING_ON_VALGRIND)
767 sleep(1);
374c22b3
ZJS
768#endif
769
be391925
PF
770 return 0;
771}