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