]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp-client.c
Merge pull request #24813 from DaanDeMeyer/at-all-the-things
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-client.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2013 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <errno.h>
7 #include <net/if.h>
8 #include <net/if_arp.h>
9 #include <stdio.h>
10 #include <sys/socket.h>
11 #include <unistd.h>
12
13 #include "sd-dhcp-client.h"
14 #include "sd-event.h"
15
16 #include "alloc-util.h"
17 #include "dhcp-identifier.h"
18 #include "dhcp-internal.h"
19 #include "dhcp-protocol.h"
20 #include "ether-addr-util.h"
21 #include "fd-util.h"
22 #include "random-util.h"
23 #include "tests.h"
24
25 static struct hw_addr_data hw_addr = {
26 .length = ETH_ALEN,
27 .ether = {{ 'A', 'B', 'C', '1', '2', '3' }},
28 }, bcast_addr = {
29 .length = ETH_ALEN,
30 .ether = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }},
31 };
32 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
33
34 static bool verbose = true;
35 static int test_fd[2];
36 static test_callback_recv_t callback_recv;
37 static be32_t xid;
38
39 static void test_request_basic(sd_event *e) {
40 int r;
41
42 sd_dhcp_client *client;
43
44 if (verbose)
45 printf("* %s\n", __func__);
46
47 /* Initialize client without Anonymize settings. */
48 r = sd_dhcp_client_new(&client, false);
49
50 assert_se(r >= 0);
51 assert_se(client);
52
53 r = sd_dhcp_client_attach_event(client, e, 0);
54 assert_se(r >= 0);
55
56 assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
57 assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
58 assert_se(sd_dhcp_client_set_ifindex(NULL, 0) == -EINVAL);
59
60 assert_se(sd_dhcp_client_set_ifindex(client, 15) == 0);
61 assert_se(sd_dhcp_client_set_ifindex(client, -42) == -EINVAL);
62 assert_se(sd_dhcp_client_set_ifindex(client, -1) == -EINVAL);
63 assert_se(sd_dhcp_client_set_ifindex(client, 0) == -EINVAL);
64 assert_se(sd_dhcp_client_set_ifindex(client, 1) == 0);
65
66 assert_se(sd_dhcp_client_set_hostname(client, "host") == 1);
67 assert_se(sd_dhcp_client_set_hostname(client, "host.domain") == 1);
68 assert_se(sd_dhcp_client_set_hostname(client, NULL) == 1);
69 assert_se(sd_dhcp_client_set_hostname(client, "~host") == -EINVAL);
70 assert_se(sd_dhcp_client_set_hostname(client, "~host.domain") == -EINVAL);
71
72 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_SUBNET_MASK) == 0);
73 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_ROUTER) == 0);
74 /* This PRL option is not set when using Anonymize, but in this test
75 * Anonymize settings are not being used. */
76 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 0);
77 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME) == 0);
78 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == 0);
79
80 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PAD) == -EINVAL);
81 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_END) == -EINVAL);
82 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
83 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
84 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
85
86 /* RFC7844: option 33 (SD_DHCP_OPTION_STATIC_ROUTE) is set in the
87 * default PRL when using Anonymize, so it is changed to other option
88 * that is not set by default, to check that it was set successfully.
89 * Options not set by default (using or not anonymize) are option 17
90 * (SD_DHCP_OPTION_ROOT_PATH) and 42 (SD_DHCP_OPTION_NTP_SERVER) */
91 assert_se(sd_dhcp_client_set_request_option(client, 17) == 1);
92 assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
93 assert_se(sd_dhcp_client_set_request_option(client, 42) == 1);
94 assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
95
96 sd_dhcp_client_unref(client);
97 }
98
99 static void test_request_anonymize(sd_event *e) {
100 int r;
101
102 sd_dhcp_client *client;
103
104 if (verbose)
105 printf("* %s\n", __func__);
106
107 /* Initialize client with Anonymize settings. */
108 r = sd_dhcp_client_new(&client, true);
109
110 assert_se(r >= 0);
111 assert_se(client);
112
113 r = sd_dhcp_client_attach_event(client, e, 0);
114 assert_se(r >= 0);
115
116 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_NETBIOS_NAME_SERVER) == 0);
117 /* This PRL option is not set when using Anonymize */
118 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 1);
119 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
120
121 /* RFC7844: option 101 (SD_DHCP_OPTION_NEW_TZDB_TIMEZONE) is not set in the
122 * default PRL when using Anonymize, */
123 assert_se(sd_dhcp_client_set_request_option(client, 101) == 1);
124 assert_se(sd_dhcp_client_set_request_option(client, 101) == 0);
125
126 sd_dhcp_client_unref(client);
127 }
128
129 static void test_checksum(void) {
130 uint8_t buf[20] = {
131 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
132 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0xff, 0xff, 0xff, 0xff
134 };
135
136 if (verbose)
137 printf("* %s\n", __func__);
138
139 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
140 }
141
142 static void test_dhcp_identifier_set_iaid(void) {
143 uint32_t iaid_legacy;
144 be32_t iaid;
145
146 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ true, &iaid_legacy) >= 0);
147 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ false, &iaid) >= 0);
148
149 /* we expect, that the MAC address was hashed. The legacy value is in native
150 * endianness. */
151 assert_se(iaid_legacy == 0x8dde4ba8u);
152 assert_se(iaid == htole32(0x8dde4ba8u));
153 #if __BYTE_ORDER == __LITTLE_ENDIAN
154 assert_se(iaid == iaid_legacy);
155 #else
156 assert_se(iaid == bswap_32(iaid_legacy));
157 #endif
158 }
159
160 static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
161 switch (code) {
162 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
163 {
164 uint32_t iaid;
165 struct duid duid;
166 size_t duid_len;
167
168 assert_se(dhcp_identifier_set_duid_en(/* test_mode = */ true, &duid, &duid_len) >= 0);
169 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ true, &iaid) >= 0);
170
171 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
172 assert_se(len == 19);
173 assert_se(((uint8_t*) option)[0] == 0xff);
174
175 assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
176 assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0);
177 break;
178 }
179
180 default:
181 break;
182 }
183
184 return 0;
185 }
186
187 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) {
188 size_t size;
189 _cleanup_free_ DHCPPacket *discover;
190 uint16_t ip_check, udp_check;
191
192 assert_se(s >= 0);
193 assert_se(packet);
194
195 size = sizeof(DHCPPacket);
196 assert_se(len > size);
197
198 discover = memdup(packet, len);
199
200 assert_se(discover->ip.ttl == IPDEFTTL);
201 assert_se(discover->ip.protocol == IPPROTO_UDP);
202 assert_se(discover->ip.saddr == INADDR_ANY);
203 assert_se(discover->ip.daddr == INADDR_BROADCAST);
204 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
205 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
206
207 ip_check = discover->ip.check;
208
209 discover->ip.ttl = 0;
210 discover->ip.check = discover->udp.len;
211
212 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
213 assert_se(udp_check == 0xffff);
214
215 discover->ip.ttl = IPDEFTTL;
216 discover->ip.check = ip_check;
217
218 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
219 assert_se(ip_check == 0xffff);
220
221 assert_se(discover->dhcp.xid);
222 assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0);
223
224 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
225
226 assert_se(callback_recv);
227 callback_recv(size, &discover->dhcp);
228
229 return 575;
230 }
231
232 int dhcp_network_bind_raw_socket(
233 int ifindex,
234 union sockaddr_union *link,
235 uint32_t id,
236 const struct hw_addr_data *_hw_addr,
237 const struct hw_addr_data *_bcast_addr,
238 uint16_t arp_type, uint16_t port) {
239
240 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
241 return -errno;
242
243 return test_fd[0];
244 }
245
246 int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
247 int fd;
248
249 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
250 if (fd < 0)
251 return -errno;
252
253 return fd;
254 }
255
256 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) {
257 return 0;
258 }
259
260 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
261 int res;
262
263 res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
264 assert_se(res == DHCP_DISCOVER);
265
266 if (verbose)
267 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
268
269 return 0;
270 }
271
272 static void test_discover_message(sd_event *e) {
273 sd_dhcp_client *client;
274 int res, r;
275
276 if (verbose)
277 printf("* %s\n", __func__);
278
279 r = sd_dhcp_client_new(&client, false);
280 assert_se(r >= 0);
281 assert_se(client);
282
283 r = sd_dhcp_client_attach_event(client, e, 0);
284 assert_se(r >= 0);
285
286 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
287 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
288 dhcp_client_set_test_mode(client, true);
289
290 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
291
292 callback_recv = test_discover_message_verify;
293
294 res = sd_dhcp_client_start(client);
295
296 assert_se(IN_SET(res, 0, -EINPROGRESS));
297
298 sd_event_run(e, UINT64_MAX);
299
300 sd_dhcp_client_stop(client);
301 sd_dhcp_client_unref(client);
302
303 test_fd[1] = safe_close(test_fd[1]);
304
305 callback_recv = NULL;
306 }
307
308 static uint8_t test_addr_acq_offer[] = {
309 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
310 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
311 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
312 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
313 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
315 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
343 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
344 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
345 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
346 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
347 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
348 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 };
351
352 static uint8_t test_addr_acq_ack[] = {
353 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
354 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
355 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
356 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
359 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
387 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
388 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
389 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
390 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
391 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
392 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 };
395
396 static int test_addr_acq_acquired(sd_dhcp_client *client, int event,
397 void *userdata) {
398 sd_event *e = userdata;
399 sd_dhcp_lease *lease;
400 struct in_addr addr;
401 const struct in_addr *addrs;
402
403 assert_se(client);
404 assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
405
406 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
407 assert_se(lease);
408
409 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
410 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
411 sizeof(addr.s_addr)) == 0);
412
413 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
414 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
415 sizeof(addr.s_addr)) == 0);
416
417 assert_se(sd_dhcp_lease_get_router(lease, &addrs) == 1);
418 assert_se(memcmp(&addrs[0].s_addr, &test_addr_acq_ack[308],
419 sizeof(addrs[0].s_addr)) == 0);
420
421 if (verbose)
422 printf(" DHCP address acquired\n");
423
424 sd_event_exit(e, 0);
425
426 return 0;
427 }
428
429 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
430 uint16_t udp_check = 0;
431 uint8_t *msg_bytes = (uint8_t *)request;
432 int res;
433
434 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
435 assert_se(res == DHCP_REQUEST);
436 assert_se(xid == request->xid);
437
438 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
439
440 if (verbose)
441 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
442
443 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
444 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
445 memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length);
446
447 callback_recv = NULL;
448
449 res = write(test_fd[1], test_addr_acq_ack,
450 sizeof(test_addr_acq_ack));
451 assert_se(res == sizeof(test_addr_acq_ack));
452
453 if (verbose)
454 printf(" send DHCP Ack\n");
455
456 return 0;
457 };
458
459 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
460 uint16_t udp_check = 0;
461 uint8_t *msg_bytes = (uint8_t *)discover;
462 int res;
463
464 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
465 assert_se(res == DHCP_DISCOVER);
466
467 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
468
469 xid = discover->xid;
470
471 if (verbose)
472 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
473
474 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
475 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
476 memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length);
477
478 callback_recv = test_addr_acq_recv_request;
479
480 res = write(test_fd[1], test_addr_acq_offer,
481 sizeof(test_addr_acq_offer));
482 assert_se(res == sizeof(test_addr_acq_offer));
483
484 if (verbose)
485 printf(" sent DHCP Offer\n");
486
487 return 0;
488 }
489
490 static void test_addr_acq(sd_event *e) {
491 sd_dhcp_client *client;
492 int res, r;
493
494 if (verbose)
495 printf("* %s\n", __func__);
496
497 r = sd_dhcp_client_new(&client, false);
498 assert_se(r >= 0);
499 assert_se(client);
500
501 r = sd_dhcp_client_attach_event(client, e, 0);
502 assert_se(r >= 0);
503
504 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
505 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
506 dhcp_client_set_test_mode(client, true);
507
508 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
509
510 callback_recv = test_addr_acq_recv_discover;
511
512 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
513 2 * USEC_PER_SEC, 0,
514 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
515
516 res = sd_dhcp_client_start(client);
517 assert_se(IN_SET(res, 0, -EINPROGRESS));
518
519 assert_se(sd_event_loop(e) >= 0);
520
521 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
522 assert_se(sd_dhcp_client_stop(client) >= 0);
523 sd_dhcp_client_unref(client);
524
525 test_fd[1] = safe_close(test_fd[1]);
526
527 callback_recv = NULL;
528 xid = 0;
529 }
530
531 int main(int argc, char *argv[]) {
532 _cleanup_(sd_event_unrefp) sd_event *e;
533
534 test_setup_logging(LOG_DEBUG);
535
536 assert_se(sd_event_new(&e) >= 0);
537
538 test_request_basic(e);
539 test_request_anonymize(e);
540 test_checksum();
541 test_dhcp_identifier_set_iaid();
542
543 test_discover_message(e);
544 test_addr_acq(e);
545
546 #if VALGRIND
547 /* Make sure the async_close thread has finished.
548 * valgrind would report some of the phread_* structures
549 * as not cleaned up properly. */
550 sleep(1);
551 #endif
552
553 return 0;
554 }