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