1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2013 Intel Corporation. All rights reserved.
6 #include <net/if_arp.h>
9 #include <sys/socket.h>
11 #if HAVE_VALGRIND_VALGRIND_H
12 # include <valgrind/valgrind.h>
15 #include "sd-dhcp-client.h"
16 #include "sd-dhcp-lease.h"
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"
29 static struct hw_addr_data hw_addr
= {
31 .ether
= {{ 'A', 'B', 'C', '1', '2', '3' }},
34 .ether
= {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }},
36 typedef int (*test_callback_recv_t
)(size_t size
, DHCPMessage
*dhcp
);
38 struct bootp_addr_data
{
44 struct bootp_addr_data
*bootp_test_context
;
46 static bool verbose
= true;
47 static int test_fd
[2];
48 static test_callback_recv_t callback_recv
;
51 static void test_request_basic(sd_event
*e
) {
54 sd_dhcp_client
*client
;
57 log_info("* %s", __func__
);
59 /* Initialize client without Anonymize settings. */
60 r
= sd_dhcp_client_new(&client
, false);
65 r
= sd_dhcp_client_attach_event(client
, e
, 0);
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
);
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);
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
);
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);
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
);
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);
108 sd_dhcp_client_unref(client
);
111 static void test_request_anonymize(sd_event
*e
) {
114 sd_dhcp_client
*client
;
117 log_info("* %s", __func__
);
119 /* Initialize client with Anonymize settings. */
120 r
= sd_dhcp_client_new(&client
, true);
125 r
= sd_dhcp_client_attach_event(client
, e
, 0);
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
);
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);
138 sd_dhcp_client_unref(client
);
141 static void test_checksum(void) {
143 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
144 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0xff, 0xff, 0xff, 0xff
149 log_info("* %s", __func__
);
151 assert_se(dhcp_packet_checksum((uint8_t*)&buf
, 20) == be16toh(0x78ae));
154 static void test_dhcp_identifier_set_iaid(void) {
155 uint32_t iaid_legacy
;
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);
161 /* we expect, that the MAC address was hashed. The legacy value is in native
163 assert_se(iaid_legacy
== 0x8dde4ba8u
);
164 assert_se(iaid
== htole32(0x8dde4ba8u
));
165 #if __BYTE_ORDER == __LITTLE_ENDIAN
166 assert_se(iaid
== iaid_legacy
);
168 assert_se(iaid
== bswap_32(iaid_legacy
));
172 static int check_options(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
174 case SD_DHCP_OPTION_CLIENT_IDENTIFIER
: {
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);
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);
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);
197 int dhcp_network_send_raw_socket(int s
, const union sockaddr_union
*link
, const void *packet
, size_t len
) {
199 _cleanup_free_ DHCPPacket
*discover
= NULL
;
200 uint16_t ip_check
, udp_check
;
205 size
= sizeof(DHCPPacket
);
206 assert_se(len
> size
);
208 discover
= memdup(packet
, len
);
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
));
217 ip_check
= discover
->ip
.check
;
219 discover
->ip
.ttl
= 0;
220 discover
->ip
.check
= discover
->udp
.len
;
222 udp_check
= ~dhcp_packet_checksum((uint8_t*)&discover
->ip
.ttl
, len
- 8);
223 assert_se(udp_check
== 0xffff);
225 discover
->ip
.ttl
= IPDEFTTL
;
226 discover
->ip
.check
= ip_check
;
228 ip_check
= ~dhcp_packet_checksum((uint8_t*)&discover
->ip
, sizeof(discover
->ip
));
229 assert_se(ip_check
== 0xffff);
231 assert_se(discover
->dhcp
.xid
);
232 assert_se(memcmp(discover
->dhcp
.chaddr
, hw_addr
.bytes
, hw_addr
.length
) == 0);
234 size
= len
- sizeof(struct iphdr
) - sizeof(struct udphdr
);
236 assert_se(callback_recv
);
237 callback_recv(size
, &discover
->dhcp
);
242 int dhcp_network_bind_raw_socket(
244 union sockaddr_union
*link
,
246 const struct hw_addr_data
*_hw_addr
,
247 const struct hw_addr_data
*_bcast_addr
,
250 bool so_priority_set
,
253 if (socketpair(AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_fd
) < 0)
259 int dhcp_network_bind_udp_socket(int ifindex
, be32_t address
, uint16_t port
, int ip_service_type
) {
262 fd
= socket(AF_INET
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0);
269 int dhcp_network_send_udp_socket(int s
, be32_t address
, uint16_t port
, const void *packet
, size_t len
) {
273 static int test_discover_message_verify(size_t size
, struct DHCPMessage
*dhcp
) {
276 res
= dhcp_option_parse(dhcp
, size
, check_options
, NULL
, NULL
);
277 assert_se(res
== DHCP_DISCOVER
);
280 log_info(" recv DHCP Discover 0x%08x", be32toh(dhcp
->xid
));
285 static void test_discover_message(sd_event
*e
) {
286 sd_dhcp_client
*client
;
290 log_info("* %s", __func__
);
292 r
= sd_dhcp_client_new(&client
, false);
296 r
= sd_dhcp_client_attach_event(client
, e
, 0);
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);
302 assert_se(sd_dhcp_client_set_request_option(client
, 248) >= 0);
304 callback_recv
= test_discover_message_verify
;
306 res
= sd_dhcp_client_start(client
);
308 assert_se(IN_SET(res
, 0, -EINPROGRESS
));
310 sd_event_run(e
, UINT64_MAX
);
312 sd_dhcp_client_stop(client
);
313 sd_dhcp_client_unref(client
);
315 test_fd
[1] = safe_close(test_fd
[1]);
317 callback_recv
= NULL
;
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,
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,
408 static int test_addr_acq_acquired(sd_dhcp_client
*client
, int event
,
410 sd_event
*e
= userdata
;
411 sd_dhcp_lease
*lease
;
413 const struct in_addr
*addrs
;
416 assert_se(IN_SET(event
, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
, SD_DHCP_CLIENT_EVENT_SELECTING
));
418 assert_se(sd_dhcp_client_get_lease(client
, &lease
) >= 0);
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);
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);
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);
434 log_info(" DHCP address acquired");
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
;
446 res
= dhcp_option_parse(request
, size
, check_options
, NULL
, NULL
);
447 assert_se(res
== DHCP_REQUEST
);
448 assert_se(xid
== request
->xid
);
450 assert_se(msg_bytes
[size
- 1] == SD_DHCP_OPTION_END
);
453 log_info(" recv DHCP Request 0x%08x", be32toh(xid
));
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
);
459 callback_recv
= NULL
;
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
));
466 log_info(" send DHCP Ack");
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
;
476 res
= dhcp_option_parse(discover
, size
, check_options
, NULL
, NULL
);
477 assert_se(res
== DHCP_DISCOVER
);
479 assert_se(msg_bytes
[size
- 1] == SD_DHCP_OPTION_END
);
484 log_info(" recv DHCP Discover 0x%08x", be32toh(xid
));
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
);
490 callback_recv
= test_addr_acq_recv_request
;
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
));
497 log_info(" sent DHCP Offer");
502 static void test_addr_acq(sd_event
*e
) {
503 sd_dhcp_client
*client
;
507 log_info("* %s", __func__
);
509 r
= sd_dhcp_client_new(&client
, false);
513 r
= sd_dhcp_client_attach_event(client
, e
, 0);
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);
519 assert_se(sd_dhcp_client_set_callback(client
, test_addr_acq_acquired
, e
) >= 0);
521 callback_recv
= test_addr_acq_recv_discover
;
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);
527 res
= sd_dhcp_client_start(client
);
528 assert_se(IN_SET(res
, 0, -EINPROGRESS
));
530 assert_se(sd_event_loop(e
) >= 0);
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
);
536 test_fd
[1] = safe_close(test_fd
[1]);
538 callback_recv
= NULL
;
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,
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,
629 static struct bootp_addr_data bootp_addr_data
[] = {
631 .offer_buf
= test_addr_bootp_reply
,
632 .offer_len
= sizeof(test_addr_bootp_reply
),
633 .netmask_offset
= 270,
637 .offer_buf
= test_addr_bootp_reply_bootpd
,
638 .offer_len
= sizeof(test_addr_bootp_reply_bootpd
),
639 .netmask_offset
= 270,
644 static int test_bootp_acquired(sd_dhcp_client
*client
, int event
,
646 sd_dhcp_lease
*lease
= NULL
;
647 sd_event
*e
= userdata
;
650 ASSERT_NOT_NULL(client
);
651 assert_se(IN_SET(event
, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
, SD_DHCP_CLIENT_EVENT_SELECTING
));
653 ASSERT_OK(sd_dhcp_client_get_lease(client
, &lease
));
654 ASSERT_NOT_NULL(lease
);
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);
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);
665 log_info(" BOOTP address acquired");
672 static int test_bootp_recv_request(size_t size
, DHCPMessage
*request
) {
673 uint16_t udp_check
= 0;
679 log_info(" recv BOOTP Request 0x%08x", be32toh(xid
));
681 callback_recv
= NULL
;
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
);
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
);
692 log_info(" sent BOOTP Reply");
697 static void test_acquire_bootp(sd_event
*e
) {
698 sd_dhcp_client
*client
= NULL
;
702 log_info("* %s", __func__
);
704 ASSERT_OK(sd_dhcp_client_new(&client
, false));
705 ASSERT_NOT_NULL(client
);
707 ASSERT_OK(sd_dhcp_client_attach_event(client
, e
, 0));
709 ASSERT_OK(sd_dhcp_client_set_bootp(client
, true));
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
));
714 ASSERT_OK(sd_dhcp_client_set_callback(client
, test_bootp_acquired
, e
));
716 callback_recv
= test_bootp_recv_request
;
718 ASSERT_OK(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
719 30 * USEC_PER_SEC
, 0,
720 NULL
, INT_TO_PTR(-ETIMEDOUT
)));
722 res
= sd_dhcp_client_start(client
);
723 assert_se(IN_SET(res
, 0, -EINPROGRESS
));
725 ASSERT_OK(sd_event_loop(e
));
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
);
732 test_fd
[1] = safe_close(test_fd
[1]);
734 callback_recv
= NULL
;
738 int main(int argc
, char *argv
[]) {
739 _cleanup_(sd_event_unrefp
) sd_event
*e
;
741 assert_se(setenv("SYSTEMD_NETWORK_TEST_MODE", "1", 1) >= 0);
743 test_setup_logging(LOG_DEBUG
);
745 assert_se(sd_event_new(&e
) >= 0);
747 test_request_basic(e
);
748 test_request_anonymize(e
);
750 test_dhcp_identifier_set_iaid();
752 test_discover_message(e
);
755 FOREACH_ELEMENT(i
, bootp_addr_data
) {
757 ASSERT_OK(sd_event_new(&e
));
758 bootp_test_context
= i
;
759 test_acquire_bootp(e
);
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
)