]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-ndisc-rs.c
dhcp6, radv: only accept valid ifindex
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f20a35cc 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
f20a35cc
PF
4***/
5
6#include <netinet/icmp6.h>
1e7a0e21 7#include <arpa/inet.h>
ca78ad1d 8#include <unistd.h>
f20a35cc 9
07630cea 10#include "sd-ndisc.h"
f20a35cc 11
1e7a0e21
LP
12#include "alloc-util.h"
13#include "hexdecoct.h"
940367a0 14#include "icmp6-util.h"
07630cea 15#include "socket-util.h"
1e7a0e21 16#include "strv.h"
5a67ed24 17#include "ndisc-internal.h"
6d7c4033 18#include "tests.h"
f20a35cc
PF
19
20static struct ether_addr mac_addr = {
21 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
22};
23
24static bool verbose = false;
25static sd_event_source *test_hangcheck;
26static int test_fd[2];
5a67ed24 27static sd_ndisc *test_timeout_nd;
f20a35cc 28
99af546d
PF
29typedef int (*send_ra_t)(uint8_t flags);
30static send_ra_t send_ra_function;
31
1e7a0e21
LP
32static 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
f20a35cc
PF
170static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
171 void *userdata) {
787784c4 172 assert_se(false);
f20a35cc
PF
173
174 return 0;
175}
176
940367a0 177int icmp6_bind_router_solicitation(int index) {
787784c4 178 assert_se(index == 42);
f20a35cc 179
3e29b889 180 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
f20a35cc
PF
181 return -errno;
182
183 return test_fd[0];
184}
185
6142bb37
PF
186int icmp6_bind_router_advertisement(int index) {
187
188 return -ENOSYS;
189}
190
88d5a3db
PF
191int icmp6_receive(int fd, void *iov_base, size_t iov_len,
192 struct in6_addr *dst, triple_timestamp *timestamp) {
19500112 193 assert_se(read (fd, iov_base, iov_len) == (ssize_t)iov_len);
88d5a3db
PF
194
195 if (timestamp)
196 triple_timestamp_get(timestamp);
197
198 return 0;
199}
200
f20a35cc
PF
201static 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
787784c4 220 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
f20a35cc
PF
221 sizeof(advertisement));
222
223 if (verbose)
224 printf(" sent RA with flag 0x%02x\n", flags);
225
226 return 0;
227}
228
940367a0 229int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
5a67ed24
PF
230 if (!send_ra_function)
231 return 0;
232
99af546d 233 return send_ra_function(0);
f20a35cc
PF
234}
235
1e7a0e21 236static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
f20a35cc 237 sd_event *e = userdata;
cb53894d 238 static unsigned idx = 0;
1e7a0e21 239 uint64_t flags_array[] = {
9d96e6c3
TG
240 0,
241 0,
242 0,
243 ND_RA_FLAG_OTHER,
244 ND_RA_FLAG_MANAGED
f20a35cc 245 };
1e7a0e21 246 uint64_t flags;
8d7f2c6a
PF
247 uint32_t mtu;
248
787784c4 249 assert_se(nd);
f20a35cc 250
1e7a0e21
LP
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);
9d96e6c3 257 assert_se(flags == flags_array[idx]);
f20a35cc
PF
258 idx++;
259
260 if (verbose)
1e7a0e21 261 printf(" got event 0x%02" PRIx64 "\n", flags);
f20a35cc 262
9d96e6c3
TG
263 if (idx < ELEMENTSOF(flags_array)) {
264 send_ra(flags_array[idx]);
8d7f2c6a
PF
265 return;
266 }
267
1e7a0e21 268 assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA);
8d7f2c6a
PF
269
270 sd_event_exit(e, 0);
f20a35cc
PF
271}
272
99af546d
PF
273static void test_rs(void) {
274 sd_event *e;
4d7b83da 275 sd_ndisc *nd;
99af546d 276 usec_t time_now = now(clock_boottime_or_monotonic());
f20a35cc
PF
277
278 if (verbose)
279 printf("* %s\n", __FUNCTION__);
280
99af546d
PF
281 send_ra_function = send_ra;
282
283 assert_se(sd_event_new(&e) >= 0);
284
4d7b83da 285 assert_se(sd_ndisc_new(&nd) >= 0);
787784c4 286 assert_se(nd);
f20a35cc 287
4d7b83da 288 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
f20a35cc 289
2f8e7633 290 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
4d7b83da 291 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
1e7a0e21 292 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
f20a35cc 293
787784c4 294 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
f20a35cc
PF
295 time_now + 2 *USEC_PER_SEC, 0,
296 test_rs_hangcheck, NULL) >= 0);
297
4d7b83da 298 assert_se(sd_ndisc_stop(nd) >= 0);
1e7a0e21 299 assert_se(sd_ndisc_start(nd) >= 0);
6b8a1aa6 300 assert_se(sd_ndisc_start(nd) >= 0);
4d7b83da 301 assert_se(sd_ndisc_stop(nd) >= 0);
836cf090 302
1e7a0e21 303 assert_se(sd_ndisc_start(nd) >= 0);
f20a35cc
PF
304
305 sd_event_loop(e);
306
307 test_hangcheck = sd_event_source_unref(test_hangcheck);
308
4d7b83da 309 nd = sd_ndisc_unref(nd);
787784c4 310 assert_se(!nd);
f20a35cc 311
f20a35cc 312 close(test_fd[1]);
99af546d
PF
313
314 sd_event_unref(e);
f20a35cc
PF
315}
316
5a67ed24
PF
317static 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
374static 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
f20a35cc 411int main(int argc, char *argv[]) {
f20a35cc 412
6d7c4033 413 test_setup_logging(LOG_DEBUG);
f20a35cc 414
99af546d 415 test_rs();
5a67ed24 416 test_timeout();
f20a35cc
PF
417
418 return 0;
419}