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