]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #10618 from yuwata/fix-10615
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8
9 #include "sd-ndisc.h"
10
11 #include "alloc-util.h"
12 #include "hexdecoct.h"
13 #include "icmp6-util.h"
14 #include "socket-util.h"
15 #include "strv.h"
16 #include "ndisc-internal.h"
17 #include "tests.h"
18
19 static struct ether_addr mac_addr = {
20 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
21 };
22
23 static bool verbose = false;
24 static sd_event_source *test_hangcheck;
25 static int test_fd[2];
26 static sd_ndisc *test_timeout_nd;
27
28 typedef int (*send_ra_t)(uint8_t flags);
29 static send_ra_t send_ra_function;
30
31 static void router_dump(sd_ndisc_router *rt) {
32 struct in6_addr addr;
33 char buf[FORMAT_TIMESTAMP_MAX];
34 uint8_t hop_limit;
35 uint64_t t, flags;
36 uint32_t mtu;
37 uint16_t lifetime;
38 unsigned preference;
39 int r;
40
41 assert_se(rt);
42
43 log_info("--");
44 assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA);
45
46 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
47 log_info("Timestamp: %s", format_timestamp(buf, sizeof(buf), t));
48
49 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
50 log_info("Monotonic: %" PRIu64, t);
51
52 if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
53 log_info("No hop limit set");
54 else
55 log_info("Hop limit: %u", hop_limit);
56
57 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
58 log_info("Flags: <%s|%s>",
59 flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
60 flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
61
62 assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
63 log_info("Preference: %s",
64 preference == SD_NDISC_PREFERENCE_LOW ? "low" :
65 preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
66
67 assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
68 log_info("Lifetime: %" PRIu16, lifetime);
69
70 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
71 log_info("No MTU set");
72 else
73 log_info("MTU: %" PRIu32, mtu);
74
75 r = sd_ndisc_router_option_rewind(rt);
76 for (;;) {
77 uint8_t type;
78
79 assert_se(r >= 0);
80
81 if (r == 0)
82 break;
83
84 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
85
86 log_info(">> Option %u", type);
87
88 switch (type) {
89
90 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
91 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
92 _cleanup_free_ char *c = NULL;
93 const void *p;
94 size_t n;
95
96 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
97 assert_se(n > 2);
98 assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
99
100 log_info("Address: %s", c);
101 break;
102 }
103
104 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
105 uint32_t lifetime_valid, lifetime_preferred;
106 unsigned prefix_len;
107 uint8_t pfl;
108 struct in6_addr a;
109 char buff[INET6_ADDRSTRLEN];
110
111 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0);
112 log_info("Valid Lifetime: %" PRIu32, lifetime_valid);
113
114 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0);
115 log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred);
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", inet_ntop(AF_INET6, &a, buff, sizeof(buff)));
127
128 break;
129 }
130
131 case SD_NDISC_OPTION_RDNSS: {
132 const struct in6_addr *a;
133 uint32_t lt;
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 char buff[INET6_ADDRSTRLEN];
141 log_info("DNS: %s", inet_ntop(AF_INET6, a + i, buff, sizeof(buff)));
142 }
143
144 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lt) >= 0);
145 log_info("Lifetime: %" PRIu32, lt);
146 break;
147 }
148
149 case SD_NDISC_OPTION_DNSSL: {
150 _cleanup_strv_free_ char **l = NULL;
151 uint32_t lt;
152 int n, i;
153
154 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
155 assert_se(n > 0);
156
157 for (i = 0; i < n; i++)
158 log_info("Domain: %s", l[i]);
159
160 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lt) >= 0);
161 log_info("Lifetime: %" PRIu32, lt);
162 break;
163 }}
164
165 r = sd_ndisc_router_option_next(rt);
166 }
167 }
168
169 static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
170 void *userdata) {
171 assert_se(false);
172
173 return 0;
174 }
175
176 int icmp6_bind_router_solicitation(int index) {
177 assert_se(index == 42);
178
179 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
180 return -errno;
181
182 return test_fd[0];
183 }
184
185 int icmp6_bind_router_advertisement(int index) {
186
187 return -ENOSYS;
188 }
189
190 int icmp6_receive(int fd, void *iov_base, size_t iov_len,
191 struct in6_addr *dst, triple_timestamp *timestamp) {
192 assert_se(read (fd, iov_base, iov_len) == (ssize_t)iov_len);
193
194 if (timestamp)
195 triple_timestamp_get(timestamp);
196
197 return 0;
198 }
199
200 static int send_ra(uint8_t flags) {
201 uint8_t advertisement[] = {
202 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
205 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
206 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
209 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
211 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
212 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
213 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
215 };
216
217 advertisement[5] = flags;
218
219 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
220 sizeof(advertisement));
221
222 if (verbose)
223 printf(" sent RA with flag 0x%02x\n", flags);
224
225 return 0;
226 }
227
228 int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
229 if (!send_ra_function)
230 return 0;
231
232 return send_ra_function(0);
233 }
234
235 static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
236 sd_event *e = userdata;
237 static unsigned idx = 0;
238 uint64_t flags_array[] = {
239 0,
240 0,
241 0,
242 ND_RA_FLAG_OTHER,
243 ND_RA_FLAG_MANAGED
244 };
245 uint64_t flags;
246 uint32_t mtu;
247
248 assert_se(nd);
249
250 if (event != SD_NDISC_EVENT_ROUTER)
251 return;
252
253 router_dump(rt);
254
255 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
256 assert_se(flags == flags_array[idx]);
257 idx++;
258
259 if (verbose)
260 printf(" got event 0x%02" PRIx64 "\n", flags);
261
262 if (idx < ELEMENTSOF(flags_array)) {
263 send_ra(flags_array[idx]);
264 return;
265 }
266
267 assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA);
268
269 sd_event_exit(e, 0);
270 }
271
272 static void test_rs(void) {
273 sd_event *e;
274 sd_ndisc *nd;
275 usec_t time_now = now(clock_boottime_or_monotonic());
276
277 if (verbose)
278 printf("* %s\n", __FUNCTION__);
279
280 send_ra_function = send_ra;
281
282 assert_se(sd_event_new(&e) >= 0);
283
284 assert_se(sd_ndisc_new(&nd) >= 0);
285 assert_se(nd);
286
287 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
288
289 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
290 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
291 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
292
293 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
294 time_now + 2 *USEC_PER_SEC, 0,
295 test_rs_hangcheck, NULL) >= 0);
296
297 assert_se(sd_ndisc_stop(nd) >= 0);
298 assert_se(sd_ndisc_start(nd) >= 0);
299 assert_se(sd_ndisc_stop(nd) >= 0);
300
301 assert_se(sd_ndisc_start(nd) >= 0);
302
303 sd_event_loop(e);
304
305 test_hangcheck = sd_event_source_unref(test_hangcheck);
306
307 nd = sd_ndisc_unref(nd);
308 assert_se(!nd);
309
310 close(test_fd[1]);
311
312 sd_event_unref(e);
313 }
314
315 static int test_timeout_value(uint8_t flags) {
316 static int count = 0;
317 static usec_t last = 0;
318 sd_ndisc *nd = test_timeout_nd;
319 usec_t min, max;
320 char time_string_min[FORMAT_TIMESPAN_MAX];
321 char time_string_nd[FORMAT_TIMESPAN_MAX];
322 char time_string_max[FORMAT_TIMESPAN_MAX];
323
324 assert_se(nd);
325 assert_se(nd->event);
326
327 if (++count >= 20)
328 sd_event_exit(nd->event, 0);
329
330 if (last == 0) {
331 /* initial RT = IRT + RAND*IRT */
332 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
333 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
334 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
335 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
336 } else {
337 /* next RT = 2*RTprev + RAND*RTprev */
338 min = 2 * last - last / 10;
339 max = 2 * last + last / 10;
340 }
341
342 /* final RT > MRT */
343 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
344 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
345 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
346 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
347 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
348 }
349
350 format_timespan(time_string_min, FORMAT_TIMESPAN_MAX,
351 min, USEC_PER_MSEC);
352 format_timespan(time_string_nd, FORMAT_TIMESPAN_MAX,
353 nd->retransmit_time, USEC_PER_MSEC);
354 format_timespan(time_string_max, FORMAT_TIMESPAN_MAX,
355 max, USEC_PER_MSEC);
356
357 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
358 count,
359 (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL)? "(max) ": "",
360 time_string_min, time_string_nd, time_string_max);
361
362 assert_se(min <= nd->retransmit_time);
363 assert_se(max >= nd->retransmit_time);
364
365 last = nd->retransmit_time;
366
367 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
368
369 return 0;
370 }
371
372 static void test_timeout(void) {
373 sd_event *e;
374 sd_ndisc *nd;
375 usec_t time_now = now(clock_boottime_or_monotonic());
376
377 if (verbose)
378 printf("* %s\n", __FUNCTION__);
379
380 send_ra_function = test_timeout_value;
381
382 assert_se(sd_event_new(&e) >= 0);
383
384 assert_se(sd_ndisc_new(&nd) >= 0);
385 assert_se(nd);
386
387 test_timeout_nd = nd;
388
389 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
390
391 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
392 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
393
394 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
395 time_now + 2U * USEC_PER_SEC, 0,
396 test_rs_hangcheck, NULL) >= 0);
397
398 assert_se(sd_ndisc_start(nd) >= 0);
399
400 sd_event_loop(e);
401
402 test_hangcheck = sd_event_source_unref(test_hangcheck);
403
404 nd = sd_ndisc_unref(nd);
405
406 sd_event_unref(e);
407 }
408
409 int main(int argc, char *argv[]) {
410
411 test_setup_logging(LOG_DEBUG);
412
413 test_rs();
414 test_timeout();
415
416 return 0;
417 }