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