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