]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-ndisc-rs.c
sd-ndisc: make callback takes arbitrary type of message
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
f20a35cc 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
f20a35cc
PF
4***/
5
6#include <netinet/icmp6.h>
1e7a0e21 7#include <arpa/inet.h>
ca78ad1d 8#include <unistd.h>
f20a35cc 9
07630cea 10#include "sd-ndisc.h"
f20a35cc 11
1e7a0e21 12#include "alloc-util.h"
86d82cb8 13#include "fd-util.h"
1e7a0e21 14#include "hexdecoct.h"
690afe79 15#include "icmp6-util-unix.h"
07630cea 16#include "socket-util.h"
1e7a0e21 17#include "strv.h"
5a67ed24 18#include "ndisc-internal.h"
6d7c4033 19#include "tests.h"
f20a35cc
PF
20
21static struct ether_addr mac_addr = {
22 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
23};
24
25static bool verbose = false;
5a67ed24 26static sd_ndisc *test_timeout_nd;
f20a35cc 27
1e7a0e21
LP
28static void router_dump(sd_ndisc_router *rt) {
29 struct in6_addr addr;
1e7a0e21 30 uint8_t hop_limit;
d4c8de21 31 usec_t t, lifetime, retrans_time;
6197db53 32 uint64_t flags;
1e7a0e21 33 uint32_t mtu;
1e7a0e21
LP
34 unsigned preference;
35 int r;
36
37 assert_se(rt);
38
39 log_info("--");
4961f566
YW
40 assert_se(sd_ndisc_router_get_address(rt, &addr) >= 0);
41 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr));
1e7a0e21
LP
42
43 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
04f5c018 44 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
1e7a0e21
LP
45
46 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
47 log_info("Monotonic: %" PRIu64, t);
48
49 if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
50 log_info("No hop limit set");
51 else
52 log_info("Hop limit: %u", hop_limit);
53
54 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
55 log_info("Flags: <%s|%s>",
56 flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
57 flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
58
59 assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
60 log_info("Preference: %s",
61 preference == SD_NDISC_PREFERENCE_LOW ? "low" :
62 preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
63
64 assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
6197db53
YW
65 assert_se(sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
66 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21 67
d4c8de21
MM
68 assert_se(sd_ndisc_router_get_retransmission_time(rt, &retrans_time) >= 0);
69 log_info("Retransmission Time: %s", FORMAT_TIMESPAN(retrans_time, USEC_PER_SEC));
70
1e7a0e21
LP
71 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
72 log_info("No MTU set");
73 else
74 log_info("MTU: %" PRIu32, mtu);
75
76 r = sd_ndisc_router_option_rewind(rt);
77 for (;;) {
78 uint8_t type;
79
80 assert_se(r >= 0);
81
82 if (r == 0)
83 break;
84
85 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
86
87 log_info(">> Option %u", type);
88
89 switch (type) {
90
91 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
92 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
93 _cleanup_free_ char *c = NULL;
94 const void *p;
95 size_t n;
96
97 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
98 assert_se(n > 2);
99 assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
100
101 log_info("Address: %s", c);
102 break;
103 }
104
105 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
1e7a0e21
LP
106 unsigned prefix_len;
107 uint8_t pfl;
108 struct in6_addr a;
1e7a0e21 109
6197db53
YW
110 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime) >= 0);
111 assert_se(sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
112 log_info("Valid Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21 113
6197db53
YW
114 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime) >= 0);
115 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
116 log_info("Preferred Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21
LP
117
118 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
119 log_info("Flags: <%s|%s>",
120 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
121 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
122
123 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
124 log_info("Prefix Length: %u", prefix_len);
125
126 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
071e522e 127 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
1e7a0e21
LP
128
129 break;
130 }
131
132 case SD_NDISC_OPTION_RDNSS: {
133 const struct in6_addr *a;
1e7a0e21
LP
134 int n, i;
135
136 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
137 assert_se(n > 0);
138
071e522e
ZJS
139 for (i = 0; i < n; i++)
140 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
1e7a0e21 141
6197db53
YW
142 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime) >= 0);
143 assert_se(sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
144 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21
LP
145 break;
146 }
147
148 case SD_NDISC_OPTION_DNSSL: {
149 _cleanup_strv_free_ char **l = NULL;
1e7a0e21
LP
150 int n, i;
151
152 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
a39d8396
YW
153 if (n == -EBADMSG) {
154 log_info("Invalid domain(s).");
155 break;
156 }
1e7a0e21
LP
157 assert_se(n > 0);
158
159 for (i = 0; i < n; i++)
160 log_info("Domain: %s", l[i]);
161
6197db53
YW
162 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime) >= 0);
163 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
164 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21
LP
165 break;
166 }}
167
168 r = sd_ndisc_router_option_next(rt);
169 }
170}
171
f20a35cc
PF
172static int send_ra(uint8_t flags) {
173 uint8_t advertisement[] = {
38a80ba1 174 /* struct nd_router_advert */
f20a35cc
PF
175 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38a80ba1 177 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
f20a35cc
PF
178 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
179 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
180 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38a80ba1 182 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
f20a35cc
PF
183 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
184 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
d9b8acda 186 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 24 */
f20a35cc
PF
187 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
188 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
189 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
d9b8acda 190 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
f20a35cc
PF
191 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
192 };
193
194 advertisement[5] = flags;
195
787784c4 196 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
c21ed681 197 sizeof(advertisement));
f20a35cc
PF
198
199 if (verbose)
200 printf(" sent RA with flag 0x%02x\n", flags);
201
202 return 0;
203}
204
28eef158 205static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
f20a35cc 206 sd_event *e = userdata;
cb53894d 207 static unsigned idx = 0;
1e7a0e21 208 uint64_t flags_array[] = {
9d96e6c3
TG
209 0,
210 0,
211 0,
212 ND_RA_FLAG_OTHER,
213 ND_RA_FLAG_MANAGED
f20a35cc 214 };
1e7a0e21 215 uint64_t flags;
8d7f2c6a 216
787784c4 217 assert_se(nd);
f20a35cc 218
1e7a0e21
LP
219 if (event != SD_NDISC_EVENT_ROUTER)
220 return;
221
28eef158
YW
222 sd_ndisc_router *rt = ASSERT_PTR(message);
223
1e7a0e21
LP
224 router_dump(rt);
225
226 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
9d96e6c3 227 assert_se(flags == flags_array[idx]);
f20a35cc
PF
228 idx++;
229
230 if (verbose)
1e7a0e21 231 printf(" got event 0x%02" PRIx64 "\n", flags);
f20a35cc 232
9d96e6c3
TG
233 if (idx < ELEMENTSOF(flags_array)) {
234 send_ra(flags_array[idx]);
8d7f2c6a
PF
235 return;
236 }
237
a39d8396 238 idx = 0;
8d7f2c6a 239 sd_event_exit(e, 0);
f20a35cc
PF
240}
241
68da8adf 242TEST(rs) {
86d82cb8
YW
243 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
244 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
f20a35cc 245
99af546d
PF
246 send_ra_function = send_ra;
247
248 assert_se(sd_event_new(&e) >= 0);
249
4d7b83da 250 assert_se(sd_ndisc_new(&nd) >= 0);
787784c4 251 assert_se(nd);
f20a35cc 252
4d7b83da 253 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
f20a35cc 254
2f8e7633 255 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
4d7b83da 256 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
1e7a0e21 257 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
f20a35cc 258
ba4e0427 259 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
2e37084f
YW
260 30 * USEC_PER_SEC, 0,
261 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
f20a35cc 262
4d7b83da 263 assert_se(sd_ndisc_stop(nd) >= 0);
1e7a0e21 264 assert_se(sd_ndisc_start(nd) >= 0);
6b8a1aa6 265 assert_se(sd_ndisc_start(nd) >= 0);
4d7b83da 266 assert_se(sd_ndisc_stop(nd) >= 0);
86d82cb8 267 test_fd[1] = safe_close(test_fd[1]);
836cf090 268
1e7a0e21 269 assert_se(sd_ndisc_start(nd) >= 0);
f20a35cc 270
2e37084f 271 assert_se(sd_event_loop(e) >= 0);
f20a35cc 272
86d82cb8 273 test_fd[1] = safe_close(test_fd[1]);
f20a35cc
PF
274}
275
a39d8396
YW
276static int send_ra_invalid_domain(uint8_t flags) {
277 uint8_t advertisement[] = {
278 /* struct nd_router_advert */
279 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
282 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
283 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
284 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
287 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
288 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
d9b8acda 290 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 112 */
a39d8396
YW
291 0x1f, 0x0e, 0xee, 0x68, 0xb0, 0xf4, 0x36, 0x39,
292 0x2c, 0xbc, 0x0b, 0xbc, 0xa9, 0x97, 0x71, 0x37,
293 0xad, 0x86, 0x80, 0x14, 0x2e, 0x58, 0xaa, 0x8a,
294 0xb7, 0xa1, 0xbe, 0x91, 0x59, 0x00, 0xc4, 0xe8,
295 0xdd, 0xd8, 0x6d, 0xe5, 0x4a, 0x7a, 0x71, 0x42,
296 0x74, 0x45, 0x9e, 0x2e, 0xfd, 0x9d, 0x71, 0x1d,
297 0xd0, 0xc0, 0x54, 0x0c, 0x4d, 0x1f, 0xbf, 0x90,
298 0xd9, 0x79, 0x58, 0xc0, 0x1d, 0xa3, 0x39, 0xcf,
299 0xb8, 0xec, 0xd2, 0xe4, 0xcd, 0xb6, 0x13, 0x2f,
300 0xc0, 0x46, 0xe8, 0x07, 0x3f, 0xaa, 0x28, 0xa5,
301 0x23, 0xf1, 0xf0, 0xca, 0xd3, 0x19, 0x3f, 0xfa,
302 0x6c, 0x7c, 0xec, 0x1b, 0xcf, 0x71, 0xeb, 0xba,
303 0x68, 0x1b, 0x8e, 0x7d, 0x93, 0x7e, 0x0b, 0x9f,
304 0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00,
d9b8acda 305 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
a39d8396
YW
306 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
307 };
308
309 advertisement[5] = flags;
310
311 printf("sizeof(nd_router_advert)=%zu\n", sizeof(struct nd_router_advert));
312
313 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
314 sizeof(advertisement));
315
316 if (verbose)
317 printf(" sent RA with flag 0x%02x\n", flags);
318
319 return 0;
320}
321
322TEST(invalid_domain) {
323 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
324 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
325
326 send_ra_function = send_ra_invalid_domain;
327
328 assert_se(sd_event_new(&e) >= 0);
329
330 assert_se(sd_ndisc_new(&nd) >= 0);
331 assert_se(nd);
332
333 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
334
335 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
336 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
337 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
338
339 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
340 30 * USEC_PER_SEC, 0,
341 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
342
343 assert_se(sd_ndisc_start(nd) >= 0);
344
345 assert_se(sd_event_loop(e) >= 0);
346
347 test_fd[1] = safe_close(test_fd[1]);
348}
349
5a67ed24
PF
350static int test_timeout_value(uint8_t flags) {
351 static int count = 0;
352 static usec_t last = 0;
353 sd_ndisc *nd = test_timeout_nd;
354 usec_t min, max;
5a67ed24
PF
355
356 assert_se(nd);
357 assert_se(nd->event);
358
359 if (++count >= 20)
360 sd_event_exit(nd->event, 0);
361
362 if (last == 0) {
363 /* initial RT = IRT + RAND*IRT */
364 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
365 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
366 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
367 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
368 } else {
369 /* next RT = 2*RTprev + RAND*RTprev */
370 min = 2 * last - last / 10;
371 max = 2 * last + last / 10;
372 }
373
374 /* final RT > MRT */
375 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
376 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
377 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
378 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
379 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
380 }
381
5a67ed24
PF
382 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
383 count,
5291f26d
ZJS
384 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
385 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
386 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
387 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
5a67ed24
PF
388
389 assert_se(min <= nd->retransmit_time);
390 assert_se(max >= nd->retransmit_time);
391
392 last = nd->retransmit_time;
393
394 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
395
396 return 0;
397}
398
68da8adf 399TEST(timeout) {
86d82cb8
YW
400 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
401 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
5a67ed24 402
5a67ed24
PF
403 send_ra_function = test_timeout_value;
404
405 assert_se(sd_event_new(&e) >= 0);
406
407 assert_se(sd_ndisc_new(&nd) >= 0);
408 assert_se(nd);
409
410 test_timeout_nd = nd;
411
412 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
413
414 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
415 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
416
ba4e0427 417 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
2e37084f
YW
418 30 * USEC_PER_SEC, 0,
419 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
5a67ed24
PF
420
421 assert_se(sd_ndisc_start(nd) >= 0);
422
2e37084f 423 assert_se(sd_event_loop(e) >= 0);
5a67ed24 424
86d82cb8 425 test_fd[1] = safe_close(test_fd[1]);
5a67ed24
PF
426}
427
68da8adf 428DEFINE_TEST_MAIN(LOG_DEBUG);