]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #31181 from fbuihuu/gpt-auto-more-defensive
[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-util-unix.h"
16 #include "socket-util.h"
17 #include "strv.h"
18 #include "ndisc-internal.h"
19 #include "tests.h"
20
21 static struct ether_addr mac_addr = {
22 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
23 };
24
25 static bool verbose = false;
26 static sd_ndisc *test_timeout_nd;
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 unsigned preference;
35 int r;
36
37 assert_se(rt);
38
39 log_info("--");
40 assert_se(sd_ndisc_router_get_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 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: {
106 unsigned prefix_len;
107 uint8_t pfl;
108 struct in6_addr a;
109
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));
113
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));
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);
127 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
128
129 break;
130 }
131
132 case SD_NDISC_OPTION_RDNSS: {
133 const struct in6_addr *a;
134 int n, i;
135
136 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
137 assert_se(n > 0);
138
139 for (i = 0; i < n; i++)
140 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
141
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));
145 break;
146 }
147
148 case SD_NDISC_OPTION_DNSSL: {
149 _cleanup_strv_free_ char **l = NULL;
150 int n, i;
151
152 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
153 if (n == -EBADMSG) {
154 log_info("Invalid domain(s).");
155 break;
156 }
157 assert_se(n > 0);
158
159 for (i = 0; i < n; i++)
160 log_info("Domain: %s", l[i]);
161
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));
165 break;
166 }}
167
168 r = sd_ndisc_router_option_next(rt);
169 }
170 }
171
172 static int send_ra(uint8_t flags) {
173 uint8_t advertisement[] = {
174 /* struct nd_router_advert */
175 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
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,
182 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
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,
186 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 24 */
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,
190 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
191 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
192 };
193
194 advertisement[5] = flags;
195
196 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
197 sizeof(advertisement));
198
199 if (verbose)
200 printf(" sent RA with flag 0x%02x\n", flags);
201
202 return 0;
203 }
204
205 static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
206 sd_event *e = userdata;
207 static unsigned idx = 0;
208 uint64_t flags_array[] = {
209 0,
210 0,
211 0,
212 ND_RA_FLAG_OTHER,
213 ND_RA_FLAG_MANAGED
214 };
215 uint64_t flags;
216
217 assert_se(nd);
218
219 if (event != SD_NDISC_EVENT_ROUTER)
220 return;
221
222 router_dump(rt);
223
224 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
225 assert_se(flags == flags_array[idx]);
226 idx++;
227
228 if (verbose)
229 printf(" got event 0x%02" PRIx64 "\n", flags);
230
231 if (idx < ELEMENTSOF(flags_array)) {
232 send_ra(flags_array[idx]);
233 return;
234 }
235
236 idx = 0;
237 sd_event_exit(e, 0);
238 }
239
240 TEST(rs) {
241 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
242 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
243
244 send_ra_function = send_ra;
245
246 assert_se(sd_event_new(&e) >= 0);
247
248 assert_se(sd_ndisc_new(&nd) >= 0);
249 assert_se(nd);
250
251 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
252
253 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
254 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
255 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
256
257 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
258 30 * USEC_PER_SEC, 0,
259 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
260
261 assert_se(sd_ndisc_stop(nd) >= 0);
262 assert_se(sd_ndisc_start(nd) >= 0);
263 assert_se(sd_ndisc_start(nd) >= 0);
264 assert_se(sd_ndisc_stop(nd) >= 0);
265 test_fd[1] = safe_close(test_fd[1]);
266
267 assert_se(sd_ndisc_start(nd) >= 0);
268
269 assert_se(sd_event_loop(e) >= 0);
270
271 test_fd[1] = safe_close(test_fd[1]);
272 }
273
274 static int send_ra_invalid_domain(uint8_t flags) {
275 uint8_t advertisement[] = {
276 /* struct nd_router_advert */
277 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
280 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
281 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
282 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
285 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
286 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
288 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 112 */
289 0x1f, 0x0e, 0xee, 0x68, 0xb0, 0xf4, 0x36, 0x39,
290 0x2c, 0xbc, 0x0b, 0xbc, 0xa9, 0x97, 0x71, 0x37,
291 0xad, 0x86, 0x80, 0x14, 0x2e, 0x58, 0xaa, 0x8a,
292 0xb7, 0xa1, 0xbe, 0x91, 0x59, 0x00, 0xc4, 0xe8,
293 0xdd, 0xd8, 0x6d, 0xe5, 0x4a, 0x7a, 0x71, 0x42,
294 0x74, 0x45, 0x9e, 0x2e, 0xfd, 0x9d, 0x71, 0x1d,
295 0xd0, 0xc0, 0x54, 0x0c, 0x4d, 0x1f, 0xbf, 0x90,
296 0xd9, 0x79, 0x58, 0xc0, 0x1d, 0xa3, 0x39, 0xcf,
297 0xb8, 0xec, 0xd2, 0xe4, 0xcd, 0xb6, 0x13, 0x2f,
298 0xc0, 0x46, 0xe8, 0x07, 0x3f, 0xaa, 0x28, 0xa5,
299 0x23, 0xf1, 0xf0, 0xca, 0xd3, 0x19, 0x3f, 0xfa,
300 0x6c, 0x7c, 0xec, 0x1b, 0xcf, 0x71, 0xeb, 0xba,
301 0x68, 0x1b, 0x8e, 0x7d, 0x93, 0x7e, 0x0b, 0x9f,
302 0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00,
303 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
304 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
305 };
306
307 advertisement[5] = flags;
308
309 printf("sizeof(nd_router_advert)=%zu\n", sizeof(struct nd_router_advert));
310
311 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
312 sizeof(advertisement));
313
314 if (verbose)
315 printf(" sent RA with flag 0x%02x\n", flags);
316
317 return 0;
318 }
319
320 TEST(invalid_domain) {
321 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
322 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
323
324 send_ra_function = send_ra_invalid_domain;
325
326 assert_se(sd_event_new(&e) >= 0);
327
328 assert_se(sd_ndisc_new(&nd) >= 0);
329 assert_se(nd);
330
331 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
332
333 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
334 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
335 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
336
337 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
338 30 * USEC_PER_SEC, 0,
339 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
340
341 assert_se(sd_ndisc_start(nd) >= 0);
342
343 assert_se(sd_event_loop(e) >= 0);
344
345 test_fd[1] = safe_close(test_fd[1]);
346 }
347
348 static int test_timeout_value(uint8_t flags) {
349 static int count = 0;
350 static usec_t last = 0;
351 sd_ndisc *nd = test_timeout_nd;
352 usec_t min, max;
353
354 assert_se(nd);
355 assert_se(nd->event);
356
357 if (++count >= 20)
358 sd_event_exit(nd->event, 0);
359
360 if (last == 0) {
361 /* initial RT = IRT + RAND*IRT */
362 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
363 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
364 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
365 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
366 } else {
367 /* next RT = 2*RTprev + RAND*RTprev */
368 min = 2 * last - last / 10;
369 max = 2 * last + last / 10;
370 }
371
372 /* final RT > MRT */
373 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
374 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
375 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
376 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
377 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
378 }
379
380 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
381 count,
382 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
383 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
384 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
385 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
386
387 assert_se(min <= nd->retransmit_time);
388 assert_se(max >= nd->retransmit_time);
389
390 last = nd->retransmit_time;
391
392 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
393
394 return 0;
395 }
396
397 TEST(timeout) {
398 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
399 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
400
401 send_ra_function = test_timeout_value;
402
403 assert_se(sd_event_new(&e) >= 0);
404
405 assert_se(sd_ndisc_new(&nd) >= 0);
406 assert_se(nd);
407
408 test_timeout_nd = nd;
409
410 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
411
412 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
413 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
414
415 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
416 30 * USEC_PER_SEC, 0,
417 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
418
419 assert_se(sd_ndisc_start(nd) >= 0);
420
421 assert_se(sd_event_loop(e) >= 0);
422
423 test_fd[1] = safe_close(test_fd[1]);
424 }
425
426 DEFINE_TEST_MAIN(LOG_DEBUG);