]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #9017 from keszybz/man-coredump
[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
8 #include <netinet/icmp6.h>
9 #include <arpa/inet.h>
10
11 #include "sd-ndisc.h"
12
13 #include "alloc-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
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, 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_stop(nd) >= 0);
301
302 assert_se(sd_ndisc_start(nd) >= 0);
303
304 sd_event_loop(e);
305
306 test_hangcheck = sd_event_source_unref(test_hangcheck);
307
308 nd = sd_ndisc_unref(nd);
309 assert_se(!nd);
310
311 close(test_fd[1]);
312
313 sd_event_unref(e);
314 }
315
316 static int test_timeout_value(uint8_t flags) {
317 static int count = 0;
318 static usec_t last = 0;
319 sd_ndisc *nd = test_timeout_nd;
320 usec_t min, max;
321 char time_string_min[FORMAT_TIMESPAN_MAX];
322 char time_string_nd[FORMAT_TIMESPAN_MAX];
323 char time_string_max[FORMAT_TIMESPAN_MAX];
324
325 assert_se(nd);
326 assert_se(nd->event);
327
328 if (++count >= 20)
329 sd_event_exit(nd->event, 0);
330
331 if (last == 0) {
332 /* initial RT = IRT + RAND*IRT */
333 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
334 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
335 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
336 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
337 } else {
338 /* next RT = 2*RTprev + RAND*RTprev */
339 min = 2 * last - last / 10;
340 max = 2 * last + last / 10;
341 }
342
343 /* final RT > MRT */
344 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
345 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
346 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
347 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
348 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
349 }
350
351 format_timespan(time_string_min, FORMAT_TIMESPAN_MAX,
352 min, USEC_PER_MSEC);
353 format_timespan(time_string_nd, FORMAT_TIMESPAN_MAX,
354 nd->retransmit_time, USEC_PER_MSEC);
355 format_timespan(time_string_max, FORMAT_TIMESPAN_MAX,
356 max, USEC_PER_MSEC);
357
358 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
359 count,
360 (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL)? "(max) ": "",
361 time_string_min, time_string_nd, time_string_max);
362
363 assert_se(min <= nd->retransmit_time);
364 assert_se(max >= nd->retransmit_time);
365
366 last = nd->retransmit_time;
367
368 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
369
370 return 0;
371 }
372
373 static void test_timeout(void) {
374 sd_event *e;
375 sd_ndisc *nd;
376 usec_t time_now = now(clock_boottime_or_monotonic());
377
378 if (verbose)
379 printf("* %s\n", __FUNCTION__);
380
381 send_ra_function = test_timeout_value;
382
383 assert_se(sd_event_new(&e) >= 0);
384
385 assert_se(sd_ndisc_new(&nd) >= 0);
386 assert_se(nd);
387
388 test_timeout_nd = nd;
389
390 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
391
392 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
393 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
394
395 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
396 time_now + 2U * USEC_PER_SEC, 0,
397 test_rs_hangcheck, NULL) >= 0);
398
399 assert_se(sd_ndisc_start(nd) >= 0);
400
401 sd_event_loop(e);
402
403 test_hangcheck = sd_event_source_unref(test_hangcheck);
404
405 nd = sd_ndisc_unref(nd);
406
407 sd_event_unref(e);
408 }
409
410 int main(int argc, char *argv[]) {
411
412 log_set_max_level(LOG_DEBUG);
413 log_parse_environment();
414 log_open();
415
416 test_rs();
417 test_timeout();
418
419 return 0;
420 }