]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp-client.c
Merge pull request #12520 from ssahani/geneve
[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 int 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(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
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 return 0;
452 }
453
454 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
455 uint16_t udp_check = 0;
456 uint8_t *msg_bytes = (uint8_t *)request;
457 int res;
458
459 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
460 assert_se(res == DHCP_REQUEST);
461 assert_se(xid == request->xid);
462
463 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
464
465 if (verbose)
466 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
467
468 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
469 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
470 memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
471
472 callback_recv = NULL;
473
474 res = write(test_fd[1], test_addr_acq_ack,
475 sizeof(test_addr_acq_ack));
476 assert_se(res == sizeof(test_addr_acq_ack));
477
478 if (verbose)
479 printf(" send DHCP Ack\n");
480
481 return 0;
482 };
483
484 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
485 uint16_t udp_check = 0;
486 uint8_t *msg_bytes = (uint8_t *)discover;
487 int res;
488
489 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
490 assert_se(res == DHCP_DISCOVER);
491
492 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
493
494 xid = discover->xid;
495
496 if (verbose)
497 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
498
499 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
500 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
501 memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
502
503 callback_recv = test_addr_acq_recv_request;
504
505 res = write(test_fd[1], test_addr_acq_offer,
506 sizeof(test_addr_acq_offer));
507 assert_se(res == sizeof(test_addr_acq_offer));
508
509 if (verbose)
510 printf(" sent DHCP Offer\n");
511
512 return 0;
513 }
514
515 static void test_addr_acq(sd_event *e) {
516 usec_t time_now = now(clock_boottime_or_monotonic());
517 sd_dhcp_client *client;
518 int res, r;
519
520 if (verbose)
521 printf("* %s\n", __FUNCTION__);
522
523 r = sd_dhcp_client_new(&client, false);
524 assert_se(r >= 0);
525 assert_se(client);
526
527 r = sd_dhcp_client_attach_event(client, e, 0);
528 assert_se(r >= 0);
529
530 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
531 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
532
533 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
534
535 callback_recv = test_addr_acq_recv_discover;
536
537 assert_se(sd_event_add_time(e, &test_hangcheck,
538 clock_boottime_or_monotonic(),
539 time_now + 2 * USEC_PER_SEC, 0,
540 test_dhcp_hangcheck, NULL) >= 0);
541
542 res = sd_dhcp_client_start(client);
543 assert_se(IN_SET(res, 0, -EINPROGRESS));
544
545 assert_se(sd_event_loop(e) >= 0);
546
547 test_hangcheck = sd_event_source_unref(test_hangcheck);
548
549 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
550 assert_se(sd_dhcp_client_stop(client) >= 0);
551 sd_dhcp_client_unref(client);
552
553 test_fd[1] = safe_close(test_fd[1]);
554
555 callback_recv = NULL;
556 xid = 0;
557 }
558
559 int main(int argc, char *argv[]) {
560 _cleanup_(sd_event_unrefp) sd_event *e;
561
562 test_setup_logging(LOG_DEBUG);
563
564 assert_se(sd_event_new(&e) >= 0);
565
566 test_request_basic(e);
567 test_request_anonymize(e);
568 test_checksum();
569 test_dhcp_identifier_set_iaid();
570
571 test_discover_message(e);
572 test_addr_acq(e);
573
574 #if VALGRIND
575 /* Make sure the async_close thread has finished.
576 * valgrind would report some of the phread_* structures
577 * as not cleaned up properly. */
578 sleep(1);
579 #endif
580
581 return 0;
582 }