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