]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #26271 from d-hatayama/fix_sulogin_shell
[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.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 int test_fd[2];
27 static sd_ndisc *test_timeout_nd;
28
29 typedef int (*send_ra_t)(uint8_t flags);
30 static send_ra_t send_ra_function;
31
32 static void router_dump(sd_ndisc_router *rt) {
33 struct in6_addr addr;
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(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
110 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0);
111 log_info("Valid Lifetime: %" PRIu32, lifetime_valid);
112
113 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0);
114 log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred);
115
116 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
117 log_info("Flags: <%s|%s>",
118 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
119 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
120
121 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
122 log_info("Prefix Length: %u", prefix_len);
123
124 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
125 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
126
127 break;
128 }
129
130 case SD_NDISC_OPTION_RDNSS: {
131 const struct in6_addr *a;
132 uint32_t lt;
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, &lt) >= 0);
142 log_info("Lifetime: %" PRIu32, lt);
143 break;
144 }
145
146 case SD_NDISC_OPTION_DNSSL: {
147 _cleanup_strv_free_ char **l = NULL;
148 uint32_t lt;
149 int n, i;
150
151 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
152 assert_se(n > 0);
153
154 for (i = 0; i < n; i++)
155 log_info("Domain: %s", l[i]);
156
157 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lt) >= 0);
158 log_info("Lifetime: %" PRIu32, lt);
159 break;
160 }}
161
162 r = sd_ndisc_router_option_next(rt);
163 }
164 }
165
166 int icmp6_bind_router_solicitation(int ifindex) {
167 assert_se(ifindex == 42);
168
169 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
170 return -errno;
171
172 return test_fd[0];
173 }
174
175 int icmp6_bind_router_advertisement(int ifindex) {
176 return -ENOSYS;
177 }
178
179 int icmp6_receive(int fd, void *iov_base, size_t iov_len,
180 struct in6_addr *dst, triple_timestamp *timestamp) {
181 assert_se(read (fd, iov_base, iov_len) == (ssize_t)iov_len);
182
183 if (timestamp)
184 triple_timestamp_get(timestamp);
185
186 return 0;
187 }
188
189 static int send_ra(uint8_t flags) {
190 uint8_t advertisement[] = {
191 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
194 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
195 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
198 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
200 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
201 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
202 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
204 };
205
206 advertisement[5] = flags;
207
208 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
209 sizeof(advertisement));
210
211 if (verbose)
212 printf(" sent RA with flag 0x%02x\n", flags);
213
214 return 0;
215 }
216
217 int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
218 if (!send_ra_function)
219 return 0;
220
221 return send_ra_function(0);
222 }
223
224 static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
225 sd_event *e = userdata;
226 static unsigned idx = 0;
227 uint64_t flags_array[] = {
228 0,
229 0,
230 0,
231 ND_RA_FLAG_OTHER,
232 ND_RA_FLAG_MANAGED
233 };
234 uint64_t flags;
235
236 assert_se(nd);
237
238 if (event != SD_NDISC_EVENT_ROUTER)
239 return;
240
241 router_dump(rt);
242
243 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
244 assert_se(flags == flags_array[idx]);
245 idx++;
246
247 if (verbose)
248 printf(" got event 0x%02" PRIx64 "\n", flags);
249
250 if (idx < ELEMENTSOF(flags_array)) {
251 send_ra(flags_array[idx]);
252 return;
253 }
254
255 sd_event_exit(e, 0);
256 }
257
258 TEST(rs) {
259 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
260 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
261
262 send_ra_function = send_ra;
263
264 assert_se(sd_event_new(&e) >= 0);
265
266 assert_se(sd_ndisc_new(&nd) >= 0);
267 assert_se(nd);
268
269 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
270
271 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
272 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
273 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
274
275 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
276 30 * USEC_PER_SEC, 0,
277 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
278
279 assert_se(sd_ndisc_stop(nd) >= 0);
280 assert_se(sd_ndisc_start(nd) >= 0);
281 assert_se(sd_ndisc_start(nd) >= 0);
282 assert_se(sd_ndisc_stop(nd) >= 0);
283 test_fd[1] = safe_close(test_fd[1]);
284
285 assert_se(sd_ndisc_start(nd) >= 0);
286
287 assert_se(sd_event_loop(e) >= 0);
288
289 test_fd[1] = safe_close(test_fd[1]);
290 }
291
292 static int test_timeout_value(uint8_t flags) {
293 static int count = 0;
294 static usec_t last = 0;
295 sd_ndisc *nd = test_timeout_nd;
296 usec_t min, max;
297
298 assert_se(nd);
299 assert_se(nd->event);
300
301 if (++count >= 20)
302 sd_event_exit(nd->event, 0);
303
304 if (last == 0) {
305 /* initial RT = IRT + RAND*IRT */
306 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
307 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
308 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
309 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
310 } else {
311 /* next RT = 2*RTprev + RAND*RTprev */
312 min = 2 * last - last / 10;
313 max = 2 * last + last / 10;
314 }
315
316 /* final RT > MRT */
317 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
318 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
319 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
320 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
321 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
322 }
323
324 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
325 count,
326 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
327 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
328 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
329 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
330
331 assert_se(min <= nd->retransmit_time);
332 assert_se(max >= nd->retransmit_time);
333
334 last = nd->retransmit_time;
335
336 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
337
338 return 0;
339 }
340
341 TEST(timeout) {
342 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
343 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
344
345 send_ra_function = test_timeout_value;
346
347 assert_se(sd_event_new(&e) >= 0);
348
349 assert_se(sd_ndisc_new(&nd) >= 0);
350 assert_se(nd);
351
352 test_timeout_nd = nd;
353
354 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
355
356 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
357 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
358
359 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
360 30 * USEC_PER_SEC, 0,
361 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
362
363 assert_se(sd_ndisc_start(nd) >= 0);
364
365 assert_se(sd_event_loop(e) >= 0);
366
367 test_fd[1] = safe_close(test_fd[1]);
368 }
369
370 DEFINE_TEST_MAIN(LOG_DEBUG);