]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp-client.c
cc08c3fbd221119f59c16315ad58043c2121883a
[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 <net/if_arp.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
11 #if HAVE_VALGRIND_VALGRIND_H
12 # include <valgrind/valgrind.h>
13 #endif
14
15 #include "sd-dhcp-client.h"
16 #include "sd-dhcp-lease.h"
17 #include "sd-event.h"
18
19 #include "alloc-util.h"
20 #include "dhcp-duid-internal.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 "log.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 struct bootp_addr_data {
39 uint8_t *offer_buf;
40 size_t offer_len;
41 int netmask_offset;
42 int ip_offset;
43 };
44 struct bootp_addr_data *bootp_test_context;
45
46 static bool verbose = true;
47 static int test_fd[2];
48 static test_callback_recv_t callback_recv;
49 static be32_t xid;
50
51 static void test_request_basic(sd_event *e) {
52 int r;
53
54 sd_dhcp_client *client;
55
56 if (verbose)
57 log_info("* %s", __func__);
58
59 /* Initialize client without Anonymize settings. */
60 r = sd_dhcp_client_new(&client, false);
61
62 assert_se(r >= 0);
63 assert_se(client);
64
65 r = sd_dhcp_client_attach_event(client, e, 0);
66 assert_se(r >= 0);
67
68 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
69 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
70 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(NULL, 0) == -EINVAL);
71
72 assert_se(sd_dhcp_client_set_ifindex(client, 15) == 0);
73 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(client, -42) == -EINVAL);
74 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(client, -1) == -EINVAL);
75 ASSERT_RETURN_EXPECTED_SE(sd_dhcp_client_set_ifindex(client, 0) == -EINVAL);
76 assert_se(sd_dhcp_client_set_ifindex(client, 1) == 0);
77
78 assert_se(sd_dhcp_client_set_hostname(client, "host") == 1);
79 assert_se(sd_dhcp_client_set_hostname(client, "host.domain") == 1);
80 assert_se(sd_dhcp_client_set_hostname(client, NULL) == 1);
81 assert_se(sd_dhcp_client_set_hostname(client, "~host") == -EINVAL);
82 assert_se(sd_dhcp_client_set_hostname(client, "~host.domain") == -EINVAL);
83
84 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_SUBNET_MASK) == 0);
85 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_ROUTER) == 0);
86 /* This PRL option is not set when using Anonymize, but in this test
87 * Anonymize settings are not being used. */
88 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 0);
89 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME) == 0);
90 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == 0);
91
92 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PAD) == -EINVAL);
93 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_END) == -EINVAL);
94 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
95 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
96 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -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) == 1);
104 assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
105 assert_se(sd_dhcp_client_set_request_option(client, 42) == 1);
106 assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
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 log_info("* %s", __func__);
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, SD_DHCP_OPTION_NETBIOS_NAME_SERVER) == 0);
129 /* This PRL option is not set when using Anonymize */
130 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_HOST_NAME) == 1);
131 assert_se(sd_dhcp_client_set_request_option(client, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL);
132
133 /* RFC7844: option 101 (SD_DHCP_OPTION_NEW_TZDB_TIMEZONE) is not set in the
134 * default PRL when using Anonymize, */
135 assert_se(sd_dhcp_client_set_request_option(client, 101) == 1);
136 assert_se(sd_dhcp_client_set_request_option(client, 101) == 0);
137
138 sd_dhcp_client_unref(client);
139 }
140
141 static void test_checksum(void) {
142 uint8_t buf[20] = {
143 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
144 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0xff, 0xff, 0xff, 0xff
146 };
147
148 if (verbose)
149 log_info("* %s", __func__);
150
151 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
152 }
153
154 static void test_dhcp_identifier_set_iaid(void) {
155 uint32_t iaid_legacy;
156 be32_t iaid;
157
158 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy_unstable_byteorder = */ true, &iaid_legacy) >= 0);
159 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy_unstable_byteorder = */ false, &iaid) >= 0);
160
161 /* we expect, that the MAC address was hashed. The legacy value is in native
162 * endianness. */
163 assert_se(iaid_legacy == 0x8dde4ba8u);
164 assert_se(iaid == htole32(0x8dde4ba8u));
165 #if __BYTE_ORDER == __LITTLE_ENDIAN
166 assert_se(iaid == iaid_legacy);
167 #else
168 assert_se(iaid == bswap_32(iaid_legacy));
169 #endif
170 }
171
172 static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
173 switch (code) {
174 case SD_DHCP_OPTION_CLIENT_IDENTIFIER: {
175 sd_dhcp_duid duid;
176 uint32_t iaid;
177
178 assert_se(sd_dhcp_duid_set_en(&duid) >= 0);
179 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy_unstable_byteorder = */ true, &iaid) >= 0);
180
181 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid.size);
182 assert_se(len == 19);
183 assert_se(((uint8_t*) option)[0] == 0xff);
184
185 assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
186 assert_se(memcmp((uint8_t*) option + 5, &duid.duid, duid.size) == 0);
187 break;
188 }
189
190 default:
191 ;
192 }
193
194 return 0;
195 }
196
197 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) {
198 size_t size;
199 _cleanup_free_ DHCPPacket *discover = NULL;
200 uint16_t ip_check, udp_check;
201
202 assert_se(s >= 0);
203 assert_se(packet);
204
205 size = sizeof(DHCPPacket);
206 assert_se(len > size);
207
208 discover = memdup(packet, len);
209
210 assert_se(discover->ip.ttl == IPDEFTTL);
211 assert_se(discover->ip.protocol == IPPROTO_UDP);
212 assert_se(discover->ip.saddr == INADDR_ANY);
213 assert_se(discover->ip.daddr == INADDR_BROADCAST);
214 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
215 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
216
217 ip_check = discover->ip.check;
218
219 discover->ip.ttl = 0;
220 discover->ip.check = discover->udp.len;
221
222 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
223 assert_se(udp_check == 0xffff);
224
225 discover->ip.ttl = IPDEFTTL;
226 discover->ip.check = ip_check;
227
228 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
229 assert_se(ip_check == 0xffff);
230
231 assert_se(discover->dhcp.xid);
232 assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0);
233
234 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
235
236 assert_se(callback_recv);
237 callback_recv(size, &discover->dhcp);
238
239 return 575;
240 }
241
242 int dhcp_network_bind_raw_socket(
243 int ifindex,
244 union sockaddr_union *link,
245 uint32_t id,
246 const struct hw_addr_data *_hw_addr,
247 const struct hw_addr_data *_bcast_addr,
248 uint16_t arp_type,
249 uint16_t port,
250 bool so_priority_set,
251 int so_priority) {
252
253 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
254 return -errno;
255
256 return test_fd[0];
257 }
258
259 int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
260 int fd;
261
262 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
263 if (fd < 0)
264 return -errno;
265
266 return fd;
267 }
268
269 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) {
270 return 0;
271 }
272
273 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
274 int res;
275
276 res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
277 assert_se(res == DHCP_DISCOVER);
278
279 if (verbose)
280 log_info(" recv DHCP Discover 0x%08x", be32toh(dhcp->xid));
281
282 return 0;
283 }
284
285 static void test_discover_message(sd_event *e) {
286 sd_dhcp_client *client;
287 int res, r;
288
289 if (verbose)
290 log_info("* %s", __func__);
291
292 r = sd_dhcp_client_new(&client, false);
293 assert_se(r >= 0);
294 assert_se(client);
295
296 r = sd_dhcp_client_attach_event(client, e, 0);
297 assert_se(r >= 0);
298
299 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
300 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
301
302 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
303
304 callback_recv = test_discover_message_verify;
305
306 res = sd_dhcp_client_start(client);
307
308 assert_se(IN_SET(res, 0, -EINPROGRESS));
309
310 sd_event_run(e, UINT64_MAX);
311
312 sd_dhcp_client_stop(client);
313 sd_dhcp_client_unref(client);
314
315 test_fd[1] = safe_close(test_fd[1]);
316
317 callback_recv = NULL;
318 }
319
320 static uint8_t test_addr_acq_offer[] = {
321 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
322 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
323 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
324 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
325 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
327 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
355 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
356 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
357 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
358 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
359 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
360 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 };
363
364 static uint8_t test_addr_acq_ack[] = {
365 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
366 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
367 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
368 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
370 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
371 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
399 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
400 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
401 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
402 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
403 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
404 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 };
407
408 static int test_addr_acq_acquired(sd_dhcp_client *client, int event,
409 void *userdata) {
410 sd_event *e = userdata;
411 sd_dhcp_lease *lease;
412 struct in_addr addr;
413 const struct in_addr *addrs;
414
415 assert_se(client);
416 assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
417
418 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
419 assert_se(lease);
420
421 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
422 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
423 sizeof(addr.s_addr)) == 0);
424
425 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
426 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
427 sizeof(addr.s_addr)) == 0);
428
429 assert_se(sd_dhcp_lease_get_router(lease, &addrs) == 1);
430 assert_se(memcmp(&addrs[0].s_addr, &test_addr_acq_ack[308],
431 sizeof(addrs[0].s_addr)) == 0);
432
433 if (verbose)
434 log_info(" DHCP address acquired");
435
436 sd_event_exit(e, 0);
437
438 return 0;
439 }
440
441 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
442 uint16_t udp_check = 0;
443 uint8_t *msg_bytes = (uint8_t *)request;
444 int res;
445
446 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
447 assert_se(res == DHCP_REQUEST);
448 assert_se(xid == request->xid);
449
450 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
451
452 if (verbose)
453 log_info(" recv DHCP Request 0x%08x", be32toh(xid));
454
455 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
456 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
457 memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length);
458
459 callback_recv = NULL;
460
461 res = write(test_fd[1], test_addr_acq_ack,
462 sizeof(test_addr_acq_ack));
463 assert_se(res == sizeof(test_addr_acq_ack));
464
465 if (verbose)
466 log_info(" send DHCP Ack");
467
468 return 0;
469 };
470
471 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
472 uint16_t udp_check = 0;
473 uint8_t *msg_bytes = (uint8_t *)discover;
474 int res;
475
476 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
477 assert_se(res == DHCP_DISCOVER);
478
479 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
480
481 xid = discover->xid;
482
483 if (verbose)
484 log_info(" recv DHCP Discover 0x%08x", be32toh(xid));
485
486 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
487 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
488 memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length);
489
490 callback_recv = test_addr_acq_recv_request;
491
492 res = write(test_fd[1], test_addr_acq_offer,
493 sizeof(test_addr_acq_offer));
494 assert_se(res == sizeof(test_addr_acq_offer));
495
496 if (verbose)
497 log_info(" sent DHCP Offer");
498
499 return 0;
500 }
501
502 static void test_addr_acq(sd_event *e) {
503 sd_dhcp_client *client;
504 int res, r;
505
506 if (verbose)
507 log_info("* %s", __func__);
508
509 r = sd_dhcp_client_new(&client, false);
510 assert_se(r >= 0);
511 assert_se(client);
512
513 r = sd_dhcp_client_attach_event(client, e, 0);
514 assert_se(r >= 0);
515
516 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
517 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
518
519 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
520
521 callback_recv = test_addr_acq_recv_discover;
522
523 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
524 30 * USEC_PER_SEC, 0,
525 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
526
527 res = sd_dhcp_client_start(client);
528 assert_se(IN_SET(res, 0, -EINPROGRESS));
529
530 assert_se(sd_event_loop(e) >= 0);
531
532 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
533 assert_se(sd_dhcp_client_stop(client) >= 0);
534 sd_dhcp_client_unref(client);
535
536 test_fd[1] = safe_close(test_fd[1]);
537
538 callback_recv = NULL;
539 xid = 0;
540 }
541
542 static uint8_t test_addr_bootp_reply[] = {
543 0x45, 0x00, 0x01, 0x48, 0x00, 0x00, 0x40, 0x00,
544 0xff, 0x11, 0x70, 0xa3, 0x0a, 0x00, 0x00, 0x02,
545 0xff, 0xff, 0xff, 0xff, 0x00, 0x43, 0x00, 0x44,
546 0x01, 0x2c, 0x2b, 0x91, 0x02, 0x01, 0x06, 0x00,
547 0x69, 0xd3, 0x79, 0x11, 0x17, 0x00, 0x80, 0x00,
548 0x00, 0x00, 0x00, 0x00, 0x0a, 0x46, 0x00, 0x02,
549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
550 0x50, 0x2d, 0xf4, 0x1f, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0x00,
577 0x00, 0x00, 0x36, 0x04, 0x0a, 0x00, 0x00, 0x02,
578 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
579 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
580 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
581 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
582 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
583 };
584
585 static uint8_t test_addr_bootp_reply_bootpd[] = {
586 0x45, 0x00, 0x01, 0x48, 0xbe, 0xad, 0x40, 0x00,
587 0x40, 0x11, 0x73, 0x43, 0xc0, 0xa8, 0x43, 0x31,
588 0xc0, 0xa8, 0x43, 0x32, 0x00, 0x43, 0x00, 0x44,
589 0x01, 0x34, 0x08, 0xfa, 0x02, 0x01, 0x06, 0x00,
590 0x82, 0x57, 0xda, 0xf1, 0x00, 0x01, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x43, 0x32,
592 0xc0, 0xa8, 0x43, 0x31, 0x00, 0x00, 0x00, 0x00,
593 0xc2, 0x3e, 0xa5, 0x53, 0x57, 0x72, 0x00, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x00, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff,
620 0xff, 0xf0, 0x03, 0x04, 0xc0, 0xa8, 0x43, 0x31,
621 0x06, 0x04, 0x0a, 0x00, 0x01, 0x01, 0x0c, 0x15,
622 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x64,
623 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x74,
624 0x72, 0x69, 0x78, 0x69, 0x65, 0xff, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627 };
628
629 static struct bootp_addr_data bootp_addr_data[] = {
630 {
631 .offer_buf = test_addr_bootp_reply,
632 .offer_len = sizeof(test_addr_bootp_reply),
633 .netmask_offset = 270,
634 .ip_offset = 44,
635 },
636 {
637 .offer_buf = test_addr_bootp_reply_bootpd,
638 .offer_len = sizeof(test_addr_bootp_reply_bootpd),
639 .netmask_offset = 270,
640 .ip_offset = 44,
641 },
642 };
643
644 static int test_bootp_acquired(sd_dhcp_client *client, int event,
645 void *userdata) {
646 sd_dhcp_lease *lease = NULL;
647 sd_event *e = userdata;
648 struct in_addr addr;
649
650 ASSERT_NOT_NULL(client);
651 assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
652
653 ASSERT_OK(sd_dhcp_client_get_lease(client, &lease));
654 ASSERT_NOT_NULL(lease);
655
656 ASSERT_OK(sd_dhcp_lease_get_address(lease, &addr));
657 ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->ip_offset],
658 sizeof(addr.s_addr)), 0);
659
660 ASSERT_OK(sd_dhcp_lease_get_netmask(lease, &addr));
661 ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->netmask_offset],
662 sizeof(addr.s_addr)), 0);
663
664 if (verbose)
665 log_info(" BOOTP address acquired");
666
667 sd_event_exit(e, 0);
668
669 return 0;
670 }
671
672 static int test_bootp_recv_request(size_t size, DHCPMessage *request) {
673 uint16_t udp_check = 0;
674 size_t res;
675
676 xid = request->xid;
677
678 if (verbose)
679 log_info(" recv BOOTP Request 0x%08x", be32toh(xid));
680
681 callback_recv = NULL;
682
683 memcpy(&bootp_test_context->offer_buf[26], &udp_check, sizeof(udp_check));
684 memcpy(&bootp_test_context->offer_buf[32], &xid, sizeof(xid));
685 memcpy(&bootp_test_context->offer_buf[56], hw_addr.bytes, hw_addr.length);
686
687 res = write(test_fd[1], bootp_test_context->offer_buf,
688 bootp_test_context->offer_len);
689 ASSERT_EQ(res, bootp_test_context->offer_len);
690
691 if (verbose)
692 log_info(" sent BOOTP Reply");
693
694 return 0;
695 };
696
697 static void test_acquire_bootp(sd_event *e) {
698 sd_dhcp_client *client = NULL;
699 int res;
700
701 if (verbose)
702 log_info("* %s", __func__);
703
704 ASSERT_OK(sd_dhcp_client_new(&client, false));
705 ASSERT_NOT_NULL(client);
706
707 ASSERT_OK(sd_dhcp_client_attach_event(client, e, 0));
708
709 ASSERT_OK(sd_dhcp_client_set_bootp(client, true));
710
711 ASSERT_OK(sd_dhcp_client_set_ifindex(client, 42));
712 ASSERT_OK(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER));
713
714 ASSERT_OK(sd_dhcp_client_set_callback(client, test_bootp_acquired, e));
715
716 callback_recv = test_bootp_recv_request;
717
718 ASSERT_OK(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
719 30 * USEC_PER_SEC, 0,
720 NULL, INT_TO_PTR(-ETIMEDOUT)));
721
722 res = sd_dhcp_client_start(client);
723 assert_se(IN_SET(res, 0, -EINPROGRESS));
724
725 ASSERT_OK(sd_event_loop(e));
726
727 ASSERT_OK(sd_dhcp_client_set_callback(client, NULL, NULL));
728 ASSERT_OK(sd_dhcp_client_stop(client));
729 client = sd_dhcp_client_unref(client);
730 ASSERT_NULL(client);
731
732 test_fd[1] = safe_close(test_fd[1]);
733
734 callback_recv = NULL;
735 xid = 0;
736 }
737
738 int main(int argc, char *argv[]) {
739 _cleanup_(sd_event_unrefp) sd_event *e;
740
741 assert_se(setenv("SYSTEMD_NETWORK_TEST_MODE", "1", 1) >= 0);
742
743 test_setup_logging(LOG_DEBUG);
744
745 assert_se(sd_event_new(&e) >= 0);
746
747 test_request_basic(e);
748 test_request_anonymize(e);
749 test_checksum();
750 test_dhcp_identifier_set_iaid();
751
752 test_discover_message(e);
753 test_addr_acq(e);
754
755 FOREACH_ELEMENT(i, bootp_addr_data) {
756 sd_event_unref(e);
757 ASSERT_OK(sd_event_new(&e));
758 bootp_test_context = i;
759 test_acquire_bootp(e);
760 }
761
762 #if HAVE_VALGRIND_VALGRIND_H
763 /* Make sure the async_close thread has finished.
764 * valgrind would report some of the phread_* structures
765 * as not cleaned up properly. */
766 if (RUNNING_ON_VALGRIND)
767 sleep(1);
768 #endif
769
770 return 0;
771 }