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