]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp-client.c
Merge pull request #25143 from yuwata/network-reconfigure-interface-when-renamed
[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(NULL, &hw_addr, /* legacy = */ true, &iaid_legacy) >= 0);
148 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ false, &iaid) >= 0);
149
150 /* we expect, that the MAC address was hashed. The legacy value is in native
151 * endianness. */
152 assert_se(iaid_legacy == 0x8dde4ba8u);
153 assert_se(iaid == htole32(0x8dde4ba8u));
154 #if __BYTE_ORDER == __LITTLE_ENDIAN
155 assert_se(iaid == iaid_legacy);
156 #else
157 assert_se(iaid == bswap_32(iaid_legacy));
158 #endif
159 }
160
161 static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
162 switch (code) {
163 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
164 {
165 uint32_t iaid;
166 struct duid duid;
167 size_t duid_len;
168
169 assert_se(dhcp_identifier_set_duid_en(/* test_mode = */ true, &duid, &duid_len) >= 0);
170 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ true, &iaid) >= 0);
171
172 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
173 assert_se(len == 19);
174 assert_se(((uint8_t*) option)[0] == 0xff);
175
176 assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
177 assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0);
178 break;
179 }
180
181 default:
182 break;
183 }
184
185 return 0;
186 }
187
188 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) {
189 size_t size;
190 _cleanup_free_ DHCPPacket *discover;
191 uint16_t ip_check, udp_check;
192
193 assert_se(s >= 0);
194 assert_se(packet);
195
196 size = sizeof(DHCPPacket);
197 assert_se(len > size);
198
199 discover = memdup(packet, len);
200
201 assert_se(discover->ip.ttl == IPDEFTTL);
202 assert_se(discover->ip.protocol == IPPROTO_UDP);
203 assert_se(discover->ip.saddr == INADDR_ANY);
204 assert_se(discover->ip.daddr == INADDR_BROADCAST);
205 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
206 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
207
208 ip_check = discover->ip.check;
209
210 discover->ip.ttl = 0;
211 discover->ip.check = discover->udp.len;
212
213 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
214 assert_se(udp_check == 0xffff);
215
216 discover->ip.ttl = IPDEFTTL;
217 discover->ip.check = ip_check;
218
219 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
220 assert_se(ip_check == 0xffff);
221
222 assert_se(discover->dhcp.xid);
223 assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0);
224
225 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
226
227 assert_se(callback_recv);
228 callback_recv(size, &discover->dhcp);
229
230 return 575;
231 }
232
233 int dhcp_network_bind_raw_socket(
234 int ifindex,
235 union sockaddr_union *link,
236 uint32_t id,
237 const struct hw_addr_data *_hw_addr,
238 const struct hw_addr_data *_bcast_addr,
239 uint16_t arp_type, uint16_t port) {
240
241 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
242 return -errno;
243
244 return test_fd[0];
245 }
246
247 int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
248 int fd;
249
250 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
251 if (fd < 0)
252 return -errno;
253
254 return fd;
255 }
256
257 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) {
258 return 0;
259 }
260
261 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
262 int res;
263
264 res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
265 assert_se(res == DHCP_DISCOVER);
266
267 if (verbose)
268 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
269
270 return 0;
271 }
272
273 static void test_discover_message(sd_event *e) {
274 sd_dhcp_client *client;
275 int res, r;
276
277 if (verbose)
278 printf("* %s\n", __func__);
279
280 r = sd_dhcp_client_new(&client, false);
281 assert_se(r >= 0);
282 assert_se(client);
283
284 r = sd_dhcp_client_attach_event(client, e, 0);
285 assert_se(r >= 0);
286
287 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
288 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
289 dhcp_client_set_test_mode(client, true);
290
291 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
292
293 callback_recv = test_discover_message_verify;
294
295 res = sd_dhcp_client_start(client);
296
297 assert_se(IN_SET(res, 0, -EINPROGRESS));
298
299 sd_event_run(e, UINT64_MAX);
300
301 sd_dhcp_client_stop(client);
302 sd_dhcp_client_unref(client);
303
304 test_fd[1] = safe_close(test_fd[1]);
305
306 callback_recv = NULL;
307 }
308
309 static uint8_t test_addr_acq_offer[] = {
310 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
311 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
312 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
313 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
314 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
316 0xc0, 0xa8, 0x02, 0x01, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
344 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
345 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
346 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
347 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
348 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
349 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 };
352
353 static uint8_t test_addr_acq_ack[] = {
354 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
355 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
356 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
357 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
360 0xc0, 0xa8, 0x02, 0x01, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
388 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
389 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
390 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
391 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
392 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
393 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 };
396
397 static int test_addr_acq_acquired(sd_dhcp_client *client, int event,
398 void *userdata) {
399 sd_event *e = userdata;
400 sd_dhcp_lease *lease;
401 struct in_addr addr;
402 const struct in_addr *addrs;
403
404 assert_se(client);
405 assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
406
407 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
408 assert_se(lease);
409
410 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
411 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
412 sizeof(addr.s_addr)) == 0);
413
414 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
415 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
416 sizeof(addr.s_addr)) == 0);
417
418 assert_se(sd_dhcp_lease_get_router(lease, &addrs) == 1);
419 assert_se(memcmp(&addrs[0].s_addr, &test_addr_acq_ack[308],
420 sizeof(addrs[0].s_addr)) == 0);
421
422 if (verbose)
423 printf(" DHCP address acquired\n");
424
425 sd_event_exit(e, 0);
426
427 return 0;
428 }
429
430 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
431 uint16_t udp_check = 0;
432 uint8_t *msg_bytes = (uint8_t *)request;
433 int res;
434
435 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
436 assert_se(res == DHCP_REQUEST);
437 assert_se(xid == request->xid);
438
439 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
440
441 if (verbose)
442 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
443
444 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
445 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
446 memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length);
447
448 callback_recv = NULL;
449
450 res = write(test_fd[1], test_addr_acq_ack,
451 sizeof(test_addr_acq_ack));
452 assert_se(res == sizeof(test_addr_acq_ack));
453
454 if (verbose)
455 printf(" send DHCP Ack\n");
456
457 return 0;
458 };
459
460 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
461 uint16_t udp_check = 0;
462 uint8_t *msg_bytes = (uint8_t *)discover;
463 int res;
464
465 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
466 assert_se(res == DHCP_DISCOVER);
467
468 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
469
470 xid = discover->xid;
471
472 if (verbose)
473 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
474
475 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
476 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
477 memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length);
478
479 callback_recv = test_addr_acq_recv_request;
480
481 res = write(test_fd[1], test_addr_acq_offer,
482 sizeof(test_addr_acq_offer));
483 assert_se(res == sizeof(test_addr_acq_offer));
484
485 if (verbose)
486 printf(" sent DHCP Offer\n");
487
488 return 0;
489 }
490
491 static void test_addr_acq(sd_event *e) {
492 sd_dhcp_client *client;
493 int res, r;
494
495 if (verbose)
496 printf("* %s\n", __func__);
497
498 r = sd_dhcp_client_new(&client, false);
499 assert_se(r >= 0);
500 assert_se(client);
501
502 r = sd_dhcp_client_attach_event(client, e, 0);
503 assert_se(r >= 0);
504
505 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
506 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
507 dhcp_client_set_test_mode(client, true);
508
509 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
510
511 callback_recv = test_addr_acq_recv_discover;
512
513 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
514 2 * USEC_PER_SEC, 0,
515 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
516
517 res = sd_dhcp_client_start(client);
518 assert_se(IN_SET(res, 0, -EINPROGRESS));
519
520 assert_se(sd_event_loop(e) >= 0);
521
522 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
523 assert_se(sd_dhcp_client_stop(client) >= 0);
524 sd_dhcp_client_unref(client);
525
526 test_fd[1] = safe_close(test_fd[1]);
527
528 callback_recv = NULL;
529 xid = 0;
530 }
531
532 int main(int argc, char *argv[]) {
533 _cleanup_(sd_event_unrefp) sd_event *e;
534
535 test_setup_logging(LOG_DEBUG);
536
537 assert_se(sd_event_new(&e) >= 0);
538
539 test_request_basic(e);
540 test_request_anonymize(e);
541 test_checksum();
542 test_dhcp_identifier_set_iaid();
543
544 test_discover_message(e);
545 test_addr_acq(e);
546
547 #if VALGRIND
548 /* Make sure the async_close thread has finished.
549 * valgrind would report some of the phread_* structures
550 * as not cleaned up properly. */
551 sleep(1);
552 #endif
553
554 return 0;
555 }