Line data Source code
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 5 : 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 5 : assert_se(rt);
43 :
44 5 : log_info("--");
45 5 : assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA);
46 :
47 5 : assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
48 5 : log_info("Timestamp: %s", format_timestamp(buf, sizeof(buf), t));
49 :
50 5 : assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
51 5 : log_info("Monotonic: %" PRIu64, t);
52 :
53 5 : if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
54 0 : log_info("No hop limit set");
55 : else
56 5 : log_info("Hop limit: %u", hop_limit);
57 :
58 5 : assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
59 5 : log_info("Flags: <%s|%s>",
60 : flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
61 : flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
62 :
63 5 : assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
64 5 : log_info("Preference: %s",
65 : preference == SD_NDISC_PREFERENCE_LOW ? "low" :
66 : preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
67 :
68 5 : assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
69 5 : log_info("Lifetime: %" PRIu16, lifetime);
70 :
71 5 : if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
72 5 : log_info("No MTU set");
73 : else
74 0 : log_info("MTU: %" PRIu32, mtu);
75 :
76 5 : r = sd_ndisc_router_option_rewind(rt);
77 20 : for (;;) {
78 : uint8_t type;
79 :
80 25 : assert_se(r >= 0);
81 :
82 25 : if (r == 0)
83 5 : break;
84 :
85 20 : assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
86 :
87 20 : log_info(">> Option %u", type);
88 :
89 20 : switch (type) {
90 :
91 5 : case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
92 : case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
93 5 : _cleanup_free_ char *c = NULL;
94 : const void *p;
95 : size_t n;
96 :
97 5 : assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
98 5 : assert_se(n > 2);
99 5 : assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
100 :
101 5 : log_info("Address: %s", c);
102 5 : break;
103 : }
104 :
105 5 : 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 5 : assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0);
113 5 : log_info("Valid Lifetime: %" PRIu32, lifetime_valid);
114 :
115 5 : assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0);
116 5 : log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred);
117 :
118 5 : assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
119 5 : log_info("Flags: <%s|%s>",
120 : pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
121 : pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
122 :
123 5 : assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
124 5 : log_info("Prefix Length: %u", prefix_len);
125 :
126 5 : assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
127 5 : log_info("Prefix: %s", inet_ntop(AF_INET6, &a, buff, sizeof(buff)));
128 :
129 5 : break;
130 : }
131 :
132 5 : case SD_NDISC_OPTION_RDNSS: {
133 : const struct in6_addr *a;
134 : uint32_t lt;
135 : int n, i;
136 :
137 5 : n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
138 5 : assert_se(n > 0);
139 :
140 10 : for (i = 0; i < n; i++) {
141 : char buff[INET6_ADDRSTRLEN];
142 5 : log_info("DNS: %s", inet_ntop(AF_INET6, a + i, buff, sizeof(buff)));
143 : }
144 :
145 5 : assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, <) >= 0);
146 5 : log_info("Lifetime: %" PRIu32, lt);
147 5 : break;
148 : }
149 :
150 5 : case SD_NDISC_OPTION_DNSSL: {
151 5 : _cleanup_strv_free_ char **l = NULL;
152 : uint32_t lt;
153 : int n, i;
154 :
155 5 : n = sd_ndisc_router_dnssl_get_domains(rt, &l);
156 5 : assert_se(n > 0);
157 :
158 10 : for (i = 0; i < n; i++)
159 5 : log_info("Domain: %s", l[i]);
160 :
161 5 : assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, <) >= 0);
162 5 : log_info("Lifetime: %" PRIu32, lt);
163 5 : break;
164 : }}
165 :
166 20 : r = sd_ndisc_router_option_next(rt);
167 : }
168 5 : }
169 :
170 0 : static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
171 : void *userdata) {
172 0 : assert_se(false);
173 :
174 : return 0;
175 : }
176 :
177 3 : int icmp6_bind_router_solicitation(int index) {
178 3 : assert_se(index == 42);
179 :
180 3 : if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
181 0 : return -errno;
182 :
183 3 : return test_fd[0];
184 : }
185 :
186 0 : int icmp6_bind_router_advertisement(int index) {
187 :
188 0 : return -ENOSYS;
189 : }
190 :
191 5 : int icmp6_receive(int fd, void *iov_base, size_t iov_len,
192 : struct in6_addr *dst, triple_timestamp *timestamp) {
193 5 : assert_se(read (fd, iov_base, iov_len) == (ssize_t)iov_len);
194 :
195 5 : if (timestamp)
196 5 : triple_timestamp_get(timestamp);
197 :
198 5 : return 0;
199 : }
200 :
201 5 : static int send_ra(uint8_t flags) {
202 5 : 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 5 : advertisement[5] = flags;
219 :
220 5 : assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
221 : sizeof(advertisement));
222 :
223 5 : if (verbose)
224 0 : printf(" sent RA with flag 0x%02x\n", flags);
225 :
226 5 : return 0;
227 : }
228 :
229 21 : int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
230 21 : if (!send_ra_function)
231 0 : return 0;
232 :
233 21 : return send_ra_function(0);
234 : }
235 :
236 5 : static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
237 5 : sd_event *e = userdata;
238 : static unsigned idx = 0;
239 5 : 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 5 : assert_se(nd);
250 :
251 5 : if (event != SD_NDISC_EVENT_ROUTER)
252 4 : return;
253 :
254 5 : router_dump(rt);
255 :
256 5 : assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
257 5 : assert_se(flags == flags_array[idx]);
258 5 : idx++;
259 :
260 5 : if (verbose)
261 0 : printf(" got event 0x%02" PRIx64 "\n", flags);
262 :
263 5 : if (idx < ELEMENTSOF(flags_array)) {
264 4 : send_ra(flags_array[idx]);
265 4 : return;
266 : }
267 :
268 1 : assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA);
269 :
270 1 : sd_event_exit(e, 0);
271 : }
272 :
273 1 : static void test_rs(void) {
274 : sd_event *e;
275 : sd_ndisc *nd;
276 1 : usec_t time_now = now(clock_boottime_or_monotonic());
277 :
278 1 : if (verbose)
279 0 : printf("* %s\n", __FUNCTION__);
280 :
281 1 : send_ra_function = send_ra;
282 :
283 1 : assert_se(sd_event_new(&e) >= 0);
284 :
285 1 : assert_se(sd_ndisc_new(&nd) >= 0);
286 1 : assert_se(nd);
287 :
288 1 : assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
289 :
290 1 : assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
291 1 : assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
292 1 : assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
293 :
294 1 : 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 1 : assert_se(sd_ndisc_stop(nd) >= 0);
299 1 : assert_se(sd_ndisc_start(nd) >= 0);
300 1 : assert_se(sd_ndisc_stop(nd) >= 0);
301 :
302 1 : assert_se(sd_ndisc_start(nd) >= 0);
303 :
304 1 : sd_event_loop(e);
305 :
306 1 : test_hangcheck = sd_event_source_unref(test_hangcheck);
307 :
308 1 : nd = sd_ndisc_unref(nd);
309 1 : assert_se(!nd);
310 :
311 1 : close(test_fd[1]);
312 :
313 1 : sd_event_unref(e);
314 1 : }
315 :
316 20 : static int test_timeout_value(uint8_t flags) {
317 : static int count = 0;
318 : static usec_t last = 0;
319 20 : 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 20 : assert_se(nd);
326 20 : assert_se(nd->event);
327 :
328 20 : if (++count >= 20)
329 1 : sd_event_exit(nd->event, 0);
330 :
331 20 : if (last == 0) {
332 : /* initial RT = IRT + RAND*IRT */
333 1 : min = NDISC_ROUTER_SOLICITATION_INTERVAL -
334 : NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
335 1 : max = NDISC_ROUTER_SOLICITATION_INTERVAL +
336 : NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
337 : } else {
338 : /* next RT = 2*RTprev + RAND*RTprev */
339 19 : min = 2 * last - last / 10;
340 19 : max = 2 * last + last / 10;
341 : }
342 :
343 : /* final RT > MRT */
344 20 : if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
345 10 : min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
346 : NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
347 10 : max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
348 : NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
349 : }
350 :
351 20 : format_timespan(time_string_min, FORMAT_TIMESPAN_MAX,
352 : min, USEC_PER_MSEC);
353 20 : format_timespan(time_string_nd, FORMAT_TIMESPAN_MAX,
354 : nd->retransmit_time, USEC_PER_MSEC);
355 20 : format_timespan(time_string_max, FORMAT_TIMESPAN_MAX,
356 : max, USEC_PER_MSEC);
357 :
358 20 : 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 20 : assert_se(min <= nd->retransmit_time);
364 20 : assert_se(max >= nd->retransmit_time);
365 :
366 20 : last = nd->retransmit_time;
367 :
368 20 : assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
369 :
370 20 : return 0;
371 : }
372 :
373 1 : static void test_timeout(void) {
374 : sd_event *e;
375 : sd_ndisc *nd;
376 1 : usec_t time_now = now(clock_boottime_or_monotonic());
377 :
378 1 : if (verbose)
379 0 : printf("* %s\n", __FUNCTION__);
380 :
381 1 : send_ra_function = test_timeout_value;
382 :
383 1 : assert_se(sd_event_new(&e) >= 0);
384 :
385 1 : assert_se(sd_ndisc_new(&nd) >= 0);
386 1 : assert_se(nd);
387 :
388 1 : test_timeout_nd = nd;
389 :
390 1 : assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
391 :
392 1 : assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
393 1 : assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
394 :
395 1 : 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 1 : assert_se(sd_ndisc_start(nd) >= 0);
400 :
401 1 : sd_event_loop(e);
402 :
403 1 : test_hangcheck = sd_event_source_unref(test_hangcheck);
404 :
405 1 : nd = sd_ndisc_unref(nd);
406 :
407 1 : sd_event_unref(e);
408 1 : }
409 :
410 1 : int main(int argc, char *argv[]) {
411 :
412 1 : test_setup_logging(LOG_DEBUG);
413 :
414 1 : test_rs();
415 1 : test_timeout();
416 :
417 1 : return 0;
418 : }
|