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