]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-dhcp-client.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-client.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
be391925 2/***
810adae9 3 Copyright © 2013 Intel Corporation. All rights reserved.
be391925
PF
4***/
5
be391925 6#include <errno.h>
39b7f596 7#include <stdio.h>
8c00042c
PF
8#include <sys/socket.h>
9#include <unistd.h>
43fc0955 10#include <net/if.h>
be391925 11
07630cea 12#include "sd-dhcp-client.h"
6e00a806 13#include "sd-event.h"
290c7324 14
b5efdb8a 15#include "alloc-util.h"
5bac5235 16#include "dhcp-identifier.h"
290c7324 17#include "dhcp-internal.h"
07630cea 18#include "dhcp-protocol.h"
3ffd4af2 19#include "fd-util.h"
43fc0955 20#include "random-util.h"
6d7c4033 21#include "tests.h"
cf0fbc49 22#include "util.h"
be391925 23
5bac5235 24static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
290c7324 25
6c8a0f07
PF
26typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
27
5bac5235 28static bool verbose = true;
8c00042c 29static int test_fd[2];
6c8a0f07 30static test_callback_recv_t callback_recv;
234ed3eb 31static be32_t xid;
8fc8e3ab
PF
32static sd_event_source *test_hangcheck;
33
52efd56a 34static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
8fc8e3ab
PF
35 assert_not_reached("Test case should have completed in 2 seconds");
36
37 return 0;
38}
8c00042c 39
52efd56a 40static void test_request_basic(sd_event *e) {
b25ef18b
TG
41 int r;
42
be391925
PF
43 sd_dhcp_client *client;
44
ede286f9
PF
45 if (verbose)
46 printf("* %s\n", __FUNCTION__);
47
db3d2358 48 /* Initialize client without Anonymize settings. */
49 r = sd_dhcp_client_new(&client, false);
be391925 50
12e0f830
TG
51 assert_se(r >= 0);
52 assert_se(client);
be391925 53
b25ef18b 54 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 55 assert_se(r >= 0);
b25ef18b 56
12e0f830
TG
57 assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
58 assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
2f8e7633 59 assert_se(sd_dhcp_client_set_ifindex(NULL, 0) == -EINVAL);
be391925 60
2f8e7633
LP
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);
be391925 66
9740eae6
SA
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
12e0f830 73 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 74 SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST);
12e0f830 75 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 76 SD_DHCP_OPTION_ROUTER) == -EEXIST);
db3d2358 77 /* This PRL option is not set when using Anonymize, but in this test
78 * Anonymize settings are not being used. */
12e0f830 79 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 80 SD_DHCP_OPTION_HOST_NAME) == -EEXIST);
12e0f830 81 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 82 SD_DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
12e0f830 83 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 84 SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == -EEXIST);
be391925 85
12e0f830 86 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 87 SD_DHCP_OPTION_PAD) == -EINVAL);
12e0f830 88 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 89 SD_DHCP_OPTION_END) == -EINVAL);
12e0f830 90 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 91 SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
12e0f830 92 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 93 SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
12e0f830 94 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 95 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
be391925
PF
96 == -EINVAL);
97
db3d2358 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
da172fa9
FK
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
db3d2358 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);
6e00a806
ZJS
107
108 sd_dhcp_client_unref(client);
be391925
PF
109}
110
dbb35f1f 111static 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
52efd56a 145static void test_checksum(void) {
39b7f596
PF
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
ede286f9
PF
152 if (verbose)
153 printf("* %s\n", __FUNCTION__);
154
0bbc2c1f 155 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
39b7f596
PF
156}
157
43fc0955 158static void test_dhcp_identifier_set_iaid(void) {
6d13616b
TH
159 uint32_t iaid_legacy;
160 be32_t iaid;
43fc0955
TH
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
6d13616b
TH
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);
43fc0955 175
6d13616b 176 /* we expect, that the MAC address was hashed. The legacy value is in native
43fc0955 177 * endianness. */
6d13616b
TH
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
43fc0955
TH
185}
186
52efd56a 187static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
d790d3f1 188 switch(code) {
22805d92 189 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
5bac5235
TG
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);
6d13616b 196 assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, true, &iaid) >= 0);
5bac5235
TG
197
198 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
199 assert_se(len == 19);
e4735228 200 assert_se(((uint8_t*) option)[0] == 0xff);
5bac5235 201
e4735228
LP
202 assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
203 assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0);
d790d3f1 204 break;
5bac5235 205 }
d790d3f1
PF
206
207 default:
208 break;
209 }
210
290c7324
PF
211 return 0;
212}
213
52efd56a 214int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) {
290c7324 215 size_t size;
f937d3d6 216 _cleanup_free_ DHCPPacket *discover;
290c7324 217 uint16_t ip_check, udp_check;
290c7324 218
12e0f830
TG
219 assert_se(s >= 0);
220 assert_se(packet);
290c7324 221
d47e1de4 222 size = sizeof(DHCPPacket);
12e0f830 223 assert_se(len > size);
290c7324
PF
224
225 discover = memdup(packet, len);
226
12e0f830
TG
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));
290c7324
PF
233
234 ip_check = discover->ip.check;
235
236 discover->ip.ttl = 0;
237 discover->ip.check = discover->udp.len;
238
0bbc2c1f 239 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
12e0f830 240 assert_se(udp_check == 0xffff);
290c7324
PF
241
242 discover->ip.ttl = IPDEFTTL;
243 discover->ip.check = ip_check;
244
0bbc2c1f 245 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
12e0f830 246 assert_se(ip_check == 0xffff);
290c7324 247
12e0f830 248 assert_se(discover->dhcp.xid);
5bac5235 249 assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0);
6c8a0f07 250
290c7324
PF
251 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
252
12e0f830 253 assert_se(callback_recv);
6c8a0f07 254 callback_recv(size, &discover->dhcp);
290c7324
PF
255
256 return 575;
257}
258
52efd56a
LP
259int 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,
9faed222 264 uint16_t arp_type, uint16_t port) {
52efd56a 265
3e29b889 266 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
8c00042c
PF
267 return -errno;
268
269 return test_fd[0];
270}
271
3e7b9f76 272int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
fe0885f8
ZJS
273 int fd;
274
3e29b889 275 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
fe0885f8
ZJS
276 if (fd < 0)
277 return -errno;
278
279 return fd;
234fc2df
PF
280}
281
52efd56a 282int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) {
234fc2df
PF
283 return 0;
284}
285
52efd56a 286static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
6c8a0f07
PF
287 int res;
288
f693e9b3 289 res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
12e0f830 290 assert_se(res == DHCP_DISCOVER);
6c8a0f07
PF
291
292 if (verbose)
293 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
294
295 return 0;
296}
297
52efd56a 298static void test_discover_message(sd_event *e) {
290c7324 299 sd_dhcp_client *client;
b25ef18b 300 int res, r;
290c7324 301
ede286f9
PF
302 if (verbose)
303 printf("* %s\n", __FUNCTION__);
304
db3d2358 305 r = sd_dhcp_client_new(&client, false);
12e0f830
TG
306 assert_se(r >= 0);
307 assert_se(client);
290c7324 308
b25ef18b 309 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 310 assert_se(r >= 0);
b25ef18b 311
2f8e7633 312 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
5bac5235 313 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
290c7324 314
12e0f830 315 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
290c7324 316
6c8a0f07
PF
317 callback_recv = test_discover_message_verify;
318
290c7324
PF
319 res = sd_dhcp_client_start(client);
320
4c701096 321 assert_se(IN_SET(res, 0, -EINPROGRESS));
8c00042c 322
6c8a0f07
PF
323 sd_event_run(e, (uint64_t) -1);
324
325 sd_dhcp_client_stop(client);
e5b04c8d 326 sd_dhcp_client_unref(client);
6c8a0f07 327
2afa65c3 328 test_fd[1] = safe_close(test_fd[1]);
6c8a0f07
PF
329
330 callback_recv = NULL;
290c7324
PF
331}
332
234ed3eb
PF
333static 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
377static 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,
d47e1de4 413 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
234ed3eb
PF
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
421static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
c4acff12 422 void *userdata) {
234ed3eb
PF
423 sd_event *e = userdata;
424 sd_dhcp_lease *lease;
425 struct in_addr addr;
f8862395 426 const struct in_addr *addrs;
234ed3eb 427
12e0f830 428 assert_se(client);
03748142 429 assert_se(event == SD_DHCP_CLIENT_EVENT_IP_ACQUIRE);
234ed3eb 430
12e0f830
TG
431 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
432 assert_se(lease);
234ed3eb 433
12e0f830
TG
434 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
435 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
234ed3eb
PF
436 sizeof(addr.s_addr)) == 0);
437
12e0f830
TG
438 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
439 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
234ed3eb
PF
440 sizeof(addr.s_addr)) == 0);
441
f8862395
TH
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);
234ed3eb
PF
445
446 if (verbose)
447 printf(" DHCP address acquired\n");
448
449 sd_event_exit(e, 0);
450}
451
c4acff12 452static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
234ed3eb 453 uint16_t udp_check = 0;
d790d3f1 454 uint8_t *msg_bytes = (uint8_t *)request;
234ed3eb
PF
455 int res;
456
f693e9b3 457 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
12e0f830
TG
458 assert_se(res == DHCP_REQUEST);
459 assert_se(xid == request->xid);
234ed3eb 460
22805d92 461 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
d790d3f1 462
234ed3eb
PF
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));
5bac5235 468 memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
234ed3eb
PF
469
470 callback_recv = NULL;
471
472 res = write(test_fd[1], test_addr_acq_ack,
473 sizeof(test_addr_acq_ack));
12e0f830 474 assert_se(res == sizeof(test_addr_acq_ack));
234ed3eb
PF
475
476 if (verbose)
477 printf(" send DHCP Ack\n");
478
479 return 0;
480};
481
c4acff12 482static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
234ed3eb 483 uint16_t udp_check = 0;
d790d3f1 484 uint8_t *msg_bytes = (uint8_t *)discover;
234ed3eb
PF
485 int res;
486
f693e9b3 487 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
12e0f830 488 assert_se(res == DHCP_DISCOVER);
234ed3eb 489
22805d92 490 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
d790d3f1 491
234ed3eb
PF
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));
5bac5235 499 memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
234ed3eb
PF
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));
12e0f830 505 assert_se(res == sizeof(test_addr_acq_offer));
234ed3eb
PF
506
507 if (verbose)
c4acff12 508 printf(" sent DHCP Offer\n");
234ed3eb
PF
509
510 return 0;
511}
512
c4acff12 513static void test_addr_acq(sd_event *e) {
fa94c34b 514 usec_t time_now = now(clock_boottime_or_monotonic());
234ed3eb
PF
515 sd_dhcp_client *client;
516 int res, r;
517
518 if (verbose)
519 printf("* %s\n", __FUNCTION__);
520
db3d2358 521 r = sd_dhcp_client_new(&client, false);
12e0f830
TG
522 assert_se(r >= 0);
523 assert_se(client);
234ed3eb
PF
524
525 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 526 assert_se(r >= 0);
234ed3eb 527
2f8e7633 528 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
5bac5235 529 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
234ed3eb 530
afa3509a 531 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
234ed3eb
PF
532
533 callback_recv = test_addr_acq_recv_discover;
534
6a0f1f6d 535 assert_se(sd_event_add_time(e, &test_hangcheck,
fa94c34b 536 clock_boottime_or_monotonic(),
6a0f1f6d
LP
537 time_now + 2 * USEC_PER_SEC, 0,
538 test_dhcp_hangcheck, NULL) >= 0);
8fc8e3ab 539
234ed3eb 540 res = sd_dhcp_client_start(client);
4c701096 541 assert_se(IN_SET(res, 0, -EINPROGRESS));
234ed3eb 542
fc292b5f 543 assert_se(sd_event_loop(e) >= 0);
234ed3eb 544
8fc8e3ab
PF
545 test_hangcheck = sd_event_source_unref(test_hangcheck);
546
fc292b5f
TG
547 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
548 assert_se(sd_dhcp_client_stop(client) >= 0);
e5b04c8d 549 sd_dhcp_client_unref(client);
234ed3eb 550
2afa65c3 551 test_fd[1] = safe_close(test_fd[1]);
234ed3eb
PF
552
553 callback_recv = NULL;
554 xid = 0;
555}
556
c4acff12 557int main(int argc, char *argv[]) {
4afd3348 558 _cleanup_(sd_event_unrefp) sd_event *e;
6e00a806 559
6d7c4033 560 test_setup_logging(LOG_DEBUG);
d3d8ac2f 561
12e0f830 562 assert_se(sd_event_new(&e) >= 0);
d3d8ac2f
PF
563
564 test_request_basic(e);
dbb35f1f 565 test_request_anonymize(e);
39b7f596 566 test_checksum();
43fc0955 567 test_dhcp_identifier_set_iaid();
be391925 568
d3d8ac2f 569 test_discover_message(e);
234ed3eb 570 test_addr_acq(e);
290c7324 571
d18cb393 572#if VALGRIND
374c22b3
ZJS
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
be391925
PF
579 return 0;
580}