]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #31932 from bluca/coverity
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8 #include <unistd.h>
9
10 #include "sd-ndisc.h"
11
12 #include "alloc-util.h"
13 #include "fd-util.h"
14 #include "hexdecoct.h"
15 #include "icmp6-packet.h"
16 #include "icmp6-util-unix.h"
17 #include "socket-util.h"
18 #include "strv.h"
19 #include "ndisc-internal.h"
20 #include "tests.h"
21
22 static struct ether_addr mac_addr = {
23 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
24 };
25
26 static bool verbose = false;
27
28 static void router_dump(sd_ndisc_router *rt) {
29 struct in6_addr addr;
30 uint8_t hop_limit;
31 usec_t t, lifetime, retrans_time;
32 uint64_t flags;
33 uint32_t mtu;
34 uint8_t preference;
35 int r;
36
37 assert_se(rt);
38
39 log_info("--");
40 assert_se(sd_ndisc_router_get_sender_address(rt, &addr) >= 0);
41 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr));
42
43 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
44 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
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);
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));
67
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
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 uint8_t *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(p + 2, n - 2));
100
101 log_info("Address: %s", c);
102 break;
103 }
104
105 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
106 uint8_t prefix_len, pfl;
107 struct in6_addr a;
108
109 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime) >= 0);
110 assert_se(sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
111 log_info("Valid Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
112
113 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime) >= 0);
114 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
115 log_info("Preferred Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
116
117 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
118 log_info("Flags: <%s|%s>",
119 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
120 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
121
122 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
123 log_info("Prefix Length: %u", prefix_len);
124
125 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
126 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
127
128 break;
129 }
130
131 case SD_NDISC_OPTION_RDNSS: {
132 const struct in6_addr *a;
133 int n, i;
134
135 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
136 assert_se(n > 0);
137
138 for (i = 0; i < n; i++)
139 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
140
141 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime) >= 0);
142 assert_se(sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
143 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
144 break;
145 }
146
147 case SD_NDISC_OPTION_DNSSL: {
148 char **l;
149
150 assert_se(sd_ndisc_router_dnssl_get_domains(rt, &l) >= 0);
151
152 STRV_FOREACH(s, l)
153 log_info("Domain: %s", *s);
154
155 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime) >= 0);
156 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
157 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
158 break;
159 }}
160
161 r = sd_ndisc_router_option_next(rt);
162 }
163 }
164
165 static int send_ra(uint8_t flags) {
166 uint8_t advertisement[] = {
167 /* struct nd_router_advert */
168 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
171 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
172 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
173 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
176 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
177 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
179 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 24 */
180 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
181 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
182 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
184 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
185 };
186
187 advertisement[5] = flags;
188
189 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
190 sizeof(advertisement));
191
192 if (verbose)
193 printf(" sent RA with flag 0x%02x\n", flags);
194
195 return 0;
196 }
197
198 static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
199 sd_event *e = userdata;
200 static unsigned idx = 0;
201 uint64_t flags_array[] = {
202 0,
203 0,
204 0,
205 ND_RA_FLAG_OTHER,
206 ND_RA_FLAG_MANAGED
207 };
208 uint64_t flags;
209
210 assert_se(nd);
211
212 if (event != SD_NDISC_EVENT_ROUTER)
213 return;
214
215 sd_ndisc_router *rt = ASSERT_PTR(message);
216
217 router_dump(rt);
218
219 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
220 assert_se(flags == flags_array[idx]);
221 idx++;
222
223 if (verbose)
224 printf(" got event 0x%02" PRIx64 "\n", flags);
225
226 if (idx < ELEMENTSOF(flags_array)) {
227 send_ra(flags_array[idx]);
228 return;
229 }
230
231 idx = 0;
232 sd_event_exit(e, 0);
233 }
234
235 static int on_recv_rs(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
236 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
237 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
238
239 return send_ra(0);
240 }
241
242 TEST(rs) {
243 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
244 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
245 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
246
247 assert_se(sd_event_new(&e) >= 0);
248
249 assert_se(sd_ndisc_new(&nd) >= 0);
250 assert_se(nd);
251
252 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
253
254 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
255 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
256 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
257
258 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
259 30 * USEC_PER_SEC, 0,
260 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
261
262 assert_se(sd_ndisc_stop(nd) >= 0);
263 assert_se(sd_ndisc_start(nd) >= 0);
264 assert_se(sd_ndisc_start(nd) >= 0);
265 assert_se(sd_ndisc_stop(nd) >= 0);
266 test_fd[1] = safe_close(test_fd[1]);
267
268 assert_se(sd_ndisc_start(nd) >= 0);
269
270 assert_se(sd_event_add_io(e, &s, test_fd[1], EPOLLIN, on_recv_rs, nd) >= 0);
271 assert_se(sd_event_source_set_io_fd_own(s, true) >= 0);
272
273 assert_se(sd_event_loop(e) >= 0);
274
275 test_fd[1] = -EBADF;
276 }
277
278 static int send_ra_invalid_domain(uint8_t flags) {
279 uint8_t advertisement[] = {
280 /* struct nd_router_advert */
281 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
284 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
285 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
286 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
289 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
290 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
292 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 112 */
293 0x1f, 0x0e, 0xee, 0x68, 0xb0, 0xf4, 0x36, 0x39,
294 0x2c, 0xbc, 0x0b, 0xbc, 0xa9, 0x97, 0x71, 0x37,
295 0xad, 0x86, 0x80, 0x14, 0x2e, 0x58, 0xaa, 0x8a,
296 0xb7, 0xa1, 0xbe, 0x91, 0x59, 0x00, 0xc4, 0xe8,
297 0xdd, 0xd8, 0x6d, 0xe5, 0x4a, 0x7a, 0x71, 0x42,
298 0x74, 0x45, 0x9e, 0x2e, 0xfd, 0x9d, 0x71, 0x1d,
299 0xd0, 0xc0, 0x54, 0x0c, 0x4d, 0x1f, 0xbf, 0x90,
300 0xd9, 0x79, 0x58, 0xc0, 0x1d, 0xa3, 0x39, 0xcf,
301 0xb8, 0xec, 0xd2, 0xe4, 0xcd, 0xb6, 0x13, 0x2f,
302 0xc0, 0x46, 0xe8, 0x07, 0x3f, 0xaa, 0x28, 0xa5,
303 0x23, 0xf1, 0xf0, 0xca, 0xd3, 0x19, 0x3f, 0xfa,
304 0x6c, 0x7c, 0xec, 0x1b, 0xcf, 0x71, 0xeb, 0xba,
305 0x68, 0x1b, 0x8e, 0x7d, 0x93, 0x7e, 0x0b, 0x9f,
306 0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00,
307 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
308 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
309 };
310
311 advertisement[5] = flags;
312
313 printf("sizeof(nd_router_advert)=%zu\n", sizeof(struct nd_router_advert));
314
315 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
316 sizeof(advertisement));
317
318 if (verbose)
319 printf(" sent RA with flag 0x%02x\n", flags);
320
321 return 0;
322 }
323
324 static int on_recv_rs_invalid_domain(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
325 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
326 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
327
328 return send_ra_invalid_domain(0);
329 }
330
331 TEST(invalid_domain) {
332 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
333 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
334 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
335
336 assert_se(sd_event_new(&e) >= 0);
337
338 assert_se(sd_ndisc_new(&nd) >= 0);
339 assert_se(nd);
340
341 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
342
343 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
344 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
345 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
346
347 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
348 30 * USEC_PER_SEC, 0,
349 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
350
351 assert_se(sd_ndisc_start(nd) >= 0);
352
353 assert_se(sd_event_add_io(e, &s, test_fd[1], EPOLLIN, on_recv_rs_invalid_domain, nd) >= 0);
354 assert_se(sd_event_source_set_io_fd_own(s, true) >= 0);
355
356 assert_se(sd_event_loop(e) >= 0);
357
358 test_fd[1] = -EBADF;
359 }
360
361 static int on_recv_rs_timeout(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
362 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
363 sd_ndisc *nd = ASSERT_PTR(userdata);
364 static int count = 0;
365 static usec_t last = 0;
366 usec_t min, max;
367
368 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
369
370 if (++count >= 20)
371 sd_event_exit(nd->event, 0);
372
373 if (last == 0) {
374 /* initial RT = IRT + RAND*IRT */
375 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
376 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
377 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
378 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
379 } else {
380 /* next RT = 2*RTprev + RAND*RTprev */
381 min = 2 * last - last / 10;
382 max = 2 * last + last / 10;
383 }
384
385 /* final RT > MRT */
386 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
387 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
388 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
389 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
390 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
391 }
392
393 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
394 count,
395 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
396 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
397 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
398 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
399
400 assert_se(min <= nd->retransmit_time);
401 assert_se(max >= nd->retransmit_time);
402
403 last = nd->retransmit_time;
404
405 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
406
407 return 0;
408 }
409
410 TEST(timeout) {
411 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
412 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
413 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
414
415 assert_se(sd_event_new(&e) >= 0);
416
417 assert_se(sd_ndisc_new(&nd) >= 0);
418 assert_se(nd);
419
420 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
421
422 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
423 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
424
425 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
426 30 * USEC_PER_SEC, 0,
427 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
428
429 assert_se(sd_ndisc_start(nd) >= 0);
430
431 assert_se(sd_event_add_io(e, &s, test_fd[1], EPOLLIN, on_recv_rs_timeout, nd) >= 0);
432 assert_se(sd_event_source_set_io_fd_own(s, true) >= 0);
433
434 assert_se(sd_event_loop(e) >= 0);
435
436 test_fd[1] = -EBADF;
437 }
438
439 DEFINE_TEST_MAIN(LOG_DEBUG);