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