]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
5d1e66fcdc96900772d66866f71edc8461c9d64e
[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 ifindex) {
178 assert_se(ifindex == 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 ifindex) {
187 return -ENOSYS;
188 }
189
190 int icmp6_receive(int fd, void *iov_base, size_t iov_len,
191 struct in6_addr *dst, triple_timestamp *timestamp) {
192 assert_se(read (fd, iov_base, iov_len) == (ssize_t)iov_len);
193
194 if (timestamp)
195 triple_timestamp_get(timestamp);
196
197 return 0;
198 }
199
200 static int send_ra(uint8_t flags) {
201 uint8_t advertisement[] = {
202 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
205 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
206 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
209 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
211 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
212 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
213 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
215 };
216
217 advertisement[5] = flags;
218
219 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
220 sizeof(advertisement));
221
222 if (verbose)
223 printf(" sent RA with flag 0x%02x\n", flags);
224
225 return 0;
226 }
227
228 int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
229 if (!send_ra_function)
230 return 0;
231
232 return send_ra_function(0);
233 }
234
235 static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
236 sd_event *e = userdata;
237 static unsigned idx = 0;
238 uint64_t flags_array[] = {
239 0,
240 0,
241 0,
242 ND_RA_FLAG_OTHER,
243 ND_RA_FLAG_MANAGED
244 };
245 uint64_t flags;
246 uint32_t mtu;
247
248 assert_se(nd);
249
250 if (event != SD_NDISC_EVENT_ROUTER)
251 return;
252
253 router_dump(rt);
254
255 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
256 assert_se(flags == flags_array[idx]);
257 idx++;
258
259 if (verbose)
260 printf(" got event 0x%02" PRIx64 "\n", flags);
261
262 if (idx < ELEMENTSOF(flags_array)) {
263 send_ra(flags_array[idx]);
264 return;
265 }
266
267 assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA);
268
269 sd_event_exit(e, 0);
270 }
271
272 static void test_rs(void) {
273 sd_event *e;
274 sd_ndisc *nd;
275 usec_t time_now = now(clock_boottime_or_monotonic());
276
277 if (verbose)
278 printf("* %s\n", __FUNCTION__);
279
280 send_ra_function = send_ra;
281
282 assert_se(sd_event_new(&e) >= 0);
283
284 assert_se(sd_ndisc_new(&nd) >= 0);
285 assert_se(nd);
286
287 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
288
289 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
290 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
291 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
292
293 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
294 time_now + 2 *USEC_PER_SEC, 0,
295 test_rs_hangcheck, NULL) >= 0);
296
297 assert_se(sd_ndisc_stop(nd) >= 0);
298 assert_se(sd_ndisc_start(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 test_setup_logging(LOG_DEBUG);
413
414 test_rs();
415 test_timeout();
416
417 return 0;
418 }