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