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